d3drm: Implement D3DRMVectorReflect.
[wine] / dlls / sane.ds / sane_main.c
1 /*
2  * SANE.DS functions
3  *
4  * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "twain.h"
30 #include "sane_i.h"
31 #include "wine/debug.h"
32 #include "wine/library.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
35
36 HINSTANCE SANE_instance;
37
38 #ifdef HAVE_SANE
39 #ifndef SONAME_LIBSANE
40 #define SONAME_LIBSANE      "libsane.so"
41 #endif
42
43 static void *libsane_handle;
44
45 static void close_libsane(void *h)
46 {
47     if (h)
48         wine_dlclose(h, NULL, 0);
49 }
50
51 static void *open_libsane(void)
52 {
53     void *h;
54
55     h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
56     if (!h)
57     {
58         WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
59         return NULL;
60     }
61
62 #define LOAD_FUNCPTR(f) \
63     if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
64         close_libsane(h); \
65         ERR("Could not dlsym %s\n", #f); \
66         return NULL; \
67     }
68
69     LOAD_FUNCPTR(sane_init)
70     LOAD_FUNCPTR(sane_exit)
71     LOAD_FUNCPTR(sane_get_devices)
72     LOAD_FUNCPTR(sane_open)
73     LOAD_FUNCPTR(sane_close)
74     LOAD_FUNCPTR(sane_get_option_descriptor)
75     LOAD_FUNCPTR(sane_control_option)
76     LOAD_FUNCPTR(sane_get_parameters)
77     LOAD_FUNCPTR(sane_start)
78     LOAD_FUNCPTR(sane_read)
79     LOAD_FUNCPTR(sane_cancel)
80     LOAD_FUNCPTR(sane_set_io_mode)
81     LOAD_FUNCPTR(sane_get_select_fd)
82     LOAD_FUNCPTR(sane_strstatus)
83 #undef LOAD_FUNCPTR
84
85     return h;
86 }
87
88 #endif /* HAVE_SANE */
89
90 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
91 {
92     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
93
94     switch (fdwReason)
95     {
96         case DLL_PROCESS_ATTACH: {
97 #ifdef HAVE_SANE
98             SANE_Status status;
99             SANE_Int version_code;
100
101             libsane_handle = open_libsane();
102             if (! libsane_handle)
103                 return FALSE;
104
105             status = psane_init (&version_code, NULL);
106 #endif
107             SANE_instance = hinstDLL;
108             DisableThreadLibraryCalls(hinstDLL);
109             break;
110         }
111         case DLL_PROCESS_DETACH:
112 #ifdef HAVE_SANE
113             TRACE("calling sane_exit()\n");
114             psane_exit ();
115
116             close_libsane(libsane_handle);
117             libsane_handle = NULL;
118 #endif 
119             SANE_instance = NULL;
120             break;
121     }
122
123     return TRUE;
124 }
125
126 #ifdef HAVE_SANE
127 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
128 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
129 #endif
130
131 static TW_UINT16 SANE_SourceControlHandler (
132            pTW_IDENTITY pOrigin,
133            TW_UINT16    DAT,
134            TW_UINT16    MSG,
135            TW_MEMREF    pData)
136 {
137     TW_UINT16 twRC = TWRC_SUCCESS;
138
139     switch (DAT)
140     {
141         case DAT_IDENTITY:
142             switch (MSG)
143             {
144                 case MSG_CLOSEDS:
145 #ifdef HAVE_SANE
146                      psane_close (activeDS.deviceHandle);
147 #endif
148                      break;
149                 case MSG_OPENDS:
150 #ifdef HAVE_SANE
151                      twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
152 #else
153                      twRC = TWRC_FAILURE;
154 #endif
155                      break;
156                 case MSG_GET:
157 #ifdef HAVE_SANE
158                      twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
159 #else
160                      twRC = TWRC_FAILURE;
161 #endif
162                      break;
163             }
164             break;
165         case DAT_CAPABILITY:
166             switch (MSG)
167             {
168                 case MSG_GET:
169                     twRC = SANE_CapabilityGet (pOrigin, pData);
170                     break;
171                 case MSG_GETCURRENT:
172                     twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
173                     break;
174                 case MSG_GETDEFAULT:
175                     twRC = SANE_CapabilityGetDefault (pOrigin, pData);
176                     break;
177                 case MSG_QUERYSUPPORT:
178                     twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
179                     break;
180                 case MSG_RESET:
181                     twRC = SANE_CapabilityReset (pOrigin, pData);
182                     break;
183                 case MSG_SET:
184                     twRC = SANE_CapabilitySet (pOrigin, pData);
185                     break;
186                 default:
187                     twRC = TWRC_FAILURE;
188                     FIXME("unrecognized opertion triplet\n");
189             }
190             break;
191
192         case DAT_CUSTOMDSDATA:
193             switch (MSG)
194             {
195                 case MSG_GET:
196                     twRC = SANE_CustomDSDataGet (pOrigin, pData);
197                     break;
198                 case MSG_SET:
199                     twRC = SANE_CustomDSDataSet (pOrigin, pData);
200                     break;
201                 default:
202                     break;
203             }
204             break;
205
206         case DAT_FILESYSTEM:
207             switch (MSG)
208             {
209                 /*case MSG_AUTOMATICCAPTUREDIRECTORY:
210                     twRC = SANE_AutomaticCaptureDirectory
211                                (pOrigin, pData);
212                     break;*/
213                 case MSG_CHANGEDIRECTORY:
214                     twRC = SANE_ChangeDirectory (pOrigin, pData);
215                     break;
216                 /*case MSG_COPY:
217                     twRC = SANE_FileSystemCopy (pOrigin, pData);
218                     break;*/
219                 case MSG_CREATEDIRECTORY:
220                     twRC = SANE_CreateDirectory (pOrigin, pData);
221                     break;
222                 case MSG_DELETE:
223                     twRC = SANE_FileSystemDelete (pOrigin, pData);
224                     break;
225                 case MSG_FORMATMEDIA:
226                     twRC = SANE_FormatMedia (pOrigin, pData);
227                     break;
228                 case MSG_GETCLOSE:
229                     twRC = SANE_FileSystemGetClose (pOrigin, pData);
230                     break;
231                 case MSG_GETFIRSTFILE:
232                     twRC = SANE_FileSystemGetFirstFile (pOrigin, pData);
233                     break;
234                 case MSG_GETINFO:
235                     twRC = SANE_FileSystemGetInfo (pOrigin, pData);
236                     break;
237                 case MSG_GETNEXTFILE:
238                     twRC = SANE_FileSystemGetNextFile (pOrigin, pData);
239                     break;
240                 case MSG_RENAME:
241                     twRC = SANE_FileSystemRename (pOrigin, pData);
242                     break;
243                 default:
244                     twRC = TWRC_FAILURE;
245                     break;
246             }
247             break;
248
249         case DAT_EVENT:
250             if (MSG == MSG_PROCESSEVENT)
251                 twRC = SANE_ProcessEvent (pOrigin, pData);
252             else
253                 twRC = TWRC_FAILURE;
254             break;
255
256         case DAT_PASSTHRU:
257             if (MSG == MSG_PASSTHRU)
258                 twRC = SANE_PassThrough (pOrigin, pData);
259             else
260                 twRC = TWRC_FAILURE;
261             break;
262
263         case DAT_PENDINGXFERS:
264             switch (MSG)
265             {
266                 case MSG_ENDXFER:
267                     twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
268                     break;
269                 case MSG_GET:
270                     twRC = SANE_PendingXfersGet (pOrigin, pData);
271                     break;
272                 case MSG_RESET:
273                     twRC = SANE_PendingXfersReset (pOrigin, pData);
274                     break;
275                 /*case MSG_STOPFEEDER:
276                     twRC = SANE_PendingXfersStopFeeder (pOrigin, pData);
277                     break;*/
278                 default:
279                     twRC = TWRC_FAILURE;
280             }
281             break;
282
283         case DAT_SETUPFILEXFER:
284             switch (MSG)
285             {
286                 case MSG_GET:
287                     twRC = SANE_SetupFileXferGet (pOrigin, pData);
288                     break;
289                 case MSG_GETDEFAULT:
290                     twRC = SANE_SetupFileXferGetDefault (pOrigin, pData);
291                     break;
292                 case MSG_RESET:
293                     twRC = SANE_SetupFileXferReset (pOrigin, pData);
294                     break;
295                 case MSG_SET:
296                     twRC = SANE_SetupFileXferSet (pOrigin, pData);
297                     break;
298                 default:
299                     twRC = TWRC_FAILURE;
300                     break;
301             }
302             break;
303
304         /*case DAT_SETUPFILEXFER2:
305             switch (MSG)
306             {
307                 case MSG_GET:
308                     twRC = SANE_SetupFileXfer2Get (pOrigin, pData);
309                     break;
310                 case MSG_GETDEFAULT:
311                     twRC = SANE_SetupFileXfer2GetDefault (pOrigin, pData);
312                     break;
313                 case MSG_RESET:
314                     twRC = SANE_SetupFileXfer2Reset (pOrigin, pData);
315                     break;
316                 case MSG_SET:
317                     twRC = SANE_SetupFileXfer2Set (pOrigin, pData);
318                     break;
319             }
320             break;*/
321         case DAT_SETUPMEMXFER:
322             if (MSG == MSG_GET)
323                 twRC = SANE_SetupMemXferGet (pOrigin, pData);
324             else
325                 twRC = TWRC_FAILURE;
326             break;
327
328         case DAT_STATUS:
329             if (MSG == MSG_GET)
330                 twRC = SANE_GetDSStatus (pOrigin, pData);
331             else
332                 twRC = TWRC_FAILURE;
333             break;
334
335         case DAT_USERINTERFACE:
336             switch (MSG)
337             {
338                 case MSG_DISABLEDS:
339                     twRC = SANE_DisableDSUserInterface (pOrigin, pData);
340                     break;
341                 case MSG_ENABLEDS:
342                     twRC = SANE_EnableDSUserInterface (pOrigin, pData);
343                     break;
344                 case MSG_ENABLEDSUIONLY:
345                     twRC = SANE_EnableDSUIOnly (pOrigin, pData);
346                     break;
347                 default:
348                     twRC = TWRC_FAILURE;
349                     break;
350             }
351             break;
352
353         case DAT_XFERGROUP:
354             switch (MSG)
355             {
356                 case MSG_GET:
357                     twRC = SANE_XferGroupGet (pOrigin, pData);
358                     break;
359                 case MSG_SET:
360                     twRC = SANE_XferGroupSet (pOrigin, pData);
361                     break;
362                 default:
363                     twRC = TWRC_FAILURE;
364                     break;
365             }
366             break;
367
368         default:
369             FIXME("code unknown: %d\n", DAT);
370             twRC = TWRC_FAILURE;
371             break;
372     }
373
374     return twRC;
375 }
376
377
378 TW_UINT16 SANE_ImageGroupHandler (
379            pTW_IDENTITY pOrigin,
380            TW_UINT16    DAT,
381            TW_UINT16    MSG,
382            TW_MEMREF    pData)
383 {
384     TW_UINT16 twRC = TWRC_SUCCESS;
385
386     switch (DAT)
387     {
388         case DAT_CIECOLOR:
389             if (MSG == MSG_GET)
390                 twRC = SANE_CIEColorGet (pOrigin, pData);
391             else
392                 twRC = TWRC_FAILURE;
393             break;
394
395         case DAT_EXTIMAGEINFO:
396             if (MSG == MSG_GET)
397                 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
398             else
399                 twRC = TWRC_FAILURE;
400             break;
401
402         case DAT_GRAYRESPONSE:
403             switch (MSG)
404             {
405                 case MSG_RESET:
406                     twRC = SANE_GrayResponseReset (pOrigin, pData);
407                     break;
408                 case MSG_SET:
409                     twRC = SANE_GrayResponseSet (pOrigin, pData);
410                     break;
411                 default:
412                     twRC = TWRC_FAILURE;
413                     activeDS.twCC = TWCC_BADPROTOCOL;
414                     FIXME("unrecognized operation triplet\n");
415                     break;
416             }
417             break;
418         case DAT_IMAGEFILEXFER:
419             if (MSG == MSG_GET)
420                 twRC = SANE_ImageFileXferGet (pOrigin, pData);
421             else
422                 twRC = TWRC_FAILURE;
423             break;
424
425         case DAT_IMAGEINFO:
426             if (MSG == MSG_GET)
427                 twRC = SANE_ImageInfoGet (pOrigin, pData);
428             else
429                 twRC = TWRC_FAILURE;
430             break;
431
432         case DAT_IMAGELAYOUT:
433             switch (MSG)
434             {
435                 case MSG_GET:
436                     twRC = SANE_ImageLayoutGet (pOrigin, pData);
437                     break;
438                 case MSG_GETDEFAULT:
439                     twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
440                     break;
441                 case MSG_RESET:
442                     twRC = SANE_ImageLayoutReset (pOrigin, pData);
443                     break;
444                 case MSG_SET:
445                     twRC = SANE_ImageLayoutSet (pOrigin, pData);
446                     break;
447                 default:
448                     twRC = TWRC_FAILURE;
449                     activeDS.twCC = TWCC_BADPROTOCOL;
450                     ERR("unrecognized operation triplet\n");
451                     break;
452             }
453             break;
454
455         case DAT_IMAGEMEMXFER:
456             if (MSG == MSG_GET)
457                 twRC = SANE_ImageMemXferGet (pOrigin, pData);
458             else
459                 twRC = TWRC_FAILURE;
460             break;
461
462         case DAT_IMAGENATIVEXFER:
463             if (MSG == MSG_GET)
464                 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
465             else
466                 twRC = TWRC_FAILURE;
467             break;
468
469         case DAT_JPEGCOMPRESSION:
470             switch (MSG)
471             {
472                 case MSG_GET:
473                     twRC = SANE_JPEGCompressionGet (pOrigin, pData);
474                     break;
475                 case MSG_GETDEFAULT:
476                     twRC = SANE_JPEGCompressionGetDefault (pOrigin, pData);
477                     break;
478                 case MSG_RESET:
479                     twRC = SANE_JPEGCompressionReset (pOrigin, pData);
480                     break;
481                 case MSG_SET:
482                     twRC = SANE_JPEGCompressionSet (pOrigin, pData);
483                     break;
484                 default:
485                     twRC = TWRC_FAILURE;
486                     activeDS.twCC = TWCC_BADPROTOCOL;
487                     WARN("unrecognized operation triplet\n");
488                     break;
489             }
490             break;
491
492         case DAT_PALETTE8:
493             switch (MSG)
494             {
495                 case MSG_GET:
496                     twRC = SANE_Palette8Get (pOrigin, pData);
497                     break;
498                 case MSG_GETDEFAULT:
499                     twRC = SANE_Palette8GetDefault (pOrigin, pData);
500                     break;
501                 case MSG_RESET:
502                     twRC = SANE_Palette8Reset (pOrigin, pData);
503                     break;
504                 case MSG_SET:
505                     twRC = SANE_Palette8Set (pOrigin, pData);
506                     break;
507                 default:
508                     twRC = TWRC_FAILURE;
509                     activeDS.twCC = TWCC_BADPROTOCOL;
510                     WARN("unrecognized operation triplet\n");
511             }
512             break;
513
514         case DAT_RGBRESPONSE:
515             switch (MSG)
516             {
517                 case MSG_RESET:
518                     twRC = SANE_RGBResponseReset (pOrigin, pData);
519                     break;
520                 case MSG_SET:
521                     twRC = SANE_RGBResponseSet (pOrigin, pData);
522                     break;
523                 default:
524                     twRC = TWRC_FAILURE;
525                     activeDS.twCC = TWCC_BADPROTOCOL;
526                     WARN("unrecognized operation triplet\n");
527                     break;
528             }
529             break;
530
531         default:
532             twRC = TWRC_FAILURE;
533             activeDS.twCC = TWCC_BADPROTOCOL;
534             FIXME("unrecognized DG type %d\n", DAT);
535     }
536     return twRC;
537 }
538
539 /* Main entry point for the TWAIN library */
540 TW_UINT16 WINAPI
541 DS_Entry ( pTW_IDENTITY pOrigin,
542            TW_UINT32    DG,
543            TW_UINT16    DAT,
544            TW_UINT16    MSG,
545            TW_MEMREF    pData)
546 {
547     TW_UINT16 twRC = TWRC_SUCCESS;  /* Return Code */
548
549     TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
550
551     switch (DG)
552     {
553         case DG_CONTROL:
554             twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
555             break;
556         case DG_IMAGE:
557             twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
558             break;
559         case DG_AUDIO:
560             FIXME("Audio group of controls not implemented yet.\n");
561         default:
562             activeDS.twCC = TWCC_BADPROTOCOL;
563             twRC = TWRC_FAILURE;
564     }
565
566     return twRC;
567 }
568
569 #ifdef HAVE_SANE
570 /* Sane returns device names that are longer than the 32 bytes allowed
571    by TWAIN.  However, it colon separates them, and the last bit is
572    the most interesting.  So we use the last bit, and add a signature
573    to ensure uniqueness */
574 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
575 {
576     const char *p;
577     int  signature = 0;
578
579     if (strlen(in) <= outsize - 1)
580     {
581         strcpy(out, in);
582         return;
583     }
584
585     for (p = in; *p; p++)
586         signature += *p;
587
588     p = strrchr(in, ':');
589     if (!p)
590         p = in;
591     else
592         p++;
593
594     if (strlen(p) > outsize - 7 - 1)
595         p += strlen(p) - (outsize - 7 - 1);
596
597     strcpy(out, p);
598     sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
599
600 }
601
602 static const SANE_Device **sane_devlist;
603
604 static void
605 detect_sane_devices(void) {
606     if (sane_devlist && sane_devlist[0]) return;
607     TRACE("detecting sane...\n");
608     if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
609         return;
610 }
611
612 static TW_UINT16
613 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
614     static int cursanedev = 0;
615
616     detect_sane_devices();
617     if (!sane_devlist[cursanedev])
618         return TWRC_FAILURE;
619     self->ProtocolMajor = TWON_PROTOCOLMAJOR;
620     self->ProtocolMinor = TWON_PROTOCOLMINOR;
621     copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
622     lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
623     lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
624     cursanedev++;
625
626     if (!sane_devlist[cursanedev]               ||
627         !sane_devlist[cursanedev]->model        ||
628         !sane_devlist[cursanedev]->vendor       ||
629         !sane_devlist[cursanedev]->name
630     )
631         cursanedev = 0; /* wrap to begin */
632     return TWRC_SUCCESS;
633 }
634
635 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
636     SANE_Status status;
637     int i;
638
639     detect_sane_devices();
640     if (!sane_devlist[0]) {
641         ERR("No scanners? We should not get to OpenDS?\n");
642         return TWRC_FAILURE;
643     }
644
645     for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
646         TW_STR32 name;
647
648         /* To make string as short as above */
649         lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
650         if (strcmp(name, self->Manufacturer))
651             continue;
652         lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
653         if (strcmp(name, self->ProductFamily))
654             continue;
655         copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
656         if (strcmp(name, self->ProductName))
657             continue;
658         break;
659     }
660     if (!sane_devlist[i]) {
661         FIXME("Scanner not found? Using first one!\n");
662         i=0;
663     }
664     status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
665     if (status == SANE_STATUS_GOOD) {
666         activeDS.currentState = 4;
667         activeDS.twCC = TWRC_SUCCESS;
668         return TWRC_SUCCESS;
669     }
670     FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
671     return TWRC_FAILURE;
672 }
673 #endif