sane.ds: Return a 0 for MSG_QUERYSUPPORT even for capabilities we don't support.
[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, ICAP_XFERMECH };
129
130     pCapability->hContainer = GlobalAlloc (0, FIELD_OFFSET( TW_ARRAY, ItemList[sizeof(supported_caps)] ));
131     pCapability->ConType = TWON_ARRAY;
132
133     if (pCapability->hContainer)
134     {
135         UINT16 *u;
136         int i;
137         a = GlobalLock (pCapability->hContainer);
138         a->ItemType = TWTY_UINT16;
139         a->NumItems = sizeof(supported_caps) / sizeof(supported_caps[0]);
140         u = (UINT16 *) a->ItemList;
141         for (i = 0; i < a->NumItems; i++)
142             u[i] = supported_caps[i];
143         GlobalUnlock (pCapability->hContainer);
144         return TWCC_SUCCESS;
145     }
146     else
147         return TWCC_LOWMEMORY;
148 }
149
150
151 /* ICAP_XFERMECH */
152 static TW_UINT16 SANE_ICAPXferMech (pTW_CAPABILITY pCapability, TW_UINT16 action)
153 {
154     static const TW_UINT32 possible_values[] = { TWSX_NATIVE, TWSX_MEMORY };
155     TW_UINT32 val;
156     TW_UINT16 twCC = TWCC_BADCAP;
157
158     TRACE("ICAP_XFERMECH\n");
159
160     switch (action)
161     {
162         case MSG_QUERYSUPPORT:
163             twCC = set_onevalue(pCapability, TWTY_INT32,
164                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
165             break;
166
167         case MSG_GET:
168             twCC = msg_get_enum(pCapability, possible_values, sizeof(possible_values) / sizeof(possible_values[0]),
169                     TWTY_UINT16, activeDS.capXferMech, TWSX_NATIVE);
170             break;
171
172         case MSG_SET:
173             twCC = msg_set(pCapability, &val);
174             if (twCC == TWCC_SUCCESS)
175             {
176                activeDS.capXferMech = (TW_UINT16) val;
177                FIXME("Partial Stub:  XFERMECH set to %d, but ignored\n", val);
178             }
179             break;
180
181         case MSG_GETDEFAULT:
182             twCC = set_onevalue(pCapability, TWTY_UINT16, TWSX_NATIVE);
183             break;
184
185         case MSG_RESET:
186             activeDS.capXferMech = TWSX_NATIVE;
187             /* .. fall through intentional .. */
188
189         case MSG_GETCURRENT:
190             twCC = set_onevalue(pCapability, TWTY_UINT16, activeDS.capXferMech);
191             FIXME("Partial Stub:  XFERMECH of %d not actually used\n", activeDS.capXferMech);
192             break;
193     }
194     return twCC;
195 }
196
197
198 /* CAP_XFERCOUNT */
199 static TW_UINT16 SANE_CAPXferCount (pTW_CAPABILITY pCapability, TW_UINT16 action)
200 {
201     TW_UINT32 val;
202     TW_UINT16 twCC = TWCC_BADCAP;
203
204     TRACE("CAP_XFERCOUNT\n");
205
206     switch (action)
207     {
208         case MSG_QUERYSUPPORT:
209             twCC = set_onevalue(pCapability, TWTY_INT32,
210                     TWQC_GET | TWQC_SET | TWQC_GETDEFAULT | TWQC_GETCURRENT | TWQC_RESET );
211             break;
212
213         case MSG_GET:
214             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
215             FIXME("Partial Stub:  Reporting only support for transfer all\n");
216             break;
217
218         case MSG_SET:
219             twCC = msg_set(pCapability, &val);
220             if (twCC == TWCC_SUCCESS)
221                FIXME("Partial Stub:  XFERCOUNT set to %d, but ignored\n", val);
222             break;
223
224         case MSG_GETDEFAULT:
225             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
226             break;
227
228         case MSG_RESET:
229             /* .. fall through intentional .. */
230
231         case MSG_GETCURRENT:
232             twCC = set_onevalue(pCapability, TWTY_INT16, -1);
233             break;
234     }
235     return twCC;
236 }
237
238 TW_UINT16 SANE_SaneCapability (pTW_CAPABILITY pCapability, TW_UINT16 action)
239 {
240     TW_UINT16 twCC = TWCC_CAPUNSUPPORTED;
241
242     TRACE("capability=%d action=%d\n", pCapability->Cap, action);
243
244     switch (pCapability->Cap)
245     {
246         case CAP_SUPPORTEDCAPS:
247             if (action == MSG_GET)
248                 twCC = TWAIN_GetSupportedCaps(pCapability);
249             else
250                 twCC = TWCC_BADVALUE;
251             break;
252
253         case CAP_XFERCOUNT:
254             twCC = SANE_CAPXferCount (pCapability, action);
255             break;
256
257         case ICAP_XFERMECH:
258             twCC = SANE_ICAPXferMech (pCapability, action);
259             break;
260     }
261
262     /* Twain specifies that you should return a 0 in response to QUERYSUPPORT,
263      *   even if you don't formally support the capability */
264     if (twCC == TWCC_CAPUNSUPPORTED && action == MSG_QUERYSUPPORT)
265         twCC = set_onevalue(pCapability, 0, TWTY_INT32);
266
267     return twCC;
268 }