makefiles: Move the testing rules to the global Make.rules file.
[wine.git] / dlls / sane.ds / sane_main.c
blobc01baeb10d67705944dcc7bc69bf8ef3e6082703
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 "sane_i.h"
28 #include "wine/debug.h"
29 #include "wine/library.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33 HINSTANCE SANE_instance;
35 #ifdef SONAME_LIBSANE
37 static void *libsane_handle;
39 static void close_libsane(void *h)
41 if (h)
42 wine_dlclose(h, NULL, 0);
45 static void *open_libsane(void)
47 void *h;
49 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
50 if (!h)
52 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
53 return NULL;
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; \
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
79 return h;
82 #endif /* SONAME_LIBSANE */
84 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
86 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
88 switch (fdwReason)
90 case DLL_PROCESS_ATTACH: {
91 #ifdef SONAME_LIBSANE
92 SANE_Int version_code;
94 libsane_handle = open_libsane();
95 if (! libsane_handle)
96 return FALSE;
98 psane_init (&version_code, NULL);
99 #endif
100 SANE_instance = hinstDLL;
101 DisableThreadLibraryCalls(hinstDLL);
102 break;
104 case DLL_PROCESS_DETACH:
105 if (lpvReserved) break;
106 #ifdef SONAME_LIBSANE
107 TRACE("calling sane_exit()\n");
108 psane_exit ();
109 close_libsane(libsane_handle);
110 #endif
111 break;
114 return TRUE;
117 #ifdef SONAME_LIBSANE
118 static TW_UINT16 SANE_GetIdentity( pTW_IDENTITY, pTW_IDENTITY);
119 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY, pTW_IDENTITY);
120 #endif
122 static TW_UINT16 SANE_SourceControlHandler (
123 pTW_IDENTITY pOrigin,
124 TW_UINT16 DAT,
125 TW_UINT16 MSG,
126 TW_MEMREF pData)
128 TW_UINT16 twRC = TWRC_SUCCESS;
130 switch (DAT)
132 case DAT_IDENTITY:
133 switch (MSG)
135 case MSG_CLOSEDS:
136 #ifdef SONAME_LIBSANE
137 psane_close (activeDS.deviceHandle);
138 #else
139 twRC = TWRC_FAILURE;
140 activeDS.twCC = TWCC_CAPUNSUPPORTED;
141 #endif
142 break;
143 case MSG_OPENDS:
144 #ifdef SONAME_LIBSANE
145 twRC = SANE_OpenDS( pOrigin, (pTW_IDENTITY)pData);
146 #else
147 twRC = TWRC_FAILURE;
148 activeDS.twCC = TWCC_CAPUNSUPPORTED;
149 #endif
150 break;
151 case MSG_GET:
152 #ifdef SONAME_LIBSANE
153 twRC = SANE_GetIdentity( pOrigin, (pTW_IDENTITY)pData);
154 #else
155 twRC = TWRC_FAILURE;
156 activeDS.twCC = TWCC_CAPUNSUPPORTED;
157 #endif
158 break;
160 break;
161 case DAT_CAPABILITY:
162 switch (MSG)
164 case MSG_GET:
165 twRC = SANE_CapabilityGet (pOrigin, pData);
166 break;
167 case MSG_GETCURRENT:
168 twRC = SANE_CapabilityGetCurrent (pOrigin, pData);
169 break;
170 case MSG_GETDEFAULT:
171 twRC = SANE_CapabilityGetDefault (pOrigin, pData);
172 break;
173 case MSG_QUERYSUPPORT:
174 twRC = SANE_CapabilityQuerySupport (pOrigin, pData);
175 break;
176 case MSG_RESET:
177 twRC = SANE_CapabilityReset (pOrigin, pData);
178 break;
179 case MSG_SET:
180 twRC = SANE_CapabilitySet (pOrigin, pData);
181 break;
182 default:
183 twRC = TWRC_FAILURE;
184 activeDS.twCC = TWCC_CAPBADOPERATION;
185 FIXME("unrecognized opertion triplet\n");
186 break;
188 break;
190 case DAT_EVENT:
191 if (MSG == MSG_PROCESSEVENT)
192 twRC = SANE_ProcessEvent (pOrigin, pData);
193 else
195 activeDS.twCC = TWCC_CAPBADOPERATION;
196 twRC = TWRC_FAILURE;
198 break;
200 case DAT_PENDINGXFERS:
201 switch (MSG)
203 case MSG_ENDXFER:
204 twRC = SANE_PendingXfersEndXfer (pOrigin, pData);
205 break;
206 case MSG_GET:
207 twRC = SANE_PendingXfersGet (pOrigin, pData);
208 break;
209 case MSG_RESET:
210 twRC = SANE_PendingXfersReset (pOrigin, pData);
211 break;
212 default:
213 activeDS.twCC = TWCC_CAPBADOPERATION;
214 twRC = TWRC_FAILURE;
216 break;
218 case DAT_SETUPMEMXFER:
219 if (MSG == MSG_GET)
220 twRC = SANE_SetupMemXferGet (pOrigin, pData);
221 else
223 activeDS.twCC = TWCC_CAPBADOPERATION;
224 twRC = TWRC_FAILURE;
226 break;
228 case DAT_STATUS:
229 if (MSG == MSG_GET)
230 twRC = SANE_GetDSStatus (pOrigin, pData);
231 else
233 activeDS.twCC = TWCC_CAPBADOPERATION;
234 twRC = TWRC_FAILURE;
236 break;
238 case DAT_USERINTERFACE:
239 switch (MSG)
241 case MSG_DISABLEDS:
242 twRC = SANE_DisableDSUserInterface (pOrigin, pData);
243 break;
244 case MSG_ENABLEDS:
245 twRC = SANE_EnableDSUserInterface (pOrigin, pData);
246 break;
247 case MSG_ENABLEDSUIONLY:
248 twRC = SANE_EnableDSUIOnly (pOrigin, pData);
249 break;
250 default:
251 activeDS.twCC = TWCC_CAPBADOPERATION;
252 twRC = TWRC_FAILURE;
253 break;
255 break;
257 case DAT_XFERGROUP:
258 switch (MSG)
260 case MSG_GET:
261 twRC = SANE_XferGroupGet (pOrigin, pData);
262 break;
263 case MSG_SET:
264 twRC = SANE_XferGroupSet (pOrigin, pData);
265 break;
266 default:
267 activeDS.twCC = TWCC_CAPBADOPERATION;
268 twRC = TWRC_FAILURE;
269 break;
271 break;
273 default:
274 WARN("code unsupported: %d\n", DAT);
275 activeDS.twCC = TWCC_CAPUNSUPPORTED;
276 twRC = TWRC_FAILURE;
277 break;
280 return twRC;
284 static TW_UINT16 SANE_ImageGroupHandler (
285 pTW_IDENTITY pOrigin,
286 TW_UINT16 DAT,
287 TW_UINT16 MSG,
288 TW_MEMREF pData)
290 TW_UINT16 twRC = TWRC_SUCCESS;
292 switch (DAT)
294 case DAT_IMAGEINFO:
295 if (MSG == MSG_GET)
296 twRC = SANE_ImageInfoGet (pOrigin, pData);
297 else
299 activeDS.twCC = TWCC_CAPBADOPERATION;
300 twRC = TWRC_FAILURE;
302 break;
304 case DAT_IMAGELAYOUT:
305 switch (MSG)
307 case MSG_GET:
308 twRC = SANE_ImageLayoutGet (pOrigin, pData);
309 break;
310 case MSG_GETDEFAULT:
311 twRC = SANE_ImageLayoutGetDefault (pOrigin, pData);
312 break;
313 case MSG_RESET:
314 twRC = SANE_ImageLayoutReset (pOrigin, pData);
315 break;
316 case MSG_SET:
317 twRC = SANE_ImageLayoutSet (pOrigin, pData);
318 break;
319 default:
320 twRC = TWRC_FAILURE;
321 activeDS.twCC = TWCC_CAPBADOPERATION;
322 ERR("unrecognized operation triplet\n");
323 break;
325 break;
327 case DAT_IMAGEMEMXFER:
328 if (MSG == MSG_GET)
329 twRC = SANE_ImageMemXferGet (pOrigin, pData);
330 else
332 activeDS.twCC = TWCC_CAPBADOPERATION;
333 twRC = TWRC_FAILURE;
335 break;
337 case DAT_IMAGENATIVEXFER:
338 if (MSG == MSG_GET)
339 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
340 else
342 activeDS.twCC = TWCC_CAPBADOPERATION;
343 twRC = TWRC_FAILURE;
345 break;
347 default:
348 twRC = TWRC_FAILURE;
349 activeDS.twCC = TWCC_CAPUNSUPPORTED;
350 WARN("unsupported DG type %d\n", DAT);
351 break;
353 return twRC;
356 /* Main entry point for the TWAIN library */
357 TW_UINT16 WINAPI
358 DS_Entry ( pTW_IDENTITY pOrigin,
359 TW_UINT32 DG,
360 TW_UINT16 DAT,
361 TW_UINT16 MSG,
362 TW_MEMREF pData)
364 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
366 TRACE("(DG=%d DAT=%d MSG=%d)\n", DG, DAT, MSG);
368 switch (DG)
370 case DG_CONTROL:
371 twRC = SANE_SourceControlHandler (pOrigin,DAT,MSG,pData);
372 break;
373 case DG_IMAGE:
374 twRC = SANE_ImageGroupHandler (pOrigin,DAT,MSG,pData);
375 break;
376 case DG_AUDIO:
377 WARN("Audio group of controls not implemented yet.\n");
378 twRC = TWRC_FAILURE;
379 activeDS.twCC = TWCC_CAPUNSUPPORTED;
380 break;
381 default:
382 activeDS.twCC = TWCC_BADPROTOCOL;
383 twRC = TWRC_FAILURE;
386 return twRC;
389 #ifdef SONAME_LIBSANE
390 /* Sane returns device names that are longer than the 32 bytes allowed
391 by TWAIN. However, it colon separates them, and the last bit is
392 the most interesting. So we use the last bit, and add a signature
393 to ensure uniqueness */
394 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
396 const char *p;
397 int signature = 0;
399 if (strlen(in) <= outsize - 1)
401 strcpy(out, in);
402 return;
405 for (p = in; *p; p++)
406 signature += *p;
408 p = strrchr(in, ':');
409 if (!p)
410 p = in;
411 else
412 p++;
414 if (strlen(p) > outsize - 7 - 1)
415 p += strlen(p) - (outsize - 7 - 1);
417 strcpy(out, p);
418 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
422 static const SANE_Device **sane_devlist;
424 static void
425 detect_sane_devices(void) {
426 if (sane_devlist && sane_devlist[0]) return;
427 TRACE("detecting sane...\n");
428 if (psane_get_devices (&sane_devlist, SANE_FALSE) != SANE_STATUS_GOOD)
429 return;
432 static TW_UINT16
433 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
434 static int cursanedev = 0;
436 detect_sane_devices();
437 if (!sane_devlist[cursanedev])
438 return TWRC_FAILURE;
439 self->ProtocolMajor = TWON_PROTOCOLMAJOR;
440 self->ProtocolMinor = TWON_PROTOCOLMINOR;
441 self->SupportedGroups = DG_CONTROL | DG_IMAGE;
442 copy_sane_short_name(sane_devlist[cursanedev]->name, self->ProductName, sizeof(self->ProductName) - 1);
443 lstrcpynA (self->Manufacturer, sane_devlist[cursanedev]->vendor, sizeof(self->Manufacturer) - 1);
444 lstrcpynA (self->ProductFamily, sane_devlist[cursanedev]->model, sizeof(self->ProductFamily) - 1);
445 cursanedev++;
447 if (!sane_devlist[cursanedev] ||
448 !sane_devlist[cursanedev]->model ||
449 !sane_devlist[cursanedev]->vendor ||
450 !sane_devlist[cursanedev]->name
452 cursanedev = 0; /* wrap to begin */
453 return TWRC_SUCCESS;
456 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
457 SANE_Status status;
458 int i;
460 detect_sane_devices();
461 if (!sane_devlist[0]) {
462 ERR("No scanners? We should not get to OpenDS?\n");
463 return TWRC_FAILURE;
466 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
467 TW_STR32 name;
469 /* To make string as short as above */
470 lstrcpynA(name, sane_devlist[i]->vendor, sizeof(name)-1);
471 if (*self->Manufacturer && strcmp(name, self->Manufacturer))
472 continue;
473 lstrcpynA(name, sane_devlist[i]->model, sizeof(name)-1);
474 if (*self->ProductFamily && strcmp(name, self->ProductFamily))
475 continue;
476 copy_sane_short_name(sane_devlist[i]->name, name, sizeof(name) - 1);
477 if (*self->ProductName && strcmp(name, self->ProductName))
478 continue;
479 break;
481 if (!sane_devlist[i]) {
482 WARN("Scanner not found.\n");
483 return TWRC_FAILURE;
485 status = psane_open(sane_devlist[i]->name,&activeDS.deviceHandle);
486 if (status == SANE_STATUS_GOOD) {
487 activeDS.twCC = SANE_SaneSetDefaults();
488 if (activeDS.twCC == TWCC_SUCCESS) {
489 activeDS.currentState = 4;
490 return TWRC_SUCCESS;
492 else
493 psane_close(activeDS.deviceHandle);
495 else
496 ERR("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
497 return TWRC_FAILURE;
499 #endif