winejoystick.drv: Use CP_UNIXCP instead of CP_ACP when converting a string that comes...
[wine] / dlls / sane.ds / capability.c
1 /*
2  * Copyright 2000 Corel Corporation
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define NONAMELESSUNION
20 #define NONAMELESSSTRUCT
21
22 #include "config.h"
23
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "twain.h"
29 #include "sane_i.h"
30 #include "wine/debug.h"
31
32 WINE_DEFAULT_DEBUG_CHANNEL(twain);
33
34 static TW_UINT16 get_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 *type, TW_UINT32 *value)
35 {
36     if (pCapability->hContainer)
37     {
38         pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
39         if (pVal)
40         {
41             *value = pVal->Item;
42             if (type)
43                 *type = pVal->ItemType;
44             GlobalUnlock (pCapability->hContainer);
45             return TWCC_SUCCESS;
46         }
47     }
48     return TWCC_BUMMER;
49 }
50
51
52 static TW_UINT16 set_onevalue(pTW_CAPABILITY pCapability, TW_UINT16 type, TW_UINT32 value)
53 {
54     pCapability->hContainer = GlobalAlloc (0, sizeof(TW_ONEVALUE));
55
56     if (pCapability->hContainer)
57     {
58         pTW_ONEVALUE pVal = GlobalLock (pCapability->hContainer);
59         if (pVal)
60         {
61             pCapability->ConType = TWON_ONEVALUE;
62             pVal->ItemType = type;
63             pVal->Item = value;
64             GlobalUnlock (pCapability->hContainer);
65             return TWCC_SUCCESS;
66         }
67     }
68    return TWCC_LOWMEMORY;
69 }
70
71 static TW_UINT16 msg_set(pTW_CAPABILITY pCapability, TW_UINT32 *val)
72 {
73     if (pCapability->ConType == TWON_ONEVALUE)
74         return get_onevalue(pCapability, NULL, val);
75
76     FIXME("Partial Stub:  MSG_SET only supports TW_ONEVALUE\n");
77     return TWCC_BADCAP;
78 }
79
80
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)
83 {
84     TW_ENUMERATION *enumv = NULL;
85     TW_UINT32 *p32;
86     TW_UINT16 *p16;
87     int i;
88
89     pCapability->ConType = TWON_ENUMERATION;
90     pCapability->hContainer = 0;
91
92     if (type == TWTY_INT16 || type == TWTY_UINT16)
93         pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT16)]));
94
95     if (type == TWTY_INT32 || type == TWTY_UINT32)
96         pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ENUMERATION, ItemList[value_count * sizeof(TW_UINT32)]));
97
98     if (pCapability->hContainer)
99         enumv = GlobalLock(pCapability->hContainer);
100
101     if (! enumv)
102         return TWCC_LOWMEMORY;
103
104     enumv->ItemType = type;
105     enumv->NumItems = value_count;
106
107     p16 = (TW_UINT16 *) enumv->ItemList;
108     p32 = (TW_UINT32 *) enumv->ItemList;
109     for (i = 0; i < value_count; i++)
110     {
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];
119     }
120
121     GlobalUnlock(pCapability->hContainer);
122     return TWCC_SUCCESS;
123 }
124
125 static TW_UINT16 TWAIN_GetSupportedCaps(pTW_CAPABILITY pCapability)
126 {
127     TW_ARRAY *a;
128     static const UINT16 supported_caps[] = { CAP_SUPPORTEDCAPS, CAP_XFERCOUNT, CAP_UICONTROLLABLE,
129                     ICAP_XFERMECH, ICAP_PIXELTYPE, ICAP_COMPRESSION, ICAP_PIXELFLAVOR };
130
131     pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
132     pCapability->ConType = TWON_ARRAY;
133
134     if (pCapability->hContainer)
135     {
136         UINT16 *u;
137         int i;
138         a = GlobalLock (pCapability->hContainer);
139         a->ItemType = TWTY_UINT16;
140         a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
141         u = (UINT16 *) a->ItemList;
142         for (i = 0; i < a->NumItems; i++)
143             u[i] = supported_caps[i];
144         GlobalUnlock (pCapability->hContainer);
145         return TWCC_SUCCESS;
146     }
147     else
148         return TWCC_LOWMEMORY;
149 }
150
151
152 /* ICAP_XFERMECH */
153 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
154 {
155     static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
156     TW_UINT32 val;
157     TW_UINT16 twCC = TWCC_BADCAP;
158
159     TRACE("ICAP_XFERMECH\n");
160
161     switch (action)
162     {
163         case MSG_QUERYSUPPORT:
164             twCC = set_onevalue(pCapability, TWTY_INT32,
165                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
166             break;
167
168         case MSG_GET:
169             twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
170                     TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
171             break;
172
173         case MSG_SET:
174             twCC = msg_set(pCapability, &val);
175             if (twCC == TWCC_SUCCESS)
176             {
177                activeDS.capXferMech = (TW_UINT16) val;
178                FIXME("Partial Stub:  XFERMECH set to %d, but ignored\n", val);
179             }
180             break;
181
182         case MSG_GETDEFAULT:
183             twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
184             break;
185
186         case MSG_RESET:
187             activeDS.capXferMech = TWSX_NATIVE;
188             /* .. fall through intentional .. */
189
190         case MSG_GETCURRENT:
191             twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
192             FIXME("Partial Stub:  XFERMECH of %d not actually used\n", activeDS.capXferMech);
193             break;
194     }
195     return twCC;
196 }
197
198
199 /* CAP_XFERCOUNT */
200 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
201 {
202     TW_UINT32 val;
203     TW_UINT16 twCC = TWCC_BADCAP;
204
205     TRACE("CAP_XFERCOUNT\n");
206
207     switch (action)
208     {
209         case MSG_QUERYSUPPORT:
210             twCC = set_onevalue(pCapability, TWTY_INT32,
211                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
212             break;
213
214         case MSG_GET:
215             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
216             FIXME("Partial Stub:  Reporting only support for transfer all\n");
217             break;
218
219         case MSG_SET:
220             twCC = msg_set(pCapability, &val);
221             if (twCC == TWCC_SUCCESS)
222                FIXME("Partial Stub:  XFERCOUNT set to %d, but ignored\n", val);
223             break;
224
225         case MSG_GETDEFAULT:
226             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
227             break;
228
229         case MSG_RESET:
230             /* .. fall through intentional .. */
231
232         case MSG_GETCURRENT:
233             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
234             break;
235     }
236     return twCC;
237 }
238
239 /* ICAP_PIXELTYPE */
240 static TW_UINT16 SANE_ICAPPixelType (pTW_CAPABILITY pCapability, TW_UINT16 action)
241 {
242     static const TW_UINT32 possible_values[] = { TWPT_BW, TWPT_GRAY, TWPT_RGB };
243     TW_UINT32 val;
244     TW_UINT16 twCC = TWCC_BADCAP;
245
246     TRACE("ICAP_PIXELTYPE\n");
247
248     switch (action)
249     {
250         case MSG_QUERYSUPPORT:
251             twCC = set_onevalue(pCapability, TWTY_INT32,
252                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
253             break;
254
255         case MSG_GET:
256             twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
257                     TWTY_UINT16, activeDS.capXferMech, TWPT_BW);
258             break;
259
260         case MSG_SET:
261             twCC = msg_set(pCapability, &val);
262             if (twCC == TWCC_SUCCESS)
263             {
264                activeDS.capPixelType = (TW_UINT16) val;
265                FIXME("Partial Stub:  PIXELTYPE set to %d, but ignored\n", val);
266             }
267             break;
268
269         case MSG_GETDEFAULT:
270             twCC = set_onevalue(pCapability, TWTY_UINT16, TWPT_BW);
271             break;
272
273         case MSG_RESET:
274             activeDS.capPixelType = TWPT_BW;
275             /* .. fall through intentional .. */
276
277         case MSG_GETCURRENT:
278             twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capPixelType);
279             break;
280     }
281
282     return twCC;
283 }
284
285 /* CAP_UICONTROLLABLE */
286 static TW_UINT16 SANE_CAPUiControllable(pTW_CAPABILITY pCapability, TW_UINT16 action)
287 {
288     TW_UINT16 twCC = TWCC_BADCAP;
289
290     TRACE("CAP_UICONTROLLABLE\n");
291
292     switch (action)
293     {
294         case MSG_QUERYSUPPORT:
295             twCC = set_onevalue(pCapability, TWTY_INT32, TWQC_GET);
296             break;
297
298         case MSG_GET:
299             twCC = set_onevalue(pCapability, TWTY_BOOL, TRUE);
300             break;
301
302     }
303     return twCC;
304 }
305
306 /* ICAP_COMPRESSION */
307 static TW_UINT16 SANE_ICAPCompression (pTW_CAPABILITY pCapability, TW_UINT16 action)
308 {
309     static const TW_UINT32 possible_values[] = { TWCP_NONE };
310     TW_UINT32 val;
311     TW_UINT16 twCC = TWCC_BADCAP;
312
313     TRACE("ICAP_COMPRESSION\n");
314
315     switch (action)
316     {
317         case MSG_QUERYSUPPORT:
318             twCC = set_onevalue(pCapability, TWTY_INT32,
319                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
320             break;
321
322         case MSG_GET:
323             twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
324                     TWTY_UINT16, TWCP_NONE, TWCP_NONE);
325             FIXME("Partial stub:  We don't attempt to support compression\n");
326             break;
327
328         case MSG_SET:
329             twCC = msg_set(pCapability, &val);
330             if (twCC == TWCC_SUCCESS)
331                FIXME("Partial Stub:  COMPRESSION set to %d, but ignored\n", val);
332             break;
333
334         case MSG_GETDEFAULT:
335             twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
336             break;
337
338         case MSG_RESET:
339             /* .. fall through intentional .. */
340
341         case MSG_GETCURRENT:
342             twCC = set_onevalue(pCapability, TWTY_UINT16, TWCP_NONE);
343             break;
344     }
345     return twCC;
346 }
347
348 /* ICAP_PIXELFLAVOR */
349 static TW_UINT16 SANE_ICAPPixelFlavor (pTW_CAPABILITY pCapability, TW_UINT16 action)
350 {
351     static const TW_UINT32 possible_values[] = { TWPF_CHOCOLATE, TWPF_VANILLA };
352     TW_UINT32 val;
353     TW_UINT16 twCC = TWCC_BADCAP;
354
355     TRACE("ICAP_PIXELFLAVOR\n");
356
357     switch (action)
358     {
359         case MSG_QUERYSUPPORT:
360             twCC = set_onevalue(pCapability, TWTY_INT32,
361                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
362             break;
363
364         case MSG_GET:
365             twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
366                     TWTY_UINT16, TWPF_CHOCOLATE, TWPF_CHOCOLATE);
367             break;
368
369         case MSG_SET:
370             twCC = msg_set(pCapability, &val);
371             if (twCC == TWCC_SUCCESS)
372             {
373                FIXME("Stub:  PIXELFLAVOR set to %d, but ignored\n", val);
374             }
375             break;
376
377         case MSG_GETDEFAULT:
378             twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
379             break;
380
381         case MSG_RESET:
382             /* .. fall through intentional .. */
383
384         case MSG_GETCURRENT:
385             twCC = set_onevalue(pCapability, TWTY_UINT16, TWPF_CHOCOLATE);
386             break;
387     }
388     return twCC;
389 }
390
391
392 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
393 {
394     TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
395
396     TRACE("capability=%d action=%d\n", pCapability->Cap, action);
397
398     switch (pCapability->Cap)
399     {
400         case CAP_SUPPORTEDCAPS:
401             if (action == MSG_GET)
402                 twCC = TWAIN_GetSupportedCaps(pCapability);
403             else
404                 twCC = TWCC_BADVALUE;
405             break;
406
407         case CAP_XFERCOUNT:
408             twCC = SANE_CAPXferCount (pCapability, action);
409             break;
410
411         case CAP_UICONTROLLABLE:
412             twCC = SANE_CAPUiControllable (pCapability, action);
413             break;
414
415         case ICAP_PIXELTYPE:
416             twCC = SANE_ICAPPixelType (pCapability, action);
417             break;
418
419         case ICAP_XFERMECH:
420             twCC = SANE_ICAPXferMech (pCapability, action);
421             break;
422
423         case ICAP_PIXELFLAVOR:
424             twCC = SANE_ICAPPixelFlavor (pCapability, action);
425             break;
426
427         case ICAP_COMPRESSION:
428             twCC = SANE_ICAPCompression(pCapability, action);
429             break;
430     }
431
432     /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
433      *   even if you don't formally support the capability */
434     if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
435         twCC = set_onevalue(pCapability, 0, TWTY_INT32);
436
437     if (twCC == TWCC_CAPUNSUPPORTED)
438         TRACE("capability 0x%x/action=%d being reported as unsupported\n", pCapability->Cap, action);
439
440     return twCC;
441 }