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