Release 8.16.
[wine.git] / dlls / sane.ds / unixlib.c
blob897aa09e5efbea9880549abf8f52f3259d819408
1 /*
2 * Unix library interface for SANE
4 * Copyright 2000 Shi Quan He
5 * Copyright 2021 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
28 #include <stdarg.h>
29 #include <stdlib.h>
30 #include <sane/sane.h>
31 #include <sane/saneopts.h>
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "unixlib.h"
36 #include "wine/list.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(twain);
41 static SANE_Handle device_handle;
42 static BOOL device_started;
43 static const SANE_Device **device_list;
45 /* Sane returns device names that are longer than the 32 bytes allowed
46 by TWAIN. However, it colon separates them, and the last bit is
47 the most interesting. So we use the last bit, and add a signature
48 to ensure uniqueness */
49 static void copy_sane_short_name(const char *in, char *out, size_t outsize)
51 const char *p;
52 int signature = 0;
54 if (strlen(in) <= outsize - 1)
56 strcpy(out, in);
57 return;
60 for (p = in; *p; p++)
61 signature += *p;
63 p = strrchr(in, ':');
64 if (!p)
65 p = in;
66 else
67 p++;
69 if (strlen(p) > outsize - 7 - 1)
70 p += strlen(p) - (outsize - 7 - 1);
72 strcpy(out, p);
73 sprintf(out + strlen(out), "(%04X)", signature % 0x10000);
77 static void detect_sane_devices(void)
79 if (device_list && device_list[0]) return;
80 TRACE("detecting sane...\n");
81 sane_get_devices( &device_list, SANE_FALSE );
84 static TW_UINT16 sane_status_to_twcc(SANE_Status rc)
86 switch (rc)
88 case SANE_STATUS_GOOD:
89 return TWCC_SUCCESS;
90 case SANE_STATUS_UNSUPPORTED:
91 return TWCC_CAPUNSUPPORTED;
92 case SANE_STATUS_JAMMED:
93 return TWCC_PAPERJAM;
94 case SANE_STATUS_NO_MEM:
95 return TWCC_LOWMEMORY;
96 case SANE_STATUS_ACCESS_DENIED:
97 return TWCC_DENIED;
99 case SANE_STATUS_IO_ERROR:
100 case SANE_STATUS_NO_DOCS:
101 case SANE_STATUS_COVER_OPEN:
102 case SANE_STATUS_EOF:
103 case SANE_STATUS_INVAL:
104 case SANE_STATUS_CANCELLED:
105 case SANE_STATUS_DEVICE_BUSY:
106 default:
107 return TWCC_BUMMER;
111 static int map_type( SANE_Value_Type type )
113 switch (type)
115 case SANE_TYPE_BOOL: return TYPE_BOOL;
116 case SANE_TYPE_INT: return TYPE_INT;
117 case SANE_TYPE_FIXED: return TYPE_FIXED;
118 case SANE_TYPE_STRING: return TYPE_STRING;
119 case SANE_TYPE_BUTTON: return TYPE_BUTTON;
120 case SANE_TYPE_GROUP: return TYPE_GROUP;
121 default: return -1;
125 static int map_unit( SANE_Unit unit )
127 switch (unit)
129 case SANE_UNIT_NONE: return UNIT_NONE;
130 case SANE_UNIT_PIXEL: return UNIT_PIXEL;
131 case SANE_UNIT_BIT: return UNIT_BIT;
132 case SANE_UNIT_MM: return UNIT_MM;
133 case SANE_UNIT_DPI: return UNIT_DPI;
134 case SANE_UNIT_PERCENT: return UNIT_PERCENT;
135 case SANE_UNIT_MICROSECOND: return UNIT_MICROSECOND;
136 default: return -1;
140 static int map_constraint_type( SANE_Constraint_Type type )
142 switch (type)
144 case SANE_CONSTRAINT_NONE: return CONSTRAINT_NONE;
145 case SANE_CONSTRAINT_RANGE: return CONSTRAINT_RANGE;
146 case SANE_CONSTRAINT_WORD_LIST: return CONSTRAINT_WORD_LIST;
147 case SANE_CONSTRAINT_STRING_LIST: return CONSTRAINT_STRING_LIST;
148 default: return CONSTRAINT_NONE;
152 static void map_descr( struct option_descriptor *descr, const SANE_Option_Descriptor *opt )
154 unsigned int i, size, len = 0;
155 WCHAR *p;
157 descr->type = map_type( opt->type );
158 descr->unit = map_unit( opt->unit );
159 descr->constraint_type = map_constraint_type( opt->constraint_type );
160 descr->size = opt->size;
161 descr->is_active = SANE_OPTION_IS_ACTIVE( opt->cap );
162 if (opt->title) len = ntdll_umbstowcs( opt->title, strlen(opt->title),
163 descr->title, ARRAY_SIZE(descr->title) );
164 descr->title[len] = 0;
165 switch (descr->constraint_type)
167 case CONSTRAINT_RANGE:
168 descr->constraint.range.min = opt->constraint.range->min;
169 descr->constraint.range.max = opt->constraint.range->max;
170 descr->constraint.range.quant = opt->constraint.range->quant;
171 break;
172 case CONSTRAINT_WORD_LIST:
173 size = min( opt->constraint.word_list[0], ARRAY_SIZE(descr->constraint.word_list) - 1 );
174 descr->constraint.word_list[0] = size;
175 for (i = 1; i <= size; i++) descr->constraint.word_list[i] = opt->constraint.word_list[i];
176 break;
177 case CONSTRAINT_STRING_LIST:
178 p = descr->constraint.strings;
179 size = ARRAY_SIZE(descr->constraint.strings) - 1;
180 for (i = 0; size && opt->constraint.string_list[i]; i++)
182 len = ntdll_umbstowcs( opt->constraint.string_list[i], strlen(opt->constraint.string_list[i]),
183 p, size );
184 p[len++] = 0;
185 size -= len;
186 p += len;
188 *p = 0;
189 break;
190 default:
191 break;
195 static NTSTATUS process_attach( void *args )
197 SANE_Int version_code;
199 sane_init( &version_code, NULL );
200 return STATUS_SUCCESS;
203 static NTSTATUS process_detach( void *args )
205 sane_exit();
206 return STATUS_SUCCESS;
209 static NTSTATUS get_identity( void *args )
211 TW_IDENTITY *id = args;
212 static int cur_dev;
214 detect_sane_devices();
215 if (!device_list[cur_dev]) return STATUS_DEVICE_NOT_CONNECTED;
216 id->ProtocolMajor = TWON_PROTOCOLMAJOR;
217 id->ProtocolMinor = TWON_PROTOCOLMINOR;
218 id->SupportedGroups = DG_CONTROL | DG_IMAGE | DF_DS2;
219 copy_sane_short_name(device_list[cur_dev]->name, id->ProductName, sizeof(id->ProductName) - 1);
220 lstrcpynA (id->Manufacturer, device_list[cur_dev]->vendor, sizeof(id->Manufacturer) - 1);
221 lstrcpynA (id->ProductFamily, device_list[cur_dev]->model, sizeof(id->ProductFamily) - 1);
222 cur_dev++;
224 if (!device_list[cur_dev] || !device_list[cur_dev]->model ||
225 !device_list[cur_dev]->vendor ||
226 !device_list[cur_dev]->name)
227 cur_dev = 0; /* wrap to begin */
229 return STATUS_SUCCESS;
232 static NTSTATUS open_ds( void *args )
234 TW_IDENTITY *id = args;
235 SANE_Status status;
236 int i;
238 detect_sane_devices();
239 if (!device_list[0])
241 ERR("No scanners? We should not get to OpenDS?\n");
242 return STATUS_DEVICE_NOT_CONNECTED;
245 for (i = 0; device_list[i] && device_list[i]->model; i++)
247 TW_STR32 name;
249 /* To make string as short as above */
250 lstrcpynA(name, device_list[i]->vendor, sizeof(name)-1);
251 if (*id->Manufacturer && strcmp(name, id->Manufacturer))
252 continue;
253 lstrcpynA(name, device_list[i]->model, sizeof(name)-1);
254 if (*id->ProductFamily && strcmp(name, id->ProductFamily))
255 continue;
256 copy_sane_short_name(device_list[i]->name, name, sizeof(name) - 1);
257 if (*id->ProductName && strcmp(name, id->ProductName))
258 continue;
259 break;
261 if (!device_list[i]) {
262 WARN("Scanner not found.\n");
263 return STATUS_DEVICE_NOT_CONNECTED;
265 status = sane_open( device_list[i]->name, &device_handle );
266 if (status == SANE_STATUS_GOOD) return STATUS_SUCCESS;
268 ERR("sane_open(%s): %s\n", device_list[i]->name, sane_strstatus (status));
269 return STATUS_DEVICE_NOT_CONNECTED;
272 static NTSTATUS close_ds( void *args )
274 if (device_handle) sane_close( device_handle );
275 device_handle = NULL;
276 device_started = FALSE;
277 return STATUS_SUCCESS;
280 static NTSTATUS start_device( void *args )
282 SANE_Status status;
284 if (device_started) return STATUS_SUCCESS;
285 status = sane_start( device_handle );
286 if (status != SANE_STATUS_GOOD)
288 TRACE("sane_start returns %s\n", sane_strstatus(status));
289 return STATUS_DEVICE_NOT_CONNECTED;
291 device_started = TRUE;
292 return STATUS_SUCCESS;
295 static NTSTATUS cancel_device( void *args )
297 if (device_started) sane_cancel( device_handle );
298 device_started = FALSE;
299 return STATUS_SUCCESS;
302 static NTSTATUS read_data( void *args )
304 const struct read_data_params *params = args;
305 unsigned char *buffer = params->buffer;
306 int read_len, remaining = params->len;
307 SANE_Status status;
309 *params->retlen = 0;
310 while (remaining)
312 status = sane_read( device_handle, buffer, remaining, &read_len );
313 if (status != SANE_STATUS_GOOD) break;
314 *params->retlen += read_len;
315 buffer += read_len;
316 remaining -= read_len;
318 if (status == SANE_STATUS_EOF) return TWCC_SUCCESS;
319 return sane_status_to_twcc( status );
322 static NTSTATUS get_params( void *args )
324 struct frame_parameters *params = args;
325 SANE_Parameters sane_params;
327 if (sane_get_parameters( device_handle, &sane_params )) return STATUS_UNSUCCESSFUL;
329 switch (sane_params.format)
331 case SANE_FRAME_GRAY:
332 params->format = FMT_GRAY;
333 break;
334 case SANE_FRAME_RGB:
335 params->format = FMT_RGB;
336 break;
337 default:
338 ERR("Unhandled source frame format %i\n", sane_params.format);
339 params->format = FMT_OTHER;
340 break;
342 params->last_frame = sane_params.last_frame;
343 params->bytes_per_line = sane_params.bytes_per_line;
344 params->pixels_per_line = sane_params.pixels_per_line;
345 params->lines = sane_params.lines;
346 params->depth = sane_params.depth;
347 return STATUS_SUCCESS;
350 static NTSTATUS option_get_value( void *args )
352 const struct option_get_value_params *params = args;
353 return sane_status_to_twcc( sane_control_option( device_handle, params->optno,
354 SANE_ACTION_GET_VALUE, params->val, NULL ));
357 static NTSTATUS option_set_value( void *args )
359 const struct option_set_value_params *params = args;
360 int status = 0;
361 TW_UINT16 rc = sane_status_to_twcc( sane_control_option( device_handle, params->optno,
362 SANE_ACTION_SET_VALUE, params->val, &status ));
363 if (rc == TWCC_SUCCESS && params->reload)
364 *params->reload = (status & (SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS | SANE_INFO_INEXACT)) != 0;
365 return rc;
368 static NTSTATUS option_get_descriptor( void *args )
370 struct option_descriptor *descr = args;
371 const SANE_Option_Descriptor *opt = sane_get_option_descriptor( device_handle, descr->optno );
373 if (!opt) return STATUS_NO_MORE_ENTRIES;
374 map_descr( descr, opt );
375 return STATUS_SUCCESS;
378 static NTSTATUS option_find_descriptor( void *args )
380 const struct option_find_descriptor_params *params = args;
381 struct option_descriptor *descr = params->descr;
382 const SANE_Option_Descriptor *opt;
383 int i;
385 for (i = 1; (opt = sane_get_option_descriptor( device_handle, i )) != NULL; i++)
387 if (params->type != map_type( opt->type )) continue;
388 if (strcmp( params->name, opt->name )) continue;
389 descr->optno = i;
390 map_descr( descr, opt );
391 return STATUS_SUCCESS;
393 return STATUS_NO_MORE_ENTRIES;
396 const unixlib_entry_t __wine_unix_call_funcs[] =
398 process_attach,
399 process_detach,
400 get_identity,
401 open_ds,
402 close_ds,
403 start_device,
404 cancel_device,
405 read_data,
406 get_params,
407 option_get_value,
408 option_set_value,
409 option_get_descriptor,
410 option_find_descriptor,
413 #ifdef _WIN64
415 typedef ULONG PTR32;
417 static NTSTATUS wow64_read_data( void *args )
419 struct
421 PTR32 buffer;
422 int len;
423 PTR32 retlen;
424 } const *params32 = args;
426 struct read_data_params params =
428 ULongToPtr(params32->buffer),
429 params32->len,
430 ULongToPtr(params32->retlen)
433 return read_data( &params );
436 static NTSTATUS wow64_option_get_value( void *args )
438 struct
440 int optno;
441 PTR32 val;
442 } const *params32 = args;
444 struct option_get_value_params params =
446 params32->optno,
447 ULongToPtr(params32->val)
450 return option_get_value( &params );
453 static NTSTATUS wow64_option_set_value( void *args )
455 struct
457 int optno;
458 PTR32 val;
459 PTR32 reload;
460 } const *params32 = args;
462 struct option_set_value_params params =
464 params32->optno,
465 ULongToPtr(params32->val),
466 ULongToPtr(params32->reload)
469 return option_set_value( &params );
473 static NTSTATUS wow64_option_find_descriptor( void *args )
475 struct
477 PTR32 name;
478 int type;
479 PTR32 descr;
480 } const *params32 = args;
482 struct option_find_descriptor_params params =
484 ULongToPtr(params32->name),
485 params32->type,
486 ULongToPtr(params32->descr)
489 return option_find_descriptor( &params );
492 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
494 process_attach,
495 process_detach,
496 get_identity,
497 open_ds,
498 close_ds,
499 start_device,
500 cancel_device,
501 wow64_read_data,
502 get_params,
503 wow64_option_get_value,
504 wow64_option_set_value,
505 option_get_descriptor,
506 wow64_option_find_descriptor,
509 #endif /* _WIN64 */