1 /* sane - Scanner Access Now Easy.
2    Copyright (C) 1996, 1997 Andreas Beck
3    Copyright (C) 2000, 2001 Michael Herder <crapsite@gmx.net>
4    Copyright (C) 2001, 2002 Henning Meier-Geinitz <henning@meier-geinitz.de>
5    Copyright (C) 2008 Stéphane Voltz <stef.dev@free.fr>
6    This file is part of the SANE package.
7 
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2 of the
11    License, or (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 
21    As a special exception, the authors of SANE give permission for
22    additional uses of the libraries contained in this release of SANE.
23 
24    The exception is that, if you link a SANE library with other files
25    to produce an executable, this does not by itself cause the
26    resulting executable to be covered by the GNU General Public
27    License.  Your use of that executable is in no way restricted on
28    account of linking the SANE library code into it.
29 
30    This exception does not, however, invalidate any other reasons why
31    the executable file might be covered by the GNU General Public
32    License.
33 
34    If you submit changes to SANE to the maintainers to be included in
35    a subsequent release, you agree by submitting the changes that
36    those changes may be distributed with this exception intact.
37 
38    If you write modifications of your own for SANE, it is your choice
39    whether to permit this exception to apply to your modifications.
40    If you do not wish that, delete this exception notice.  */
41 
42 #define BUILD 9
43 
44 #include "../include/sane/config.h"
45 
46 #include <stdlib.h>
47 #include <string.h>
48 #include <stdio.h>
49 #include <unistd.h>
50 #include <fcntl.h>
51 #include <errno.h>
52 #include <sys/time.h>
53 
54 #include "../include/sane/sane.h"
55 #include "../include/sane/sanei.h"
56 #include "../include/sane/saneopts.h"
57 
58 #define BACKEND_NAME	pnm
59 #include "../include/sane/sanei_backend.h"
60 
61 #ifndef PATH_MAX
62 # define PATH_MAX	1024
63 #endif
64 
65 #define MAGIC	(void *)0xab730324
66 
67 static int is_open = 0;
68 static int rgb_comp = 0;
69 static int three_pass = 0;
70 static int hand_scanner = 0;
71 static int pass = 0;
72 static char filename[PATH_MAX] = "/tmp/input.ppm";
73 static SANE_Word status_none = SANE_TRUE;
74 static SANE_Word status_eof = SANE_FALSE;
75 static SANE_Word status_jammed = SANE_FALSE;
76 static SANE_Word status_nodocs = SANE_FALSE;
77 static SANE_Word status_coveropen = SANE_FALSE;
78 static SANE_Word status_ioerror = SANE_FALSE;
79 static SANE_Word status_nomem = SANE_FALSE;
80 static SANE_Word status_accessdenied = SANE_FALSE;
81 static SANE_Word test_option = 0;
82 #ifdef SANE_STATUS_WARMING_UP
83 static SANE_Word warming_up = SANE_FALSE;
84 static struct timeval start;
85 #endif
86 
87 static SANE_Fixed bright = 0;
88 static SANE_Word res = 75;
89 static SANE_Fixed contr = 0;
90 static SANE_Bool gray = SANE_FALSE;
91 static SANE_Bool usegamma = SANE_FALSE;
92 static SANE_Word gamma[4][256];
93 static enum
94 {
95   ppm_bitmap,
96   ppm_greyscale,
97   ppm_color
98 }
99 ppm_type = ppm_color;
100 static FILE *infile = NULL;
101 static const SANE_Word resbit_list[] = {
102   17,
103   75, 90, 100, 120, 135, 150, 165, 180, 195,
104   200, 210, 225, 240, 255, 270, 285, 300
105 };
106 static const SANE_Range percentage_range = {
107   SANE_FIX(-100),	/* minimum */
108   SANE_FIX(100),	/* maximum */
109   SANE_FIX(0)           /* quantization */
110 };
111 static const SANE_Range gamma_range = {
112   0,				/* minimum */
113   255,				/* maximum */
114   0				/* quantization */
115 };
116 typedef enum
117 {
118   opt_num_opts = 0,
119   opt_source_group,
120   opt_filename,
121   opt_resolution,
122   opt_enhancement_group,
123   opt_brightness,
124   opt_contrast,
125   opt_grayify,
126   opt_three_pass,
127   opt_hand_scanner,
128   opt_default_enhancements,
129   opt_read_only,
130   opt_gamma_group,
131   opt_custom_gamma,
132   opt_gamma,
133   opt_gamma_r,
134   opt_gamma_g,
135   opt_gamma_b,
136   opt_status_group,
137   opt_status,
138   opt_status_eof,
139   opt_status_jammed,
140   opt_status_nodocs,
141   opt_status_coveropen,
142   opt_status_ioerror,
143   opt_status_nomem,
144   opt_status_accessdenied,
145 
146   /* must come last: */
147   num_options
148 }
149 pnm_opts;
150 
151 static SANE_Option_Descriptor sod[] = {
152   {				/* opt_num_opts */
153    SANE_NAME_NUM_OPTIONS,
154    SANE_TITLE_NUM_OPTIONS,
155    SANE_DESC_NUM_OPTIONS,
156    SANE_TYPE_INT,
157    SANE_UNIT_NONE,
158    sizeof (SANE_Word),
159    SANE_CAP_SOFT_DETECT,
160    SANE_CONSTRAINT_NONE,
161    {NULL}
162    }
163   ,
164   {				/* opt_source_group */
165    "",
166    SANE_I18N ("Source Selection"),
167    "",
168    SANE_TYPE_GROUP,
169    SANE_UNIT_NONE,
170    0,
171    0,
172    SANE_CONSTRAINT_NONE,
173    {NULL}
174    }
175   ,
176   {				/* opt_filename */
177    SANE_NAME_FILE,
178    SANE_TITLE_FILE,
179    SANE_DESC_FILE,
180    SANE_TYPE_STRING,
181    SANE_UNIT_NONE,
182    sizeof (filename),
183    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
184    SANE_CONSTRAINT_NONE,
185    {NULL}
186    }
187   ,
188   {
189    /* opt_resolution */
190    SANE_NAME_SCAN_RESOLUTION,
191    SANE_TITLE_SCAN_RESOLUTION,
192    SANE_DESC_SCAN_RESOLUTION,
193    SANE_TYPE_INT,
194    SANE_UNIT_DPI,
195    sizeof (SANE_Word),
196    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_AUTOMATIC,
197    SANE_CONSTRAINT_WORD_LIST,
198    {(SANE_String_Const *) resbit_list}
199    }
200   ,
201   {				/* opt_enhancement_group */
202    "",
203    SANE_I18N ("Image Enhancement"),
204    "",
205    SANE_TYPE_GROUP,
206    SANE_UNIT_NONE,
207    0,
208    0,
209    SANE_CONSTRAINT_NONE,
210    {NULL}
211    }
212   ,
213   {				/* opt_brightness */
214    SANE_NAME_BRIGHTNESS,
215    SANE_TITLE_BRIGHTNESS,
216    SANE_DESC_BRIGHTNESS,
217    SANE_TYPE_FIXED,
218    SANE_UNIT_PERCENT,
219    sizeof (SANE_Word),
220    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
221    SANE_CONSTRAINT_RANGE,
222    {(SANE_String_Const *) & percentage_range}	/* this is ANSI conformant! */
223    }
224   ,
225   {				/* opt_contrast */
226    SANE_NAME_CONTRAST,
227    SANE_TITLE_CONTRAST,
228    SANE_DESC_CONTRAST,
229    SANE_TYPE_FIXED,
230    SANE_UNIT_PERCENT,
231    sizeof (SANE_Word),
232    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
233    SANE_CONSTRAINT_RANGE,
234    {(SANE_String_Const *) & percentage_range}	/* this is ANSI conformant! */
235    }
236   ,
237   {				/* opt_grayify */
238    "grayify",
239    SANE_I18N ("Grayify"),
240    SANE_I18N ("Load the image as grayscale."),
241    SANE_TYPE_BOOL,
242    SANE_UNIT_NONE,
243    sizeof (SANE_Word),
244    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
245    SANE_CONSTRAINT_NONE,
246    {NULL}
247    }
248   ,
249   {				/* opt_three_pass */
250    "three-pass",
251    SANE_I18N ("Three-Pass Simulation"),
252    SANE_I18N
253    ("Simulate a three-pass scanner by returning 3 separate frames.  "
254     "For kicks, it returns green, then blue, then red."),
255    SANE_TYPE_BOOL,
256    SANE_UNIT_NONE,
257    sizeof (SANE_Word),
258    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
259    SANE_CONSTRAINT_NONE,
260    {NULL}
261    }
262   ,
263   {				/* opt_hand_scanner */
264    "hand-scanner",
265    SANE_I18N ("Hand-Scanner Simulation"),
266    SANE_I18N ("Simulate a hand-scanner.  Hand-scanners often do not know the "
267 	      "image height a priori.  Instead, they return a height of -1.  "
268 	      "Setting this option allows one to test whether a frontend can "
269 	      "handle this correctly."),
270    SANE_TYPE_BOOL,
271    SANE_UNIT_NONE,
272    sizeof (SANE_Word),
273    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
274    SANE_CONSTRAINT_NONE,
275    {NULL}
276    }
277   ,
278   {				/* opt_default_enhancements */
279    "default-enhancements",
280    SANE_I18N ("Defaults"),
281    SANE_I18N ("Set default values for enhancement controls (brightness & "
282 	      "contrast)."),
283    SANE_TYPE_BUTTON,
284    SANE_UNIT_NONE,
285    0,
286    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
287    SANE_CONSTRAINT_NONE,
288    {NULL}
289    }
290   ,
291   {				/* opt_read_only */
292    "read-only",
293    SANE_I18N ("Read only test-option"),
294    SANE_I18N ("Let's see whether frontends can treat this right"),
295    SANE_TYPE_INT,
296    SANE_UNIT_PERCENT,
297    sizeof (SANE_Word),
298    SANE_CAP_SOFT_DETECT,
299    SANE_CONSTRAINT_NONE,
300    {NULL}
301    }
302   ,
303   {				/* opt_gamma_group */
304    "",
305    SANE_I18N ("Gamma Tables"),
306    "",
307    SANE_TYPE_GROUP,
308    SANE_UNIT_NONE,
309    0,
310    0,
311    SANE_CONSTRAINT_NONE,
312    {NULL}
313    }
314   ,
315   {				/* opt_custom_gamma */
316    SANE_NAME_CUSTOM_GAMMA,
317    SANE_TITLE_CUSTOM_GAMMA,
318    SANE_DESC_CUSTOM_GAMMA,
319    SANE_TYPE_BOOL,
320    SANE_UNIT_NONE,
321    sizeof (SANE_Word),
322    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
323    SANE_CONSTRAINT_NONE,
324    {NULL}
325    }
326   ,
327   {				/* opt_gamma */
328    SANE_NAME_GAMMA_VECTOR,
329    SANE_TITLE_GAMMA_VECTOR,
330    SANE_DESC_GAMMA_VECTOR,
331    SANE_TYPE_INT,
332    SANE_UNIT_NONE,
333    sizeof (SANE_Word) * 256,
334    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE,
335    SANE_CONSTRAINT_RANGE,
336    {(SANE_String_Const *) & gamma_range}
337    }
338   ,
339   {				/* opt_gamma_r */
340    SANE_NAME_GAMMA_VECTOR_R,
341    SANE_TITLE_GAMMA_VECTOR_R,
342    SANE_DESC_GAMMA_VECTOR_R,
343    SANE_TYPE_INT,
344    SANE_UNIT_NONE,
345    sizeof (SANE_Word) * 256,
346    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE,
347    SANE_CONSTRAINT_RANGE,
348    {(SANE_String_Const *) & gamma_range}
349    }
350   ,
351   {				/* opt_gamma_g */
352    SANE_NAME_GAMMA_VECTOR_G,
353    SANE_TITLE_GAMMA_VECTOR_G,
354    SANE_DESC_GAMMA_VECTOR_G,
355    SANE_TYPE_INT,
356    SANE_UNIT_NONE,
357    sizeof (SANE_Word) * 256,
358    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE,
359    SANE_CONSTRAINT_RANGE,
360    {(SANE_String_Const *) & gamma_range}
361    }
362   ,
363   {				/* opt_gamma_b */
364    SANE_NAME_GAMMA_VECTOR_B,
365    SANE_TITLE_GAMMA_VECTOR_B,
366    SANE_DESC_GAMMA_VECTOR_B,
367    SANE_TYPE_INT,
368    SANE_UNIT_NONE,
369    sizeof (SANE_Word) * 256,
370    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE,
371    SANE_CONSTRAINT_RANGE,
372    {(SANE_String_Const *) & gamma_range}
373    }
374   ,
375   {				/* opt_status_group */
376    "",
377    SANE_I18N ("Status Code Simulation"),
378    "",
379    SANE_TYPE_GROUP,
380    SANE_UNIT_NONE,
381    0,
382    SANE_CAP_ADVANCED,
383    SANE_CONSTRAINT_NONE,
384    {NULL}
385    }
386   ,
387   {				/* opt_status */
388    "status",
389    SANE_I18N ("Do not force status code"),
390    SANE_I18N ("Do not force the backend to return a status code."),
391    SANE_TYPE_BOOL,
392    SANE_UNIT_NONE,
393    sizeof (SANE_Bool),
394    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
395    SANE_CONSTRAINT_NONE,
396    {NULL}
397    }
398   ,
399   {				/* opt_status_eof */
400    "status-eof",
401    SANE_I18N ("Return SANE_STATUS_EOF"),
402    SANE_I18N ("Force the backend to return the status code SANE_STATUS_EOF "
403 	      "after sane_read() has been called."),
404    SANE_TYPE_BOOL,
405    SANE_UNIT_NONE,
406    sizeof (SANE_Bool),
407    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
408    SANE_CONSTRAINT_NONE,
409    {NULL}
410    }
411   ,
412   {				/* opt_status_jammed */
413    "status-jammed",
414    SANE_I18N ("Return SANE_STATUS_JAMMED"),
415    SANE_I18N
416    ("Force the backend to return the status code SANE_STATUS_JAMMED "
417     "after sane_read() has been called."),
418    SANE_TYPE_BOOL,
419    SANE_UNIT_NONE,
420    sizeof (SANE_Bool),
421    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
422    SANE_CONSTRAINT_NONE,
423    {NULL}
424    }
425   ,
426   {				/* opt_status_nodocs */
427    "status-nodocs",
428    SANE_I18N ("Return SANE_STATUS_NO_DOCS"),
429    SANE_I18N ("Force the backend to return the status code "
430 	      "SANE_STATUS_NO_DOCS after sane_read() has been called."),
431    SANE_TYPE_BOOL,
432    SANE_UNIT_NONE,
433    sizeof (SANE_Bool),
434    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
435    SANE_CONSTRAINT_NONE,
436    {NULL}
437    }
438   ,
439   {				/* opt_status_coveropen */
440    "status-coveropen",
441    SANE_I18N ("Return SANE_STATUS_COVER_OPEN"),
442    SANE_I18N ("Force the backend to return the status code "
443 	      "SANE_STATUS_COVER_OPEN after sane_read() has been called."),
444    SANE_TYPE_BOOL,
445    SANE_UNIT_NONE,
446    sizeof (SANE_Bool),
447    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
448    SANE_CONSTRAINT_NONE,
449    {NULL}
450    }
451   ,
452   {				/* opt_status_ioerror */
453    "status-ioerror",
454    SANE_I18N ("Return SANE_STATUS_IO_ERROR"),
455    SANE_I18N ("Force the backend to return the status code "
456 	      "SANE_STATUS_IO_ERROR after sane_read() has been called."),
457    SANE_TYPE_BOOL,
458    SANE_UNIT_NONE,
459    sizeof (SANE_Bool),
460    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
461    SANE_CONSTRAINT_NONE,
462    {NULL}
463    }
464   ,
465   {				/* opt_status_nomem */
466    "status-nomem",
467    SANE_I18N ("Return SANE_STATUS_NO_MEM"),
468    SANE_I18N
469    ("Force the backend to return the status code SANE_STATUS_NO_MEM "
470     "after sane_read() has been called."),
471    SANE_TYPE_BOOL,
472    SANE_UNIT_NONE,
473    sizeof (SANE_Bool),
474    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
475    SANE_CONSTRAINT_NONE,
476    {NULL}
477    }
478   ,
479   {				/* opt_status_accessdenied */
480    "status-accessdenied",
481    SANE_I18N ("Return SANE_STATUS_ACCESS_DENIED"),
482    SANE_I18N ("Force the backend to return the status code "
483 	      "SANE_STATUS_ACCESS_DENIED after sane_read() has been called."),
484    SANE_TYPE_BOOL,
485    SANE_UNIT_NONE,
486    sizeof (SANE_Bool),
487    SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT,
488    SANE_CONSTRAINT_NONE,
489    {NULL}
490    }
491 };
492 
493 static SANE_Parameters parms = {
494   SANE_FRAME_RGB,
495   0,
496   0,				/* Number of bytes returned per scan line: */
497   0,				/* Number of pixels per scan line.  */
498   0,				/* Number of lines for the current scan.  */
499   8,				/* Number of bits per sample. */
500 };
501 
502 /* This library is a demo implementation of a SANE backend.  It
503    implements a virtual device, a PNM file-filter. */
504 SANE_Status
sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize)505 sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize)
506 {
507   DBG_INIT ();
508 
509   DBG (2, "sane_init: version_code %s 0, authorize %s 0\n",
510        version_code == 0 ? "=" : "!=", authorize == 0 ? "=" : "!=");
511   DBG (1, "sane_init: SANE pnm backend version %d.%d.%d from %s\n",
512        SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD, PACKAGE_STRING);
513 
514   if (version_code)
515     *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, BUILD);
516   return SANE_STATUS_GOOD;
517 }
518 
519 void
sane_exit(void)520 sane_exit (void)
521 {
522   DBG (2, "sane_exit\n");
523   return;
524 }
525 
526 /* Device select/open/close */
527 
528 static const SANE_Device dev[] = {
529   {
530    "0",
531    "Noname",
532    "PNM file reader",
533    "virtual device"},
534   {
535    "1",
536    "Noname",
537    "PNM file reader",
538    "virtual device"},
539 #ifdef SANE_STATUS_HW_LOCKED
540   {
541    "locked",
542    "Noname",
543    "Hardware locked",
544    "virtual device"},
545 #endif
546 #ifdef SANE_STATUS_WARMING_UP
547   {
548    "warmup",
549    "Noname",
550    "Always warming up",
551    "virtual device"},
552 #endif
553 };
554 
555 SANE_Status
sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only)556 sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only)
557 {
558   static const SANE_Device *devlist[] = {
559     dev + 0, dev + 1,
560 #ifdef SANE_STATUS_HW_LOCKED
561     dev + 2,
562 #endif
563 #ifdef SANE_STATUS_WARMING_UP
564     dev + 3,
565 #endif
566     0
567   };
568 
569   DBG (2, "sane_get_devices: local_only = %d\n", local_only);
570   *device_list = devlist;
571   return SANE_STATUS_GOOD;
572 }
573 
574 SANE_Status
sane_open(SANE_String_Const devicename, SANE_Handle * handle)575 sane_open (SANE_String_Const devicename, SANE_Handle * handle)
576 {
577   int i;
578 
579   if (!devicename)
580     return SANE_STATUS_INVAL;
581   DBG (2, "sane_open: devicename = \"%s\"\n", devicename);
582 
583   if (!devicename[0])
584     i = 0;
585   else
586     for (i = 0; i < NELEMS (dev); ++i)
587       if (strcmp (devicename, dev[i].name) == 0)
588 	break;
589   if (i >= NELEMS (dev))
590     return SANE_STATUS_INVAL;
591 
592   if (is_open)
593     return SANE_STATUS_DEVICE_BUSY;
594 
595   is_open = 1;
596   *handle = MAGIC;
597   for (i = 0; i < 256; i++)
598     {
599       gamma[0][i] = i;
600       gamma[1][i] = i;
601       gamma[2][i] = i;
602       gamma[3][i] = i;
603     }
604 
605 #ifdef SANE_STATUS_HW_LOCKED
606   if(strncmp(devicename,"locked",6)==0)
607     return SANE_STATUS_HW_LOCKED;
608 #endif
609 
610 #ifdef SANE_STATUS_WARMING_UP
611   if(strncmp(devicename,"warmup",6)==0)
612     {
613       warming_up = SANE_TRUE;
614       start.tv_sec = 0;
615     }
616 #endif
617 
618   return SANE_STATUS_GOOD;
619 }
620 
621 void
sane_close(SANE_Handle handle)622 sane_close (SANE_Handle handle)
623 {
624   DBG (2, "sane_close\n");
625   if (handle == MAGIC)
626     is_open = 0;
627 }
628 
629 const SANE_Option_Descriptor *
sane_get_option_descriptor(SANE_Handle handle, SANE_Int option)630 sane_get_option_descriptor (SANE_Handle handle, SANE_Int option)
631 {
632   DBG (2, "sane_get_option_descriptor: option = %d\n", option);
633   if (handle != MAGIC || !is_open)
634     return NULL;		/* wrong device */
635   if (option < 0 || option >= NELEMS (sod))
636     return NULL;
637   return &sod[option];
638 }
639 
640 SANE_Status
sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action action, void *value, SANE_Int * info)641 sane_control_option (SANE_Handle handle, SANE_Int option,
642 		     SANE_Action action, void *value, SANE_Int * info)
643 {
644   SANE_Int myinfo = 0;
645   SANE_Status status;
646   int v;
647   v = 75;
648 
649   DBG (2, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n",
650        handle, option, action, value, (void *) info);
651 
652   if (handle != MAGIC || !is_open)
653     {
654       DBG (1, "sane_control_option: unknown handle or not open\n");
655       return SANE_STATUS_INVAL;	/* Unknown handle ... */
656     }
657 
658   if (option < 0 || option >= NELEMS (sod))
659     {
660       DBG (1, "sane_control_option: option %d < 0 or >= number of options\n",
661 	   option);
662       return SANE_STATUS_INVAL;	/* Unknown option ... */
663     }
664 
665   if (!SANE_OPTION_IS_ACTIVE (sod[option].cap))
666     {
667       DBG (4, "sane_control_option: option is inactive\n");
668       return SANE_STATUS_INVAL;
669     }
670 
671   switch (action)
672     {
673     case SANE_ACTION_SET_AUTO:
674       if (!SANE_OPTION_IS_SETTABLE (sod[option].cap))
675 	{
676 	  DBG (4, "sane_control_option: option is not settable\n");
677 	  return SANE_STATUS_INVAL;
678 	}
679       status = sanei_constrain_value (sod + option, (void *) &v, &myinfo);
680       if (status != SANE_STATUS_GOOD)
681 	return status;
682       switch (option)
683 	{
684 	case opt_resolution:
685 	  res = 75;
686 	  myinfo |= SANE_INFO_RELOAD_PARAMS;
687 	  break;
688 	default:
689 	  return SANE_STATUS_INVAL;
690 	}
691       break;
692     case SANE_ACTION_SET_VALUE:
693       if (!SANE_OPTION_IS_SETTABLE (sod[option].cap))
694 	{
695 	  DBG (4, "sane_control_option: option is not settable\n");
696 	  return SANE_STATUS_INVAL;
697 	}
698       status = sanei_constrain_value (sod + option, value, &myinfo);
699       if (status != SANE_STATUS_GOOD)
700 	return status;
701       switch (option)
702 	{
703 	case opt_filename:
704 	  if ((strlen (value) + 1) > sizeof (filename))
705 	    return SANE_STATUS_NO_MEM;
706 	  strcpy (filename, value);
707 	  myinfo |= SANE_INFO_RELOAD_PARAMS;
708 	  break;
709 	case opt_resolution:
710 	  res = *(SANE_Word *) value;
711 	  break;
712 	case opt_brightness:
713 	  bright = *(SANE_Word *) value;
714 	  break;
715 	case opt_contrast:
716 	  contr = *(SANE_Word *) value;
717 	  break;
718 	case opt_grayify:
719 	  gray = !!*(SANE_Word *) value;
720 	  if (usegamma)
721 	    {
722 	      if (gray)
723 		{
724 		  sod[opt_gamma].cap &= ~SANE_CAP_INACTIVE;
725 		  sod[opt_gamma_r].cap |= SANE_CAP_INACTIVE;
726 		  sod[opt_gamma_g].cap |= SANE_CAP_INACTIVE;
727 		  sod[opt_gamma_b].cap |= SANE_CAP_INACTIVE;
728 		}
729 	      else
730 		{
731 		  sod[opt_gamma].cap |= SANE_CAP_INACTIVE;
732 		  sod[opt_gamma_r].cap &= ~SANE_CAP_INACTIVE;
733 		  sod[opt_gamma_g].cap &= ~SANE_CAP_INACTIVE;
734 		  sod[opt_gamma_b].cap &= ~SANE_CAP_INACTIVE;
735 		}
736 	    }
737 	  else
738 	    {
739 	      sod[opt_gamma].cap |= SANE_CAP_INACTIVE;
740 	      sod[opt_gamma_r].cap |= SANE_CAP_INACTIVE;
741 	      sod[opt_gamma_g].cap |= SANE_CAP_INACTIVE;
742 	      sod[opt_gamma_b].cap |= SANE_CAP_INACTIVE;
743 	    }
744 	  myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS;
745 	  break;
746 	case opt_three_pass:
747 	  three_pass = !!*(SANE_Word *) value;
748 	  myinfo |= SANE_INFO_RELOAD_PARAMS;
749 	  break;
750 	case opt_hand_scanner:
751 	  hand_scanner = !!*(SANE_Word *) value;
752 	  myinfo |= SANE_INFO_RELOAD_PARAMS;
753 	  break;
754 	case opt_default_enhancements:
755 	  bright = contr = 0;
756 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
757 	  break;
758 	case opt_custom_gamma:
759 	  usegamma = *(SANE_Word *) value;
760 	  /* activate/deactivate gamma */
761 	  if (usegamma)
762 	    {
763 	      test_option = 100;
764 	      if (gray)
765 		{
766 		  sod[opt_gamma].cap &= ~SANE_CAP_INACTIVE;
767 		  sod[opt_gamma_r].cap |= SANE_CAP_INACTIVE;
768 		  sod[opt_gamma_g].cap |= SANE_CAP_INACTIVE;
769 		  sod[opt_gamma_b].cap |= SANE_CAP_INACTIVE;
770 		}
771 	      else
772 		{
773 		  sod[opt_gamma].cap |= SANE_CAP_INACTIVE;
774 		  sod[opt_gamma_r].cap &= ~SANE_CAP_INACTIVE;
775 		  sod[opt_gamma_g].cap &= ~SANE_CAP_INACTIVE;
776 		  sod[opt_gamma_b].cap &= ~SANE_CAP_INACTIVE;
777 		}
778 	    }
779 	  else
780 	    {
781 	      test_option = 0;
782 	      sod[opt_gamma].cap |= SANE_CAP_INACTIVE;
783 	      sod[opt_gamma_r].cap |= SANE_CAP_INACTIVE;
784 	      sod[opt_gamma_g].cap |= SANE_CAP_INACTIVE;
785 	      sod[opt_gamma_b].cap |= SANE_CAP_INACTIVE;
786 	    }
787 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
788 	  break;
789 	case opt_gamma:
790 	  memcpy (&gamma[0][0], (SANE_Word *) value,
791 		  256 * sizeof (SANE_Word));
792 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
793 	  break;
794 	case opt_gamma_r:
795 	  memcpy (&gamma[1][0], (SANE_Word *) value,
796 		  256 * sizeof (SANE_Word));
797 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
798 	  break;
799 	case opt_gamma_g:
800 	  memcpy (&gamma[2][0], (SANE_Word *) value,
801 		  256 * sizeof (SANE_Word));
802 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
803 	  break;
804 	case opt_gamma_b:
805 	  memcpy (&gamma[3][0], (SANE_Word *) value,
806 		  256 * sizeof (SANE_Word));
807 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
808 	  break;
809 	  /* status */
810 	case opt_status:
811 	  status_none = *(SANE_Word *) value;
812 	  if (status_none)
813 	    {
814 	      status_eof = SANE_FALSE;
815 	      status_jammed = SANE_FALSE;
816 	      status_nodocs = SANE_FALSE;
817 	      status_coveropen = SANE_FALSE;
818 	      status_ioerror = SANE_FALSE;
819 	      status_nomem = SANE_FALSE;
820 	      status_accessdenied = SANE_FALSE;
821 	    }
822 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
823 	  break;
824 	case opt_status_eof:
825 	  status_eof = *(SANE_Word *) value;
826 	  if (status_eof)
827 	    {
828 	      status_none = SANE_FALSE;
829 	      status_jammed = SANE_FALSE;
830 	      status_nodocs = SANE_FALSE;
831 	      status_coveropen = SANE_FALSE;
832 	      status_ioerror = SANE_FALSE;
833 	      status_nomem = SANE_FALSE;
834 	      status_accessdenied = SANE_FALSE;
835 	    }
836 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
837 	  break;
838 	case opt_status_jammed:
839 	  status_jammed = *(SANE_Word *) value;
840 	  if (status_jammed)
841 	    {
842 	      status_eof = SANE_FALSE;
843 	      status_none = SANE_FALSE;
844 	      status_nodocs = SANE_FALSE;
845 	      status_coveropen = SANE_FALSE;
846 	      status_ioerror = SANE_FALSE;
847 	      status_nomem = SANE_FALSE;
848 	      status_accessdenied = SANE_FALSE;
849 	    }
850 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
851 	  break;
852 	case opt_status_nodocs:
853 	  status_nodocs = *(SANE_Word *) value;
854 	  if (status_nodocs)
855 	    {
856 	      status_eof = SANE_FALSE;
857 	      status_jammed = SANE_FALSE;
858 	      status_none = SANE_FALSE;
859 	      status_coveropen = SANE_FALSE;
860 	      status_ioerror = SANE_FALSE;
861 	      status_nomem = SANE_FALSE;
862 	      status_accessdenied = SANE_FALSE;
863 	    }
864 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
865 	  break;
866 	case opt_status_coveropen:
867 	  status_coveropen = *(SANE_Word *) value;
868 	  if (status_coveropen)
869 	    {
870 	      status_eof = SANE_FALSE;
871 	      status_jammed = SANE_FALSE;
872 	      status_nodocs = SANE_FALSE;
873 	      status_none = SANE_FALSE;
874 	      status_ioerror = SANE_FALSE;
875 	      status_nomem = SANE_FALSE;
876 	      status_accessdenied = SANE_FALSE;
877 	    }
878 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
879 	  break;
880 	case opt_status_ioerror:
881 	  status_ioerror = *(SANE_Word *) value;
882 	  if (status_ioerror)
883 	    {
884 	      status_eof = SANE_FALSE;
885 	      status_jammed = SANE_FALSE;
886 	      status_nodocs = SANE_FALSE;
887 	      status_coveropen = SANE_FALSE;
888 	      status_none = SANE_FALSE;
889 	      status_nomem = SANE_FALSE;
890 	      status_accessdenied = SANE_FALSE;
891 	    }
892 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
893 	  break;
894 	case opt_status_nomem:
895 	  status_nomem = *(SANE_Word *) value;
896 	  if (status_nomem)
897 	    {
898 	      status_eof = SANE_FALSE;
899 	      status_jammed = SANE_FALSE;
900 	      status_nodocs = SANE_FALSE;
901 	      status_coveropen = SANE_FALSE;
902 	      status_ioerror = SANE_FALSE;
903 	      status_none = SANE_FALSE;
904 	      status_accessdenied = SANE_FALSE;
905 	    }
906 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
907 	  break;
908 	case opt_status_accessdenied:
909 	  status_accessdenied = *(SANE_Word *) value;
910 	  if (status_accessdenied)
911 	    {
912 	      status_eof = SANE_FALSE;
913 	      status_jammed = SANE_FALSE;
914 	      status_nodocs = SANE_FALSE;
915 	      status_coveropen = SANE_FALSE;
916 	      status_ioerror = SANE_FALSE;
917 	      status_nomem = SANE_FALSE;
918 	      status_none = SANE_FALSE;
919 	    }
920 	  myinfo |= SANE_INFO_RELOAD_OPTIONS;
921 	  break;
922 	default:
923 	  return SANE_STATUS_INVAL;
924 	}
925       break;
926     case SANE_ACTION_GET_VALUE:
927       switch (option)
928 	{
929 	case opt_num_opts:
930 	  *(SANE_Word *) value = NELEMS (sod);
931 	  break;
932 	case opt_filename:
933 	  strcpy (value, filename);
934 	  break;
935 	case opt_resolution:
936 	  *(SANE_Word *) value = res;
937 	  break;
938 	case opt_brightness:
939 	  *(SANE_Word *) value = bright;
940 	  break;
941 	case opt_contrast:
942 	  *(SANE_Word *) value = contr;
943 	  break;
944 	case opt_grayify:
945 	  *(SANE_Word *) value = gray;
946 	  break;
947 	case opt_three_pass:
948 	  *(SANE_Word *) value = three_pass;
949 	  break;
950 	case opt_hand_scanner:
951 	  *(SANE_Word *) value = hand_scanner;
952 	  break;
953 	case opt_read_only:
954 	  *(SANE_Word *) value = test_option;
955 	  break;
956 	case opt_custom_gamma:
957 	  *(SANE_Word *) value = usegamma;
958 	  break;
959 	case opt_gamma:
960 	  memcpy ((SANE_Word *) value, &gamma[0][0],
961 		  256 * sizeof (SANE_Word));
962 	  break;
963 	case opt_gamma_r:
964 	  memcpy ((SANE_Word *) value, &gamma[1][0],
965 		  256 * sizeof (SANE_Word));
966 	  break;
967 	case opt_gamma_g:
968 	  memcpy ((SANE_Word *) value, &gamma[2][0],
969 		  256 * sizeof (SANE_Word));
970 	  break;
971 	case opt_gamma_b:
972 	  memcpy ((SANE_Word *) value, &gamma[3][0],
973 		  256 * sizeof (SANE_Word));
974 	  break;
975 	case opt_status:
976 	  *(SANE_Word *) value = status_none;
977 	  break;
978 	case opt_status_eof:
979 	  *(SANE_Word *) value = status_eof;
980 	  break;
981 	case opt_status_jammed:
982 	  *(SANE_Word *) value = status_jammed;
983 	  break;
984 	case opt_status_nodocs:
985 	  *(SANE_Word *) value = status_nodocs;
986 	  break;
987 	case opt_status_coveropen:
988 	  *(SANE_Word *) value = status_coveropen;
989 	  break;
990 	case opt_status_ioerror:
991 	  *(SANE_Word *) value = status_ioerror;
992 	  break;
993 	case opt_status_nomem:
994 	  *(SANE_Word *) value = status_nomem;
995 	  break;
996 	case opt_status_accessdenied:
997 	  *(SANE_Word *) value = status_accessdenied;
998 	  break;
999 	default:
1000 	  return SANE_STATUS_INVAL;
1001 	}
1002       break;
1003     }
1004   if (info)
1005     *info = myinfo;
1006   return SANE_STATUS_GOOD;
1007 }
1008 
1009 static void
get_line(char *buf, int len, FILE * f)1010 get_line (char *buf, int len, FILE * f)
1011 {
1012   do
1013     fgets (buf, len, f);
1014   while (*buf == '#');
1015 }
1016 
1017 static int
getparmfromfile(void)1018 getparmfromfile (void)
1019 {
1020   FILE *fn;
1021   int x, y;
1022   char buf[1024];
1023 
1024   parms.depth = 8;
1025   parms.bytes_per_line = parms.pixels_per_line = parms.lines = 0;
1026   if ((fn = fopen (filename, "rb")) == NULL)
1027     {
1028       DBG (1, "getparmfromfile: unable to open file \"%s\"\n", filename);
1029       return -1;
1030     }
1031 
1032   /* Skip comments. */
1033   do
1034     get_line (buf, sizeof (buf), fn);
1035   while (*buf == '#');
1036   if (!strncmp (buf, "P4", 2))
1037     {
1038       /* Binary monochrome. */
1039       parms.depth = 1;
1040       ppm_type = ppm_bitmap;
1041     }
1042   else if (!strncmp (buf, "P5", 2))
1043     {
1044       /* Grayscale. */
1045       parms.depth = 8;
1046       ppm_type = ppm_greyscale;
1047     }
1048   else if (!strncmp (buf, "P6", 2))
1049     {
1050       /* Color. */
1051       parms.depth = 8;
1052       ppm_type = ppm_color;
1053     }
1054   else
1055     {
1056       DBG (1, "getparmfromfile: %s is not a recognized PPM\n", filename);
1057       fclose (fn);
1058       return -1;
1059     }
1060 
1061   /* Skip comments. */
1062   do
1063     get_line (buf, sizeof (buf), fn);
1064   while (*buf == '#');
1065   sscanf (buf, "%d %d", &x, &y);
1066 
1067   parms.last_frame = SANE_TRUE;
1068   parms.bytes_per_line = (ppm_type == ppm_bitmap) ? (x + 7) / 8 : x;
1069   parms.pixels_per_line = x;
1070   if (hand_scanner)
1071     parms.lines = -1;
1072   else
1073     parms.lines = y;
1074   if ((ppm_type == ppm_greyscale) || (ppm_type == ppm_bitmap) || gray)
1075     parms.format = SANE_FRAME_GRAY;
1076   else
1077     {
1078       if (three_pass)
1079 	{
1080 	  parms.format = SANE_FRAME_RED + (pass + 1) % 3;
1081 	  parms.last_frame = (pass >= 2);
1082 	}
1083       else
1084 	{
1085 	  parms.format = SANE_FRAME_RGB;
1086 	  parms.bytes_per_line *= 3;
1087 	}
1088     }
1089   fclose (fn);
1090   return 0;
1091 }
1092 
1093 SANE_Status
sane_get_parameters(SANE_Handle handle, SANE_Parameters * params)1094 sane_get_parameters (SANE_Handle handle, SANE_Parameters * params)
1095 {
1096   int rc = SANE_STATUS_GOOD;
1097 
1098   DBG (2, "sane_get_parameters\n");
1099   if (handle != MAGIC || !is_open)
1100     rc = SANE_STATUS_INVAL;	/* Unknown handle ... */
1101   else if (getparmfromfile ())
1102     rc = SANE_STATUS_INVAL;
1103   *params = parms;
1104   return rc;
1105 }
1106 
1107 SANE_Status
sane_start(SANE_Handle handle)1108 sane_start (SANE_Handle handle)
1109 {
1110   char buf[1024];
1111   int nlines;
1112 #ifdef SANE_STATUS_WARMING_UP
1113   struct timeval current;
1114 #endif
1115 
1116   DBG (2, "sane_start\n");
1117   rgb_comp = 0;
1118   if (handle != MAGIC || !is_open)
1119     return SANE_STATUS_INVAL;	/* Unknown handle ... */
1120 
1121 #ifdef SANE_STATUS_WARMING_UP
1122   if(warming_up == SANE_TRUE)
1123    {
1124       gettimeofday(&current,NULL);
1125       if(current.tv_sec-start.tv_sec>5)
1126 	{
1127 	   start.tv_sec = current.tv_sec;
1128 	   return SANE_STATUS_WARMING_UP;
1129 	}
1130       if(current.tv_sec-start.tv_sec<5)
1131 	return SANE_STATUS_WARMING_UP;
1132    }
1133 #endif
1134 
1135   if (infile != NULL)
1136     {
1137       fclose (infile);
1138       infile = NULL;
1139       if (!three_pass || ++pass >= 3)
1140 	return SANE_STATUS_EOF;
1141     }
1142 
1143   if (getparmfromfile ())
1144     return SANE_STATUS_INVAL;
1145 
1146   if ((infile = fopen (filename, "rb")) == NULL)
1147     {
1148       DBG (1, "sane_start: unable to open file \"%s\"\n", filename);
1149       return SANE_STATUS_INVAL;
1150     }
1151 
1152   /* Skip the header (only two lines for a bitmap). */
1153   nlines = (ppm_type == ppm_bitmap) ? 1 : 0;
1154   while (nlines < 3)
1155     {
1156       /* Skip comments. */
1157       get_line (buf, sizeof (buf), infile);
1158       if (*buf != '#')
1159 	nlines++;
1160     }
1161 
1162   return SANE_STATUS_GOOD;
1163 }
1164 
1165 static SANE_Int rgblength = 0;
1166 static SANE_Byte *rgbbuf = 0;
1167 static SANE_Byte rgbleftover[3] = { 0, 0, 0 };
1168 
1169 SANE_Status
sane_read(SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length)1170 sane_read (SANE_Handle handle, SANE_Byte * data,
1171 	   SANE_Int max_length, SANE_Int * length)
1172 {
1173   int len, x, hlp;
1174 
1175   DBG (2, "sane_read: max_length = %d, rgbleftover = {%d, %d, %d}\n",
1176        max_length, rgbleftover[0], rgbleftover[1], rgbleftover[2]);
1177   if (!length)
1178     {
1179       DBG (1, "sane_read: length == NULL\n");
1180       return SANE_STATUS_INVAL;
1181     }
1182   *length = 0;
1183   if (!data)
1184     {
1185       DBG (1, "sane_read: data == NULL\n");
1186       return SANE_STATUS_INVAL;
1187     }
1188   if (handle != MAGIC)
1189     {
1190       DBG (1, "sane_read: unknown handle\n");
1191       return SANE_STATUS_INVAL;
1192     }
1193   if (!is_open)
1194     {
1195       DBG (1, "sane_read: call sane_open first\n");
1196       return SANE_STATUS_INVAL;
1197     }
1198   if (!infile)
1199     {
1200       DBG (1, "sane_read: scan was cancelled\n");
1201       return SANE_STATUS_CANCELLED;
1202     }
1203   if (feof (infile))
1204     {
1205       DBG (2, "sane_read: EOF reached\n");
1206       return SANE_STATUS_EOF;
1207     }
1208 
1209   if (status_jammed == SANE_TRUE)
1210     return SANE_STATUS_JAMMED;
1211   if (status_eof == SANE_TRUE)
1212     return SANE_STATUS_EOF;
1213   if (status_nodocs == SANE_TRUE)
1214     return SANE_STATUS_NO_DOCS;
1215   if (status_coveropen == SANE_TRUE)
1216     return SANE_STATUS_COVER_OPEN;
1217   if (status_ioerror == SANE_TRUE)
1218     return SANE_STATUS_IO_ERROR;
1219   if (status_nomem == SANE_TRUE)
1220     return SANE_STATUS_NO_MEM;
1221   if (status_accessdenied == SANE_TRUE)
1222     return SANE_STATUS_ACCESS_DENIED;
1223 
1224   /* Allocate a buffer for the RGB values. */
1225   if (ppm_type == ppm_color && (gray || three_pass))
1226     {
1227       SANE_Byte *p, *q, *rgbend;
1228       if (rgbbuf == 0 || rgblength < 3 * max_length)
1229 	{
1230 	  /* Allocate a new rgbbuf. */
1231 	  free (rgbbuf);
1232 	  rgblength = 3 * max_length;
1233 	  rgbbuf = malloc (rgblength);
1234 	  if (rgbbuf == 0)
1235 	    return SANE_STATUS_NO_MEM;
1236 	}
1237       else
1238 	rgblength = 3 * max_length;
1239 
1240       /* Copy any leftovers into the buffer. */
1241       q = rgbbuf;
1242       p = rgbleftover + 1;
1243       while (p - rgbleftover <= rgbleftover[0])
1244 	*q++ = *p++;
1245 
1246       /* Slurp in the RGB buffer. */
1247       len = fread (q, 1, rgblength - rgbleftover[0], infile);
1248       rgbend = rgbbuf + len;
1249 
1250       q = data;
1251       if (gray)
1252 	{
1253 	  /* Zip through the buffer, converting color data to grayscale. */
1254 	  for (p = rgbbuf; p < rgbend; p += 3)
1255 	    *q++ = ((long) p[0] + p[1] + p[2]) / 3;
1256 	}
1257       else
1258 	{
1259 	  /* Zip through the buffer, extracting data for this pass. */
1260 	  for (p = (rgbbuf + (pass + 1) % 3); p < rgbend; p += 3)
1261 	    *q++ = *p;
1262 	}
1263 
1264       /* Save any leftovers in the array. */
1265       rgbleftover[0] = len % 3;
1266       p = rgbbuf + (len - rgbleftover[0]);
1267       q = rgbleftover + 1;
1268       while (p < rgbend)
1269 	*q++ = *p++;
1270 
1271       len /= 3;
1272     }
1273   else
1274     /* Suck in as much of the file as possible, since it's already in the
1275        correct format. */
1276     len = fread (data, 1, max_length, infile);
1277 
1278   if (len == 0)
1279     {
1280       if (feof (infile))
1281 	{
1282 	  DBG (2, "sane_read: EOF reached\n");
1283 	  return SANE_STATUS_EOF;
1284 	}
1285       else
1286 	{
1287 	  DBG (1, "sane_read: error while reading file (%s)\n",
1288 	       strerror (errno));
1289 	  return SANE_STATUS_IO_ERROR;
1290 	}
1291     }
1292 
1293   if (parms.depth == 8)
1294     {
1295       /* Do the transformations ... DEMO ONLY ! THIS MAKES NO SENSE ! */
1296       for (x = 0; x < len; x++)
1297 	{
1298 	  hlp = *((unsigned char *) data + x) - 128;
1299 	  hlp *= (contr + (100 << SANE_FIXED_SCALE_SHIFT));
1300 	  hlp /= 100 << SANE_FIXED_SCALE_SHIFT;
1301 	  hlp += (bright >> SANE_FIXED_SCALE_SHIFT) + 128;
1302 	  if (hlp < 0)
1303 	    hlp = 0;
1304 	  if (hlp > 255)
1305 	    hlp = 255;
1306 	  *(data + x) = hlp;
1307 	}
1308       /*gamma */
1309       if (usegamma)
1310 	{
1311 	  unsigned char uc;
1312 	  if (gray)
1313 	    {
1314 	      for (x = 0; x < len; x++)
1315 		{
1316 		  uc = *((unsigned char *) data + x);
1317 		  uc = gamma[0][uc];
1318 		  *(data + x) = uc;
1319 		}
1320 	    }
1321 	  else
1322 	    {
1323 	      for (x = 0; x < len; x++)
1324 		{
1325 		  if (parms.format == SANE_FRAME_RGB)
1326 		    {
1327 		      uc = *((unsigned char *) (data + x));
1328 		      uc = (unsigned char) gamma[rgb_comp + 1][(int) uc];
1329 		      *((unsigned char *) data + x) = uc;
1330 		      rgb_comp += 1;
1331 		      if (rgb_comp > 2)
1332 			rgb_comp = 0;
1333 		    }
1334 		  else
1335 		    {
1336 		      int f = 0;
1337 		      if (parms.format == SANE_FRAME_RED)
1338 			f = 1;
1339 		      if (parms.format == SANE_FRAME_GREEN)
1340 			f = 2;
1341 		      if (parms.format == SANE_FRAME_BLUE)
1342 			f = 3;
1343 		      if (f)
1344 			{
1345 			  uc = *((unsigned char *) (data + x));
1346 			  uc = (unsigned char) gamma[f][(int) uc];
1347 			  *((unsigned char *) data + x) = uc;
1348 			}
1349 		    }
1350 		}
1351 	    }
1352 	}
1353     }
1354   *length = len;
1355   DBG (2, "sane_read: read %d bytes\n", len);
1356   return SANE_STATUS_GOOD;
1357 }
1358 
1359 void
sane_cancel(SANE_Handle handle)1360 sane_cancel (SANE_Handle handle)
1361 {
1362   DBG (2, "sane_cancel: handle = %p\n", handle);
1363   pass = 0;
1364   if (infile != NULL)
1365     {
1366       fclose (infile);
1367       infile = NULL;
1368     }
1369   return;
1370 }
1371 
1372 SANE_Status
sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking)1373 sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking)
1374 {
1375   DBG (2, "sane_set_io_mode: handle = %p, non_blocking = %d\n", handle,
1376        non_blocking);
1377   if (!infile)
1378     {
1379       DBG (1, "sane_set_io_mode: not scanning\n");
1380       return SANE_STATUS_INVAL;
1381     }
1382   if (non_blocking)
1383     return SANE_STATUS_UNSUPPORTED;
1384   return SANE_STATUS_GOOD;
1385 }
1386 
1387 SANE_Status
sane_get_select_fd(SANE_Handle handle, SANE_Int * fd)1388 sane_get_select_fd (SANE_Handle handle, SANE_Int * fd)
1389 {
1390   DBG (2, "sane_get_select_fd: handle = %p, fd %s 0\n", handle,
1391        fd ? "!=" : "=");
1392   return SANE_STATUS_UNSUPPORTED;
1393 }
1394