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