Changes in crossover-wine-src-6.1.0 except for configure
[wine/hacks.git] / dlls / sane.ds / sane_main.c
blobd08a96882dfb21ea4c1c68884b925096d59f472b
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 HAVE_SANE
39 #ifndef SONAME_LIBSANE
40 #define SONAME_LIBSANE "libsane.so"
41 #endif
43 static void *libsane_handle;
45 static void close_libsane(void *h)
47 if (h)
48 wine_dlclose(h, NULL, 0);
51 static void *open_libsane(void)
53 void *h;
55 h = wine_dlopen(SONAME_LIBSANE, RTLD_GLOBAL | RTLD_NOW, NULL, 0);
56 if (!h)
58 WARN("dlopen(%s) failed\n", SONAME_LIBSANE);
59 return NULL;
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; \
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
85 return h;
88 #endif /* HAVE_SANE */
90 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
92 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
94 switch (fdwReason)
96 case DLL_PROCESS_ATTACH: {
97 #ifdef HAVE_SANE
98 SANE_Status status;
99 SANE_Int version_code;
101 libsane_handle = open_libsane();
102 if (! libsane_handle)
103 return FALSE;
105 status = psane_init (&version_code, NULL);
106 #endif
107 SANE_instance = hinstDLL;
108 DisableThreadLibraryCalls(hinstDLL);
109 break;
111 case DLL_PROCESS_DETACH:
112 #ifdef HAVE_SANE
113 TRACE("calling sane_exit()\n");
114 psane_exit ();
116 close_libsane(libsane_handle);
117 libsane_handle = NULL;
118 #endif
119 SANE_instance = NULL;
120 break;
123 return TRUE;
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
131 static TW_UINT16 SANE_SourceControlHandler (
132 pTW_IDENTITY pOrigin,
133 TW_UINT16 DAT,
134 TW_UINT16 MSG,
135 TW_MEMREF pData)
137 TW_UINT16 twRC = TWRC_SUCCESS;
139 switch (DAT)
141 case DAT_IDENTITY:
142 switch (MSG)
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;
164 break;
165 case DAT_CAPABILITY:
166 switch (MSG)
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");
190 break;
192 case DAT_CUSTOMDSDATA:
193 switch (MSG)
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;
204 break;
206 case DAT_FILESYSTEM:
207 switch (MSG)
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;
247 break;
249 case DAT_EVENT:
250 if (MSG == MSG_PROCESSEVENT)
251 twRC = SANE_ProcessEvent (pOrigin, pData);
252 else
253 twRC = TWRC_FAILURE;
254 break;
256 case DAT_PASSTHRU:
257 if (MSG == MSG_PASSTHRU)
258 twRC = SANE_PassThrough (pOrigin, pData);
259 else
260 twRC = TWRC_FAILURE;
261 break;
263 case DAT_PENDINGXFERS:
264 switch (MSG)
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;
281 break;
283 case DAT_SETUPFILEXFER:
284 switch (MSG)
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;
302 break;
304 /*case DAT_SETUPFILEXFER2:
305 switch (MSG)
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;
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;
328 case DAT_STATUS:
329 if (MSG == MSG_GET)
330 twRC = SANE_GetDSStatus (pOrigin, pData);
331 else
332 twRC = TWRC_FAILURE;
333 break;
335 case DAT_USERINTERFACE:
336 switch (MSG)
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;
351 break;
353 case DAT_XFERGROUP:
354 switch (MSG)
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;
366 break;
368 default:
369 FIXME("code unknown: %d\n", DAT);
370 twRC = TWRC_FAILURE;
371 break;
374 return twRC;
378 TW_UINT16 SANE_ImageGroupHandler (
379 pTW_IDENTITY pOrigin,
380 TW_UINT16 DAT,
381 TW_UINT16 MSG,
382 TW_MEMREF pData)
384 TW_UINT16 twRC = TWRC_SUCCESS;
386 switch (DAT)
388 case DAT_CIECOLOR:
389 if (MSG == MSG_GET)
390 twRC = SANE_CIEColorGet (pOrigin, pData);
391 else
392 twRC = TWRC_FAILURE;
393 break;
395 case DAT_EXTIMAGEINFO:
396 if (MSG == MSG_GET)
397 twRC = SANE_ExtImageInfoGet (pOrigin, pData);
398 else
399 twRC = TWRC_FAILURE;
400 break;
402 case DAT_GRAYRESPONSE:
403 switch (MSG)
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;
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;
425 case DAT_IMAGEINFO:
426 if (MSG == MSG_GET)
427 twRC = SANE_ImageInfoGet (pOrigin, pData);
428 else
429 twRC = TWRC_FAILURE;
430 break;
432 case DAT_IMAGELAYOUT:
433 switch (MSG)
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;
453 break;
455 case DAT_IMAGEMEMXFER:
456 if (MSG == MSG_GET)
457 twRC = SANE_ImageMemXferGet (pOrigin, pData);
458 else
459 twRC = TWRC_FAILURE;
460 break;
462 case DAT_IMAGENATIVEXFER:
463 if (MSG == MSG_GET)
464 twRC = SANE_ImageNativeXferGet (pOrigin, pData);
465 else
466 twRC = TWRC_FAILURE;
467 break;
469 case DAT_JPEGCOMPRESSION:
470 switch (MSG)
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;
490 break;
492 case DAT_PALETTE8:
493 switch (MSG)
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");
512 break;
514 case DAT_RGBRESPONSE:
515 switch (MSG)
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;
529 break;
531 default:
532 twRC = TWRC_FAILURE;
533 activeDS.twCC = TWCC_BADPROTOCOL;
534 FIXME("unrecognized DG type %d\n", DAT);
536 return twRC;
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)
547 TW_UINT16 twRC = TWRC_SUCCESS; /* Return Code */
549 TRACE("(DG=%ld DAT=%d MSG=%d)\n", DG, DAT, MSG);
551 switch (DG)
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;
566 return twRC;
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)
576 const char *p;
577 int signature = 0;
579 if (strlen(in) <= outsize - 1)
581 strcpy(out, in);
582 return;
585 for (p = in; *p; p++)
586 signature += *p;
588 p = strrchr(in, ':');
589 if (!p)
590 p = in;
591 else
592 p++;
594 if (strlen(p) > outsize - 7 - 1)
595 p += strlen(p) - (outsize - 7 - 1);
597 strcpy(out, p);
598 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
602 static const SANE_Device **sane_devlist;
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;
612 static TW_UINT16
613 SANE_GetIdentity( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
614 static int cursanedev = 0;
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++;
626 if (!sane_devlist[cursanedev] ||
627 !sane_devlist[cursanedev]->model ||
628 !sane_devlist[cursanedev]->vendor ||
629 !sane_devlist[cursanedev]->name
631 cursanedev = 0; /* wrap to begin */
632 return TWRC_SUCCESS;
635 static TW_UINT16 SANE_OpenDS( pTW_IDENTITY pOrigin, pTW_IDENTITY self) {
636 SANE_Status status;
637 int i;
639 detect_sane_devices();
640 if (!sane_devlist[0]) {
641 ERR("No scanners? We should not get to OpenDS?\n");
642 return TWRC_FAILURE;
645 for (i=0; sane_devlist[i] && sane_devlist[i]->model; i++) {
646 TW_STR32 name;
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;
660 if (!sane_devlist[i]) {
661 FIXME("Scanner not found? Using first one!\n");
662 i=0;
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;
670 FIXME("sane_open(%s): %s\n", sane_devlist[i]->name, psane_strstatus (status));
671 return TWRC_FAILURE;
673 #endif