kernelbase: Use nameless unions/structs for loader data.
[wine.git] / dlls / gphoto2.ds / unixlib.c
blob3dd3481003419cfa96236edd4195abf155b7eb31
1 /*
2 * Unix library interface for gphoto
4 * Copyright 2000 Corel Corporation
5 * Copyright 2006 Marcus Meissner
6 * Copyright 2021 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #if 0
24 #pragma makedep unix
25 #endif
27 #include "config.h"
29 #include <stdarg.h>
30 #include <stdlib.h>
31 /* Hack for gphoto2, which changes behaviour when WIN32 is set. */
32 #undef WIN32
33 #include <gphoto2/gphoto2-camera.h>
35 #include "ntstatus.h"
36 #define WIN32_NO_STATUS
37 #include "windef.h"
38 #include "unixlib.h"
39 #include "wine/list.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(twain);
44 static Camera *camera;
45 static GPContext *context;
47 static char **files;
48 static unsigned int files_count;
49 static unsigned int files_size;
51 static void load_filesystem( const char *folder )
53 const char *name, *ext;
54 char *fullname;
55 int i, count, ret;
56 CameraList *list;
58 ERR("%s\n",folder);
59 ret = gp_list_new (&list);
60 if (ret < GP_OK)
61 return;
62 ret = gp_camera_folder_list_files (camera, folder, list, context);
63 if (ret < GP_OK) {
64 ERR("list %d %p %p\n",ret, camera, context);
65 gp_list_free (list);
66 return;
68 count = gp_list_count (list);
69 if (count < GP_OK) {
70 gp_list_free (list);
71 return;
73 for (i = 0; i < count; i++) {
74 ret = gp_list_get_name (list, i, &name);
75 if (ret < GP_OK)
76 continue;
77 if (!(ext = strrchr( name, '.' ))) continue;
78 if (strcmp( ext, ".jpg" ) && strcmp( ext, ".JPG" )) continue;
80 if (files_count == files_size)
82 unsigned int size = max( 64, files_size * 2 );
83 char **new = realloc( files, size * sizeof(*files) );
84 if (!new) return;
85 files = new;
86 files_size = size;
88 fullname = malloc( strlen(folder) + 1 + strlen(name) + 1 );
89 sprintf( fullname, "%s/%s", folder[1] ? folder : "", name );
90 files[files_count++] = fullname;
91 TRACE("adding %s\n", fullname);
93 gp_list_reset (list);
95 ret = gp_camera_folder_list_folders (camera, folder, list, context);
96 if (ret < GP_OK) {
97 FIXME("list_folders failed\n");
98 gp_list_free (list);
99 return;
101 count = gp_list_count (list);
102 if (count < GP_OK) {
103 FIXME("list_folders failed\n");
104 gp_list_free (list);
105 return;
107 for (i = 0; i < count; i++) {
108 ret = gp_list_get_name (list, i, &name);
109 if (ret < GP_OK)
110 continue;
111 TRACE("recursing into %s\n", name);
112 fullname = malloc( strlen(folder) + 1 + strlen(name) + 1 );
113 sprintf( fullname, "%s/%s", folder[1] ? folder : "", name );
114 load_filesystem( fullname );
115 free( fullname );
117 gp_list_free (list);
120 static NTSTATUS load_file_list( void *args )
122 const struct load_file_list_params *params = args;
124 if (!context) context = gp_context_new ();
125 load_filesystem( params->root );
126 *params->count = files_count;
127 return STATUS_SUCCESS;
130 static void free_file_list(void)
132 unsigned int i;
134 for (i = 0; i < files_count; i++) free( files[i] );
135 files_count = 0;
138 static NTSTATUS get_file_name( void *args )
140 const struct get_file_name_params *params = args;
141 char *name;
142 unsigned int len;
144 if (params->idx >= files_count) return STATUS_NO_MORE_FILES;
145 name = strrchr( files[params->idx], '/' ) + 1;
146 len = min( strlen(name) + 1, params->size );
147 if (len)
149 memcpy( params->buffer, name, len - 1 );
150 params->buffer[len - 1] = 0;
152 return STATUS_SUCCESS;
155 static NTSTATUS open_file( void *args )
157 const struct open_file_params *params = args;
158 CameraFileType type = params->preview ? GP_FILE_TYPE_PREVIEW : GP_FILE_TYPE_NORMAL;
159 CameraFile *file;
160 char *folder, *filename;
161 const char *filedata;
162 unsigned long filesize;
163 int ret;
165 if (params->idx >= files_count) return STATUS_NO_MORE_FILES;
166 folder = strdup( files[params->idx] );
167 filename = strrchr( folder, '/' );
168 *filename++ = 0;
170 gp_file_new( &file );
171 ret = gp_camera_file_get( camera, folder, filename, type, file, context );
172 free( folder );
173 if (ret < GP_OK)
175 FIXME( "Failed to get %s\n", files[params->idx] );
176 gp_file_unref( file );
177 return STATUS_NO_SUCH_FILE;
179 ret = gp_file_get_data_and_size( file, &filedata, &filesize );
180 if (ret < GP_OK)
182 gp_file_unref( file );
183 return STATUS_NO_SUCH_FILE;
185 *params->handle = (ULONG_PTR)file;
186 *params->size = filesize;
187 return STATUS_SUCCESS;
190 static NTSTATUS get_file_data( void *args )
192 const struct get_file_data_params *params = args;
193 CameraFile *file = (CameraFile *)(ULONG_PTR)params->handle;
194 const char *filedata;
195 unsigned long filesize;
196 int ret;
198 ret = gp_file_get_data_and_size( file, &filedata, &filesize );
199 if (ret < GP_OK) return STATUS_NO_SUCH_FILE;
200 if (filesize > params->size) return STATUS_BUFFER_TOO_SMALL;
201 memcpy( params->data, filedata, filesize );
202 return STATUS_SUCCESS;
205 static NTSTATUS close_file( void *args )
207 const struct close_file_params *params = args;
208 CameraFile *file = (CameraFile *)(ULONG_PTR)params->handle;
210 gp_file_unref( file );
211 return STATUS_SUCCESS;
214 #ifdef HAVE_GPHOTO2_PORT
216 static GPPortInfoList *port_list;
217 static int curcamera;
218 static CameraList *detected_cameras;
219 static CameraAbilitiesList *abilities_list;
221 static BOOL gphoto2_auto_detect(void)
223 int result, count;
225 if (detected_cameras && (gp_list_count (detected_cameras) == 0)) {
226 /* Reload if previously no cameras, we might detect new ones. */
227 TRACE("Reloading portlist trying to detect cameras.\n");
228 if (port_list) {
229 gp_port_info_list_free (port_list);
230 port_list = NULL;
233 if (!port_list) {
234 TRACE("Auto detecting gphoto cameras.\n");
235 TRACE("Loading ports...\n");
236 if (gp_port_info_list_new (&port_list) < GP_OK)
237 return FALSE;
238 result = gp_port_info_list_load (port_list);
239 if (result < 0) {
240 gp_port_info_list_free (port_list);
241 return FALSE;
243 count = gp_port_info_list_count (port_list);
244 if (count <= 0)
245 return FALSE;
246 if (gp_list_new (&detected_cameras) < GP_OK)
247 return FALSE;
248 if (!abilities_list) { /* Load only once per program start */
249 gp_abilities_list_new (&abilities_list);
250 TRACE("Loading cameras...\n");
251 gp_abilities_list_load (abilities_list, NULL);
253 TRACE("Detecting cameras...\n");
254 gp_abilities_list_detect (abilities_list, port_list, detected_cameras, NULL);
255 curcamera = 0;
256 TRACE("%d cameras detected\n", gp_list_count(detected_cameras));
258 return TRUE;
261 static NTSTATUS get_identity( void *args )
263 TW_IDENTITY *id = args;
264 int count;
265 const char *cname, *pname;
267 if (!gphoto2_auto_detect()) return STATUS_DEVICE_NOT_CONNECTED;
269 count = gp_list_count (detected_cameras);
270 if (count < GP_OK) {
271 gp_list_free (detected_cameras);
272 return STATUS_DEVICE_NOT_CONNECTED;
274 TRACE("%d cameras detected.\n", count);
275 id->ProtocolMajor = TWON_PROTOCOLMAJOR;
276 id->ProtocolMinor = TWON_PROTOCOLMINOR;
277 id->SupportedGroups = DG_CONTROL | DG_IMAGE | DF_DS2;
278 lstrcpynA (id->Manufacturer, "The Wine Team", sizeof(id->Manufacturer) - 1);
279 lstrcpynA (id->ProductFamily, "GPhoto2 Camera", sizeof(id->ProductFamily) - 1);
281 if (!count) { /* No camera detected. But we need to return an IDENTITY anyway. */
282 lstrcpynA (id->ProductName, "GPhoto2 Camera", sizeof(id->ProductName) - 1);
283 return STATUS_SUCCESS;
285 gp_list_get_name (detected_cameras, curcamera, &cname);
286 gp_list_get_value (detected_cameras, curcamera, &pname);
287 if (count == 1) /* Normal case, only one camera. */
288 snprintf (id->ProductName, sizeof(id->ProductName), "%s", cname);
289 else
290 snprintf (id->ProductName, sizeof(id->ProductName), "%s@%s", cname, pname);
291 curcamera = (curcamera+1) % count;
292 return STATUS_SUCCESS;
295 static NTSTATUS open_ds( void *args )
297 TW_IDENTITY *id = args;
298 int ret, m, p, count, i;
299 CameraAbilities a;
300 GPPortInfo info;
301 const char *model, *port;
303 if (!gphoto2_auto_detect()) return STATUS_DEVICE_NOT_CONNECTED;
305 if (strcmp(id->ProductFamily,"GPhoto2 Camera")) {
306 FIXME("identity passed is not a gphoto camera, but %s!?!\n", id->ProductFamily);
307 return STATUS_DEVICE_UNRESPONSIVE;
309 count = gp_list_count (detected_cameras);
310 if (!count) {
311 ERR("No camera found by autodetection. Returning failure.\n");
312 return STATUS_DEVICE_NOT_CONNECTED;
315 if (!strcmp (id->ProductName, "GPhoto2 Camera")) {
316 TRACE("Potential undetected camera. Just using the first autodetected one.\n");
317 i = 0;
318 } else {
319 for (i=0;i<count;i++) {
320 const char *cname, *pname;
321 TW_STR32 name;
323 gp_list_get_name (detected_cameras, i, &cname);
324 gp_list_get_value (detected_cameras, i, &pname);
325 if (!strcmp(id->ProductName,cname))
326 break;
327 snprintf(name, sizeof(name), "%s", cname);
328 if (!strcmp(id->ProductName,name))
329 break;
330 snprintf(name, sizeof(name), "%s@%s", cname, pname);
331 if (!strcmp(id->ProductName,name))
332 break;
334 if (i == count) {
335 TRACE("Camera %s not found in autodetected list. Using first entry.\n", id->ProductName);
336 i=0;
339 gp_list_get_name (detected_cameras, i, &model);
340 gp_list_get_value (detected_cameras, i, &port);
341 TRACE("model %s, port %s\n", model, port);
342 ret = gp_camera_new (&camera);
343 if (ret < GP_OK) {
344 ERR("gp_camera_new: %d\n", ret);
345 return STATUS_DEVICE_NOT_CONNECTED;
347 m = gp_abilities_list_lookup_model (abilities_list, model);
348 if (m < GP_OK) {
349 FIXME("Model %s not found, %d!\n", model, m);
350 return STATUS_DEVICE_NOT_CONNECTED;
352 ret = gp_abilities_list_get_abilities (abilities_list, m, &a);
353 if (ret < GP_OK) {
354 FIXME("gp_camera_list_get_abilities failed? %d\n", ret);
355 return STATUS_DEVICE_NOT_CONNECTED;
357 ret = gp_camera_set_abilities (camera, a);
358 if (ret < GP_OK) {
359 FIXME("gp_camera_set_abilities failed? %d\n", ret);
360 return STATUS_DEVICE_NOT_CONNECTED;
363 p = gp_port_info_list_lookup_path (port_list, port);
364 if (p < GP_OK) {
365 FIXME("port %s not in portlist?\n", port);
366 return STATUS_DEVICE_NOT_CONNECTED;
368 ret = gp_port_info_list_get_info (port_list, p, &info);
369 if (ret < GP_OK) {
370 FIXME("could not get portinfo for port %s?\n", port);
371 return STATUS_DEVICE_NOT_CONNECTED;
373 ret = gp_camera_set_port_info (camera, info);
374 if (ret < GP_OK) {
375 FIXME("could not set portinfo for port %s to camera?\n", port);
376 return STATUS_DEVICE_NOT_CONNECTED;
378 return STATUS_SUCCESS;
381 static NTSTATUS close_ds( void *args )
383 if (!camera) return STATUS_SUCCESS;
384 gp_camera_free (camera);
385 free_file_list();
386 return STATUS_SUCCESS;
389 #else /* HAVE_GPHOTO2_PORT */
391 static NTSTATUS get_identity( void *args )
393 return STATUS_DEVICE_NOT_CONNECTED;
396 static NTSTATUS open_ds( void *args )
398 return STATUS_DEVICE_NOT_CONNECTED;
401 static NTSTATUS close_ds( void *args )
403 return STATUS_SUCCESS;
406 #endif /* HAVE_GPHOTO2_PORT */
408 const unixlib_entry_t __wine_unix_call_funcs[] =
410 get_identity,
411 open_ds,
412 close_ds,
413 load_file_list,
414 get_file_name,
415 open_file,
416 get_file_data,
417 close_file,
420 #ifdef _WIN64
422 typedef ULONG PTR32;
424 static NTSTATUS wow64_load_file_list( void *args )
426 struct
428 PTR32 root;
429 PTR32 count;
430 } const *params32 = args;
432 struct load_file_list_params params =
434 ULongToPtr(params32->root),
435 ULongToPtr(params32->count)
438 return load_file_list( &params );
441 static NTSTATUS wow64_get_file_name( void *args )
443 struct
445 unsigned int idx;
446 unsigned int size;
447 PTR32 buffer;
448 } const *params32 = args;
450 struct get_file_name_params params =
452 params32->idx,
453 params32->size,
454 ULongToPtr(params32->buffer)
457 return get_file_name( &params );
460 static NTSTATUS wow64_open_file( void *args )
462 struct
464 unsigned int idx;
465 BOOL preview;
466 PTR32 handle;
467 PTR32 size;
468 } const *params32 = args;
470 struct open_file_params params =
472 params32->idx,
473 params32->preview,
474 ULongToPtr(params32->handle),
475 ULongToPtr(params32->size)
478 return open_file( &params );
481 static NTSTATUS wow64_get_file_data( void *args )
483 struct
485 UINT64 handle;
486 PTR32 data;
487 unsigned int size;
488 } const *params32 = args;
490 struct get_file_data_params params =
492 params32->handle,
493 ULongToPtr(params32->data),
494 params32->size
497 return get_file_data( &params );
500 static NTSTATUS wow64_close_file( void *args )
502 struct
504 UINT64 handle;
505 } const *params32 = args;
507 struct close_file_params params = { params32->handle };
509 return close_file( &params );
512 const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
514 get_identity,
515 open_ds,
516 close_ds,
517 wow64_load_file_list,
518 wow64_get_file_name,
519 wow64_open_file,
520 wow64_get_file_data,
521 wow64_close_file,
524 #endif /* _WIN64 */