aboutsummaryrefslogtreecommitdiff
path: root/backend/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'backend/utils.c')
-rw-r--r--backend/utils.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/backend/utils.c b/backend/utils.c
new file mode 100644
index 0000000..e43afc1
--- /dev/null
+++ b/backend/utils.c
@@ -0,0 +1,334 @@
+/* utils.c -- assorted utility functions and macros
+ * Copyright (C) 2008, 2009 SEIKO EPSON CORPORATION
+ *
+ * License: GPLv2+|iscan
+ * Authors: AVASYS CORPORATION
+ *
+ * This file is part of the SANE backend distributed with Image Scan!
+ *
+ * Image Scan!'s SANE backend is free software.
+ * You can redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software Foundation;
+ * either version 2 of the License or at your option any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You ought to have received a copy of the GNU General Public License
+ * along with this package. If not, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Linking Image Scan!'s SANE backend statically or dynamically with
+ * other modules is making a combined work based on this SANE backend.
+ * Thus, the terms and conditions of the GNU General Public License
+ * cover the whole combination.
+ *
+ * As a special exception, the copyright holders of Image Scan!'s SANE
+ * backend give you permission to link Image Scan!'s SANE backend with
+ * SANE frontends that communicate with Image Scan!'s SANE backend
+ * solely through the SANE Application Programming Interface,
+ * regardless of the license terms of these SANE frontends, and to
+ * copy and distribute the resulting combined work under terms of your
+ * choice, provided that every copy of the combined work is
+ * accompanied by a complete copy of the source code of Image Scan!'s
+ * SANE backend (the version of Image Scan!'s SANE backend used to
+ * produce the combined work), being distributed under the terms of
+ * the GNU General Public License plus this exception. An independent
+ * module is a module which is not derived from or based on Image
+ * Scan!'s SANE backend.
+ *
+ * As a special exception, the copyright holders of Image Scan!'s SANE
+ * backend give you permission to link Image Scan!'s SANE backend with
+ * independent modules that communicate with Image Scan!'s SANE
+ * backend solely through the "Interpreter" interface, regardless of
+ * the license terms of these independent modules, and to copy and
+ * distribute the resulting combined work under terms of your choice,
+ * provided that every copy of the combined work is accompanied by a
+ * complete copy of the source code of Image Scan!'s SANE backend (the
+ * version of Image Scan!'s SANE backend used to produce the combined
+ * work), being distributed under the terms of the GNU General Public
+ * License plus this exception. An independent module is a module
+ * which is not derived from or based on Image Scan!'s SANE backend.
+ *
+ * Note that people who make modified versions of Image Scan!'s SANE
+ * backend are not obligated to grant special exceptions for their
+ * modified versions; it is their choice whether to do so. The GNU
+ * General Public License gives permission to release a modified
+ * version without this exception; this exception also makes it
+ * possible to release a modified version which carries forward this
+ * exception.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "utils.h"
+
+#include <errno.h>
+#include <string.h>
+#include <time.h> /* nanosleep */
+
+
+/*! Creates a string of 2-character hexadecimal values from a NUL
+ terminated character string.
+
+ The implementation acquires the memory needed for the result and
+ the caller is responsible for releasing it.
+
+ \return a pointer to the encoded string or \c NULL if the memory
+ required could not be acquired
+ */
+char *
+fw_name_to_hex (const char *fw_name) /* '\0' terminated */
+{
+ char *rv, *p;
+
+ log_call();
+
+ if (!fw_name) return NULL; /* guard clause */
+
+ p = rv = t_malloc (2 * strlen (fw_name) + 1, char);
+ if (!rv) return NULL;
+
+ while ('\0' != *fw_name)
+ {
+ sprintf (p, "%02x", *fw_name);
+ p += 2;
+ ++fw_name;
+ }
+ *p = '\0';
+ return rv;
+}
+
+/*! Sets up a properly initialised resolution info object.
+ */
+void
+init_resolution_info (resolution_info *self, u_char *data)
+{
+ SANE_Bool (*cond) (const u_char *) = NULL;
+ size_t step = 0;
+
+ if (!self) return;
+
+ self->last = 0; /* set defaults */
+ self->size = -1;
+ self->list = NULL;
+ self->deep = SANE_TRUE;
+
+ if (!data) return; /* act like a default constructor */
+
+ self->size = 0;
+ self->list = t_realloc (NULL, self->size + 1, SANE_Word);
+
+ if (!self->list)
+ {
+ err_major ("%s", strerror (ENOMEM));
+ self->size = -1;
+ return;
+ }
+
+ if ('R' == data[0]) /* ESC I data block */
+ {
+ cond = resolution_info_ESC_I_cond;
+ step = 3;
+ }
+ else /* ESC i data block, hopefully */
+ {
+ cond = resolution_info_ESC_i_cond;
+ step = 2;
+ }
+
+ while (cond (data))
+ {
+ void *p = self->list;
+
+ self->size++;
+ self->list = t_realloc (p, self->size + 1, SANE_Word);
+ if (!self->list)
+ {
+ delete (p);
+
+ err_major ("%s", strerror (ENOMEM));
+ self->size = -1;
+ return;
+ }
+ self->list[self->size] = data[step - 1] << 8 | data[step - 2];
+ data += step;
+ log_info ("resolution: %d dpi", self->list[self->size]);
+ }
+ self->list[0] = self->size;
+}
+
+/*! Releases resources held by \a self and resets it to default state.
+ */
+void
+free_resolution_info (resolution_info *self)
+{
+ if (!self) return;
+
+ if (self->deep)
+ delete (self->list);
+
+ init_resolution_info (self, NULL);
+}
+
+/*! Makes an optionally deep copy of \a src to \a dest.
+
+ Any resources held by \a dest will be returned to the system.
+ */
+SANE_Status
+copy_resolution_info (resolution_info *dest, const resolution_info *src,
+ SANE_Bool deep)
+{
+ if (!dest || !src) return SANE_STATUS_INVAL;
+
+ require (!src->list || src->size == src->list[0]);
+
+ if (deep && src->list) /* copy resolution list */
+ {
+ size_t size = (src->size + 1) * sizeof (SANE_Word);
+ SANE_Word *list = t_malloc (size, SANE_Word);
+
+ if (!list) return SANE_STATUS_NO_MEM;
+
+ memcpy (list, src->list, size);
+
+ if (dest->deep)
+ delete (dest->list);
+ dest->list = list;
+ }
+ else /* just refer to it */
+ {
+ if (dest->deep)
+ delete (dest->list);
+ dest->list = src->list;
+ }
+
+ dest->last = src->last;
+ dest->size = src->size;
+ dest->deep = deep;
+
+ promise (!dest->list || dest->size == dest->list[0]);
+
+ return SANE_STATUS_GOOD;
+}
+
+
+void
+_update_ranges (const device *hw, extension *src)
+{
+ require (hw);
+ require (src);
+
+ src->x_range.min = 0;
+ src->x_range.max = SANE_FIX (src->max_x * MM_PER_INCH / hw->base_res);
+ src->x_range.quant = 0;
+
+ src->y_range.min = 0;
+ src->y_range.max = SANE_FIX (src->max_y * MM_PER_INCH / hw->base_res);
+ src->y_range.quant = 0;
+
+ if (!hw->cmd->request_identity2) return;
+
+ /* correct for color shuffle offsets */
+ src->y_range.max = SANE_FIX ((src->max_y - 2 * hw->max_line_distance)
+ * MM_PER_INCH / hw->base_res);
+}
+
+
+/*! Convenience type to hold document size information.
+ */
+struct _doc_size_info
+{
+ const double width;
+ const double height;
+ const char *label;
+};
+
+/*! Document size information for known sizes.
+ */
+static const struct _doc_size_info
+doc_size[] = {
+ /* second byte bit flag values */
+ { 182.00, 257.00, "B5V"},
+ { 257.00, 182.00, "B5H"},
+ { 148.00, 210.00, "A5V"},
+ { 210.00, 148.00, "A5H"},
+ { 184.15, 266.70, "EXV"},
+ { 266.70, 184.15, "EXH"},
+ { 0 , 0 , "RSV"}, /* reserved */
+ { 0 , 0 , "UNK"}, /* unknown */
+ /* first byte bit flag values */
+ { 297.00, 420.00, "A3V"},
+ { 279.40, 431.80, "WLT"},
+ { 257.00, 364.00, "B4V"},
+ { 215.90, 355.60, "LGV"},
+ { 210.00, 297.00, "A4V"},
+ { 297.00, 210.00, "A4H"},
+ { 215.90, 279.40, "LTV"},
+ { 279.40, 215.90, "LTH"},
+};
+
+
+void
+_update_doc_size (extension *src, uint16_t value)
+{
+ const uint16_t DOC_MASK = ~0x0200;
+
+ size_t i = 0;
+
+ require (src);
+
+ if ((DOC_MASK & value) != value)
+ {
+ err_minor ("clearing reserved bit flags to match spec");
+ value &= DOC_MASK;
+ }
+
+ if (0 == value) /* size detection not supported */
+ {
+ src->doc_x = 0;
+ src->doc_y = 0;
+ return;
+ }
+
+ while (!(0x8000 & value) && (num_of (doc_size) > i))
+ {
+ value = value << 1;
+ ++i;
+ }
+
+ if (0 != strcmp_c ("UNK", doc_size[i].label))
+ {
+ src->doc_x = doc_size[i].width;
+ src->doc_y = doc_size[i].height;
+ }
+ else
+ {
+ src->doc_x = SANE_UNFIX (src->x_range.max);
+ src->doc_y = SANE_UNFIX (src->y_range.max);
+ }
+
+ value = value << 1;
+ if (0 != value)
+ {
+ err_minor ("device detected multiple document sizes!\n");
+ }
+
+ log_info ("detected document size: %s (%.2fmm x %.2fmm)",
+ doc_size[i].label, src->doc_x, src->doc_y);
+}
+
+int
+microsleep (size_t usec)
+{
+ struct timespec ts;
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+
+ return nanosleep (&ts, NULL);
+}