2 * Copyright 2000 Corel Corporation
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
34 static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
36 if (pCapability->hContainer)
38 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
43 *type = pVal->ItemType;
44 GlobalUnlock (pCapability->hContainer);
52 static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
54 pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
56 if (pCapability->hContainer)
58 pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
61 pCapability->ConType = TWON_ONEVALUE;
62 pVal->ItemType = type;
64 GlobalUnlock (pCapability->hContainer);
68 return TWCC_LOWMEMORY;
71 static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
73 if (pCapability->ConType == TWON_ONEVALUE)
74 return get_onevalue(pCapability, NULL, val);
76 FIXME("Partial Stub: MSG_SET only supports TW_ONEVALUE\n");
81 static TW_UINT16 msg_get_enum(pTW_CAPABILITY pCapability, const TW_UINT32 *values, int value_count,
82 TW_UINT16 type, TW_UINT32 current, TW_UINT32 default_value)
84 TW_ENUMERATION *enumv = NULL;
89 pCapability->ConType = TWON_ENUMERATION;
90 pCapability->hContainer = 0;
92 if (type == TWTY_INT16 || type == TWTY_UINT16)
93 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
95 if (type == TWTY_INT32 || type == TWTY_UINT32)
96 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
98 if (pCapability->hContainer)
99 enumv = GlobalLock(pCapability->hContainer);
102 return TWCC_LOWMEMORY;
104 enumv->ItemType = type;
105 enumv->NumItems = value_count;
107 p16 = (TW_UINT16 *) enumv->ItemList;
108 p32 = (TW_UINT32 *) enumv->ItemList;
109 for (i = 0; i < value_count; i++)
111 if (values[i] == current)
112 enumv->CurrentIndex = i;
113 if (values[i] == default_value)
114 enumv->DefaultIndex = i;
115 if (type == TWTY_INT16 || type == TWTY_UINT16)
117 if (type == TWTY_INT32 || type == TWTY_UINT32)
121 GlobalUnlock(pCapability->hContainer);
125 #ifdef SONAME_LIBSANE
126 static TW_UINT16 msg_get_range(pTW_CAPABILITY pCapability, TW_UINT16 type,
127 TW_UINT32 minval, TW_UINT32 maxval, TW_UINT32 step, TW_UINT32 def, TW_UINT32 current)
129 TW_RANGE *range = NULL;
131 pCapability->ConType = TWON_RANGE;
132 pCapability->hContainer = 0;
134 pCapability->hContainer = GlobalAlloc (0, sizeof(*range));
135 if (pCapability->hContainer)
136 range = GlobalLock(pCapability->hContainer);
139 return TWCC_LOWMEMORY;
141 range->ItemType = type;
142 range->MinValue = minval;
143 range->MaxValue = maxval;
144 range->StepSize = step;
145 range->DefaultValue = def;
146 range->CurrentValue = current;
148 GlobalUnlock(pCapability->hContainer);
153 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
156 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
157 ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_UNITS, ICAP_BITDEPTH, ICAP_COMPRESSION, ICAP_PIXELFLAVOR,
158 ICAP_XRESOLUTION, ICAP_YRESOLUTION };
160 pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
161 pCapability->ConType = TWON_ARRAY;
163 if (pCapability->hContainer)
167 a = GlobalLock (pCapability->hContainer);
168 a->ItemType = TWTY_UINT16;
169 a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
170 u = (UINT16 *) a->ItemList;
171 for (i = 0; i < a->NumItems; i++)
172 u[i] = supported_caps[i];
173 GlobalUnlock (pCapability->hContainer);
177 return TWCC_LOWMEMORY;
182 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
184 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
186 TW_UINT16 twCC = TWCC_BADCAP;
188 TRACE("ICAP_XFERMECH\n");
192 case MSG_QUERYSUPPORT:
193 twCC = set_onevalue(pCapability, TWTY_INT32,
194 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
198 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
199 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
203 twCC = msg_set(pCapability, &val);
204 if (twCC == TWCC_SUCCESS)
206 activeDS.capXferMech = (TW_UINT16) val;
207 FIXME("Partial Stub: XFERMECH set to %d, but ignored\n", val);
212 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
216 activeDS.capXferMech = TWSX_NATIVE;
217 /* .. fall through intentional .. */
220 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
221 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
229 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
232 TW_UINT16 twCC = TWCC_BADCAP;
234 TRACE("CAP_XFERCOUNT\n");
238 case MSG_QUERYSUPPORT:
239 twCC = set_onevalue(pCapability, TWTY_INT32,
240 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
244 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
245 FIXME("Partial Stub: Reporting only support for transfer all\n");
249 twCC = msg_set(pCapability, &val);
250 if (twCC == TWCC_SUCCESS)
251 FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val);
255 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
259 /* .. fall through intentional .. */
262 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
269 static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
271 static const TW_UINT32 possible_values[] = { TWPT_BW, TWPT_GRAY, TWPT_RGB };
273 TW_UINT16 twCC = TWCC_BADCAP;
275 TRACE("ICAP_PIXELTYPE\n");
279 case MSG_QUERYSUPPORT:
280 twCC = set_onevalue(pCapability, TWTY_INT32,
281 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
285 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
286 TWTY_UINT16, activeDS.capXferMech, TWPT_BW);
290 twCC = msg_set(pCapability, &val);
291 if (twCC == TWCC_SUCCESS)
293 activeDS.capPixelType = (TW_UINT16) val;
294 FIXME("Partial Stub: PIXELTYPE set to %d, but ignored\n", val);
299 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPT_BW);
303 activeDS.capPixelType = TWPT_BW;
304 /* .. fall through intentional .. */
307 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capPixelType);
315 static TW_UINT16 SANE_ICAPUnits (pTW_CAPABILITY pCapability, TW_UINT16 action)
318 TW_UINT16 twCC = TWCC_BADCAP;
320 TRACE("ICAP_UNITS\n");
324 case MSG_QUERYSUPPORT:
325 twCC = set_onevalue(pCapability, TWTY_INT32,
326 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
330 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
334 twCC = msg_set(pCapability, &val);
335 if (twCC == TWCC_SUCCESS)
337 if (val != TWUN_INCHES)
339 ERR("Sane supports only SANE_UNIT_DPI\n");
340 twCC = TWCC_BADVALUE;
347 /* .. fall through intentional .. */
350 twCC = set_onevalue(pCapability, TWTY_UINT16, TWUN_INCHES);
358 static TW_UINT16 SANE_ICAPBitDepth(pTW_CAPABILITY pCapability, TW_UINT16 action)
360 TW_UINT16 twCC = TWCC_BADCAP;
361 #ifdef SONAME_LIBSANE
362 TW_UINT32 possible_values[1];
364 TRACE("ICAP_BITDEPTH\n");
366 possible_values[0] = activeDS.sane_param.depth;
370 case MSG_QUERYSUPPORT:
371 twCC = set_onevalue(pCapability, TWTY_INT32,
372 TWQC_GET | TWQC_GETDEFAULT | TWQC_GETCURRENT );
376 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
377 TWTY_UINT16, activeDS.sane_param.depth, activeDS.sane_param.depth);
381 /* .. Fall through intentional .. */
384 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.sane_param.depth);
391 /* CAP_UICONTROLLABLE */
392 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
394 TW_UINT16 twCC = TWCC_BADCAP;
396 TRACE("CAP_UICONTROLLABLE\n");
400 case MSG_QUERYSUPPORT:
401 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
405 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
412 /* ICAP_COMPRESSION */
413 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
415 static const TW_UINT32 possible_values[] = { TWCP_NONE };
417 TW_UINT16 twCC = TWCC_BADCAP;
419 TRACE("ICAP_COMPRESSION\n");
423 case MSG_QUERYSUPPORT:
424 twCC = set_onevalue(pCapability, TWTY_INT32,
425 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
429 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
430 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
431 FIXME("Partial stub: We don't attempt to support compression\n");
435 twCC = msg_set(pCapability, &val);
436 if (twCC == TWCC_SUCCESS)
437 FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val);
441 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
445 /* .. fall through intentional .. */
448 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
454 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
455 static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
457 TW_UINT16 twCC = TWCC_BADCAP;
458 #ifdef SONAME_LIBSANE
460 SANE_Int current_resolution;
461 TW_FIX32 *default_res;
462 const char *best_option_name;
463 SANE_Int minval, maxval, quantval;
467 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
469 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
470 if (cap == ICAP_XRESOLUTION)
472 best_option_name = "x-resolution";
473 default_res = &activeDS.defaultXResolution;
477 best_option_name = "y-resolution";
478 default_res = &activeDS.defaultYResolution;
480 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD)
482 best_option_name = "resolution";
483 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, ¤t_resolution) != SANE_STATUS_GOOD)
487 /* Sane does not support a concept of 'default' resolution, so we have to
488 * cache the resolution the very first time we load the scanner, and use that
490 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
492 default_res->Whole = current_resolution;
493 default_res->Frac = 0;
494 activeDS.XResolutionSet = TRUE;
497 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
499 default_res->Whole = current_resolution;
500 default_res->Frac = 0;
501 activeDS.YResolutionSet = TRUE;
506 case MSG_QUERYSUPPORT:
507 twCC = set_onevalue(pCapability, TWTY_INT32,
508 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
512 sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
513 if (sane_rc != SANE_STATUS_GOOD)
516 twCC = msg_get_range(pCapability, TWTY_FIX32,
517 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
521 twCC = msg_set(pCapability, &val);
522 if (twCC == TWCC_SUCCESS)
525 memcpy(&f32, &val, sizeof(f32));
526 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
527 if (sane_rc != SANE_STATUS_GOOD)
529 FIXME("Status of %d not expected or handled\n", sane_rc);
532 else if (set_status == SANE_INFO_INEXACT)
533 twCC = TWCC_CHECKSTATUS;
538 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
542 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
543 if (sane_rc != SANE_STATUS_GOOD)
546 /* .. fall through intentional .. */
549 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
556 /* ICAP_PIXELFLAVOR */
557 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
559 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
561 TW_UINT16 twCC = TWCC_BADCAP;
563 TRACE("ICAP_PIXELFLAVOR\n");
567 case MSG_QUERYSUPPORT:
568 twCC = set_onevalue(pCapability, TWTY_INT32,
569 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
573 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
574 TWTY_UINT16, TWPF_CHOCOLATE, TWPF_CHOCOLATE);
578 twCC = msg_set(pCapability, &val);
579 if (twCC == TWCC_SUCCESS)
581 FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val);
586 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
590 /* .. fall through intentional .. */
593 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
600 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
602 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
604 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
606 switch (pCapability->Cap)
608 case CAP_SUPPORTEDCAPS:
609 if (action == MSG_GET)
610 twCC = TWAIN_GetSupportedCaps(pCapability);
612 twCC = TWCC_BADVALUE;
616 twCC = SANE_CAPXferCount (pCapability, action);
619 case CAP_UICONTROLLABLE:
620 twCC = SANE_CAPUiControllable (pCapability, action);
624 twCC = SANE_ICAPPixelType (pCapability, action);
628 twCC = SANE_ICAPUnits (pCapability, action);
632 twCC = SANE_ICAPBitDepth(pCapability, action);
636 twCC = SANE_ICAPXferMech (pCapability, action);
639 case ICAP_PIXELFLAVOR:
640 twCC = SANE_ICAPPixelFlavor (pCapability, action);
643 case ICAP_COMPRESSION:
644 twCC = SANE_ICAPCompression(pCapability, action);
647 case ICAP_XRESOLUTION:
648 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
651 case ICAP_YRESOLUTION:
652 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
656 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
657 * even if you don't formally support the capability */
658 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
659 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
661 if (twCC == TWCC_CAPUNSUPPORTED)
662 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);