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 <