msi: Fix handling of buffer sizes in MsiEnumPatchesA and avoid a redundant call to...
[wine/multimedia.git] / dlls / sane.ds / capability.c
blob1d574e321e2c82d092f1dc2782acf27be7cfb8e7
1 /*
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
22 #include "config.h"
24 #include <stdarg.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
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);
39 if (pVal)
41 *value = pVal->Item;
42 if (type)
43 *type = pVal->ItemType;
44 GlobalUnlock (pCapability->hContainer);
45 return TWCC_SUCCESS;
48 return TWCC_BUMMER;
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);
59 if (pVal)
61 pCapability->ConType = TWON_ONEVALUE;
62 pVal->ItemType = type;
63 pVal->Item = value;
64 GlobalUnlock (pCapability->hContainer);
65 return TWCC_SUCCESS;
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");
77 return TWCC_BADCAP;
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;
85 TW_UINT32 *p32;
86 TW_UINT16 *p16;
87 int i;
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);
101 if (! enumv)
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)
116 p16[i] = values[i];
117 if (type == TWTY_INT32 || type == TWTY_UINT32)
118 p32[i] = values[i];
121 GlobalUnlock(pCapability->hContainer);
122 return TWCC_SUCCESS;
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);
138 if (! range)
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);
149 return TWCC_SUCCESS;
151 #endif
153 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
155 TW_ARRAY *a;
156 static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
157 ICAP_XFERMECH, ICAP_PIXELTYPE, 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)
165 UINT16 *u;
166 int i;
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);
174 return TWCC_SUCCESS;
176 else
177 return TWCC_LOWMEMORY;
181 /* ICAP_XFERMECH */
182 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
184 static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
185 TW_UINT32 val;
186 TW_UINT16 twCC = TWCC_BADCAP;
188 TRACE("ICAP_XFERMECH\n");
190 switch (action)
192 case MSG_QUERYSUPPORT:
193 twCC = set_onevalue(pCapability, TWTY_INT32,
194 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
195 break;
197 case MSG_GET:
198 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
199 TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
200 break;
202 case MSG_SET:
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);
209 break;
211 case MSG_GETDEFAULT:
212 twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
213 break;
215 case MSG_RESET:
216 activeDS.capXferMech = TWSX_NATIVE;
217 /* .. fall through intentional .. */
219 case MSG_GETCURRENT:
220 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
221 FIXME("Partial Stub: XFERMECH of %d not actually used\n", activeDS.capXferMech);
222 break;
224 return twCC;
228 /* CAP_XFERCOUNT */
229 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
231 TW_UINT32 val;
232 TW_UINT16 twCC = TWCC_BADCAP;
234 TRACE("CAP_XFERCOUNT\n");
236 switch (action)
238 case MSG_QUERYSUPPORT:
239 twCC = set_onevalue(pCapability, TWTY_INT32,
240 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
241 break;
243 case MSG_GET:
244 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
245 FIXME("Partial Stub: Reporting only support for transfer all\n");
246 break;
248 case MSG_SET:
249 twCC = msg_set(pCapability, &val);
250 if (twCC == TWCC_SUCCESS)
251 FIXME("Partial Stub: XFERCOUNT set to %d, but ignored\n", val);
252 break;
254 case MSG_GETDEFAULT:
255 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
256 break;
258 case MSG_RESET:
259 /* .. fall through intentional .. */
261 case MSG_GETCURRENT:
262 twCC = set_onevalue(pCapability, TWTY_INT16, -1);
263 break;
265 return twCC;
268 /* ICAP_PIXELTYPE */
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 };
272 TW_UINT32 val;
273 TW_UINT16 twCC = TWCC_BADCAP;
275 TRACE("ICAP_PIXELTYPE\n");
277 switch (action)
279 case MSG_QUERYSUPPORT:
280 twCC = set_onevalue(pCapability, TWTY_INT32,
281 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
282 break;
284 case MSG_GET:
285 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
286 TWTY_UINT16, activeDS.capXferMech, TWPT_BW);
287 break;
289 case MSG_SET:
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);
296 break;
298 case MSG_GETDEFAULT:
299 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPT_BW);
300 break;
302 case MSG_RESET:
303 activeDS.capPixelType = TWPT_BW;
304 /* .. fall through intentional .. */
306 case MSG_GETCURRENT:
307 twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capPixelType);
308 break;
311 return twCC;
314 /* CAP_UICONTROLLABLE */
315 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
317 TW_UINT16 twCC = TWCC_BADCAP;
319 TRACE("CAP_UICONTROLLABLE\n");
321 switch (action)
323 case MSG_QUERYSUPPORT:
324 twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
325 break;
327 case MSG_GET:
328 twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
329 break;
332 return twCC;
335 /* ICAP_COMPRESSION */
336 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
338 static const TW_UINT32 possible_values[] = { TWCP_NONE };
339 TW_UINT32 val;
340 TW_UINT16 twCC = TWCC_BADCAP;
342 TRACE("ICAP_COMPRESSION\n");
344 switch (action)
346 case MSG_QUERYSUPPORT:
347 twCC = set_onevalue(pCapability, TWTY_INT32,
348 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
349 break;
351 case MSG_GET:
352 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
353 TWTY_UINT16, TWCP_NONE, TWCP_NONE);
354 FIXME("Partial stub: We don't attempt to support compression\n");
355 break;
357 case MSG_SET:
358 twCC = msg_set(pCapability, &val);
359 if (twCC == TWCC_SUCCESS)
360 FIXME("Partial Stub: COMPRESSION set to %d, but ignored\n", val);
361 break;
363 case MSG_GETDEFAULT:
364 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
365 break;
367 case MSG_RESET:
368 /* .. fall through intentional .. */
370 case MSG_GETCURRENT:
371 twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
372 break;
374 return twCC;
377 /* ICAP_XRESOLUTION, ICAP_YRESOLUTION */
378 static TW_UINT16 SANE_ICAPResolution (pTW_CAPABILITY pCapability, TW_UINT16 action, TW_UINT16 cap)
380 TW_UINT16 twCC = TWCC_BADCAP;
381 #ifdef SONAME_LIBSANE
382 TW_UINT32 val;
383 SANE_Int current_resolution;
384 TW_FIX32 *default_res;
385 const char *best_option_name;
386 SANE_Int minval, maxval, quantval;
387 SANE_Status sane_rc;
388 SANE_Int set_status;
390 TRACE("ICAP_%cRESOLUTION\n", cap == ICAP_XRESOLUTION ? 'X' : 'Y');
392 /* Some scanners support 'x-resolution', most seem to just support 'resolution' */
393 if (cap == ICAP_XRESOLUTION)
395 best_option_name = "x-resolution";
396 default_res = &activeDS.defaultXResolution;
398 else
400 best_option_name = "y-resolution";
401 default_res = &activeDS.defaultYResolution;
403 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
405 best_option_name = "resolution";
406 if (sane_option_get_int(activeDS.deviceHandle, best_option_name, &current_resolution) != SANE_STATUS_GOOD)
407 return TWCC_BADCAP;
410 /* Sane does not support a concept of 'default' resolution, so we have to
411 * cache the resolution the very first time we load the scanner, and use that
412 * as the default */
413 if (cap == ICAP_XRESOLUTION && ! activeDS.XResolutionSet)
415 default_res->Whole = current_resolution;
416 default_res->Frac = 0;
417 activeDS.XResolutionSet = TRUE;
420 if (cap == ICAP_YRESOLUTION && ! activeDS.YResolutionSet)
422 default_res->Whole = current_resolution;
423 default_res->Frac = 0;
424 activeDS.YResolutionSet = TRUE;
427 switch (action)
429 case MSG_QUERYSUPPORT:
430 twCC = set_onevalue(pCapability, TWTY_INT32,
431 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
432 break;
434 case MSG_GET:
435 sane_rc = sane_option_probe_resolution(activeDS.deviceHandle, best_option_name, &minval, &maxval, &quantval);
436 if (sane_rc != SANE_STATUS_GOOD)
437 twCC = TWCC_BADCAP;
438 else
439 twCC = msg_get_range(pCapability, TWTY_FIX32,
440 minval, maxval, quantval == 0 ? 1 : quantval, default_res->Whole, current_resolution);
441 break;
443 case MSG_SET:
444 twCC = msg_set(pCapability, &val);
445 if (twCC == TWCC_SUCCESS)
447 TW_FIX32 f32;
448 memcpy(&f32, &val, sizeof(f32));
449 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, f32.Whole, &set_status);
450 if (sane_rc != SANE_STATUS_GOOD)
452 FIXME("Status of %d not expected or handled\n", sane_rc);
453 twCC = TWCC_BADCAP;
455 else if (set_status == SANE_INFO_INEXACT)
456 twCC = TWCC_CHECKSTATUS;
458 break;
460 case MSG_GETDEFAULT:
461 twCC = set_onevalue(pCapability, TWTY_FIX32, default_res->Whole);
462 break;
464 case MSG_RESET:
465 sane_rc = sane_option_set_int(activeDS.deviceHandle, best_option_name, default_res->Whole, NULL);
466 if (sane_rc != SANE_STATUS_GOOD)
467 return TWCC_BADCAP;
469 /* .. fall through intentional .. */
471 case MSG_GETCURRENT:
472 twCC = set_onevalue(pCapability, TWTY_FIX32, current_resolution);
473 break;
475 #endif
476 return twCC;
479 /* ICAP_PIXELFLAVOR */
480 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
482 static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
483 TW_UINT32 val;
484 TW_UINT16 twCC = TWCC_BADCAP;
486 TRACE("ICAP_PIXELFLAVOR\n");
488 switch (action)
490 case MSG_QUERYSUPPORT:
491 twCC = set_onevalue(pCapability, TWTY_INT32,
492 TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
493 break;
495 case MSG_GET:
496 twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
497 TWTY_UINT16, TWPF_CHOCOLATE, TWPF_CHOCOLATE);
498 break;
500 case MSG_SET:
501 twCC = msg_set(pCapability, &val);
502 if (twCC == TWCC_SUCCESS)
504 FIXME("Stub: PIXELFLAVOR set to %d, but ignored\n", val);
506 break;
508 case MSG_GETDEFAULT:
509 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
510 break;
512 case MSG_RESET:
513 /* .. fall through intentional .. */
515 case MSG_GETCURRENT:
516 twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
517 break;
519 return twCC;
523 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
525 TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
527 TRACE("capability=%d action=%d\n", pCapability->Cap, action);
529 switch (pCapability->Cap)
531 case CAP_SUPPORTEDCAPS:
532 if (action == MSG_GET)
533 twCC = TWAIN_GetSupportedCaps(pCapability);
534 else
535 twCC = TWCC_BADVALUE;
536 break;
538 case CAP_XFERCOUNT:
539 twCC = SANE_CAPXferCount (pCapability, action);
540 break;
542 case CAP_UICONTROLLABLE:
543 twCC = SANE_CAPUiControllable (pCapability, action);
544 break;
546 case ICAP_PIXELTYPE:
547 twCC = SANE_ICAPPixelType (pCapability, action);
548 break;
550 case ICAP_XFERMECH:
551 twCC = SANE_ICAPXferMech (pCapability, action);
552 break;
554 case ICAP_PIXELFLAVOR:
555 twCC = SANE_ICAPPixelFlavor (pCapability, action);
556 break;
558 case ICAP_COMPRESSION:
559 twCC = SANE_ICAPCompression(pCapability, action);
560 break;
562 case ICAP_XRESOLUTION:
563 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
564 break;
566 case ICAP_YRESOLUTION:
567 twCC = SANE_ICAPResolution(pCapability, action, pCapability->Cap);
568 break;
571 /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
572 * even if you don't formally support the capability */
573 if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
574 twCC = set_onevalue(pCapability, 0, TWTY_INT32);
576 if (twCC == TWCC_CAPUNSUPPORTED)
577 TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
579 return twCC;