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