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
31 /* Hack for gphoto2, which changes behaviour when WIN32 is set. */
33 #include <gphoto2/gphoto2-camera.h>
36 #define WIN32_NO_STATUS
39 #include "wine/list.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(twain
);
44 static Camera
*camera
;
45 static GPContext
*context
;
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
;
59 ret
= gp_list_new (&list
);
62 ret
= gp_camera_folder_list_files (camera
, folder
, list
, context
);
64 ERR("list %d %p %p\n",ret
, camera
, context
);
68 count
= gp_list_count (list
);
73 for (i
= 0; i
< count
; i
++) {
74 ret
= gp_list_get_name (list
, i
, &name
);
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
) );
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
);
95 ret
= gp_camera_folder_list_folders (camera
, folder
, list
, context
);
97 FIXME("list_folders failed\n");
101 count
= gp_list_count (list
);
103 FIXME("list_folders failed\n");
107 for (i
= 0; i
< count
; i
++) {
108 ret
= gp_list_get_name (list
, i
, &name
);
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
);
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)
134 for (i
= 0; i
< files_count
; i
++) free( files
[i
] );
138 static NTSTATUS
get_file_name( void *args
)
140 const struct get_file_name_params
*params
= args
;
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
);
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
;
160 char *folder
, *filename
;
161 const char *filedata
;
162 unsigned long filesize
;
165 if (params
->idx
>= files_count
) return STATUS_NO_MORE_FILES
;
166 folder
= strdup( files
[params
->idx
] );
167 filename
= strrchr( folder
, '/' );
170 gp_file_new( &file
);
171 ret
= gp_camera_file_get( camera
, folder
, filename
, type
, file
, context
);
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
);
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
;
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)
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");
229 gp_port_info_list_free (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
)
238 result
= gp_port_info_list_load (port_list
);
240 gp_port_info_list_free (port_list
);
243 count
= gp_port_info_list_count (port_list
);
246 if (gp_list_new (&detected_cameras
) < GP_OK
)
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
);
256 TRACE("%d cameras detected\n", gp_list_count(detected_cameras
));
261 static NTSTATUS
get_identity( void *args
)
263 TW_IDENTITY
*id
= args
;
265 const char *cname
, *pname
;
267 if (!gphoto2_auto_detect()) return STATUS_DEVICE_NOT_CONNECTED
;
269 count
= gp_list_count (detected_cameras
);
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
);
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
;
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
);
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");
319 for (i
=0;i
<count
;i
++) {
320 const char *cname
, *pname
;
323 gp_list_get_name (detected_cameras
, i
, &cname
);
324 gp_list_get_value (detected_cameras
, i
, &pname
);
325 if (!strcmp(id
->ProductName
,cname
))
327 snprintf(name
, sizeof(name
), "%s", cname
);
328 if (!strcmp(id
->ProductName
,name
))
330 snprintf(name
, sizeof(name
), "%s@%s", cname
, pname
);
331 if (!strcmp(id
->ProductName
,name
))
335 TRACE("Camera %s not found in autodetected list. Using first entry.\n", id
->ProductName
);
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
);
344 ERR("gp_camera_new: %d\n", ret
);
345 return STATUS_DEVICE_NOT_CONNECTED
;
347 m
= gp_abilities_list_lookup_model (abilities_list
, model
);
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
);
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
);
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
);
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
);
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
);
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
);
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
[] =
424 static NTSTATUS
wow64_load_file_list( void *args
)
430 } const *params32
= args
;
432 struct load_file_list_params params
=
434 ULongToPtr(params32
->root
),
435 ULongToPtr(params32
->count
)
438 return load_file_list( ¶ms
);
441 static NTSTATUS
wow64_get_file_name( void *args
)
448 } const *params32
= args
;
450 struct get_file_name_params params
=
454 ULongToPtr(params32
->buffer
)
457 return get_file_name( ¶ms
);
460 static NTSTATUS
wow64_open_file( void *args
)
468 } const *params32
= args
;
470 struct open_file_params params
=
474 ULongToPtr(params32
->handle
),
475 ULongToPtr(params32
->size
)
478 return open_file( ¶ms
);
481 static NTSTATUS
wow64_get_file_data( void *args
)
488 } const *params32
= args
;
490 struct get_file_data_params params
=
493 ULongToPtr(params32
->data
),
497 return get_file_data( ¶ms
);
500 static NTSTATUS
wow64_close_file( void *args
)
505 } const *params32
= args
;
507 struct close_file_params params
= { params32
->handle
};
509 return close_file( ¶ms
);
512 const unixlib_entry_t __wine_unix_call_wow64_funcs
[] =
517 wow64_load_file_list
,