1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2019 Touboul Nathane 4141cc406Sopenharmony_ci Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com> 5141cc406Sopenharmony_ci 6141cc406Sopenharmony_ci This file is part of the SANE package. 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci SANE is free software; you can redistribute it and/or modify it under 9141cc406Sopenharmony_ci the terms of the GNU General Public License as published by the Free 10141cc406Sopenharmony_ci Software Foundation; either version 3 of the License, or (at your 11141cc406Sopenharmony_ci option) any later version. 12141cc406Sopenharmony_ci 13141cc406Sopenharmony_ci SANE is distributed in the hope that it will be useful, but WITHOUT 14141cc406Sopenharmony_ci ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15141cc406Sopenharmony_ci FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16141cc406Sopenharmony_ci for more details. 17141cc406Sopenharmony_ci 18141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 19141cc406Sopenharmony_ci along with sane; see the file COPYING. 20141cc406Sopenharmony_ci If not, see <https://www.gnu.org/licenses/>. 21141cc406Sopenharmony_ci 22141cc406Sopenharmony_ci This file implements a SANE backend for eSCL scanners. */ 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 25141cc406Sopenharmony_ci#include "../include/sane/config.h" 26141cc406Sopenharmony_ci 27141cc406Sopenharmony_ci#include "escl.h" 28141cc406Sopenharmony_ci 29141cc406Sopenharmony_ci#include <stdio.h> 30141cc406Sopenharmony_ci#include <stdlib.h> 31141cc406Sopenharmony_ci#include <string.h> 32141cc406Sopenharmony_ci 33141cc406Sopenharmony_ci#include <libxml/parser.h> 34141cc406Sopenharmony_ci 35141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_cistruct cap 38141cc406Sopenharmony_ci{ 39141cc406Sopenharmony_ci char *memory; 40141cc406Sopenharmony_ci size_t size; 41141cc406Sopenharmony_ci}; 42141cc406Sopenharmony_ci 43141cc406Sopenharmony_cistatic size_t 44141cc406Sopenharmony_ciheader_callback(void *str, size_t size, size_t nmemb, void *userp) 45141cc406Sopenharmony_ci{ 46141cc406Sopenharmony_ci struct cap *header = (struct cap *)userp; 47141cc406Sopenharmony_ci size_t realsize = size * nmemb; 48141cc406Sopenharmony_ci char *content = realloc(header->memory, header->size + realsize + 1); 49141cc406Sopenharmony_ci 50141cc406Sopenharmony_ci if (content == NULL) { 51141cc406Sopenharmony_ci DBG( 1, "Not enough memory (realloc returned NULL)\n"); 52141cc406Sopenharmony_ci return (0); 53141cc406Sopenharmony_ci } 54141cc406Sopenharmony_ci header->memory = content; 55141cc406Sopenharmony_ci memcpy(&(header->memory[header->size]), str, realsize); 56141cc406Sopenharmony_ci header->size = header->size + realsize; 57141cc406Sopenharmony_ci header->memory[header->size] = 0; 58141cc406Sopenharmony_ci return (realsize); 59141cc406Sopenharmony_ci} 60141cc406Sopenharmony_ci 61141cc406Sopenharmony_ci 62141cc406Sopenharmony_ci/** 63141cc406Sopenharmony_ci * \fn static SANE_String_Const convert_elements(SANE_String_Const str) 64141cc406Sopenharmony_ci * \brief Function that converts the 'color modes' of the scanner (color/gray) to be understood by SANE. 65141cc406Sopenharmony_ci * 66141cc406Sopenharmony_ci * \return SANE_VALUE_SCAN_MODE_GRAY / SANE_VALUE_SCAN_MODE_COLOR / SANE_VALUE_SCAN_MODE_LINEART; NULL otherwise 67141cc406Sopenharmony_ci */ 68141cc406Sopenharmony_cistatic SANE_String_Const 69141cc406Sopenharmony_ciconvert_elements(SANE_String_Const str) 70141cc406Sopenharmony_ci{ 71141cc406Sopenharmony_ci if (strcmp(str, "Grayscale8") == 0) 72141cc406Sopenharmony_ci return (SANE_VALUE_SCAN_MODE_GRAY); 73141cc406Sopenharmony_ci else if (strcmp(str, "RGB24") == 0) 74141cc406Sopenharmony_ci return (SANE_VALUE_SCAN_MODE_COLOR); 75141cc406Sopenharmony_ci#if(defined HAVE_POPPLER_GLIB) 76141cc406Sopenharmony_ci else if (strcmp(str, "BlackAndWhite1") == 0) 77141cc406Sopenharmony_ci return (SANE_VALUE_SCAN_MODE_LINEART); 78141cc406Sopenharmony_ci#endif 79141cc406Sopenharmony_ci return (NULL); 80141cc406Sopenharmony_ci} 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci/** 83141cc406Sopenharmony_ci * \fn static SANE_String_Const *char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array) 84141cc406Sopenharmony_ci * \brief Function that creates the character arrays to put inside : 85141cc406Sopenharmony_ci * the 'color modes', the 'content types', the 'document formats' and the 'supported intents'. 86141cc406Sopenharmony_ci * 87141cc406Sopenharmony_ci * \return board (the allocated array) 88141cc406Sopenharmony_ci */ 89141cc406Sopenharmony_cistatic SANE_String_Const * 90141cc406Sopenharmony_cichar_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array) 91141cc406Sopenharmony_ci{ 92141cc406Sopenharmony_ci SANE_String_Const *board = NULL; 93141cc406Sopenharmony_ci int i = 0; 94141cc406Sopenharmony_ci SANE_String_Const convert = NULL; 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci if (mode == NULL) 97141cc406Sopenharmony_ci return (tab); 98141cc406Sopenharmony_ci if (good_array != 0) { 99141cc406Sopenharmony_ci convert = convert_elements(mode); 100141cc406Sopenharmony_ci if (convert == NULL) 101141cc406Sopenharmony_ci return (tab); 102141cc406Sopenharmony_ci } 103141cc406Sopenharmony_ci else 104141cc406Sopenharmony_ci convert = mode; 105141cc406Sopenharmony_ci for (i = 0; i < (*tabsize); i++) { 106141cc406Sopenharmony_ci if (strcmp(tab[i], convert) == 0) 107141cc406Sopenharmony_ci return (tab); 108141cc406Sopenharmony_ci } 109141cc406Sopenharmony_ci (*tabsize)++; 110141cc406Sopenharmony_ci if (*tabsize == 1) 111141cc406Sopenharmony_ci board = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * ((*tabsize) + 1)); 112141cc406Sopenharmony_ci else 113141cc406Sopenharmony_ci board = (SANE_String_Const *)realloc(tab, sizeof(SANE_String_Const) * ((*tabsize) + 1)); 114141cc406Sopenharmony_ci board[*tabsize - 1] = (SANE_String_Const)strdup(convert); 115141cc406Sopenharmony_ci board[*tabsize] = NULL; 116141cc406Sopenharmony_ci return (board); 117141cc406Sopenharmony_ci} 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ci/** 120141cc406Sopenharmony_ci * \fn static SANE_Int *int_to_array(SANE_Int *tab, int *tabsize, int cont) 121141cc406Sopenharmony_ci * \brief Function that creates the integer array to put inside the 'supported resolutions'. 122141cc406Sopenharmony_ci * 123141cc406Sopenharmony_ci * \return board (the allocated array) 124141cc406Sopenharmony_ci */ 125141cc406Sopenharmony_cistatic SANE_Int * 126141cc406Sopenharmony_ciint_to_array(SANE_Int *tab, int *tabsize, int cont) 127141cc406Sopenharmony_ci{ 128141cc406Sopenharmony_ci SANE_Int *board = NULL; 129141cc406Sopenharmony_ci int i = 0; 130141cc406Sopenharmony_ci 131141cc406Sopenharmony_ci for (i = 0; i < (*tabsize); i++) { 132141cc406Sopenharmony_ci if (tab[i] == cont) 133141cc406Sopenharmony_ci return (tab); 134141cc406Sopenharmony_ci } 135141cc406Sopenharmony_ci (*tabsize)++; 136141cc406Sopenharmony_ci if (*tabsize == 1) { 137141cc406Sopenharmony_ci (*tabsize)++; 138141cc406Sopenharmony_ci board = malloc(sizeof(SANE_Int *) * (*tabsize) + 1); 139141cc406Sopenharmony_ci } 140141cc406Sopenharmony_ci else 141141cc406Sopenharmony_ci board = realloc(tab, sizeof(SANE_Int *) * (*tabsize) + 1); 142141cc406Sopenharmony_ci board[0] = *tabsize - 1; 143141cc406Sopenharmony_ci board[*tabsize - 1] = cont; 144141cc406Sopenharmony_ci board[*tabsize] = -1; 145141cc406Sopenharmony_ci return (board); 146141cc406Sopenharmony_ci} 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci/** 149141cc406Sopenharmony_ci * \fn static size_t memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) 150141cc406Sopenharmony_ci * \brief Callback function that stocks in memory the content of the scanner capabilities. 151141cc406Sopenharmony_ci * 152141cc406Sopenharmony_ci * \return realsize (size of the content needed -> the scanner capabilities) 153141cc406Sopenharmony_ci */ 154141cc406Sopenharmony_cistatic size_t 155141cc406Sopenharmony_cimemory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) 156141cc406Sopenharmony_ci{ 157141cc406Sopenharmony_ci size_t realsize = size * nmemb; 158141cc406Sopenharmony_ci struct cap *mem = (struct cap *)userp; 159141cc406Sopenharmony_ci 160141cc406Sopenharmony_ci char *str = realloc(mem->memory, mem->size + realsize + 1); 161141cc406Sopenharmony_ci if (str == NULL) { 162141cc406Sopenharmony_ci DBG(10, "not enough memory (realloc returned NULL)\n"); 163141cc406Sopenharmony_ci return (0); 164141cc406Sopenharmony_ci } 165141cc406Sopenharmony_ci mem->memory = str; 166141cc406Sopenharmony_ci memcpy(&(mem->memory[mem->size]), contents, realsize); 167141cc406Sopenharmony_ci mem->size = mem->size + realsize; 168141cc406Sopenharmony_ci mem->memory[mem->size] = 0; 169141cc406Sopenharmony_ci return (realsize); 170141cc406Sopenharmony_ci} 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ci/** 173141cc406Sopenharmony_ci * \fn static int find_nodes_c(xmlNode *node) 174141cc406Sopenharmony_ci * \brief Function that browses the xml file and parses it, to find the xml children node. 175141cc406Sopenharmony_ci * --> to recover the scanner capabilities. 176141cc406Sopenharmony_ci * 177141cc406Sopenharmony_ci * \return 0 if a xml child node is found, 1 otherwise 178141cc406Sopenharmony_ci */ 179141cc406Sopenharmony_cistatic int 180141cc406Sopenharmony_cifind_nodes_c(xmlNode *node) 181141cc406Sopenharmony_ci{ 182141cc406Sopenharmony_ci xmlNode *child = node->children; 183141cc406Sopenharmony_ci 184141cc406Sopenharmony_ci while (child) { 185141cc406Sopenharmony_ci if (child->type == XML_ELEMENT_NODE) 186141cc406Sopenharmony_ci return (0); 187141cc406Sopenharmony_ci child = child->next; 188141cc406Sopenharmony_ci } 189141cc406Sopenharmony_ci return (1); 190141cc406Sopenharmony_ci} 191141cc406Sopenharmony_ci 192141cc406Sopenharmony_ci/** 193141cc406Sopenharmony_ci * \fn static int find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner) 194141cc406Sopenharmony_ci * \brief Function that searches in the xml file if a scanner capabilitie stocked 195141cc406Sopenharmony_ci * in one of the created array (character/integer array) is found. 196141cc406Sopenharmony_ci * 197141cc406Sopenharmony_ci * \return 0 198141cc406Sopenharmony_ci */ 199141cc406Sopenharmony_cistatic int 200141cc406Sopenharmony_cifind_valor_of_array_variables(xmlNode *node, capabilities_t *scanner, int type) 201141cc406Sopenharmony_ci{ 202141cc406Sopenharmony_ci const char *name = (const char *)node->name; 203141cc406Sopenharmony_ci if (strcmp(name, "ColorMode") == 0) { 204141cc406Sopenharmony_ci const char *color = (SANE_String_Const)xmlNodeGetContent(node); 205141cc406Sopenharmony_ci if (type == PLATEN || strcmp(color, "BlackAndWhite1")) 206141cc406Sopenharmony_ci scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, &scanner->caps[type].ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1); 207141cc406Sopenharmony_ci } 208141cc406Sopenharmony_ci else if (strcmp(name, "ContentType") == 0) 209141cc406Sopenharmony_ci scanner->caps[type].ContentTypes = char_to_array(scanner->caps[type].ContentTypes, &scanner->caps[type].ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0); 210141cc406Sopenharmony_ci else if (strcmp(name, "DocumentFormat") == 0) 211141cc406Sopenharmony_ci { 212141cc406Sopenharmony_ci int i = 0; 213141cc406Sopenharmony_ci SANE_Bool have_jpeg = SANE_FALSE, have_png = SANE_FALSE, have_tiff = SANE_FALSE, have_pdf = SANE_FALSE; 214141cc406Sopenharmony_ci scanner->caps[type].DocumentFormats = char_to_array(scanner->caps[type].DocumentFormats, &scanner->caps[type].DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0); 215141cc406Sopenharmony_ci scanner->caps[type].have_jpeg = -1; 216141cc406Sopenharmony_ci scanner->caps[type].have_png = -1; 217141cc406Sopenharmony_ci scanner->caps[type].have_tiff = -1; 218141cc406Sopenharmony_ci scanner->caps[type].have_pdf = -1; 219141cc406Sopenharmony_ci for(; i < scanner->caps[type].DocumentFormatsSize; i++) 220141cc406Sopenharmony_ci { 221141cc406Sopenharmony_ci if (!strcmp(scanner->caps[type].DocumentFormats[i], "image/jpeg")) 222141cc406Sopenharmony_ci { 223141cc406Sopenharmony_ci have_jpeg = SANE_TRUE; 224141cc406Sopenharmony_ci scanner->caps[type].have_jpeg = i; 225141cc406Sopenharmony_ci } 226141cc406Sopenharmony_ci#if(defined HAVE_LIBPNG) 227141cc406Sopenharmony_ci else if(!strcmp(scanner->caps[type].DocumentFormats[i], "image/png")) 228141cc406Sopenharmony_ci { 229141cc406Sopenharmony_ci have_png = SANE_TRUE; 230141cc406Sopenharmony_ci scanner->caps[type].have_png = i; 231141cc406Sopenharmony_ci } 232141cc406Sopenharmony_ci#endif 233141cc406Sopenharmony_ci#if(defined HAVE_TIFFIO_H) 234141cc406Sopenharmony_ci else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "image/tiff")) 235141cc406Sopenharmony_ci { 236141cc406Sopenharmony_ci have_tiff = SANE_TRUE; 237141cc406Sopenharmony_ci scanner->caps[type].have_tiff = i; 238141cc406Sopenharmony_ci } 239141cc406Sopenharmony_ci#endif 240141cc406Sopenharmony_ci#if(defined HAVE_POPPLER_GLIB) 241141cc406Sopenharmony_ci else if(type == PLATEN && !strcmp(scanner->caps[type].DocumentFormats[i], "application/pdf")) 242141cc406Sopenharmony_ci { 243141cc406Sopenharmony_ci have_pdf = SANE_TRUE; 244141cc406Sopenharmony_ci scanner->caps[type].have_pdf = i; 245141cc406Sopenharmony_ci } 246141cc406Sopenharmony_ci#endif 247141cc406Sopenharmony_ci } 248141cc406Sopenharmony_ci if (have_pdf) 249141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("application/pdf"); 250141cc406Sopenharmony_ci else if (have_tiff) 251141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/tiff"); 252141cc406Sopenharmony_ci else if (have_png) 253141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/png"); 254141cc406Sopenharmony_ci else if (have_jpeg) 255141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/jpeg"); 256141cc406Sopenharmony_ci } 257141cc406Sopenharmony_ci else if (strcmp(name, "DocumentFormatExt") == 0) 258141cc406Sopenharmony_ci scanner->caps[type].format_ext = 1; 259141cc406Sopenharmony_ci else if (strcmp(name, "Intent") == 0) 260141cc406Sopenharmony_ci scanner->caps[type].SupportedIntents = char_to_array(scanner->caps[type].SupportedIntents, &scanner->caps[type].SupportedIntentsSize, (SANE_String_Const)xmlNodeGetContent(node), 0); 261141cc406Sopenharmony_ci else if (strcmp(name, "XResolution") == 0) 262141cc406Sopenharmony_ci scanner->caps[type].SupportedResolutions = int_to_array(scanner->caps[type].SupportedResolutions, &scanner->caps[type].SupportedResolutionsSize, atoi((const char *)xmlNodeGetContent(node))); 263141cc406Sopenharmony_ci return (0); 264141cc406Sopenharmony_ci} 265141cc406Sopenharmony_ci 266141cc406Sopenharmony_ci/** 267141cc406Sopenharmony_ci * \fn static int find_value_of_int_variables(xmlNode *node, capabilities_t *scanner) 268141cc406Sopenharmony_ci * \brief Function that searches in the xml file if a integer scanner capabilitie is found. 269141cc406Sopenharmony_ci * The integer scanner capabilities that are interesting are : 270141cc406Sopenharmony_ci * MinWidth, MaxWidth, MaxHeight, MinHeight, MaxScanRegions, MaxOpticalXResolution, 271141cc406Sopenharmony_ci * RiskyLeftMargin, RiskyRightMargin, RiskyTopMargin, RiskyBottomMargin. 272141cc406Sopenharmony_ci * 273141cc406Sopenharmony_ci * \return 0 274141cc406Sopenharmony_ci */ 275141cc406Sopenharmony_cistatic int 276141cc406Sopenharmony_cifind_value_of_int_variables(xmlNode *node, capabilities_t *scanner, int type) 277141cc406Sopenharmony_ci{ 278141cc406Sopenharmony_ci int MaxWidth = 0; 279141cc406Sopenharmony_ci int MaxHeight = 0; 280141cc406Sopenharmony_ci const char *name = (const char *)node->name; 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_ci if (strcmp(name, "MinWidth") == 0) 283141cc406Sopenharmony_ci scanner->caps[type].MinWidth = atoi((const char*)xmlNodeGetContent(node)); 284141cc406Sopenharmony_ci else if (strcmp(name, "MaxWidth") == 0) { 285141cc406Sopenharmony_ci MaxWidth = atoi((const char*)xmlNodeGetContent(node)); 286141cc406Sopenharmony_ci if (scanner->caps[type].MaxWidth == 0 || MaxWidth < scanner->caps[type].MaxWidth) 287141cc406Sopenharmony_ci scanner->caps[type].MaxWidth = atoi((const char *)xmlNodeGetContent(node)); 288141cc406Sopenharmony_ci } 289141cc406Sopenharmony_ci else if (strcmp(name, "MinHeight") == 0) 290141cc406Sopenharmony_ci scanner->caps[type].MinHeight = atoi((const char*)xmlNodeGetContent(node)); 291141cc406Sopenharmony_ci else if (strcmp(name, "MaxHeight") == 0) { 292141cc406Sopenharmony_ci MaxHeight = atoi((const char*)xmlNodeGetContent(node)); 293141cc406Sopenharmony_ci if (scanner->caps[type].MaxHeight == 0 || MaxHeight < scanner->caps[type].MaxHeight) 294141cc406Sopenharmony_ci scanner->caps[type].MaxHeight = atoi((const char *)xmlNodeGetContent(node)); 295141cc406Sopenharmony_ci } 296141cc406Sopenharmony_ci else if (strcmp(name, "MaxScanRegions") == 0) 297141cc406Sopenharmony_ci scanner->caps[type].MaxScanRegions = atoi((const char *)xmlNodeGetContent(node)); 298141cc406Sopenharmony_ci else if (strcmp(name, "MaxOpticalXResolution") == 0) 299141cc406Sopenharmony_ci scanner->caps[type].MaxOpticalXResolution = atoi((const char *)xmlNodeGetContent(node)); 300141cc406Sopenharmony_ci else if (strcmp(name, "RiskyLeftMargin") == 0) 301141cc406Sopenharmony_ci scanner->caps[type].RiskyLeftMargin = atoi((const char *)xmlNodeGetContent(node)); 302141cc406Sopenharmony_ci else if (strcmp(name, "RiskyRightMargin") == 0) 303141cc406Sopenharmony_ci scanner->caps[type].RiskyRightMargin = atoi((const char *)xmlNodeGetContent(node)); 304141cc406Sopenharmony_ci else if (strcmp(name, "RiskyTopMargin") == 0) 305141cc406Sopenharmony_ci scanner->caps[type].RiskyTopMargin = atoi((const char *)xmlNodeGetContent(node)); 306141cc406Sopenharmony_ci else if (strcmp(name, "RiskyBottomMargin") == 0) 307141cc406Sopenharmony_ci scanner->caps[type].RiskyBottomMargin = atoi((const char *)xmlNodeGetContent(node)); 308141cc406Sopenharmony_ci find_valor_of_array_variables(node, scanner, type); 309141cc406Sopenharmony_ci return (0); 310141cc406Sopenharmony_ci} 311141cc406Sopenharmony_ci 312141cc406Sopenharmony_cistatic support_t* 313141cc406Sopenharmony_ciprint_support(xmlNode *node) 314141cc406Sopenharmony_ci{ 315141cc406Sopenharmony_ci support_t *sup = (support_t*)calloc(1, sizeof(support_t)); 316141cc406Sopenharmony_ci int cpt = 0; 317141cc406Sopenharmony_ci int have_norm = 0; 318141cc406Sopenharmony_ci while (node) { 319141cc406Sopenharmony_ci if (!strcmp((const char *)node->name, "Min")){ 320141cc406Sopenharmony_ci sup->min = atoi((const char *)xmlNodeGetContent(node)); 321141cc406Sopenharmony_ci cpt++; 322141cc406Sopenharmony_ci } 323141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "Max")) { 324141cc406Sopenharmony_ci sup->max = atoi((const char *)xmlNodeGetContent(node)); 325141cc406Sopenharmony_ci cpt++; 326141cc406Sopenharmony_ci } 327141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "Normal")) { 328141cc406Sopenharmony_ci sup->value = atoi((const char *)xmlNodeGetContent(node)); 329141cc406Sopenharmony_ci sup->normal = sup->value; 330141cc406Sopenharmony_ci cpt++; 331141cc406Sopenharmony_ci have_norm = 1; 332141cc406Sopenharmony_ci } 333141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "Step")) { 334141cc406Sopenharmony_ci sup->step = atoi((const char *)xmlNodeGetContent(node)); 335141cc406Sopenharmony_ci cpt++; 336141cc406Sopenharmony_ci } 337141cc406Sopenharmony_ci node = node->next; 338141cc406Sopenharmony_ci } 339141cc406Sopenharmony_ci if (cpt == 4) 340141cc406Sopenharmony_ci return sup; 341141cc406Sopenharmony_ci if (cpt == 3 && have_norm == 0) { 342141cc406Sopenharmony_ci sup->value = (sup->max / 2 ); 343141cc406Sopenharmony_ci sup->normal = sup->value; 344141cc406Sopenharmony_ci return sup; 345141cc406Sopenharmony_ci } 346141cc406Sopenharmony_ci free(sup); 347141cc406Sopenharmony_ci return NULL; 348141cc406Sopenharmony_ci} 349141cc406Sopenharmony_ci 350141cc406Sopenharmony_cistatic int 351141cc406Sopenharmony_cifind_struct_variables(xmlNode *node, capabilities_t *scanner) 352141cc406Sopenharmony_ci{ 353141cc406Sopenharmony_ci const char *name = (const char *)node->name; 354141cc406Sopenharmony_ci if (strcmp(name, "BrightnessSupport") == 0) { 355141cc406Sopenharmony_ci scanner->brightness = 356141cc406Sopenharmony_ci print_support(node->children); 357141cc406Sopenharmony_ci return 1; 358141cc406Sopenharmony_ci } 359141cc406Sopenharmony_ci else if (strcmp(name, "ContrastSupport") == 0) { 360141cc406Sopenharmony_ci scanner->contrast = 361141cc406Sopenharmony_ci print_support(node->children); 362141cc406Sopenharmony_ci return 1; 363141cc406Sopenharmony_ci } 364141cc406Sopenharmony_ci else if (strcmp(name, "SharpenSupport") == 0) { 365141cc406Sopenharmony_ci scanner->sharpen = 366141cc406Sopenharmony_ci print_support(node->children); 367141cc406Sopenharmony_ci return 1; 368141cc406Sopenharmony_ci } 369141cc406Sopenharmony_ci else if (strcmp(name, "ThresholdSupport") == 0) { 370141cc406Sopenharmony_ci scanner->threshold = 371141cc406Sopenharmony_ci print_support(node->children); 372141cc406Sopenharmony_ci return 1; 373141cc406Sopenharmony_ci } 374141cc406Sopenharmony_ci return (0); 375141cc406Sopenharmony_ci} 376141cc406Sopenharmony_ci 377141cc406Sopenharmony_ci/** 378141cc406Sopenharmony_ci * \fn static int find_true_variables(xmlNode *node, capabilities_t *scanner) 379141cc406Sopenharmony_ci * \brief Function that searches in the xml file if we find a scanner capability stored 380141cc406Sopenharmony_ci * in one of the created array (character/integer array), 381141cc406Sopenharmony_ci * or, if we find a integer scanner capability. 382141cc406Sopenharmony_ci * 383141cc406Sopenharmony_ci * \return 0 384141cc406Sopenharmony_ci */ 385141cc406Sopenharmony_cistatic int 386141cc406Sopenharmony_cifind_true_variables(xmlNode *node, capabilities_t *scanner, int type) 387141cc406Sopenharmony_ci{ 388141cc406Sopenharmony_ci const char *name = (const char *)node->name; 389141cc406Sopenharmony_ci if (strcmp(name, "MinWidth") == 0 || 390141cc406Sopenharmony_ci strcmp(name, "MaxWidth") == 0 || 391141cc406Sopenharmony_ci strcmp(name, "MinHeight") == 0 || 392141cc406Sopenharmony_ci strcmp(name, "MaxHeight") == 0 || 393141cc406Sopenharmony_ci strcmp(name, "MaxScanRegions") == 0 || 394141cc406Sopenharmony_ci strcmp(name, "ColorMode") == 0 || 395141cc406Sopenharmony_ci strcmp(name, "ContentType") == 0 || 396141cc406Sopenharmony_ci strcmp(name, "DocumentFormat") == 0 || 397141cc406Sopenharmony_ci strcmp(name, "XResolution") == 0 || 398141cc406Sopenharmony_ci strcmp(name, "Intent") == 0 || 399141cc406Sopenharmony_ci strcmp(name, "MaxOpticalXResolution") == 0 || 400141cc406Sopenharmony_ci strcmp(name, "RiskyLeftMargin") == 0 || 401141cc406Sopenharmony_ci strcmp(name, "RiskyRightMargin") == 0 || 402141cc406Sopenharmony_ci strcmp(name, "RiskyTopMargin") == 0 || 403141cc406Sopenharmony_ci strcmp(name, "RiskyBottomMargin") == 0 || 404141cc406Sopenharmony_ci strcmp(name, "DocumentFormatExt") == 0) 405141cc406Sopenharmony_ci find_value_of_int_variables(node, scanner, type); 406141cc406Sopenharmony_ci return (0); 407141cc406Sopenharmony_ci} 408141cc406Sopenharmony_ci 409141cc406Sopenharmony_cistatic char* 410141cc406Sopenharmony_cireplace_char(char* str, char find, char replace){ 411141cc406Sopenharmony_ci char *current_pos = strchr(str,find); 412141cc406Sopenharmony_ci while (current_pos) { 413141cc406Sopenharmony_ci *current_pos = replace; 414141cc406Sopenharmony_ci current_pos = strchr(current_pos,find); 415141cc406Sopenharmony_ci } 416141cc406Sopenharmony_ci return str; 417141cc406Sopenharmony_ci} 418141cc406Sopenharmony_ci 419141cc406Sopenharmony_ci/** 420141cc406Sopenharmony_ci * \fn static int print_xml_c(xmlNode *node, capabilities_t *scanner) 421141cc406Sopenharmony_ci * \brief Function that browses the xml file, node by node. 422141cc406Sopenharmony_ci * 423141cc406Sopenharmony_ci * \return 0 424141cc406Sopenharmony_ci */ 425141cc406Sopenharmony_cistatic int 426141cc406Sopenharmony_ciprint_xml_c(xmlNode *node, ESCL_Device *device, capabilities_t *scanner, int type) 427141cc406Sopenharmony_ci{ 428141cc406Sopenharmony_ci while (node) { 429141cc406Sopenharmony_ci if (node->type == XML_ELEMENT_NODE) { 430141cc406Sopenharmony_ci if (find_nodes_c(node) && type != -1) 431141cc406Sopenharmony_ci find_true_variables(node, scanner, type); 432141cc406Sopenharmony_ci } 433141cc406Sopenharmony_ci if (!strcmp((const char *)node->name, "Version")&& node->ns && node->ns->prefix){ 434141cc406Sopenharmony_ci if (!strcmp((const char*)node->ns->prefix, "pwg")) 435141cc406Sopenharmony_ci device->version = atof ((const char *)xmlNodeGetContent(node)); 436141cc406Sopenharmony_ci } 437141cc406Sopenharmony_ci if (!strcmp((const char *)node->name, "MakeAndModel")){ 438141cc406Sopenharmony_ci device->model_name = strdup((const char *)xmlNodeGetContent(node)); 439141cc406Sopenharmony_ci } 440141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "PlatenInputCaps")) { 441141cc406Sopenharmony_ci scanner->Sources[PLATEN] = (SANE_String_Const)strdup(SANE_I18N ("Flatbed")); 442141cc406Sopenharmony_ci scanner->SourcesSize++; 443141cc406Sopenharmony_ci scanner->source = PLATEN; 444141cc406Sopenharmony_ci print_xml_c(node->children, device, scanner, PLATEN); 445141cc406Sopenharmony_ci scanner->caps[PLATEN].duplex = 0; 446141cc406Sopenharmony_ci } 447141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "AdfSimplexInputCaps")) { 448141cc406Sopenharmony_ci scanner->Sources[ADFSIMPLEX] = (SANE_String_Const)strdup(SANE_I18N("ADF")); 449141cc406Sopenharmony_ci scanner->SourcesSize++; 450141cc406Sopenharmony_ci if (scanner->source == -1) scanner->source = ADFSIMPLEX; 451141cc406Sopenharmony_ci print_xml_c(node->children, device, scanner, ADFSIMPLEX); 452141cc406Sopenharmony_ci scanner->caps[ADFSIMPLEX].duplex = 0; 453141cc406Sopenharmony_ci } 454141cc406Sopenharmony_ci else if (!strcmp((const char *)node->name, "AdfDuplexInputCaps")) { 455141cc406Sopenharmony_ci scanner->Sources[ADFDUPLEX] = (SANE_String_Const)strdup(SANE_I18N ("ADF Duplex")); 456141cc406Sopenharmony_ci scanner->SourcesSize++; 457141cc406Sopenharmony_ci if (scanner->source == -1) scanner->source = ADFDUPLEX; 458141cc406Sopenharmony_ci print_xml_c(node->children, device, scanner, ADFDUPLEX); 459141cc406Sopenharmony_ci scanner->caps[ADFDUPLEX].duplex = 1; 460141cc406Sopenharmony_ci } 461141cc406Sopenharmony_ci else if (find_struct_variables(node, scanner) == 0) 462141cc406Sopenharmony_ci print_xml_c(node->children, device, scanner, type); 463141cc406Sopenharmony_ci node = node->next; 464141cc406Sopenharmony_ci } 465141cc406Sopenharmony_ci return (0); 466141cc406Sopenharmony_ci} 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_cistatic void 469141cc406Sopenharmony_ci_reduce_color_modes(capabilities_t *scanner) 470141cc406Sopenharmony_ci{ 471141cc406Sopenharmony_ci int type = 0; 472141cc406Sopenharmony_ci for (type = 0; type < 3; type++) { 473141cc406Sopenharmony_ci if (scanner->caps[type].ColorModesSize) { 474141cc406Sopenharmony_ci if (scanner->caps[type].default_format && 475141cc406Sopenharmony_ci strcmp(scanner->caps[type].default_format, "application/pdf")) { 476141cc406Sopenharmony_ci if (scanner->caps[type].ColorModesSize == 3) { 477141cc406Sopenharmony_ci free(scanner->caps[type].ColorModes); 478141cc406Sopenharmony_ci scanner->caps[type].ColorModes = NULL; 479141cc406Sopenharmony_ci scanner->caps[type].ColorModesSize = 0; 480141cc406Sopenharmony_ci scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, 481141cc406Sopenharmony_ci &scanner->caps[type].ColorModesSize, 482141cc406Sopenharmony_ci (SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0); 483141cc406Sopenharmony_ci scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, 484141cc406Sopenharmony_ci &scanner->caps[type].ColorModesSize, 485141cc406Sopenharmony_ci (SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0); 486141cc406Sopenharmony_ci } 487141cc406Sopenharmony_ci } 488141cc406Sopenharmony_ci } 489141cc406Sopenharmony_ci } 490141cc406Sopenharmony_ci} 491141cc406Sopenharmony_ci 492141cc406Sopenharmony_cistatic void 493141cc406Sopenharmony_ci_delete_pdf(capabilities_t *scanner) 494141cc406Sopenharmony_ci{ 495141cc406Sopenharmony_ci int type = 0; 496141cc406Sopenharmony_ci for (type = 0; type < 3; type++) { 497141cc406Sopenharmony_ci if (scanner->caps[type].ColorModesSize) { 498141cc406Sopenharmony_ci if (scanner->caps[type].default_format) { 499141cc406Sopenharmony_ci scanner->caps[type].have_pdf = -1; 500141cc406Sopenharmony_ci if (!strcmp(scanner->caps[type].default_format, "application/pdf")) { 501141cc406Sopenharmony_ci free(scanner->caps[type].default_format); 502141cc406Sopenharmony_ci if (scanner->caps[type].have_tiff > -1) 503141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/tiff"); 504141cc406Sopenharmony_ci else if (scanner->caps[type].have_png > -1) 505141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/png"); 506141cc406Sopenharmony_ci else if (scanner->caps[type].have_jpeg > -1) 507141cc406Sopenharmony_ci scanner->caps[type].default_format = strdup("image/jpeg"); 508141cc406Sopenharmony_ci } 509141cc406Sopenharmony_ci free(scanner->caps[type].ColorModes); 510141cc406Sopenharmony_ci scanner->caps[type].ColorModes = NULL; 511141cc406Sopenharmony_ci scanner->caps[type].ColorModesSize = 0; 512141cc406Sopenharmony_ci scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, 513141cc406Sopenharmony_ci &scanner->caps[type].ColorModesSize, 514141cc406Sopenharmony_ci (SANE_String_Const)SANE_VALUE_SCAN_MODE_GRAY, 0); 515141cc406Sopenharmony_ci scanner->caps[type].ColorModes = char_to_array(scanner->caps[type].ColorModes, 516141cc406Sopenharmony_ci &scanner->caps[type].ColorModesSize, 517141cc406Sopenharmony_ci (SANE_String_Const)SANE_VALUE_SCAN_MODE_COLOR, 0); 518141cc406Sopenharmony_ci } 519141cc406Sopenharmony_ci } 520141cc406Sopenharmony_ci } 521141cc406Sopenharmony_ci} 522141cc406Sopenharmony_ci 523141cc406Sopenharmony_ci/** 524141cc406Sopenharmony_ci * \fn capabilities_t *escl_capabilities(const ESCL_Device *device, SANE_Status *status) 525141cc406Sopenharmony_ci * \brief Function that finally recovers all the capabilities of the scanner, using curl. 526141cc406Sopenharmony_ci * This function is called in the 'sane_open' function and it's the equivalent of 527141cc406Sopenharmony_ci * the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerCapabilities". 528141cc406Sopenharmony_ci * 529141cc406Sopenharmony_ci * \return scanner (the structure that stocks all the capabilities elements) 530141cc406Sopenharmony_ci */ 531141cc406Sopenharmony_cicapabilities_t * 532141cc406Sopenharmony_ciescl_capabilities(ESCL_Device *device, char *blacklist, SANE_Status *status) 533141cc406Sopenharmony_ci{ 534141cc406Sopenharmony_ci capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t)); 535141cc406Sopenharmony_ci CURL *curl_handle = NULL; 536141cc406Sopenharmony_ci struct cap *var = NULL; 537141cc406Sopenharmony_ci struct cap *header = NULL; 538141cc406Sopenharmony_ci xmlDoc *data = NULL; 539141cc406Sopenharmony_ci xmlNode *node = NULL; 540141cc406Sopenharmony_ci int i = 0; 541141cc406Sopenharmony_ci const char *scanner_capabilities = "/eSCL/ScannerCapabilities"; 542141cc406Sopenharmony_ci SANE_Bool use_pdf = SANE_TRUE; 543141cc406Sopenharmony_ci 544141cc406Sopenharmony_ci *status = SANE_STATUS_GOOD; 545141cc406Sopenharmony_ci if (device == NULL) 546141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 547141cc406Sopenharmony_ci var = (struct cap *)calloc(1, sizeof(struct cap)); 548141cc406Sopenharmony_ci if (var == NULL) 549141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 550141cc406Sopenharmony_ci var->memory = malloc(1); 551141cc406Sopenharmony_ci var->size = 0; 552141cc406Sopenharmony_ci header = (struct cap *)calloc(1, sizeof(struct cap)); 553141cc406Sopenharmony_ci if (header == NULL) 554141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 555141cc406Sopenharmony_ci header->memory = malloc(1); 556141cc406Sopenharmony_ci header->size = 0; 557141cc406Sopenharmony_ci curl_handle = curl_easy_init(); 558141cc406Sopenharmony_ci escl_curl_url(curl_handle, device, scanner_capabilities); 559141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c); 560141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); 561141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); 562141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)header); 563141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); 564141cc406Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 3L); 565141cc406Sopenharmony_ci CURLcode res = curl_easy_perform(curl_handle); 566141cc406Sopenharmony_ci if (res == CURLE_OK) 567141cc406Sopenharmony_ci DBG( 1, "Create NewJob : the scanner header responded : [%s]\n", header->memory); 568141cc406Sopenharmony_ci if (res != CURLE_OK) { 569141cc406Sopenharmony_ci DBG( 1, "The scanner didn't respond: %s\n", curl_easy_strerror(res)); 570141cc406Sopenharmony_ci *status = SANE_STATUS_INVAL; 571141cc406Sopenharmony_ci goto clean_data; 572141cc406Sopenharmony_ci } 573141cc406Sopenharmony_ci DBG( 10, "XML Capabilities[\n%s\n]\n", var->memory); 574141cc406Sopenharmony_ci data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0); 575141cc406Sopenharmony_ci if (data == NULL) { 576141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 577141cc406Sopenharmony_ci goto clean_data; 578141cc406Sopenharmony_ci } 579141cc406Sopenharmony_ci node = xmlDocGetRootElement(data); 580141cc406Sopenharmony_ci if (node == NULL) { 581141cc406Sopenharmony_ci *status = SANE_STATUS_NO_MEM; 582141cc406Sopenharmony_ci goto clean; 583141cc406Sopenharmony_ci } 584141cc406Sopenharmony_ci 585141cc406Sopenharmony_ci if (device->hack && 586141cc406Sopenharmony_ci header && 587141cc406Sopenharmony_ci header->memory && 588141cc406Sopenharmony_ci strstr(header->memory, "Server: HP_Compact_Server")) 589141cc406Sopenharmony_ci device->hack = curl_slist_append(NULL, "Host: localhost"); 590141cc406Sopenharmony_ci 591141cc406Sopenharmony_ci device->version = 0.0; 592141cc406Sopenharmony_ci scanner->source = 0; 593141cc406Sopenharmony_ci scanner->Sources = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * 4); 594141cc406Sopenharmony_ci for (i = 0; i < 4; i++) 595141cc406Sopenharmony_ci scanner->Sources[i] = NULL; 596141cc406Sopenharmony_ci print_xml_c(node, device, scanner, -1); 597141cc406Sopenharmony_ci DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") ); 598141cc406Sopenharmony_ci if (device->model_name != NULL) { 599141cc406Sopenharmony_ci if (strcasestr(device->model_name, "MFC-J985DW")) { 600141cc406Sopenharmony_ci DBG (3, "blacklist_pdf: device not support PDF\n"); 601141cc406Sopenharmony_ci use_pdf = SANE_FALSE; 602141cc406Sopenharmony_ci } 603141cc406Sopenharmony_ci else if (blacklist) { 604141cc406Sopenharmony_ci char *model = strdup(device->model_name); 605141cc406Sopenharmony_ci replace_char(model, ' ', '_'); 606141cc406Sopenharmony_ci if (strcasestr(blacklist, model)) { 607141cc406Sopenharmony_ci use_pdf = SANE_FALSE; 608141cc406Sopenharmony_ci } 609141cc406Sopenharmony_ci free(model); 610141cc406Sopenharmony_ci } 611141cc406Sopenharmony_ci } 612141cc406Sopenharmony_ci DBG (3, "1-blacklist_pdf: %s\n", (use_pdf ? "TRUE" : "FALSE") ); 613141cc406Sopenharmony_ci if (use_pdf) 614141cc406Sopenharmony_ci _reduce_color_modes(scanner); 615141cc406Sopenharmony_ci else 616141cc406Sopenharmony_ci _delete_pdf(scanner); 617141cc406Sopenharmony_ciclean: 618141cc406Sopenharmony_ci xmlFreeDoc(data); 619141cc406Sopenharmony_ciclean_data: 620141cc406Sopenharmony_ci xmlCleanupParser(); 621141cc406Sopenharmony_ci xmlMemoryDump(); 622141cc406Sopenharmony_ci curl_easy_cleanup(curl_handle); 623141cc406Sopenharmony_ci if (header) 624141cc406Sopenharmony_ci free(header->memory); 625141cc406Sopenharmony_ci free(header); 626141cc406Sopenharmony_ci if (var) 627141cc406Sopenharmony_ci free(var->memory); 628141cc406Sopenharmony_ci free(var); 629141cc406Sopenharmony_ci return (scanner); 630141cc406Sopenharmony_ci} 631