jscript: Pass correct cpbegin to InitMatch.
[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 "sane_i.h"
28 #include "wine/debug.h"
29 #include "wine/library.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(twain);
32
33 HINSTANCE SANE_instance;
34
35 #ifdef SONAME_LIBSANE
36
37 static void *libsane_handle;
38
39 static void close_libsane(void *h)
40 {
41     if (h)
42         wine_dlclose(h, NULL, 0);
43 }
44
45 static void *open_libsane(void)
46 {
47     void *h;
48
49     h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
50     if (!h)
51     {
52         WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
53         return NULL;
54     }
55
56 #define LOAD_FUNCPTR(f) \
57     if((p##f = wine_dlsym(h, #f, NULL, 0)) == NULL) { \
58         close_libsane(h); \
59         ERR("Could not dlsym %s\n", #f); \
60         return NULL; \
61     }
62
63     LOAD_FUNCPTR(sane_init)
64     LOAD_FUNCPTR(sane_exit)
65     LOAD_FUNCPTR(sane_get_devices)
66     LOAD_FUNCPTR(sane_open)
67     LOAD_FUNCPTR(sane_close)
68     LOAD_FUNCPTR(sane_get_option_descriptor)
69     LOAD_FUNCPTR(sane_control_option)
70     LOAD_FUNCPTR(sane_get_parameters)
71     LOAD_FUNCPTR(sane_start)
72     LOAD_FUNCPTR(sane_read)
73     LOAD_FUNCPTR(sane_cancel)
74     LOAD_FUNCPTR(sane_set_io_mode)
75     LOAD_FUNCPTR(sane_get_select_fd)
76     LOAD_FUNCPTR(sane_strstatus)
77 #undef LOAD_FUNCPTR
78
79     return h;
80 }
81
82 #endif /* SONAME_LIBSANE */
83
84 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
85 {
86     TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
87
88     switch (fdwReason)
89     {
90         case DLL_PROCESS_ATTACH: {
91 #ifdef SONAME_LIBSANE
92             SANE_Int version_code;
93
94             libsane_handle = open_libsane();
95             if (! libsane_handle)
96                 return FALSE;
97
98             psane_init (&version_code, NULL);
99 #endif
100             SANE_instance = hinstDLL;
101             DisableThreadLibraryCalls(hinstDLL);
102             break;
103         }
104         case DLL_PROCESS_DETACH:
105 #ifdef SONAME_LIBSANE
106             TRACE("calling sane_exit()\n");
107             psane_exit ();
108
109             close_libsane(libsane_handle);
110             libsane_handle = NULL;
111 #endif 
112             SANE_instance = NULL;
113             break;
114     }
115
116     return TRUE;
117 }
118
119 #ifdef SONAME_LIBSANE
120 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
121 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
122 #endif
123
124 static TW_UINT16 SANE_SourceControlHandler (
125            pTW_IDENTITY pOrigin,
126            TW_UINT16    DAT,
127            TW_UINT16    MSG,
128            TW_MEMREF    pData)
129 {
130     TW_UINT16 twRC = TWRC_SUCCESS;
131
132     switch (DAT)
133     {
134         case DAT_IDENTITY:
135             switch (MSG)
136             {
137                 case MSG_CLOSEDS:
138 #ifdef SONAME_LIBSANE
139                      psane_close (activeDS.deviceHandle);
140 #else
141                      twRC = TWRC_FAILURE;
142                      activeDS.twCC = TWCC_CAPUNSUPPORTED;
143 #endif
144                      break;
145                 case MSG_OPENDS:
146 #ifdef SONAME_LIBSANE
147                      twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
148 #else
149                      twRC = TWRC_FAILURE;
150                      activeDS.twCC = TWCC_CAPUNSUPPORTED;
151 #endif
152                      break;
153                 case MSG_GET:
154 #ifdef SONAME_LIBSANE
155                      twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
156 #else
157                      twRC = TWRC_FAILURE;
158                      activeDS.twCC = TWCC_CAPUNSUPPORTED;
159 #endif
160                      break;
161             }
162             break;
163         case DAT_CAPABILITY:
164             switch (MSG)
165             {
166                 case MSG_GET:
167                     twRC = SANE_CapabilityGet (pOrigin, pData);
168                     break;
169                 case MSG_GETCURRENT:
170                     twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
171                     break;
172                 case MSG_GETDEFAULT:
173                     twRC = SANE_CapabilityGetDefault (pOrigin, pData);
174                     break;
175                 case MSG_QUERYSUPPORT:
176                     twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
177                     break;
178                 case MSG_RESET:
179                     twRC = SANE_CapabilityReset (pOrigin, pData);
180                     break;
181                 case MSG_SET:
182                     twRC = SANE_CapabilitySet (pOrigin, pData);
183                     break;
184                 default:
185                     twRC = TWRC_FAILURE;
186                     activeDS.twCC = TWCC_CAPBADOPERATION;
187                     FIXME("unrecognized opertion triplet\n");
188                     break;
189             }
190             break;
191
192         case DAT_EVENT:
193             if (MSG == MSG_PROCESSEVENT)
194                 twRC = SANE_ProcessEvent (pOrigin, pData);
195             else
196             {
197                 activeDS.twCC = TWCC_CAPBADOPERATION;
198                 twRC = TWRC_FAILURE;
199             }
200             break;
201
202         case DAT_PENDINGXFERS:
203             switch (MSG)
204             {
205                 case MSG_ENDXFER:
206                     twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
207                     break;
208                 case MSG_GET:
209                     twRC = SANE_PendingXfersGet (pOrigin, pData);
210                     break;
211                 case MSG_RESET:
212                     twRC = SANE_PendingXfersReset (pOrigin, pData);
213                     break;
214                 default:
215                     activeDS.twCC = TWCC_CAPBADOPERATION;
216                     twRC = TWRC_FAILURE;
217             }
218             break;
219
220         case DAT_SETUPMEMXFER:
221             if (MSG == MSG_GET)
222                 twRC = SANE_SetupMemXferGet (pOrigin, pData);
223             else
224             {
225                 activeDS.twCC = TWCC_CAPBADOPERATION;
226                 twRC = TWRC_FAILURE;
227             }
228             break;
229
230         case DAT_STATUS:
231             if (MSG == MSG_GET)
232                 twRC = SANE_GetDSStatus (pOrigin, pData);
233             else
234             {
235                 activeDS.twCC = TWCC_CAPBADOPERATION;
236                 twRC = TWRC_FAILURE;
237             }
238             break;
239
240         case DAT_USERINTERFACE:
241             switch (MSG)
242             {
243                 case MSG_DISABLEDS:
244                     twRC = SANE_DisableDSUserInterface (pOrigin, pData);
245                     break;
246                 case MSG_ENABLEDS:
247                     twRC = SANE_EnableDSUserInterface (pOrigin, pData);
248                     break;
249                 case MSG_ENABLEDSUIONLY:
250                     twRC = SANE_EnableDSUIOnly (pOrigin, pData);
251                     break;
252                 default:
253                     activeDS.twCC = TWCC_CAPBADOPERATION;
254                     twRC = TWRC_FAILURE;
255                     break;
256             }
257             break;
258
259         case DAT_XFERGROUP:
260             switch (MSG)
261             {
262                 case MSG_GET:
263                     twRC = SANE_XferGroupGet (pOrigin, pData);
264                     break;
265                 case MSG_SET:
266                     twRC = SANE_XferGroupSet (pOrigin, pData);
267                     break;
268                 default:
269                     activeDS.twCC = TWCC_CAPBADOPERATION;
270                     twRC = TWRC_FAILURE;
271                     break;
272             }
273             break;
274
275         default:
276             WARN("code unsupported: %d\n", DAT);
277             activeDS.twCC = TWCC_CAPUNSUPPORTED;
278             twRC = TWRC_FAILURE;
279             break;
280     }
281
282     return twRC;
283 }
284
285
286 static TW_UINT16 SANE_ImageGroupHandler (
287            pTW_IDENTITY pOrigin,
288            TW_UINT16    DAT,
289            TW_UINT16    MSG,
290            TW_MEMREF    pData)
291 {
292     TW_UINT16 twRC = TWRC_SUCCESS;
293
294     switch (DAT)
295     {
296         case DAT_IMAGEINFO:
297             if (MSG == MSG_GET)
298                 twRC = SANE_ImageInfoGet (pOrigin, pData);
299             else
300             {
301                 activeDS.twCC = TWCC_CAPBADOPERATION;
302                 twRC = TWRC_FAILURE;
303             }
304             break;
305
306         case DAT_IMAGELAYOUT:
307             switch (MSG)
308             {
309                 case MSG_GET:
310                     twRC = SANE_ImageLayoutGet (pOrigin, pData);
311                     break;
312                 case MSG_GETDEFAULT:
313                     twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
314                     break;
315                 case MSG_RESET:
316                     twRC = SANE_ImageLayoutReset (pOrigin, pData);
317                     break;
318                 case MSG_SET:
319                     twRC = SANE_ImageLayoutSet (pOrigin, pData);
320                     break;
321                 default:
322                     twRC = TWRC_FAILURE;
323                     activeDS.twCC = TWCC_CAPBADOPERATION;
324                     ERR("unrecognized operation triplet\n");
325                     break;
326             }
327             break;
328
329         case DAT_IMAGEMEMXFER:
330             if (MSG == MSG_GET)
331                 twRC = SANE_ImageMemXferGet (pOrigin, pData);
332             else
333             {
334                 activeDS.twCC = TWCC_CAPBADOPERATION;
335                 twRC = TWRC_FAILURE;
336             }
337             break;
338
339         case DAT_IMAGENATIVEXFER:
340             if (MSG == MSG_GET)
341                 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
342             else
343             {
344                 activeDS.twCC = TWCC_CAPBADOPERATION;
345                 twRC = TWRC_FAILURE;
346             }
347             break;
348
349         default:
350             twRC = TWRC_FAILURE;
351             activeDS.twCC = TWCC_CAPUNSUPPORTED;
352             WARN("unsupported DG type %d\n", DAT);
353             break;
354     }
355     return twRC;
356 }
357
358 /* Main entry point for the TWAIN library */
359 TW_UINT16 WINAPI
360 DS_Entry ( pTW_IDENTITY pOrigin,
361            TW_UINT32    DG,
362            TW_UINT16    DAT,
363            TW_UINT16    MSG,
364            TW_MEMREF    pData)
365 {
366     TW_UINT16 twRC = TWRC_SUCCESS;  /* Return Code */
367
368     TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
369
370     switch (DG)
371     {
372         case DG_CONTROL:
373             twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
374             break;
375         case DG_IMAGE:
376             twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
377             break;
378         case DG_AUDIO:
379             WARN("Audio group of controls not implemented yet.\n");
380             twRC = TWRC_FAILURE;
381             activeDS.twCC = TWCC_CAPUNSUPPORTED;
382             break;
383         default:
384             activeDS.twCC = TWCC_BADPROTOCOL;
385             twRC = TWRC_FAILURE;
386     }
387
388     return twRC;
389 }
390
391 #ifdef SONAME_LIBSANE
392 /* Sane returns device names that are longer than the 32 bytes allowed
393    by TWAIN.  However, it colon separates them, and the last bit is
394    the most interesting.  So we use the last bit, and add a signature
395    to ensure uniqueness */
396 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
397 {
398     const char *p;
399     int  signature = 0;
400
401     if (strlen(in) <= outsize - 1)
402     {
403         strcpy(out, in);
404         return;
405     }
406
407     for (p = in; *p; p++)
408         signature += *p;
409
410     p = strrchr(in, ':');
411     if (!p)
412         p = in;
413     else
414         p++;
415
416     if (strlen(p) > outsize - 7 - 1)
417         p += strlen(p) - (outsize - 7 - 1);
418
419     strcpy(out, p);
420     sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
421
422 }
423
424 static const SANE_Device **sane_devlist;
425
426 static void
427 detect_sane_devices(void) {
428     if (sane_devlist && sane_devlist[0]) return;
429     TRACE("detecting sane...\n");
430     if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
431         return;
432 }
433
434 static TW_UINT16
435 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
436     static int cursanedev = 0;
437
438     detect_sane_devices();
439     if (!sane_devlist[cursanedev])
440         return TWRC_FAILURE;
441     self->ProtocolMajor = TWON_PROTOCOLMAJOR;
442     self->ProtocolMinor = TWON_PROTOCOLMINOR;
443     self->SupportedGroups = DG_CONTROL | DG_IMAGE;
444     copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
445     lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
446     lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
447     cursanedev++;
448
449     if (!sane_devlist[cursanedev]               ||
450         !sane_devlist[cursanedev]->model        ||
451         !sane_devlist[cursanedev]->vendor       ||
452         !sane_devlist[cursanedev]->name
453     )
454         cursanedev = 0; /* wrap to begin */
455     return TWRC_SUCCESS;
456 }
457
458 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
459     SANE_Status status;
460     int i;
461
462     detect_sane_devices();
463     if (!sane_devlist[0]) {
464         ERR("No scanners? We should not get to OpenDS?\n");
465         return TWRC_FAILURE;
466     }
467
468     for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
469         TW_STR32 name;
470
471         /* To make string as short as above */
472         lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
473         if (*self->Manufacturer && strcmp(name, self->Manufacturer))
474             continue;
475         lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
476         if (*self->ProductFamily && strcmp(name, self->ProductFamily))
477             continue;
478         copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
479         if (*self->ProductName && strcmp(name, self->ProductName))
480             continue;
481         break;
482     }
483     if (!sane_devlist[i]) {
484         WARN("Scanner not found.\n");
485         return TWRC_FAILURE;
486     }
487     status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
488     if (status == SANE_STATUS_GOOD) {
489         activeDS.twCC = SANE_SaneSetDefaults();
490         if (activeDS.twCC == TWCC_SUCCESS) {
491             activeDS.currentState = 4;
492             return TWRC_SUCCESS;
493         }
494         else
495             psane_close(activeDS.deviceHandle);
496     }
497     else
498         ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
499     return TWRC_FAILURE;
500 }
501 #endif