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   struct utimbuf mtime;
   4720   int ret;
   4721 
   4722   // Sanity check
   4723   if (path == NULL) {
   4724     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
   4725     return -1;
   4726   }
   4727 
   4728   // Open file
   4729 #ifdef __WIN32__
   4730 #ifdef USE_WINDOWS_IO_H
   4731   if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
   4732 #else
   4733   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
   4734 #endif
   4735 #else
   4736   if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
   4737 #endif
   4738     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
   4739     return -1;
   4740   }
   4741 
   4742   ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data, &mtime);
   4743 
   4744   // Close file
   4745   close(fd);
   4746 
   4747   // Delete partial file.
   4748   if (ret == -1) {
   4749     unlink(path);
   4750   } else {
   4751       utime(path, &mtime);
   4752   }
   4753   return ret;
   4754 }
   4755 
   4756 /**
   4757  * This gets a file off the device to a file identified
   4758  * by a file descriptor.
   4759  *
   4760  * This function can potentially be used for streaming
   4761  * files off the device for playback or broadcast for example,
   4762  * by downloading the file into a stream sink e.g. a socket.
   4763  *
   4764  * @param device a pointer to the device to get the file from.
   4765  * @param id the file ID of the file to retrieve.
   4766  * @param fd a local file descriptor to write the file to.
   4767  * @param callback a progress indicator function or NULL to ignore.
   4768  * @param data a user-defined pointer that is passed along to
   4769  *             the <code>progress</code> function in order to
   4770  *             pass along some user defined data to the progress
   4771  *             updates. If not used, set this to NULL.
   4772  * @param mtime out parameter to return the timestamp for file on
   4773  *             the device.
   4774  * @return 0 if the transfer was successful, any other value means
   4775  *             failure.
   4776  * @see LIBMTP_Get_File_To_File()
   4777  */
   4778 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
   4779 					uint32_t const id,
   4780 					int const fd,
   4781 					LIBMTP_progressfunc_t const callback,
   4782 					void const * const data,
   4783                     struct utimbuf * mtime)
   4784 {
   4785   uint16_t ret;
   4786   PTPParams *params = (PTPParams *) device->params;
   4787   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   4788   PTPObject *ob;
   4789 
   4790   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   4791   if (ret != PTP_RC_OK) {
   4792     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
   4793     return -1;
   4794   }
   4795   if (ob->oi.ObjectFormat == PTP_OFC_Association) {
   4796     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
   4797     return -1;
   4798   }
   4799 
   4800   if (mtime != NULL) {
   4801     mtime->actime = ob->oi.CaptureDate;
   4802     mtime->modtime = ob->oi.ModificationDate;
   4803   }
   4804 
   4805   // Callbacks
   4806   ptp_usb->callback_active = 1;
   4807   ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
   4808     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
   4809   ptp_usb->current_transfer_complete = 0;
   4810   ptp_usb->current_transfer_callback = callback;
   4811   ptp_usb->current_transfer_callback_data = data;
   4812 
   4813   ret = ptp_getobject_tofd(params, id, fd);
   4814 
   4815   ptp_usb->callback_active = 0;
   4816   ptp_usb->current_transfer_callback = NULL;
   4817   ptp_usb->current_transfer_callback_data = NULL;
   4818 
   4819   if (ret == PTP_ERROR_CANCEL) {
   4820     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
   4821     return -1;
   4822   }
   4823   if (ret != PTP_RC_OK) {
   4824     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
   4825     return -1;
   4826   }
   4827 
   4828   return 0;
   4829 }
   4830 
   4831 /**
   4832  * This gets a file off the device and calls put_func
   4833  * with chunks of data
   4834  *
   4835  * @param device a pointer to the device to get the file from.
   4836  * @param id the file ID of the file to retrieve.
   4837  * @param put_func the function to call when we have data.
   4838  * @param priv the user-defined pointer that is passed to
   4839  *             <code>put_func</code>.
   4840  * @param callback a progress indicator function or NULL to ignore.
   4841  * @param data a user-defined pointer that is passed along to
   4842  *             the <code>progress</code> function in order to
   4843  *             pass along some user defined data to the progress
   4844  *             updates. If not used, set this to NULL.
   4845  * @return 0 if the transfer was successful, any other value means
   4846  *           failure.
   4847  */
   4848 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
   4849 					uint32_t const id,
   4850 					MTPDataPutFunc put_func,
   4851           void * priv,
   4852 					LIBMTP_progressfunc_t const callback,
   4853 					void const * const data)
   4854 {
   4855   PTPObject *ob;
   4856   uint16_t ret;
   4857   PTPParams *params = (PTPParams *) device->params;
   4858   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   4859 
   4860   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   4861   if (ret != PTP_RC_OK) {
   4862     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
   4863     return -1;
   4864   }
   4865   if (ob->oi.ObjectFormat == PTP_OFC_Association) {
   4866     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
   4867     return -1;
   4868   }
   4869 
   4870   // Callbacks
   4871   ptp_usb->callback_active = 1;
   4872   ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
   4873     PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
   4874   ptp_usb->current_transfer_complete = 0;
   4875   ptp_usb->current_transfer_callback = callback;
   4876   ptp_usb->current_transfer_callback_data = data;
   4877 
   4878   MTPDataHandler mtp_handler;
   4879   mtp_handler.getfunc = NULL;
   4880   mtp_handler.putfunc = put_func;
   4881   mtp_handler.priv = priv;
   4882 
   4883   PTPDataHandler handler;
   4884   handler.getfunc = NULL;
   4885   handler.putfunc = put_func_wrapper;
   4886   handler.priv = &mtp_handler;
   4887 
   4888   ret = ptp_getobject_to_handler(params, id, &handler);
   4889 
   4890   ptp_usb->callback_active = 0;
   4891   ptp_usb->current_transfer_callback = NULL;
   4892   ptp_usb->current_transfer_callback_data = NULL;
   4893 
   4894   if (ret == PTP_ERROR_CANCEL) {
   4895     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
   4896     return -1;
   4897   }
   4898   if (ret != PTP_RC_OK) {
   4899     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
   4900     return -1;
   4901   }
   4902 
   4903   return 0;
   4904 }
   4905 
   4906 
   4907 /**
   4908  * This gets a track off the device to a file identified
   4909  * by a filename. This is actually just a wrapper for the
   4910  * \c LIBMTP_Get_Track_To_File() function.
   4911  * @param device a pointer to the device to get the track from.
   4912  * @param id the track ID of the track to retrieve.
   4913  * @param path a filename to use for the retrieved track.
   4914  * @param callback a progress indicator function or NULL to ignore.
   4915  * @param data a user-defined pointer that is passed along to
   4916  *             the <code>progress</code> function in order to
   4917  *             pass along some user defined data to the progress
   4918  *             updates. If not used, set this to NULL.
   4919  * @return 0 if the transfer was successful, any other value means
   4920  *           failure.
   4921  * @see LIBMTP_Get_Track_To_File_Descriptor()
   4922  */
   4923 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
   4924 			 char const * const path, LIBMTP_progressfunc_t const callback,
   4925 			 void const * const data)
   4926 {
   4927   // This is just a wrapper
   4928   return LIBMTP_Get_File_To_File(device, id, path, callback, data);
   4929 }
   4930 
   4931 /**
   4932  * This gets a track off the device to a file identified
   4933  * by a file descriptor. This is actually just a wrapper for
   4934  * the \c LIBMTP_Get_File_To_File_Descriptor() function.
   4935  * @param device a pointer to the device to get the track from.
   4936  * @param id the track ID of the track to retrieve.
   4937  * @param fd a file descriptor to write the track to.
   4938  * @param callback a progress indicator function or NULL to ignore.
   4939  * @param data a user-defined pointer that is passed along to
   4940  *             the <code>progress</code> function in order to
   4941  *             pass along some user defined data to the progress
   4942  *             updates. If not used, set this to NULL.
   4943  * @param mtime out parameter to return the timestamp for file on
   4944  *             the device.
   4945  * @return 0 if the transfer was successful, any other value means
   4946  *           failure.
   4947  * @see LIBMTP_Get_Track_To_File()
   4948  */
   4949 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
   4950 					uint32_t const id,
   4951 					int const fd,
   4952 					LIBMTP_progressfunc_t const callback,
   4953 					void const * const data,
   4954                     struct utimbuf * mtime)
   4955 {
   4956   // This is just a wrapper
   4957   return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data, mtime);
   4958 }
   4959 
   4960 /**
   4961  * This gets a track off the device to a handler function.
   4962  * This is actually just a wrapper for
   4963  * the \c LIBMTP_Get_File_To_Handler() function.
   4964  * @param device a pointer to the device to get the track from.
   4965  * @param id the track ID of the track to retrieve.
   4966  * @param put_func the function to call when we have data.
   4967  * @param priv the user-defined pointer that is passed to
   4968  *             <code>put_func</code>.
   4969  * @param callback a progress indicator function or NULL to ignore.
   4970  * @param data a user-defined pointer that is passed along to
   4971  *             the <code>progress</code> function in order to
   4972  *             pass along some user defined data to the progress
   4973  *             updates. If not used, set this to NULL.
   4974  * @return 0 if the transfer was successful, any other value means
   4975  *           failure.
   4976  */
   4977 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
   4978 					uint32_t const id,
   4979 					MTPDataPutFunc put_func,
   4980           void * priv,
   4981 					LIBMTP_progressfunc_t const callback,
   4982 					void const * const data)
   4983 {
   4984   // This is just a wrapper
   4985   return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
   4986 }
   4987 
   4988 /**
   4989  * This function sends a track from a local file to an
   4990  * MTP device. A filename and a set of metadata must be
   4991  * given as input.
   4992  * @param device a pointer to the device to send the track to.
   4993  * @param path the filename of a local file which will be sent.
   4994  * @param metadata a track metadata set to be written along with the file.
   4995  *        After this call the field <code>metadata-&gt;item_id</code>
   4996  *        will contain the new track ID. Other fields such
   4997  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
   4998  *        or <code>metadata-&gt;storage_id</code> may also change during this
   4999  *        operation due to device restrictions, so do not rely on the
   5000  *        contents of this struct to be preserved in any way.
   5001  *        <ul>
   5002  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
   5003  *        (e.g. folder) to store this track in. Since some
   5004  *        devices are a bit picky about where files
   5005  *        are placed, a default folder will be chosen if libmtp
   5006  *        has detected one for the current filetype and this
   5007  *        parameter is set to 0. If this is 0 and no default folder
   5008  *        can be found, the file will be stored in the root folder.
   5009  *        <li><code>metadata-&gt;storage_id</code> should be set to the
   5010  *        desired storage (e.g. memory card or whatever your device
   5011  *        presents) to store this track in. Setting this to 0 will store
   5012  *        the track on the primary storage.
   5013  *        </ul>
   5014  * @param callback a progress indicator function or NULL to ignore.
   5015  * @param data a user-defined pointer that is passed along to
   5016  *             the <code>progress</code> function in order to
   5017  *             pass along some user defined data to the progress
   5018  *             updates. If not used, set this to NULL.
   5019  * @return 0 if the transfer was successful, any other value means
   5020  *           failure.
   5021  * @see LIBMTP_Send_Track_From_File_Descriptor()
   5022  * @see LIBMTP_Send_File_From_File()
   5023  * @see LIBMTP_Delete_Object()
   5024  */
   5025 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
   5026 			 char const * const path, LIBMTP_track_t * const metadata,
   5027                          LIBMTP_progressfunc_t const callback,
   5028 			 void const * const data)
   5029 {
   5030   int fd;
   5031   int ret;
   5032 
   5033   // Sanity check
   5034   if (path == NULL) {
   5035     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
   5036     return -1;
   5037   }
   5038 
   5039   // Open file
   5040 #ifdef __WIN32__
   5041 #ifdef USE_WINDOWS_IO_H
   5042   if ( (fd = _open(path, O_RDONLY|O_BINARY) == -1) ) {
   5043 #else
   5044   if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
   5045 #endif
   5046 #else
   5047   if ( (fd = open(path, O_RDONLY)) == -1) {
   5048 #endif
   5049     printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
   5050     return -1;
   5051   }
   5052 
   5053   ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
   5054 
   5055   // Close file.
   5056 #ifdef USE_WINDOWS_IO_H
   5057   _close(fd);
   5058 #else
   5059   close(fd);
   5060 #endif
   5061 
   5062   return ret;
   5063 }
   5064 
   5065 /**
   5066  * This function sends a track from a file descriptor to an
   5067  * MTP device. A filename and a set of metadata must be
   5068  * given as input.
   5069  * @param device a pointer to the device to send the track to.
   5070  * @param fd the filedescriptor for a local file which will be sent.
   5071  * @param metadata a track metadata set to be written along with the file.
   5072  *        After this call the field <code>metadata-&gt;item_id</code>
   5073  *        will contain the new track ID. Other fields such
   5074  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
   5075  *        or <code>metadata-&gt;storage_id</code> may also change during this
   5076  *        operation due to device restrictions, so do not rely on the
   5077  *        contents of this struct to be preserved in any way.
   5078  *        <ul>
   5079  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
   5080  *        (e.g. folder) to store this track in. Since some
   5081  *        devices are a bit picky about where files
   5082  *        are placed, a default folder will be chosen if libmtp
   5083  *        has detected one for the current filetype and this
   5084  *        parameter is set to 0. If this is 0 and no default folder
   5085  *        can be found, the file will be stored in the root folder.
   5086  *        <li><code>metadata-&gt;storage_id</code> should be set to the
   5087  *        desired storage (e.g. memory card or whatever your device
   5088  *        presents) to store this track in. Setting this to 0 will store
   5089  *        the track on the primary storage.
   5090  *        </ul>
   5091  * @param callback a progress indicator function or NULL to ignore.
   5092  * @param data a user-defined pointer that is passed along to
   5093  *             the <code>progress</code> function in order to
   5094  *             pass along some user defined data to the progress
   5095  *             updates. If not used, set this to NULL.
   5096  * @return 0 if the transfer was successful, any other value means
   5097  *           failure.
   5098  * @see LIBMTP_Send_Track_From_File()
   5099  * @see LIBMTP_Delete_Object()
   5100  */
   5101 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
   5102 			 int const fd, LIBMTP_track_t * const metadata,
   5103                          LIBMTP_progressfunc_t const callback,
   5104 			 void const * const data)
   5105 {
   5106   int subcall_ret;
   5107   LIBMTP_file_t filedata;
   5108 
   5109   // Sanity check, is this really a track?
   5110   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
   5111     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5112 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
   5113 			    "I don't think this is actually a track, strange filetype...");
   5114   }
   5115 
   5116   // Wrap around the file transfer function
   5117   filedata.item_id = metadata->item_id;
   5118   filedata.parent_id = metadata->parent_id;
   5119   filedata.storage_id = metadata->storage_id;
   5120   filedata.filename = metadata->filename;
   5121   filedata.filesize = metadata->filesize;
   5122   filedata.filetype = metadata->filetype;
   5123   filedata.next = NULL;
   5124 
   5125   subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
   5126 						      fd,
   5127 						      &filedata,
   5128 						      callback,
   5129 						      data);
   5130 
   5131   if (subcall_ret != 0) {
   5132     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5133 			    "LIBMTP_Send_Track_From_File_Descriptor(): "
   5134 			    "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
   5135     // We used to delete the file here, but don't... It might be OK after all.
   5136     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
   5137     return -1;
   5138   }
   5139 
   5140   // Pick up new item (and parent, storage) ID
   5141   metadata->item_id = filedata.item_id;
   5142   metadata->parent_id = filedata.parent_id;
   5143   metadata->storage_id = filedata.storage_id;
   5144 
   5145   // Set track metadata for the new fine track
   5146   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
   5147   if (subcall_ret != 0) {
   5148     // Subcall will add error to errorstack
   5149     // We used to delete the file here, but don't... It might be OK after all.
   5150     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
   5151     return -1;
   5152   }
   5153 
   5154   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
   5155   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
   5156 
   5157   return 0;
   5158 }
   5159 
   5160 /**
   5161  * This function sends a track from a handler function to an
   5162  * MTP device. A filename and a set of metadata must be
   5163  * given as input.
   5164  * @param device a pointer to the device to send the track to.
   5165  * @param get_func the function to call when we have data.
   5166  * @param priv the user-defined pointer that is passed to
   5167  *             <code>get_func</code>.
   5168  * @param metadata a track metadata set to be written along with the file.
   5169  *        After this call the field <code>metadata-&gt;item_id</code>
   5170  *        will contain the new track ID. Other fields such
   5171  *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
   5172  *        or <code>metadata-&gt;storage_id</code> may also change during this
   5173  *        operation due to device restrictions, so do not rely on the
   5174  *        contents of this struct to be preserved in any way.
   5175  *        <ul>
   5176  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
   5177  *        (e.g. folder) to store this track in. Since some
   5178  *        devices are a bit picky about where files
   5179  *        are placed, a default folder will be chosen if libmtp
   5180  *        has detected one for the current filetype and this
   5181  *        parameter is set to 0. If this is 0 and no default folder
   5182  *        can be found, the file will be stored in the root folder.
   5183  *        <li><code>metadata-&gt;storage_id</code> should be set to the
   5184  *        desired storage (e.g. memory card or whatever your device
   5185  *        presents) to store this track in. Setting this to 0 will store
   5186  *        the track on the primary storage.
   5187  *        </ul>
   5188  * @param callback a progress indicator function or NULL to ignore.
   5189  * @param data a user-defined pointer that is passed along to
   5190  *             the <code>progress</code> function in order to
   5191  *             pass along some user defined data to the progress
   5192  *             updates. If not used, set this to NULL.
   5193  * @return 0 if the transfer was successful, any other value means
   5194  *           failure.
   5195  * @see LIBMTP_Send_Track_From_File()
   5196  * @see LIBMTP_Delete_Object()
   5197  */
   5198 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
   5199 			 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
   5200                          LIBMTP_progressfunc_t const callback,
   5201 			 void const * const data)
   5202 {
   5203   int subcall_ret;
   5204   LIBMTP_file_t filedata;
   5205 
   5206   // Sanity check, is this really a track?
   5207   if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
   5208     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5209 			    "LIBMTP_Send_Track_From_Handler(): "
   5210 			    "I don't think this is actually a track, strange filetype...");
   5211   }
   5212 
   5213   // Wrap around the file transfer function
   5214   filedata.item_id = metadata->item_id;
   5215   filedata.parent_id = metadata->parent_id;
   5216   filedata.storage_id = metadata->storage_id;
   5217   filedata.filename = metadata->filename;
   5218   filedata.filesize = metadata->filesize;
   5219   filedata.filetype = metadata->filetype;
   5220   filedata.next = NULL;
   5221 
   5222   subcall_ret = LIBMTP_Send_File_From_Handler(device,
   5223 						      get_func,
   5224                   priv,
   5225 						      &filedata,
   5226 						      callback,
   5227 						      data);
   5228 
   5229   if (subcall_ret != 0) {
   5230     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5231 			    "LIBMTP_Send_Track_From_Handler(): "
   5232 			    "subcall to LIBMTP_Send_File_From_Handler failed.");
   5233     // We used to delete the file here, but don't... It might be OK after all.
   5234     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
   5235     return -1;
   5236   }
   5237 
   5238   // Pick up new item (and parent, storage) ID
   5239   metadata->item_id = filedata.item_id;
   5240   metadata->parent_id = filedata.parent_id;
   5241   metadata->storage_id = filedata.storage_id;
   5242 
   5243   // Set track metadata for the new fine track
   5244   subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
   5245   if (subcall_ret != 0) {
   5246     // Subcall will add error to errorstack
   5247     // We used to delete the file here, but don't... It might be OK after all.
   5248     // (void) LIBMTP_Delete_Object(device, metadata->item_id);
   5249     return -1;
   5250   }
   5251 
   5252   // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
   5253   // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
   5254 
   5255   return 0;
   5256 }
   5257 
   5258 /**
   5259  * This function sends a local file to an MTP device.
   5260  * A filename and a set of metadata must be
   5261  * given as input.
   5262  * @param device a pointer to the device to send the track to.
   5263  * @param path the filename of a local file which will be sent.
   5264  * @param filedata a file metadata set to be written along with the file.
   5265  *        After this call the field <code>filedata-&gt;item_id</code>
   5266  *        will contain the new file ID. Other fields such
   5267  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
   5268  *        or <code>filedata-&gt;storage_id</code> may also change during this
   5269  *        operation due to device restrictions, so do not rely on the
   5270  *        contents of this struct to be preserved in any way.
   5271  *        <ul>
   5272  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
   5273  *        (e.g. folder) to store this file in. If this is 0,
   5274  *        the file will be stored in the root folder.
   5275  *        <li><code>filedata-&gt;storage_id</code> should be set to the
   5276  *        desired storage (e.g. memory card or whatever your device
   5277  *        presents) to store this file in. Setting this to 0 will store
   5278  *        the file on the primary storage.
   5279  *        </ul>
   5280  * @param callback a progress indicator function or NULL to ignore.
   5281  * @param data a user-defined pointer that is passed along to
   5282  *             the <code>progress</code> function in order to
   5283  *             pass along some user defined data to the progress
   5284  *             updates. If not used, set this to NULL.
   5285  * @return 0 if the transfer was successful, any other value means
   5286  *           failure.
   5287  * @see LIBMTP_Send_File_From_File_Descriptor()
   5288  * @see LIBMTP_Delete_Object()
   5289  */
   5290 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
   5291 			       char const * const path, LIBMTP_file_t * const filedata,
   5292 			       LIBMTP_progressfunc_t const callback,
   5293 			       void const * const data)
   5294 {
   5295   int fd;
   5296   int ret;
   5297 
   5298   // Sanity check
   5299   if (path == NULL) {
   5300     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
   5301     return -1;
   5302   }
   5303 
   5304   // Open file
   5305 #ifdef __WIN32__
   5306 #ifdef USE_WINDOWS_IO_H
   5307   if ( (fd = _open(path, O_RDONLY|O_BINARY) == -1) ) {
   5308 #else
   5309   if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
   5310 #endif
   5311 #else
   5312   if ( (fd = open(path, O_RDONLY)) == -1) {
   5313 #endif
   5314     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
   5315     return -1;
   5316   }
   5317 
   5318   ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
   5319 
   5320   // Close file.
   5321 #ifdef USE_WINDOWS_IO_H
   5322   _close(fd);
   5323 #else
   5324   close(fd);
   5325 #endif
   5326 
   5327   return ret;
   5328 }
   5329 
   5330 /**
   5331  * This function sends a generic file from a file descriptor to an
   5332  * MTP device. A filename and a set of metadata must be
   5333  * given as input.
   5334  *
   5335  * This can potentially be used for sending in a stream of unknown
   5336  * length. Send music files with
   5337  * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
   5338  *
   5339  * @param device a pointer to the device to send the file to.
   5340  * @param fd the filedescriptor for a local file which will be sent.
   5341  * @param filedata a file metadata set to be written along with the file.
   5342  *        After this call the field <code>filedata-&gt;item_id</code>
   5343  *        will contain the new file ID. Other fields such
   5344  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
   5345  *        or <code>filedata-&gt;storage_id</code> may also change during this
   5346  *        operation due to device restrictions, so do not rely on the
   5347  *        contents of this struct to be preserved in any way.
   5348  *        <ul>
   5349  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
   5350  *        (e.g. folder) to store this file in. If this is 0,
   5351  *        the file will be stored in the root folder.
   5352  *        <li><code>filedata-&gt;storage_id</code> should be set to the
   5353  *        desired storage (e.g. memory card or whatever your device
   5354  *        presents) to store this file in. Setting this to 0 will store
   5355  *        the file on the primary storage.
   5356  *        </ul>
   5357  * @param callback a progress indicator function or NULL to ignore.
   5358  * @param data a user-defined pointer that is passed along to
   5359  *             the <code>progress</code> function in order to
   5360  *             pass along some user defined data to the progress
   5361  *             updates. If not used, set this to NULL.
   5362  * @return 0 if the transfer was successful, any other value means
   5363  *           failure.
   5364  * @see LIBMTP_Send_File_From_File()
   5365  * @see LIBMTP_Send_Track_From_File_Descriptor()
   5366  * @see LIBMTP_Delete_Object()
   5367  */
   5368 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
   5369 			 int const fd, LIBMTP_file_t * const filedata,
   5370                          LIBMTP_progressfunc_t const callback,
   5371 			 void const * const data)
   5372 {
   5373   uint16_t ret;
   5374   PTPParams *params = (PTPParams *) device->params;
   5375   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   5376   LIBMTP_file_t *newfilemeta;
   5377 
   5378   if (send_file_object_info(device, filedata))
   5379   {
   5380     // no need to output an error since send_file_object_info will already have done so
   5381     return -1;
   5382   }
   5383 
   5384   // Callbacks
   5385   ptp_usb->callback_active = 1;
   5386   // The callback will deactivate itself after this amount of data has been sent
   5387   // One BULK header for the request, one for the data phase. No parameters to the request.
   5388   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
   5389   ptp_usb->current_transfer_complete = 0;
   5390   ptp_usb->current_transfer_callback = callback;
   5391   ptp_usb->current_transfer_callback_data = data;
   5392 
   5393   ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
   5394 
   5395   ptp_usb->callback_active = 0;
   5396   ptp_usb->current_transfer_callback = NULL;
   5397   ptp_usb->current_transfer_callback_data = NULL;
   5398 
   5399   if (ret == PTP_ERROR_CANCEL) {
   5400     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
   5401     return -1;
   5402   }
   5403   if (ret != PTP_RC_OK) {
   5404     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
   5405 				"Could not send object.");
   5406     return -1;
   5407   }
   5408 
   5409   add_object_to_cache(device, filedata->item_id);
   5410 
   5411   /*
   5412    * Get the device-assined parent_id from the cache.
   5413    * The operation that adds it to the cache will
   5414    * look it up from the device, so we get the new
   5415    * parent_id from the cache.
   5416    */
   5417   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
   5418   if (newfilemeta != NULL) {
   5419     filedata->parent_id = newfilemeta->parent_id;
   5420     filedata->storage_id = newfilemeta->storage_id;
   5421     LIBMTP_destroy_file_t(newfilemeta);
   5422   } else {
   5423     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5424 			    "LIBMTP_Send_File_From_File_Descriptor(): "
   5425 			    "Could not retrieve updated metadata.");
   5426     return -1;
   5427   }
   5428 
   5429   return 0;
   5430 }
   5431 
   5432 /**
   5433  * This function sends a generic file from a handler function to an
   5434  * MTP device. A filename and a set of metadata must be
   5435  * given as input.
   5436  *
   5437  * This can potentially be used for sending in a stream of unknown
   5438  * length. Send music files with
   5439  * <code>LIBMTP_Send_Track_From_Handler()</code>
   5440  *
   5441  * @param device a pointer to the device to send the file to.
   5442  * @param get_func the function to call to get data to write
   5443  * @param priv a user-defined pointer that is passed along to
   5444  *        <code>get_func</code>. If not used, this is set to NULL.
   5445  * @param filedata a file metadata set to be written along with the file.
   5446  *        After this call the field <code>filedata-&gt;item_id</code>
   5447  *        will contain the new file ID. Other fields such
   5448  *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
   5449  *        or <code>filedata-&gt;storage_id</code> may also change during this
   5450  *        operation due to device restrictions, so do not rely on the
   5451  *        contents of this struct to be preserved in any way.
   5452  *        <ul>
   5453  *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
   5454  *        (e.g. folder) to store this file in. If this is 0,
   5455  *        the file will be stored in the root folder.
   5456  *        <li><code>filedata-&gt;storage_id</code> should be set to the
   5457  *        desired storage (e.g. memory card or whatever your device
   5458  *        presents) to store this file in. Setting this to 0 will store
   5459  *        the file on the primary storage.
   5460  *        </ul>
   5461  * @param callback a progress indicator function or NULL to ignore.
   5462  * @param data a user-defined pointer that is passed along to
   5463  *             the <code>progress</code> function in order to
   5464  *             pass along some user defined data to the progress
   5465  *             updates. If not used, set this to NULL.
   5466  * @return 0 if the transfer was successful, any other value means
   5467  *           failure.
   5468  * @see LIBMTP_Send_File_From_File()
   5469  * @see LIBMTP_Send_Track_From_File_Descriptor()
   5470  * @see LIBMTP_Delete_Object()
   5471  */
   5472 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
   5473 			 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
   5474        LIBMTP_progressfunc_t const callback, void const * const data)
   5475 {
   5476   uint16_t ret;
   5477   PTPParams *params = (PTPParams *) device->params;
   5478   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   5479   LIBMTP_file_t *newfilemeta;
   5480 
   5481   if (send_file_object_info(device, filedata))
   5482   {
   5483     // no need to output an error since send_file_object_info will already have done so
   5484     return -1;
   5485   }
   5486 
   5487   // Callbacks
   5488   ptp_usb->callback_active = 1;
   5489   // The callback will deactivate itself after this amount of data has been sent
   5490   // One BULK header for the request, one for the data phase. No parameters to the request.
   5491   ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
   5492   ptp_usb->current_transfer_complete = 0;
   5493   ptp_usb->current_transfer_callback = callback;
   5494   ptp_usb->current_transfer_callback_data = data;
   5495 
   5496   MTPDataHandler mtp_handler;
   5497   mtp_handler.getfunc = get_func;
   5498   mtp_handler.putfunc = NULL;
   5499   mtp_handler.priv = priv;
   5500 
   5501   PTPDataHandler handler;
   5502   handler.getfunc = get_func_wrapper;
   5503   handler.putfunc = NULL;
   5504   handler.priv = &mtp_handler;
   5505 
   5506   ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
   5507 
   5508   ptp_usb->callback_active = 0;
   5509   ptp_usb->current_transfer_callback = NULL;
   5510   ptp_usb->current_transfer_callback_data = NULL;
   5511 
   5512   if (ret == PTP_ERROR_CANCEL) {
   5513     add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
   5514     return -1;
   5515   }
   5516   if (ret != PTP_RC_OK) {
   5517     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
   5518 				"Could not send object.");
   5519     return -1;
   5520   }
   5521 
   5522   add_object_to_cache(device, filedata->item_id);
   5523 
   5524   /*
   5525    * Get the device-assined parent_id from the cache.
   5526    * The operation that adds it to the cache will
   5527    * look it up from the device, so we get the new
   5528    * parent_id from the cache.
   5529    */
   5530   newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
   5531   if (newfilemeta != NULL) {
   5532     filedata->parent_id = newfilemeta->parent_id;
   5533     filedata->storage_id = newfilemeta->storage_id;
   5534     LIBMTP_destroy_file_t(newfilemeta);
   5535   } else {
   5536     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
   5537 			    "LIBMTP_Send_File_From_Handler(): "
   5538 			    "Could not retrieve updated metadata.");
   5539     return -1;
   5540   }
   5541 
   5542   return 0;
   5543 }
   5544 
   5545 /**
   5546  * This function sends the file object info, ready for sendobject
   5547  * @param device a pointer to the device to send the file to.
   5548  * @param filedata a file metadata set to be written along with the file.
   5549  * @return 0 if the transfer was successful, any other value means
   5550  *           failure.
   5551  */
   5552 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
   5553 {
   5554   PTPParams *params = (PTPParams *) device->params;
   5555   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   5556   uint32_t store;
   5557 
   5558 #ifdef _AFT_BUILD
   5559   int use_primary_storage = 0;
   5560 #else
   5561   int use_primary_storage = 1;
   5562 #endif
   5563 
   5564   uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
   5565   LIBMTP_devicestorage_t *storage;
   5566   uint32_t localph = filedata->parent_id;
   5567   uint16_t ret;
   5568   int i;
   5569 
   5570   if (filedata->storage_id != 0) {
   5571     store = filedata->storage_id;
   5572   } else {
   5573     store = get_writeable_storageid(device, filedata->filesize);
   5574   }
   5575   // Detect if something non-primary is in use.
   5576   storage = device->storage;
   5577   if (storage != NULL && store != storage->id) {
   5578     use_primary_storage = 0;
   5579   }
   5580 
   5581   /*
   5582    * If no destination folder was given, look up a default
   5583    * folder if possible. Perhaps there is some way of retrieveing
   5584    * the default folder for different forms of content, what
   5585    * do I know, we use a fixed list in lack of any better method.
   5586    * Some devices obviously need to have their files in certain
   5587    * folders in order to find/display them at all (hello Creative),
   5588    * so we have to have a method for this. We only do this if the
   5589    * primary storage is in use.
   5590    */
   5591 
   5592   if (localph == 0 && use_primary_storage) {
   5593     if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
   5594       localph = device->default_music_folder;
   5595     } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
   5596       localph = device->default_video_folder;
   5597     } else if (of == PTP_OFC_EXIF_JPEG ||
   5598 	       of == PTP_OFC_JP2 ||
   5599 	       of == PTP_OFC_JPX ||
   5600 	       of == PTP_OFC_JFIF ||
   5601 	       of == PTP_OFC_TIFF ||
   5602 	       of == PTP_OFC_TIFF_IT ||
   5603 	       of == PTP_OFC_BMP ||
   5604 	       of == PTP_OFC_GIF ||
   5605 	       of == PTP_OFC_PICT ||
   5606 	       of == PTP_OFC_PNG ||
   5607 	       of == PTP_OFC_MTP_WindowsImageFormat) {
   5608       localph = device->default_picture_folder;
   5609     } else if (of == PTP_OFC_MTP_vCalendar1 ||
   5610 	       of == PTP_OFC_MTP_vCalendar2 ||
   5611 	       of == PTP_OFC_MTP_UndefinedContact ||
   5612 	       of == PTP_OFC_MTP_vCard2 ||
   5613 	       of == PTP_OFC_MTP_vCard3 ||
   5614 	       of == PTP_OFC_MTP_UndefinedCalendarItem) {
   5615       localph = device->default_organizer_folder;
   5616     } else if (of == PTP_OFC_Text) {
   5617       localph = device->default_text_folder;
   5618     }
   5619   }
   5620 
   5621   // default parent handle
   5622   if (localph == 0) {
   5623     localph = 0xFFFFFFFFU; // Set to -1
   5624   }
   5625 
   5626   // Here we wire the type to unknown on bugged, but
   5627   // Ogg or FLAC-supportive devices.
   5628   if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
   5629     of = PTP_OFC_Undefined;
   5630   }
   5631   if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
   5632     of = PTP_OFC_Undefined;
   5633   }
   5634 
   5635   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
   5636       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
   5637     /*
   5638      * MTP enhanched does it this way (from a sniff):
   5639      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
   5640      *    20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
   5641      *    FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
   5642      *    Length: 0x00000020
   5643      *    Type:   0x0001 PTP_USB_CONTAINER_COMMAND
   5644      *    Code:   0x9808
   5645      *    Transaction ID: 0x0000001B
   5646      *    Param1: 0x00010001 <- store
   5647      *    Param2: 0xffffffff <- parent handle (-1 ?)
   5648      *    Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
   5649      *    Param4: 0x00000000 <- file length MSB (-0x0c header len)
   5650      *    Param5: 0x00005e12 <- file length LSB (-0x0c header len)
   5651      *
   5652      * -> PTP_OC_MTP_SendObjectPropList (0x9808):
   5653      *    46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
   5654      *    00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
   5655      *    00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
   5656      *    00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
   5657      *    00 4F DC 02 00 01                               - dc4f = non consumable
   5658      *    Length: 0x00000046
   5659      *    Type:   0x0002 PTP_USB_CONTAINER_DATA
   5660      *    Code:   0x9808
   5661      *    Transaction ID: 0x0000001B
   5662      *    Metadata....
   5663      *    0x00000003 <- Number of metadata items
   5664      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
   5665      *    0xdc07     <- metadata type: file name
   5666      *    0xffff     <- metadata type: string
   5667      *    0x0d       <- number of (uint16_t) characters
   5668      *    4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
   5669      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
   5670      *    0xdc03     <- metadata type: protection status
   5671      *    0x0004     <- metadata type: uint16_t
   5672      *    0x0000     <- not protected
   5673      *    0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
   5674      *    0xdc4f     <- non consumable
   5675      *    0x0002     <- metadata type: uint8_t
   5676      *    0x01       <- non-consumable (this device cannot display PDF)
   5677      *
   5678      * <- Read 0x18 bytes back
   5679      *    18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
   5680      *    00 00 00 00 01 40 00 00
   5681      *    Length: 0x000000018
   5682      *    Type:   0x0003 PTP_USB_CONTAINER_RESPONSE
   5683      *    Code:   0x2001 PTP_OK
   5684      *    Transaction ID: 0x0000001B
   5685      *    Param1: 0x00010001 <- store
   5686      *    Param2: 0x00000000 <- parent handle
   5687      *    Param3: 0x00004001 <- new file/object ID
   5688      *
   5689      * -> PTP_OC_SendObject (0x100d)
   5690      *    0C 00 00 00 01 00 0D 10 1C 00 00 00
   5691      * -> ... all the bytes ...
   5692      * <- Read 0x0c bytes back
   5693      *    0C 00 00 00 03 00 01 20 1C 00 00 00
   5694      *    ... Then update metadata one-by one, actually (instead of sending it first!) ...
   5695      */
   5696     MTPProperties *props = NULL;
   5697     int nrofprops = 0;
   5698     MTPProperties *prop = NULL;
   5699     uint16_t *properties = NULL;
   5700     uint32_t propcnt = 0;
   5701 
   5702     // Must be 0x00000000U for new objects
   5703     filedata->item_id = 0x00000000U;
   5704 
   5705     ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
   5706 
   5707     for (i=0;i<propcnt;i++) {
   5708       PTPObjectPropDesc opd;
   5709 
   5710       ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
   5711       if (ret != PTP_RC_OK) {
   5712 	add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
   5713 				"could not get property description.");
   5714       } else if (opd.GetSet) {
   5715 	switch (properties[i]) {
   5716 	case PTP_OPC_ObjectFileName:
   5717 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   5718 	  prop->ObjectHandle = filedata->item_id;
   5719 	  prop->property = PTP_OPC_ObjectFileName;
   5720 	  prop->datatype = PTP_DTC_STR;
   5721 	  if (filedata->filename != NULL) {
   5722 	    prop->propval.str = strdup(filedata->filename);
   5723 	    if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   5724 	      strip_7bit_from_utf8(prop->propval.str);
   5725 	    }
   5726 	  }
   5727 	  break;
   5728 	case PTP_OPC_ProtectionStatus:
   5729 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   5730 	  prop->ObjectHandle = filedata->item_id;
   5731 	  prop->property = PTP_OPC_ProtectionStatus;
   5732 	  prop->datatype = PTP_DTC_UINT16;
   5733 	  prop->propval.u16 = 0x0000U; /* Not protected */
   5734 	  break;
   5735 	case PTP_OPC_NonConsumable:
   5736 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   5737 	  prop->ObjectHandle = filedata->item_id;
   5738 	  prop->property = PTP_OPC_NonConsumable;
   5739 	  prop->datatype = PTP_DTC_UINT8;
   5740 	  prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
   5741 	  break;
   5742 	case PTP_OPC_Name:
   5743 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   5744 	  prop->ObjectHandle = filedata->item_id;
   5745 	  prop->property = PTP_OPC_Name;
   5746 	  prop->datatype = PTP_DTC_STR;
   5747 	  if (filedata->filename != NULL)
   5748 	    prop->propval.str = strdup(filedata->filename);
   5749 	  break;
   5750 	case PTP_OPC_DateModified:
   5751 	  // Tag with current time if that is supported
   5752 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   5753 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   5754 	    prop->ObjectHandle = filedata->item_id;
   5755 	    prop->property = PTP_OPC_DateModified;
   5756 	    prop->datatype = PTP_DTC_STR;
   5757 	    prop->propval.str = get_iso8601_stamp();
   5758 	    filedata->modificationdate = time(NULL);
   5759 	  }
   5760 	  break;
   5761 	}
   5762       }
   5763       ptp_free_objectpropdesc(&opd);
   5764     }
   5765     free(properties);
   5766 
   5767     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
   5768 				     of, filedata->filesize, props, nrofprops);
   5769 
   5770     /* Free property list */
   5771     ptp_destroy_object_prop_list(props, nrofprops);
   5772 
   5773     if (ret != PTP_RC_OK) {
   5774       add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
   5775 				  "Could not send object property list.");
   5776       if (ret == PTP_RC_AccessDenied) {
   5777 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
   5778       }
   5779       return -1;
   5780     }
   5781   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
   5782     PTPObjectInfo new_file;
   5783 
   5784     memset(&new_file, 0, sizeof(PTPObjectInfo));
   5785 
   5786     new_file.Filename = filedata->filename;
   5787     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   5788       strip_7bit_from_utf8(new_file.Filename);
   5789     }
   5790     // We lose precision here.
   5791     new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
   5792     new_file.ObjectFormat = of;
   5793     new_file.StorageID = store;
   5794     new_file.ParentObject = localph;
   5795     new_file.ModificationDate = time(NULL);
   5796     // Create the object
   5797 
   5798     ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
   5799 
   5800     if (ret != PTP_RC_OK) {
   5801       add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
   5802 				  "Could not send object info.");
   5803       if (ret == PTP_RC_AccessDenied) {
   5804 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
   5805       }
   5806       return -1;
   5807     }
   5808     // NOTE: the char* pointers inside new_file are not copies so don't
   5809     // try to destroy this objectinfo!
   5810   }
   5811 
   5812   // Now there IS an object with this parent handle.
   5813   filedata->parent_id = localph;
   5814 
   5815   return 0;
   5816 }
   5817 
   5818 /**
   5819  * This function updates the MTP track object metadata on a
   5820  * single file identified by an object ID.
   5821  * @param device a pointer to the device to update the track
   5822  *        metadata on.
   5823  * @param metadata a track metadata set to be written to the file.
   5824  *        notice that the <code>track_id</code> field of the
   5825  *        metadata structure must be correct so that the
   5826  *        function can update the right file. If some properties
   5827  *        of this metadata are set to NULL (strings) or 0
   5828  *        (numerical values) they will be discarded and the
   5829  *        track will not be tagged with these blank values.
   5830  * @return 0 on success, any other value means failure. If some
   5831  *        or all of the properties fail to update we will still
   5832  *        return success. On some devices (notably iRiver T30)
   5833  *        properties that exist cannot be updated.
   5834  */
   5835 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
   5836 				 LIBMTP_track_t const * const metadata)
   5837 {
   5838   uint16_t ret;
   5839   PTPParams *params = (PTPParams *) device->params;
   5840   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   5841   uint32_t i;
   5842   uint16_t *properties = NULL;
   5843   uint32_t propcnt = 0;
   5844 
   5845   // First see which properties can be set on this file format and apply accordingly
   5846   // i.e only try to update this metadata for object tags that exist on the current player.
   5847   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
   5848   if (ret != PTP_RC_OK) {
   5849     // Just bail out for now, nothing is ever set.
   5850     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   5851 			    "could not retrieve supported object properties.");
   5852     return -1;
   5853   }
   5854   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
   5855       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
   5856     MTPProperties *props = NULL;
   5857     MTPProperties *prop = NULL;
   5858     int nrofprops = 0;
   5859 
   5860     for (i=0;i<propcnt;i++) {
   5861       PTPObjectPropDesc opd;
   5862 
   5863       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
   5864       if (ret != PTP_RC_OK) {
   5865 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   5866 				"could not get property description.");
   5867       } else if (opd.GetSet) {
   5868 	switch (properties[i]) {
   5869 	case PTP_OPC_Name:
   5870 	  if (metadata->title == NULL)
   5871 	    break;
   5872 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5873 	  prop->ObjectHandle = metadata->item_id;
   5874 	  prop->property = PTP_OPC_Name;
   5875 	  prop->datatype = PTP_DTC_STR;
   5876 	  prop->propval.str = strdup(metadata->title);
   5877 	  break;
   5878 	case PTP_OPC_AlbumName:
   5879 	  if (metadata->album == NULL)
   5880 	    break;
   5881 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5882 	  prop->ObjectHandle = metadata->item_id;
   5883 	  prop->property = PTP_OPC_AlbumName;
   5884 	  prop->datatype = PTP_DTC_STR;
   5885 	  prop->propval.str = strdup(metadata->album);
   5886 	  break;
   5887 	case PTP_OPC_Artist:
   5888 	  if (metadata->artist == NULL)
   5889 	    break;
   5890 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5891 	  prop->ObjectHandle = metadata->item_id;
   5892 	  prop->property = PTP_OPC_Artist;
   5893 	  prop->datatype = PTP_DTC_STR;
   5894 	  prop->propval.str = strdup(metadata->artist);
   5895 	  break;
   5896 	case PTP_OPC_Composer:
   5897 	  if (metadata->composer == NULL)
   5898 	    break;
   5899 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5900 	  prop->ObjectHandle = metadata->item_id;
   5901 	  prop->property = PTP_OPC_Composer;
   5902 	  prop->datatype = PTP_DTC_STR;
   5903 	  prop->propval.str = strdup(metadata->composer);
   5904 	  break;
   5905 	case PTP_OPC_Genre:
   5906 	  if (metadata->genre == NULL)
   5907 	    break;
   5908 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5909 	  prop->ObjectHandle = metadata->item_id;
   5910 	  prop->property = PTP_OPC_Genre;
   5911 	  prop->datatype = PTP_DTC_STR;
   5912 	  prop->propval.str = strdup(metadata->genre);
   5913 	  break;
   5914 	case PTP_OPC_Duration:
   5915 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5916 	  prop->ObjectHandle = metadata->item_id;
   5917 	  prop->property = PTP_OPC_Duration;
   5918 	  prop->datatype = PTP_DTC_UINT32;
   5919 	  prop->propval.u32 = adjust_u32(metadata->duration, &opd);
   5920 	  break;
   5921 	case PTP_OPC_Track:
   5922 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5923 	  prop->ObjectHandle = metadata->item_id;
   5924 	  prop->property = PTP_OPC_Track;
   5925 	  prop->datatype = PTP_DTC_UINT16;
   5926 	  prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
   5927 	  break;
   5928 	case PTP_OPC_OriginalReleaseDate:
   5929 	  if (metadata->date == NULL)
   5930 	    break;
   5931 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5932 	  prop->ObjectHandle = metadata->item_id;
   5933 	  prop->property = PTP_OPC_OriginalReleaseDate;
   5934 	  prop->datatype = PTP_DTC_STR;
   5935 	  prop->propval.str = strdup(metadata->date);
   5936 	  break;
   5937 	case PTP_OPC_SampleRate:
   5938 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5939 	  prop->ObjectHandle = metadata->item_id;
   5940 	  prop->property = PTP_OPC_SampleRate;
   5941 	  prop->datatype = PTP_DTC_UINT32;
   5942 	  prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
   5943 	  break;
   5944 	case PTP_OPC_NumberOfChannels:
   5945 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5946 	  prop->ObjectHandle = metadata->item_id;
   5947 	  prop->property = PTP_OPC_NumberOfChannels;
   5948 	  prop->datatype = PTP_DTC_UINT16;
   5949 	  prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
   5950 	  break;
   5951 	case PTP_OPC_AudioWAVECodec:
   5952 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5953 	  prop->ObjectHandle = metadata->item_id;
   5954 	  prop->property = PTP_OPC_AudioWAVECodec;
   5955 	  prop->datatype = PTP_DTC_UINT32;
   5956 	  prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
   5957 	  break;
   5958 	case PTP_OPC_AudioBitRate:
   5959 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5960 	  prop->ObjectHandle = metadata->item_id;
   5961 	  prop->property = PTP_OPC_AudioBitRate;
   5962 	  prop->datatype = PTP_DTC_UINT32;
   5963 	  prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
   5964 	  break;
   5965 	case PTP_OPC_BitRateType:
   5966 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5967 	  prop->ObjectHandle = metadata->item_id;
   5968 	  prop->property = PTP_OPC_BitRateType;
   5969 	  prop->datatype = PTP_DTC_UINT16;
   5970 	  prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
   5971 	  break;
   5972 	case PTP_OPC_Rating:
   5973 	  // TODO: shall this be set for rating 0?
   5974 	  if (metadata->rating == 0)
   5975 	    break;
   5976 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5977 	  prop->ObjectHandle = metadata->item_id;
   5978 	  prop->property = PTP_OPC_Rating;
   5979 	  prop->datatype = PTP_DTC_UINT16;
   5980 	  prop->propval.u16 = adjust_u16(metadata->rating, &opd);
   5981 	  break;
   5982 	case PTP_OPC_UseCount:
   5983 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5984 	  prop->ObjectHandle = metadata->item_id;
   5985 	  prop->property = PTP_OPC_UseCount;
   5986 	  prop->datatype = PTP_DTC_UINT32;
   5987 	  prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
   5988 	  break;
   5989 	case PTP_OPC_DateModified:
   5990 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   5991 	    // Tag with current time if that is supported
   5992 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   5993 	    prop->ObjectHandle = metadata->item_id;
   5994 	    prop->property = PTP_OPC_DateModified;
   5995 	    prop->datatype = PTP_DTC_STR;
   5996 	    prop->propval.str = get_iso8601_stamp();
   5997 	  }
   5998 	  break;
   5999 	default:
   6000 	  break;
   6001 	}
   6002       }
   6003       ptp_free_objectpropdesc(&opd);
   6004     }
   6005 
   6006     // NOTE: File size is not updated, this should not change anyway.
   6007     // neither will we change the filename.
   6008 
   6009     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
   6010 
   6011     ptp_destroy_object_prop_list(props, nrofprops);
   6012 
   6013     if (ret != PTP_RC_OK) {
   6014       // TODO: return error of which property we couldn't set
   6015       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6016 			      "could not set object property list.");
   6017       free(properties);
   6018       return -1;
   6019     }
   6020 
   6021   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
   6022     for (i=0;i<propcnt;i++) {
   6023       PTPObjectPropDesc opd;
   6024 
   6025       ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
   6026       if (ret != PTP_RC_OK) {
   6027 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6028 				"could not get property description.");
   6029       } else if (opd.GetSet) {
   6030 	switch (properties[i]) {
   6031 	case PTP_OPC_Name:
   6032 	  // Update title
   6033 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
   6034 	  if (ret != 0) {
   6035 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6036 				    "could not set track title.");
   6037 	  }
   6038 	  break;
   6039 	case PTP_OPC_AlbumName:
   6040 	  // Update album
   6041 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
   6042 	  if (ret != 0) {
   6043 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6044 				    "could not set track album name.");
   6045 	  }
   6046 	  break;
   6047 	case PTP_OPC_Artist:
   6048 	  // Update artist
   6049 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
   6050 	  if (ret != 0) {
   6051 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6052 				    "could not set track artist name.");
   6053 	  }
   6054 	  break;
   6055 	case PTP_OPC_Composer:
   6056 	  // Update composer
   6057 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
   6058 	  if (ret != 0) {
   6059 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6060 				    "could not set track composer name.");
   6061 	  }
   6062 	  break;
   6063 	case PTP_OPC_Genre:
   6064 	  // Update genre
   6065 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
   6066 	  if (ret != 0) {
   6067 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6068 				    "could not set track genre name.");
   6069 	  }
   6070 	  break;
   6071 	case PTP_OPC_Duration:
   6072 	  // Update duration
   6073 	  if (metadata->duration != 0) {
   6074 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
   6075 	    if (ret != 0) {
   6076 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6077 				      "could not set track duration.");
   6078 	    }
   6079 	  }
   6080 	  break;
   6081 	case PTP_OPC_Track:
   6082 	  // Update track number.
   6083 	  if (metadata->tracknumber != 0) {
   6084 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
   6085 	    if (ret != 0) {
   6086 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6087 				      "could not set track tracknumber.");
   6088 	    }
   6089 	  }
   6090 	  break;
   6091 	case PTP_OPC_OriginalReleaseDate:
   6092 	  // Update creation datetime
   6093 	  ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
   6094 	  if (ret != 0) {
   6095 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6096 				    "could not set track release date.");
   6097 	  }
   6098 	  break;
   6099 	  // These are, well not so important.
   6100 	case PTP_OPC_SampleRate:
   6101 	  // Update sample rate
   6102 	  if (metadata->samplerate != 0) {
   6103 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
   6104 	    if (ret != 0) {
   6105 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6106 				      "could not set samplerate.");
   6107 	    }
   6108 	  }
   6109 	  break;
   6110 	case PTP_OPC_NumberOfChannels:
   6111 	  // Update number of channels
   6112 	  if (metadata->nochannels != 0) {
   6113 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
   6114 	  if (ret != 0) {
   6115 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6116 				    "could not set number of channels.");
   6117 	  }
   6118 	}
   6119 	  break;
   6120 	case PTP_OPC_AudioWAVECodec:
   6121 	  // Update WAVE codec
   6122 	  if (metadata->wavecodec != 0) {
   6123 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
   6124 	    if (ret != 0) {
   6125 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6126 				      "could not set WAVE codec.");
   6127 	    }
   6128 	  }
   6129 	  break;
   6130 	case PTP_OPC_AudioBitRate:
   6131 	  // Update bitrate
   6132 	  if (metadata->bitrate != 0) {
   6133 	    ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
   6134 	    if (ret != 0) {
   6135 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6136 				      "could not set bitrate.");
   6137 	  }
   6138 	  }
   6139 	  break;
   6140 	case PTP_OPC_BitRateType:
   6141 	  // Update bitrate type
   6142 	  if (metadata->bitratetype != 0) {
   6143 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
   6144 	    if (ret != 0) {
   6145 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6146 				      "could not set bitratetype.");
   6147 	    }
   6148 	  }
   6149 	  break;
   6150 	case PTP_OPC_Rating:
   6151 	  // Update user rating
   6152 	  // TODO: shall this be set for rating 0?
   6153 	  if (metadata->rating != 0) {
   6154 	    ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
   6155 	    if (ret != 0) {
   6156 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6157 				      "could not set user rating.");
   6158 	    }
   6159 	  }
   6160 	  break;
   6161 	case PTP_OPC_UseCount:
   6162 	  // Update use count, set even to zero if desired.
   6163 	  ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
   6164 	  if (ret != 0) {
   6165 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6166 				  "could not set use count.");
   6167 	  }
   6168 	  break;
   6169 	case PTP_OPC_DateModified:
   6170 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   6171 	    // Update modification time if supported
   6172 	    char *tmpstamp = get_iso8601_stamp();
   6173 	    ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
   6174 	    if (ret != 0) {
   6175 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6176 				      "could not set modification date.");
   6177 	    }
   6178 	    free(tmpstamp);
   6179 	  }
   6180 	  break;
   6181 
   6182 	  // NOTE: File size is not updated, this should not change anyway.
   6183 	  // neither will we change the filename.
   6184 	default:
   6185 	  break;
   6186 	}
   6187       }
   6188       ptp_free_objectpropdesc(&opd);
   6189     }
   6190   } else {
   6191     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
   6192                             "Your device doesn't seem to support any known way of setting metadata.");
   6193     free(properties);
   6194     return -1;
   6195   }
   6196 
   6197   // update cached object properties if metadata cache exists
   6198   update_metadata_cache(device, metadata->item_id);
   6199 
   6200   free(properties);
   6201 
   6202   return 0;
   6203 }
   6204 
   6205 /**
   6206  * This function deletes a single file, track, playlist, folder or
   6207  * any other object off the MTP device, identified by the object ID.
   6208  *
   6209  * If you delete a folder, there is no guarantee that the device will
   6210  * really delete all the files that were in that folder, rather it is
   6211  * expected that they will not be deleted, and will turn up in object
   6212  * listings with parent set to a non-existant object ID. The safe way
   6213  * to do this is to recursively delete all files (and folders) contained
   6214  * in the folder, then the folder itself.
   6215  *
   6216  * @param device a pointer to the device to delete the object from.
   6217  * @param object_id the object to delete.
   6218  * @return 0 on success, any other value means failure.
   6219  */
   6220 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
   6221 			 uint32_t object_id)
   6222 {
   6223   uint16_t ret;
   6224   PTPParams *params = (PTPParams *) device->params;
   6225 
   6226   ret = ptp_deleteobject(params, object_id, 0);
   6227   if (ret != PTP_RC_OK) {
   6228     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
   6229     return -1;
   6230   }
   6231 
   6232   return 0;
   6233 }
   6234 
   6235 /**
   6236  * Internal function to update an object filename property.
   6237  */
   6238 static int set_object_filename(LIBMTP_mtpdevice_t *device,
   6239 			       uint32_t object_id, uint16_t ptp_type,
   6240 			       const char **newname_ptr)
   6241 {
   6242   PTPParams             *params = (PTPParams *) device->params;
   6243   PTP_USB               *ptp_usb = (PTP_USB*) device->usbinfo;
   6244   PTPObjectPropDesc     opd;
   6245   uint16_t              ret;
   6246   char                  *newname;
   6247 
   6248   // See if we can modify the filename on this kind of files.
   6249   ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
   6250   if (ret != PTP_RC_OK) {
   6251     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
   6252 			    "could not get property description.");
   6253     return -1;
   6254   }
   6255 
   6256   if (!opd.GetSet) {
   6257     ptp_free_objectpropdesc(&opd);
   6258     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
   6259             " property is not settable.");
   6260     // TODO: we COULD actually upload/download the object here, if we feel
   6261     //       like wasting time for the user.
   6262     return -1;
   6263   }
   6264 
   6265   newname = strdup(*newname_ptr);
   6266 
   6267   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   6268     strip_7bit_from_utf8(newname);
   6269   }
   6270 
   6271   if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
   6272       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
   6273     MTPProperties *props = NULL;
   6274     MTPProperties *prop = NULL;
   6275     int nrofprops = 0;
   6276 
   6277     prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   6278     prop->ObjectHandle = object_id;
   6279     prop->property = PTP_OPC_ObjectFileName;
   6280     prop->datatype = PTP_DTC_STR;
   6281     prop->propval.str = newname;
   6282 
   6283     ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
   6284 
   6285     ptp_destroy_object_prop_list(props, nrofprops);
   6286 
   6287     if (ret != PTP_RC_OK) {
   6288         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
   6289               " could not set object property list.");
   6290         ptp_free_objectpropdesc(&opd);
   6291         return -1;
   6292     }
   6293   } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
   6294     ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
   6295     if (ret != 0) {
   6296       add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
   6297               " could not set object filename.");
   6298       ptp_free_objectpropdesc(&opd);
   6299       return -1;
   6300     }
   6301   } else {
   6302     free(newname);
   6303     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
   6304               " your device doesn't seem to support any known way of setting metadata.");
   6305     ptp_free_objectpropdesc(&opd);
   6306     return -1;
   6307   }
   6308 
   6309   ptp_free_objectpropdesc(&opd);
   6310 
   6311   // update cached object properties if metadata cache exists
   6312   update_metadata_cache(device, object_id);
   6313 
   6314   return 0;
   6315 }
   6316 
   6317 /**
   6318  * This function renames a single file.
   6319  * This simply means that the PTP_OPC_ObjectFileName property
   6320  * is updated, if this is supported by the device.
   6321  *
   6322  * @param device a pointer to the device that contains the file.
   6323  * @param file the file metadata of the file to rename.
   6324  *        On success, the filename member is updated. Be aware, that
   6325  *        this name can be different than newname depending of device restrictions.
   6326  * @param newname the new filename for this object.
   6327  * @return 0 on success, any other value means failure.
   6328  */
   6329 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
   6330                    LIBMTP_file_t *file, const char *newname)
   6331 {
   6332   int         ret;
   6333 
   6334   ret = set_object_filename(device, file->item_id,
   6335 			    map_libmtp_type_to_ptp_type(file->filetype),
   6336 			    &newname);
   6337 
   6338   if (ret != 0) {
   6339     return ret;
   6340   }
   6341 
   6342   free(file->filename);
   6343   file->filename = strdup(newname);
   6344   return ret;
   6345 }
   6346 
   6347 /**
   6348  * This function renames a single folder.
   6349  * This simply means that the PTP_OPC_ObjectFileName property
   6350  * is updated, if this is supported by the device.
   6351  *
   6352  * @param device a pointer to the device that contains the file.
   6353  * @param folder the folder metadata of the folder to rename.
   6354  *        On success, the name member is updated. Be aware, that
   6355  *        this name can be different than newname depending of device restrictions.
   6356  * @param newname the new name for this object.
   6357  * @return 0 on success, any other value means failure.
   6358  */
   6359 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
   6360                    LIBMTP_folder_t *folder, const char* newname)
   6361 {
   6362   int ret;
   6363 
   6364   ret = set_object_filename(device, folder->folder_id,
   6365 			    PTP_OFC_Association,
   6366 			    &newname);
   6367 
   6368   if (ret != 0) {
   6369     return ret;
   6370     }
   6371 
   6372   free(folder->name);
   6373   folder->name = strdup(newname);
   6374   return ret;
   6375 }
   6376 
   6377 /**
   6378  * This function renames a single track.
   6379  * This simply means that the PTP_OPC_ObjectFileName property
   6380  * is updated, if this is supported by the device.
   6381  *
   6382  * @param device a pointer to the device that contains the file.
   6383  * @param track the track metadata of the track to rename.
   6384  *        On success, the filename member is updated. Be aware, that
   6385  *        this name can be different than newname depending of device restrictions.
   6386  * @param newname the new filename for this object.
   6387  * @return 0 on success, any other value means failure.
   6388  */
   6389 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
   6390                    LIBMTP_track_t *track, const char* newname)
   6391 {
   6392   int         ret;
   6393 
   6394   ret = set_object_filename(device, track->item_id,
   6395 			    map_libmtp_type_to_ptp_type(track->filetype),
   6396 			    &newname);
   6397 
   6398   if (ret != 0) {
   6399     return ret;
   6400   }
   6401 
   6402   free(track->filename);
   6403   track->filename = strdup(newname);
   6404   return ret;
   6405 }
   6406 
   6407 /**
   6408  * This function renames a single playlist object file holder.
   6409  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
   6410  * property is updated, if this is supported by the device.
   6411  * The playlist filename should nominally end with an extension
   6412  * like ".pla".
   6413  *
   6414  * NOTE: if you want to change the metadata the device display
   6415  * about a playlist you must <i>not</i> use this function,
   6416  * use <code>LIBMTP_Update_Playlist()</code> instead!
   6417  *
   6418  * @param device a pointer to the device that contains the file.
   6419  * @param playlist the playlist metadata of the playlist to rename.
   6420  *        On success, the name member is updated. Be aware, that
   6421  *        this name can be different than newname depending of device restrictions.
   6422  * @param newname the new name for this object.
   6423  * @return 0 on success, any other value means failure.
   6424  * @see LIBMTP_Update_Playlist()
   6425  */
   6426 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
   6427                    LIBMTP_playlist_t *playlist, const char* newname)
   6428 {
   6429   int ret;
   6430 
   6431   ret = set_object_filename(device, playlist->playlist_id,
   6432 			    PTP_OFC_MTP_AbstractAudioVideoPlaylist,
   6433 			    &newname);
   6434 
   6435   if (ret != 0) {
   6436     return ret;
   6437   }
   6438 
   6439   free(playlist->name);
   6440   playlist->name = strdup(newname);
   6441   return ret;
   6442 }
   6443 
   6444 /**
   6445  * This function renames a single album.
   6446  * This simply means that the <code>PTP_OPC_ObjectFileName</code>
   6447  * property is updated, if this is supported by the device.
   6448  * The album filename should nominally end with an extension
   6449  * like ".alb".
   6450  *
   6451  * NOTE: if you want to change the metadata the device display
   6452  * about a playlist you must <i>not</i> use this function,
   6453  * use <code>LIBMTP_Update_Album()</code> instead!
   6454  *
   6455  * @param device a pointer to the device that contains the file.
   6456  * @param album the album metadata of the album to rename.
   6457  *        On success, the name member is updated. Be aware, that
   6458  *        this name can be different than newname depending of device restrictions.
   6459  * @param newname the new name for this object.
   6460  * @return 0 on success, any other value means failure.
   6461  * @see LIBMTP_Update_Album()
   6462  */
   6463 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
   6464                    LIBMTP_album_t *album, const char* newname)
   6465 {
   6466   int ret;
   6467 
   6468   ret = set_object_filename(device, album->album_id,
   6469 			    PTP_OFC_MTP_AbstractAudioAlbum,
   6470 			    &newname);
   6471 
   6472   if (ret != 0) {
   6473     return ret;
   6474   }
   6475 
   6476   free(album->name);
   6477   album->name = strdup(newname);
   6478   return ret;
   6479 }
   6480 
   6481 /**
   6482  * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
   6483  * NOT TO USE IT.
   6484  *
   6485  * @see LIBMTP_Set_File_Name()
   6486  * @see LIBMTP_Set_Track_Name()
   6487  * @see LIBMTP_Set_Folder_Name()
   6488  * @see LIBMTP_Set_Playlist_Name()
   6489  * @see LIBMTP_Set_Album_Name()
   6490  */
   6491 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
   6492                    uint32_t object_id, char* newname)
   6493 {
   6494   int             ret;
   6495   LIBMTP_file_t   *file;
   6496 
   6497   file = LIBMTP_Get_Filemetadata(device, object_id);
   6498 
   6499   if (file == NULL) {
   6500     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
   6501 			    "could not get file metadata for target object.");
   6502     return -1;
   6503   }
   6504 
   6505   ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
   6506 
   6507   free(file);
   6508 
   6509   return ret;
   6510 }
   6511 
   6512 /**
   6513  * Helper function. This indicates if a track exists on the device
   6514  * @param device a pointer to the device to get the track from.
   6515  * @param id the track ID of the track to retrieve.
   6516  * @return TRUE (!=0) if the track exists, FALSE (0) if not
   6517  */
   6518 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
   6519            uint32_t const id)
   6520 {
   6521   PTPParams *params = (PTPParams *) device->params;
   6522   uint16_t ret;
   6523   PTPObject *ob;
   6524 
   6525   ret = ptp_object_want (params, id, 0, &ob);
   6526   if (ret == PTP_RC_OK)
   6527       return -1;
   6528   return 0;
   6529 }
   6530 
   6531 /**
   6532  * This creates a new folder structure and allocates memory
   6533  * for it. Notice that if you add strings to this structure they
   6534  * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
   6535  * operation later, so be careful of using strdup() when assigning
   6536  * strings, e.g.:
   6537  *
   6538  * @return a pointer to the newly allocated folder structure.
   6539  * @see LIBMTP_destroy_folder_t()
   6540  */
   6541 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
   6542 {
   6543   LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
   6544   if (new == NULL) {
   6545     return NULL;
   6546   }
   6547   new->folder_id = 0;
   6548   new->parent_id = 0;
   6549   new->storage_id = 0;
   6550   new->name = NULL;
   6551   new->sibling = NULL;
   6552   new->child = NULL;
   6553   return new;
   6554 }
   6555 
   6556 /**
   6557  * This recursively deletes the memory for a folder structure.
   6558  * This shall typically be called on a top-level folder list to
   6559  * detsroy the entire folder tree.
   6560  *
   6561  * @param folder folder structure to destroy
   6562  * @see LIBMTP_new_folder_t()
   6563  */
   6564 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
   6565 {
   6566 
   6567   if(folder == NULL) {
   6568      return;
   6569   }
   6570 
   6571   //Destroy from the bottom up
   6572   if(folder->child != NULL) {
   6573      LIBMTP_destroy_folder_t(folder->child);
   6574   }
   6575 
   6576   if(folder->sibling != NULL) {
   6577     LIBMTP_destroy_folder_t(folder->sibling);
   6578   }
   6579 
   6580   if(folder->name != NULL) {
   6581     free(folder->name);
   6582   }
   6583 
   6584   free(folder);
   6585 }
   6586 
   6587 /**
   6588  * Helper function. Returns a folder structure for a
   6589  * specified id.
   6590  *
   6591  * @param folderlist list of folders to search
   6592  * @id id of folder to look for
   6593  * @return a folder or NULL if not found
   6594  */
   6595 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
   6596 {
   6597   LIBMTP_folder_t *ret = NULL;
   6598 
   6599   if(folderlist == NULL) {
   6600     return NULL;
   6601   }
   6602 
   6603   if(folderlist->folder_id == id) {
   6604     return folderlist;
   6605   }
   6606 
   6607   if(folderlist->sibling) {
   6608     ret = LIBMTP_Find_Folder(folderlist->sibling, id);
   6609   }
   6610 
   6611   if(folderlist->child && ret == NULL) {
   6612     ret = LIBMTP_Find_Folder(folderlist->child, id);
   6613   }
   6614 
   6615   return ret;
   6616 }
   6617 
   6618 /**
   6619  * Function used to recursively get subfolders from params.
   6620  */
   6621 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
   6622 {
   6623   LIBMTP_folder_t *retfolders = NULL, *children, *iter, *curr;
   6624 
   6625   iter = list->sibling;
   6626   while(iter != list) {
   6627     if (iter->parent_id != parent) {
   6628       iter = iter->sibling;
   6629       continue;
   6630     }
   6631 
   6632     /* We know that iter is a child of 'parent', therefore we can safely
   6633      * hold on to 'iter' locally since no one else will steal it
   6634      * from the 'list' as we recurse. */
   6635     children = get_subfolders_for_folder(list, iter->folder_id);
   6636 
   6637     curr = iter;
   6638     iter = iter->sibling;
   6639 
   6640     // Remove curr from the list.
   6641     curr->child->sibling = curr->sibling;
   6642     curr->sibling->child = curr->child;
   6643 
   6644     // Attach the children to curr.
   6645     curr->child = children;
   6646 
   6647     // Put this folder into the list of siblings.
   6648     curr->sibling = retfolders;
   6649     retfolders = curr;
   6650   }
   6651 
   6652   return retfolders;
   6653 }
   6654 
   6655 /**
   6656  * This returns a list of all folders available
   6657  * on the current MTP device.
   6658  *
   6659  * @param device a pointer to the device to get the folder listing for.
   6660  * @return a list of folders
   6661  */
   6662 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
   6663 {
   6664   PTPParams *params = (PTPParams *) device->params;
   6665   LIBMTP_folder_t head, *rv;
   6666   int i;
   6667 
   6668   // Get all the handles if we haven't already done that
   6669   if (params->nrofobjects == 0) {
   6670     flush_handles(device);
   6671   }
   6672 
   6673   /*
   6674    * This creates a temporary list of the folders, this is in a
   6675    * reverse order and uses the Folder pointers that are already
   6676    * in the Folder structure. From this we can then build up the
   6677    * folder hierarchy with only looking at this temporary list,
   6678    * and removing the folders from this temporary list as we go.
   6679    * This significantly reduces the number of operations that we
   6680    * have to do in building the folder hierarchy. Also since the
   6681    * temp list is in reverse order, when we prepend to the sibling
   6682    * list things are in the same order as they were originally
   6683    * in the handle list.
   6684    */
   6685   head.sibling = &head;
   6686   head.child = &head;
   6687   for (i = 0; i < params->nrofobjects; i++) {
   6688     LIBMTP_folder_t *folder;
   6689     PTPObject *ob;
   6690 
   6691     ob = &params->objects[i];
   6692     if (ob->oi.ObjectFormat != PTP_OFC_Association) {
   6693       continue;
   6694     }
   6695     /*
   6696      * Do we know how to handle these? They are part
   6697      * of the MTP 1.0 specification paragraph 3.6.4.
   6698      * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
   6699      * should be called on these to get the contained objects, but
   6700      * we basically don't care. Hopefully parent_id is maintained for all
   6701      * children, because we rely on that instead.
   6702      */
   6703     if (ob->oi.AssociationDesc != 0x00000000U) {
   6704       printf("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
   6705     }
   6706 
   6707     // Create a folder struct...
   6708     folder = LIBMTP_new_folder_t();
   6709     if (folder == NULL) {
   6710       // malloc failure or so.
   6711       return NULL;
   6712     }
   6713     folder->folder_id = ob->oid;
   6714     folder->parent_id = ob->oi.ParentObject;
   6715     folder->storage_id = ob->oi.StorageID;
   6716     folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
   6717 
   6718     // pretend sibling says next, and child says prev.
   6719     folder->sibling = head.sibling;
   6720     folder->child = &head;
   6721     head.sibling->child = folder;
   6722     head.sibling = folder;
   6723   }
   6724 
   6725   // We begin at the root folder and get them all recursively
   6726   rv = get_subfolders_for_folder(&head, 0x00000000);
   6727 
   6728   // The temp list should be empty. Clean up any orphans just in case.
   6729   while(head.sibling != &head) {
   6730     LIBMTP_folder_t *curr = head.sibling;
   6731 
   6732     printf("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
   6733 	   curr->folder_id,
   6734 	   curr->name);
   6735     curr->sibling->child = curr->child;
   6736     curr->child->sibling = curr->sibling;
   6737     curr->child = NULL;
   6738     curr->sibling = NULL;
   6739     LIBMTP_destroy_folder_t(curr);
   6740   }
   6741 
   6742   return rv;
   6743 }
   6744 
   6745 /**
   6746  * This create a folder on the current MTP device. The PTP name
   6747  * for a folder is "association". The PTP/MTP devices does not
   6748  * have an internal "folder" concept really, it contains a flat
   6749  * list of all files and some file are "associations" that other
   6750  * files and folders may refer to as its "parent".
   6751  *
   6752  * @param device a pointer to the device to create the folder on.
   6753  * @param name the name of the new folder. Note this can be modified
   6754  *        if the device does not support all the characters in the
   6755  *        name.
   6756  * @param parent_id id of parent folder to add the new folder to,
   6757  *        or 0 to put it in the root directory.
   6758  * @param storage_id id of the storage to add this new folder to.
   6759  *        notice that you cannot mismatch storage id and parent id:
   6760  *        they must both be on the same storage! Pass in 0 if you
   6761  *        want to create this folder on the default storage.
   6762  * @return id to new folder or 0 if an error occured
   6763  */
   6764 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
   6765 			      uint32_t parent_id, uint32_t storage_id)
   6766 {
   6767   PTPParams *params = (PTPParams *) device->params;
   6768   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   6769   uint32_t parenthandle = 0;
   6770   uint32_t store;
   6771   PTPObjectInfo new_folder;
   6772   uint16_t ret;
   6773   uint32_t new_id = 0;
   6774 
   6775   if (storage_id == 0) {
   6776     // I'm just guessing that a folder may require 512 bytes
   6777     store = get_writeable_storageid(device, 512);
   6778   } else {
   6779     store = storage_id;
   6780   }
   6781 
   6782   if (parent_id == 0) {
   6783     parent_id = 0xFFFFFFFFU; // Set to -1
   6784   }
   6785 
   6786   parenthandle = parent_id;
   6787 
   6788   memset(&new_folder, 0, sizeof(new_folder));
   6789   new_folder.Filename = name;
   6790   if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   6791     strip_7bit_from_utf8(new_folder.Filename);
   6792   }
   6793   new_folder.ObjectCompressedSize = 1;
   6794   new_folder.ObjectFormat = PTP_OFC_Association;
   6795   new_folder.ProtectionStatus = PTP_PS_NoProtection;
   6796   new_folder.AssociationType = PTP_AT_GenericFolder;
   6797   new_folder.ParentObject = parent_id;
   6798   new_folder.StorageID = store;
   6799 
   6800   // Create the object
   6801   // FIXME: use send list here if available.
   6802   ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
   6803   if (ret != PTP_RC_OK) {
   6804     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
   6805     if (ret == PTP_RC_AccessDenied) {
   6806       add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
   6807     }
   6808     return 0;
   6809   }
   6810   // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
   6811   // several strings.
   6812 
   6813   add_object_to_cache(device, new_id);
   6814 
   6815   return new_id;
   6816 }
   6817 
   6818 /**
   6819  * This creates a new playlist metadata structure and allocates memory
   6820  * for it. Notice that if you add strings to this structure they
   6821  * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
   6822  * operation later, so be careful of using strdup() when assigning
   6823  * strings, e.g.:
   6824  *
   6825  * <pre>
   6826  * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
   6827  * pl->name = strdup(str);
   6828  * ....
   6829  * LIBMTP_destroy_playlist_t(pl);
   6830  * </pre>
   6831  *
   6832  * @return a pointer to the newly allocated metadata structure.
   6833  * @see LIBMTP_destroy_playlist_t()
   6834  */
   6835 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
   6836 {
   6837   LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
   6838   if (new == NULL) {
   6839     return NULL;
   6840   }
   6841   new->playlist_id = 0;
   6842   new->parent_id = 0;
   6843   new->storage_id = 0;
   6844   new->name = NULL;
   6845   new->tracks = NULL;
   6846   new->no_tracks = 0;
   6847   new->next = NULL;
   6848   return new;
   6849 }
   6850 
   6851 /**
   6852  * This destroys a playlist metadata structure and deallocates the memory
   6853  * used by it, including any strings. Never use a track metadata
   6854  * structure again after calling this function on it.
   6855  * @param playlist the playlist metadata to destroy.
   6856  * @see LIBMTP_new_playlist_t()
   6857  */
   6858 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
   6859 {
   6860   if (playlist == NULL) {
   6861     return;
   6862   }
   6863   if (playlist->name != NULL)
   6864     free(playlist->name);
   6865   if (playlist->tracks != NULL)
   6866     free(playlist->tracks);
   6867   free(playlist);
   6868   return;
   6869 }
   6870 
   6871 /**
   6872  * This function returns a list of the playlists available on the
   6873  * device. Typical usage:
   6874  *
   6875  * <pre>
   6876  * </pre>
   6877  *
   6878  * @param device a pointer to the device to get the playlist listing from.
   6879  * @return a playlist list on success, else NULL. If there are no playlists
   6880  *         on the device, NULL will be returned as well.
   6881  * @see LIBMTP_Get_Playlist()
   6882  */
   6883 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
   6884 {
   6885   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   6886   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
   6887   PTPParams *params = (PTPParams *) device->params;
   6888   LIBMTP_playlist_t *retlists = NULL;
   6889   LIBMTP_playlist_t *curlist = NULL;
   6890   uint32_t i;
   6891 
   6892   // Get all the handles if we haven't already done that
   6893   if (params->nrofobjects == 0) {
   6894     flush_handles(device);
   6895   }
   6896 
   6897   for (i = 0; i < params->nrofobjects; i++) {
   6898     LIBMTP_playlist_t *pl;
   6899     PTPObject *ob;
   6900     uint16_t ret;
   6901 
   6902     ob = &params->objects[i];
   6903 
   6904     // Ignore stuff that isn't playlists
   6905 
   6906     // For Samsung players we must look for the .spl extension explicitly since
   6907     // playlists are not stored as playlist objects.
   6908     if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
   6909       // Allocate a new playlist type
   6910       pl = LIBMTP_new_playlist_t();
   6911       spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
   6912     }
   6913     else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
   6914       continue;
   6915     }
   6916     else {
   6917       // Allocate a new playlist type
   6918       pl = LIBMTP_new_playlist_t();
   6919 
   6920       // Try to look up proper name, else use the oi->Filename field.
   6921       pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
   6922       if (pl->name == NULL) {
   6923 	pl->name = strdup(ob->oi.Filename);
   6924       }
   6925       pl->playlist_id = ob->oid;
   6926       pl->parent_id = ob->oi.ParentObject;
   6927       pl->storage_id = ob->oi.StorageID;
   6928 
   6929       // Then get the track listing for this playlist
   6930       ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
   6931       if (ret != PTP_RC_OK) {
   6932         add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
   6933 				    "could not get object references.");
   6934         pl->tracks = NULL;
   6935         pl->no_tracks = 0;
   6936       }
   6937     }
   6938 
   6939     // Add playlist to a list that will be returned afterwards.
   6940     if (retlists == NULL) {
   6941       retlists = pl;
   6942       curlist = pl;
   6943     } else {
   6944       curlist->next = pl;
   6945       curlist = pl;
   6946     }
   6947 
   6948     // Call callback here if we decide to add that possibility...
   6949   }
   6950   return retlists;
   6951 }
   6952 
   6953 
   6954 /**
   6955  * This function retrieves an individual playlist from the device.
   6956  * @param device a pointer to the device to get the playlist from.
   6957  * @param plid the unique ID of the playlist to retrieve.
   6958  * @return a valid playlist metadata post or NULL on failure.
   6959  * @see LIBMTP_Get_Playlist_List()
   6960  */
   6961 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
   6962 {
   6963   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   6964   const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
   6965   PTPParams *params = (PTPParams *) device->params;
   6966   PTPObject *ob;
   6967   LIBMTP_playlist_t *pl;
   6968   uint16_t ret;
   6969 
   6970   // Get all the handles if we haven't already done that
   6971   if (params->nrofobjects == 0) {
   6972     flush_handles(device);
   6973   }
   6974 
   6975   ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   6976   if (ret != PTP_RC_OK)
   6977     return NULL;
   6978 
   6979   // For Samsung players we must look for the .spl extension explicitly since
   6980   // playlists are not stored as playlist objects.
   6981   if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
   6982     // Allocate a new playlist type
   6983     pl = LIBMTP_new_playlist_t();
   6984     spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
   6985     return pl;
   6986   }
   6987 
   6988   // Ignore stuff that isn't playlists
   6989   else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
   6990     return NULL;
   6991   }
   6992 
   6993   // Allocate a new playlist type
   6994   pl = LIBMTP_new_playlist_t();
   6995 
   6996   pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
   6997   if (pl->name == NULL) {
   6998     pl->name = strdup(ob->oi.Filename);
   6999   }
   7000   pl->playlist_id = ob->oid;
   7001   pl->parent_id = ob->oi.ParentObject;
   7002   pl->storage_id = ob->oi.StorageID;
   7003 
   7004   // Then get the track listing for this playlist
   7005   ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
   7006   if (ret != PTP_RC_OK) {
   7007     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
   7008     pl->tracks = NULL;
   7009     pl->no_tracks = 0;
   7010   }
   7011 
   7012   return pl;
   7013 }
   7014 
   7015 /**
   7016  * This function creates a new abstract list such as a playlist
   7017  * or an album.
   7018  *
   7019  * @param device a pointer to the device to create the new abstract list
   7020  *        on.
   7021  * @param name the name of the new abstract list.
   7022  * @param artist the artist of the new abstract list or NULL.
   7023  * @param genre the genre of the new abstract list or NULL.
   7024  * @param parenthandle the handle of the parent or 0 for no parent
   7025  *        i.e. the root folder.
   7026  * @param objectformat the abstract list type to create.
   7027  * @param suffix the ".foo" (4 characters) suffix to use for the virtual
   7028  *        "file" created by this operation.
   7029  * @param newid a pointer to a variable that will hold the new object
   7030  *        ID if this call is successful.
   7031  * @param tracks an array of tracks to associate with this list.
   7032  * @param no_tracks the number of tracks in the list.
   7033  * @return 0 on success, any other value means failure.
   7034  */
   7035 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
   7036 				    char const * const name,
   7037 				    char const * const artist,
   7038 				    char const * const composer,
   7039 				    char const * const genre,
   7040 				    uint32_t const parenthandle,
   7041 				    uint32_t const storageid,
   7042 				    uint16_t const objectformat,
   7043 				    char const * const suffix,
   7044 				    uint32_t * const newid,
   7045 				    uint32_t const * const tracks,
   7046 				    uint32_t const no_tracks)
   7047 
   7048 {
   7049   int i;
   7050   int supported = 0;
   7051   uint16_t ret;
   7052   uint16_t *properties = NULL;
   7053   uint32_t propcnt = 0;
   7054   uint32_t store;
   7055   uint32_t localph = parenthandle;
   7056   uint8_t nonconsumable = 0x00U; /* By default it is consumable */
   7057   PTPParams *params = (PTPParams *) device->params;
   7058   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   7059   char fname[256];
   7060   uint8_t data[2];
   7061 
   7062   if (storageid == 0) {
   7063     // I'm just guessing that an abstract list may require 512 bytes
   7064     store = get_writeable_storageid(device, 512);
   7065   } else {
   7066     store = storageid;
   7067   }
   7068 
   7069   // Check if we can create an object of this type
   7070   for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
   7071     if (params->deviceinfo.ImageFormats[i] == objectformat) {
   7072       supported = 1;
   7073       break;
   7074     }
   7075   }
   7076   if (!supported) {
   7077     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type.");
   7078     printf("Unsupported abstract list type: %04x\n", objectformat);
   7079     return -1;
   7080   }
   7081 
   7082   // add the new suffix if it isn't there
   7083   fname[0] = '\0';
   7084   if (strlen(name) > strlen(suffix)) {
   7085     char const * const suff = &name[strlen(name)-strlen(suffix)];
   7086     if (!strcmp(suff, suffix)) {
   7087       // Home free.
   7088       strncpy(fname, name, sizeof(fname));
   7089     }
   7090   }
   7091   // If it didn't end with "<suffix>" then add that here.
   7092   if (fname[0] == '\0') {
   7093     strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
   7094     strcat(fname, suffix);
   7095     fname[sizeof(fname)-1] = '\0';
   7096   }
   7097 
   7098   if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
   7099       !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
   7100     MTPProperties *props = NULL;
   7101     MTPProperties *prop = NULL;
   7102     int nrofprops = 0;
   7103 
   7104     *newid = 0x00000000U;
   7105 
   7106     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
   7107 
   7108     for (i=0;i<propcnt;i++) {
   7109       PTPObjectPropDesc opd;
   7110 
   7111       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
   7112       if (ret != PTP_RC_OK) {
   7113 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
   7114 				"could not get property description.");
   7115       } else if (opd.GetSet) {
   7116 	switch (properties[i]) {
   7117 	case PTP_OPC_ObjectFileName:
   7118 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7119 	  prop->ObjectHandle = *newid;
   7120 	  prop->property = PTP_OPC_ObjectFileName;
   7121 	  prop->datatype = PTP_DTC_STR;
   7122 	  prop->propval.str = strdup(fname);
   7123 	  if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   7124 	    strip_7bit_from_utf8(prop->propval.str);
   7125 	  }
   7126 	  break;
   7127 	case PTP_OPC_ProtectionStatus:
   7128 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7129 	  prop->ObjectHandle = *newid;
   7130 	  prop->property = PTP_OPC_ProtectionStatus;
   7131 	  prop->datatype = PTP_DTC_UINT16;
   7132 	  prop->propval.u16 = 0x0000U; /* Not protected */
   7133 	  break;
   7134 	case PTP_OPC_NonConsumable:
   7135 	  prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7136 	  prop->ObjectHandle = *newid;
   7137 	  prop->property = PTP_OPC_NonConsumable;
   7138 	  prop->datatype = PTP_DTC_UINT8;
   7139 	  prop->propval.u8 = nonconsumable;
   7140 	  break;
   7141 	case PTP_OPC_Name:
   7142 	  if (name != NULL) {
   7143 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7144 	    prop->ObjectHandle = *newid;
   7145 	    prop->property = PTP_OPC_Name;
   7146 	    prop->datatype = PTP_DTC_STR;
   7147 	    prop->propval.str = strdup(name);
   7148 	  }
   7149 	  break;
   7150 	case PTP_OPC_AlbumArtist:
   7151 	  if (artist != NULL) {
   7152 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7153 	    prop->ObjectHandle = *newid;
   7154 	    prop->property = PTP_OPC_AlbumArtist;
   7155 	    prop->datatype = PTP_DTC_STR;
   7156 	    prop->propval.str = strdup(artist);
   7157 	  }
   7158 	  break;
   7159 	case PTP_OPC_Artist:
   7160 	  if (artist != NULL) {
   7161 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7162 	    prop->ObjectHandle = *newid;
   7163 	    prop->property = PTP_OPC_Artist;
   7164 	    prop->datatype = PTP_DTC_STR;
   7165 	    prop->propval.str = strdup(artist);
   7166 	  }
   7167 	  break;
   7168 	case PTP_OPC_Composer:
   7169 	  if (composer != NULL) {
   7170 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7171 	    prop->ObjectHandle = *newid;
   7172 	    prop->property = PTP_OPC_Composer;
   7173 	    prop->datatype = PTP_DTC_STR;
   7174 	    prop->propval.str = strdup(composer);
   7175 	  }
   7176 	  break;
   7177 	case PTP_OPC_Genre:
   7178 	  if (genre != NULL) {
   7179 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7180 	    prop->ObjectHandle = *newid;
   7181 	    prop->property = PTP_OPC_Genre;
   7182 	    prop->datatype = PTP_DTC_STR;
   7183 	    prop->propval.str = strdup(genre);
   7184 	  }
   7185 	  break;
   7186  	case PTP_OPC_DateModified:
   7187 	  // Tag with current time if that is supported
   7188 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   7189 	    prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
   7190 	    prop->ObjectHandle = *newid;
   7191 	    prop->property = PTP_OPC_DateModified;
   7192 	    prop->datatype = PTP_DTC_STR;
   7193 	    prop->propval.str = get_iso8601_stamp();
   7194 	  }
   7195 	  break;
   7196 	}
   7197       }
   7198       ptp_free_objectpropdesc(&opd);
   7199     }
   7200     free(properties);
   7201 
   7202     ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
   7203 				     objectformat, 0, props, nrofprops);
   7204 
   7205     /* Free property list */
   7206     ptp_destroy_object_prop_list(props, nrofprops);
   7207 
   7208     if (ret != PTP_RC_OK) {
   7209       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
   7210       if (ret == PTP_RC_AccessDenied) {
   7211 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
   7212       }
   7213       return -1;
   7214     }
   7215 
   7216     // now send the blank object
   7217     ret = ptp_sendobject(params, NULL, 0);
   7218     if (ret != PTP_RC_OK) {
   7219       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
   7220       return -1;
   7221     }
   7222 
   7223   } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
   7224     PTPObjectInfo new_object;
   7225 
   7226     new_object.Filename = fname;
   7227     if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
   7228       strip_7bit_from_utf8(new_object.Filename);
   7229     }
   7230     new_object.ObjectCompressedSize = 1;
   7231     new_object.ObjectFormat = objectformat;
   7232 
   7233     // Create the object
   7234     ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
   7235     if (ret != PTP_RC_OK) {
   7236       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
   7237       if (ret == PTP_RC_AccessDenied) {
   7238 	add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
   7239       }
   7240       return -1;
   7241     }
   7242     // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
   7243     // not copies.
   7244     /*
   7245      * We have to send this one blank data byte.
   7246      * If we don't, the handle will not be created and thus there is no playlist.
   7247      */
   7248     data[0] = '\0';
   7249     data[1] = '\0';
   7250     ret = ptp_sendobject(params, data, 1);
   7251     if (ret != PTP_RC_OK) {
   7252       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
   7253       return -1;
   7254     }
   7255 
   7256     // set the properties one by one
   7257     ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
   7258 
   7259     for (i=0;i<propcnt;i++) {
   7260       PTPObjectPropDesc opd;
   7261 
   7262       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
   7263       if (ret != PTP_RC_OK) {
   7264 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
   7265 				"could not get property description.");
   7266       } else if (opd.GetSet) {
   7267 	switch (properties[i]) {
   7268 	case PTP_OPC_Name:
   7269 	  if (name != NULL) {
   7270 	    ret = set_object_string(device, *newid, PTP_OPC_Name, name);
   7271 	    if (ret != 0) {
   7272 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
   7273 	      return -1;
   7274 	    }
   7275 	  }
   7276 	  break;
   7277 	case PTP_OPC_AlbumArtist:
   7278 	  if (artist != NULL) {
   7279 	    ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
   7280 	    if (ret != 0) {
   7281 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
   7282 	      return -1;
   7283 	    }
   7284 	  }
   7285 	  break;
   7286 	case PTP_OPC_Artist:
   7287 	  if (artist != NULL) {
   7288 	    ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
   7289 	    if (ret != 0) {
   7290 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
   7291 	      return -1;
   7292 	    }
   7293 	  }
   7294 	  break;
   7295 	case PTP_OPC_Composer:
   7296 	  if (composer != NULL) {
   7297 	    ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
   7298 	    if (ret != 0) {
   7299 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
   7300 	      return -1;
   7301 	    }
   7302 	  }
   7303 	  break;
   7304 	case PTP_OPC_Genre:
   7305 	  if (genre != NULL) {
   7306 	    ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
   7307 	    if (ret != 0) {
   7308 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
   7309 	      return -1;
   7310 	    }
   7311 	  }
   7312 	  break;
   7313  	case PTP_OPC_DateModified:
   7314 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   7315 	    ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
   7316 	    if (ret != 0) {
   7317 	      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
   7318 	      return -1;
   7319 	    }
   7320 	  }
   7321 	  break;
   7322 	}
   7323       }
   7324       ptp_free_objectpropdesc(&opd);
   7325     }
   7326     free(properties);
   7327   }
   7328 
   7329   if (no_tracks > 0) {
   7330     // Add tracks to the list as object references.
   7331     ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
   7332     if (ret != PTP_RC_OK) {
   7333       add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
   7334       return -1;
   7335     }
   7336   }
   7337 
   7338   add_object_to_cache(device, *newid);
   7339 
   7340   return 0;
   7341 }
   7342 
   7343 /**
   7344  * This updates the metadata and track listing
   7345  * for an abstract list.
   7346  * @param device a pointer to the device that the abstract list
   7347  *        resides on.
   7348  * @param name the name of the abstract list.
   7349  * @param artist the artist of the abstract list or NULL.
   7350  * @param genre the genre of the abstract list or NULL.
   7351  * @param objecthandle the object to be updated.
   7352  * @param objectformat the abstract list type to update.
   7353  * @param tracks an array of tracks to associate with this list.
   7354  * @param no_tracks the number of tracks in the list.
   7355  * @return 0 on success, any other value means failure.
   7356  */
   7357 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
   7358 				char const * const name,
   7359 				char const * const artist,
   7360 				char const * const composer,
   7361 				char const * const genre,
   7362 				uint32_t const objecthandle,
   7363 				uint16_t const objectformat,
   7364 				uint32_t const * const tracks,
   7365 				uint32_t const no_tracks)
   7366 {
   7367   uint16_t ret;
   7368   PTPParams *params = (PTPParams *) device->params;
   7369   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   7370   uint16_t *properties = NULL;
   7371   uint32_t propcnt = 0;
   7372   int i;
   7373 
   7374   // First see which properties can be set
   7375   // i.e only try to update this metadata for object tags that exist on the current player.
   7376   ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
   7377   if (ret != PTP_RC_OK) {
   7378     // Just bail out for now, nothing is ever set.
   7379     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7380 			    "could not retrieve supported object properties.");
   7381     return -1;
   7382   }
   7383   if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
   7384       !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
   7385     MTPProperties *props = NULL;
   7386     MTPProperties *prop = NULL;
   7387     int nrofprops = 0;
   7388 
   7389     for (i=0;i<propcnt;i++) {
   7390       PTPObjectPropDesc opd;
   7391 
   7392       ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
   7393       if (ret != PTP_RC_OK) {
   7394 	add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7395 				"could not get property description.");
   7396       } else if (opd.GetSet) {
   7397 	switch (properties[i]) {
   7398 	case PTP_OPC_Name:
   7399 	  prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7400 	  prop->ObjectHandle = objecthandle;
   7401 	  prop->property = PTP_OPC_Name;
   7402 	  prop->datatype = PTP_DTC_STR;
   7403 	  if (name != NULL)
   7404 	    prop->propval.str = strdup(name);
   7405 	  break;
   7406 	case PTP_OPC_AlbumArtist:
   7407 	  if (artist != NULL) {
   7408 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7409 	    prop->ObjectHandle = objecthandle;
   7410 	    prop->property = PTP_OPC_AlbumArtist;
   7411 	    prop->datatype = PTP_DTC_STR;
   7412 	    prop->propval.str = strdup(artist);
   7413 	  }
   7414 	  break;
   7415 	case PTP_OPC_Artist:
   7416 	  if (artist != NULL) {
   7417 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7418 	    prop->ObjectHandle = objecthandle;
   7419 	    prop->property = PTP_OPC_Artist;
   7420 	    prop->datatype = PTP_DTC_STR;
   7421 	    prop->propval.str = strdup(artist);
   7422 	  }
   7423 	  break;
   7424 	case PTP_OPC_Composer:
   7425 	  if (composer != NULL) {
   7426 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7427 	    prop->ObjectHandle = objecthandle;
   7428 	    prop->property = PTP_OPC_Composer;
   7429 	    prop->datatype = PTP_DTC_STR;
   7430 	    prop->propval.str = strdup(composer);
   7431 	  }
   7432 	  break;
   7433 	case PTP_OPC_Genre:
   7434 	  if (genre != NULL) {
   7435 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7436 	    prop->ObjectHandle = objecthandle;
   7437 	    prop->property = PTP_OPC_Genre;
   7438 	    prop->datatype = PTP_DTC_STR;
   7439 	    prop->propval.str = strdup(genre);
   7440 	  }
   7441 	  break;
   7442  	case PTP_OPC_DateModified:
   7443 	  if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   7444 	    // Tag with current time if that is supported
   7445 	    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
   7446 	    prop->ObjectHandle = objecthandle;
   7447 	    prop->property = PTP_OPC_DateModified;
   7448 	    prop->datatype = PTP_DTC_STR;
   7449 	    prop->propval.str = get_iso8601_stamp();
   7450 	  }
   7451 	  break;
   7452 	default:
   7453 	  break;
   7454 	}
   7455       }
   7456       ptp_free_objectpropdesc(&opd);
   7457     }
   7458 
   7459     // proplist could be NULL if we can't write any properties
   7460     if (props != NULL) {
   7461       ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
   7462 
   7463       ptp_destroy_object_prop_list(props, nrofprops);
   7464 
   7465       if (ret != PTP_RC_OK) {
   7466         // TODO: return error of which property we couldn't set
   7467         add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7468                                 "could not set object property list.");
   7469         free(properties);
   7470         return -1;
   7471       }
   7472     }
   7473 
   7474   } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
   7475     for (i=0;i<propcnt;i++) {
   7476       switch (properties[i]) {
   7477       case PTP_OPC_Name:
   7478 	// Update title
   7479 	ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
   7480 	if (ret != 0) {
   7481 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7482 				  "could not set title.");
   7483 	}
   7484 	break;
   7485       case PTP_OPC_AlbumArtist:
   7486 	// Update album artist
   7487 	ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
   7488 	if (ret != 0) {
   7489 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7490 				  "could not set album artist name.");
   7491 	}
   7492 	break;
   7493       case PTP_OPC_Artist:
   7494 	// Update artist
   7495 	ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
   7496 	if (ret != 0) {
   7497 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7498 				  "could not set artist name.");
   7499 	}
   7500       case PTP_OPC_Composer:
   7501 	// Update composer
   7502 	ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
   7503 	if (ret != 0) {
   7504 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7505 				  "could not set composer name.");
   7506 	}
   7507 	break;
   7508       case PTP_OPC_Genre:
   7509 	// Update genre
   7510 	ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
   7511 	if (ret != 0) {
   7512 	  add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7513 				  "could not set genre.");
   7514 	}
   7515 	break;
   7516       case PTP_OPC_DateModified:
   7517 	// Update date modified
   7518 	if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
   7519 	  char *tmpdate = get_iso8601_stamp();
   7520 	  ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
   7521 	  if (ret != 0) {
   7522 	    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7523 				    "could not set modification date.");
   7524 	  }
   7525 	  free(tmpdate);
   7526 	}
   7527       default:
   7528 	break;
   7529       }
   7530     }
   7531   } else {
   7532     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
   7533                             "Your device doesn't seem to support any known way of setting metadata.");
   7534     free(properties);
   7535     return -1;
   7536   }
   7537 
   7538   // Then the object references...
   7539   ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
   7540   if (ret != PTP_RC_OK) {
   7541     add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
   7542     free(properties);
   7543     return -1;
   7544   }
   7545 
   7546   free(properties);
   7547 
   7548   update_metadata_cache(device, objecthandle);
   7549 
   7550   return 0;
   7551 }
   7552 
   7553 
   7554 /**
   7555  * This routine creates a new playlist based on the metadata
   7556  * supplied. If the <code>tracks</code> field of the metadata
   7557  * contains a track listing, these tracks will be added to the
   7558  * playlist.
   7559  * @param device a pointer to the device to create the new playlist on.
   7560  * @param metadata the metadata for the new playlist. If the function
   7561  *        exits with success, the <code>playlist_id</code> field of this
   7562  *        struct will contain the new playlist ID of the playlist.
   7563  *        <ul>
   7564  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
   7565  *        (e.g. folder) to store this track in. Since some
   7566  *        devices are a bit picky about where files
   7567  *        are placed, a default folder will be chosen if libmtp
   7568  *        has detected one for the current filetype and this
   7569  *        parameter is set to 0. If this is 0 and no default folder
   7570  *        can be found, the file will be stored in the root folder.
   7571  *        <li><code>metadata-&gt;storage_id</code> should be set to the
   7572  *        desired storage (e.g. memory card or whatever your device
   7573  *        presents) to store this track in. Setting this to 0 will store
   7574  *        the track on the primary storage.
   7575  *        </ul>
   7576  * @return 0 on success, any other value means failure.
   7577  * @see LIBMTP_Update_Playlist()
   7578  * @see LIBMTP_Delete_Object()
   7579  */
   7580 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
   7581 			       LIBMTP_playlist_t * const metadata)
   7582 {
   7583   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   7584   uint32_t localph = metadata->parent_id;
   7585 
   7586   // Use a default folder if none given
   7587   if (localph == 0) {
   7588     if (device->default_playlist_folder != 0)
   7589       localph = device->default_playlist_folder;
   7590     else
   7591       localph = device->default_music_folder;
   7592   }
   7593   metadata->parent_id = localph;
   7594 
   7595   // Samsung needs its own special type of playlists
   7596   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
   7597     return playlist_t_to_spl(device, metadata);
   7598   }
   7599 
   7600   // Just create a new abstract audio/video playlist...
   7601   return create_new_abstract_list(device,
   7602 				  metadata->name,
   7603 				  NULL,
   7604 				  NULL,
   7605 				  NULL,
   7606 				  localph,
   7607 				  metadata->storage_id,
   7608 				  PTP_OFC_MTP_AbstractAudioVideoPlaylist,
   7609 				  get_playlist_extension(ptp_usb),
   7610 				  &metadata->playlist_id,
   7611 				  metadata->tracks,
   7612 				  metadata->no_tracks);
   7613 }
   7614 
   7615 /**
   7616  * This routine updates a playlist based on the metadata
   7617  * supplied. If the <code>tracks</code> field of the metadata
   7618  * contains a track listing, these tracks will be added to the
   7619  * playlist in place of those already present, i.e. the
   7620  * previous track listing will be deleted. For Samsung devices the
   7621  * playlist id (metadata->playlist_id) is likely to change.
   7622  * @param device a pointer to the device to create the new playlist on.
   7623  * @param metadata the metadata for the playlist to be updated.
   7624  *                 notice that the field <code>playlist_id</code>
   7625  *                 must contain the apropriate playlist ID. Playlist ID
   7626  *                 be modified to a new playlist ID by the time the
   7627  *                 function returns since edit-in-place is not always possible.
   7628  * @return 0 on success, any other value means failure.
   7629  * @see LIBMTP_Create_New_Playlist()
   7630  * @see LIBMTP_Delete_Object()
   7631  */
   7632 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
   7633 			   LIBMTP_playlist_t * const metadata)
   7634 {
   7635 
   7636   // Samsung needs its own special type of playlists
   7637   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   7638   if(FLAG_PLAYLIST_SPL(ptp_usb)) {
   7639     return update_spl_playlist(device, metadata);
   7640   }
   7641 
   7642   return update_abstract_list(device,
   7643 			      metadata->name,
   7644 			      NULL,
   7645 			      NULL,
   7646 			      NULL,
   7647 			      metadata->playlist_id,
   7648 			      PTP_OFC_MTP_AbstractAudioVideoPlaylist,
   7649 			      metadata->tracks,
   7650 			      metadata->no_tracks);
   7651 }
   7652 
   7653 /**
   7654  * This creates a new album metadata structure and allocates memory
   7655  * for it. Notice that if you add strings to this structure they
   7656  * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
   7657  * operation later, so be careful of using strdup() when assigning
   7658  * strings.
   7659  *
   7660  * @return a pointer to the newly allocated metadata structure.
   7661  * @see LIBMTP_destroy_album_t()
   7662  */
   7663 LIBMTP_album_t *LIBMTP_new_album_t(void)
   7664 {
   7665   LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
   7666   if (new == NULL) {
   7667     return NULL;
   7668   }
   7669   new->album_id = 0;
   7670   new->parent_id = 0;
   7671   new->storage_id = 0;
   7672   new->name = NULL;
   7673   new->artist = NULL;
   7674   new->composer = NULL;
   7675   new->genre = NULL;
   7676   new->tracks = NULL;
   7677   new->no_tracks = 0;
   7678   new->next = NULL;
   7679   return new;
   7680 }
   7681 
   7682 /**
   7683  * This recursively deletes the memory for an album structure
   7684  *
   7685  * @param album structure to destroy
   7686  * @see LIBMTP_new_album_t()
   7687  */
   7688 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
   7689 {
   7690   if (album == NULL) {
   7691     return;
   7692   }
   7693   if (album->name != NULL)
   7694     free(album->name);
   7695   if (album->artist != NULL)
   7696     free(album->artist);
   7697   if (album->composer != NULL)
   7698     free(album->composer);
   7699   if (album->genre != NULL)
   7700     free(album->genre);
   7701   if (album->tracks != NULL)
   7702     free(album->tracks);
   7703   free(album);
   7704   return;
   7705 }
   7706 
   7707 /**
   7708  * This function maps and copies a property onto the album metadata if applicable.
   7709  */
   7710 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
   7711 					    MTPProperties *prop, LIBMTP_album_t *alb)
   7712 {
   7713   switch (prop->property) {
   7714   case PTP_OPC_Name:
   7715     if (prop->propval.str != NULL)
   7716       alb->name = strdup(prop->propval.str);
   7717     else
   7718       alb->name = NULL;
   7719     break;
   7720   case PTP_OPC_AlbumArtist:
   7721     if (prop->propval.str != NULL) {
   7722       // This should take precedence over plain "Artist"
   7723       if (alb->artist != NULL)
   7724 	free(alb->artist);
   7725       alb->artist = strdup(prop->propval.str);
   7726     } else
   7727       alb->artist = NULL;
   7728     break;
   7729   case PTP_OPC_Artist:
   7730     if (prop->propval.str != NULL) {
   7731       // Only use of AlbumArtist is not set
   7732       if (alb->artist == NULL)
   7733 	alb->artist = strdup(prop->propval.str);
   7734     } else
   7735       alb->artist = NULL;
   7736     break;
   7737   case PTP_OPC_Composer:
   7738     if (prop->propval.str != NULL)
   7739       alb->composer = strdup(prop->propval.str);
   7740     else
   7741       alb->composer = NULL;
   7742     break;
   7743   case PTP_OPC_Genre:
   7744     if (prop->propval.str != NULL)
   7745       alb->genre = strdup(prop->propval.str);
   7746     else
   7747       alb->genre = NULL;
   7748     break;
   7749   }
   7750 }
   7751 
   7752 /**
   7753  * This function retrieves the album metadata for an album
   7754  * given by a unique ID.
   7755  * @param device a pointer to the device to get the track metadata off.
   7756  * @param alb an album metadata metadata set to fill in.
   7757  */
   7758 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
   7759 			       LIBMTP_album_t *alb)
   7760 {
   7761   uint16_t ret;
   7762   PTPParams *params = (PTPParams *) device->params;
   7763   uint32_t i;
   7764   MTPProperties *prop;
   7765   PTPObject *ob;
   7766 
   7767   /*
   7768    * If we have a cached, large set of metadata, then use it!
   7769    */
   7770   ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
   7771   if (ob->mtpprops) {
   7772     prop = ob->mtpprops;
   7773     for (i=0;i<ob->nrofmtpprops;i++,prop++)
   7774       pick_property_to_album_metadata(device, prop, alb);
   7775   } else {
   7776     uint16_t *props = NULL;
   7777     uint32_t propcnt = 0;
   7778 
   7779     // First see which properties can be retrieved for albums
   7780     ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
   7781     if (ret != PTP_RC_OK) {
   7782       add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
   7783       // Just bail out for now, nothing is ever set.
   7784       return;
   7785     } else {
   7786       for (i=0;i<propcnt;i++) {
   7787 	switch (props[i]) {
   7788 	case PTP_OPC_Name:
   7789 	  alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
   7790 	  break;
   7791 	case PTP_OPC_AlbumArtist:
   7792 	  if (alb->artist != NULL)
   7793 	    free(alb->artist);
   7794 	  alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
   7795 	  break;
   7796 	case PTP_OPC_Artist:
   7797 	  if (alb->artist == NULL)
   7798 	    alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
   7799 	  break;
   7800 	case PTP_OPC_Composer:
   7801 	  alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
   7802 	  break;
   7803 	case PTP_OPC_Genre:
   7804 	  alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
   7805 	  break;
   7806 	default:
   7807 	  break;
   7808 	}
   7809       }
   7810       free(props);
   7811     }
   7812   }
   7813 }
   7814 
   7815 /**
   7816  * This function returns a list of the albums available on the
   7817  * device.
   7818  *
   7819  * @param device a pointer to the device to get the album listing from.
   7820  * @return an album list on success, else NULL. If there are no albums
   7821  *         on the device, NULL will be returned as well.
   7822  * @see LIBMTP_Get_Album()
   7823  */
   7824 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
   7825 {
   7826   PTPParams *params = (PTPParams *) device->params;
   7827   LIBMTP_album_t *retalbums = NULL;
   7828   LIBMTP_album_t *curalbum = NULL;
   7829   uint32_t i;
   7830 
   7831   // Get all the handles if we haven't already done that
   7832   if (params->nrofobjects == 0)
   7833     flush_handles(device);
   7834 
   7835   for (i = 0; i < params->nrofobjects; i++) {
   7836     LIBMTP_album_t *alb;
   7837     PTPObject *ob;
   7838     uint16_t ret;
   7839 
   7840     ob = &params->objects[i];
   7841 
   7842     // Ignore stuff that isn't an album
   7843     if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
   7844       continue;
   7845 
   7846     // Allocate a new album type
   7847     alb = LIBMTP_new_album_t();
   7848     alb->album_id = ob->oid;
   7849     alb->parent_id = ob->oi.ParentObject;
   7850     alb->storage_id = ob->oi.StorageID;
   7851 
   7852     // Fetch supported metadata
   7853     get_album_metadata(device, alb);
   7854 
   7855     // Then get the track listing for this album
   7856     ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
   7857     if (ret != PTP_RC_OK) {
   7858       add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
   7859       alb->tracks = NULL;
   7860       alb->no_tracks = 0;
   7861     }
   7862 
   7863     // Add album to a list that will be returned afterwards.
   7864     if (retalbums == NULL) {
   7865       retalbums = alb;
   7866       curalbum = alb;
   7867     } else {
   7868       curalbum->next = alb;
   7869       curalbum = alb;
   7870     }
   7871 
   7872   }
   7873   return retalbums;
   7874 }
   7875 
   7876 /**
   7877  * This function retrieves an individual album from the device.
   7878  * @param device a pointer to the device to get the album from.
   7879  * @param albid the unique ID of the album to retrieve.
   7880  * @return a valid album metadata or NULL on failure.
   7881  * @see LIBMTP_Get_Album_List()
   7882  */
   7883 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
   7884 {
   7885   PTPParams *params = (PTPParams *) device->params;
   7886   uint16_t ret;
   7887   PTPObject *ob;
   7888   LIBMTP_album_t *alb;
   7889 
   7890   // Get all the handles if we haven't already done that
   7891   if (params->nrofobjects == 0)
   7892     flush_handles(device);
   7893 
   7894   ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   7895   if (ret != PTP_RC_OK)
   7896     return NULL;
   7897 
   7898   // Ignore stuff that isn't an album
   7899   if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
   7900     return NULL;
   7901 
   7902   // Allocate a new album type
   7903   alb = LIBMTP_new_album_t();
   7904   alb->album_id = ob->oid;
   7905   alb->parent_id = ob->oi.ParentObject;
   7906   alb->storage_id = ob->oi.StorageID;
   7907 
   7908   // Fetch supported metadata
   7909   get_album_metadata(device, alb);
   7910 
   7911   // Then get the track listing for this album
   7912   ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
   7913   if (ret != PTP_RC_OK) {
   7914     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
   7915     alb->tracks = NULL;
   7916     alb->no_tracks = 0;
   7917   }
   7918 
   7919   return alb;
   7920 }
   7921 
   7922 /**
   7923  * This routine creates a new album based on the metadata
   7924  * supplied. If the <code>tracks</code> field of the metadata
   7925  * contains a track listing, these tracks will be added to the
   7926  * album.
   7927  * @param device a pointer to the device to create the new album on.
   7928  * @param metadata the metadata for the new album. If the function
   7929  *        exits with success, the <code>album_id</code> field of this
   7930  *        struct will contain the new ID of the album.
   7931  *        <ul>
   7932  *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
   7933  *        (e.g. folder) to store this track in. Since some
   7934  *        devices are a bit picky about where files
   7935  *        are placed, a default folder will be chosen if libmtp
   7936  *        has detected one for the current filetype and this
   7937  *        parameter is set to 0. If this is 0 and no default folder
   7938  *        can be found, the file will be stored in the root folder.
   7939  *        <li><code>metadata-&gt;storage_id</code> should be set to the
   7940  *        desired storage (e.g. memory card or whatever your device
   7941  *        presents) to store this track in. Setting this to 0 will store
   7942  *        the track on the primary storage.
   7943  *        </ul>
   7944  * @return 0 on success, any other value means failure.
   7945  * @see LIBMTP_Update_Album()
   7946  * @see LIBMTP_Delete_Object()
   7947  */
   7948 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
   7949 			    LIBMTP_album_t * const metadata)
   7950 {
   7951   uint32_t localph = metadata->parent_id;
   7952 
   7953   // Use a default folder if none given
   7954   if (localph == 0) {
   7955     if (device->default_album_folder != 0)
   7956       localph = device->default_album_folder;
   7957     else
   7958       localph = device->default_music_folder;
   7959   }
   7960   metadata->parent_id = localph;
   7961 
   7962   // Just create a new abstract album...
   7963   return create_new_abstract_list(device,
   7964 				  metadata->name,
   7965 				  metadata->artist,
   7966 				  metadata->composer,
   7967 				  metadata->genre,
   7968 				  localph,
   7969 				  metadata->storage_id,
   7970 				  PTP_OFC_MTP_AbstractAudioAlbum,
   7971 				  ".alb",
   7972 				  &metadata->album_id,
   7973 				  metadata->tracks,
   7974 				  metadata->no_tracks);
   7975 }
   7976 
   7977 /**
   7978  * This creates a new sample data metadata structure and allocates memory
   7979  * for it. Notice that if you add strings to this structure they
   7980  * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
   7981  * operation later, so be careful of using strdup() when assigning
   7982  * strings.
   7983  *
   7984  * @return a pointer to the newly allocated metadata structure.
   7985  * @see LIBMTP_destroy_sampledata_t()
   7986  */
   7987 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
   7988 {
   7989   LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
   7990   if (new == NULL) {
   7991     return NULL;
   7992   }
   7993   new->height=0;
   7994   new->width = 0;
   7995   new->data = NULL;
   7996   new->duration = 0;
   7997   new->size = 0;
   7998   return new;
   7999 }
   8000 
   8001 /**
   8002  * This destroys a file sample metadata type.
   8003  * @param sample the file sample metadata to be destroyed.
   8004  */
   8005 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
   8006 {
   8007   if (sample == NULL) {
   8008     return;
   8009   }
   8010   if (sample->data != NULL) {
   8011     free(sample->data);
   8012   }
   8013   free(sample);
   8014 }
   8015 
   8016 /**
   8017  * This routine figures out whether a certain filetype supports
   8018  * representative samples (small thumbnail images) or not. This
   8019  * typically applies to JPEG files, MP3 files and Album abstract
   8020  * playlists, but in theory any filetype could support representative
   8021  * samples.
   8022  * @param device a pointer to the device which is to be examined.
   8023  * @param filetype the fileype to examine, and return the representative sample
   8024  *        properties for.
   8025  * @param sample this will contain a new sample type with the fields
   8026  *        filled in with suitable default values. For example, the
   8027  *        supported sample type will be set, the supported height and
   8028  *        width will be set to max values if it is an image sample,
   8029  *        and duration will also be given some suitable default value
   8030  *        which should not be exceeded on audio samples. If the
   8031  *        device does not support samples for this filetype, this
   8032  *        pointer will be NULL. If it is not NULL, the user must
   8033  *        destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
   8034  *        after use.
   8035  * @return 0 on success, any other value means failure.
   8036  * @see LIBMTP_Send_Representative_Sample()
   8037  * @see LIBMTP_Create_New_Album()
   8038  */
   8039 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
   8040 					    LIBMTP_filetype_t const filetype,
   8041 					    LIBMTP_filesampledata_t ** sample)
   8042 {
   8043   uint16_t ret;
   8044   PTPParams *params = (PTPParams *) device->params;
   8045   uint16_t *props = NULL;
   8046   uint32_t propcnt = 0;
   8047   int i;
   8048   // TODO: Get rid of these when we can properly query the device.
   8049   int support_data = 0;
   8050   int support_format = 0;
   8051   int support_height = 0;
   8052   int support_width = 0;
   8053   int support_duration = 0;
   8054   int support_size = 0;
   8055 
   8056   PTPObjectPropDesc opd_height;
   8057   PTPObjectPropDesc opd_width;
   8058   PTPObjectPropDesc opd_format;
   8059   PTPObjectPropDesc opd_duration;
   8060   PTPObjectPropDesc opd_size;
   8061 
   8062   // Default to no type supported.
   8063   *sample = NULL;
   8064 
   8065   ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
   8066   if (ret != PTP_RC_OK) {
   8067     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
   8068     return -1;
   8069   }
   8070   /*
   8071    * TODO: when walking through these object properties, make calls to
   8072    * a new function in ptp.h/ptp.c that can send the command
   8073    * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
   8074    * supported.
   8075    */
   8076   for (i = 0; i < propcnt; i++) {
   8077     switch(props[i]) {
   8078     case PTP_OPC_RepresentativeSampleData:
   8079       support_data = 1;
   8080       break;
   8081     case PTP_OPC_RepresentativeSampleFormat:
   8082       support_format = 1;
   8083       break;
   8084     case PTP_OPC_RepresentativeSampleSize:
   8085       support_size = 1;
   8086       break;
   8087     case PTP_OPC_RepresentativeSampleHeight:
   8088       support_height = 1;
   8089       break;
   8090     case PTP_OPC_RepresentativeSampleWidth:
   8091       support_width = 1;
   8092       break;
   8093     case PTP_OPC_RepresentativeSampleDuration:
   8094       support_duration = 1;
   8095       break;
   8096     default:
   8097       break;
   8098     }
   8099   }
   8100   free(props);
   8101 
   8102   if (support_data && support_format && support_height && support_width && !support_duration) {
   8103     // Something that supports height and width and not duration is likely to be JPEG
   8104     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
   8105     /*
   8106      * Populate the sample format with the first supported format
   8107      *
   8108      * TODO: figure out how to pass back more than one format if more are
   8109      * supported by the device.
   8110      */
   8111     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
   8112     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
   8113     ptp_free_objectpropdesc(&opd_format);
   8114     /* Populate the maximum image height */
   8115     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
   8116     retsam->width = opd_width.FORM.Range.MaximumValue.u32;
   8117     ptp_free_objectpropdesc(&opd_width);
   8118     /* Populate the maximum image width */
   8119     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
   8120     retsam->height = opd_height.FORM.Range.MaximumValue.u32;
   8121     ptp_free_objectpropdesc(&opd_height);
   8122     /* Populate the maximum size */
   8123     if (support_size) {
   8124       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
   8125       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
   8126       ptp_free_objectpropdesc(&opd_size);
   8127     }
   8128     *sample = retsam;
   8129   } else if (support_data && support_format && !support_height && !support_width && support_duration) {
   8130     // Another qualified guess
   8131     LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
   8132     /*
   8133      * Populate the sample format with the first supported format
   8134      *
   8135      * TODO: figure out how to pass back more than one format if more are
   8136      * supported by the device.
   8137      */
   8138     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
   8139     retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
   8140     ptp_free_objectpropdesc(&opd_format);
   8141     /* Populate the maximum duration */
   8142     ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
   8143     retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
   8144     ptp_free_objectpropdesc(&opd_duration);
   8145     /* Populate the maximum size */
   8146     if (support_size) {
   8147       ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
   8148       retsam->size = opd_size.FORM.Range.MaximumValue.u32;
   8149       ptp_free_objectpropdesc(&opd_size);
   8150     }
   8151     *sample = retsam;
   8152   }
   8153   return 0;
   8154 }
   8155 
   8156 /**
   8157  * This routine sends representative sample data for an object.
   8158  * This uses the RepresentativeSampleData property of the album,
   8159  * if the device supports it. The data should be of a format acceptable
   8160  * to the player (for iRiver and Creative, this seems to be JPEG) and
   8161  * must not be too large. (for a Creative, max seems to be about 20KB.)
   8162  * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
   8163  * maximum size, dimensions, etc..
   8164  * @param device a pointer to the device which the object is on.
   8165  * @param id unique id of the object to set artwork for.
   8166  * @param pointer to LIBMTP_filesampledata_t struct containing data
   8167  * @return 0 on success, any other value means failure.
   8168  * @see LIBMTP_Get_Representative_Sample()
   8169  * @see LIBMTP_Get_Representative_Sample_Format()
   8170  * @see LIBMTP_Create_New_Album()
   8171  */
   8172 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
   8173                           uint32_t const id,
   8174                           LIBMTP_filesampledata_t *sampledata)
   8175 {
   8176   uint16_t ret;
   8177   PTPParams *params = (PTPParams *) device->params;
   8178   PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
   8179   PTPPropertyValue propval;
   8180   PTPObject *ob;
   8181   uint32_t i;
   8182   uint16_t *props = NULL;
   8183   uint32_t propcnt = 0;
   8184   int supported = 0;
   8185 
   8186   // get the file format for the object we're going to send representative data for
   8187   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   8188   if (ret != PTP_RC_OK) {
   8189     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
   8190     return -1;
   8191   }
   8192 
   8193   // check that we can send representative sample data for this object format
   8194   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
   8195   if (ret != PTP_RC_OK) {
   8196     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
   8197     return -1;
   8198   }
   8199 
   8200   for (i = 0; i < propcnt; i++) {
   8201     if (props[i] == PTP_OPC_RepresentativeSampleData) {
   8202       supported = 1;
   8203       break;
   8204     }
   8205   }
   8206   if (!supported) {
   8207     free(props);
   8208     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
   8209     return -1;
   8210   }
   8211   free(props);
   8212 
   8213   // Go ahead and send the data
   8214   propval.a.count = sampledata->size;
   8215   propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
   8216   for (i = 0; i < sampledata->size; i++) {
   8217     propval.a.v[i].u8 = sampledata->data[i];
   8218   }
   8219 
   8220   ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
   8221 				   &propval,PTP_DTC_AUINT8);
   8222   if (ret != PTP_RC_OK) {
   8223     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
   8224     free(propval.a.v);
   8225     return -1;
   8226   }
   8227   free(propval.a.v);
   8228 
   8229   /* Set the height and width if the sample is an image, otherwise just
   8230    * set the duration and size */
   8231   switch(sampledata->filetype) {
   8232   case LIBMTP_FILETYPE_JPEG:
   8233   case LIBMTP_FILETYPE_JFIF:
   8234   case LIBMTP_FILETYPE_TIFF:
   8235   case LIBMTP_FILETYPE_BMP:
   8236   case LIBMTP_FILETYPE_GIF:
   8237   case LIBMTP_FILETYPE_PICT:
   8238   case LIBMTP_FILETYPE_PNG:
   8239     if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
   8240       // For images, set the height and width
   8241       set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
   8242       set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
   8243     }
   8244     break;
   8245   default:
   8246     // For anything not an image, set the duration and size
   8247     set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
   8248     set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
   8249     break;
   8250   }
   8251 
   8252   return 0;
   8253 }
   8254 
   8255 /**
   8256  * This routine gets representative sample data for an object.
   8257  * This uses the RepresentativeSampleData property of the album,
   8258  * if the device supports it.
   8259  * @param device a pointer to the device which the object is on.
   8260  * @param id unique id of the object to get data for.
   8261  * @param pointer to LIBMTP_filesampledata_t struct to receive data
   8262  * @return 0 on success, any other value means failure.
   8263  * @see LIBMTP_Send_Representative_Sample()
   8264  * @see LIBMTP_Get_Representative_Sample_Format()
   8265  * @see LIBMTP_Create_New_Album()
   8266  */
   8267 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
   8268                           uint32_t const id,
   8269                           LIBMTP_filesampledata_t *sampledata)
   8270 {
   8271   uint16_t ret;
   8272   PTPParams *params = (PTPParams *) device->params;
   8273   PTPPropertyValue propval;
   8274   PTPObject *ob;
   8275   uint32_t i;
   8276   uint16_t *props = NULL;
   8277   uint32_t propcnt = 0;
   8278   int supported = 0;
   8279 
   8280   // get the file format for the object we're going to send representative data for
   8281   ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
   8282   if (ret != PTP_RC_OK) {
   8283     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
   8284     return -1;
   8285   }
   8286 
   8287   // check that we can store representative sample data for this object format
   8288   ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
   8289   if (ret != PTP_RC_OK) {
   8290     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
   8291     return -1;
   8292   }
   8293 
   8294   for (i = 0; i < propcnt; i++) {
   8295     if (props[i] == PTP_OPC_RepresentativeSampleData) {
   8296       supported = 1;
   8297       break;
   8298     }
   8299   }
   8300   if (!supported) {
   8301     free(props);
   8302     add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
   8303     return -1;
   8304   }
   8305   free(props);
   8306 
   8307   // Get the data
   8308   ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
   8309 				   &propval,PTP_DTC_AUINT8);
   8310   if (ret != PTP_RC_OK) {
   8311     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
   8312     return -1;
   8313   }
   8314 
   8315   // Store it
   8316   sampledata->size = propval.a.count;
   8317   sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
   8318   for (i = 0; i < propval.a.count; i++) {
   8319     sampledata->data[i] = propval.a.v[i].u8;
   8320   }
   8321   free(propval.a.v);
   8322 
   8323   // Get the other properties
   8324   sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
   8325   sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
   8326   sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
   8327   sampledata->filetype = map_ptp_type_to_libmtp_type(
   8328         get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
   8329 
   8330   return 0;
   8331 }
   8332 
   8333 /**
   8334  * This routine updates an album based on the metadata
   8335  * supplied. If the <code>tracks</code> field of the metadata
   8336  * contains a track listing, these tracks will be added to the
   8337  * album in place of those already present, i.e. the
   8338  * previous track listing will be deleted.
   8339  * @param device a pointer to the device to create the new album on.
   8340  * @param metadata the metadata for the album to be updated.
   8341  *                 notice that the field <code>album_id</code>
   8342  *                 must contain the apropriate album ID.
   8343  * @return 0 on success, any other value means failure.
   8344  * @see LIBMTP_Create_New_Album()
   8345  * @see LIBMTP_Delete_Object()
   8346  */
   8347 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
   8348 			   LIBMTP_album_t const * const metadata)
   8349 {
   8350   return update_abstract_list(device,
   8351 			      metadata->name,
   8352 			      metadata->artist,
   8353 			      metadata->composer,
   8354 			      metadata->genre,
   8355 			      metadata->album_id,
   8356 			      PTP_OFC_MTP_AbstractAudioAlbum,
   8357 			      metadata->tracks,
   8358 			      metadata->no_tracks);
   8359 }
   8360 
   8361 /**
   8362  * Dummy function needed to interface to upstream
   8363  * ptp.c/ptp.h files.
   8364  */
   8365 void ptp_nikon_getptpipguid (unsigned char* guid) {
   8366   return;
   8367 }
   8368 
   8369 /**
   8370  * Add an object to cache.
   8371  * @param device the device which may have a cache to which the object should be added.
   8372  * @param object_id the object to add to the cache.
   8373  */
   8374 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
   8375 {
   8376   PTPParams *params = (PTPParams *)device->params;
   8377   uint16_t ret;
   8378 
   8379   ret = ptp_add_object_to_cache(params, object_id);
   8380   if (ret != PTP_RC_OK) {
   8381     add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
   8382   }
   8383 }
   8384 
   8385 
   8386 /**
   8387  * Update cache after object has been modified
   8388  * @param device the device which may have a cache to which the object should be updated.
   8389  * @param object_id the object to update.
   8390  */
   8391 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
   8392 {
   8393   PTPParams *params = (PTPParams *)device->params;
   8394 
   8395   ptp_remove_object_from_cache(params, object_id);
   8396   add_object_to_cache(device, object_id);
   8397 }
   8398