1 /**
2 * \file libmtp.c
3 *
4 * Copyright (C) 2005-2011 Linus Walleij <triad@df.lth.se>
5 * Copyright (C) 2005-2008 Richard A. Low <richard@wentnet.com>
6 * Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
7 * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
8 * Copyright (C) 2008 Florent Mertens <flomertens@gmail.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 *
25 * This file provides an interface "glue" to the underlying
26 * PTP implementation from libgphoto2. It uses some local
27 * code to convert from/to UTF-8 (stored in unicode.c/.h)
28 * and some small utility functions, mainly for debugging
29 * (stored in util.c/.h).
30 *
31 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
32 * plain copied from the libhphoto2 codebase.
33 *
34 * The files libusb-glue.c/.h are just what they say: an
35 * interface to libusb for the actual, physical USB traffic.
36 */
37 #include "config.h"
38 #include "libmtp.h"
39 #include "unicode.h"
40 #include "ptp.h"
41 #include "libusb-glue.h"
42 #include "device-flags.h"
43 #include "playlist-spl.h"
44 #include "util.h"
45
46 #include "mtpz.h"
47
48 #include <stdarg.h>
49 #include <stdlib.h>
50 #include <limits.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include <time.h>
57 #include <errno.h>
58 #ifdef _MSC_VER // For MSVC++
59 #define USE_WINDOWS_IO_H
60 #include <io.h>
61 #endif
62
63
64 /**
65 * Global debug level
66 * We use a flag system to enable a part of logs.
67 *
68 * The LIBMTP_DEBUG environment variable sets the debug flags for any binary
69 * that uses libmtp and calls LIBMTP_Init. The value can be given in decimal
70 * (must not start with "0" or it will be interpreted in octal), or in
71 * hexadecimal (must start with "0x").
72 *
73 * The value "-1" enables all debug flags.
74 *
75 * Some of the utilities in examples/ also take a command-line flag "-d" that
76 * enables LIBMTP_DEBUG_PTP and LIBMTP_DEBUG_DATA (same as setting
77 * LIBMTP_DEBUG=9).
78 *
79 * Flags (combine by adding the hex values):
80 * 0x00 [0000 0000] : LIBMTP_DEBUG_NONE : no debug (default)
81 * 0x01 [0000 0001] : LIBMTP_DEBUG_PTP : PTP debug
82 * 0x02 [0000 0010] : LIBMTP_DEBUG_PLST : Playlist debug
83 * 0x04 [0000 0100] : LIBMTP_DEBUG_USB : USB debug
84 * 0x08 [0000 1000] : LIBMTP_DEBUG_DATA : USB data debug
85 *
86 * (Please keep this list in sync with libmtp.h.)
87 */
88 int LIBMTP_debug = LIBMTP_DEBUG_NONE;
89
90
91 /*
92 * This is a mapping between libmtp internal MTP filetypes and
93 * the libgphoto2/PTP equivalent defines. We need this because
94 * otherwise the libmtp.h device has to be dependent on ptp.h
95 * to be installed too, and we don't want that.
96 */
97 //typedef struct filemap_struct filemap_t;
98 typedef struct filemap_struct {
99 char *description; /**< Text description for the file type */
100 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
101 uint16_t ptp_id; /**< PTP ID for the filetype */
102 struct filemap_struct *next;
103 } filemap_t;
104
105 /*
106 * This is a mapping between libmtp internal MTP properties and
107 * the libgphoto2/PTP equivalent defines. We need this because
108 * otherwise the libmtp.h device has to be dependent on ptp.h
109 * to be installed too, and we don't want that.
110 */
111 typedef struct propertymap_struct {
112 char *description; /**< Text description for the property */
113 LIBMTP_property_t id; /**< LIBMTP internal type for the property */
114 uint16_t ptp_id; /**< PTP ID for the property */
115 struct propertymap_struct *next;
116 } propertymap_t;
117
118 /*
119 * This is a simple container for holding our callback and user_data
120 * for parsing onwards to the usb_event_async function.
121 */
122 typedef struct event_cb_data_struct {
123 LIBMTP_event_cb_fn cb;
124 void *user_data;
125 } event_cb_data_t;
126
127 // Global variables
128 // This holds the global filetype mapping table
129 static filemap_t *g_filemap = NULL;
130 // This holds the global property mapping table
131 static propertymap_t *g_propertymap = NULL;
132
133 static int load_cache_on_demand = 0;
134 /*
135 * Forward declarations of local (static) functions.
136 */
137 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
138 uint16_t const ptp_id);
139 static void init_filemap();
140 static int register_property(char const * const description, LIBMTP_property_t const id,
141 uint16_t const ptp_id);
142 static void init_propertymap();
143 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
144 LIBMTP_error_number_t errornumber,
145 char const * const error_text);
146 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
147 uint16_t ptp_error,
148 char const * const error_text);
149 static void flush_handles(LIBMTP_mtpdevice_t *device);
150 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
151 PTPParams *params,
152 uint32_t storageid,
153 uint32_t parent);
154 static void free_storage_list(LIBMTP_mtpdevice_t *device);
155 static int sort_storage_by(LIBMTP_mtpdevice_t *device, int const sortby);
156 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
157 uint64_t fitsize);
158 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
159 LIBMTP_devicestorage_t *storage,
160 uint64_t *freespace);
161 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
162 LIBMTP_devicestorage_t *storage,
163 uint64_t const filesize);
164 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
165 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
166 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
167 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
168 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
169 char **unicstring, uint16_t property);
170 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
171 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd);
172 static char *get_iso8601_stamp(void);
173 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
174 uint16_t const attribute_id);
175 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
176 uint16_t const attribute_id, uint64_t const value_default);
177 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
178 uint16_t const attribute_id, uint32_t const value_default);
179 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
180 uint16_t const attribute_id, uint16_t const value_default);
181 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
182 uint16_t const attribute_id, uint8_t const value_default);
183 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
184 uint16_t const attribute_id, char const * const string);
185 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
186 uint16_t const attribute_id, uint32_t const value);
187 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
188 uint16_t const attribute_id, uint16_t const value);
189 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
190 uint16_t const attribute_id, uint8_t const value);
191 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
192 LIBMTP_track_t *track);
193 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent);
194 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
195 char const * const name,
196 char const * const artist,
197 char const * const composer,
198 char const * const genre,
199 uint32_t const parenthandle,
200 uint32_t const storageid,
201 uint16_t const objectformat,
202 char const * const suffix,
203 uint32_t * const newid,
204 uint32_t const * const tracks,
205 uint32_t const no_tracks);
206 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
207 char const * const name,
208 char const * const artist,
209 char const * const composer,
210 char const * const genre,
211 uint32_t const objecthandle,
212 uint16_t const objectformat,
213 uint32_t const * const tracks,
214 uint32_t const no_tracks);
215 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
216 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
217 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
218 static int set_object_filename(LIBMTP_mtpdevice_t *device,
219 uint32_t object_id,
220 uint16_t ptp_type,
221 const char **newname);
222 static char *generate_unique_filename(PTPParams* params, char const * const filename);
223 static int check_filename_exists(PTPParams* params, char const * const filename);
224 static void LIBMTP_Handle_Event(PTPContainer *ptp_event,
225 LIBMTP_event_t *event, uint32_t *out1);
226
227 /**
228 * These are to wrap the get/put handlers to convert from the MTP types to PTP types
229 * in a reliable way
230 */
231 typedef struct _MTPDataHandler {
232 MTPDataGetFunc getfunc;
233 MTPDataPutFunc putfunc;
234 void *priv;
235 } MTPDataHandler;
236
237 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
238 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data);
239
240 /**
241 * Checks if a filename ends with ".ogg". Used in various
242 * situations when the device has no idea that it support
243 * OGG but still does.
244 *
245 * @param name string to be checked.
246 * @return 0 if this does not end with ogg, any other
247 * value means it does.
248 */
has_ogg_extension(char * name)249 static int has_ogg_extension(char *name) {
250 char *ptype;
251
252 if (name == NULL)
253 return 0;
254 ptype = strrchr(name,'.');
255 if (ptype == NULL)
256 return 0;
257 if (!strcasecmp (ptype, ".ogg"))
258 return 1;
259 return 0;
260 }
261
262 /**
263 * Checks if a filename ends with ".flac". Used in various
264 * situations when the device has no idea that it support
265 * FLAC but still does.
266 *
267 * @param name string to be checked.
268 * @return 0 if this does not end with flac, any other
269 * value means it does.
270 */
has_flac_extension(char * name)271 static int has_flac_extension(char *name) {
272 char *ptype;
273
274 if (name == NULL)
275 return 0;
276 ptype = strrchr(name,'.');
277 if (ptype == NULL)
278 return 0;
279 if (!strcasecmp (ptype, ".flac"))
280 return 1;
281 return 0;
282 }
283
284
285
286 /**
287 * Create a new file mapping entry
288 * @return a newly allocated filemapping entry.
289 */
new_filemap_entry()290 static filemap_t *new_filemap_entry()
291 {
292 filemap_t *filemap;
293
294 filemap = (filemap_t *)malloc(sizeof(filemap_t));
295
296 if( filemap != NULL ) {
297 filemap->description = NULL;
298 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
299 filemap->ptp_id = PTP_OFC_Undefined;
300 filemap->next = NULL;
301 }
302
303 return filemap;
304 }
305
306 /**
307 * Register an MTP or PTP filetype for data retrieval
308 *
309 * @param description Text description of filetype
310 * @param id libmtp internal filetype id
311 * @param ptp_id PTP filetype id
312 * @return 0 for success any other value means error.
313 */
register_filetype(char const * const description,LIBMTP_filetype_t const id,uint16_t const ptp_id)314 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
315 uint16_t const ptp_id)
316 {
317 filemap_t *new = NULL, *current;
318
319 // Has this LIBMTP filetype been registered before ?
320 current = g_filemap;
321 while (current != NULL) {
322 if(current->id == id) {
323 break;
324 }
325 current = current->next;
326 }
327
328 // Create the entry
329 if(current == NULL) {
330 new = new_filemap_entry();
331 if(new == NULL) {
332 return 1;
333 }
334
335 new->id = id;
336 if(description != NULL) {
337 new->description = strdup(description);
338 }
339 new->ptp_id = ptp_id;
340
341 // Add the entry to the list
342 if(g_filemap == NULL) {
343 g_filemap = new;
344 } else {
345 current = g_filemap;
346 while (current->next != NULL ) current=current->next;
347 current->next = new;
348 }
349 // Update the existing entry
350 } else {
351 if (current->description != NULL) {
352 free(current->description);
353 }
354 current->description = NULL;
355 if(description != NULL) {
356 current->description = strdup(description);
357 }
358 current->ptp_id = ptp_id;
359 }
360
361 return 0;
362 }
363
init_filemap()364 static void init_filemap()
365 {
366 register_filetype("Folder", LIBMTP_FILETYPE_FOLDER, PTP_OFC_Association);
367 register_filetype("MediaCard", LIBMTP_FILETYPE_MEDIACARD, PTP_OFC_MTP_MediaCard);
368 register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);
369 register_filetype("ISO MPEG-1 Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);
370 register_filetype("ISO MPEG-1 Audio Layer 2", LIBMTP_FILETYPE_MP2, PTP_OFC_MTP_MP2);
371 register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);
372 register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
373 register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
374 register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
375 register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
376 register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
377 register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
378 register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
379 register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
380 register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);
381 register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);
382 register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);
383 register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);
384 register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);
385 register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);
386 register_filetype("JP2 file", LIBMTP_FILETYPE_JP2, PTP_OFC_JP2);
387 register_filetype("JPX file", LIBMTP_FILETYPE_JPX, PTP_OFC_JPX);
388 register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);
389 register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);
390 register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);
391 register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);
392 register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);
393 register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);
394 register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);
395 register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);
396 register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);
397 register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);
398 register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);
399 register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);
400 register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);
401 register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);
402 register_filetype("XML file", LIBMTP_FILETYPE_XML, PTP_OFC_MTP_XMLDocument);
403 register_filetype("DOC file", LIBMTP_FILETYPE_DOC, PTP_OFC_MTP_MSWordDocument);
404 register_filetype("XLS file", LIBMTP_FILETYPE_XLS, PTP_OFC_MTP_MSExcelSpreadsheetXLS);
405 register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
406 register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
407 register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
408 register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
409 register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
410 register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
411 }
412
413 /**
414 * Returns the PTP filetype that maps to a certain libmtp internal file type.
415 * @param intype the MTP library interface type
416 * @return the PTP (libgphoto2) interface type
417 */
map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)418 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
419 {
420 filemap_t *current;
421
422 current = g_filemap;
423
424 while (current != NULL) {
425 if(current->id == intype) {
426 return current->ptp_id;
427 }
428 current = current->next;
429 }
430 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
431 return PTP_OFC_Undefined;
432 }
433
434
435 /**
436 * Returns the MTP internal interface type that maps to a certain ptp
437 * interface type.
438 * @param intype the PTP (libgphoto2) interface type
439 * @return the MTP library interface type
440 */
map_ptp_type_to_libmtp_type(uint16_t intype)441 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
442 {
443 filemap_t *current;
444
445 current = g_filemap;
446
447 while (current != NULL) {
448 if(current->ptp_id == intype) {
449 return current->id;
450 }
451 current = current->next;
452 }
453 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
454 return LIBMTP_FILETYPE_UNKNOWN;
455 }
456
457 /**
458 * Create a new property mapping entry
459 * @return a newly allocated propertymapping entry.
460 */
new_propertymap_entry()461 static propertymap_t *new_propertymap_entry()
462 {
463 propertymap_t *propertymap;
464
465 propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
466
467 if( propertymap != NULL ) {
468 propertymap->description = NULL;
469 propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
470 propertymap->ptp_id = 0;
471 propertymap->next = NULL;
472 }
473
474 return propertymap;
475 }
476
477 /**
478 * Register an MTP or PTP property for data retrieval
479 *
480 * @param description Text description of property
481 * @param id libmtp internal property id
482 * @param ptp_id PTP property id
483 * @return 0 for success any other value means error.
484 */
register_property(char const * const description,LIBMTP_property_t const id,uint16_t const ptp_id)485 static int register_property(char const * const description, LIBMTP_property_t const id,
486 uint16_t const ptp_id)
487 {
488 propertymap_t *new = NULL, *current;
489
490 // Has this LIBMTP propety been registered before ?
491 current = g_propertymap;
492 while (current != NULL) {
493 if(current->id == id) {
494 break;
495 }
496 current = current->next;
497 }
498
499 // Create the entry
500 if(current == NULL) {
501 new = new_propertymap_entry();
502 if(new == NULL) {
503 return 1;
504 }
505
506 new->id = id;
507 if(description != NULL) {
508 new->description = strdup(description);
509 }
510 new->ptp_id = ptp_id;
511
512 // Add the entry to the list
513 if(g_propertymap == NULL) {
514 g_propertymap = new;
515 } else {
516 current = g_propertymap;
517 while (current->next != NULL ) current=current->next;
518 current->next = new;
519 }
520 // Update the existing entry
521 } else {
522 if (current->description != NULL) {
523 free(current->description);
524 }
525 current->description = NULL;
526 if(description != NULL) {
527 current->description = strdup(description);
528 }
529 current->ptp_id = ptp_id;
530 }
531
532 return 0;
533 }
534
init_propertymap()535 static void init_propertymap()
536 {
537 register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
538 register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
539 register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
540 register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
541 register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
542 register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
543 register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
544 register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
545 register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
546 register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
547 register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
548 register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
549 register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
550 register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
551 register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
552 register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
553 register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
554 register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
555 register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
556 register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
557 register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
558 register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
559 register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
560 register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
561 register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
562 register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
563 register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
564 register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
565 register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
566 register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
567 register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
568 register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
569 register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
570 register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
571 register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
572 register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
573 register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
574 register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
575 register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
576 register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
577 register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
578 register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
579 register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
580 register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
581 register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
582 register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
583 register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
584 register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
585 register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
586 register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
587 register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
588 register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
589 register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
590 register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
591 register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
592 register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
593 register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
594 register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
595 register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
596 register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
597 register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
598 register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
599 register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
600 register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
601 register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
602 register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
603 register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
604 register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
605 register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
606 register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
607 register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
608 register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
609 register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
610 register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
611 register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
612 register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
613 register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
614 register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
615 register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
616 register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
617 register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
618 register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
619 register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
620 register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
621 register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
622 register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
623 register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
624 register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
625 register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
626 register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
627 register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
628 register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
629 register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
630 register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
631 register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
632 register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
633 register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
634 register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
635 register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
636 register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
637 register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
638 register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
639 register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
640 register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
641 register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
642 register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
643 register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
644 register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
645 register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
646 register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
647 register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
648 register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
649 register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
650 register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
651 register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
652 register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
653 register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
654 register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
655 register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
656 register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
657 register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
658 register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
659 register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
660 register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
661 register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
662 register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
663 register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
664 register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
665 register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
666 register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
667 register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
668 register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
669 register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
670 register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
671 register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
672 register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
673 register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
674 register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
675 register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
676 register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
677 register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
678 register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
679 register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
680 register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
681 register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
682 register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
683 register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
684 register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
685 register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
686 register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
687 register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
688 register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
689 register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
690 register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
691 register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
692 register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
693 register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
694 register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
695 register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
696 register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
697 register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
698 register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
699 register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
700 register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
701 register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
702 register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
703 register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
704 register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
705 }
706
707 /**
708 * Returns the PTP property that maps to a certain libmtp internal property type.
709 * @param inproperty the MTP library interface property
710 * @return the PTP (libgphoto2) property type
711 */
map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)712 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
713 {
714 propertymap_t *current;
715
716 current = g_propertymap;
717
718 while (current != NULL) {
719 if(current->id == inproperty) {
720 return current->ptp_id;
721 }
722 current = current->next;
723 }
724 return 0;
725 }
726
727
728 /**
729 * Returns the MTP internal interface property that maps to a certain ptp
730 * interface property.
731 * @param inproperty the PTP (libgphoto2) interface property
732 * @return the MTP library interface property
733 */
map_ptp_property_to_libmtp_property(uint16_t inproperty)734 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
735 {
736 propertymap_t *current;
737
738 current = g_propertymap;
739
740 while (current != NULL) {
741 if(current->ptp_id == inproperty) {
742 return current->id;
743 }
744 current = current->next;
745 }
746 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
747 return LIBMTP_PROPERTY_UNKNOWN;
748 }
749
750
751 /**
752 * Set the debug level.
753 *
754 * By default, the debug level is set to '0' (disable).
755 */
LIBMTP_Set_Debug(int level)756 void LIBMTP_Set_Debug(int level)
757 {
758 if (LIBMTP_debug || level)
759 LIBMTP_ERROR("LIBMTP_Set_Debug: Setting debugging level to %d (0x%02x) "
760 "(%s)\n", level, level, level ? "on" : "off");
761
762 LIBMTP_debug = level;
763 }
764
765
766 /**
767 * Initialize the library. You are only supposed to call this
768 * one, before using the library for the first time in a program.
769 * Never re-initialize libmtp!
770 *
771 * The only thing this does at the moment is to initialise the
772 * filetype mapping table, as well as load MTPZ data if necessary.
773 */
LIBMTP_Init(void)774 void LIBMTP_Init(void)
775 {
776 const char *env_debug = getenv("LIBMTP_DEBUG");
777 if (env_debug) {
778 const long debug_flags = strtol(env_debug, NULL, 0);
779 if (debug_flags != LONG_MIN && debug_flags != LONG_MAX &&
780 INT_MIN <= debug_flags && debug_flags <= INT_MAX) {
781 LIBMTP_Set_Debug(debug_flags);
782 } else {
783 fprintf(stderr, "LIBMTP_Init: error setting debug flags from environment "
784 "value \"%s\"\n", env_debug);
785 }
786 }
787
788 init_filemap();
789 init_propertymap();
790
791 if (mtpz_loaddata() == -1)
792 use_mtpz = 0;
793 else
794 use_mtpz = 1;
795
796 return;
797 }
798
799
800 /**
801 * This helper function returns a textual description for a libmtp
802 * file type to be used in dialog boxes etc.
803 * @param intype the libmtp internal filetype to get a description for.
804 * @return a string representing the filetype, this must <b>NOT</b>
805 * be free():ed by the caller!
806 */
LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)807 char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
808 {
809 filemap_t *current;
810
811 current = g_filemap;
812
813 while (current != NULL) {
814 if(current->id == intype) {
815 return current->description;
816 }
817 current = current->next;
818 }
819
820 return "Unknown filetype";
821 }
822
823 /**
824 * This helper function returns a textual description for a libmtp
825 * property to be used in dialog boxes etc.
826 * @param inproperty the libmtp internal property to get a description for.
827 * @return a string representing the filetype, this must <b>NOT</b>
828 * be free():ed by the caller!
829 */
LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)830 char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
831 {
832 propertymap_t *current;
833
834 current = g_propertymap;
835
836 while (current != NULL) {
837 if(current->id == inproperty) {
838 return current->description;
839 }
840 current = current->next;
841 }
842
843 return "Unknown property";
844 }
845
846 /**
847 * This function will do its best to fit a 16bit
848 * value into a PTP object property if the property
849 * is limited in range or step sizes.
850 */
adjust_u16(uint16_t val,PTPObjectPropDesc * opd)851 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd)
852 {
853 switch (opd->FormFlag) {
854 case PTP_DPFF_Range:
855 if (val < opd->FORM.Range.MinimumValue.u16) {
856 return opd->FORM.Range.MinimumValue.u16;
857 }
858 if (val > opd->FORM.Range.MaximumValue.u16) {
859 return opd->FORM.Range.MaximumValue.u16;
860 }
861 // Round down to last step.
862 if (val % opd->FORM.Range.StepSize.u16 != 0) {
863 return val - (val % opd->FORM.Range.StepSize.u16);
864 }
865 return val;
866 break;
867 case PTP_DPFF_Enumeration:
868 {
869 int i;
870 uint16_t bestfit = opd->FORM.Enum.SupportedValue[0].u16;
871
872 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
873 if (val == opd->FORM.Enum.SupportedValue[i].u16) {
874 return val;
875 }
876 // Rough guess of best fit
877 if (opd->FORM.Enum.SupportedValue[i].u16 < val) {
878 bestfit = opd->FORM.Enum.SupportedValue[i].u16;
879 }
880 }
881 // Just some default that'll work.
882 return bestfit;
883 }
884 default:
885 // Will accept any value
886 break;
887 }
888 return val;
889 }
890
891 /**
892 * This function will do its best to fit a 32bit
893 * value into a PTP object property if the property
894 * is limited in range or step sizes.
895 */
adjust_u32(uint32_t val,PTPObjectPropDesc * opd)896 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd)
897 {
898 switch (opd->FormFlag) {
899 case PTP_DPFF_Range:
900 if (val < opd->FORM.Range.MinimumValue.u32) {
901 return opd->FORM.Range.MinimumValue.u32;
902 }
903 if (val > opd->FORM.Range.MaximumValue.u32) {
904 return opd->FORM.Range.MaximumValue.u32;
905 }
906 // Round down to last step.
907 if (val % opd->FORM.Range.StepSize.u32 != 0) {
908 return val - (val % opd->FORM.Range.StepSize.u32);
909 }
910 return val;
911 break;
912 case PTP_DPFF_Enumeration:
913 {
914 int i;
915 uint32_t bestfit = opd->FORM.Enum.SupportedValue[0].u32;
916
917 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
918 if (val == opd->FORM.Enum.SupportedValue[i].u32) {
919 return val;
920 }
921 // Rough guess of best fit
922 if (opd->FORM.Enum.SupportedValue[i].u32 < val) {
923 bestfit = opd->FORM.Enum.SupportedValue[i].u32;
924 }
925 }
926 // Just some default that'll work.
927 return bestfit;
928 }
929 default:
930 // Will accept any value
931 break;
932 }
933 return val;
934 }
935
936 /**
937 * This function returns a newly created ISO 8601 timestamp with the
938 * current time in as high precision as possible. It even adds
939 * the time zone if it can.
940 */
get_iso8601_stamp(void)941 static char *get_iso8601_stamp(void)
942 {
943 time_t curtime;
944 struct tm *loctime;
945 char tmp[64];
946
947 curtime = time(NULL);
948 loctime = localtime(&curtime);
949 strftime (tmp, sizeof(tmp), "%Y%m%dT%H%M%S.0%z", loctime);
950 return strdup(tmp);
951 }
952
953 /**
954 * Gets the allowed values (range or enum) for a property
955 * @param device a pointer to an MTP device
956 * @param property the property to query
957 * @param filetype the filetype of the object you want to set values for
958 * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
959 * receive the allowed values. Call LIBMTP_destroy_allowed_values_t
960 * on this on successful completion.
961 * @return 0 on success, any other value means failure
962 */
LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype,LIBMTP_allowed_values_t * allowed_vals)963 int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
964 LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
965 {
966 PTPObjectPropDesc opd;
967 uint16_t ret = 0;
968
969 ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
970 if (ret != PTP_RC_OK) {
971 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
972 return -1;
973 }
974
975 if (opd.FormFlag == PTP_OPFF_Enumeration) {
976 int i = 0;
977
978 allowed_vals->is_range = 0;
979 allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
980
981 switch (opd.DataType)
982 {
983 case PTP_DTC_INT8:
984 allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
985 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
986 break;
987 case PTP_DTC_UINT8:
988 allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
989 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
990 break;
991 case PTP_DTC_INT16:
992 allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
993 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
994 break;
995 case PTP_DTC_UINT16:
996 allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
997 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
998 break;
999 case PTP_DTC_INT32:
1000 allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
1001 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1002 break;
1003 case PTP_DTC_UINT32:
1004 allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
1005 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1006 break;
1007 case PTP_DTC_INT64:
1008 allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
1009 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1010 break;
1011 case PTP_DTC_UINT64:
1012 allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
1013 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1014 break;
1015 }
1016
1017 for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
1018 switch (opd.DataType)
1019 {
1020 case PTP_DTC_INT8:
1021 allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
1022 break;
1023 case PTP_DTC_UINT8:
1024 allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
1025 break;
1026 case PTP_DTC_INT16:
1027 allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
1028 break;
1029 case PTP_DTC_UINT16:
1030 allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
1031 break;
1032 case PTP_DTC_INT32:
1033 allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
1034 break;
1035 case PTP_DTC_UINT32:
1036 allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
1037 break;
1038 case PTP_DTC_INT64:
1039 allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
1040 break;
1041 case PTP_DTC_UINT64:
1042 allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
1043 break;
1044 }
1045 }
1046 ptp_free_objectpropdesc(&opd);
1047 return 0;
1048 } else if (opd.FormFlag == PTP_OPFF_Range) {
1049 allowed_vals->is_range = 1;
1050
1051 switch (opd.DataType)
1052 {
1053 case PTP_DTC_INT8:
1054 allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
1055 allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
1056 allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
1057 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
1058 break;
1059 case PTP_DTC_UINT8:
1060 allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
1061 allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
1062 allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
1063 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
1064 break;
1065 case PTP_DTC_INT16:
1066 allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
1067 allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
1068 allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
1069 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
1070 break;
1071 case PTP_DTC_UINT16:
1072 allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
1073 allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
1074 allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
1075 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
1076 break;
1077 case PTP_DTC_INT32:
1078 allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
1079 allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
1080 allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
1081 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1082 break;
1083 case PTP_DTC_UINT32:
1084 allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
1085 allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
1086 allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
1087 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1088 break;
1089 case PTP_DTC_INT64:
1090 allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
1091 allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
1092 allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
1093 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1094 break;
1095 case PTP_DTC_UINT64:
1096 allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
1097 allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
1098 allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
1099 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1100 break;
1101 }
1102 return 0;
1103 } else
1104 return -1;
1105 }
1106
1107 /**
1108 * Destroys a LIBMTP_allowed_values_t struct
1109 * @param allowed_vals the struct to destroy
1110 */
LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t * allowed_vals)1111 void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
1112 {
1113 if (!allowed_vals->is_range)
1114 {
1115 switch (allowed_vals->datatype)
1116 {
1117 case LIBMTP_DATATYPE_INT8:
1118 if (allowed_vals->i8vals)
1119 free(allowed_vals->i8vals);
1120 break;
1121 case LIBMTP_DATATYPE_UINT8:
1122 if (allowed_vals->u8vals)
1123 free(allowed_vals->u8vals);
1124 break;
1125 case LIBMTP_DATATYPE_INT16:
1126 if (allowed_vals->i16vals)
1127 free(allowed_vals->i16vals);
1128 break;
1129 case LIBMTP_DATATYPE_UINT16:
1130 if (allowed_vals->u16vals)
1131 free(allowed_vals->u16vals);
1132 break;
1133 case LIBMTP_DATATYPE_INT32:
1134 if (allowed_vals->i32vals)
1135 free(allowed_vals->i32vals);
1136 break;
1137 case LIBMTP_DATATYPE_UINT32:
1138 if (allowed_vals->u32vals)
1139 free(allowed_vals->u32vals);
1140 break;
1141 case LIBMTP_DATATYPE_INT64:
1142 if (allowed_vals->i64vals)
1143 free(allowed_vals->i64vals);
1144 break;
1145 case LIBMTP_DATATYPE_UINT64:
1146 if (allowed_vals->u64vals)
1147 free(allowed_vals->u64vals);
1148 break;
1149 }
1150 }
1151 }
1152
1153 /**
1154 * Determine if a property is supported for a given file type
1155 * @param device a pointer to an MTP device
1156 * @param property the property to query
1157 * @param filetype the filetype of the object you want to set values for
1158 * @return 0 if not supported, positive if supported, negative on error
1159 */
LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype)1160 int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
1161 LIBMTP_filetype_t const filetype)
1162 {
1163 uint16_t *props = NULL;
1164 uint32_t propcnt = 0;
1165 uint16_t ret = 0;
1166 int i = 0;
1167 int supported = 0;
1168 uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
1169
1170 if (!ptp_operation_issupported(device->params, PTP_OC_MTP_GetObjectPropsSupported))
1171 return 0;
1172
1173 ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
1174 if (ret != PTP_RC_OK) {
1175 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
1176 return -1;
1177 }
1178
1179 for (i = 0; i < propcnt; i++) {
1180 if (props[i] == ptp_prop) {
1181 supported = 1;
1182 break;
1183 }
1184 }
1185
1186 free(props);
1187
1188 return supported;
1189 }
1190
1191 /**
1192 * Retrieves a string from an object
1193 *
1194 * @param device a pointer to an MTP device.
1195 * @param object_id Object reference
1196 * @param attribute_id MTP attribute ID
1197 * @return valid string or NULL on failure. The returned string
1198 * must bee <code>free()</code>:ed by the caller after
1199 * use.
1200 */
LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id)1201 char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1202 LIBMTP_property_t const attribute_id)
1203 {
1204 return get_string_from_object(device, object_id, attribute_id);
1205 }
1206
1207 /**
1208 * Retrieves an unsigned 64-bit integer from an object attribute
1209 *
1210 * @param device a pointer to an MTP device.
1211 * @param object_id Object reference
1212 * @param attribute_id MTP attribute ID
1213 * @param value_default Default value to return on failure
1214 * @return the value
1215 */
LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint64_t const value_default)1216 uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1217 LIBMTP_property_t const attribute_id, uint64_t const value_default)
1218 {
1219 return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1220 }
1221
1222 /**
1223 * Retrieves an unsigned 32-bit integer from an object attribute
1224 *
1225 * @param device a pointer to an MTP device.
1226 * @param object_id Object reference
1227 * @param attribute_id MTP attribute ID
1228 * @param value_default Default value to return on failure
1229 * @return the value
1230 */
LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value_default)1231 uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1232 LIBMTP_property_t const attribute_id, uint32_t const value_default)
1233 {
1234 return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1235 }
1236
1237 /**
1238 * Retrieves an unsigned 16-bit integer from an object attribute
1239 *
1240 * @param device a pointer to an MTP device.
1241 * @param object_id Object reference
1242 * @param attribute_id MTP attribute ID
1243 * @param value_default Default value to return on failure
1244 * @return a value
1245 */
LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value_default)1246 uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1247 LIBMTP_property_t const attribute_id, uint16_t const value_default)
1248 {
1249 return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1250 }
1251
1252 /**
1253 * Retrieves an unsigned 8-bit integer from an object attribute
1254 *
1255 * @param device a pointer to an MTP device.
1256 * @param object_id Object reference
1257 * @param attribute_id MTP attribute ID
1258 * @param value_default Default value to return on failure
1259 * @return a value
1260 */
LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value_default)1261 uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1262 LIBMTP_property_t const attribute_id, uint8_t const value_default)
1263 {
1264 return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1265 }
1266
1267 /**
1268 * Sets an object attribute from a string
1269 *
1270 * @param device a pointer to an MTP device.
1271 * @param object_id Object reference
1272 * @param attribute_id MTP attribute ID
1273 * @param string string value to set
1274 * @return 0 on success, any other value means failure
1275 */
LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,char const * const string)1276 int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1277 LIBMTP_property_t const attribute_id, char const * const string)
1278 {
1279 return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
1280 }
1281
1282
1283 /**
1284 * Sets an object attribute from an unsigned 32-bit integer
1285 *
1286 * @param device a pointer to an MTP device.
1287 * @param object_id Object reference
1288 * @param attribute_id MTP attribute ID
1289 * @param value 32-bit unsigned integer to set
1290 * @return 0 on success, any other value means failure
1291 */
LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value)1292 int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1293 LIBMTP_property_t const attribute_id, uint32_t const value)
1294 {
1295 return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1296 }
1297
1298 /**
1299 * Sets an object attribute from an unsigned 16-bit integer
1300 *
1301 * @param device a pointer to an MTP device.
1302 * @param object_id Object reference
1303 * @param attribute_id MTP attribute ID
1304 * @param value 16-bit unsigned integer to set
1305 * @return 0 on success, any other value means failure
1306 */
LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value)1307 int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1308 LIBMTP_property_t const attribute_id, uint16_t const value)
1309 {
1310 return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1311 }
1312
1313 /**
1314 * Sets an object attribute from an unsigned 8-bit integer
1315 *
1316 * @param device a pointer to an MTP device.
1317 * @param object_id Object reference
1318 * @param attribute_id MTP attribute ID
1319 * @param value 8-bit unsigned integer to set
1320 * @return 0 on success, any other value means failure
1321 */
LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value)1322 int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1323 LIBMTP_property_t const attribute_id, uint8_t const value)
1324 {
1325 return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1326 }
1327
1328 /**
1329 * Retrieves a string from an object
1330 *
1331 * @param device a pointer to an MTP device.
1332 * @param object_id Object reference
1333 * @param attribute_id PTP attribute ID
1334 * @return valid string or NULL on failure. The returned string
1335 * must bee <code>free()</code>:ed by the caller after
1336 * use.
1337 */
get_string_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id)1338 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1339 uint16_t const attribute_id)
1340 {
1341 PTPPropertyValue propval;
1342 char *retstring = NULL;
1343 PTPParams *params;
1344 uint16_t ret;
1345 MTPProperties *prop;
1346
1347 if (!device || !object_id)
1348 return NULL;
1349
1350 params = (PTPParams *) device->params;
1351
1352 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1353 if (prop) {
1354 if (prop->propval.str != NULL)
1355 return strdup(prop->propval.str);
1356 else
1357 return NULL;
1358 }
1359
1360 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1361 if (ret == PTP_RC_OK) {
1362 if (propval.str != NULL) {
1363 retstring = (char *) strdup(propval.str);
1364 free(propval.str);
1365 }
1366 } else {
1367 add_ptp_error_to_errorstack(device, ret, "get_string_from_object(): could not get object string.");
1368 }
1369
1370 return retstring;
1371 }
1372
1373 /**
1374 * Retrieves an unsigned 64-bit integer from an object attribute
1375 *
1376 * @param device a pointer to an MTP device.
1377 * @param object_id Object reference
1378 * @param attribute_id PTP attribute ID
1379 * @param value_default Default value to return on failure
1380 * @return the value
1381 */
get_u64_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint64_t const value_default)1382 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1383 uint16_t const attribute_id, uint64_t const value_default)
1384 {
1385 PTPPropertyValue propval;
1386 uint64_t retval = value_default;
1387 PTPParams *params;
1388 uint16_t ret;
1389 MTPProperties *prop;
1390
1391 if (!device)
1392 return value_default;
1393
1394 params = (PTPParams *) device->params;
1395
1396 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1397 if (prop)
1398 return prop->propval.u64;
1399
1400 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1401 attribute_id,
1402 &propval,
1403 PTP_DTC_UINT64);
1404 if (ret == PTP_RC_OK) {
1405 retval = propval.u64;
1406 } else {
1407 add_ptp_error_to_errorstack(device, ret, "get_u64_from_object(): could not get unsigned 64bit integer from object.");
1408 }
1409
1410 return retval;
1411 }
1412
1413 /**
1414 * Retrieves an unsigned 32-bit integer from an object attribute
1415 *
1416 * @param device a pointer to an MTP device.
1417 * @param object_id Object reference
1418 * @param attribute_id PTP attribute ID
1419 * @param value_default Default value to return on failure
1420 * @return the value
1421 */
get_u32_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value_default)1422 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1423 uint16_t const attribute_id, uint32_t const value_default)
1424 {
1425 PTPPropertyValue propval;
1426 uint32_t retval = value_default;
1427 PTPParams *params;
1428 uint16_t ret;
1429 MTPProperties *prop;
1430
1431 if (!device)
1432 return value_default;
1433
1434 params = (PTPParams *) device->params;
1435
1436 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1437 if (prop)
1438 return prop->propval.u32;
1439
1440 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1441 attribute_id,
1442 &propval,
1443 PTP_DTC_UINT32);
1444 if (ret == PTP_RC_OK) {
1445 retval = propval.u32;
1446 } else {
1447 add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
1448 }
1449 return retval;
1450 }
1451
1452 /**
1453 * Retrieves an unsigned 16-bit integer from an object attribute
1454 *
1455 * @param device a pointer to an MTP device.
1456 * @param object_id Object reference
1457 * @param attribute_id PTP attribute ID
1458 * @param value_default Default value to return on failure
1459 * @return a value
1460 */
get_u16_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value_default)1461 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1462 uint16_t const attribute_id, uint16_t const value_default)
1463 {
1464 PTPPropertyValue propval;
1465 uint16_t retval = value_default;
1466 PTPParams *params;
1467 uint16_t ret;
1468 MTPProperties *prop;
1469
1470 if (!device)
1471 return value_default;
1472
1473 params = (PTPParams *) device->params;
1474
1475 // This O(n) search should not be used so often, since code
1476 // using the cached properties don't usually call this function.
1477 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1478 if (prop)
1479 return prop->propval.u16;
1480
1481 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1482 attribute_id,
1483 &propval,
1484 PTP_DTC_UINT16);
1485 if (ret == PTP_RC_OK) {
1486 retval = propval.u16;
1487 } else {
1488 add_ptp_error_to_errorstack(device, ret, "get_u16_from_object(): could not get unsigned 16bit integer from object.");
1489 }
1490
1491 return retval;
1492 }
1493
1494 /**
1495 * Retrieves an unsigned 8-bit integer from an object attribute
1496 *
1497 * @param device a pointer to an MTP device.
1498 * @param object_id Object reference
1499 * @param attribute_id PTP attribute ID
1500 * @param value_default Default value to return on failure
1501 * @return a value
1502 */
get_u8_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value_default)1503 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1504 uint16_t const attribute_id, uint8_t const value_default)
1505 {
1506 PTPPropertyValue propval;
1507 uint8_t retval = value_default;
1508 PTPParams *params;
1509 uint16_t ret;
1510 MTPProperties *prop;
1511
1512 if (!device)
1513 return value_default;
1514
1515 params = (PTPParams *) device->params;
1516
1517 // This O(n) search should not be used so often, since code
1518 // using the cached properties don't usually call this function.
1519 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1520 if (prop)
1521 return prop->propval.u8;
1522
1523 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1524 attribute_id,
1525 &propval,
1526 PTP_DTC_UINT8);
1527 if (ret == PTP_RC_OK) {
1528 retval = propval.u8;
1529 } else {
1530 add_ptp_error_to_errorstack(device, ret, "get_u8_from_object(): could not get unsigned 8bit integer from object.");
1531 }
1532
1533 return retval;
1534 }
1535
1536 /**
1537 * Sets an object attribute from a string
1538 *
1539 * @param device a pointer to an MTP device.
1540 * @param object_id Object reference
1541 * @param attribute_id PTP attribute ID
1542 * @param string string value to set
1543 * @return 0 on success, any other value means failure
1544 */
set_object_string(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,char const * const string)1545 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1546 uint16_t const attribute_id, char const * const string)
1547 {
1548 PTPPropertyValue propval;
1549 PTPParams *params;
1550 uint16_t ret;
1551
1552 if (!device || !string)
1553 return -1;
1554
1555 params = (PTPParams *) device->params;
1556
1557 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1558 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_string(): could not set object string: "
1559 "PTP_OC_MTP_SetObjectPropValue not supported.");
1560 return -1;
1561 }
1562 propval.str = (char *) string;
1563 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1564 if (ret != PTP_RC_OK) {
1565 add_ptp_error_to_errorstack(device, ret, "set_object_string(): could not set object string.");
1566 return -1;
1567 }
1568
1569 return 0;
1570 }
1571
1572
1573 /**
1574 * Sets an object attribute from an unsigned 32-bit integer
1575 *
1576 * @param device a pointer to an MTP device.
1577 * @param object_id Object reference
1578 * @param attribute_id PTP attribute ID
1579 * @param value 32-bit unsigned integer to set
1580 * @return 0 on success, any other value means failure
1581 */
set_object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value)1582 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1583 uint16_t const attribute_id, uint32_t const value)
1584 {
1585 PTPPropertyValue propval;
1586 PTPParams *params;
1587 uint16_t ret;
1588
1589 if (!device)
1590 return -1;
1591
1592 params = (PTPParams *) device->params;
1593
1594 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1595 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u32(): could not set unsigned 32bit integer property: "
1596 "PTP_OC_MTP_SetObjectPropValue not supported.");
1597 return -1;
1598 }
1599
1600 propval.u32 = value;
1601 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
1602 if (ret != PTP_RC_OK) {
1603 add_ptp_error_to_errorstack(device, ret, "set_object_u32(): could not set unsigned 32bit integer property.");
1604 return -1;
1605 }
1606
1607 return 0;
1608 }
1609
1610 /**
1611 * Sets an object attribute from an unsigned 16-bit integer
1612 *
1613 * @param device a pointer to an MTP device.
1614 * @param object_id Object reference
1615 * @param attribute_id PTP attribute ID
1616 * @param value 16-bit unsigned integer to set
1617 * @return 0 on success, any other value means failure
1618 */
set_object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value)1619 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1620 uint16_t const attribute_id, uint16_t const value)
1621 {
1622 PTPPropertyValue propval;
1623 PTPParams *params;
1624 uint16_t ret;
1625
1626 if (!device)
1627 return 1;
1628
1629 params = (PTPParams *) device->params;
1630
1631 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1632 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u16(): could not set unsigned 16bit integer property: "
1633 "PTP_OC_MTP_SetObjectPropValue not supported.");
1634 return -1;
1635 }
1636 propval.u16 = value;
1637 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
1638 if (ret != PTP_RC_OK) {
1639 add_ptp_error_to_errorstack(device, ret, "set_object_u16(): could not set unsigned 16bit integer property.");
1640 return 1;
1641 }
1642
1643 return 0;
1644 }
1645
1646 /**
1647 * Sets an object attribute from an unsigned 8-bit integer
1648 *
1649 * @param device a pointer to an MTP device.
1650 * @param object_id Object reference
1651 * @param attribute_id PTP attribute ID
1652 * @param value 8-bit unsigned integer to set
1653 * @return 0 on success, any other value means failure
1654 */
set_object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value)1655 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1656 uint16_t const attribute_id, uint8_t const value)
1657 {
1658 PTPPropertyValue propval;
1659 PTPParams *params;
1660 uint16_t ret;
1661
1662 if (!device)
1663 return 1;
1664
1665 params = (PTPParams *) device->params;
1666
1667 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1668 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u8(): could not set unsigned 8bit integer property: "
1669 "PTP_OC_MTP_SetObjectPropValue not supported.");
1670 return -1;
1671 }
1672 propval.u8 = value;
1673 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
1674 if (ret != PTP_RC_OK) {
1675 add_ptp_error_to_errorstack(device, ret, "set_object_u8(): could not set unsigned 8bit integer property.");
1676 return 1;
1677 }
1678
1679 return 0;
1680 }
1681
1682 /**
1683 * Get the first (as in "first in the list of") connected MTP device.
1684 * @return a device pointer.
1685 * @see LIBMTP_Get_Connected_Devices()
1686 */
LIBMTP_Get_First_Device(void)1687 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1688 {
1689 LIBMTP_mtpdevice_t *first_device = NULL;
1690 LIBMTP_raw_device_t *devices;
1691 int numdevs;
1692 LIBMTP_error_number_t ret;
1693
1694 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1695 if (ret != LIBMTP_ERROR_NONE) {
1696 return NULL;
1697 }
1698
1699 if (devices == NULL || numdevs == 0) {
1700 free(devices);
1701 return NULL;
1702 }
1703
1704 first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1705 free(devices);
1706 return first_device;
1707 }
1708
1709 /**
1710 * Overriding debug function.
1711 * This way we can disable debug prints.
1712 */
1713 static void
1714 #ifdef __GNUC__
1715 __attribute__((__format__(printf,2,0)))
1716 #endif
LIBMTP_ptp_debug(void * data,const char * format,va_list args)1717 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1718 {
1719 if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1720 vfprintf (stderr, format, args);
1721 fprintf (stderr, "\n");
1722 fflush (stderr);
1723 }
1724 }
1725
1726 /**
1727 * Overriding error function.
1728 * This way we can capture all error etc to our errorstack.
1729 */
1730 static void
1731 #ifdef __GNUC__
1732 __attribute__((__format__(printf,2,0)))
1733 #endif
LIBMTP_ptp_error(void * data,const char * format,va_list args)1734 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1735 {
1736 // if (data == NULL) {
1737 vfprintf (stderr, format, args);
1738 fflush (stderr);
1739 /*
1740 FIXME: find out how we shall get the device here.
1741 } else {
1742 PTP_USB *ptp_usb = data;
1743 LIBMTP_mtpdevice_t *device = ...;
1744 char buf[2048];
1745
1746 vsnprintf (buf, sizeof (buf), format, args);
1747 add_error_to_errorstack(device,
1748 LIBMTP_ERROR_PTP_LAYER,
1749 buf);
1750 }
1751 */
1752 }
1753
1754 /**
1755 * Parses the extension descriptor, there may be stuff in
1756 * this that we want to know about.
1757 */
parse_extension_descriptor(LIBMTP_mtpdevice_t * mtpdevice,char * desc)1758 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1759 char *desc)
1760 {
1761 int start = 0;
1762 int end = 0;
1763
1764 /* NULL on Canon A70 */
1765 if (!desc)
1766 return;
1767
1768 /* descriptors are divided by semicolons */
1769 while (end < strlen(desc)) {
1770 /* Skip past initial whitespace */
1771 while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1772 start++;
1773 end++;
1774 }
1775 /* Detect extension */
1776 while ((end < strlen(desc)) && (desc[end] != ';'))
1777 end++;
1778 if (end < strlen(desc)) {
1779 char *element = strndup(desc + start, end-start);
1780 if (element) {
1781 int i = 0;
1782 // printf(" Element: \"%s\"\n", element);
1783
1784 /* Parse for an extension */
1785 while ((i < strlen(element)) && (element[i] != ':'))
1786 i++;
1787 if (i < strlen(element)) {
1788 char *name = strndup(element, i);
1789 int major = 0, minor = 0;
1790
1791 /* extension versions have to be MAJOR.MINOR, but Samsung has one
1792 * with just 0, so just cope with those cases too */
1793 if ( (2 == sscanf(element+i+1,"%d.%d",&major,&minor)) ||
1794 (1 == sscanf(element+i+1,"%d",&major))
1795 ) {
1796 LIBMTP_device_extension_t *extension;
1797
1798 extension = malloc(sizeof(LIBMTP_device_extension_t));
1799 extension->name = name;
1800 extension->major = major;
1801 extension->minor = minor;
1802 extension->next = NULL;
1803 if (mtpdevice->extensions == NULL) {
1804 mtpdevice->extensions = extension;
1805 } else {
1806 LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1807 while (tmp->next != NULL)
1808 tmp = tmp->next;
1809 tmp->next = extension;
1810 }
1811 } else {
1812 LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1813 element);
1814 }
1815 }
1816 free(element);
1817 }
1818 }
1819 end++;
1820 start = end;
1821 }
1822 }
1823
1824 /**
1825 * This function opens a device from a raw device. It is the
1826 * preferred way to access devices in the new interface where
1827 * several devices can come and go as the library is working
1828 * on a certain device.
1829 * @param rawdevice the raw device to open a "real" device for.
1830 * @return an open device.
1831 */
LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t * rawdevice)1832 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1833 {
1834 LIBMTP_mtpdevice_t *mtp_device;
1835 uint8_t bs = 0;
1836 PTPParams *current_params;
1837 PTP_USB *ptp_usb;
1838 LIBMTP_error_number_t err;
1839 int i;
1840
1841 /* Allocate dynamic space for our device */
1842 mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1843 /* Check if there was a memory allocation error */
1844 if(mtp_device == NULL) {
1845 /* There has been an memory allocation error. We are going to ignore this
1846 device and attempt to continue */
1847
1848 /* TODO: This error statement could probably be a bit more robust */
1849 LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1850 "allocation error with device %d on bus %d, trying to continue",
1851 rawdevice->devnum, rawdevice->bus_location);
1852
1853 return NULL;
1854 }
1855 memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1856 // Non-cached by default
1857 mtp_device->cached = 0;
1858
1859 /* Create PTP params */
1860 current_params = (PTPParams *) malloc(sizeof(PTPParams));
1861 if (current_params == NULL) {
1862 free(mtp_device);
1863 return NULL;
1864 }
1865 memset(current_params, 0, sizeof(PTPParams));
1866 current_params->device_flags = rawdevice->device_entry.device_flags;
1867 current_params->nrofobjects = 0;
1868 current_params->cachetime = 2;
1869 current_params->objects = NULL;
1870 current_params->response_packet_size = 0;
1871 current_params->response_packet = NULL;
1872 /* This will be a pointer to PTP_USB later */
1873 current_params->data = NULL;
1874 /* Set upp local debug and error functions */
1875 current_params->debug_func = LIBMTP_ptp_debug;
1876 current_params->error_func = LIBMTP_ptp_error;
1877 /* TODO: Will this always be little endian? */
1878 current_params->byteorder = PTP_DL_LE;
1879 current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1880 current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1881
1882 if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1883 current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1884 LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1885 "Too old stdlibc, glibc and libiconv?\n");
1886 free(current_params);
1887 free(mtp_device);
1888 return NULL;
1889 }
1890 mtp_device->params = current_params;
1891
1892 /* Create usbinfo, this also opens the session */
1893 err = configure_usb_device(rawdevice,
1894 current_params,
1895 &mtp_device->usbinfo);
1896 if (err != LIBMTP_ERROR_NONE) {
1897 free(current_params);
1898 free(mtp_device);
1899 return NULL;
1900 }
1901 ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1902 /* Set pointer back to params */
1903 ptp_usb->params = current_params;
1904
1905 /* Cache the device information for later use */
1906 if (ptp_getdeviceinfo(current_params,
1907 ¤t_params->deviceinfo) != PTP_RC_OK) {
1908 LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1909 "%d on bus %d, trying to continue",
1910 rawdevice->devnum, rawdevice->bus_location);
1911
1912 /* Prevent memory leaks for this device */
1913 free(mtp_device->usbinfo);
1914 free(mtp_device->params);
1915 current_params = NULL;
1916 free(mtp_device);
1917 return NULL;
1918 }
1919
1920 /* Check: if this is a PTP device, is it really tagged as MTP? */
1921 if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1922 LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1923 "%d on bus %d",
1924 rawdevice->devnum, rawdevice->bus_location);
1925 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1926 current_params->deviceinfo.VendorExtensionID);
1927 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1928 current_params->deviceinfo.VendorExtensionDesc);
1929 LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1930 "(i.e. a camera) but not an MTP device at all. "
1931 "Trying to continue anyway.");
1932 }
1933
1934 parse_extension_descriptor(mtp_device,
1935 current_params->deviceinfo.VendorExtensionDesc);
1936
1937 /*
1938 * Android has a number of bugs, force-assign these bug flags
1939 * if Android is encountered. Same thing for devices we detect
1940 * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1941 * I just know only NWZs have it.
1942 */
1943 {
1944 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1945 int is_microsoft_com_wpdna = 0;
1946 int is_android = 0;
1947 int is_sony_net_wmfu = 0;
1948 int is_sonyericsson_com_se = 0;
1949
1950 /* Loop over extensions and set flags */
1951 while (tmpext != NULL) {
1952 if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1953 is_microsoft_com_wpdna = 1;
1954 if (!strcmp(tmpext->name, "android.com"))
1955 is_android = 1;
1956 if (!strcmp(tmpext->name, "sony.net/WMFU"))
1957 is_sony_net_wmfu = 1;
1958 if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1959 is_sonyericsson_com_se = 1;
1960 tmpext = tmpext->next;
1961 }
1962
1963 /* Check for specific stacks */
1964 if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1965 /*
1966 * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1967 * extension and NO Android extension.
1968 */
1969 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1970 LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1971 }
1972 else if (is_android) {
1973 /*
1974 * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1975 */
1976 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1977 LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1978 }
1979 else if (is_sony_net_wmfu) {
1980 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1981 LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
1982 }
1983 }
1984
1985 /*
1986 * If the OGG or FLAC filetypes are flagged as "unknown", check
1987 * if the firmware has been updated to actually support it.
1988 */
1989 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
1990 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1991 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_OGG) {
1992 /* This is not unknown anymore, unflag it */
1993 ptp_usb->rawdevice.device_entry.device_flags &=
1994 ~DEVICE_FLAG_OGG_IS_UNKNOWN;
1995 break;
1996 }
1997 }
1998 }
1999 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
2000 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2001 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
2002 /* This is not unknown anymore, unflag it */
2003 ptp_usb->rawdevice.device_entry.device_flags &=
2004 ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2005 break;
2006 }
2007 }
2008 }
2009
2010 /* Determine if the object size supported is 32 or 64 bit wide */
2011 if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2012 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2013 PTPObjectPropDesc opd;
2014
2015 if (ptp_mtp_getobjectpropdesc(current_params,
2016 PTP_OPC_ObjectSize,
2017 current_params->deviceinfo.ImageFormats[i],
2018 &opd) != PTP_RC_OK) {
2019 LIBMTP_ERROR("LIBMTP PANIC: "
2020 "could not inspect object property descriptions!\n");
2021 } else {
2022 if (opd.DataType == PTP_DTC_UINT32) {
2023 if (bs == 0) {
2024 bs = 32;
2025 } else if (bs != 32) {
2026 LIBMTP_ERROR("LIBMTP PANIC: "
2027 "different objects support different object sizes!\n");
2028 bs = 0;
2029 break;
2030 }
2031 } else if (opd.DataType == PTP_DTC_UINT64) {
2032 if (bs == 0) {
2033 bs = 64;
2034 } else if (bs != 64) {
2035 LIBMTP_ERROR("LIBMTP PANIC: "
2036 "different objects support different object sizes!\n");
2037 bs = 0;
2038 break;
2039 }
2040 } else {
2041 // Ignore if other size.
2042 LIBMTP_ERROR("LIBMTP PANIC: "
2043 "awkward object size data type: %04x\n", opd.DataType);
2044 bs = 0;
2045 break;
2046 }
2047 }
2048 }
2049 }
2050 if (bs == 0) {
2051 // Could not detect object bitsize, assume 32 bits
2052 bs = 32;
2053 }
2054 mtp_device->object_bitsize = bs;
2055
2056 /* No Errors yet for this device */
2057 mtp_device->errorstack = NULL;
2058
2059 /* Default Max Battery Level, we will adjust this if possible */
2060 mtp_device->maximum_battery_level = 100;
2061
2062 /* Check if device supports reading maximum battery level */
2063 if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2064 ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2065 PTPDevicePropDesc dpd;
2066
2067 /* Try to read maximum battery level */
2068 if(ptp_getdevicepropdesc(current_params,
2069 PTP_DPC_BatteryLevel,
2070 &dpd) != PTP_RC_OK) {
2071 add_error_to_errorstack(mtp_device,
2072 LIBMTP_ERROR_CONNECTING,
2073 "Unable to read Maximum Battery Level for this "
2074 "device even though the device supposedly "
2075 "supports this functionality");
2076 }
2077
2078 /* TODO: is this appropriate? */
2079 /* If max battery level is 0 then leave the default, otherwise assign */
2080 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2081 mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2082 }
2083
2084 ptp_free_devicepropdesc(&dpd);
2085 }
2086
2087 /* Set all default folders to 0xffffffffU (root directory) */
2088 mtp_device->default_music_folder = 0xffffffffU;
2089 mtp_device->default_playlist_folder = 0xffffffffU;
2090 mtp_device->default_picture_folder = 0xffffffffU;
2091 mtp_device->default_video_folder = 0xffffffffU;
2092 mtp_device->default_organizer_folder = 0xffffffffU;
2093 mtp_device->default_zencast_folder = 0xffffffffU;
2094 mtp_device->default_album_folder = 0xffffffffU;
2095 mtp_device->default_text_folder = 0xffffffffU;
2096
2097 /* Set initial storage information */
2098 mtp_device->storage = NULL;
2099 if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2100 add_error_to_errorstack(mtp_device,
2101 LIBMTP_ERROR_GENERAL,
2102 "Get Storage information failed.");
2103 mtp_device->storage = NULL;
2104 }
2105
2106
2107 return mtp_device;
2108 }
2109
LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t * rawdevice)2110 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2111 {
2112 LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2113
2114 if (mtp_device == NULL)
2115 return NULL;
2116
2117 /* Check for MTPZ devices. */
2118 if (use_mtpz) {
2119 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2120
2121 while (tmpext != NULL) {
2122 if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2123 LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2124 if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2125 LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2126 } else {
2127 LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2128 }
2129 break;
2130 }
2131 tmpext = tmpext->next;
2132 }
2133 }
2134
2135 // Set up this device as cached
2136 mtp_device->cached = 1;
2137 /*
2138 * Then get the handles and try to locate the default folders.
2139 * This has the desired side effect of caching all handles from
2140 * the device which speeds up later operations.
2141 */
2142 flush_handles(mtp_device);
2143 return mtp_device;
2144 }
2145
2146 /**
2147 * To read events sent by the device, repeatedly call this function from a secondary
2148 * thread until the return value is < 0.
2149 *
2150 * @param device a pointer to the MTP device to poll for events.
2151 * @param event contains a pointer to be filled in with the event retrieved if the call
2152 * is successful.
2153 * @param out1 contains the param1 value from the raw event.
2154 * @return 0 on success, any other value means the polling loop shall be
2155 * terminated immediately for this session.
2156 */
LIBMTP_Read_Event(LIBMTP_mtpdevice_t * device,LIBMTP_event_t * event,uint32_t * out1)2157 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2158 {
2159 /*
2160 * FIXME: Potential race-condition here, if client deallocs device
2161 * while we're *not* waiting for input. As we'll be waiting for
2162 * input most of the time, it's unlikely but still worth considering
2163 * for improvement. Also we cannot affect the state of the cache etc
2164 * unless we know we are the sole user on the device. A spinlock or
2165 * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2166 */
2167 PTPParams *params = (PTPParams *) device->params;
2168 PTPContainer ptp_event;
2169 uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2170
2171 if (ret != PTP_RC_OK) {
2172 /* Device is closing down or other fatal stuff, exit thread */
2173 return -1;
2174 }
2175 LIBMTP_Handle_Event(&ptp_event, event, out1);
2176 return 0;
2177 }
2178
LIBMTP_Handle_Event(PTPContainer * ptp_event,LIBMTP_event_t * event,uint32_t * out1)2179 void LIBMTP_Handle_Event(PTPContainer *ptp_event,
2180 LIBMTP_event_t *event, uint32_t *out1) {
2181 uint16_t code;
2182 uint32_t session_id;
2183 uint32_t param1;
2184
2185 *event = LIBMTP_EVENT_NONE;
2186
2187 /* Process the event */
2188 code = ptp_event->Code;
2189 session_id = ptp_event->SessionID;
2190 param1 = ptp_event->Param1;
2191
2192 switch(code) {
2193 case PTP_EC_Undefined:
2194 LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2195 break;
2196 case PTP_EC_CancelTransaction:
2197 LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2198 break;
2199 case PTP_EC_ObjectAdded:
2200 LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2201 *event = LIBMTP_EVENT_OBJECT_ADDED;
2202 *out1 = param1;
2203 break;
2204 case PTP_EC_ObjectRemoved:
2205 LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2206 *event = LIBMTP_EVENT_OBJECT_REMOVED;
2207 *out1 = param1;
2208 break;
2209 case PTP_EC_StoreAdded:
2210 LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2211 /* TODO: rescan storages */
2212 *event = LIBMTP_EVENT_STORE_ADDED;
2213 *out1 = param1;
2214 break;
2215 case PTP_EC_StoreRemoved:
2216 LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2217 /* TODO: rescan storages */
2218 *event = LIBMTP_EVENT_STORE_REMOVED;
2219 *out1 = param1;
2220 break;
2221 case PTP_EC_DevicePropChanged:
2222 LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2223 /* TODO: update device properties */
2224 break;
2225 case PTP_EC_ObjectInfoChanged:
2226 LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2227 /* TODO: rescan object cache or just for this one object */
2228 break;
2229 case PTP_EC_DeviceInfoChanged:
2230 LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2231 /* TODO: update device info */
2232 break;
2233 case PTP_EC_RequestObjectTransfer:
2234 LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2235 break;
2236 case PTP_EC_StoreFull:
2237 LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2238 break;
2239 case PTP_EC_DeviceReset:
2240 LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2241 break;
2242 case PTP_EC_StorageInfoChanged :
2243 LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2244 /* TODO: update storage info */
2245 break;
2246 case PTP_EC_CaptureComplete :
2247 LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2248 break;
2249 case PTP_EC_UnreportedStatus :
2250 LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2251 break;
2252 default :
2253 LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2254 break;
2255 }
2256 }
2257
LIBMTP_Read_Event_Cb(PTPParams * params,uint16_t ret_code,PTPContainer * ptp_event,void * user_data)2258 static void LIBMTP_Read_Event_Cb(PTPParams *params, uint16_t ret_code,
2259 PTPContainer *ptp_event, void *user_data) {
2260 event_cb_data_t *data = user_data;
2261 LIBMTP_event_t event = LIBMTP_EVENT_NONE;
2262 uint32_t param1 = 0;
2263 int handler_ret;
2264
2265 switch (ret_code) {
2266 case PTP_RC_OK:
2267 handler_ret = LIBMTP_HANDLER_RETURN_OK;
2268 LIBMTP_Handle_Event(ptp_event, &event, ¶m1);
2269 break;
2270 case PTP_ERROR_CANCEL:
2271 handler_ret = LIBMTP_HANDLER_RETURN_CANCEL;
2272 break;
2273 default:
2274 handler_ret = LIBMTP_HANDLER_RETURN_ERROR;
2275 break;
2276 }
2277
2278 data->cb(handler_ret, event, param1, data->user_data);
2279 free(data);
2280 }
2281
2282 /**
2283 * This function reads events sent by the device, in a non-blocking manner.
2284 * The callback function will be called when an event is received, but for the function
2285 * to make progress, polling must take place, using LIBMTP_Handle_Events_Timeout_Completed.
2286 *
2287 * After an event is received, this function should be called again to listen for the next
2288 * event.
2289 *
2290 * For now, this non-blocking mechanism only works with libusb-1.0, and not any of the
2291 * other usb library backends. Attempting to call this method with another backend will
2292 * always return an error.
2293 *
2294 * @param device a pointer to the MTP device to poll for events.
2295 * @param cb a callback to be invoked when an event is received.
2296 * @param user_data arbitrary user data passed to the callback.
2297 * @return 0 on success, any other value means that the callback was not registered and
2298 * no event notification will take place.
2299 */
LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t * device,LIBMTP_event_cb_fn cb,void * user_data)2300 int LIBMTP_Read_Event_Async(LIBMTP_mtpdevice_t *device, LIBMTP_event_cb_fn cb, void *user_data) {
2301 PTPParams *params = (PTPParams *) device->params;
2302 event_cb_data_t *data = malloc(sizeof(event_cb_data_t));
2303 uint16_t ret;
2304
2305 data->cb = cb;
2306 data->user_data = user_data;
2307
2308 ret = ptp_usb_event_async(params, LIBMTP_Read_Event_Cb, data);
2309 return ret == PTP_RC_OK ? 0 : -1;
2310 }
2311
2312 /**
2313 * Recursive function that adds MTP devices to a linked list
2314 * @param devices a list of raw devices to have real devices created for.
2315 * @return a device pointer to a newly created mtpdevice (used in linked
2316 * list creation).
2317 */
create_usb_mtp_devices(LIBMTP_raw_device_t * devices,int numdevs)2318 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2319 {
2320 uint8_t i;
2321 LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2322 LIBMTP_mtpdevice_t *current_device = NULL;
2323
2324 for (i=0; i < numdevs; i++) {
2325 LIBMTP_mtpdevice_t *mtp_device;
2326 mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2327
2328 /* On error, try next device */
2329 if (mtp_device == NULL)
2330 continue;
2331
2332 /* Add the device to the list */
2333 mtp_device->next = NULL;
2334 if (mtp_device_list == NULL) {
2335 mtp_device_list = current_device = mtp_device;
2336 } else {
2337 current_device->next = mtp_device;
2338 current_device = mtp_device;
2339 }
2340 }
2341 return mtp_device_list;
2342 }
2343
2344 /**
2345 * Get the number of devices that are available in the listed device list
2346 * @param device_list Pointer to a linked list of devices
2347 * @return Number of devices in the device list device_list
2348 * @see LIBMTP_Get_Connected_Devices()
2349 */
LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t * device_list)2350 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2351 {
2352 uint32_t numdevices = 0;
2353 LIBMTP_mtpdevice_t *iter;
2354 for(iter = device_list; iter != NULL; iter = iter->next)
2355 numdevices++;
2356
2357 return numdevices;
2358 }
2359
2360 /**
2361 * Get the first connected MTP device node in the linked list of devices.
2362 * Currently this only provides access to USB devices
2363 * @param device_list A list of devices ready to be used by the caller. You
2364 * need to know how many there are.
2365 * @return Any error information gathered from device connections
2366 * @see LIBMTP_Number_Devices_In_List()
2367 */
LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t ** device_list)2368 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2369 {
2370 LIBMTP_raw_device_t *devices;
2371 int numdevs;
2372 LIBMTP_error_number_t ret;
2373
2374 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2375 if (ret != LIBMTP_ERROR_NONE) {
2376 *device_list = NULL;
2377 return ret;
2378 }
2379
2380 /* Assign linked list of devices */
2381 if (devices == NULL || numdevs == 0) {
2382 *device_list = NULL;
2383 free(devices);
2384 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2385 }
2386
2387 *device_list = create_usb_mtp_devices(devices, numdevs);
2388 free(devices);
2389
2390 /* TODO: Add wifi device access here */
2391
2392 /* We have found some devices but create failed */
2393 if (*device_list == NULL)
2394 return LIBMTP_ERROR_CONNECTING;
2395
2396 return LIBMTP_ERROR_NONE;
2397 }
2398
2399 /**
2400 * This closes and releases an allocated MTP device.
2401 * @param device a pointer to the MTP device to release.
2402 */
LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t * device)2403 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2404 {
2405 if(device != NULL)
2406 {
2407 if(device->next != NULL)
2408 {
2409 LIBMTP_Release_Device_List(device->next);
2410 }
2411
2412 LIBMTP_Release_Device(device);
2413 }
2414 }
2415
2416 /**
2417 * This closes and releases an allocated MTP device.
2418 * @param device a pointer to the MTP device to release.
2419 */
LIBMTP_Release_Device(LIBMTP_mtpdevice_t * device)2420 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2421 {
2422 PTPParams *params = (PTPParams *) device->params;
2423 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2424
2425 close_device(ptp_usb, params);
2426 // Clear error stack
2427 LIBMTP_Clear_Errorstack(device);
2428 // Free iconv() converters...
2429 iconv_close(params->cd_locale_to_ucs2);
2430 iconv_close(params->cd_ucs2_to_locale);
2431 free(ptp_usb);
2432 ptp_free_params(params);
2433 free(params);
2434 free_storage_list(device);
2435 // Free extension list...
2436 if (device->extensions != NULL) {
2437 LIBMTP_device_extension_t *tmp = device->extensions;
2438
2439 while (tmp != NULL) {
2440 LIBMTP_device_extension_t *next = tmp->next;
2441
2442 if (tmp->name)
2443 free(tmp->name);
2444 free(tmp);
2445 tmp = next;
2446 }
2447 }
2448 free(device);
2449 }
2450
2451 /**
2452 * This can be used by any libmtp-intrinsic code that
2453 * need to stack up an error on the stack. You are only
2454 * supposed to add errors to the error stack using this
2455 * function, do not create and reference error entries
2456 * directly.
2457 */
add_error_to_errorstack(LIBMTP_mtpdevice_t * device,LIBMTP_error_number_t errornumber,char const * const error_text)2458 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2459 LIBMTP_error_number_t errornumber,
2460 char const * const error_text)
2461 {
2462 LIBMTP_error_t *newerror;
2463
2464 if (device == NULL) {
2465 LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2466 return;
2467 }
2468 newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2469 newerror->errornumber = errornumber;
2470 newerror->error_text = strdup(error_text);
2471 newerror->next = NULL;
2472 if (device->errorstack == NULL) {
2473 device->errorstack = newerror;
2474 } else {
2475 LIBMTP_error_t *tmp = device->errorstack;
2476
2477 while (tmp->next != NULL) {
2478 tmp = tmp->next;
2479 }
2480 tmp->next = newerror;
2481 }
2482 }
2483
2484 /**
2485 * Adds an error from the PTP layer to the error stack.
2486 */
add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t * device,uint16_t ptp_error,char const * const error_text)2487 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2488 uint16_t ptp_error,
2489 char const * const error_text)
2490 {
2491 PTPParams *params = (PTPParams *) device->params;
2492
2493 if (device == NULL) {
2494 LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2495 return;
2496 } else {
2497 char outstr[256];
2498 snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2499 outstr[sizeof(outstr)-1] = '\0';
2500 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2501
2502 snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error, params->deviceinfo.VendorExtensionID));
2503 outstr[sizeof(outstr)-1] = '\0';
2504 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2505 }
2506 }
2507
2508 /**
2509 * This returns the error stack for a device in case you
2510 * need to either reference the error numbers (e.g. when
2511 * creating multilingual apps with multiple-language text
2512 * representations for each error number) or when you need
2513 * to build a multi-line error text widget or something like
2514 * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2515 * to clear it when you're finished with it.
2516 * @param device a pointer to the MTP device to get the error
2517 * stack for.
2518 * @return the error stack or NULL if there are no errors
2519 * on the stack.
2520 * @see LIBMTP_Clear_Errorstack()
2521 * @see LIBMTP_Dump_Errorstack()
2522 */
LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t * device)2523 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2524 {
2525 if (device == NULL) {
2526 LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2527 return NULL;
2528 }
2529 return device->errorstack;
2530 }
2531
2532 /**
2533 * This function clears the error stack of a device and frees
2534 * any memory used by it. Call this when you're finished with
2535 * using the errors.
2536 * @param device a pointer to the MTP device to clear the error
2537 * stack for.
2538 */
LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t * device)2539 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2540 {
2541 if (device == NULL) {
2542 LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2543 } else {
2544 LIBMTP_error_t *tmp = device->errorstack;
2545
2546 while (tmp != NULL) {
2547 LIBMTP_error_t *tmp2;
2548
2549 if (tmp->error_text != NULL) {
2550 free(tmp->error_text);
2551 }
2552 tmp2 = tmp;
2553 tmp = tmp->next;
2554 free(tmp2);
2555 }
2556 device->errorstack = NULL;
2557 }
2558 }
2559
2560 /**
2561 * This function dumps the error stack to <code>stderr</code>.
2562 * (You still have to clear the stack though.)
2563 * @param device a pointer to the MTP device to dump the error
2564 * stack for.
2565 */
LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t * device)2566 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2567 {
2568 if (device == NULL) {
2569 LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2570 } else {
2571 LIBMTP_error_t *tmp = device->errorstack;
2572
2573 while (tmp != NULL) {
2574 if (tmp->error_text != NULL) {
2575 LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2576 } else {
2577 LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2578 }
2579 tmp = tmp->next;
2580 }
2581 }
2582 }
2583
LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t * device,int milliseconds)2584 void LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t *device, int milliseconds)
2585 {
2586 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2587 set_usb_device_timeout(ptp_usb, milliseconds);
2588 }
2589
LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t * device,int * milliseconds)2590 void LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t *device, int *milliseconds)
2591 {
2592 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2593 get_usb_device_timeout(ptp_usb, milliseconds);
2594 }
2595
2596 /**
2597 * This command gets all handles and stuff by FAST directory retrieveal
2598 * which is available by getting all metadata for object
2599 * <code>0xffffffff</code> which simply means "all metadata for all objects".
2600 * This works on the vast majority of MTP devices (there ARE exceptions!)
2601 * and is quite quick. Check the error stack to see if there were
2602 * problems getting the metadata.
2603 * @return 0 if all was OK, -1 on failure.
2604 */
get_all_metadata_fast(LIBMTP_mtpdevice_t * device)2605 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2606 {
2607 PTPParams *params = (PTPParams *) device->params;
2608 int cnt = 0;
2609 int i, j, nrofprops;
2610 uint32_t lasthandle = 0xffffffff;
2611 MTPProperties *props = NULL;
2612 MTPProperties *prop;
2613 uint16_t ret;
2614 int oldtimeout;
2615 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2616
2617 /*
2618 * The follow request causes the device to generate
2619 * a list of every file on the device and return it
2620 * in a single response.
2621 *
2622 * Some slow devices as well as devices with very
2623 * large file systems can easily take longer then
2624 * the standard timeout value before it is able
2625 * to return a response.
2626 *
2627 * Temporarly set timeout to allow working with
2628 * widest range of devices.
2629 */
2630 get_usb_device_timeout(ptp_usb, &oldtimeout);
2631 set_usb_device_timeout(ptp_usb, 60000);
2632
2633 ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2634 set_usb_device_timeout(ptp_usb, oldtimeout);
2635
2636 if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2637 // What's the point in the device implementing this command if
2638 // you cannot use it to get all props for AT LEAST one object?
2639 // Well, whatever...
2640 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2641 "cannot retrieve all metadata for an object on this device.");
2642 return -1;
2643 }
2644 if (ret != PTP_RC_OK) {
2645 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2646 "could not get proplist of all objects.");
2647 return -1;
2648 }
2649 if (props == NULL && nrofprops != 0) {
2650 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2651 "get_all_metadata_fast(): "
2652 "call to ptp_mtp_getobjectproplist() returned "
2653 "inconsistent results.");
2654 return -1;
2655 }
2656 /*
2657 * We count the number of objects by counting the ObjectHandle
2658 * references, whenever it changes we get a new object, when it's
2659 * the same, it is just different properties of the same object.
2660 */
2661 prop = props;
2662 for (i=0;i<nrofprops;i++) {
2663 if (lasthandle != prop->ObjectHandle) {
2664 cnt++;
2665 lasthandle = prop->ObjectHandle;
2666 }
2667 prop++;
2668 }
2669 lasthandle = 0xffffffff;
2670 params->objects = calloc (cnt, sizeof(PTPObject));
2671 prop = props;
2672 i = -1;
2673 for (j=0;j<nrofprops;j++) {
2674 if (lasthandle != prop->ObjectHandle) {
2675 if (i >= 0) {
2676 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2677 if (!params->objects[i].oi.Filename) {
2678 /* I have one such file on my Creative (Marcus) */
2679 params->objects[i].oi.Filename = strdup("<null>");
2680 }
2681 }
2682 i++;
2683 lasthandle = prop->ObjectHandle;
2684 params->objects[i].oid = prop->ObjectHandle;
2685 }
2686 switch (prop->property) {
2687 case PTP_OPC_ParentObject:
2688 params->objects[i].oi.ParentObject = prop->propval.u32;
2689 params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2690 break;
2691 case PTP_OPC_ObjectFormat:
2692 params->objects[i].oi.ObjectFormat = prop->propval.u16;
2693 break;
2694 case PTP_OPC_ObjectSize:
2695 // We loose precision here, up to 32 bits! However the commands that
2696 // retrieve metadata for files and tracks will make sure that the
2697 // PTP_OPC_ObjectSize is read in and duplicated again.
2698 if (device->object_bitsize == 64) {
2699 params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2700 } else {
2701 params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2702 }
2703 break;
2704 case PTP_OPC_StorageID:
2705 params->objects[i].oi.StorageID = prop->propval.u32;
2706 params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2707 break;
2708 case PTP_OPC_ObjectFileName:
2709 if (prop->propval.str != NULL)
2710 params->objects[i].oi.Filename = strdup(prop->propval.str);
2711 break;
2712 default: {
2713 MTPProperties *newprops;
2714
2715 /* Copy all of the other MTP oprierties into the per-object proplist */
2716 if (params->objects[i].nrofmtpprops) {
2717 newprops = realloc(params->objects[i].mtpprops,
2718 (params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2719 } else {
2720 newprops = calloc(1,sizeof(MTPProperties));
2721 }
2722 if (!newprops) return 0; /* FIXME: error handling? */
2723 params->objects[i].mtpprops = newprops;
2724 memcpy(¶ms->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2725 &props[j],sizeof(props[j]));
2726 params->objects[i].nrofmtpprops++;
2727 params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2728 break;
2729 }
2730 }
2731 prop++;
2732 }
2733 /* mark last entry also */
2734 if (i >= 0) {
2735 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2736 params->nrofobjects = i+1;
2737 } else {
2738 params->nrofobjects = 0;
2739 }
2740 free (props);
2741 /* The device might not give the list in linear ascending order */
2742 ptp_objects_sort (params);
2743 return 0;
2744 }
2745
2746 /**
2747 * This function will recurse through all the directories on the device,
2748 * starting at the root directory, gathering metadata as it moves along.
2749 * It works better on some devices that will only return data for a
2750 * certain directory and does not respect the option to get all metadata
2751 * for all objects.
2752 */
get_handles_recursively(LIBMTP_mtpdevice_t * device,PTPParams * params,uint32_t storageid,uint32_t parent)2753 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2754 PTPParams *params,
2755 uint32_t storageid,
2756 uint32_t parent)
2757 {
2758 PTPObjectHandles currentHandles;
2759 int i = 0;
2760 uint16_t ret = ptp_getobjecthandles(params,
2761 storageid,
2762 PTP_GOH_ALL_FORMATS,
2763 parent,
2764 ¤tHandles);
2765
2766 if (ret != PTP_RC_OK) {
2767 add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2768 return;
2769 }
2770
2771 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2772 return;
2773
2774 // Now descend into any subdirectories found
2775 for (i = 0; i < currentHandles.n; i++) {
2776 PTPObject *ob;
2777 ret = ptp_object_want(params,currentHandles.Handler[i],
2778 PTPOBJECT_OBJECTINFO_LOADED, &ob);
2779 if (ret == PTP_RC_OK) {
2780 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2781 get_handles_recursively(device, params,
2782 storageid, currentHandles.Handler[i]);
2783 } else {
2784 add_error_to_errorstack(device,
2785 LIBMTP_ERROR_CONNECTING,
2786 "Found a bad handle, trying to ignore it.");
2787 }
2788 }
2789 free(currentHandles.Handler);
2790 }
2791
2792 /**
2793 * This function refresh the internal handle list whenever
2794 * the items stored inside the device is altered. On operations
2795 * that do not add or remove objects, this is typically not
2796 * called.
2797 * @param device a pointer to the MTP device to flush handles for.
2798 */
flush_handles(LIBMTP_mtpdevice_t * device)2799 static void flush_handles(LIBMTP_mtpdevice_t *device)
2800 {
2801 PTPParams *params = (PTPParams *) device->params;
2802 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2803 int ret;
2804 uint32_t i;
2805
2806 if (!device->cached) {
2807 return;
2808 }
2809
2810 if (load_cache_on_demand) {
2811 return;
2812 }
2813
2814 if (params->objects != NULL) {
2815 for (i=0;i<params->nrofobjects;i++)
2816 ptp_free_object (¶ms->objects[i]);
2817 free(params->objects);
2818 params->objects = NULL;
2819 params->nrofobjects = 0;
2820 }
2821
2822 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2823 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2824 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2825 // Use the fast method. Ignore return value for now.
2826 ret = get_all_metadata_fast(device);
2827 }
2828
2829 // If the previous failed or returned no objects, use classic
2830 // methods instead.
2831 if (params->nrofobjects == 0) {
2832 // Get all the handles using just standard commands.
2833 if (device->storage == NULL) {
2834 get_handles_recursively(device, params,
2835 PTP_GOH_ALL_STORAGE,
2836 PTP_GOH_ROOT_PARENT);
2837 } else {
2838 // Get handles for each storage in turn.
2839 LIBMTP_devicestorage_t *storage = device->storage;
2840 while(storage != NULL) {
2841 get_handles_recursively(device, params,
2842 storage->id,
2843 PTP_GOH_ROOT_PARENT);
2844 storage = storage->next;
2845 }
2846 }
2847 }
2848
2849 /*
2850 * Loop over the handles, fix up any NULL filenames or
2851 * keywords, then attempt to locate some default folders
2852 * in the root directory of the primary storage.
2853 */
2854 for(i = 0; i < params->nrofobjects; i++) {
2855 PTPObject *ob, *xob;
2856
2857 ob = ¶ms->objects[i];
2858 ret = ptp_object_want(params,params->objects[i].oid,
2859 PTPOBJECT_OBJECTINFO_LOADED, &xob);
2860 if (ret != PTP_RC_OK) {
2861 LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2862 }
2863 if (ob->oi.Filename == NULL)
2864 ob->oi.Filename = strdup("<null>");
2865 if (ob->oi.Keywords == NULL)
2866 ob->oi.Keywords = strdup("<null>");
2867
2868 /* Ignore handles that point to non-folders */
2869 if(ob->oi.ObjectFormat != PTP_OFC_Association)
2870 continue;
2871 /* Only look in the root folder */
2872 if (ob->oi.ParentObject == 0xffffffffU) {
2873 LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2874 ob->oid);
2875 } else if (ob->oi.ParentObject != 0x00000000U)
2876 continue;
2877 /* Only look in the primary storage */
2878 if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2879 continue;
2880
2881 /* Is this the Music Folder */
2882 if (!strcasecmp(ob->oi.Filename, "My Music") ||
2883 !strcasecmp(ob->oi.Filename, "My_Music") ||
2884 !strcasecmp(ob->oi.Filename, "Music")) {
2885 device->default_music_folder = ob->oid;
2886 }
2887 else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2888 !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2889 !strcasecmp(ob->oi.Filename, "Playlists")) {
2890 device->default_playlist_folder = ob->oid;
2891 }
2892 else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2893 !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2894 !strcasecmp(ob->oi.Filename, "Pictures")) {
2895 device->default_picture_folder = ob->oid;
2896 }
2897 else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2898 !strcasecmp(ob->oi.Filename, "My_Video") ||
2899 !strcasecmp(ob->oi.Filename, "Video")) {
2900 device->default_video_folder = ob->oid;
2901 }
2902 else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2903 !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2904 device->default_organizer_folder = ob->oid;
2905 }
2906 else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2907 !strcasecmp(ob->oi.Filename, "Datacasts")) {
2908 device->default_zencast_folder = ob->oid;
2909 }
2910 else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2911 !strcasecmp(ob->oi.Filename, "My_Albums") ||
2912 !strcasecmp(ob->oi.Filename, "Albums")) {
2913 device->default_album_folder = ob->oid;
2914 }
2915 else if (!strcasecmp(ob->oi.Filename, "Text") ||
2916 !strcasecmp(ob->oi.Filename, "Texts")) {
2917 device->default_text_folder = ob->oid;
2918 }
2919 }
2920 }
2921
2922 /**
2923 * This function traverses a devices storage list freeing up the
2924 * strings and the structs.
2925 * @param device a pointer to the MTP device to free the storage
2926 * list for.
2927 */
free_storage_list(LIBMTP_mtpdevice_t * device)2928 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2929 {
2930 LIBMTP_devicestorage_t *storage;
2931 LIBMTP_devicestorage_t *tmp;
2932
2933 storage = device->storage;
2934 while(storage != NULL) {
2935 if (storage->StorageDescription != NULL) {
2936 free(storage->StorageDescription);
2937 }
2938 if (storage->VolumeIdentifier != NULL) {
2939 free(storage->VolumeIdentifier);
2940 }
2941 tmp = storage;
2942 storage = storage->next;
2943 free(tmp);
2944 }
2945 device->storage = NULL;
2946
2947 return;
2948 }
2949
2950 /**
2951 * This function traverses a devices storage list freeing up the
2952 * strings and the structs.
2953 * @param device a pointer to the MTP device to free the storage
2954 * list for.
2955 */
sort_storage_by(LIBMTP_mtpdevice_t * device,int const sortby)2956 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2957 {
2958 LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2959
2960 if (device->storage == NULL)
2961 return -1;
2962 if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2963 return 0;
2964
2965 oldhead = ptr1 = ptr2 = device->storage;
2966
2967 newlist = NULL;
2968
2969 while(oldhead != NULL) {
2970 ptr1 = ptr2 = oldhead;
2971 while(ptr1 != NULL) {
2972
2973 if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2974 ptr2 = ptr1;
2975 if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2976 ptr2 = ptr1;
2977
2978 ptr1 = ptr1->next;
2979 }
2980
2981 // Make our previous entries next point to our next
2982 if(ptr2->prev != NULL) {
2983 ptr1 = ptr2->prev;
2984 ptr1->next = ptr2->next;
2985 } else {
2986 oldhead = ptr2->next;
2987 if(oldhead != NULL)
2988 oldhead->prev = NULL;
2989 }
2990
2991 // Make our next entries previous point to our previous
2992 ptr1 = ptr2->next;
2993 if(ptr1 != NULL) {
2994 ptr1->prev = ptr2->prev;
2995 } else {
2996 ptr1 = ptr2->prev;
2997 if(ptr1 != NULL)
2998 ptr1->next = NULL;
2999 }
3000
3001 if(newlist == NULL) {
3002 newlist = ptr2;
3003 newlist->prev = NULL;
3004 } else {
3005 ptr2->prev = newlist;
3006 newlist->next = ptr2;
3007 newlist = newlist->next;
3008 }
3009 }
3010
3011 if (newlist != NULL) {
3012 newlist->next = NULL;
3013 while(newlist->prev != NULL)
3014 newlist = newlist->prev;
3015 device->storage = newlist;
3016 }
3017
3018 return 0;
3019 }
3020
3021 /**
3022 * This function grabs the first writeable storageid from the
3023 * device storage list.
3024 * @param device a pointer to the MTP device to locate writeable
3025 * storage for.
3026 * @param fitsize a file of this file must fit on the device.
3027 */
get_writeable_storageid(LIBMTP_mtpdevice_t * device,uint64_t fitsize)3028 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
3029 uint64_t fitsize)
3030 {
3031 LIBMTP_devicestorage_t *storage;
3032 uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
3033 int subcall_ret;
3034
3035 // See if there is some storage we can fit this file on.
3036 storage = device->storage;
3037 if (storage == NULL) {
3038 // Sometimes the storage just cannot be detected.
3039 store = 0x00000000U;
3040 } else {
3041 while(storage != NULL) {
3042 // These storages cannot be used.
3043 if (storage->StorageType == PTP_ST_FixedROM ||
3044 storage->StorageType == PTP_ST_RemovableROM) {
3045 storage = storage->next;
3046 continue;
3047 }
3048 // Storage IDs with the lower 16 bits 0x0000 are not supposed
3049 // to be writeable.
3050 if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
3051 storage = storage->next;
3052 continue;
3053 }
3054 // Also check the access capability to avoid e.g. deletable only storages
3055 if (storage->AccessCapability == PTP_AC_ReadOnly ||
3056 storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
3057 storage = storage->next;
3058 continue;
3059 }
3060 // Then see if we can fit the file.
3061 subcall_ret = check_if_file_fits(device, storage, fitsize);
3062 if (subcall_ret != 0) {
3063 storage = storage->next;
3064 } else {
3065 // We found a storage that is writable and can fit the file!
3066 break;
3067 }
3068 }
3069 if (storage == NULL) {
3070 add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
3071 "get_writeable_storageid(): "
3072 "all device storage is full or corrupt.");
3073 return -1;
3074 }
3075 store = storage->id;
3076 }
3077
3078 return store;
3079 }
3080
3081 /**
3082 * Tries to suggest a storage_id of a given ID when we have a parent
3083 * @param device a pointer to the device where to search for the storage ID
3084 * @param fitsize a file of this file must fit on the device.
3085 * @param parent_id look for this ID
3086 * @ret storageID
3087 */
get_suggested_storage_id(LIBMTP_mtpdevice_t * device,uint64_t fitsize,uint32_t parent_id)3088 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3089 uint64_t fitsize,
3090 uint32_t parent_id)
3091 {
3092 PTPParams *params = (PTPParams *) device->params;
3093 PTPObject *ob;
3094 uint16_t ret;
3095
3096 ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3097 if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3098 add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3099 "could not get storage id from parent id.");
3100 return get_writeable_storageid(device, fitsize);
3101 } else {
3102 /* OK we know the parent storage, then use that */
3103 return ob->oi.StorageID;
3104 }
3105 }
3106
3107 /**
3108 * This function grabs the freespace from a certain storage in
3109 * device storage list.
3110 * @param device a pointer to the MTP device to free the storage
3111 * list for.
3112 * @param storageid the storage ID for the storage to flush and
3113 * get free space for.
3114 * @param freespace the free space on this storage will be returned
3115 * in this variable.
3116 */
get_storage_freespace(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t * freespace)3117 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3118 LIBMTP_devicestorage_t *storage,
3119 uint64_t *freespace)
3120 {
3121 PTPParams *params = (PTPParams *) device->params;
3122
3123 // Always query the device about this, since some models explicitly
3124 // needs that. We flush all data on queries storage here.
3125 if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3126 PTPStorageInfo storageInfo;
3127 uint16_t ret;
3128
3129 ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3130 if (ret != PTP_RC_OK) {
3131 add_ptp_error_to_errorstack(device, ret,
3132 "get_storage_freespace(): could not get storage info.");
3133 return -1;
3134 }
3135 if (storage->StorageDescription != NULL) {
3136 free(storage->StorageDescription);
3137 }
3138 if (storage->VolumeIdentifier != NULL) {
3139 free(storage->VolumeIdentifier);
3140 }
3141 storage->StorageType = storageInfo.StorageType;
3142 storage->FilesystemType = storageInfo.FilesystemType;
3143 storage->AccessCapability = storageInfo.AccessCapability;
3144 storage->MaxCapacity = storageInfo.MaxCapability;
3145 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3146 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3147 storage->StorageDescription = storageInfo.StorageDescription;
3148 storage->VolumeIdentifier = storageInfo.VolumeLabel;
3149 }
3150 if(storage->FreeSpaceInBytes == (uint64_t) -1)
3151 return -1;
3152 *freespace = storage->FreeSpaceInBytes;
3153 return 0;
3154 }
3155
3156 /**
3157 * This function dumps out a large chunk of textual information
3158 * provided from the PTP protocol and additionally some extra
3159 * MTP-specific information where applicable.
3160 * @param device a pointer to the MTP device to report info from.
3161 */
LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t * device)3162 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3163 {
3164 int i;
3165 PTPParams *params = (PTPParams *) device->params;
3166 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3167 LIBMTP_devicestorage_t *storage = device->storage;
3168 LIBMTP_device_extension_t *tmpext = device->extensions;
3169
3170 printf("USB low-level info:\n");
3171 dump_usbinfo(ptp_usb);
3172 /* Print out some verbose information */
3173 printf("Device info:\n");
3174 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3175 printf(" Model: %s\n", params->deviceinfo.Model);
3176 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
3177 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
3178 printf(" Vendor extension ID: 0x%08x\n",
3179 params->deviceinfo.VendorExtensionID);
3180 printf(" Vendor extension description: %s\n",
3181 params->deviceinfo.VendorExtensionDesc);
3182 printf(" Detected object size: %d bits\n",
3183 device->object_bitsize);
3184 printf(" Extensions:\n");
3185 while (tmpext != NULL) {
3186 printf(" %s: %d.%d\n",
3187 tmpext->name,
3188 tmpext->major,
3189 tmpext->minor);
3190 tmpext = tmpext->next;
3191 }
3192 printf("Supported operations:\n");
3193 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++)
3194 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], ptp_get_opcode_name(params, params->deviceinfo.OperationsSupported[i]));
3195 printf("Events supported:\n");
3196 if (params->deviceinfo.EventsSupported_len == 0) {
3197 printf(" None.\n");
3198 } else {
3199 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3200 printf(" 0x%04x (%s)\n", params->deviceinfo.EventsSupported[i], ptp_strerror(params->deviceinfo.EventsSupported[i], params->deviceinfo.VendorExtensionID));
3201 }
3202 }
3203 printf("Device Properties Supported:\n");
3204 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3205 char const *propdesc = ptp_get_property_description(params,
3206 params->deviceinfo.DevicePropertiesSupported[i]);
3207
3208 if (propdesc != NULL) {
3209 printf(" 0x%04x: %s\n",
3210 params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3211 } else {
3212 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3213 printf(" 0x%04x: Unknown property\n", prop);
3214 }
3215 }
3216
3217 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3218 printf("Playable File (Object) Types and Object Properties Supported:\n");
3219 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3220 char txt[256];
3221 uint16_t ret;
3222 uint16_t *props = NULL;
3223 uint32_t propcnt = 0;
3224 int j;
3225
3226 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3227 sizeof(txt), txt);
3228 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3229
3230 ret = ptp_mtp_getobjectpropssupported (params,
3231 params->deviceinfo.ImageFormats[i], &propcnt, &props);
3232 if (ret != PTP_RC_OK) {
3233 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3234 "error on query for object properties.");
3235 } else {
3236 for (j=0;j<propcnt;j++) {
3237 PTPObjectPropDesc opd;
3238 int k;
3239
3240 printf(" %04x: %s", props[j],
3241 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3242 // Get a more verbose description
3243 ret = ptp_mtp_getobjectpropdesc(params, props[j],
3244 params->deviceinfo.ImageFormats[i],
3245 &opd);
3246 if (ret != PTP_RC_OK) {
3247 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3248 "LIBMTP_Dump_Device_Info(): "
3249 "could not get property description.");
3250 break;
3251 }
3252
3253 if (opd.DataType == PTP_DTC_STR) {
3254 printf(" STRING data type");
3255 switch (opd.FormFlag) {
3256 case PTP_OPFF_DateTime:
3257 printf(" DATETIME FORM");
3258 break;
3259 case PTP_OPFF_RegularExpression:
3260 printf(" REGULAR EXPRESSION FORM");
3261 break;
3262 case PTP_OPFF_LongString:
3263 printf(" LONG STRING FORM");
3264 break;
3265 default:
3266 break;
3267 }
3268 } else {
3269 if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3270 printf(" array of");
3271 }
3272
3273 switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3274
3275 case PTP_DTC_UNDEF:
3276 printf(" UNDEFINED data type");
3277 break;
3278 case PTP_DTC_INT8:
3279 printf(" INT8 data type");
3280 switch (opd.FormFlag) {
3281 case PTP_OPFF_Range:
3282 printf(" range: MIN %d, MAX %d, STEP %d",
3283 opd.FORM.Range.MinimumValue.i8,
3284 opd.FORM.Range.MaximumValue.i8,
3285 opd.FORM.Range.StepSize.i8);
3286 break;
3287 case PTP_OPFF_Enumeration:
3288 printf(" enumeration: ");
3289 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3290 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3291 }
3292 break;
3293 case PTP_OPFF_ByteArray:
3294 printf(" byte array: ");
3295 break;
3296 default:
3297 printf(" ANY 8BIT VALUE form");
3298 break;
3299 }
3300 break;
3301
3302 case PTP_DTC_UINT8:
3303 printf(" UINT8 data type");
3304 switch (opd.FormFlag) {
3305 case PTP_OPFF_Range:
3306 printf(" range: MIN %d, MAX %d, STEP %d",
3307 opd.FORM.Range.MinimumValue.u8,
3308 opd.FORM.Range.MaximumValue.u8,
3309 opd.FORM.Range.StepSize.u8);
3310 break;
3311 case PTP_OPFF_Enumeration:
3312 printf(" enumeration: ");
3313 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3314 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3315 }
3316 break;
3317 case PTP_OPFF_ByteArray:
3318 printf(" byte array: ");
3319 break;
3320 default:
3321 printf(" ANY 8BIT VALUE form");
3322 break;
3323 }
3324 break;
3325
3326 case PTP_DTC_INT16:
3327 printf(" INT16 data type");
3328 switch (opd.FormFlag) {
3329 case PTP_OPFF_Range:
3330 printf(" range: MIN %d, MAX %d, STEP %d",
3331 opd.FORM.Range.MinimumValue.i16,
3332 opd.FORM.Range.MaximumValue.i16,
3333 opd.FORM.Range.StepSize.i16);
3334 break;
3335 case PTP_OPFF_Enumeration:
3336 printf(" enumeration: ");
3337 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3338 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3339 }
3340 break;
3341 default:
3342 printf(" ANY 16BIT VALUE form");
3343 break;
3344 }
3345 break;
3346
3347 case PTP_DTC_UINT16:
3348 printf(" UINT16 data type");
3349 switch (opd.FormFlag) {
3350 case PTP_OPFF_Range:
3351 printf(" range: MIN %d, MAX %d, STEP %d",
3352 opd.FORM.Range.MinimumValue.u16,
3353 opd.FORM.Range.MaximumValue.u16,
3354 opd.FORM.Range.StepSize.u16);
3355 break;
3356 case PTP_OPFF_Enumeration:
3357 printf(" enumeration: ");
3358 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3359 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3360 }
3361 break;
3362 default:
3363 printf(" ANY 16BIT VALUE form");
3364 break;
3365 }
3366 break;
3367
3368 case PTP_DTC_INT32:
3369 printf(" INT32 data type");
3370 switch (opd.FormFlag) {
3371 case PTP_OPFF_Range:
3372 printf(" range: MIN %d, MAX %d, STEP %d",
3373 opd.FORM.Range.MinimumValue.i32,
3374 opd.FORM.Range.MaximumValue.i32,
3375 opd.FORM.Range.StepSize.i32);
3376 break;
3377 case PTP_OPFF_Enumeration:
3378 printf(" enumeration: ");
3379 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3380 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3381 }
3382 break;
3383 default:
3384 printf(" ANY 32BIT VALUE form");
3385 break;
3386 }
3387 break;
3388
3389 case PTP_DTC_UINT32:
3390 printf(" UINT32 data type");
3391 switch (opd.FormFlag) {
3392 case PTP_OPFF_Range:
3393 printf(" range: MIN %d, MAX %d, STEP %d",
3394 opd.FORM.Range.MinimumValue.u32,
3395 opd.FORM.Range.MaximumValue.u32,
3396 opd.FORM.Range.StepSize.u32);
3397 break;
3398 case PTP_OPFF_Enumeration:
3399 // Special pretty-print for FOURCC codes
3400 if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3401 printf(" enumeration of u32 casted FOURCC: ");
3402 for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3403 if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3404 printf("ANY, ");
3405 } else {
3406 char fourcc[6];
3407 fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3408 fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3409 fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3410 fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3411 fourcc[4] = '\n';
3412 fourcc[5] = '\0';
3413 printf("\"%s\", ", fourcc);
3414 }
3415 }
3416 } else {
3417 printf(" enumeration: ");
3418 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3419 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3420 }
3421 }
3422 break;
3423 default:
3424 printf(" ANY 32BIT VALUE form");
3425 break;
3426 }
3427 break;
3428
3429 case PTP_DTC_INT64:
3430 printf(" INT64 data type");
3431 break;
3432
3433 case PTP_DTC_UINT64:
3434 printf(" UINT64 data type");
3435 break;
3436
3437 case PTP_DTC_INT128:
3438 printf(" INT128 data type");
3439 break;
3440
3441 case PTP_DTC_UINT128:
3442 printf(" UINT128 data type");
3443 break;
3444
3445 default:
3446 printf(" UNKNOWN data type");
3447 break;
3448 }
3449 }
3450 if (opd.GetSet) {
3451 printf(" GET/SET");
3452 } else {
3453 printf(" READ ONLY");
3454 }
3455 printf("\n");
3456 ptp_free_objectpropdesc(&opd);
3457 }
3458 free(props);
3459 }
3460 }
3461 }
3462
3463 if(storage != NULL &&
3464 ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3465 printf("Storage Devices:\n");
3466 while(storage != NULL) {
3467 printf(" StorageID: 0x%08x\n",storage->id);
3468 printf(" StorageType: 0x%04x ",storage->StorageType);
3469 switch (storage->StorageType) {
3470 case PTP_ST_Undefined:
3471 printf("(undefined)\n");
3472 break;
3473 case PTP_ST_FixedROM:
3474 printf("fixed ROM storage\n");
3475 break;
3476 case PTP_ST_RemovableROM:
3477 printf("removable ROM storage\n");
3478 break;
3479 case PTP_ST_FixedRAM:
3480 printf("fixed RAM storage\n");
3481 break;
3482 case PTP_ST_RemovableRAM:
3483 printf("removable RAM storage\n");
3484 break;
3485 default:
3486 printf("UNKNOWN storage\n");
3487 break;
3488 }
3489 printf(" FilesystemType: 0x%04x ",storage->FilesystemType);
3490 switch(storage->FilesystemType) {
3491 case PTP_FST_Undefined:
3492 printf("(undefined)\n");
3493 break;
3494 case PTP_FST_GenericFlat:
3495 printf("generic flat filesystem\n");
3496 break;
3497 case PTP_FST_GenericHierarchical:
3498 printf("generic hierarchical\n");
3499 break;
3500 case PTP_FST_DCF:
3501 printf("DCF\n");
3502 break;
3503 default:
3504 printf("UNKNONWN filesystem type\n");
3505 break;
3506 }
3507 printf(" AccessCapability: 0x%04x ",storage->AccessCapability);
3508 switch(storage->AccessCapability) {
3509 case PTP_AC_ReadWrite:
3510 printf("read/write\n");
3511 break;
3512 case PTP_AC_ReadOnly:
3513 printf("read only\n");
3514 break;
3515 case PTP_AC_ReadOnly_with_Object_Deletion:
3516 printf("read only + object deletion\n");
3517 break;
3518 default:
3519 printf("UNKNOWN access capability\n");
3520 break;
3521 }
3522 printf(" MaxCapacity: %llu\n",
3523 (long long unsigned int) storage->MaxCapacity);
3524 printf(" FreeSpaceInBytes: %llu\n",
3525 (long long unsigned int) storage->FreeSpaceInBytes);
3526 printf(" FreeSpaceInObjects: %llu\n",
3527 (long long unsigned int) storage->FreeSpaceInObjects);
3528 printf(" StorageDescription: %s\n",storage->StorageDescription);
3529 printf(" VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3530 storage = storage->next;
3531 }
3532 }
3533
3534 printf("Special directories:\n");
3535 printf(" Default music folder: 0x%08x\n",
3536 device->default_music_folder);
3537 printf(" Default playlist folder: 0x%08x\n",
3538 device->default_playlist_folder);
3539 printf(" Default picture folder: 0x%08x\n",
3540 device->default_picture_folder);
3541 printf(" Default video folder: 0x%08x\n",
3542 device->default_video_folder);
3543 printf(" Default organizer folder: 0x%08x\n",
3544 device->default_organizer_folder);
3545 printf(" Default zencast folder: 0x%08x\n",
3546 device->default_zencast_folder);
3547 printf(" Default album folder: 0x%08x\n",
3548 device->default_album_folder);
3549 printf(" Default text folder: 0x%08x\n",
3550 device->default_text_folder);
3551 }
3552
3553 /**
3554 * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3555 * operation code (0x1010).
3556 * @param device a pointer to the device to reset.
3557 * @return 0 on success, any other value means failure.
3558 */
LIBMTP_Reset_Device(LIBMTP_mtpdevice_t * device)3559 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3560 {
3561 PTPParams *params = (PTPParams *) device->params;
3562 uint16_t ret;
3563
3564 if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3565 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3566 "LIBMTP_Reset_Device(): "
3567 "device does not support resetting.");
3568 return -1;
3569 }
3570 ret = ptp_resetdevice(params);
3571 if (ret != PTP_RC_OK) {
3572 add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3573 return -1;
3574 }
3575 return 0;
3576 }
3577
3578 /**
3579 * This retrieves the manufacturer name of an MTP device.
3580 * @param device a pointer to the device to get the manufacturer name for.
3581 * @return a newly allocated UTF-8 string representing the manufacturer name.
3582 * The string must be freed by the caller after use. If the call
3583 * was unsuccessful this will contain NULL.
3584 */
LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t * device)3585 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3586 {
3587 char *retmanuf = NULL;
3588 PTPParams *params = (PTPParams *) device->params;
3589
3590 if (params->deviceinfo.Manufacturer != NULL) {
3591 retmanuf = strdup(params->deviceinfo.Manufacturer);
3592 }
3593 return retmanuf;
3594 }
3595
3596 /**
3597 * This retrieves the model name (often equal to product name)
3598 * of an MTP device.
3599 * @param device a pointer to the device to get the model name for.
3600 * @return a newly allocated UTF-8 string representing the model name.
3601 * The string must be freed by the caller after use. If the call
3602 * was unsuccessful this will contain NULL.
3603 */
LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t * device)3604 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3605 {
3606 char *retmodel = NULL;
3607 PTPParams *params = (PTPParams *) device->params;
3608
3609 if (params->deviceinfo.Model != NULL) {
3610 retmodel = strdup(params->deviceinfo.Model);
3611 }
3612 return retmodel;
3613 }
3614
3615 /**
3616 * This retrieves the serial number of an MTP device.
3617 * @param device a pointer to the device to get the serial number for.
3618 * @return a newly allocated UTF-8 string representing the serial number.
3619 * The string must be freed by the caller after use. If the call
3620 * was unsuccessful this will contain NULL.
3621 */
LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t * device)3622 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3623 {
3624 char *retnumber = NULL;
3625 PTPParams *params = (PTPParams *) device->params;
3626
3627 if (params->deviceinfo.SerialNumber != NULL) {
3628 retnumber = strdup(params->deviceinfo.SerialNumber);
3629 }
3630 return retnumber;
3631 }
3632
3633 /**
3634 * This retrieves the device version (hardware and firmware version) of an
3635 * MTP device.
3636 * @param device a pointer to the device to get the device version for.
3637 * @return a newly allocated UTF-8 string representing the device version.
3638 * The string must be freed by the caller after use. If the call
3639 * was unsuccessful this will contain NULL.
3640 */
LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t * device)3641 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3642 {
3643 char *retversion = NULL;
3644 PTPParams *params = (PTPParams *) device->params;
3645
3646 if (params->deviceinfo.DeviceVersion != NULL) {
3647 retversion = strdup(params->deviceinfo.DeviceVersion);
3648 }
3649 return retversion;
3650 }
3651
3652
3653 /**
3654 * This retrieves the "friendly name" of an MTP device. Usually
3655 * this is simply the name of the owner or something like
3656 * "John Doe's Digital Audio Player". This property should be supported
3657 * by all MTP devices.
3658 * @param device a pointer to the device to get the friendly name for.
3659 * @return a newly allocated UTF-8 string representing the friendly name.
3660 * The string must be freed by the caller after use.
3661 * @see LIBMTP_Set_Friendlyname()
3662 */
LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t * device)3663 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3664 {
3665 PTPPropertyValue propval;
3666 char *retstring = NULL;
3667 PTPParams *params = (PTPParams *) device->params;
3668 uint16_t ret;
3669
3670 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3671 return NULL;
3672 }
3673
3674 ret = ptp_getdevicepropvalue(params,
3675 PTP_DPC_MTP_DeviceFriendlyName,
3676 &propval,
3677 PTP_DTC_STR);
3678 if (ret != PTP_RC_OK) {
3679 add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3680 return NULL;
3681 }
3682 if (propval.str != NULL) {
3683 retstring = strdup(propval.str);
3684 free(propval.str);
3685 }
3686 return retstring;
3687 }
3688
3689 /**
3690 * Sets the "friendly name" of an MTP device.
3691 * @param device a pointer to the device to set the friendly name for.
3692 * @param friendlyname the new friendly name for the device.
3693 * @return 0 on success, any other value means failure.
3694 * @see LIBMTP_Get_Friendlyname()
3695 */
LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t * device,char const * const friendlyname)3696 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3697 char const * const friendlyname)
3698 {
3699 PTPPropertyValue propval;
3700 PTPParams *params = (PTPParams *) device->params;
3701 uint16_t ret;
3702
3703 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3704 return -1;
3705 }
3706 propval.str = (char *) friendlyname;
3707 ret = ptp_setdevicepropvalue(params,
3708 PTP_DPC_MTP_DeviceFriendlyName,
3709 &propval,
3710 PTP_DTC_STR);
3711 if (ret != PTP_RC_OK) {
3712 add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3713 return -1;
3714 }
3715 return 0;
3716 }
3717
3718 /**
3719 * This retrieves the syncronization partner of an MTP device. This
3720 * property should be supported by all MTP devices.
3721 * @param device a pointer to the device to get the sync partner for.
3722 * @return a newly allocated UTF-8 string representing the synchronization
3723 * partner. The string must be freed by the caller after use.
3724 * @see LIBMTP_Set_Syncpartner()
3725 */
LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t * device)3726 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3727 {
3728 PTPPropertyValue propval;
3729 char *retstring = NULL;
3730 PTPParams *params = (PTPParams *) device->params;
3731 uint16_t ret;
3732
3733 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3734 return NULL;
3735 }
3736
3737 ret = ptp_getdevicepropvalue(params,
3738 PTP_DPC_MTP_SynchronizationPartner,
3739 &propval,
3740 PTP_DTC_STR);
3741 if (ret != PTP_RC_OK) {
3742 add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3743 return NULL;
3744 }
3745 if (propval.str != NULL) {
3746 retstring = strdup(propval.str);
3747 free(propval.str);
3748 }
3749 return retstring;
3750 }
3751
3752
3753 /**
3754 * Sets the synchronization partner of an MTP device. Note that
3755 * we have no idea what the effect of setting this to "foobar"
3756 * may be. But the general idea seems to be to tell which program
3757 * shall synchronize with this device and tell others to leave
3758 * it alone.
3759 * @param device a pointer to the device to set the sync partner for.
3760 * @param syncpartner the new synchronization partner for the device.
3761 * @return 0 on success, any other value means failure.
3762 * @see LIBMTP_Get_Syncpartner()
3763 */
LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t * device,char const * const syncpartner)3764 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3765 char const * const syncpartner)
3766 {
3767 PTPPropertyValue propval;
3768 PTPParams *params = (PTPParams *) device->params;
3769 uint16_t ret;
3770
3771 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3772 return -1;
3773 }
3774 propval.str = (char *) syncpartner;
3775 ret = ptp_setdevicepropvalue(params,
3776 PTP_DPC_MTP_SynchronizationPartner,
3777 &propval,
3778 PTP_DTC_STR);
3779 if (ret != PTP_RC_OK) {
3780 add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3781 return -1;
3782 }
3783 return 0;
3784 }
3785
3786 /**
3787 * Checks if the device can stora a file of this size or
3788 * if it's too big.
3789 * @param device a pointer to the device.
3790 * @param filesize the size of the file to check whether it will fit.
3791 * @param storageid the ID of the storage to try to fit the file on.
3792 * @return 0 if the file fits, any other value means failure.
3793 */
check_if_file_fits(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t const filesize)3794 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3795 LIBMTP_devicestorage_t *storage,
3796 uint64_t const filesize) {
3797 PTPParams *params = (PTPParams *) device->params;
3798 uint64_t freebytes;
3799 int ret;
3800
3801 // If we cannot check the storage, no big deal.
3802 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3803 return 0;
3804 }
3805
3806 ret = get_storage_freespace(device, storage, &freebytes);
3807 if (ret != 0) {
3808 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3809 "check_if_file_fits(): error checking free storage.");
3810 return -1;
3811 } else {
3812 // See if it fits.
3813 if (filesize > freebytes) {
3814 return -1;
3815 }
3816 }
3817 return 0;
3818 }
3819
3820
3821 /**
3822 * This function retrieves the current battery level on the device.
3823 * @param device a pointer to the device to get the battery level for.
3824 * @param maximum_level a pointer to a variable that will hold the
3825 * maximum level of the battery if the call was successful.
3826 * @param current_level a pointer to a variable that will hold the
3827 * current level of the battery if the call was successful.
3828 * A value of 0 means that the device is on external power.
3829 * @return 0 if the storage info was successfully retrieved, any other
3830 * means failure. A typical cause of failure is that
3831 * the device does not support the battery level property.
3832 */
LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t * device,uint8_t * const maximum_level,uint8_t * const current_level)3833 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3834 uint8_t * const maximum_level,
3835 uint8_t * const current_level)
3836 {
3837 PTPPropertyValue propval;
3838 uint16_t ret;
3839 PTPParams *params = (PTPParams *) device->params;
3840 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3841
3842 *maximum_level = 0;
3843 *current_level = 0;
3844
3845 if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3846 !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3847 return -1;
3848 }
3849
3850 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3851 &propval, PTP_DTC_UINT8);
3852 if (ret != PTP_RC_OK) {
3853 add_ptp_error_to_errorstack(device, ret,
3854 "LIBMTP_Get_Batterylevel(): "
3855 "could not get device property value.");
3856 return -1;
3857 }
3858
3859 *maximum_level = device->maximum_battery_level;
3860 *current_level = propval.u8;
3861
3862 return 0;
3863 }
3864
3865
3866 /**
3867 * Formats device storage (if the device supports the operation).
3868 * WARNING: This WILL delete all data from the device. Make sure you've
3869 * got confirmation from the user BEFORE you call this function.
3870 *
3871 * @param device a pointer to the device containing the storage to format.
3872 * @param storage the actual storage to format.
3873 * @return 0 on success, any other value means failure.
3874 */
LIBMTP_Format_Storage(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage)3875 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3876 LIBMTP_devicestorage_t *storage)
3877 {
3878 uint16_t ret;
3879 PTPParams *params = (PTPParams *) device->params;
3880
3881 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3882 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3883 "LIBMTP_Format_Storage(): "
3884 "device does not support formatting storage.");
3885 return -1;
3886 }
3887 ret = ptp_formatstore(params, storage->id);
3888 if (ret != PTP_RC_OK) {
3889 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3890 "failed to format storage.");
3891 return -1;
3892 }
3893 return 0;
3894 }
3895
3896 /**
3897 * Helper function to extract a unicode property off a device.
3898 * This is the standard way of retrieveing unicode device
3899 * properties as described by the PTP spec.
3900 * @param device a pointer to the device to get the property from.
3901 * @param unicstring a pointer to a pointer that will hold the
3902 * property after this call is completed.
3903 * @param property the property to retrieve.
3904 * @return 0 on success, any other value means failure.
3905 */
get_device_unicode_property(LIBMTP_mtpdevice_t * device,char ** unicstring,uint16_t property)3906 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3907 char **unicstring, uint16_t property)
3908 {
3909 PTPPropertyValue propval;
3910 PTPParams *params = (PTPParams *) device->params;
3911 uint16_t *tmp;
3912 uint16_t ret;
3913 int i;
3914
3915 if (!ptp_property_issupported(params, property)) {
3916 return -1;
3917 }
3918
3919 // Unicode strings are 16bit unsigned integer arrays.
3920 ret = ptp_getdevicepropvalue(params,
3921 property,
3922 &propval,
3923 PTP_DTC_AUINT16);
3924 if (ret != PTP_RC_OK) {
3925 // TODO: add a note on WHICH property that we failed to get.
3926 *unicstring = NULL;
3927 add_ptp_error_to_errorstack(device, ret,
3928 "get_device_unicode_property(): "
3929 "failed to get unicode property.");
3930 return -1;
3931 }
3932
3933 // Extract the actual array.
3934 // printf("Array of %d elements\n", propval.a.count);
3935 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3936 for (i = 0; i < propval.a.count; i++) {
3937 tmp[i] = propval.a.v[i].u16;
3938 // printf("%04x ", tmp[i]);
3939 }
3940 tmp[propval.a.count] = 0x0000U;
3941 free(propval.a.v);
3942
3943 *unicstring = utf16_to_utf8(device, tmp);
3944
3945 free(tmp);
3946
3947 return 0;
3948 }
3949
3950 /**
3951 * This function returns the secure time as an XML document string from
3952 * the device.
3953 * @param device a pointer to the device to get the secure time for.
3954 * @param sectime the secure time string as an XML document or NULL if the call
3955 * failed or the secure time property is not supported. This string
3956 * must be <code>free()</code>:ed by the caller after use.
3957 * @return 0 on success, any other value means failure.
3958 */
LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t * device,char ** const sectime)3959 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3960 {
3961 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3962 }
3963
3964 /**
3965 * This function returns the device (public key) certificate as an
3966 * XML document string from the device.
3967 * @param device a pointer to the device to get the device certificate for.
3968 * @param devcert the device certificate as an XML string or NULL if the call
3969 * failed or the device certificate property is not supported. This
3970 * string must be <code>free()</code>:ed by the caller after use.
3971 * @return 0 on success, any other value means failure.
3972 */
LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t * device,char ** const devcert)3973 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3974 {
3975 return get_device_unicode_property(device, devcert,
3976 PTP_DPC_MTP_DeviceCertificate);
3977 }
3978
3979 /**
3980 * This function retrieves a list of supported file types, i.e. the file
3981 * types that this device claims it supports, e.g. audio file types that
3982 * the device can play etc. This list is mitigated to
3983 * inlcude the file types that libmtp can handle, i.e. it will not list
3984 * filetypes that libmtp will handle internally like playlists and folders.
3985 * @param device a pointer to the device to get the filetype capabilities for.
3986 * @param filetypes a pointer to a pointer that will hold the list of
3987 * supported filetypes if the call was successful. This list must
3988 * be <code>free()</code>:ed by the caller after use.
3989 * @param length a pointer to a variable that will hold the length of the
3990 * list of supported filetypes if the call was successful.
3991 * @return 0 on success, any other value means failure.
3992 * @see LIBMTP_Get_Filetype_Description()
3993 */
LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t * device,uint16_t ** const filetypes,uint16_t * const length)3994 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3995 uint16_t * const length)
3996 {
3997 PTPParams *params = (PTPParams *) device->params;
3998 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3999 uint16_t *localtypes;
4000 uint16_t localtypelen;
4001 uint32_t i;
4002
4003 // This is more memory than needed if there are unknown types, but what the heck.
4004 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
4005 localtypelen = 0;
4006
4007 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
4008 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
4009 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
4010 localtypes[localtypelen] = localtype;
4011 localtypelen++;
4012 }
4013 }
4014 // The forgotten Ogg support on YP-10 and others...
4015 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
4016 localtypes = (uint16_t *) realloc(localtypes,
4017 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4018 localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
4019 localtypelen++;
4020 }
4021 // The forgotten FLAC support on Cowon iAudio S9 and others...
4022 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
4023 localtypes = (uint16_t *) realloc(localtypes,
4024 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4025 localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
4026 localtypelen++;
4027 }
4028
4029 *filetypes = localtypes;
4030 *length = localtypelen;
4031
4032 return 0;
4033 }
4034
4035 /**
4036 * This function checks if the device has some specific capabilities, in
4037 * order to avoid calling APIs that may disturb the device.
4038 *
4039 * @param device a pointer to the device to check the capability on.
4040 * @param cap the capability to check.
4041 * @return 0 if not supported, any other value means the device has the
4042 * requested capability.
4043 */
LIBMTP_Check_Capability(LIBMTP_mtpdevice_t * device,LIBMTP_devicecap_t cap)4044 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
4045 {
4046 switch (cap) {
4047 case LIBMTP_DEVICECAP_GetPartialObject:
4048 return (ptp_operation_issupported(device->params,
4049 PTP_OC_GetPartialObject) ||
4050 ptp_operation_issupported(device->params,
4051 PTP_OC_ANDROID_GetPartialObject64));
4052 case LIBMTP_DEVICECAP_SendPartialObject:
4053 return ptp_operation_issupported(device->params,
4054 PTP_OC_ANDROID_SendPartialObject);
4055 case LIBMTP_DEVICECAP_EditObjects:
4056 return (ptp_operation_issupported(device->params,
4057 PTP_OC_ANDROID_TruncateObject) &&
4058 ptp_operation_issupported(device->params,
4059 PTP_OC_ANDROID_BeginEditObject) &&
4060 ptp_operation_issupported(device->params,
4061 PTP_OC_ANDROID_EndEditObject));
4062 /*
4063 * Handle other capabilities here, this is also a good place to
4064 * blacklist some advanced operations on specific devices if need
4065 * be.
4066 */
4067
4068 default:
4069 break;
4070 }
4071 return 0;
4072 }
4073
4074 /**
4075 * This function updates all the storage id's of a device and their
4076 * properties, then creates a linked list and puts the list head into
4077 * the device struct. It also optionally sorts this list. If you want
4078 * to display storage information in your application you should call
4079 * this function, then dereference the device struct
4080 * (<code>device->storage</code>) to get out information on the storage.
4081 *
4082 * You need to call this everytime you want to update the
4083 * <code>device->storage</code> list, for example anytime you need
4084 * to check available storage somewhere.
4085 *
4086 * <b>WARNING:</b> since this list is dynamically updated, do not
4087 * reference its fields in external applications by pointer! E.g
4088 * do not put a reference to any <code>char *</code> field. instead
4089 * <code>strncpy()</code> it!
4090 *
4091 * @param device a pointer to the device to get the storage for.
4092 * @param sortby an integer that determines the sorting of the storage list.
4093 * Valid sort methods are defined in libmtp.h with beginning with
4094 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4095 * sort.
4096 * @return 0 on success, 1 success but only with storage id's, storage
4097 * properities could not be retrieved and -1 means failure.
4098 */
LIBMTP_Get_Storage(LIBMTP_mtpdevice_t * device,int const sortby)4099 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4100 {
4101 uint32_t i = 0;
4102 PTPStorageInfo storageInfo;
4103 PTPParams *params = (PTPParams *) device->params;
4104 PTPStorageIDs storageIDs;
4105 LIBMTP_devicestorage_t *storage = NULL;
4106 LIBMTP_devicestorage_t *storageprev = NULL;
4107
4108 if (device->storage != NULL)
4109 free_storage_list(device);
4110
4111 // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4112 // return -1;
4113 if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4114 return -1;
4115 if (storageIDs.n < 1)
4116 return -1;
4117
4118 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4119 for (i = 0; i < storageIDs.n; i++) {
4120
4121 storage = (LIBMTP_devicestorage_t *)
4122 malloc(sizeof(LIBMTP_devicestorage_t));
4123 storage->prev = storageprev;
4124 if (storageprev != NULL)
4125 storageprev->next = storage;
4126 if (device->storage == NULL)
4127 device->storage = storage;
4128
4129 storage->id = storageIDs.Storage[i];
4130 storage->StorageType = PTP_ST_Undefined;
4131 storage->FilesystemType = PTP_FST_Undefined;
4132 storage->AccessCapability = PTP_AC_ReadWrite;
4133 storage->MaxCapacity = (uint64_t) -1;
4134 storage->FreeSpaceInBytes = (uint64_t) -1;
4135 storage->FreeSpaceInObjects = (uint64_t) -1;
4136 storage->StorageDescription = strdup("Unknown storage");
4137 storage->VolumeIdentifier = strdup("Unknown volume");
4138 storage->next = NULL;
4139
4140 storageprev = storage;
4141 }
4142 free(storageIDs.Storage);
4143 return 1;
4144 } else {
4145 for (i = 0; i < storageIDs.n; i++) {
4146 uint16_t ret;
4147 ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4148 if (ret != PTP_RC_OK) {
4149 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4150 "Could not get storage info.");
4151 if (device->storage != NULL) {
4152 free_storage_list(device);
4153 }
4154 return -1;
4155 }
4156
4157 storage = (LIBMTP_devicestorage_t *)
4158 malloc(sizeof(LIBMTP_devicestorage_t));
4159 storage->prev = storageprev;
4160 if (storageprev != NULL)
4161 storageprev->next = storage;
4162 if (device->storage == NULL)
4163 device->storage = storage;
4164
4165 storage->id = storageIDs.Storage[i];
4166 storage->StorageType = storageInfo.StorageType;
4167 storage->FilesystemType = storageInfo.FilesystemType;
4168 storage->AccessCapability = storageInfo.AccessCapability;
4169 storage->MaxCapacity = storageInfo.MaxCapability;
4170 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4171 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4172 storage->StorageDescription = storageInfo.StorageDescription;
4173 storage->VolumeIdentifier = storageInfo.VolumeLabel;
4174 storage->next = NULL;
4175
4176 storageprev = storage;
4177 }
4178
4179 if (storage != NULL)
4180 storage->next = NULL;
4181
4182 sort_storage_by(device,sortby);
4183 free(storageIDs.Storage);
4184 return 0;
4185 }
4186 }
4187
4188 /**
4189 * This creates a new file metadata structure and allocates memory
4190 * for it. Notice that if you add strings to this structure they
4191 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4192 * operation later, so be careful of using strdup() when assigning
4193 * strings, e.g.:
4194 *
4195 * <pre>
4196 * LIBMTP_file_t *file = LIBMTP_new_file_t();
4197 * file->filename = strdup(namestr);
4198 * ....
4199 * LIBMTP_destroy_file_t(file);
4200 * </pre>
4201 *
4202 * @return a pointer to the newly allocated metadata structure.
4203 * @see LIBMTP_destroy_file_t()
4204 */
LIBMTP_new_file_t(void)4205 LIBMTP_file_t *LIBMTP_new_file_t(void)
4206 {
4207 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4208 if (new == NULL) {
4209 return NULL;
4210 }
4211 new->filename = NULL;
4212 new->item_id = 0;
4213 new->parent_id = 0;
4214 new->storage_id = 0;
4215 new->filesize = 0;
4216 new->modificationdate = 0;
4217 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4218 new->next = NULL;
4219 return new;
4220 }
4221
4222 /**
4223 * This destroys a file metadata structure and deallocates the memory
4224 * used by it, including any strings. Never use a file metadata
4225 * structure again after calling this function on it.
4226 * @param file the file metadata to destroy.
4227 * @see LIBMTP_new_file_t()
4228 */
LIBMTP_destroy_file_t(LIBMTP_file_t * file)4229 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4230 {
4231 if (file == NULL) {
4232 return;
4233 }
4234 if (file->filename != NULL)
4235 free(file->filename);
4236 free(file);
4237 return;
4238 }
4239
4240 /**
4241 * Helper function that takes one PTP object and creates a
4242 * LIBMTP_file_t metadata entry.
4243 */
obj2file(LIBMTP_mtpdevice_t * device,PTPObject * ob)4244 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4245 {
4246 PTPParams *params = (PTPParams *) device->params;
4247 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4248 LIBMTP_file_t *file;
4249 int i;
4250
4251 // Allocate a new file type
4252 file = LIBMTP_new_file_t();
4253
4254 file->parent_id = ob->oi.ParentObject;
4255 file->storage_id = ob->oi.StorageID;
4256
4257 // Set the filetype
4258 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4259
4260 /*
4261 * A special quirk for devices that doesn't quite
4262 * remember that some files marked as "unknown" type are
4263 * actually OGG or FLAC files. We look at the filename extension
4264 * and see if it happens that this was atleast named "ogg" or "flac"
4265 * and fall back on this heuristic approach in that case,
4266 * for these bugged devices only.
4267 */
4268 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4269 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4270 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4271 has_ogg_extension(file->filename)) {
4272 file->filetype = LIBMTP_FILETYPE_OGG;
4273 }
4274
4275 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4276 file->filetype = LIBMTP_FILETYPE_FLAC;
4277 }
4278 }
4279
4280 // Set the modification date
4281 file->modificationdate = ob->oi.ModificationDate;
4282
4283 // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4284 file->filesize = ob->oi.ObjectCompressedSize;
4285 if (ob->oi.Filename != NULL) {
4286 file->filename = strdup(ob->oi.Filename);
4287 }
4288
4289 // This is a unique ID so we can keep track of the file.
4290 file->item_id = ob->oid;
4291
4292 /*
4293 * If we have a cached, large set of metadata, then use it!
4294 */
4295 if (ob->mtpprops) {
4296 MTPProperties *prop = ob->mtpprops;
4297
4298 for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4299 // Pick ObjectSize here...
4300 if (prop->property == PTP_OPC_ObjectSize) {
4301 // This may already be set, but this 64bit precision value
4302 // is better than the PTP 32bit value, so let it override.
4303 if (device->object_bitsize == 64) {
4304 file->filesize = prop->propval.u64;
4305 } else {
4306 file->filesize = prop->propval.u32;
4307 }
4308 break;
4309 }
4310 }
4311 } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4312 uint16_t *props = NULL;
4313 uint32_t propcnt = 0;
4314 int ret;
4315
4316 // First see which properties can be retrieved for this object format
4317 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4318 if (ret != PTP_RC_OK) {
4319 add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4320 // Silently fall through.
4321 } else {
4322 for (i = 0; i < propcnt; i++) {
4323 switch (props[i]) {
4324 case PTP_OPC_ObjectSize:
4325 if (device->object_bitsize == 64) {
4326 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4327 } else {
4328 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4329 }
4330 break;
4331 default:
4332 break;
4333 }
4334 }
4335 free(props);
4336 }
4337 }
4338
4339 return file;
4340 }
4341
4342
4343 /**
4344 * This function retrieves the metadata for a single file off
4345 * the device.
4346 *
4347 * Do not call this function repeatedly! The file handles are linearly
4348 * searched O(n) and the call may involve (slow) USB traffic, so use
4349 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4350 * as an efficient data structure such as a hash list.
4351 *
4352 * Incidentally this function will return metadata for
4353 * a folder (association) as well, but this is not a proper use
4354 * of it, it is intended for file manipulation, not folder manipulation.
4355 *
4356 * @param device a pointer to the device to get the file metadata from.
4357 * @param fileid the object ID of the file that you want the metadata for.
4358 * @return a metadata entry on success or NULL on failure.
4359 * @see LIBMTP_Get_Filelisting()
4360 */
LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t * device,uint32_t const fileid)4361 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4362 {
4363 PTPParams *params = (PTPParams *) device->params;
4364 uint16_t ret;
4365 PTPObject *ob;
4366
4367 // Get all the handles if we haven't already done that
4368 // (Only on cached devices.)
4369 if (device->cached && params->nrofobjects == 0) {
4370 flush_handles(device);
4371 }
4372
4373 ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4374 if (ret != PTP_RC_OK)
4375 return NULL;
4376
4377 return obj2file(device, ob);
4378 }
4379
4380 /**
4381 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4382 * NOT TO USE IT.
4383 * @see LIBMTP_Get_Filelisting_With_Callback()
4384 */
LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t * device)4385 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4386 {
4387 LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4388 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4389 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4390 }
4391
4392 /**
4393 * This returns a long list of all files available
4394 * on the current MTP device. Folders will not be returned, but abstract
4395 * entities like playlists and albums will show up as "files". Typical usage:
4396 *
4397 * <pre>
4398 * LIBMTP_file_t *filelist;
4399 *
4400 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4401 * while (filelist != NULL) {
4402 * LIBMTP_file_t *tmp;
4403 *
4404 * // Do something on each element in the list here...
4405 * tmp = filelist;
4406 * filelist = filelist->next;
4407 * LIBMTP_destroy_file_t(tmp);
4408 * }
4409 * </pre>
4410 *
4411 * If you want to group your file listing by storage (per storage unit) or
4412 * arrange files into folders, you must dereference the <code>storage_id</code>
4413 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4414 * struct. To arrange by folders or files you typically have to create the proper
4415 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4416 * <code>LIBMTP_Get_Folder_List()</code> first.
4417 *
4418 * @param device a pointer to the device to get the file listing for.
4419 * @param callback a function to be called during the tracklisting retrieveal
4420 * for displaying progress bars etc, or NULL if you don't want
4421 * any callbacks.
4422 * @param data a user-defined pointer that is passed along to
4423 * the <code>progress</code> function in order to
4424 * pass along some user defined data to the progress
4425 * updates. If not used, set this to NULL.
4426 * @return a list of files that can be followed using the <code>next</code>
4427 * field of the <code>LIBMTP_file_t</code> data structure.
4428 * Each of the metadata tags must be freed after use, and may
4429 * contain only partial metadata information, i.e. one or several
4430 * fields may be NULL or 0.
4431 * @see LIBMTP_Get_Filemetadata()
4432 */
LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4433 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4434 LIBMTP_progressfunc_t const callback,
4435 void const * const data)
4436 {
4437 uint32_t i = 0;
4438 LIBMTP_file_t *retfiles = NULL;
4439 LIBMTP_file_t *curfile = NULL;
4440 PTPParams *params = (PTPParams *) device->params;
4441
4442 // Get all the handles if we haven't already done that
4443 if (params->nrofobjects == 0) {
4444 flush_handles(device);
4445 }
4446
4447 for (i = 0; i < params->nrofobjects; i++) {
4448 LIBMTP_file_t *file;
4449 PTPObject *ob;
4450
4451 if (callback != NULL)
4452 callback(i, params->nrofobjects, data);
4453
4454 ob = ¶ms->objects[i];
4455
4456 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4457 // MTP use this object format for folders which means
4458 // these "files" will turn up on a folder listing instead.
4459 continue;
4460 }
4461
4462 // Look up metadata
4463 file = obj2file(device, ob);
4464 if (file == NULL) {
4465 continue;
4466 }
4467
4468 // Add track to a list that will be returned afterwards.
4469 if (retfiles == NULL) {
4470 retfiles = file;
4471 curfile = file;
4472 } else {
4473 curfile->next = file;
4474 curfile = file;
4475 }
4476
4477 // Call listing callback
4478 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4479
4480 } // Handle counting loop
4481 return retfiles;
4482 }
4483
4484 /**
4485 * This function retrieves the contents of a certain folder
4486 * with id parent on a certain storage on a certain device.
4487 * The result contains both files and folders.
4488 * The device used with this operations must have been opened with
4489 * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4490 *
4491 * NOTE: the request will always perform I/O with the device.
4492 * @param device a pointer to the MTP device to report info from.
4493 * @param storage a storage on the device to report info from. If
4494 * 0 is passed in, the files for the given parent will be
4495 * searched across all available storages.
4496 * @param parent the parent folder id.
4497 */
LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t * device,uint32_t const storage,uint32_t const parent)4498 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4499 uint32_t const storage,
4500 uint32_t const parent)
4501 {
4502 PTPParams *params = (PTPParams *) device->params;
4503 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4504 LIBMTP_file_t *retfiles = NULL;
4505 LIBMTP_file_t *curfile = NULL;
4506 PTPObjectHandles currentHandles;
4507 uint32_t storageid;
4508 uint16_t ret;
4509 int i = 0;
4510
4511 if (device->cached) {
4512 // This function is only supposed to be used by devices
4513 // opened as uncached!
4514 LIBMTP_ERROR("tried to use %s on a cached device!\n",
4515 __func__);
4516 return NULL;
4517 }
4518
4519 if (FLAG_BROKEN_GET_OBJECT_PROPVAL(ptp_usb)) {
4520 // These devices cannot handle the commands needed for
4521 // Uncached access!
4522 LIBMTP_ERROR("tried to use %s on an unsupported device, "
4523 "this command does not work on all devices "
4524 "due to missing low-level support to read "
4525 "information on individual tracks\n",
4526 __func__);
4527 return NULL;
4528 }
4529
4530 if (storage == 0)
4531 storageid = PTP_GOH_ALL_STORAGE;
4532 else
4533 storageid = storage;
4534
4535 ret = ptp_getobjecthandles(params,
4536 storageid,
4537 PTP_GOH_ALL_FORMATS,
4538 parent,
4539 ¤tHandles);
4540
4541 if (ret != PTP_RC_OK) {
4542 add_ptp_error_to_errorstack(device, ret,
4543 "LIBMTP_Get_Files_And_Folders(): could not get object handles.");
4544 return NULL;
4545 }
4546
4547 if (currentHandles.Handler == NULL || currentHandles.n == 0)
4548 return NULL;
4549
4550 for (i = 0; i < currentHandles.n; i++) {
4551 LIBMTP_file_t *file;
4552
4553 // Get metadata for one file, if it fails, try next file
4554 file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4555 if (file == NULL)
4556 continue;
4557
4558 // Add track to a list that will be returned afterwards.
4559 if (curfile == NULL) {
4560 curfile = file;
4561 retfiles = file;
4562 } else {
4563 curfile->next = file;
4564 curfile = file;
4565 }
4566 }
4567
4568 free(currentHandles.Handler);
4569
4570 // Return a pointer to the original first file
4571 // in the big list.
4572 return retfiles;
4573 }
4574
LIBMTP_Set_Load_Cache_On_Demand(int flag)4575 void LIBMTP_Set_Load_Cache_On_Demand(int flag)
4576 {
4577 load_cache_on_demand = flag;
4578 }
4579
4580 /**
4581 * This creates a new track metadata structure and allocates memory
4582 * for it. Notice that if you add strings to this structure they
4583 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4584 * operation later, so be careful of using strdup() when assigning
4585 * strings, e.g.:
4586 *
4587 * <pre>
4588 * LIBMTP_track_t *track = LIBMTP_new_track_t();
4589 * track->title = strdup(titlestr);
4590 * ....
4591 * LIBMTP_destroy_track_t(track);
4592 * </pre>
4593 *
4594 * @return a pointer to the newly allocated metadata structure.
4595 * @see LIBMTP_destroy_track_t()
4596 */
LIBMTP_new_track_t(void)4597 LIBMTP_track_t *LIBMTP_new_track_t(void)
4598 {
4599 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4600 if (new == NULL) {
4601 return NULL;
4602 }
4603 new->item_id = 0;
4604 new->parent_id = 0;
4605 new->storage_id = 0;
4606 new->title = NULL;
4607 new->artist = NULL;
4608 new->composer = NULL;
4609 new->album = NULL;
4610 new->genre = NULL;
4611 new->date = NULL;
4612 new->filename = NULL;
4613 new->duration = 0;
4614 new->tracknumber = 0;
4615 new->filesize = 0;
4616 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4617 new->samplerate = 0;
4618 new->nochannels = 0;
4619 new->wavecodec = 0;
4620 new->bitrate = 0;
4621 new->bitratetype = 0;
4622 new->rating = 0;
4623 new->usecount = 0;
4624 new->modificationdate = 0;
4625 new->next = NULL;
4626 return new;
4627 }
4628
4629 /**
4630 * This destroys a track metadata structure and deallocates the memory
4631 * used by it, including any strings. Never use a track metadata
4632 * structure again after calling this function on it.
4633 * @param track the track metadata to destroy.
4634 * @see LIBMTP_new_track_t()
4635 */
LIBMTP_destroy_track_t(LIBMTP_track_t * track)4636 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4637 {
4638 if (track == NULL) {
4639 return;
4640 }
4641 if (track->title != NULL)
4642 free(track->title);
4643 if (track->artist != NULL)
4644 free(track->artist);
4645 if (track->composer != NULL)
4646 free(track->composer);
4647 if (track->album != NULL)
4648 free(track->album);
4649 if (track->genre != NULL)
4650 free(track->genre);
4651 if (track->date != NULL)
4652 free(track->date);
4653 if (track->filename != NULL)
4654 free(track->filename);
4655 free(track);
4656 return;
4657 }
4658
4659 /**
4660 * This function maps and copies a property onto the track metadata if applicable.
4661 */
pick_property_to_track_metadata(LIBMTP_mtpdevice_t * device,MTPProperties * prop,LIBMTP_track_t * track)4662 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4663 {
4664 switch (prop->property) {
4665 case PTP_OPC_Name:
4666 if (prop->propval.str != NULL)
4667 track->title = strdup(prop->propval.str);
4668 else
4669 track->title = NULL;
4670 break;
4671 case PTP_OPC_Artist:
4672 if (prop->propval.str != NULL)
4673 track->artist = strdup(prop->propval.str);
4674 else
4675 track->artist = NULL;
4676 break;
4677 case PTP_OPC_Composer:
4678 if (prop->propval.str != NULL)
4679 track->composer = strdup(prop->propval.str);
4680 else
4681 track->composer = NULL;
4682 break;
4683 case PTP_OPC_Duration:
4684 track->duration = prop->propval.u32;
4685 break;
4686 case PTP_OPC_Track:
4687 track->tracknumber = prop->propval.u16;
4688 break;
4689 case PTP_OPC_Genre:
4690 if (prop->propval.str != NULL)
4691 track->genre = strdup(prop->propval.str);
4692 else
4693 track->genre = NULL;
4694 break;
4695 case PTP_OPC_AlbumName:
4696 if (prop->propval.str != NULL)
4697 track->album = strdup(prop->propval.str);
4698 else
4699 track->album = NULL;
4700 break;
4701 case PTP_OPC_OriginalReleaseDate:
4702 if (prop->propval.str != NULL)
4703 track->date = strdup(prop->propval.str);
4704 else
4705 track->date = NULL;
4706 break;
4707 // These are, well not so important.
4708 case PTP_OPC_SampleRate:
4709 track->samplerate = prop->propval.u32;
4710 break;
4711 case PTP_OPC_NumberOfChannels:
4712 track->nochannels = prop->propval.u16;
4713 break;
4714 case PTP_OPC_AudioWAVECodec:
4715 track->wavecodec = prop->propval.u32;
4716 break;
4717 case PTP_OPC_AudioBitRate:
4718 track->bitrate = prop->propval.u32;
4719 break;
4720 case PTP_OPC_BitRateType:
4721 track->bitratetype = prop->propval.u16;
4722 break;
4723 case PTP_OPC_Rating:
4724 track->rating = prop->propval.u16;
4725 break;
4726 case PTP_OPC_UseCount:
4727 track->usecount = prop->propval.u32;
4728 break;
4729 case PTP_OPC_ObjectSize:
4730 if (device->object_bitsize == 64) {
4731 track->filesize = prop->propval.u64;
4732 } else {
4733 track->filesize = prop->propval.u32;
4734 }
4735 break;
4736 default:
4737 break;
4738 }
4739 }
4740
4741 /**
4742 * This function retrieves the track metadata for a track
4743 * given by a unique ID.
4744 * @param device a pointer to the device to get the track metadata off.
4745 * @param trackid the unique ID of the track.
4746 * @param objectformat the object format of this track, so we know what it supports.
4747 * @param track a metadata set to fill in.
4748 */
get_track_metadata(LIBMTP_mtpdevice_t * device,uint16_t objectformat,LIBMTP_track_t * track)4749 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4750 LIBMTP_track_t *track)
4751 {
4752 uint16_t ret;
4753 PTPParams *params = (PTPParams *) device->params;
4754 uint32_t i;
4755 MTPProperties *prop;
4756 PTPObject *ob;
4757
4758 /*
4759 * If we have a cached, large set of metadata, then use it!
4760 */
4761 ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4762 if (ob->mtpprops) {
4763 prop = ob->mtpprops;
4764 for (i=0;i<ob->nrofmtpprops;i++,prop++)
4765 pick_property_to_track_metadata(device, prop, track);
4766 } else {
4767 uint16_t *props = NULL;
4768 uint32_t propcnt = 0;
4769
4770 // First see which properties can be retrieved for this object format
4771 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4772 if (ret != PTP_RC_OK) {
4773 add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4774 // Just bail out for now, nothing is ever set.
4775 return;
4776 } else {
4777 for (i=0;i<propcnt;i++) {
4778 switch (props[i]) {
4779 case PTP_OPC_Name:
4780 track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4781 break;
4782 case PTP_OPC_Artist:
4783 track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4784 break;
4785 case PTP_OPC_Composer:
4786 track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4787 break;
4788 case PTP_OPC_Duration:
4789 track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4790 break;
4791 case PTP_OPC_Track:
4792 track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4793 break;
4794 case PTP_OPC_Genre:
4795 track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4796 break;
4797 case PTP_OPC_AlbumName:
4798 track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4799 break;
4800 case PTP_OPC_OriginalReleaseDate:
4801 track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4802 break;
4803 // These are, well not so important.
4804 case PTP_OPC_SampleRate:
4805 track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4806 break;
4807 case PTP_OPC_NumberOfChannels:
4808 track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4809 break;
4810 case PTP_OPC_AudioWAVECodec:
4811 track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4812 break;
4813 case PTP_OPC_AudioBitRate:
4814 track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4815 break;
4816 case PTP_OPC_BitRateType:
4817 track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4818 break;
4819 case PTP_OPC_Rating:
4820 track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4821 break;
4822 case PTP_OPC_UseCount:
4823 track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4824 break;
4825 case PTP_OPC_ObjectSize:
4826 if (device->object_bitsize == 64) {
4827 track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4828 } else {
4829 track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4830 }
4831 break;
4832 }
4833 }
4834 free(props);
4835 }
4836 }
4837 }
4838
4839 /**
4840 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4841 * NOT TO USE IT.
4842 * @see LIBMTP_Get_Tracklisting_With_Callback()
4843 */
LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t * device)4844 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4845 {
4846 LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4847 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4848 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4849 }
4850
4851 /**
4852 * This returns a long list of all tracks available on the current MTP device.
4853 * Tracks include multimedia objects, both music tracks and video tracks.
4854 * Typical usage:
4855 *
4856 * <pre>
4857 * LIBMTP_track_t *tracklist;
4858 *
4859 * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4860 * while (tracklist != NULL) {
4861 * LIBMTP_track_t *tmp;
4862 *
4863 * // Do something on each element in the list here...
4864 * tmp = tracklist;
4865 * tracklist = tracklist->next;
4866 * LIBMTP_destroy_track_t(tmp);
4867 * }
4868 * </pre>
4869 *
4870 * If you want to group your track listing by storage (per storage unit) or
4871 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4872 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4873 * struct. To arrange by folders or files you typically have to create the proper
4874 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4875 * <code>LIBMTP_Get_Folder_List()</code> first.
4876 *
4877 * @param device a pointer to the device to get the track listing for.
4878 * @param callback a function to be called during the tracklisting retrieveal
4879 * for displaying progress bars etc, or NULL if you don't want
4880 * any callbacks.
4881 * @param data a user-defined pointer that is passed along to
4882 * the <code>progress</code> function in order to
4883 * pass along some user defined data to the progress
4884 * updates. If not used, set this to NULL.
4885 * @return a list of tracks that can be followed using the <code>next</code>
4886 * field of the <code>LIBMTP_track_t</code> data structure.
4887 * Each of the metadata tags must be freed after use, and may
4888 * contain only partial metadata information, i.e. one or several
4889 * fields may be NULL or 0.
4890 * @see LIBMTP_Get_Trackmetadata()
4891 */
LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4892 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4893 LIBMTP_progressfunc_t const callback,
4894 void const * const data)
4895 {
4896 return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4897 }
4898
4899
4900 /**
4901 * This returns a long list of all tracks available on the current MTP device.
4902 * Tracks include multimedia objects, both music tracks and video tracks.
4903 * Typical usage:
4904 *
4905 * <pre>
4906 * LIBMTP_track_t *tracklist;
4907 *
4908 * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4909 * while (tracklist != NULL) {
4910 * LIBMTP_track_t *tmp;
4911 *
4912 * // Do something on each element in the list here...
4913 * tmp = tracklist;
4914 * tracklist = tracklist->next;
4915 * LIBMTP_destroy_track_t(tmp);
4916 * }
4917 * </pre>
4918 *
4919 * If you want to group your track listing by storage (per storage unit) or
4920 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4921 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4922 * struct. To arrange by folders or files you typically have to create the proper
4923 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4924 * <code>LIBMTP_Get_Folder_List()</code> first.
4925 *
4926 * @param device a pointer to the device to get the track listing for.
4927 * @param storage_id ID of device storage (if null, no filter)
4928 * @param callback a function to be called during the tracklisting retrieveal
4929 * for displaying progress bars etc, or NULL if you don't want
4930 * any callbacks.
4931 * @param data a user-defined pointer that is passed along to
4932 * the <code>progress</code> function in order to
4933 * pass along some user defined data to the progress
4934 * updates. If not used, set this to NULL.
4935 * @return a list of tracks that can be followed using the <code>next</code>
4936 * field of the <code>LIBMTP_track_t</code> data structure.
4937 * Each of the metadata tags must be freed after use, and may
4938 * contain only partial metadata information, i.e. one or several
4939 * fields may be NULL or 0.
4940 * @see LIBMTP_Get_Trackmetadata()
4941 */
LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t * device,uint32_t const storage_id,LIBMTP_progressfunc_t const callback,void const * const data)4942 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4943 LIBMTP_progressfunc_t const callback,
4944 void const * const data)
4945 {
4946 uint32_t i = 0;
4947 LIBMTP_track_t *retracks = NULL;
4948 LIBMTP_track_t *curtrack = NULL;
4949 PTPParams *params = (PTPParams *) device->params;
4950 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4951
4952 // Get all the handles if we haven't already done that
4953 if (params->nrofobjects == 0) {
4954 flush_handles(device);
4955 }
4956
4957 for (i = 0; i < params->nrofobjects; i++) {
4958 LIBMTP_track_t *track;
4959 PTPObject *ob;
4960 LIBMTP_filetype_t mtptype;
4961
4962 if (callback != NULL)
4963 callback(i, params->nrofobjects, data);
4964
4965 ob = ¶ms->objects[i];
4966 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4967
4968 // Ignore stuff we don't know how to handle...
4969 // TODO: get this list as an intersection of the sets
4970 // supported by the device and the from the device and
4971 // all known track files?
4972 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4973 // This row lets through undefined files for examination since they may be forgotten OGG files.
4974 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4975 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4976 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4977 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4978 ) {
4979 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4980 continue;
4981 }
4982
4983 // Ignore stuff that isn't into the storage device
4984 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4985 continue;
4986
4987 // Allocate a new track type
4988 track = LIBMTP_new_track_t();
4989
4990 // This is some sort of unique ID so we can keep track of the track.
4991 track->item_id = ob->oid;
4992 track->parent_id = ob->oi.ParentObject;
4993 track->storage_id = ob->oi.StorageID;
4994 track->modificationdate = ob->oi.ModificationDate;
4995
4996 track->filetype = mtptype;
4997
4998 // Original file-specific properties
4999 track->filesize = ob->oi.ObjectCompressedSize;
5000 if (ob->oi.Filename != NULL) {
5001 track->filename = strdup(ob->oi.Filename);
5002 }
5003
5004 get_track_metadata(device, ob->oi.ObjectFormat, track);
5005
5006 /*
5007 * A special quirk for iriver devices that doesn't quite
5008 * remember that some files marked as "unknown" type are
5009 * actually OGG or FLAC files. We look at the filename extension
5010 * and see if it happens that this was atleast named "ogg" or "flac"
5011 * and fall back on this heuristic approach in that case,
5012 * for these bugged devices only.
5013 */
5014 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5015 track->filename != NULL) {
5016 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5017 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5018 has_ogg_extension(track->filename))
5019 track->filetype = LIBMTP_FILETYPE_OGG;
5020 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5021 has_flac_extension(track->filename))
5022 track->filetype = LIBMTP_FILETYPE_FLAC;
5023 else {
5024 // This was not an OGG/FLAC file so discard it and continue
5025 LIBMTP_destroy_track_t(track);
5026 continue;
5027 }
5028 }
5029
5030 // Add track to a list that will be returned afterwards.
5031 if (retracks == NULL) {
5032 retracks = track;
5033 curtrack = track;
5034 } else {
5035 curtrack->next = track;
5036 curtrack = track;
5037 }
5038
5039 // Call listing callback
5040 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
5041
5042 } // Handle counting loop
5043 return retracks;
5044 }
5045
5046 /**
5047 * This function retrieves the metadata for a single track off
5048 * the device.
5049 *
5050 * Do not call this function repeatedly! The track handles are linearly
5051 * searched O(n) and the call may involve (slow) USB traffic, so use
5052 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
5053 * as an efficient data structure such as a hash list.
5054 *
5055 * @param device a pointer to the device to get the track metadata from.
5056 * @param trackid the object ID of the track that you want the metadata for.
5057 * @return a track metadata entry on success or NULL on failure.
5058 * @see LIBMTP_Get_Tracklisting()
5059 */
LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t * device,uint32_t const trackid)5060 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
5061 {
5062 PTPParams *params = (PTPParams *) device->params;
5063 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5064 PTPObject *ob;
5065 LIBMTP_track_t *track;
5066 LIBMTP_filetype_t mtptype;
5067 uint16_t ret;
5068
5069 // Get all the handles if we haven't already done that
5070 if (params->nrofobjects == 0)
5071 flush_handles(device);
5072
5073 ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5074 if (ret != PTP_RC_OK)
5075 return NULL;
5076
5077 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
5078
5079 // Ignore stuff we don't know how to handle...
5080 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
5081 /*
5082 * This row lets through undefined files for examination
5083 * since they may be forgotten OGG or FLAC files.
5084 */
5085 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5086 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5087 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5088 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5089 ) {
5090 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5091 return NULL;
5092 }
5093
5094 // Allocate a new track type
5095 track = LIBMTP_new_track_t();
5096
5097 // This is some sort of unique ID so we can keep track of the track.
5098 track->item_id = ob->oid;
5099 track->parent_id = ob->oi.ParentObject;
5100 track->storage_id = ob->oi.StorageID;
5101 track->modificationdate = ob->oi.ModificationDate;
5102
5103 track->filetype = mtptype;
5104
5105 // Original file-specific properties
5106 track->filesize = ob->oi.ObjectCompressedSize;
5107 if (ob->oi.Filename != NULL) {
5108 track->filename = strdup(ob->oi.Filename);
5109 }
5110
5111 /*
5112 * A special quirk for devices that doesn't quite
5113 * remember that some files marked as "unknown" type are
5114 * actually OGG or FLAC files. We look at the filename extension
5115 * and see if it happens that this was atleast named "ogg"
5116 * and fall back on this heuristic approach in that case,
5117 * for these bugged devices only.
5118 */
5119 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5120 track->filename != NULL) {
5121 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5122 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5123 has_ogg_extension(track->filename))
5124 track->filetype = LIBMTP_FILETYPE_OGG;
5125 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5126 has_flac_extension(track->filename))
5127 track->filetype = LIBMTP_FILETYPE_FLAC;
5128 else {
5129 // This was not an OGG/FLAC file so discard it
5130 LIBMTP_destroy_track_t(track);
5131 return NULL;
5132 }
5133 }
5134 get_track_metadata(device, ob->oi.ObjectFormat, track);
5135 return track;
5136 }
5137
5138 /**
5139 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5140 * to isolate the internal type.
5141 */
get_func_wrapper(PTPParams * params,void * priv,unsigned long wantlen,unsigned char * data,unsigned long * gotlen)5142 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5143 {
5144 MTPDataHandler *handler = (MTPDataHandler *)priv;
5145 uint16_t ret;
5146 uint32_t local_gotlen = 0;
5147 ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5148 *gotlen = local_gotlen;
5149 switch (ret)
5150 {
5151 case LIBMTP_HANDLER_RETURN_OK:
5152 return PTP_RC_OK;
5153 case LIBMTP_HANDLER_RETURN_ERROR:
5154 return PTP_ERROR_IO;
5155 case LIBMTP_HANDLER_RETURN_CANCEL:
5156 return PTP_ERROR_CANCEL;
5157 default:
5158 return PTP_ERROR_IO;
5159 }
5160 }
5161
5162 /**
5163 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5164 * to isolate the internal type.
5165 */
put_func_wrapper(PTPParams * params,void * priv,unsigned long sendlen,unsigned char * data)5166 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data)
5167 {
5168 MTPDataHandler *handler = (MTPDataHandler *)priv;
5169 uint16_t ret;
5170 uint32_t local_putlen = 0;
5171
5172 ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5173
5174 switch (ret)
5175 {
5176 case LIBMTP_HANDLER_RETURN_OK:
5177 if (local_putlen != sendlen)
5178 return PTP_ERROR_IO;
5179 return PTP_RC_OK;
5180 case LIBMTP_HANDLER_RETURN_ERROR:
5181 return PTP_ERROR_IO;
5182 case LIBMTP_HANDLER_RETURN_CANCEL:
5183 return PTP_ERROR_CANCEL;
5184 default:
5185 return PTP_ERROR_IO;
5186 }
5187 }
5188
5189 /**
5190 * This gets a file off the device to a local file identified
5191 * by a filename.
5192 * @param device a pointer to the device to get the track from.
5193 * @param id the file ID of the file to retrieve.
5194 * @param path a filename to use for the retrieved file.
5195 * @param callback a progress indicator function or NULL to ignore.
5196 * @param data a user-defined pointer that is passed along to
5197 * the <code>progress</code> function in order to
5198 * pass along some user defined data to the progress
5199 * updates. If not used, set this to NULL.
5200 * @return 0 if the transfer was successful, any other value means
5201 * failure.
5202 * @see LIBMTP_Get_File_To_File_Descriptor()
5203 */
LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t * device,uint32_t const id,char const * const path,LIBMTP_progressfunc_t const callback,void const * const data)5204 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5205 char const * const path, LIBMTP_progressfunc_t const callback,
5206 void const * const data)
5207 {
5208 int fd = -1;
5209 int ret;
5210
5211 // Sanity check
5212 if (path == NULL) {
5213 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5214 return -1;
5215 }
5216
5217 // Open file
5218 #ifdef __WIN32__
5219 #ifdef USE_WINDOWS_IO_H
5220 if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5221 #else
5222 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5223 #endif
5224 #else
5225 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5226 #endif
5227 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5228 return -1;
5229 }
5230
5231 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5232
5233 // Close file
5234 close(fd);
5235
5236 // Delete partial file.
5237 if (ret == -1) {
5238 unlink(path);
5239 }
5240
5241 return ret;
5242 }
5243
5244 /**
5245 * This gets a file off the device to a file identified
5246 * by a file descriptor.
5247 *
5248 * This function can potentially be used for streaming
5249 * files off the device for playback or broadcast for example,
5250 * by downloading the file into a stream sink e.g. a socket.
5251 *
5252 * @param device a pointer to the device to get the file from.
5253 * @param id the file ID of the file to retrieve.
5254 * @param fd a local file descriptor to write the file to.
5255 * @param callback a progress indicator function or NULL to ignore.
5256 * @param data a user-defined pointer that is passed along to
5257 * the <code>progress</code> function in order to
5258 * pass along some user defined data to the progress
5259 * updates. If not used, set this to NULL.
5260 * @return 0 if the transfer was successful, any other value means
5261 * failure.
5262 * @see LIBMTP_Get_File_To_File()
5263 */
5264 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5265 uint32_t const id,
5266 int const fd,
5267 LIBMTP_progressfunc_t const callback,
5268 void const * const data)
5269 {
5270 uint16_t ret;
5271 PTPParams *params = (PTPParams *) device->params;
5272 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5273 PTPObject *ob;
5274
5275 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5276 if (ret != PTP_RC_OK) {
5277 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5278 return -1;
5279 }
5280 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5281 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5282 return -1;
5283 }
5284
5285 // Callbacks
5286 ptp_usb->callback_active = 1;
5287 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5288 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5289 ptp_usb->current_transfer_complete = 0;
5290 ptp_usb->current_transfer_callback = callback;
5291 ptp_usb->current_transfer_callback_data = data;
5292
5293 ret = ptp_getobject_tofd(params, id, fd);
5294
5295 ptp_usb->callback_active = 0;
5296 ptp_usb->current_transfer_callback = NULL;
5297 ptp_usb->current_transfer_callback_data = NULL;
5298
5299 if (ret == PTP_ERROR_CANCEL) {
5300 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5301 return -1;
5302 }
5303 if (ret != PTP_RC_OK) {
5304 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5305 return -1;
5306 }
5307
5308 return 0;
5309 }
5310
5311 /**
5312 * This gets a file off the device and calls put_func
5313 * with chunks of data
5314 *
5315 * @param device a pointer to the device to get the file from.
5316 * @param id the file ID of the file to retrieve.
5317 * @param put_func the function to call when we have data.
5318 * @param priv the user-defined pointer that is passed to
5319 * <code>put_func</code>.
5320 * @param callback a progress indicator function or NULL to ignore.
5321 * @param data a user-defined pointer that is passed along to
5322 * the <code>progress</code> function in order to
5323 * pass along some user defined data to the progress
5324 * updates. If not used, set this to NULL.
5325 * @return 0 if the transfer was successful, any other value means
5326 * failure.
5327 */
5328 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5329 uint32_t const id,
5330 MTPDataPutFunc put_func,
5331 void * priv,
5332 LIBMTP_progressfunc_t const callback,
5333 void const * const data)
5334 {
5335 PTPObject *ob;
5336 uint16_t ret;
5337 PTPParams *params = (PTPParams *) device->params;
5338 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5339
5340 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5341 if (ret != PTP_RC_OK) {
5342 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5343 return -1;
5344 }
5345 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5346 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5347 return -1;
5348 }
5349
5350 // Callbacks
5351 ptp_usb->callback_active = 1;
5352 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5353 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5354 ptp_usb->current_transfer_complete = 0;
5355 ptp_usb->current_transfer_callback = callback;
5356 ptp_usb->current_transfer_callback_data = data;
5357
5358 MTPDataHandler mtp_handler;
5359 mtp_handler.getfunc = NULL;
5360 mtp_handler.putfunc = put_func;
5361 mtp_handler.priv = priv;
5362
5363 PTPDataHandler handler;
5364 handler.getfunc = NULL;
5365 handler.putfunc = put_func_wrapper;
5366 handler.priv = &mtp_handler;
5367
5368 ret = ptp_getobject_to_handler(params, id, &handler);
5369
5370 ptp_usb->callback_active = 0;
5371 ptp_usb->current_transfer_callback = NULL;
5372 ptp_usb->current_transfer_callback_data = NULL;
5373
5374 if (ret == PTP_ERROR_CANCEL) {
5375 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5376 return -1;
5377 }
5378 if (ret != PTP_RC_OK) {
5379 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5380 return -1;
5381 }
5382
5383 return 0;
5384 }
5385
5386
5387 /**
5388 * This gets a track off the device to a file identified
5389 * by a filename. This is actually just a wrapper for the
5390 * \c LIBMTP_Get_Track_To_File() function.
5391 * @param device a pointer to the device to get the track from.
5392 * @param id the track ID of the track to retrieve.
5393 * @param path a filename to use for the retrieved track.
5394 * @param callback a progress indicator function or NULL to ignore.
5395 * @param data a user-defined pointer that is passed along to
5396 * the <code>progress</code> function in order to
5397 * pass along some user defined data to the progress
5398 * updates. If not used, set this to NULL.
5399 * @return 0 if the transfer was successful, any other value means
5400 * failure.
5401 * @see LIBMTP_Get_Track_To_File_Descriptor()
5402 */
5403 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5404 char const * const path, LIBMTP_progressfunc_t const callback,
5405 void const * const data)
5406 {
5407 // This is just a wrapper
5408 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5409 }
5410
5411 /**
5412 * This gets a track off the device to a file identified
5413 * by a file descriptor. This is actually just a wrapper for
5414 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5415 * @param device a pointer to the device to get the track from.
5416 * @param id the track ID of the track to retrieve.
5417 * @param fd a file descriptor to write the track to.
5418 * @param callback a progress indicator function or NULL to ignore.
5419 * @param data a user-defined pointer that is passed along to
5420 * the <code>progress</code> function in order to
5421 * pass along some user defined data to the progress
5422 * updates. If not used, set this to NULL.
5423 * @return 0 if the transfer was successful, any other value means
5424 * failure.
5425 * @see LIBMTP_Get_Track_To_File()
5426 */
5427 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5428 uint32_t const id,
5429 int const fd,
5430 LIBMTP_progressfunc_t const callback,
5431 void const * const data)
5432 {
5433 // This is just a wrapper
5434 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5435 }
5436
5437 /**
5438 * This gets a track off the device to a handler function.
5439 * This is actually just a wrapper for
5440 * the \c LIBMTP_Get_File_To_Handler() function.
5441 * @param device a pointer to the device to get the track from.
5442 * @param id the track ID of the track to retrieve.
5443 * @param put_func the function to call when we have data.
5444 * @param priv the user-defined pointer that is passed to
5445 * <code>put_func</code>.
5446 * @param callback a progress indicator function or NULL to ignore.
5447 * @param data a user-defined pointer that is passed along to
5448 * the <code>progress</code> function in order to
5449 * pass along some user defined data to the progress
5450 * updates. If not used, set this to NULL.
5451 * @return 0 if the transfer was successful, any other value means
5452 * failure.
5453 */
5454 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5455 uint32_t const id,
5456 MTPDataPutFunc put_func,
5457 void * priv,
5458 LIBMTP_progressfunc_t const callback,
5459 void const * const data)
5460 {
5461 // This is just a wrapper
5462 return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5463 }
5464
5465 /**
5466 * This function sends a track from a local file to an
5467 * MTP device. A filename and a set of metadata must be
5468 * given as input.
5469 * @param device a pointer to the device to send the track to.
5470 * @param path the filename of a local file which will be sent.
5471 * @param metadata a track metadata set to be written along with the file.
5472 * After this call the field <code>metadata->item_id</code>
5473 * will contain the new track ID. Other fields such
5474 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5475 * or <code>metadata->storage_id</code> may also change during this
5476 * operation due to device restrictions, so do not rely on the
5477 * contents of this struct to be preserved in any way.
5478 * <ul>
5479 * <li><code>metadata->parent_id</code> should be set to the parent
5480 * (e.g. folder) to store this track in. Since some
5481 * devices are a bit picky about where files
5482 * are placed, a default folder will be chosen if libmtp
5483 * has detected one for the current filetype and this
5484 * parameter is set to 0. If this is 0 and no default folder
5485 * can be found, the file will be stored in the root folder.
5486 * <li><code>metadata->storage_id</code> should be set to the
5487 * desired storage (e.g. memory card or whatever your device
5488 * presents) to store this track in. Setting this to 0 will store
5489 * the track on the primary storage.
5490 * </ul>
5491 * @param callback a progress indicator function or NULL to ignore.
5492 * @param data a user-defined pointer that is passed along to
5493 * the <code>progress</code> function in order to
5494 * pass along some user defined data to the progress
5495 * updates. If not used, set this to NULL.
5496 * @return 0 if the transfer was successful, any other value means
5497 * failure.
5498 * @see LIBMTP_Send_Track_From_File_Descriptor()
5499 * @see LIBMTP_Send_File_From_File()
5500 * @see LIBMTP_Delete_Object()
5501 */
5502 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5503 char const * const path, LIBMTP_track_t * const metadata,
5504 LIBMTP_progressfunc_t const callback,
5505 void const * const data)
5506 {
5507 int fd;
5508 int ret;
5509
5510 // Sanity check
5511 if (path == NULL) {
5512 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5513 return -1;
5514 }
5515
5516 // Open file
5517 #ifdef __WIN32__
5518 #ifdef USE_WINDOWS_IO_H
5519 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5520 #else
5521 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5522 #endif
5523 #else
5524 if ( (fd = open(path, O_RDONLY)) == -1) {
5525 #endif
5526 LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5527 return -1;
5528 }
5529
5530 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5531
5532 // Close file.
5533 #ifdef USE_WINDOWS_IO_H
5534 _close(fd);
5535 #else
5536 close(fd);
5537 #endif
5538
5539 return ret;
5540 }
5541
5542
5543
5544 /**
5545 * This helper function checks if a filename already exists on the device
5546 * @param PTPParams*
5547 * @param string representing the filename
5548 * @return 0 if the filename doesn't exist, -1 if it does
5549 */
5550 static int check_filename_exists(PTPParams* params, char const * const filename)
5551 {
5552 int i;
5553
5554 for (i = 0; i < params->nrofobjects; i++) {
5555 char *fname = params->objects[i].oi.Filename;
5556 if ((fname != NULL) && (strcmp(filename, fname) == 0))
5557 {
5558 return -1;
5559 }
5560 }
5561
5562 return 0;
5563 }
5564
5565 /**
5566 * This helper function returns a unique filename, with a random string before the extension
5567 * @param string representing the original filename
5568 * @return a string representing the unique filename
5569 */
5570 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5571 {
5572 int suffix;
5573 char * extension_position;
5574
5575 if (check_filename_exists(params, filename))
5576 {
5577 extension_position = strrchr(filename,'.');
5578
5579 char basename[extension_position - filename + 1];
5580 strncpy(basename, filename, extension_position - filename);
5581 basename[extension_position - filename] = '\0';
5582
5583 suffix = 1;
5584 char newname[ strlen(basename) + 6 + strlen(extension_position)];
5585 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5586 while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5587 suffix++;
5588 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5589 }
5590 return strdup(newname);
5591 }
5592 else
5593 {
5594 return strdup(filename);
5595 }
5596 }
5597
5598 /**
5599 * This function sends a track from a file descriptor to an
5600 * MTP device. A filename and a set of metadata must be
5601 * given as input.
5602 * @param device a pointer to the device to send the track to.
5603 * @param fd the filedescriptor for a local file which will be sent.
5604 * @param metadata a track metadata set to be written along with the file.
5605 * After this call the field <code>metadata->item_id</code>
5606 * will contain the new track ID. Other fields such
5607 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5608 * or <code>metadata->storage_id</code> may also change during this
5609 * operation due to device restrictions, so do not rely on the
5610 * contents of this struct to be preserved in any way.
5611 * <ul>
5612 * <li><code>metadata->parent_id</code> should be set to the parent
5613 * (e.g. folder) to store this track in. Since some
5614 * devices are a bit picky about where files
5615 * are placed, a default folder will be chosen if libmtp
5616 * has detected one for the current filetype and this
5617 * parameter is set to 0. If this is 0 and no default folder
5618 * can be found, the file will be stored in the root folder.
5619 * <li><code>metadata->storage_id</code> should be set to the
5620 * desired storage (e.g. memory card or whatever your device
5621 * presents) to store this track in. Setting this to 0 will store
5622 * the track on the primary storage.
5623 * </ul>
5624 * @param callback a progress indicator function or NULL to ignore.
5625 * @param data a user-defined pointer that is passed along to
5626 * the <code>progress</code> function in order to
5627 * pass along some user defined data to the progress
5628 * updates. If not used, set this to NULL.
5629 * @return 0 if the transfer was successful, any other value means
5630 * failure.
5631 * @see LIBMTP_Send_Track_From_File()
5632 * @see LIBMTP_Delete_Object()
5633 */
5634 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5635 int const fd, LIBMTP_track_t * const metadata,
5636 LIBMTP_progressfunc_t const callback,
5637 void const * const data)
5638 {
5639 int subcall_ret;
5640 LIBMTP_file_t filedata;
5641 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5642 PTPParams *params = (PTPParams *) device->params;
5643
5644 // Sanity check, is this really a track?
5645 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5646 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5647 "LIBMTP_Send_Track_From_File_Descriptor(): "
5648 "I don't think this is actually a track, strange filetype...");
5649 }
5650
5651 // Wrap around the file transfer function
5652 filedata.item_id = metadata->item_id;
5653 filedata.parent_id = metadata->parent_id;
5654 filedata.storage_id = metadata->storage_id;
5655 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5656 filedata.filename = generate_unique_filename(params, metadata->filename);
5657 }
5658 else {
5659 filedata.filename = metadata->filename;
5660 }
5661 filedata.filesize = metadata->filesize;
5662 filedata.filetype = metadata->filetype;
5663 filedata.next = NULL;
5664
5665 subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5666 fd,
5667 &filedata,
5668 callback,
5669 data);
5670
5671 if (subcall_ret != 0) {
5672 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5673 "LIBMTP_Send_Track_From_File_Descriptor(): "
5674 "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5675 // We used to delete the file here, but don't... It might be OK after all.
5676 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5677 return -1;
5678 }
5679
5680 // Pick up new item (and parent, storage) ID
5681 metadata->item_id = filedata.item_id;
5682 metadata->parent_id = filedata.parent_id;
5683 metadata->storage_id = filedata.storage_id;
5684
5685 // Set track metadata for the new fine track
5686 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5687 if (subcall_ret != 0) {
5688 // Subcall will add error to errorstack
5689 // We used to delete the file here, but don't... It might be OK after all.
5690 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5691 return -1;
5692 }
5693
5694 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5695 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5696
5697 return 0;
5698 }
5699
5700 /**
5701 * This function sends a track from a handler function to an
5702 * MTP device. A filename and a set of metadata must be
5703 * given as input.
5704 * @param device a pointer to the device to send the track to.
5705 * @param get_func the function to call when we have data.
5706 * @param priv the user-defined pointer that is passed to
5707 * <code>get_func</code>.
5708 * @param metadata a track metadata set to be written along with the file.
5709 * After this call the field <code>metadata->item_id</code>
5710 * will contain the new track ID. Other fields such
5711 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5712 * or <code>metadata->storage_id</code> may also change during this
5713 * operation due to device restrictions, so do not rely on the
5714 * contents of this struct to be preserved in any way.
5715 * <ul>
5716 * <li><code>metadata->parent_id</code> should be set to the parent
5717 * (e.g. folder) to store this track in. Since some
5718 * devices are a bit picky about where files
5719 * are placed, a default folder will be chosen if libmtp
5720 * has detected one for the current filetype and this
5721 * parameter is set to 0. If this is 0 and no default folder
5722 * can be found, the file will be stored in the root folder.
5723 * <li><code>metadata->storage_id</code> should be set to the
5724 * desired storage (e.g. memory card or whatever your device
5725 * presents) to store this track in. Setting this to 0 will store
5726 * the track on the primary storage.
5727 * </ul>
5728 * @param callback a progress indicator function or NULL to ignore.
5729 * @param data a user-defined pointer that is passed along to
5730 * the <code>progress</code> function in order to
5731 * pass along some user defined data to the progress
5732 * updates. If not used, set this to NULL.
5733 * @return 0 if the transfer was successful, any other value means
5734 * failure.
5735 * @see LIBMTP_Send_Track_From_File()
5736 * @see LIBMTP_Delete_Object()
5737 */
5738 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5739 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5740 LIBMTP_progressfunc_t const callback,
5741 void const * const data)
5742 {
5743 int subcall_ret;
5744 LIBMTP_file_t filedata;
5745 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5746 PTPParams *params = (PTPParams *) device->params;
5747
5748 // Sanity check, is this really a track?
5749 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5750 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5751 "LIBMTP_Send_Track_From_Handler(): "
5752 "I don't think this is actually a track, strange filetype...");
5753 }
5754
5755 // Wrap around the file transfer function
5756 filedata.item_id = metadata->item_id;
5757 filedata.parent_id = metadata->parent_id;
5758 filedata.storage_id = metadata->storage_id;
5759 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5760 filedata.filename = generate_unique_filename(params, metadata->filename);
5761 }
5762 else {
5763 filedata.filename = metadata->filename;
5764 }
5765 filedata.filesize = metadata->filesize;
5766 filedata.filetype = metadata->filetype;
5767 filedata.next = NULL;
5768
5769 subcall_ret = LIBMTP_Send_File_From_Handler(device,
5770 get_func,
5771 priv,
5772 &filedata,
5773 callback,
5774 data);
5775
5776 if (subcall_ret != 0) {
5777 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5778 "LIBMTP_Send_Track_From_Handler(): "
5779 "subcall to LIBMTP_Send_File_From_Handler failed.");
5780 // We used to delete the file here, but don't... It might be OK after all.
5781 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5782 return -1;
5783 }
5784
5785 // Pick up new item (and parent, storage) ID
5786 metadata->item_id = filedata.item_id;
5787 metadata->parent_id = filedata.parent_id;
5788 metadata->storage_id = filedata.storage_id;
5789
5790 // Set track metadata for the new fine track
5791 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5792 if (subcall_ret != 0) {
5793 // Subcall will add error to errorstack
5794 // We used to delete the file here, but don't... It might be OK after all.
5795 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5796 return -1;
5797 }
5798
5799 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5800 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5801
5802 return 0;
5803 }
5804
5805 /**
5806 * This function sends a local file to an MTP device.
5807 * A filename and a set of metadata must be
5808 * given as input.
5809 * @param device a pointer to the device to send the track to.
5810 * @param path the filename of a local file which will be sent.
5811 * @param filedata a file metadata set to be written along with the file.
5812 * After this call the field <code>filedata->item_id</code>
5813 * will contain the new file ID. Other fields such
5814 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5815 * or <code>filedata->storage_id</code> may also change during this
5816 * operation due to device restrictions, so do not rely on the
5817 * contents of this struct to be preserved in any way.
5818 * <ul>
5819 * <li><code>filedata->parent_id</code> should be set to the parent
5820 * (e.g. folder) to store this file in. If this is 0,
5821 * the file will be stored in the root folder.
5822 * <li><code>filedata->storage_id</code> should be set to the
5823 * desired storage (e.g. memory card or whatever your device
5824 * presents) to store this file in. Setting this to 0 will store
5825 * the file on the primary storage.
5826 * </ul>
5827 * @param callback a progress indicator function or NULL to ignore.
5828 * @param data a user-defined pointer that is passed along to
5829 * the <code>progress</code> function in order to
5830 * pass along some user defined data to the progress
5831 * updates. If not used, set this to NULL.
5832 * @return 0 if the transfer was successful, any other value means
5833 * failure.
5834 * @see LIBMTP_Send_File_From_File_Descriptor()
5835 * @see LIBMTP_Delete_Object()
5836 */
5837 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5838 char const * const path, LIBMTP_file_t * const filedata,
5839 LIBMTP_progressfunc_t const callback,
5840 void const * const data)
5841 {
5842 int fd;
5843 int ret;
5844
5845 // Sanity check
5846 if (path == NULL) {
5847 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5848 return -1;
5849 }
5850
5851 // Open file
5852 #ifdef __WIN32__
5853 #ifdef USE_WINDOWS_IO_H
5854 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5855 #else
5856 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5857 #endif
5858 #else
5859 if ( (fd = open(path, O_RDONLY)) == -1) {
5860 #endif
5861 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5862 return -1;
5863 }
5864
5865 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5866
5867 // Close file.
5868 #ifdef USE_WINDOWS_IO_H
5869 _close(fd);
5870 #else
5871 close(fd);
5872 #endif
5873
5874 return ret;
5875 }
5876
5877 /**
5878 * This function sends a generic file from a file descriptor to an
5879 * MTP device. A filename and a set of metadata must be
5880 * given as input.
5881 *
5882 * This can potentially be used for sending in a stream of unknown
5883 * length. Send music files with
5884 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5885 *
5886 * @param device a pointer to the device to send the file to.
5887 * @param fd the filedescriptor for a local file which will be sent.
5888 * @param filedata a file metadata set to be written along with the file.
5889 * After this call the field <code>filedata->item_id</code>
5890 * will contain the new file ID. Other fields such
5891 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5892 * or <code>filedata->storage_id</code> may also change during this
5893 * operation due to device restrictions, so do not rely on the
5894 * contents of this struct to be preserved in any way.
5895 * <ul>
5896 * <li><code>filedata->parent_id</code> should be set to the parent
5897 * (e.g. folder) to store this file in. If this is 0,
5898 * the file will be stored in the root folder.
5899 * <li><code>filedata->storage_id</code> should be set to the
5900 * desired storage (e.g. memory card or whatever your device
5901 * presents) to store this file in. Setting this to 0 will store
5902 * the file on the primary storage.
5903 * </ul>
5904 * @param callback a progress indicator function or NULL to ignore.
5905 * @param data a user-defined pointer that is passed along to
5906 * the <code>progress</code> function in order to
5907 * pass along some user defined data to the progress
5908 * updates. If not used, set this to NULL.
5909 * @return 0 if the transfer was successful, any other value means
5910 * failure.
5911 * @see LIBMTP_Send_File_From_File()
5912 * @see LIBMTP_Send_Track_From_File_Descriptor()
5913 * @see LIBMTP_Delete_Object()
5914 */
5915 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5916 int const fd, LIBMTP_file_t * const filedata,
5917 LIBMTP_progressfunc_t const callback,
5918 void const * const data)
5919 {
5920 uint16_t ret;
5921 PTPParams *params = (PTPParams *) device->params;
5922 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5923 LIBMTP_file_t *newfilemeta;
5924 int oldtimeout;
5925 int timeout;
5926
5927 if (send_file_object_info(device, filedata))
5928 {
5929 // no need to output an error since send_file_object_info will already have done so
5930 return -1;
5931 }
5932
5933 // Callbacks
5934 ptp_usb->callback_active = 1;
5935 // The callback will deactivate itself after this amount of data has been sent
5936 // One BULK header for the request, one for the data phase. No parameters to the request.
5937 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5938 ptp_usb->current_transfer_complete = 0;
5939 ptp_usb->current_transfer_callback = callback;
5940 ptp_usb->current_transfer_callback_data = data;
5941
5942 /*
5943 * We might need to increase the timeout here, files can be pretty
5944 * large. Take the default timeout and add the calculated time for
5945 * this transfer
5946 */
5947 get_usb_device_timeout(ptp_usb, &oldtimeout);
5948 timeout = oldtimeout +
5949 (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5950 set_usb_device_timeout(ptp_usb, timeout);
5951
5952 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5953
5954 ptp_usb->callback_active = 0;
5955 ptp_usb->current_transfer_callback = NULL;
5956 ptp_usb->current_transfer_callback_data = NULL;
5957 set_usb_device_timeout(ptp_usb, oldtimeout);
5958
5959 if (ret == PTP_ERROR_CANCEL) {
5960 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5961 return -1;
5962 }
5963 if (ret != PTP_RC_OK) {
5964 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5965 "Could not send object.");
5966 return -1;
5967 }
5968
5969 add_object_to_cache(device, filedata->item_id);
5970
5971 /*
5972 * Get the device-assigned parent_id from the cache.
5973 * The operation that adds it to the cache will
5974 * look it up from the device, so we get the new
5975 * parent_id from the cache.
5976 */
5977 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5978 if (newfilemeta != NULL) {
5979 filedata->parent_id = newfilemeta->parent_id;
5980 filedata->storage_id = newfilemeta->storage_id;
5981 LIBMTP_destroy_file_t(newfilemeta);
5982 } else {
5983 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5984 "LIBMTP_Send_File_From_File_Descriptor(): "
5985 "Could not retrieve updated metadata.");
5986 return -1;
5987 }
5988
5989 return 0;
5990 }
5991
5992 /**
5993 * This function sends a generic file from a handler function to an
5994 * MTP device. A filename and a set of metadata must be
5995 * given as input.
5996 *
5997 * This can potentially be used for sending in a stream of unknown
5998 * length. Send music files with
5999 * <code>LIBMTP_Send_Track_From_Handler()</code>
6000 *
6001 * @param device a pointer to the device to send the file to.
6002 * @param get_func the function to call to get data to write
6003 * @param priv a user-defined pointer that is passed along to
6004 * <code>get_func</code>. If not used, this is set to NULL.
6005 * @param filedata a file metadata set to be written along with the file.
6006 * After this call the field <code>filedata->item_id</code>
6007 * will contain the new file ID. Other fields such
6008 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
6009 * or <code>filedata->storage_id</code> may also change during this
6010 * operation due to device restrictions, so do not rely on the
6011 * contents of this struct to be preserved in any way.
6012 * <ul>
6013 * <li><code>filedata->parent_id</code> should be set to the parent
6014 * (e.g. folder) to store this file in. If this is 0,
6015 * the file will be stored in the root folder.
6016 * <li><code>filedata->storage_id</code> should be set to the
6017 * desired storage (e.g. memory card or whatever your device
6018 * presents) to store this file in. Setting this to 0 will store
6019 * the file on the primary storage.
6020 * </ul>
6021 * @param callback a progress indicator function or NULL to ignore.
6022 * @param data a user-defined pointer that is passed along to
6023 * the <code>progress</code> function in order to
6024 * pass along some user defined data to the progress
6025 * updates. If not used, set this to NULL.
6026 * @return 0 if the transfer was successful, any other value means
6027 * failure.
6028 * @see LIBMTP_Send_File_From_File()
6029 * @see LIBMTP_Send_Track_From_File_Descriptor()
6030 * @see LIBMTP_Delete_Object()
6031 */
6032 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
6033 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
6034 LIBMTP_progressfunc_t const callback, void const * const data)
6035 {
6036 uint16_t ret;
6037 PTPParams *params = (PTPParams *) device->params;
6038 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6039 LIBMTP_file_t *newfilemeta;
6040
6041 if (send_file_object_info(device, filedata))
6042 {
6043 // no need to output an error since send_file_object_info will already have done so
6044 return -1;
6045 }
6046
6047 // Callbacks
6048 ptp_usb->callback_active = 1;
6049 // The callback will deactivate itself after this amount of data has been sent
6050 // One BULK header for the request, one for the data phase. No parameters to the request.
6051 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
6052 ptp_usb->current_transfer_complete = 0;
6053 ptp_usb->current_transfer_callback = callback;
6054 ptp_usb->current_transfer_callback_data = data;
6055
6056 MTPDataHandler mtp_handler;
6057 mtp_handler.getfunc = get_func;
6058 mtp_handler.putfunc = NULL;
6059 mtp_handler.priv = priv;
6060
6061 PTPDataHandler handler;
6062 handler.getfunc = get_func_wrapper;
6063 handler.putfunc = NULL;
6064 handler.priv = &mtp_handler;
6065
6066 ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
6067
6068 ptp_usb->callback_active = 0;
6069 ptp_usb->current_transfer_callback = NULL;
6070 ptp_usb->current_transfer_callback_data = NULL;
6071
6072 if (ret == PTP_ERROR_CANCEL) {
6073 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
6074 return -1;
6075 }
6076 if (ret != PTP_RC_OK) {
6077 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
6078 "Could not send object.");
6079 return -1;
6080 }
6081
6082 add_object_to_cache(device, filedata->item_id);
6083
6084 /*
6085 * Get the device-assined parent_id from the cache.
6086 * The operation that adds it to the cache will
6087 * look it up from the device, so we get the new
6088 * parent_id from the cache.
6089 */
6090 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6091 if (newfilemeta != NULL) {
6092 filedata->parent_id = newfilemeta->parent_id;
6093 filedata->storage_id = newfilemeta->storage_id;
6094 LIBMTP_destroy_file_t(newfilemeta);
6095 } else {
6096 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6097 "LIBMTP_Send_File_From_Handler(): "
6098 "Could not retrieve updated metadata.");
6099 return -1;
6100 }
6101
6102 return 0;
6103 }
6104
6105 /**
6106 * This function sends the file object info, ready for sendobject
6107 * @param device a pointer to the device to send the file to.
6108 * @param filedata a file metadata set to be written along with the file.
6109 * @return 0 if the transfer was successful, any other value means
6110 * failure.
6111 */
6112 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6113 {
6114 PTPParams *params = (PTPParams *) device->params;
6115 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6116 uint32_t store;
6117 int use_primary_storage = 1;
6118 uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6119 LIBMTP_devicestorage_t *storage;
6120 uint32_t localph = filedata->parent_id;
6121 uint16_t ret;
6122 int i;
6123
6124 #if 0
6125 // Sanity check: no zerolength files on some devices?
6126 // If the zerolength files cause problems on some devices,
6127 // then add a bug flag for this.
6128 if (filedata->filesize == 0) {
6129 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6130 "File of zero size.");
6131 return -1;
6132 }
6133 #endif
6134 if (filedata->storage_id != 0) {
6135 store = filedata->storage_id;
6136 } else {
6137 store = get_suggested_storage_id(device, filedata->filesize, localph);
6138 }
6139
6140 // Detect if something non-primary is in use.
6141 storage = device->storage;
6142 if (storage != NULL && store != storage->id) {
6143 use_primary_storage = 0;
6144 }
6145
6146 /*
6147 * If no destination folder was given, look up a default
6148 * folder if possible. Perhaps there is some way of retrieveing
6149 * the default folder for different forms of content, what
6150 * do I know, we use a fixed list in lack of any better method.
6151 * Some devices obviously need to have their files in certain
6152 * folders in order to find/display them at all (hello Creative),
6153 * so we have to have a method for this. We only do this if the
6154 * primary storage is in use.
6155 */
6156
6157 if (localph == 0 && use_primary_storage) {
6158 if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6159 localph = device->default_music_folder;
6160 } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6161 localph = device->default_video_folder;
6162 } else if (of == PTP_OFC_EXIF_JPEG ||
6163 of == PTP_OFC_JP2 ||
6164 of == PTP_OFC_JPX ||
6165 of == PTP_OFC_JFIF ||
6166 of == PTP_OFC_TIFF ||
6167 of == PTP_OFC_TIFF_IT ||
6168 of == PTP_OFC_BMP ||
6169 of == PTP_OFC_GIF ||
6170 of == PTP_OFC_PICT ||
6171 of == PTP_OFC_PNG ||
6172 of == PTP_OFC_MTP_WindowsImageFormat) {
6173 localph = device->default_picture_folder;
6174 } else if (of == PTP_OFC_MTP_vCalendar1 ||
6175 of == PTP_OFC_MTP_vCalendar2 ||
6176 of == PTP_OFC_MTP_UndefinedContact ||
6177 of == PTP_OFC_MTP_vCard2 ||
6178 of == PTP_OFC_MTP_vCard3 ||
6179 of == PTP_OFC_MTP_UndefinedCalendarItem) {
6180 localph = device->default_organizer_folder;
6181 } else if (of == PTP_OFC_Text) {
6182 localph = device->default_text_folder;
6183 }
6184 }
6185
6186 // Here we wire the type to unknown on bugged, but
6187 // Ogg or FLAC-supportive devices.
6188 if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6189 of = PTP_OFC_Undefined;
6190 }
6191 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6192 of = PTP_OFC_Undefined;
6193 }
6194
6195 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6196 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6197 /*
6198 * MTP enhanched does it this way (from a sniff):
6199 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6200 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6201 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6202 * Length: 0x00000020
6203 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
6204 * Code: 0x9808
6205 * Transaction ID: 0x0000001B
6206 * Param1: 0x00010001 <- store
6207 * Param2: 0xffffffff <- parent handle (-1 ?)
6208 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6209 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
6210 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6211 *
6212 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6213 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6214 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6215 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6216 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6217 * 00 4F DC 02 00 01 - dc4f = non consumable
6218 * Length: 0x00000046
6219 * Type: 0x0002 PTP_USB_CONTAINER_DATA
6220 * Code: 0x9808
6221 * Transaction ID: 0x0000001B
6222 * Metadata....
6223 * 0x00000003 <- Number of metadata items
6224 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6225 * 0xdc07 <- metadata type: file name
6226 * 0xffff <- metadata type: string
6227 * 0x0d <- number of (uint16_t) characters
6228 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6229 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6230 * 0xdc03 <- metadata type: protection status
6231 * 0x0004 <- metadata type: uint16_t
6232 * 0x0000 <- not protected
6233 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6234 * 0xdc4f <- non consumable
6235 * 0x0002 <- metadata type: uint8_t
6236 * 0x01 <- non-consumable (this device cannot display PDF)
6237 *
6238 * <- Read 0x18 bytes back
6239 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6240 * 00 00 00 00 01 40 00 00
6241 * Length: 0x000000018
6242 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
6243 * Code: 0x2001 PTP_OK
6244 * Transaction ID: 0x0000001B
6245 * Param1: 0x00010001 <- store
6246 * Param2: 0x00000000 <- parent handle
6247 * Param3: 0x00004001 <- new file/object ID
6248 *
6249 * -> PTP_OC_SendObject (0x100d)
6250 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
6251 * -> ... all the bytes ...
6252 * <- Read 0x0c bytes back
6253 * 0C 00 00 00 03 00 01 20 1C 00 00 00
6254 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
6255 */
6256 MTPProperties *props = NULL;
6257 int nrofprops = 0;
6258 MTPProperties *prop = NULL;
6259 uint16_t *properties = NULL;
6260 uint32_t propcnt = 0;
6261
6262 // default parent handle
6263 if (localph == 0)
6264 localph = 0xFFFFFFFFU; // Set to -1
6265
6266 // Must be 0x00000000U for new objects
6267 filedata->item_id = 0x00000000U;
6268
6269 ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6270
6271 for (i=0;i<propcnt;i++) {
6272 PTPObjectPropDesc opd;
6273
6274 ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6275 if (ret != PTP_RC_OK) {
6276 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6277 "could not get property description.");
6278 } else if (opd.GetSet) {
6279 switch (properties[i]) {
6280 case PTP_OPC_ObjectFileName:
6281 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6282 prop->ObjectHandle = filedata->item_id;
6283 prop->property = PTP_OPC_ObjectFileName;
6284 prop->datatype = PTP_DTC_STR;
6285 if (filedata->filename != NULL) {
6286 prop->propval.str = strdup(filedata->filename);
6287 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6288 strip_7bit_from_utf8(prop->propval.str);
6289 }
6290 }
6291 break;
6292 case PTP_OPC_ProtectionStatus:
6293 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6294 prop->ObjectHandle = filedata->item_id;
6295 prop->property = PTP_OPC_ProtectionStatus;
6296 prop->datatype = PTP_DTC_UINT16;
6297 prop->propval.u16 = 0x0000U; /* Not protected */
6298 break;
6299 case PTP_OPC_NonConsumable:
6300 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6301 prop->ObjectHandle = filedata->item_id;
6302 prop->property = PTP_OPC_NonConsumable;
6303 prop->datatype = PTP_DTC_UINT8;
6304 prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6305 break;
6306 case PTP_OPC_Name:
6307 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6308 prop->ObjectHandle = filedata->item_id;
6309 prop->property = PTP_OPC_Name;
6310 prop->datatype = PTP_DTC_STR;
6311 if (filedata->filename != NULL)
6312 prop->propval.str = strdup(filedata->filename);
6313 break;
6314 case PTP_OPC_DateModified:
6315 // Tag with current time if that is supported
6316 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6317 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6318 prop->ObjectHandle = filedata->item_id;
6319 prop->property = PTP_OPC_DateModified;
6320 prop->datatype = PTP_DTC_STR;
6321 prop->propval.str = get_iso8601_stamp();
6322 filedata->modificationdate = time(NULL);
6323 }
6324 break;
6325 }
6326 }
6327 ptp_free_objectpropdesc(&opd);
6328 }
6329 free(properties);
6330
6331 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6332 of, filedata->filesize, props, nrofprops);
6333
6334 /* Free property list */
6335 ptp_destroy_object_prop_list(props, nrofprops);
6336
6337 if (ret != PTP_RC_OK) {
6338 add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6339 "Could not send object property list.");
6340 if (ret == PTP_RC_AccessDenied) {
6341 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6342 }
6343 return -1;
6344 }
6345 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6346 PTPObjectInfo new_file;
6347
6348 memset(&new_file, 0, sizeof(PTPObjectInfo));
6349
6350 new_file.Filename = filedata->filename;
6351 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6352 strip_7bit_from_utf8(new_file.Filename);
6353 }
6354 if (filedata->filesize > 0xFFFFFFFFL) {
6355 // This is a kludge in the MTP standard for large files.
6356 new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6357 } else {
6358 new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6359 }
6360 new_file.ObjectFormat = of;
6361 new_file.StorageID = store;
6362 new_file.ParentObject = localph;
6363 new_file.ModificationDate = time(NULL);
6364
6365 // Create the object
6366 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6367
6368 if (ret != PTP_RC_OK) {
6369 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6370 "Could not send object info.");
6371 if (ret == PTP_RC_AccessDenied) {
6372 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6373 }
6374 return -1;
6375 }
6376 // NOTE: the char* pointers inside new_file are not copies so don't
6377 // try to destroy this objectinfo!
6378 }
6379
6380 // Now there IS an object with this parent handle.
6381 filedata->parent_id = localph;
6382
6383 return 0;
6384 }
6385
6386 /**
6387 * This function updates the MTP track object metadata on a
6388 * single file identified by an object ID.
6389 * @param device a pointer to the device to update the track
6390 * metadata on.
6391 * @param metadata a track metadata set to be written to the file.
6392 * notice that the <code>track_id</code> field of the
6393 * metadata structure must be correct so that the
6394 * function can update the right file. If some properties
6395 * of this metadata are set to NULL (strings) or 0
6396 * (numerical values) they will be discarded and the
6397 * track will not be tagged with these blank values.
6398 * @return 0 on success, any other value means failure. If some
6399 * or all of the properties fail to update we will still
6400 * return success. On some devices (notably iRiver T30)
6401 * properties that exist cannot be updated.
6402 */
6403 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6404 LIBMTP_track_t const * const metadata)
6405 {
6406 uint16_t ret;
6407 PTPParams *params = (PTPParams *) device->params;
6408 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6409 uint32_t i;
6410 uint16_t *properties = NULL;
6411 uint32_t propcnt = 0;
6412
6413 // First see which properties can be set on this file format and apply accordingly
6414 // i.e only try to update this metadata for object tags that exist on the current player.
6415 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6416 if (ret != PTP_RC_OK) {
6417 // Just bail out for now, nothing is ever set.
6418 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6419 "could not retrieve supported object properties.");
6420 return -1;
6421 }
6422 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6423 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6424 MTPProperties *props = NULL;
6425 MTPProperties *prop = NULL;
6426 int nrofprops = 0;
6427
6428 for (i=0;i<propcnt;i++) {
6429 PTPObjectPropDesc opd;
6430
6431 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6432 if (ret != PTP_RC_OK) {
6433 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6434 "could not get property description.");
6435 } else if (opd.GetSet) {
6436 switch (properties[i]) {
6437 case PTP_OPC_Name:
6438 if (metadata->title == NULL)
6439 break;
6440 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6441 prop->ObjectHandle = metadata->item_id;
6442 prop->property = PTP_OPC_Name;
6443 prop->datatype = PTP_DTC_STR;
6444 prop->propval.str = strdup(metadata->title);
6445 break;
6446 case PTP_OPC_AlbumName:
6447 if (metadata->album == NULL)
6448 break;
6449 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6450 prop->ObjectHandle = metadata->item_id;
6451 prop->property = PTP_OPC_AlbumName;
6452 prop->datatype = PTP_DTC_STR;
6453 prop->propval.str = strdup(metadata->album);
6454 break;
6455 case PTP_OPC_Artist:
6456 if (metadata->artist == NULL)
6457 break;
6458 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6459 prop->ObjectHandle = metadata->item_id;
6460 prop->property = PTP_OPC_Artist;
6461 prop->datatype = PTP_DTC_STR;
6462 prop->propval.str = strdup(metadata->artist);
6463 break;
6464 case PTP_OPC_Composer:
6465 if (metadata->composer == NULL)
6466 break;
6467 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6468 prop->ObjectHandle = metadata->item_id;
6469 prop->property = PTP_OPC_Composer;
6470 prop->datatype = PTP_DTC_STR;
6471 prop->propval.str = strdup(metadata->composer);
6472 break;
6473 case PTP_OPC_Genre:
6474 if (metadata->genre == NULL)
6475 break;
6476 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6477 prop->ObjectHandle = metadata->item_id;
6478 prop->property = PTP_OPC_Genre;
6479 prop->datatype = PTP_DTC_STR;
6480 prop->propval.str = strdup(metadata->genre);
6481 break;
6482 case PTP_OPC_Duration:
6483 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6484 prop->ObjectHandle = metadata->item_id;
6485 prop->property = PTP_OPC_Duration;
6486 prop->datatype = PTP_DTC_UINT32;
6487 prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6488 break;
6489 case PTP_OPC_Track:
6490 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6491 prop->ObjectHandle = metadata->item_id;
6492 prop->property = PTP_OPC_Track;
6493 prop->datatype = PTP_DTC_UINT16;
6494 prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6495 break;
6496 case PTP_OPC_OriginalReleaseDate:
6497 if (metadata->date == NULL)
6498 break;
6499 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6500 prop->ObjectHandle = metadata->item_id;
6501 prop->property = PTP_OPC_OriginalReleaseDate;
6502 prop->datatype = PTP_DTC_STR;
6503 prop->propval.str = strdup(metadata->date);
6504 break;
6505 case PTP_OPC_SampleRate:
6506 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6507 prop->ObjectHandle = metadata->item_id;
6508 prop->property = PTP_OPC_SampleRate;
6509 prop->datatype = PTP_DTC_UINT32;
6510 prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6511 break;
6512 case PTP_OPC_NumberOfChannels:
6513 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6514 prop->ObjectHandle = metadata->item_id;
6515 prop->property = PTP_OPC_NumberOfChannels;
6516 prop->datatype = PTP_DTC_UINT16;
6517 prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6518 break;
6519 case PTP_OPC_AudioWAVECodec:
6520 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6521 prop->ObjectHandle = metadata->item_id;
6522 prop->property = PTP_OPC_AudioWAVECodec;
6523 prop->datatype = PTP_DTC_UINT32;
6524 prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6525 break;
6526 case PTP_OPC_AudioBitRate:
6527 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6528 prop->ObjectHandle = metadata->item_id;
6529 prop->property = PTP_OPC_AudioBitRate;
6530 prop->datatype = PTP_DTC_UINT32;
6531 prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6532 break;
6533 case PTP_OPC_BitRateType:
6534 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6535 prop->ObjectHandle = metadata->item_id;
6536 prop->property = PTP_OPC_BitRateType;
6537 prop->datatype = PTP_DTC_UINT16;
6538 prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6539 break;
6540 case PTP_OPC_Rating:
6541 // TODO: shall this be set for rating 0?
6542 if (metadata->rating == 0)
6543 break;
6544 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6545 prop->ObjectHandle = metadata->item_id;
6546 prop->property = PTP_OPC_Rating;
6547 prop->datatype = PTP_DTC_UINT16;
6548 prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6549 break;
6550 case PTP_OPC_UseCount:
6551 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6552 prop->ObjectHandle = metadata->item_id;
6553 prop->property = PTP_OPC_UseCount;
6554 prop->datatype = PTP_DTC_UINT32;
6555 prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6556 break;
6557 case PTP_OPC_DateModified:
6558 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6559 // Tag with current time if that is supported
6560 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6561 prop->ObjectHandle = metadata->item_id;
6562 prop->property = PTP_OPC_DateModified;
6563 prop->datatype = PTP_DTC_STR;
6564 prop->propval.str = get_iso8601_stamp();
6565 }
6566 break;
6567 default:
6568 break;
6569 }
6570 }
6571 ptp_free_objectpropdesc(&opd);
6572 }
6573
6574 // NOTE: File size is not updated, this should not change anyway.
6575 // neither will we change the filename.
6576
6577 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6578
6579 ptp_destroy_object_prop_list(props, nrofprops);
6580
6581 if (ret != PTP_RC_OK) {
6582 // TODO: return error of which property we couldn't set
6583 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6584 "could not set object property list.");
6585 free(properties);
6586 return -1;
6587 }
6588
6589 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6590 for (i=0;i<propcnt;i++) {
6591 PTPObjectPropDesc opd;
6592
6593 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6594 if (ret != PTP_RC_OK) {
6595 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6596 "could not get property description.");
6597 } else if (opd.GetSet) {
6598 switch (properties[i]) {
6599 case PTP_OPC_Name:
6600 // Update title
6601 ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6602 if (ret != 0) {
6603 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6604 "could not set track title.");
6605 }
6606 break;
6607 case PTP_OPC_AlbumName:
6608 // Update album
6609 ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6610 if (ret != 0) {
6611 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6612 "could not set track album name.");
6613 }
6614 break;
6615 case PTP_OPC_Artist:
6616 // Update artist
6617 ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6618 if (ret != 0) {
6619 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6620 "could not set track artist name.");
6621 }
6622 break;
6623 case PTP_OPC_Composer:
6624 // Update composer
6625 ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6626 if (ret != 0) {
6627 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6628 "could not set track composer name.");
6629 }
6630 break;
6631 case PTP_OPC_Genre:
6632 // Update genre (but only if valid)
6633 if (metadata->genre) {
6634 ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6635 if (ret != 0) {
6636 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6637 "could not set genre.");
6638 }
6639 }
6640 break;
6641 case PTP_OPC_Duration:
6642 // Update duration
6643 if (metadata->duration != 0) {
6644 ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6645 if (ret != 0) {
6646 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6647 "could not set track duration.");
6648 }
6649 }
6650 break;
6651 case PTP_OPC_Track:
6652 // Update track number.
6653 if (metadata->tracknumber != 0) {
6654 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6655 if (ret != 0) {
6656 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6657 "could not set track tracknumber.");
6658 }
6659 }
6660 break;
6661 case PTP_OPC_OriginalReleaseDate:
6662 // Update creation datetime
6663 // The date can be zero, but some devices do not support setting zero
6664 // dates (and it seems that a zero date should never be set anyway)
6665 if (metadata->date) {
6666 ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6667 if (ret != 0) {
6668 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6669 "could not set track release date.");
6670 }
6671 }
6672 break;
6673 // These are, well not so important.
6674 case PTP_OPC_SampleRate:
6675 // Update sample rate
6676 if (metadata->samplerate != 0) {
6677 ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6678 if (ret != 0) {
6679 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6680 "could not set samplerate.");
6681 }
6682 }
6683 break;
6684 case PTP_OPC_NumberOfChannels:
6685 // Update number of channels
6686 if (metadata->nochannels != 0) {
6687 ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6688 if (ret != 0) {
6689 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6690 "could not set number of channels.");
6691 }
6692 }
6693 break;
6694 case PTP_OPC_AudioWAVECodec:
6695 // Update WAVE codec
6696 if (metadata->wavecodec != 0) {
6697 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6698 if (ret != 0) {
6699 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6700 "could not set WAVE codec.");
6701 }
6702 }
6703 break;
6704 case PTP_OPC_AudioBitRate:
6705 // Update bitrate
6706 if (metadata->bitrate != 0) {
6707 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6708 if (ret != 0) {
6709 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6710 "could not set bitrate.");
6711 }
6712 }
6713 break;
6714 case PTP_OPC_BitRateType:
6715 // Update bitrate type
6716 if (metadata->bitratetype != 0) {
6717 ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6718 if (ret != 0) {
6719 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6720 "could not set bitratetype.");
6721 }
6722 }
6723 break;
6724 case PTP_OPC_Rating:
6725 // Update user rating
6726 // TODO: shall this be set for rating 0?
6727 if (metadata->rating != 0) {
6728 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6729 if (ret != 0) {
6730 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6731 "could not set user rating.");
6732 }
6733 }
6734 break;
6735 case PTP_OPC_UseCount:
6736 // Update use count, set even to zero if desired.
6737 ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6738 if (ret != 0) {
6739 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6740 "could not set use count.");
6741 }
6742 break;
6743 case PTP_OPC_DateModified:
6744 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6745 // Update modification time if supported
6746 char *tmpstamp = get_iso8601_stamp();
6747 ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6748 if (ret != 0) {
6749 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6750 "could not set modification date.");
6751 }
6752 free(tmpstamp);
6753 }
6754 break;
6755
6756 // NOTE: File size is not updated, this should not change anyway.
6757 // neither will we change the filename.
6758 default:
6759 break;
6760 }
6761 }
6762 ptp_free_objectpropdesc(&opd);
6763 }
6764 } else {
6765 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6766 "Your device doesn't seem to support any known way of setting metadata.");
6767 free(properties);
6768 return -1;
6769 }
6770
6771 // update cached object properties if metadata cache exists
6772 update_metadata_cache(device, metadata->item_id);
6773
6774 free(properties);
6775
6776 return 0;
6777 }
6778
6779 /**
6780 * This function deletes a single file, track, playlist, folder or
6781 * any other object off the MTP device, identified by the object ID.
6782 *
6783 * If you delete a folder, there is no guarantee that the device will
6784 * really delete all the files that were in that folder, rather it is
6785 * expected that they will not be deleted, and will turn up in object
6786 * listings with parent set to a non-existant object ID. The safe way
6787 * to do this is to recursively delete all files (and folders) contained
6788 * in the folder, then the folder itself.
6789 *
6790 * @param device a pointer to the device to delete the object from.
6791 * @param object_id the object to delete.
6792 * @return 0 on success, any other value means failure.
6793 */
6794 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6795 uint32_t object_id)
6796 {
6797 uint16_t ret;
6798 PTPParams *params = (PTPParams *) device->params;
6799
6800 ret = ptp_deleteobject(params, object_id, 0);
6801 if (ret != PTP_RC_OK) {
6802 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6803 return -1;
6804 }
6805
6806 return 0;
6807 }
6808
6809 /**
6810 * Internal function to update an object filename property.
6811 */
6812 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6813 uint32_t object_id, uint16_t ptp_type,
6814 const char **newname_ptr)
6815 {
6816 PTPParams *params = (PTPParams *) device->params;
6817 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6818 PTPObjectPropDesc opd;
6819 uint16_t ret;
6820 char *newname;
6821
6822 // See if we can modify the filename on this kind of files.
6823 ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6824 if (ret != PTP_RC_OK) {
6825 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6826 "could not get property description.");
6827 return -1;
6828 }
6829
6830 if (!opd.GetSet) {
6831 ptp_free_objectpropdesc(&opd);
6832 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6833 " property is not settable.");
6834 // TODO: we COULD actually upload/download the object here, if we feel
6835 // like wasting time for the user.
6836 return -1;
6837 }
6838
6839 newname = strdup(*newname_ptr);
6840
6841 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6842 strip_7bit_from_utf8(newname);
6843 }
6844
6845 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6846 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6847 MTPProperties *props = NULL;
6848 MTPProperties *prop = NULL;
6849 int nrofprops = 0;
6850
6851 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6852 prop->ObjectHandle = object_id;
6853 prop->property = PTP_OPC_ObjectFileName;
6854 prop->datatype = PTP_DTC_STR;
6855 prop->propval.str = newname;
6856
6857 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6858
6859 ptp_destroy_object_prop_list(props, nrofprops);
6860
6861 if (ret != PTP_RC_OK) {
6862 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6863 " could not set object property list.");
6864 ptp_free_objectpropdesc(&opd);
6865 return -1;
6866 }
6867 } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6868 ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6869 if (ret != 0) {
6870 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6871 " could not set object filename.");
6872 ptp_free_objectpropdesc(&opd);
6873 return -1;
6874 }
6875 } else {
6876 free(newname);
6877 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6878 " your device doesn't seem to support any known way of setting metadata.");
6879 ptp_free_objectpropdesc(&opd);
6880 return -1;
6881 }
6882
6883 ptp_free_objectpropdesc(&opd);
6884
6885 // update cached object properties if metadata cache exists
6886 update_metadata_cache(device, object_id);
6887
6888 return 0;
6889 }
6890
6891 /**
6892 * This function renames a single file.
6893 * This simply means that the PTP_OPC_ObjectFileName property
6894 * is updated, if this is supported by the device.
6895 *
6896 * @param device a pointer to the device that contains the file.
6897 * @param file the file metadata of the file to rename.
6898 * On success, the filename member is updated. Be aware, that
6899 * this name can be different than newname depending of device restrictions.
6900 * @param newname the new filename for this object.
6901 * @return 0 on success, any other value means failure.
6902 */
6903 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6904 LIBMTP_file_t *file, const char *newname)
6905 {
6906 int ret;
6907
6908 ret = set_object_filename(device, file->item_id,
6909 map_libmtp_type_to_ptp_type(file->filetype),
6910 &newname);
6911
6912 if (ret != 0) {
6913 return ret;
6914 }
6915
6916 free(file->filename);
6917 file->filename = strdup(newname);
6918 return ret;
6919 }
6920
6921 /**
6922 * This function renames a single folder.
6923 * This simply means that the PTP_OPC_ObjectFileName property
6924 * is updated, if this is supported by the device.
6925 *
6926 * @param device a pointer to the device that contains the file.
6927 * @param folder the folder metadata of the folder to rename.
6928 * On success, the name member is updated. Be aware, that
6929 * this name can be different than newname depending of device restrictions.
6930 * @param newname the new name for this object.
6931 * @return 0 on success, any other value means failure.
6932 */
6933 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6934 LIBMTP_folder_t *folder, const char* newname)
6935 {
6936 int ret;
6937
6938 ret = set_object_filename(device, folder->folder_id,
6939 PTP_OFC_Association,
6940 &newname);
6941
6942 if (ret != 0) {
6943 return ret;
6944 }
6945
6946 free(folder->name);
6947 folder->name = strdup(newname);
6948 return ret;
6949 }
6950
6951 /**
6952 * This function renames a single track.
6953 * This simply means that the PTP_OPC_ObjectFileName property
6954 * is updated, if this is supported by the device.
6955 *
6956 * @param device a pointer to the device that contains the file.
6957 * @param track the track metadata of the track to rename.
6958 * On success, the filename member is updated. Be aware, that
6959 * this name can be different than newname depending of device restrictions.
6960 * @param newname the new filename for this object.
6961 * @return 0 on success, any other value means failure.
6962 */
6963 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6964 LIBMTP_track_t *track, const char* newname)
6965 {
6966 int ret;
6967
6968 ret = set_object_filename(device, track->item_id,
6969 map_libmtp_type_to_ptp_type(track->filetype),
6970 &newname);
6971
6972 if (ret != 0) {
6973 return ret;
6974 }
6975
6976 free(track->filename);
6977 track->filename = strdup(newname);
6978 return ret;
6979 }
6980
6981 /**
6982 * This function renames a single playlist object file holder.
6983 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6984 * property is updated, if this is supported by the device.
6985 * The playlist filename should nominally end with an extension
6986 * like ".pla".
6987 *
6988 * NOTE: if you want to change the metadata the device display
6989 * about a playlist you must <i>not</i> use this function,
6990 * use <code>LIBMTP_Update_Playlist()</code> instead!
6991 *
6992 * @param device a pointer to the device that contains the file.
6993 * @param playlist the playlist metadata of the playlist to rename.
6994 * On success, the name member is updated. Be aware, that
6995 * this name can be different than newname depending of device restrictions.
6996 * @param newname the new name for this object.
6997 * @return 0 on success, any other value means failure.
6998 * @see LIBMTP_Update_Playlist()
6999 */
7000 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
7001 LIBMTP_playlist_t *playlist, const char* newname)
7002 {
7003 int ret;
7004
7005 ret = set_object_filename(device, playlist->playlist_id,
7006 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7007 &newname);
7008
7009 if (ret != 0) {
7010 return ret;
7011 }
7012
7013 free(playlist->name);
7014 playlist->name = strdup(newname);
7015 return ret;
7016 }
7017
7018 /**
7019 * This function renames a single album.
7020 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
7021 * property is updated, if this is supported by the device.
7022 * The album filename should nominally end with an extension
7023 * like ".alb".
7024 *
7025 * NOTE: if you want to change the metadata the device display
7026 * about a playlist you must <i>not</i> use this function,
7027 * use <code>LIBMTP_Update_Album()</code> instead!
7028 *
7029 * @param device a pointer to the device that contains the file.
7030 * @param album the album metadata of the album to rename.
7031 * On success, the name member is updated. Be aware, that
7032 * this name can be different than newname depending of device restrictions.
7033 * @param newname the new name for this object.
7034 * @return 0 on success, any other value means failure.
7035 * @see LIBMTP_Update_Album()
7036 */
7037 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
7038 LIBMTP_album_t *album, const char* newname)
7039 {
7040 int ret;
7041
7042 ret = set_object_filename(device, album->album_id,
7043 PTP_OFC_MTP_AbstractAudioAlbum,
7044 &newname);
7045
7046 if (ret != 0) {
7047 return ret;
7048 }
7049
7050 free(album->name);
7051 album->name = strdup(newname);
7052 return ret;
7053 }
7054
7055 /**
7056 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
7057 * NOT TO USE IT.
7058 *
7059 * @see LIBMTP_Set_File_Name()
7060 * @see LIBMTP_Set_Track_Name()
7061 * @see LIBMTP_Set_Folder_Name()
7062 * @see LIBMTP_Set_Playlist_Name()
7063 * @see LIBMTP_Set_Album_Name()
7064 */
7065 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
7066 uint32_t object_id, char* newname)
7067 {
7068 int ret;
7069 LIBMTP_file_t *file;
7070
7071 file = LIBMTP_Get_Filemetadata(device, object_id);
7072
7073 if (file == NULL) {
7074 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
7075 "could not get file metadata for target object.");
7076 return -1;
7077 }
7078
7079 ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7080
7081 free(file);
7082
7083 return ret;
7084 }
7085
7086 /**
7087 * Helper function. This indicates if a track exists on the device
7088 * @param device a pointer to the device to get the track from.
7089 * @param id the track ID of the track to retrieve.
7090 * @return TRUE (!=0) if the track exists, FALSE (0) if not
7091 */
7092 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7093 uint32_t const id)
7094 {
7095 PTPParams *params = (PTPParams *) device->params;
7096 uint16_t ret;
7097 PTPObject *ob;
7098
7099 ret = ptp_object_want (params, id, 0, &ob);
7100 if (ret == PTP_RC_OK)
7101 return -1;
7102 return 0;
7103 }
7104
7105 /**
7106 * This creates a new folder structure and allocates memory
7107 * for it. Notice that if you add strings to this structure they
7108 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7109 * operation later, so be careful of using strdup() when assigning
7110 * strings, e.g.:
7111 *
7112 * @return a pointer to the newly allocated folder structure.
7113 * @see LIBMTP_destroy_folder_t()
7114 */
7115 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7116 {
7117 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7118 if (new == NULL) {
7119 return NULL;
7120 }
7121 new->folder_id = 0;
7122 new->parent_id = 0;
7123 new->storage_id = 0;
7124 new->name = NULL;
7125 new->sibling = NULL;
7126 new->child = NULL;
7127 return new;
7128 }
7129
7130 /**
7131 * This recursively deletes the memory for a folder structure.
7132 * This shall typically be called on a top-level folder list to
7133 * detsroy the entire folder tree.
7134 *
7135 * @param folder folder structure to destroy
7136 * @see LIBMTP_new_folder_t()
7137 */
7138 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7139 {
7140
7141 if(folder == NULL) {
7142 return;
7143 }
7144
7145 //Destroy from the bottom up
7146 if(folder->child != NULL) {
7147 LIBMTP_destroy_folder_t(folder->child);
7148 }
7149
7150 if(folder->sibling != NULL) {
7151 LIBMTP_destroy_folder_t(folder->sibling);
7152 }
7153
7154 if(folder->name != NULL) {
7155 free(folder->name);
7156 }
7157
7158 free(folder);
7159 }
7160
7161 /**
7162 * Helper function. Returns a folder structure for a
7163 * specified id.
7164 *
7165 * @param folderlist list of folders to search
7166 * @id id of folder to look for
7167 * @return a folder or NULL if not found
7168 */
7169 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7170 {
7171 LIBMTP_folder_t *ret = NULL;
7172
7173 if(folderlist == NULL) {
7174 return NULL;
7175 }
7176
7177 if(folderlist->folder_id == id) {
7178 return folderlist;
7179 }
7180
7181 if(folderlist->sibling) {
7182 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7183 }
7184
7185 if(folderlist->child && ret == NULL) {
7186 ret = LIBMTP_Find_Folder(folderlist->child, id);
7187 }
7188
7189 return ret;
7190 }
7191
7192 /**
7193 * Function used to recursively get subfolders from params.
7194 */
7195 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7196 {
7197 LIBMTP_folder_t *retfolders = NULL;
7198 LIBMTP_folder_t *children, *iter, *curr;
7199
7200 iter = list->sibling;
7201 while(iter != list) {
7202 if (iter->parent_id != parent) {
7203 iter = iter->sibling;
7204 continue;
7205 }
7206
7207 /* We know that iter is a child of 'parent', therefore we can safely
7208 * hold on to 'iter' locally since no one else will steal it
7209 * from the 'list' as we recurse. */
7210 children = get_subfolders_for_folder(list, iter->folder_id);
7211
7212 curr = iter;
7213 iter = iter->sibling;
7214
7215 // Remove curr from the list.
7216 curr->child->sibling = curr->sibling;
7217 curr->sibling->child = curr->child;
7218
7219 // Attach the children to curr.
7220 curr->child = children;
7221
7222 // Put this folder into the list of siblings.
7223 curr->sibling = retfolders;
7224 retfolders = curr;
7225 }
7226
7227 return retfolders;
7228 }
7229
7230 /**
7231 * This returns a list of all folders available
7232 * on the current MTP device.
7233 *
7234 * @param device a pointer to the device to get the folder listing for.
7235 * @param storage a storage ID to get the folder list from
7236 * @return a list of folders
7237 */
7238 LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7239 uint32_t const storage)
7240 {
7241 PTPParams *params = (PTPParams *) device->params;
7242 LIBMTP_folder_t head, *rv;
7243 int i;
7244
7245 // Get all the handles if we haven't already done that
7246 if (params->nrofobjects == 0) {
7247 flush_handles(device);
7248 }
7249
7250 /*
7251 * This creates a temporary list of the folders, this is in a
7252 * reverse order and uses the Folder pointers that are already
7253 * in the Folder structure. From this we can then build up the
7254 * folder hierarchy with only looking at this temporary list,
7255 * and removing the folders from this temporary list as we go.
7256 * This significantly reduces the number of operations that we
7257 * have to do in building the folder hierarchy. Also since the
7258 * temp list is in reverse order, when we prepend to the sibling
7259 * list things are in the same order as they were originally
7260 * in the handle list.
7261 */
7262 head.sibling = &head;
7263 head.child = &head;
7264 for (i = 0; i < params->nrofobjects; i++) {
7265 LIBMTP_folder_t *folder;
7266 PTPObject *ob;
7267
7268 ob = ¶ms->objects[i];
7269 if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7270 continue;
7271 }
7272
7273 if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7274 continue;
7275 }
7276
7277 /*
7278 * Do we know how to handle these? They are part
7279 * of the MTP 1.0 specification paragraph 3.6.4.
7280 * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7281 * should be called on these to get the contained objects, but
7282 * we basically don't care. Hopefully parent_id is maintained for all
7283 * children, because we rely on that instead.
7284 */
7285 if (ob->oi.AssociationDesc != 0x00000000U) {
7286 LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7287 }
7288
7289 // Create a folder struct...
7290 folder = LIBMTP_new_folder_t();
7291 if (folder == NULL) {
7292 // malloc failure or so.
7293 return NULL;
7294 }
7295 folder->folder_id = ob->oid;
7296 folder->parent_id = ob->oi.ParentObject;
7297 folder->storage_id = ob->oi.StorageID;
7298 folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7299
7300 // pretend sibling says next, and child says prev.
7301 folder->sibling = head.sibling;
7302 folder->child = &head;
7303 head.sibling->child = folder;
7304 head.sibling = folder;
7305 }
7306
7307 // We begin at the given root folder and get them all recursively
7308 rv = get_subfolders_for_folder(&head, 0x00000000U);
7309
7310 // Some buggy devices may have some files in the "root folder"
7311 // 0xffffffff so if 0x00000000 didn't return any folders,
7312 // look for children of the root 0xffffffffU
7313 if (rv == NULL) {
7314 rv = get_subfolders_for_folder(&head, 0xffffffffU);
7315 if (rv != NULL)
7316 LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7317 "this is a firmware bug (but continuing)\n");
7318 }
7319
7320 // The temp list should be empty. Clean up any orphans just in case.
7321 while(head.sibling != &head) {
7322 LIBMTP_folder_t *curr = head.sibling;
7323
7324 LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7325 curr->folder_id,
7326 curr->name);
7327 curr->sibling->child = curr->child;
7328 curr->child->sibling = curr->sibling;
7329 curr->child = NULL;
7330 curr->sibling = NULL;
7331 LIBMTP_destroy_folder_t(curr);
7332 }
7333
7334 return rv;
7335 }
7336
7337 /**
7338 * This returns a list of all folders available
7339 * on the current MTP device.
7340 *
7341 * @param device a pointer to the device to get the folder listing for.
7342 * @return a list of folders
7343 */
7344 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7345 {
7346 return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7347 }
7348
7349 /**
7350 * This create a folder on the current MTP device. The PTP name
7351 * for a folder is "association". The PTP/MTP devices does not
7352 * have an internal "folder" concept really, it contains a flat
7353 * list of all files and some file are "associations" that other
7354 * files and folders may refer to as its "parent".
7355 *
7356 * @param device a pointer to the device to create the folder on.
7357 * @param name the name of the new folder. Note this can be modified
7358 * if the device does not support all the characters in the
7359 * name.
7360 * @param parent_id id of parent folder to add the new folder to,
7361 * or 0xFFFFFFFF to put it in the root directory.
7362 * @param storage_id id of the storage to add this new folder to.
7363 * notice that you cannot mismatch storage id and parent id:
7364 * they must both be on the same storage! Pass in 0 if you
7365 * want to create this folder on the default storage.
7366 * @return id to new folder or 0 if an error occured
7367 */
7368 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7369 uint32_t parent_id, uint32_t storage_id)
7370 {
7371 PTPParams *params = (PTPParams *) device->params;
7372 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7373 uint32_t parenthandle = 0;
7374 uint32_t store;
7375 PTPObjectInfo new_folder;
7376 uint16_t ret;
7377 uint32_t new_id = 0;
7378
7379 if (storage_id == 0) {
7380 // I'm just guessing that a folder may require 512 bytes
7381 store = get_suggested_storage_id(device, 512, parent_id);
7382 } else {
7383 store = storage_id;
7384 }
7385 parenthandle = parent_id;
7386
7387 memset(&new_folder, 0, sizeof(new_folder));
7388 new_folder.Filename = name;
7389 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7390 strip_7bit_from_utf8(new_folder.Filename);
7391 }
7392 new_folder.ObjectCompressedSize = 0;
7393 new_folder.ObjectFormat = PTP_OFC_Association;
7394 new_folder.ProtectionStatus = PTP_PS_NoProtection;
7395 new_folder.AssociationType = PTP_AT_GenericFolder;
7396 new_folder.ParentObject = parent_id;
7397 new_folder.StorageID = store;
7398
7399 // Create the object
7400 if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7401 ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7402 MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7403
7404 props[0].property = PTP_OPC_ObjectFileName;
7405 props[0].datatype = PTP_DTC_STR;
7406 props[0].propval.str = name;
7407
7408 props[1].property = PTP_OPC_Name;
7409 props[1].datatype = PTP_DTC_STR;
7410 props[1].propval.str = name;
7411
7412 ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7413 0, props, 1);
7414 free(props);
7415 } else {
7416 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7417 }
7418
7419 if (ret != PTP_RC_OK) {
7420 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7421 if (ret == PTP_RC_AccessDenied) {
7422 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7423 }
7424 return 0;
7425 }
7426 // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7427 // several strings.
7428
7429 add_object_to_cache(device, new_id);
7430
7431 return new_id;
7432 }
7433
7434 /**
7435 * This creates a new playlist metadata structure and allocates memory
7436 * for it. Notice that if you add strings to this structure they
7437 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7438 * operation later, so be careful of using strdup() when assigning
7439 * strings, e.g.:
7440 *
7441 * <pre>
7442 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7443 * pl->name = strdup(str);
7444 * ....
7445 * LIBMTP_destroy_playlist_t(pl);
7446 * </pre>
7447 *
7448 * @return a pointer to the newly allocated metadata structure.
7449 * @see LIBMTP_destroy_playlist_t()
7450 */
7451 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7452 {
7453 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7454 if (new == NULL) {
7455 return NULL;
7456 }
7457 new->playlist_id = 0;
7458 new->parent_id = 0;
7459 new->storage_id = 0;
7460 new->name = NULL;
7461 new->tracks = NULL;
7462 new->no_tracks = 0;
7463 new->next = NULL;
7464 return new;
7465 }
7466
7467 /**
7468 * This destroys a playlist metadata structure and deallocates the memory
7469 * used by it, including any strings. Never use a track metadata
7470 * structure again after calling this function on it.
7471 * @param playlist the playlist metadata to destroy.
7472 * @see LIBMTP_new_playlist_t()
7473 */
7474 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7475 {
7476 if (playlist == NULL) {
7477 return;
7478 }
7479 if (playlist->name != NULL)
7480 free(playlist->name);
7481 if (playlist->tracks != NULL)
7482 free(playlist->tracks);
7483 free(playlist);
7484 return;
7485 }
7486
7487 /**
7488 * This function returns a list of the playlists available on the
7489 * device. Typical usage:
7490 *
7491 * <pre>
7492 * </pre>
7493 *
7494 * @param device a pointer to the device to get the playlist listing from.
7495 * @return a playlist list on success, else NULL. If there are no playlists
7496 * on the device, NULL will be returned as well.
7497 * @see LIBMTP_Get_Playlist()
7498 */
7499 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7500 {
7501 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7502 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7503 PTPParams *params = (PTPParams *) device->params;
7504 LIBMTP_playlist_t *retlists = NULL;
7505 LIBMTP_playlist_t *curlist = NULL;
7506 uint32_t i;
7507
7508 // Get all the handles if we haven't already done that
7509 if (params->nrofobjects == 0) {
7510 flush_handles(device);
7511 }
7512
7513 for (i = 0; i < params->nrofobjects; i++) {
7514 LIBMTP_playlist_t *pl;
7515 PTPObject *ob;
7516 uint16_t ret;
7517
7518 ob = ¶ms->objects[i];
7519
7520 // Ignore stuff that isn't playlists
7521
7522 // For Samsung players we must look for the .spl extension explicitly since
7523 // playlists are not stored as playlist objects.
7524 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7525 // Allocate a new playlist type
7526 pl = LIBMTP_new_playlist_t();
7527 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7528 }
7529 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7530 continue;
7531 }
7532 else {
7533 // Allocate a new playlist type
7534 pl = LIBMTP_new_playlist_t();
7535
7536 // Try to look up proper name, else use the oi->Filename field.
7537 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7538 if (pl->name == NULL) {
7539 pl->name = strdup(ob->oi.Filename);
7540 }
7541 pl->playlist_id = ob->oid;
7542 pl->parent_id = ob->oi.ParentObject;
7543 pl->storage_id = ob->oi.StorageID;
7544
7545 // Then get the track listing for this playlist
7546 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7547 if (ret != PTP_RC_OK) {
7548 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7549 "could not get object references.");
7550 pl->tracks = NULL;
7551 pl->no_tracks = 0;
7552 }
7553 }
7554
7555 // Add playlist to a list that will be returned afterwards.
7556 if (retlists == NULL) {
7557 retlists = pl;
7558 curlist = pl;
7559 } else {
7560 curlist->next = pl;
7561 curlist = pl;
7562 }
7563
7564 // Call callback here if we decide to add that possibility...
7565 }
7566 return retlists;
7567 }
7568
7569
7570 /**
7571 * This function retrieves an individual playlist from the device.
7572 * @param device a pointer to the device to get the playlist from.
7573 * @param plid the unique ID of the playlist to retrieve.
7574 * @return a valid playlist metadata post or NULL on failure.
7575 * @see LIBMTP_Get_Playlist_List()
7576 */
7577 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7578 {
7579 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7580 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7581 PTPParams *params = (PTPParams *) device->params;
7582 PTPObject *ob;
7583 LIBMTP_playlist_t *pl;
7584 uint16_t ret;
7585
7586 // Get all the handles if we haven't already done that
7587 if (params->nrofobjects == 0) {
7588 flush_handles(device);
7589 }
7590
7591 ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7592 if (ret != PTP_RC_OK)
7593 return NULL;
7594
7595 // For Samsung players we must look for the .spl extension explicitly since
7596 // playlists are not stored as playlist objects.
7597 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7598 // Allocate a new playlist type
7599 pl = LIBMTP_new_playlist_t();
7600 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7601 return pl;
7602 }
7603
7604 // Ignore stuff that isn't playlists
7605 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7606 return NULL;
7607 }
7608
7609 // Allocate a new playlist type
7610 pl = LIBMTP_new_playlist_t();
7611
7612 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7613 if (pl->name == NULL) {
7614 pl->name = strdup(ob->oi.Filename);
7615 }
7616 pl->playlist_id = ob->oid;
7617 pl->parent_id = ob->oi.ParentObject;
7618 pl->storage_id = ob->oi.StorageID;
7619
7620 // Then get the track listing for this playlist
7621 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7622 if (ret != PTP_RC_OK) {
7623 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7624 pl->tracks = NULL;
7625 pl->no_tracks = 0;
7626 }
7627
7628 return pl;
7629 }
7630
7631 /**
7632 * This function creates a new abstract list such as a playlist
7633 * or an album.
7634 *
7635 * @param device a pointer to the device to create the new abstract list
7636 * on.
7637 * @param name the name of the new abstract list.
7638 * @param artist the artist of the new abstract list or NULL.
7639 * @param genre the genre of the new abstract list or NULL.
7640 * @param parenthandle the handle of the parent or 0 for no parent
7641 * i.e. the root folder.
7642 * @param objectformat the abstract list type to create.
7643 * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7644 * "file" created by this operation.
7645 * @param newid a pointer to a variable that will hold the new object
7646 * ID if this call is successful.
7647 * @param tracks an array of tracks to associate with this list.
7648 * @param no_tracks the number of tracks in the list.
7649 * @return 0 on success, any other value means failure.
7650 */
7651 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7652 char const * const name,
7653 char const * const artist,
7654 char const * const composer,
7655 char const * const genre,
7656 uint32_t const parenthandle,
7657 uint32_t const storageid,
7658 uint16_t const objectformat,
7659 char const * const suffix,
7660 uint32_t * const newid,
7661 uint32_t const * const tracks,
7662 uint32_t const no_tracks)
7663
7664 {
7665 int i;
7666 int supported = 0;
7667 uint16_t ret;
7668 uint16_t *properties = NULL;
7669 uint32_t propcnt = 0;
7670 uint32_t store;
7671 uint32_t localph = parenthandle;
7672 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7673 PTPParams *params = (PTPParams *) device->params;
7674 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7675 char fname[256];
7676 //uint8_t data[2];
7677
7678 // NULL check
7679 if (!name) {
7680 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7681 return -1;
7682 }
7683
7684 if (storageid == 0) {
7685 // I'm just guessing that an abstract list may require 512 bytes
7686 store = get_suggested_storage_id(device, 512, localph);
7687 } else {
7688 store = storageid;
7689 }
7690
7691 // Check if we can create an object of this type
7692 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7693 if (params->deviceinfo.ImageFormats[i] == objectformat) {
7694 supported = 1;
7695 break;
7696 }
7697 }
7698 if (!supported) {
7699 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7700 LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7701 return -1;
7702 }
7703
7704 // add the new suffix if it isn't there
7705 fname[0] = '\0';
7706 if (strlen(name) > strlen(suffix)) {
7707 char const * const suff = &name[strlen(name)-strlen(suffix)];
7708 if (!strcmp(suff, suffix)) {
7709 // Home free.
7710 strncpy(fname, name, sizeof(fname));
7711 }
7712 }
7713 // If it didn't end with "<suffix>" then add that here.
7714 if (fname[0] == '\0') {
7715 strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7716 strcat(fname, suffix);
7717 fname[sizeof(fname)-1] = '\0';
7718 }
7719
7720 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7721 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7722 MTPProperties *props = NULL;
7723 MTPProperties *prop = NULL;
7724 int nrofprops = 0;
7725
7726 *newid = 0x00000000U;
7727
7728 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7729
7730 for (i=0;i<propcnt;i++) {
7731 PTPObjectPropDesc opd;
7732
7733 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7734 if (ret != PTP_RC_OK) {
7735 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7736 "could not get property description.");
7737 } else if (opd.GetSet) {
7738 switch (properties[i]) {
7739 case PTP_OPC_ObjectFileName:
7740 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7741 prop->ObjectHandle = *newid;
7742 prop->property = PTP_OPC_ObjectFileName;
7743 prop->datatype = PTP_DTC_STR;
7744 prop->propval.str = strdup(fname);
7745 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7746 strip_7bit_from_utf8(prop->propval.str);
7747 }
7748 break;
7749 case PTP_OPC_ProtectionStatus:
7750 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7751 prop->ObjectHandle = *newid;
7752 prop->property = PTP_OPC_ProtectionStatus;
7753 prop->datatype = PTP_DTC_UINT16;
7754 prop->propval.u16 = 0x0000U; /* Not protected */
7755 break;
7756 case PTP_OPC_NonConsumable:
7757 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7758 prop->ObjectHandle = *newid;
7759 prop->property = PTP_OPC_NonConsumable;
7760 prop->datatype = PTP_DTC_UINT8;
7761 prop->propval.u8 = nonconsumable;
7762 break;
7763 case PTP_OPC_Name:
7764 if (name != NULL) {
7765 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7766 prop->ObjectHandle = *newid;
7767 prop->property = PTP_OPC_Name;
7768 prop->datatype = PTP_DTC_STR;
7769 prop->propval.str = strdup(name);
7770 }
7771 break;
7772 case PTP_OPC_AlbumArtist:
7773 if (artist != NULL) {
7774 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7775 prop->ObjectHandle = *newid;
7776 prop->property = PTP_OPC_AlbumArtist;
7777 prop->datatype = PTP_DTC_STR;
7778 prop->propval.str = strdup(artist);
7779 }
7780 break;
7781 case PTP_OPC_Artist:
7782 if (artist != NULL) {
7783 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7784 prop->ObjectHandle = *newid;
7785 prop->property = PTP_OPC_Artist;
7786 prop->datatype = PTP_DTC_STR;
7787 prop->propval.str = strdup(artist);
7788 }
7789 break;
7790 case PTP_OPC_Composer:
7791 if (composer != NULL) {
7792 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7793 prop->ObjectHandle = *newid;
7794 prop->property = PTP_OPC_Composer;
7795 prop->datatype = PTP_DTC_STR;
7796 prop->propval.str = strdup(composer);
7797 }
7798 break;
7799 case PTP_OPC_Genre:
7800 if (genre != NULL) {
7801 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7802 prop->ObjectHandle = *newid;
7803 prop->property = PTP_OPC_Genre;
7804 prop->datatype = PTP_DTC_STR;
7805 prop->propval.str = strdup(genre);
7806 }
7807 break;
7808 case PTP_OPC_DateModified:
7809 // Tag with current time if that is supported
7810 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7811 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7812 prop->ObjectHandle = *newid;
7813 prop->property = PTP_OPC_DateModified;
7814 prop->datatype = PTP_DTC_STR;
7815 prop->propval.str = get_iso8601_stamp();
7816 }
7817 break;
7818 }
7819 }
7820 ptp_free_objectpropdesc(&opd);
7821 }
7822 free(properties);
7823
7824 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7825 objectformat, 0, props, nrofprops);
7826
7827 /* Free property list */
7828 ptp_destroy_object_prop_list(props, nrofprops);
7829
7830 if (ret != PTP_RC_OK) {
7831 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7832 if (ret == PTP_RC_AccessDenied) {
7833 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7834 }
7835 return -1;
7836 }
7837
7838 // now send the blank object
7839 ret = ptp_sendobject(params, NULL, 0);
7840 if (ret != PTP_RC_OK) {
7841 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7842 return -1;
7843 }
7844
7845 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7846 PTPObjectInfo new_object;
7847
7848 new_object.Filename = fname;
7849 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7850 strip_7bit_from_utf8(new_object.Filename);
7851 }
7852 // At one point this had to be one
7853 new_object.ObjectCompressedSize = 0;
7854 new_object.ObjectFormat = objectformat;
7855
7856 // Create the object
7857 ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7858 if (ret != PTP_RC_OK) {
7859 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7860 if (ret == PTP_RC_AccessDenied) {
7861 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7862 }
7863 return -1;
7864 }
7865 // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7866 // not copies.
7867
7868 #if 0
7869 /*
7870 * At one time we had to send this one blank data byte.
7871 * If we didn't, the handle will not be created and thus there is
7872 * no playlist. Possibly this was masking some bug, so removing it
7873 * now.
7874 */
7875 data[0] = '\0';
7876 data[1] = '\0';
7877 ret = ptp_sendobject(params, data, 1);
7878 if (ret != PTP_RC_OK) {
7879 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7880 return -1;
7881 }
7882 #endif
7883
7884 // set the properties one by one
7885 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7886
7887 for (i=0;i<propcnt;i++) {
7888 PTPObjectPropDesc opd;
7889
7890 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7891 if (ret != PTP_RC_OK) {
7892 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7893 "could not get property description.");
7894 } else if (opd.GetSet) {
7895 switch (properties[i]) {
7896 case PTP_OPC_Name:
7897 if (name != NULL) {
7898 ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7899 if (ret != 0) {
7900 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7901 return -1;
7902 }
7903 }
7904 break;
7905 case PTP_OPC_AlbumArtist:
7906 if (artist != NULL) {
7907 ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7908 if (ret != 0) {
7909 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7910 return -1;
7911 }
7912 }
7913 break;
7914 case PTP_OPC_Artist:
7915 if (artist != NULL) {
7916 ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7917 if (ret != 0) {
7918 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7919 return -1;
7920 }
7921 }
7922 break;
7923 case PTP_OPC_Composer:
7924 if (composer != NULL) {
7925 ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7926 if (ret != 0) {
7927 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7928 return -1;
7929 }
7930 }
7931 break;
7932 case PTP_OPC_Genre:
7933 if (genre != NULL) {
7934 ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7935 if (ret != 0) {
7936 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7937 return -1;
7938 }
7939 }
7940 break;
7941 case PTP_OPC_DateModified:
7942 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7943 ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7944 if (ret != 0) {
7945 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7946 return -1;
7947 }
7948 }
7949 break;
7950 }
7951 }
7952 ptp_free_objectpropdesc(&opd);
7953 }
7954 free(properties);
7955 }
7956
7957 if (no_tracks > 0) {
7958 // Add tracks to the list as object references.
7959 ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7960 if (ret != PTP_RC_OK) {
7961 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7962 return -1;
7963 }
7964 }
7965
7966 add_object_to_cache(device, *newid);
7967
7968 return 0;
7969 }
7970
7971 /**
7972 * This updates the metadata and track listing
7973 * for an abstract list.
7974 * @param device a pointer to the device that the abstract list
7975 * resides on.
7976 * @param name the name of the abstract list.
7977 * @param artist the artist of the abstract list or NULL.
7978 * @param genre the genre of the abstract list or NULL.
7979 * @param objecthandle the object to be updated.
7980 * @param objectformat the abstract list type to update.
7981 * @param tracks an array of tracks to associate with this list.
7982 * @param no_tracks the number of tracks in the list.
7983 * @return 0 on success, any other value means failure.
7984 */
7985 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7986 char const * const name,
7987 char const * const artist,
7988 char const * const composer,
7989 char const * const genre,
7990 uint32_t const objecthandle,
7991 uint16_t const objectformat,
7992 uint32_t const * const tracks,
7993 uint32_t const no_tracks)
7994 {
7995 uint16_t ret;
7996 PTPParams *params = (PTPParams *) device->params;
7997 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7998 uint16_t *properties = NULL;
7999 uint32_t propcnt = 0;
8000 int i;
8001
8002 // First see which properties can be set
8003 // i.e only try to update this metadata for object tags that exist on the current player.
8004 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
8005 if (ret != PTP_RC_OK) {
8006 // Just bail out for now, nothing is ever set.
8007 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8008 "could not retrieve supported object properties.");
8009 return -1;
8010 }
8011 if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
8012 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
8013 MTPProperties *props = NULL;
8014 MTPProperties *prop = NULL;
8015 int nrofprops = 0;
8016
8017 for (i=0;i<propcnt;i++) {
8018 PTPObjectPropDesc opd;
8019
8020 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
8021 if (ret != PTP_RC_OK) {
8022 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8023 "could not get property description.");
8024 } else if (opd.GetSet) {
8025 switch (properties[i]) {
8026 case PTP_OPC_Name:
8027 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8028 prop->ObjectHandle = objecthandle;
8029 prop->property = PTP_OPC_Name;
8030 prop->datatype = PTP_DTC_STR;
8031 if (name != NULL)
8032 prop->propval.str = strdup(name);
8033 break;
8034 case PTP_OPC_AlbumArtist:
8035 if (artist != NULL) {
8036 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8037 prop->ObjectHandle = objecthandle;
8038 prop->property = PTP_OPC_AlbumArtist;
8039 prop->datatype = PTP_DTC_STR;
8040 prop->propval.str = strdup(artist);
8041 }
8042 break;
8043 case PTP_OPC_Artist:
8044 if (artist != NULL) {
8045 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8046 prop->ObjectHandle = objecthandle;
8047 prop->property = PTP_OPC_Artist;
8048 prop->datatype = PTP_DTC_STR;
8049 prop->propval.str = strdup(artist);
8050 }
8051 break;
8052 case PTP_OPC_Composer:
8053 if (composer != NULL) {
8054 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8055 prop->ObjectHandle = objecthandle;
8056 prop->property = PTP_OPC_Composer;
8057 prop->datatype = PTP_DTC_STR;
8058 prop->propval.str = strdup(composer);
8059 }
8060 break;
8061 case PTP_OPC_Genre:
8062 if (genre != NULL) {
8063 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8064 prop->ObjectHandle = objecthandle;
8065 prop->property = PTP_OPC_Genre;
8066 prop->datatype = PTP_DTC_STR;
8067 prop->propval.str = strdup(genre);
8068 }
8069 break;
8070 case PTP_OPC_DateModified:
8071 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8072 // Tag with current time if that is supported
8073 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8074 prop->ObjectHandle = objecthandle;
8075 prop->property = PTP_OPC_DateModified;
8076 prop->datatype = PTP_DTC_STR;
8077 prop->propval.str = get_iso8601_stamp();
8078 }
8079 break;
8080 default:
8081 break;
8082 }
8083 }
8084 ptp_free_objectpropdesc(&opd);
8085 }
8086
8087 // proplist could be NULL if we can't write any properties
8088 if (props != NULL) {
8089 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8090
8091 ptp_destroy_object_prop_list(props, nrofprops);
8092
8093 if (ret != PTP_RC_OK) {
8094 // TODO: return error of which property we couldn't set
8095 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8096 "could not set object property list.");
8097 free(properties);
8098 return -1;
8099 }
8100 }
8101
8102 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8103 for (i=0;i<propcnt;i++) {
8104 switch (properties[i]) {
8105 case PTP_OPC_Name:
8106 // Update title
8107 ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8108 if (ret != 0) {
8109 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8110 "could not set title.");
8111 }
8112 break;
8113 case PTP_OPC_AlbumArtist:
8114 // Update album artist
8115 ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8116 if (ret != 0) {
8117 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8118 "could not set album artist name.");
8119 }
8120 break;
8121 case PTP_OPC_Artist:
8122 // Update artist
8123 ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8124 if (ret != 0) {
8125 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8126 "could not set artist name.");
8127 }
8128 break;
8129 case PTP_OPC_Composer:
8130 // Update composer
8131 ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8132 if (ret != 0) {
8133 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8134 "could not set composer name.");
8135 }
8136 break;
8137 case PTP_OPC_Genre:
8138 // Update genre (but only if valid)
8139 if(genre) {
8140 ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8141 if (ret != 0) {
8142 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8143 "could not set genre.");
8144 }
8145 }
8146 break;
8147 case PTP_OPC_DateModified:
8148 // Update date modified
8149 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8150 char *tmpdate = get_iso8601_stamp();
8151 ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8152 if (ret != 0) {
8153 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8154 "could not set modification date.");
8155 }
8156 free(tmpdate);
8157 }
8158 break;
8159 default:
8160 break;
8161 }
8162 }
8163 } else {
8164 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8165 "Your device doesn't seem to support any known way of setting metadata.");
8166 free(properties);
8167 return -1;
8168 }
8169
8170 // Then the object references...
8171 ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8172 if (ret != PTP_RC_OK) {
8173 add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8174 free(properties);
8175 return -1;
8176 }
8177
8178 free(properties);
8179
8180 update_metadata_cache(device, objecthandle);
8181
8182 return 0;
8183 }
8184
8185
8186 /**
8187 * This routine creates a new playlist based on the metadata
8188 * supplied. If the <code>tracks</code> field of the metadata
8189 * contains a track listing, these tracks will be added to the
8190 * playlist.
8191 * @param device a pointer to the device to create the new playlist on.
8192 * @param metadata the metadata for the new playlist. If the function
8193 * exits with success, the <code>playlist_id</code> field of this
8194 * struct will contain the new playlist ID of the playlist.
8195 * <ul>
8196 * <li><code>metadata->parent_id</code> should be set to the parent
8197 * (e.g. folder) to store this track in. Since some
8198 * devices are a bit picky about where files
8199 * are placed, a default folder will be chosen if libmtp
8200 * has detected one for the current filetype and this
8201 * parameter is set to 0. If this is 0 and no default folder
8202 * can be found, the file will be stored in the root folder.
8203 * <li><code>metadata->storage_id</code> should be set to the
8204 * desired storage (e.g. memory card or whatever your device
8205 * presents) to store this track in. Setting this to 0 will store
8206 * the track on the primary storage.
8207 * </ul>
8208 * @return 0 on success, any other value means failure.
8209 * @see LIBMTP_Update_Playlist()
8210 * @see LIBMTP_Delete_Object()
8211 */
8212 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8213 LIBMTP_playlist_t * const metadata)
8214 {
8215 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8216 uint32_t localph = metadata->parent_id;
8217
8218 // Use a default folder if none given
8219 if (localph == 0) {
8220 if (device->default_playlist_folder != 0)
8221 localph = device->default_playlist_folder;
8222 else
8223 localph = device->default_music_folder;
8224 }
8225 metadata->parent_id = localph;
8226
8227 // Samsung needs its own special type of playlists
8228 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8229 return playlist_t_to_spl(device, metadata);
8230 }
8231
8232 // Just create a new abstract audio/video playlist...
8233 return create_new_abstract_list(device,
8234 metadata->name,
8235 NULL,
8236 NULL,
8237 NULL,
8238 localph,
8239 metadata->storage_id,
8240 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8241 get_playlist_extension(ptp_usb),
8242 &metadata->playlist_id,
8243 metadata->tracks,
8244 metadata->no_tracks);
8245 }
8246
8247 /**
8248 * This routine updates a playlist based on the metadata
8249 * supplied. If the <code>tracks</code> field of the metadata
8250 * contains a track listing, these tracks will be added to the
8251 * playlist in place of those already present, i.e. the
8252 * previous track listing will be deleted. For Samsung devices the
8253 * playlist id (metadata->playlist_id) is likely to change.
8254 * @param device a pointer to the device to create the new playlist on.
8255 * @param metadata the metadata for the playlist to be updated.
8256 * notice that the field <code>playlist_id</code>
8257 * must contain the apropriate playlist ID. Playlist ID
8258 * be modified to a new playlist ID by the time the
8259 * function returns since edit-in-place is not always possible.
8260 * @return 0 on success, any other value means failure.
8261 * @see LIBMTP_Create_New_Playlist()
8262 * @see LIBMTP_Delete_Object()
8263 */
8264 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8265 LIBMTP_playlist_t * const metadata)
8266 {
8267
8268 // Samsung needs its own special type of playlists
8269 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8270 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8271 return update_spl_playlist(device, metadata);
8272 }
8273
8274 return update_abstract_list(device,
8275 metadata->name,
8276 NULL,
8277 NULL,
8278 NULL,
8279 metadata->playlist_id,
8280 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8281 metadata->tracks,
8282 metadata->no_tracks);
8283 }
8284
8285 /**
8286 * This creates a new album metadata structure and allocates memory
8287 * for it. Notice that if you add strings to this structure they
8288 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8289 * operation later, so be careful of using strdup() when assigning
8290 * strings.
8291 *
8292 * @return a pointer to the newly allocated metadata structure.
8293 * @see LIBMTP_destroy_album_t()
8294 */
8295 LIBMTP_album_t *LIBMTP_new_album_t(void)
8296 {
8297 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8298 if (new == NULL) {
8299 return NULL;
8300 }
8301 new->album_id = 0;
8302 new->parent_id = 0;
8303 new->storage_id = 0;
8304 new->name = NULL;
8305 new->artist = NULL;
8306 new->composer = NULL;
8307 new->genre = NULL;
8308 new->tracks = NULL;
8309 new->no_tracks = 0;
8310 new->next = NULL;
8311 return new;
8312 }
8313
8314 /**
8315 * This recursively deletes the memory for an album structure
8316 *
8317 * @param album structure to destroy
8318 * @see LIBMTP_new_album_t()
8319 */
8320 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8321 {
8322 if (album == NULL) {
8323 return;
8324 }
8325 if (album->name != NULL)
8326 free(album->name);
8327 if (album->artist != NULL)
8328 free(album->artist);
8329 if (album->composer != NULL)
8330 free(album->composer);
8331 if (album->genre != NULL)
8332 free(album->genre);
8333 if (album->tracks != NULL)
8334 free(album->tracks);
8335 free(album);
8336 return;
8337 }
8338
8339 /**
8340 * This function maps and copies a property onto the album metadata if applicable.
8341 */
8342 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8343 MTPProperties *prop, LIBMTP_album_t *alb)
8344 {
8345 switch (prop->property) {
8346 case PTP_OPC_Name:
8347 if (prop->propval.str != NULL)
8348 alb->name = strdup(prop->propval.str);
8349 else
8350 alb->name = NULL;
8351 break;
8352 case PTP_OPC_AlbumArtist:
8353 if (prop->propval.str != NULL) {
8354 // This should take precedence over plain "Artist"
8355 if (alb->artist != NULL)
8356 free(alb->artist);
8357 alb->artist = strdup(prop->propval.str);
8358 } else
8359 alb->artist = NULL;
8360 break;
8361 case PTP_OPC_Artist:
8362 if (prop->propval.str != NULL) {
8363 // Only use of AlbumArtist is not set
8364 if (alb->artist == NULL)
8365 alb->artist = strdup(prop->propval.str);
8366 } else
8367 alb->artist = NULL;
8368 break;
8369 case PTP_OPC_Composer:
8370 if (prop->propval.str != NULL)
8371 alb->composer = strdup(prop->propval.str);
8372 else
8373 alb->composer = NULL;
8374 break;
8375 case PTP_OPC_Genre:
8376 if (prop->propval.str != NULL)
8377 alb->genre = strdup(prop->propval.str);
8378 else
8379 alb->genre = NULL;
8380 break;
8381 }
8382 }
8383
8384 /**
8385 * This function retrieves the album metadata for an album
8386 * given by a unique ID.
8387 * @param device a pointer to the device to get the track metadata off.
8388 * @param alb an album metadata metadata set to fill in.
8389 */
8390 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8391 LIBMTP_album_t *alb)
8392 {
8393 uint16_t ret;
8394 PTPParams *params = (PTPParams *) device->params;
8395 uint32_t i;
8396 MTPProperties *prop;
8397 PTPObject *ob;
8398
8399 /*
8400 * If we have a cached, large set of metadata, then use it!
8401 */
8402 ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8403 if (ob->mtpprops) {
8404 prop = ob->mtpprops;
8405 for (i=0;i<ob->nrofmtpprops;i++,prop++)
8406 pick_property_to_album_metadata(device, prop, alb);
8407 } else {
8408 uint16_t *props = NULL;
8409 uint32_t propcnt = 0;
8410
8411 // First see which properties can be retrieved for albums
8412 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8413 if (ret != PTP_RC_OK) {
8414 add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8415 // Just bail out for now, nothing is ever set.
8416 return;
8417 } else {
8418 for (i=0;i<propcnt;i++) {
8419 switch (props[i]) {
8420 case PTP_OPC_Name:
8421 alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8422 break;
8423 case PTP_OPC_AlbumArtist:
8424 if (alb->artist != NULL)
8425 free(alb->artist);
8426 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8427 break;
8428 case PTP_OPC_Artist:
8429 if (alb->artist == NULL)
8430 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8431 break;
8432 case PTP_OPC_Composer:
8433 alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8434 break;
8435 case PTP_OPC_Genre:
8436 alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8437 break;
8438 default:
8439 break;
8440 }
8441 }
8442 free(props);
8443 }
8444 }
8445 }
8446
8447
8448 /**
8449 * This function returns a list of the albums available on the
8450 * device.
8451 *
8452 * @param device a pointer to the device to get the album listing from.
8453 * @return an album list on success, else NULL. If there are no albums
8454 * on the device, NULL will be returned as well.
8455 * @see LIBMTP_Get_Album()
8456 */
8457 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8458 {
8459 // Read all storage devices
8460 return LIBMTP_Get_Album_List_For_Storage(device, 0);
8461 }
8462
8463
8464 /**
8465 * This function returns a list of the albums available on the
8466 * device. You can filter on the storage ID.
8467 *
8468 * @param device a pointer to the device to get the album listing from.
8469 * @param storage_id ID of device storage (if null, all storages)
8470 *
8471 * @return an album list on success, else NULL. If there are no albums
8472 * on the device, NULL will be returned as well.
8473 * @see LIBMTP_Get_Album()
8474 */
8475 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8476 {
8477 PTPParams *params = (PTPParams *) device->params;
8478 LIBMTP_album_t *retalbums = NULL;
8479 LIBMTP_album_t *curalbum = NULL;
8480 uint32_t i;
8481
8482 // Get all the handles if we haven't already done that
8483 if (params->nrofobjects == 0)
8484 flush_handles(device);
8485
8486 for (i = 0; i < params->nrofobjects; i++) {
8487 LIBMTP_album_t *alb;
8488 PTPObject *ob;
8489 uint16_t ret;
8490
8491 ob = ¶ms->objects[i];
8492
8493 // Ignore stuff that isn't an album
8494 if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8495 continue;
8496
8497 // Ignore stuff that isn't into the storage device
8498 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8499 continue;
8500
8501 // Allocate a new album type
8502 alb = LIBMTP_new_album_t();
8503 alb->album_id = ob->oid;
8504 alb->parent_id = ob->oi.ParentObject;
8505 alb->storage_id = ob->oi.StorageID;
8506
8507 // Fetch supported metadata
8508 get_album_metadata(device, alb);
8509
8510 // Then get the track listing for this album
8511 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8512 if (ret != PTP_RC_OK) {
8513 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8514 alb->tracks = NULL;
8515 alb->no_tracks = 0;
8516 }
8517
8518 // Add album to a list that will be returned afterwards.
8519 if (retalbums == NULL) {
8520 retalbums = alb;
8521 curalbum = alb;
8522 } else {
8523 curalbum->next = alb;
8524 curalbum = alb;
8525 }
8526
8527 }
8528 return retalbums;
8529 }
8530
8531 /**
8532 * This function retrieves an individual album from the device.
8533 * @param device a pointer to the device to get the album from.
8534 * @param albid the unique ID of the album to retrieve.
8535 * @return a valid album metadata or NULL on failure.
8536 * @see LIBMTP_Get_Album_List()
8537 */
8538 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8539 {
8540 PTPParams *params = (PTPParams *) device->params;
8541 uint16_t ret;
8542 PTPObject *ob;
8543 LIBMTP_album_t *alb;
8544
8545 // Get all the handles if we haven't already done that
8546 if (params->nrofobjects == 0)
8547 flush_handles(device);
8548
8549 ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8550 if (ret != PTP_RC_OK)
8551 return NULL;
8552
8553 // Ignore stuff that isn't an album
8554 if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8555 return NULL;
8556
8557 // Allocate a new album type
8558 alb = LIBMTP_new_album_t();
8559 alb->album_id = ob->oid;
8560 alb->parent_id = ob->oi.ParentObject;
8561 alb->storage_id = ob->oi.StorageID;
8562
8563 // Fetch supported metadata
8564 get_album_metadata(device, alb);
8565
8566 // Then get the track listing for this album
8567 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8568 if (ret != PTP_RC_OK) {
8569 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8570 alb->tracks = NULL;
8571 alb->no_tracks = 0;
8572 }
8573
8574 return alb;
8575 }
8576
8577 /**
8578 * This routine creates a new album based on the metadata
8579 * supplied. If the <code>tracks</code> field of the metadata
8580 * contains a track listing, these tracks will be added to the
8581 * album.
8582 * @param device a pointer to the device to create the new album on.
8583 * @param metadata the metadata for the new album. If the function
8584 * exits with success, the <code>album_id</code> field of this
8585 * struct will contain the new ID of the album.
8586 * <ul>
8587 * <li><code>metadata->parent_id</code> should be set to the parent
8588 * (e.g. folder) to store this track in. Since some
8589 * devices are a bit picky about where files
8590 * are placed, a default folder will be chosen if libmtp
8591 * has detected one for the current filetype and this
8592 * parameter is set to 0. If this is 0 and no default folder
8593 * can be found, the file will be stored in the root folder.
8594 * <li><code>metadata->storage_id</code> should be set to the
8595 * desired storage (e.g. memory card or whatever your device
8596 * presents) to store this track in. Setting this to 0 will store
8597 * the track on the primary storage.
8598 * </ul>
8599 * @return 0 on success, any other value means failure.
8600 * @see LIBMTP_Update_Album()
8601 * @see LIBMTP_Delete_Object()
8602 */
8603 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8604 LIBMTP_album_t * const metadata)
8605 {
8606 uint32_t localph = metadata->parent_id;
8607
8608 // Use a default folder if none given
8609 if (localph == 0) {
8610 if (device->default_album_folder != 0)
8611 localph = device->default_album_folder;
8612 else
8613 localph = device->default_music_folder;
8614 }
8615 metadata->parent_id = localph;
8616
8617 // Just create a new abstract album...
8618 return create_new_abstract_list(device,
8619 metadata->name,
8620 metadata->artist,
8621 metadata->composer,
8622 metadata->genre,
8623 localph,
8624 metadata->storage_id,
8625 PTP_OFC_MTP_AbstractAudioAlbum,
8626 ".alb",
8627 &metadata->album_id,
8628 metadata->tracks,
8629 metadata->no_tracks);
8630 }
8631
8632 /**
8633 * This creates a new sample data metadata structure and allocates memory
8634 * for it. Notice that if you add strings to this structure they
8635 * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8636 * operation later, so be careful of using strdup() when assigning
8637 * strings.
8638 *
8639 * @return a pointer to the newly allocated metadata structure.
8640 * @see LIBMTP_destroy_sampledata_t()
8641 */
8642 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8643 {
8644 LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8645 if (new == NULL) {
8646 return NULL;
8647 }
8648 new->height=0;
8649 new->width = 0;
8650 new->data = NULL;
8651 new->duration = 0;
8652 new->size = 0;
8653 return new;
8654 }
8655
8656 /**
8657 * This destroys a file sample metadata type.
8658 * @param sample the file sample metadata to be destroyed.
8659 */
8660 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8661 {
8662 if (sample == NULL) {
8663 return;
8664 }
8665 if (sample->data != NULL) {
8666 free(sample->data);
8667 }
8668 free(sample);
8669 }
8670
8671 /**
8672 * This routine figures out whether a certain filetype supports
8673 * representative samples (small thumbnail images) or not. This
8674 * typically applies to JPEG files, MP3 files and Album abstract
8675 * playlists, but in theory any filetype could support representative
8676 * samples.
8677 * @param device a pointer to the device which is to be examined.
8678 * @param filetype the fileype to examine, and return the representative sample
8679 * properties for.
8680 * @param sample this will contain a new sample type with the fields
8681 * filled in with suitable default values. For example, the
8682 * supported sample type will be set, the supported height and
8683 * width will be set to max values if it is an image sample,
8684 * and duration will also be given some suitable default value
8685 * which should not be exceeded on audio samples. If the
8686 * device does not support samples for this filetype, this
8687 * pointer will be NULL. If it is not NULL, the user must
8688 * destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8689 * after use.
8690 * @return 0 on success, any other value means failure.
8691 * @see LIBMTP_Send_Representative_Sample()
8692 * @see LIBMTP_Create_New_Album()
8693 */
8694 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8695 LIBMTP_filetype_t const filetype,
8696 LIBMTP_filesampledata_t ** sample)
8697 {
8698 uint16_t ret;
8699 PTPParams *params = (PTPParams *) device->params;
8700 uint16_t *props = NULL;
8701 uint32_t propcnt = 0;
8702 int i;
8703 // TODO: Get rid of these when we can properly query the device.
8704 int support_data = 0;
8705 int support_format = 0;
8706 int support_height = 0;
8707 int support_width = 0;
8708 int support_duration = 0;
8709 int support_size = 0;
8710
8711 PTPObjectPropDesc opd_height;
8712 PTPObjectPropDesc opd_width;
8713 PTPObjectPropDesc opd_format;
8714 PTPObjectPropDesc opd_duration;
8715 PTPObjectPropDesc opd_size;
8716
8717 // Default to no type supported.
8718 *sample = NULL;
8719
8720 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8721 if (ret != PTP_RC_OK) {
8722 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8723 return -1;
8724 }
8725 /*
8726 * TODO: when walking through these object properties, make calls to
8727 * a new function in ptp.h/ptp.c that can send the command
8728 * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8729 * supported.
8730 */
8731 for (i = 0; i < propcnt; i++) {
8732 switch(props[i]) {
8733 case PTP_OPC_RepresentativeSampleData:
8734 support_data = 1;
8735 break;
8736 case PTP_OPC_RepresentativeSampleFormat:
8737 support_format = 1;
8738 break;
8739 case PTP_OPC_RepresentativeSampleSize:
8740 support_size = 1;
8741 break;
8742 case PTP_OPC_RepresentativeSampleHeight:
8743 support_height = 1;
8744 break;
8745 case PTP_OPC_RepresentativeSampleWidth:
8746 support_width = 1;
8747 break;
8748 case PTP_OPC_RepresentativeSampleDuration:
8749 support_duration = 1;
8750 break;
8751 default:
8752 break;
8753 }
8754 }
8755 free(props);
8756
8757 if (support_data && support_format && support_height && support_width && !support_duration) {
8758 // Something that supports height and width and not duration is likely to be JPEG
8759 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8760 /*
8761 * Populate the sample format with the first supported format
8762 *
8763 * TODO: figure out how to pass back more than one format if more are
8764 * supported by the device.
8765 */
8766 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8767 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8768 ptp_free_objectpropdesc(&opd_format);
8769 /* Populate the maximum image height */
8770 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8771 retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8772 ptp_free_objectpropdesc(&opd_width);
8773 /* Populate the maximum image width */
8774 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8775 retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8776 ptp_free_objectpropdesc(&opd_height);
8777 /* Populate the maximum size */
8778 if (support_size) {
8779 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8780 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8781 ptp_free_objectpropdesc(&opd_size);
8782 }
8783 *sample = retsam;
8784 } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8785 // Another qualified guess
8786 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8787 /*
8788 * Populate the sample format with the first supported format
8789 *
8790 * TODO: figure out how to pass back more than one format if more are
8791 * supported by the device.
8792 */
8793 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8794 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8795 ptp_free_objectpropdesc(&opd_format);
8796 /* Populate the maximum duration */
8797 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8798 retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8799 ptp_free_objectpropdesc(&opd_duration);
8800 /* Populate the maximum size */
8801 if (support_size) {
8802 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8803 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8804 ptp_free_objectpropdesc(&opd_size);
8805 }
8806 *sample = retsam;
8807 }
8808 return 0;
8809 }
8810
8811 /**
8812 * This routine sends representative sample data for an object.
8813 * This uses the RepresentativeSampleData property of the album,
8814 * if the device supports it. The data should be of a format acceptable
8815 * to the player (for iRiver and Creative, this seems to be JPEG) and
8816 * must not be too large. (for a Creative, max seems to be about 20KB.)
8817 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8818 * maximum size, dimensions, etc..
8819 * @param device a pointer to the device which the object is on.
8820 * @param id unique id of the object to set artwork for.
8821 * @param pointer to LIBMTP_filesampledata_t struct containing data
8822 * @return 0 on success, any other value means failure.
8823 * @see LIBMTP_Get_Representative_Sample()
8824 * @see LIBMTP_Get_Representative_Sample_Format()
8825 * @see LIBMTP_Create_New_Album()
8826 */
8827 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8828 uint32_t const id,
8829 LIBMTP_filesampledata_t *sampledata)
8830 {
8831 uint16_t ret;
8832 PTPParams *params = (PTPParams *) device->params;
8833 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8834 PTPPropertyValue propval;
8835 PTPObject *ob;
8836 uint32_t i;
8837 uint16_t *props = NULL;
8838 uint32_t propcnt = 0;
8839 int supported = 0;
8840
8841 // get the file format for the object we're going to send representative data for
8842 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8843 if (ret != PTP_RC_OK) {
8844 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8845 return -1;
8846 }
8847
8848 // check that we can send representative sample data for this object format
8849 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8850 if (ret != PTP_RC_OK) {
8851 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8852 return -1;
8853 }
8854
8855 for (i = 0; i < propcnt; i++) {
8856 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8857 supported = 1;
8858 break;
8859 }
8860 }
8861 if (!supported) {
8862 free(props);
8863 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8864 return -1;
8865 }
8866 free(props);
8867
8868 // Go ahead and send the data
8869 propval.a.count = sampledata->size;
8870 propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8871 for (i = 0; i < sampledata->size; i++) {
8872 propval.a.v[i].u8 = sampledata->data[i];
8873 }
8874
8875 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8876 &propval,PTP_DTC_AUINT8);
8877 if (ret != PTP_RC_OK) {
8878 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8879 free(propval.a.v);
8880 return -1;
8881 }
8882 free(propval.a.v);
8883
8884 /* Set the height and width if the sample is an image, otherwise just
8885 * set the duration and size */
8886 switch(sampledata->filetype) {
8887 case LIBMTP_FILETYPE_JPEG:
8888 case LIBMTP_FILETYPE_JFIF:
8889 case LIBMTP_FILETYPE_TIFF:
8890 case LIBMTP_FILETYPE_BMP:
8891 case LIBMTP_FILETYPE_GIF:
8892 case LIBMTP_FILETYPE_PICT:
8893 case LIBMTP_FILETYPE_PNG:
8894 if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8895 // For images, set the height and width
8896 set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8897 set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8898 }
8899 break;
8900 default:
8901 // For anything not an image, set the duration and size
8902 set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8903 set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8904 break;
8905 }
8906
8907 return 0;
8908 }
8909
8910 /**
8911 * This routine gets representative sample data for an object.
8912 * This uses the RepresentativeSampleData property of the album,
8913 * if the device supports it.
8914 * @param device a pointer to the device which the object is on.
8915 * @param id unique id of the object to get data for.
8916 * @param pointer to LIBMTP_filesampledata_t struct to receive data
8917 * @return 0 on success, any other value means failure.
8918 * @see LIBMTP_Send_Representative_Sample()
8919 * @see LIBMTP_Get_Representative_Sample_Format()
8920 * @see LIBMTP_Create_New_Album()
8921 */
8922 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8923 uint32_t const id,
8924 LIBMTP_filesampledata_t *sampledata)
8925 {
8926 uint16_t ret;
8927 PTPParams *params = (PTPParams *) device->params;
8928 PTPPropertyValue propval;
8929 PTPObject *ob;
8930 uint32_t i;
8931 uint16_t *props = NULL;
8932 uint32_t propcnt = 0;
8933 int supported = 0;
8934
8935 // get the file format for the object we're going to send representative data for
8936 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8937 if (ret != PTP_RC_OK) {
8938 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8939 return -1;
8940 }
8941
8942 // check that we can store representative sample data for this object format
8943 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8944 if (ret != PTP_RC_OK) {
8945 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8946 return -1;
8947 }
8948
8949 for (i = 0; i < propcnt; i++) {
8950 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8951 supported = 1;
8952 break;
8953 }
8954 }
8955 if (!supported) {
8956 free(props);
8957 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8958 return -1;
8959 }
8960 free(props);
8961
8962 // Get the data
8963 ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8964 &propval,PTP_DTC_AUINT8);
8965 if (ret != PTP_RC_OK) {
8966 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8967 return -1;
8968 }
8969
8970 // Store it
8971 sampledata->size = propval.a.count;
8972 sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8973 for (i = 0; i < propval.a.count; i++) {
8974 sampledata->data[i] = propval.a.v[i].u8;
8975 }
8976 free(propval.a.v);
8977
8978 // Get the other properties
8979 sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8980 sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8981 sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8982 sampledata->filetype = map_ptp_type_to_libmtp_type(
8983 get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8984
8985 return 0;
8986 }
8987
8988 /**
8989 * Retrieve the thumbnail for a file.
8990 * @param device a pointer to the device to get the thumbnail from.
8991 * @param id the object ID of the file to retrieve the thumbnail for.
8992 * @return 0 on success, any other value means failure.
8993 */
8994 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
8995 unsigned char **data, unsigned int *size)
8996 {
8997 PTPParams *params = (PTPParams *) device->params;
8998 uint16_t ret;
8999
9000 ret = ptp_getthumb(params, id, data, size);
9001 if (ret == PTP_RC_OK)
9002 return 0;
9003 return -1;
9004 }
9005
9006
9007 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9008 uint64_t offset, uint32_t maxbytes,
9009 unsigned char **data, unsigned int *size)
9010 {
9011 PTPParams *params = (PTPParams *) device->params;
9012 uint16_t ret;
9013
9014 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_GetPartialObject64)) {
9015 if (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
9016 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9017 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
9018 return -1;
9019 }
9020
9021 if (offset >> 32 != 0) {
9022 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9023 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject only supports 32bit offsets");
9024 return -1;
9025 }
9026
9027 ret = ptp_getpartialobject(params, id, (uint32_t)offset, maxbytes, data, size);
9028 } else {
9029 ret = ptp_android_getpartialobject64(params, id, offset, maxbytes, data, size);
9030 }
9031 if (ret == PTP_RC_OK)
9032 return 0;
9033 return -1;
9034 }
9035
9036
9037 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9038 uint64_t offset, unsigned char *data, unsigned int size)
9039 {
9040 PTPParams *params = (PTPParams *) device->params;
9041 uint16_t ret;
9042
9043 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
9044 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9045 "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
9046 return -1;
9047 }
9048
9049 ret = ptp_android_sendpartialobject(params, id, offset, data, size);
9050 if (ret == PTP_RC_OK)
9051 return 0;
9052 return -1;
9053 }
9054
9055
9056 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9057 {
9058 PTPParams *params = (PTPParams *) device->params;
9059 uint16_t ret;
9060
9061 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
9062 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9063 "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
9064 return -1;
9065 }
9066
9067 ret = ptp_android_begineditobject(params, id);
9068 if (ret == PTP_RC_OK)
9069 return 0;
9070 return -1;
9071 }
9072
9073
9074 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9075 {
9076 PTPParams *params = (PTPParams *) device->params;
9077 uint16_t ret;
9078
9079 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
9080 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9081 "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
9082 return -1;
9083 }
9084
9085 ret = ptp_android_endeditobject(params, id);
9086 if (ret == PTP_RC_OK) {
9087 // update cached object properties if metadata cache exists
9088 update_metadata_cache(device, id);
9089 return 0;
9090 }
9091 return -1;
9092 }
9093
9094
9095 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9096 uint64_t offset)
9097 {
9098 PTPParams *params = (PTPParams *) device->params;
9099 uint16_t ret;
9100
9101 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9102 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9103 "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9104 return -1;
9105 }
9106
9107 ret = ptp_android_truncate(params, id, offset);
9108 if (ret == PTP_RC_OK)
9109 return 0;
9110 return -1;
9111 }
9112
9113
9114 /**
9115 * This routine updates an album based on the metadata
9116 * supplied. If the <code>tracks</code> field of the metadata
9117 * contains a track listing, these tracks will be added to the
9118 * album in place of those already present, i.e. the
9119 * previous track listing will be deleted.
9120 * @param device a pointer to the device to create the new album on.
9121 * @param metadata the metadata for the album to be updated.
9122 * notice that the field <code>album_id</code>
9123 * must contain the apropriate album ID.
9124 * @return 0 on success, any other value means failure.
9125 * @see LIBMTP_Create_New_Album()
9126 * @see LIBMTP_Delete_Object()
9127 */
9128 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9129 LIBMTP_album_t const * const metadata)
9130 {
9131 return update_abstract_list(device,
9132 metadata->name,
9133 metadata->artist,
9134 metadata->composer,
9135 metadata->genre,
9136 metadata->album_id,
9137 PTP_OFC_MTP_AbstractAudioAlbum,
9138 metadata->tracks,
9139 metadata->no_tracks);
9140 }
9141
9142 /**
9143 * Dummy function needed to interface to upstream
9144 * ptp.c/ptp.h files.
9145 */
9146 void ptp_nikon_getptpipguid (unsigned char* guid) {
9147 return;
9148 }
9149
9150 /**
9151 * Add an object to cache.
9152 * @param device the device which may have a cache to which the object should be added.
9153 * @param object_id the object to add to the cache.
9154 */
9155 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9156 {
9157 PTPParams *params = (PTPParams *)device->params;
9158 uint16_t ret;
9159
9160 ret = ptp_add_object_to_cache(params, object_id);
9161 if (ret != PTP_RC_OK) {
9162 add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9163 }
9164 }
9165
9166
9167 /**
9168 * Update cache after object has been modified
9169 * @param device the device which may have a cache to which the object should be updated.
9170 * @param object_id the object to update.
9171 */
9172 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9173 {
9174 PTPParams *params = (PTPParams *)device->params;
9175
9176 ptp_remove_object_from_cache(params, object_id);
9177 add_object_to_cache(device, object_id);
9178 }
9179
9180
9181 /**
9182 * Issue custom (e.g. vendor specific) operation (without data phase)
9183 * @param device a pointer to the device to send custom operation to.
9184 * @param code operation code to send.
9185 * @param n_param number of parameters passed.
9186 * @param ... uint32_t operation specific parameters.
9187 */
9188 int LIBMTP_Custom_Operation(LIBMTP_mtpdevice_t *device, uint16_t code, int n_param, ...)
9189 {
9190 PTPParams *params = (PTPParams *) device->params;
9191 PTPContainer ptp;
9192 va_list args;
9193 uint16_t ret;
9194 int i;
9195
9196 ptp.Code = code;
9197 ptp.Nparam = n_param;
9198 va_start(args, n_param);
9199 for (i = 0; i < n_param; i++)
9200 (&ptp.Param1)[i] = va_arg(args, uint32_t);
9201 va_end(args);
9202
9203 ret = ptp_transaction_new(params, &ptp, PTP_DP_NODATA, 0, NULL);
9204
9205 if (ret != PTP_RC_OK) {
9206 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Custom_Operation(): failed to execute operation.");
9207 return -1;
9208 }
9209
9210 return 0;
9211 }
9212