/* 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 . * * * 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 #endif #include "utils.h" #include #include #include /* 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); }