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