shlwapi/tests: Run more language dependent tests only on English locales.
[wine.git] / dlls / sane.ds / sane_main.c
blob13422bb8bac129082712fc112854e01de132a983
1 /*
2 * SANE.DS functions
4 * Copyright 2000 Shi Quan He <shiquan@cyberdude.com>
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
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"
34 WINE_DEFAULT_DEBUG_CHANNEL(twain);
36 HINSTANCE SANE_instance;
38 #ifdef SONAME_LIBSANE
40 static void *libsane_handle;
42 static void close_libsane(void *h)
44 if (h)
45 wine_dlclose(h, NULL, 0);
48 static void *open_libsane(void)
50 void *h;
52 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
53 if (!h)
55 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
56 return NULL;
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; \
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
82 return h;
85 #endif /* SONAME_LIBSANE */
87 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
89 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
91 switch (fdwReason)
93 case DLL_PROCESS_ATTACH: {
94 #ifdef SONAME_LIBSANE
95 SANE_Int version_code;
97 libsane_handle = open_libsane();
98 if (! libsane_handle)
99 return FALSE;
101 psane_init (&version_code, NULL);
102 #endif
103 SANE_instance = hinstDLL;
104 DisableThreadLibraryCalls(hinstDLL);
105 break;
107 case DLL_PROCESS_DETACH:
108 #ifdef SONAME_LIBSANE
109 TRACE("calling sane_exit()\n");
110 psane_exit ();
112 close_libsane(libsane_handle);
113 libsane_handle = NULL;
114 #endif
115 SANE_instance = NULL;
116 break;
119 return TRUE;
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
127 static TW_UINT16 SANE_SourceControlHandler (
128 pTW_IDENTITY pOrigin,
129 TW_UINT16 DAT,
130 TW_UINT16 MSG,
131 TW_MEMREF pData)
133 TW_UINT16 twRC = TWRC_SUCCESS;
135 switch (DAT)
137 case DAT_IDENTITY:
138 switch (MSG)
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;
165 break;
166 case DAT_CAPABILITY:
167 switch (MSG)
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;
193 break;
195 case DAT_EVENT:
196 if (MSG == MSG_PROCESSEVENT)
197 twRC = SANE_ProcessEvent (pOrigin, pData);
198 else
200 activeDS.twCC = TWCC_CAPBADOPERATION;
201 twRC = TWRC_FAILURE;
203 break;
205 case DAT_PENDINGXFERS:
206 switch (MSG)
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;
221 break;
223 case DAT_SETUPMEMXFER:
224 if (MSG == MSG_GET)
225 twRC = SANE_SetupMemXferGet (pOrigin, pData);
226 else
228 activeDS.twCC = TWCC_CAPBADOPERATION;
229 twRC = TWRC_FAILURE;
231 break;
233 case DAT_STATUS:
234 if (MSG == MSG_GET)
235 twRC = SANE_GetDSStatus (pOrigin, pData);
236 else
238 activeDS.twCC = TWCC_CAPBADOPERATION;
239 twRC = TWRC_FAILURE;
241 break;
243 case DAT_USERINTERFACE:
244 switch (MSG)
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;
260 break;
262 case DAT_XFERGROUP:
263 switch (MSG)
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;
276 break;
278 default:
279 WARN("code unsupported: %d\n", DAT);
280 activeDS.twCC = TWCC_CAPUNSUPPORTED;
281 twRC = TWRC_FAILURE;
282 break;
285 return twRC;
289 static TW_UINT16 SANE_ImageGroupHandler (
290 pTW_IDENTITY pOrigin,
291 TW_UINT16 DAT,
292 TW_UINT16 MSG,
293 TW_MEMREF pData)
295 TW_UINT16 twRC = TWRC_SUCCESS;
297 switch (DAT)
299 case DAT_IMAGEINFO:
300 if (MSG == MSG_GET)
301 twRC = SANE_ImageInfoGet (pOrigin, pData);
302 else
304 activeDS.twCC = TWCC_CAPBADOPERATION;
305 twRC = TWRC_FAILURE;
307 break;
309 case DAT_IMAGELAYOUT:
310 switch (MSG)
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;
330 break;
332 case DAT_IMAGEMEMXFER:
333 if (MSG == MSG_GET)
334 twRC = SANE_ImageMemXferGet (pOrigin, pData);
335 else
337 activeDS.twCC = TWCC_CAPBADOPERATION;
338 twRC = TWRC_FAILURE;
340 break;
342 case DAT_IMAGENATIVEXFER:
343 if (MSG == MSG_GET)
344 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
345 else
347 activeDS.twCC = TWCC_CAPBADOPERATION;
348 twRC = TWRC_FAILURE;
350 break;
352 default:
353 twRC = TWRC_FAILURE;
354 activeDS.twCC = TWCC_CAPUNSUPPORTED;
355 WARN("unsupported DG type %d\n", DAT);
356 break;
358 return twRC;
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)
369 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
371 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
373 switch (DG)
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;
391 return twRC;
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)
401 const char *p;
402 int signature = 0;
404 if (strlen(in) <= outsize - 1)
406 strcpy(out, in);
407 return;
410 for (p = in; *p; p++)
411 signature += *p;
413 p = strrchr(in, ':');
414 if (!p)
415 p = in;
416 else
417 p++;
419 if (strlen(p) > outsize - 7 - 1)
420 p += strlen(p) - (outsize - 7 - 1);
422 strcpy(out, p);
423 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
427 static const SANE_Device **sane_devlist;
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;
437 static TW_UINT16
438 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
439 static int cursanedev = 0;
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++;
452 if (!sane_devlist[cursanedev] ||
453 !sane_devlist[cursanedev]->model ||
454 !sane_devlist[cursanedev]->vendor ||
455 !sane_devlist[cursanedev]->name
457 cursanedev = 0; /* wrap to begin */
458 return TWRC_SUCCESS;
461 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
462 SANE_Status status;
463 int i;
465 detect_sane_devices();
466 if (!sane_devlist[0]) {
467 ERR("No scanners? We should not get to OpenDS?\n");
468 return TWRC_FAILURE;
471 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
472 TW_STR32 name;
474 /* To make string as short as above */
475 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
476 if (self->Manufacturer && *self->Manufacturer && strcmp(name, self->Manufacturer))
477 continue;
478 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
479 if (self->ProductFamily && *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 && *self->ProductName && strcmp(name, self->ProductName))
483 continue;
484 break;
486 if (!sane_devlist[i]) {
487 WARN("Scanner not found.\n");
488 return TWRC_FAILURE;
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;
497 else
498 psane_close(activeDS.deviceHandle);
500 else
501 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
502 return TWRC_FAILURE;
504 #endif