4 * Copyright (C) 2005-2011 Linus Walleij <triad@df.lth.se>
5 * Copyright (C) 2005-2008 Richard A. Low <richard@wentnet.com>
6 * Copyright (C) 2007 Ted Bullock <tbullock@canada.com>
7 * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
8 * Copyright (C) 2008 Florent Mertens <flomertens@gmail.com>
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.
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.
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.
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).
31 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
32 * plain copied from the libhphoto2 codebase.
34 * The files libusb-glue.c/.h are just what they say: an
35 * interface to libusb for the actual, physical USB traffic.
41 #include "libusb-glue.h"
42 #include "device-flags.h"
43 #include "playlist-spl.h"
52 #include <sys/types.h>
57 #ifdef _MSC_VER // For MSVC++
58 #define USE_WINDOWS_IO_H
65 * We use a flag system to enable a part of logs.
67 * The LIBMTP_DEBUG environment variable sets the debug flags for any binary
68 * that uses libmtp and calls LIBMTP_Init. The value can be given in decimal
69 * (must not start with "0" or it will be interpreted in octal), or in
70 * hexadecimal (must start with "0x").
72 * The value "-1" enables all debug flags.
74 * Some of the utilities in examples/ also take a command-line flag "-d" that
75 * enables LIBMTP_DEBUG_PTP and LIBMTP_DEBUG_DATA (same as setting
78 * Flags (combine by adding the hex values):
79 * 0x00 [0000 0000] : LIBMTP_DEBUG_NONE : no debug (default)
80 * 0x01 [0000 0001] : LIBMTP_DEBUG_PTP : PTP debug
81 * 0x02 [0000 0010] : LIBMTP_DEBUG_PLST : Playlist debug
82 * 0x04 [0000 0100] : LIBMTP_DEBUG_USB : USB debug
83 * 0x08 [0000 1000] : LIBMTP_DEBUG_DATA : USB data debug
85 * (Please keep this list in sync with libmtp.h.)
87 int LIBMTP_debug = LIBMTP_DEBUG_NONE;
91 * This is a mapping between libmtp internal MTP filetypes and
92 * the libgphoto2/PTP equivalent defines. We need this because
93 * otherwise the libmtp.h device has to be dependent on ptp.h
94 * to be installed too, and we don't want that.
96 //typedef struct filemap_struct filemap_t;
97 typedef struct filemap_struct {
98 char *description; /**< Text description for the file type */
99 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
100 uint16_t ptp_id; /**< PTP ID for the filetype */
101 struct filemap_struct *next;
105 * This is a mapping between libmtp internal MTP properties and
106 * the libgphoto2/PTP equivalent defines. We need this because
107 * otherwise the libmtp.h device has to be dependent on ptp.h
108 * to be installed too, and we don't want that.
110 typedef struct propertymap_struct {
111 char *description; /**< Text description for the property */
112 LIBMTP_property_t id; /**< LIBMTP internal type for the property */
113 uint16_t ptp_id; /**< PTP ID for the property */
114 struct propertymap_struct *next;
118 // This holds the global filetype mapping table
119 static filemap_t *g_filemap = NULL;
120 // This holds the global property mapping table
121 static propertymap_t *g_propertymap = NULL;
124 * Forward declarations of local (static) functions.
126 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
127 uint16_t const ptp_id);
128 static void init_filemap();
129 static int register_property(char const * const description, LIBMTP_property_t const id,
130 uint16_t const ptp_id);
131 static void init_propertymap();
132 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
133 LIBMTP_error_number_t errornumber,
134 char const * const error_text);
135 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
137 char const * const error_text);
138 static void flush_handles(LIBMTP_mtpdevice_t *device);
139 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
143 static void free_storage_list(LIBMTP_mtpdevice_t *device);
144 static int sort_storage_by(LIBMTP_mtpdevice_t *device, int const sortby);
145 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
147 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
148 LIBMTP_devicestorage_t *storage,
149 uint64_t *freespace);
150 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
151 LIBMTP_devicestorage_t *storage,
152 uint64_t const filesize);
153 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
154 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
155 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
156 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
157 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
158 char **unicstring, uint16_t property);
159 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
160 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd);
161 static char *get_iso8601_stamp(void);
162 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
163 uint16_t const attribute_id);
164 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
165 uint16_t const attribute_id, uint64_t const value_default);
166 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
167 uint16_t const attribute_id, uint32_t const value_default);
168 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
169 uint16_t const attribute_id, uint16_t const value_default);
170 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
171 uint16_t const attribute_id, uint8_t const value_default);
172 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
173 uint16_t const attribute_id, char const * const string);
174 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
175 uint16_t const attribute_id, uint32_t const value);
176 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
177 uint16_t const attribute_id, uint16_t const value);
178 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
179 uint16_t const attribute_id, uint8_t const value);
180 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
181 LIBMTP_track_t *track);
182 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent);
183 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
184 char const * const name,
185 char const * const artist,
186 char const * const composer,
187 char const * const genre,
188 uint32_t const parenthandle,
189 uint32_t const storageid,
190 uint16_t const objectformat,
191 char const * const suffix,
192 uint32_t * const newid,
193 uint32_t const * const tracks,
194 uint32_t const no_tracks);
195 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
196 char const * const name,
197 char const * const artist,
198 char const * const composer,
199 char const * const genre,
200 uint32_t const objecthandle,
201 uint16_t const objectformat,
202 uint32_t const * const tracks,
203 uint32_t const no_tracks);
204 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
205 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
206 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
207 static int set_object_filename(LIBMTP_mtpdevice_t *device,
210 const char **newname);
211 static char *generate_unique_filename(PTPParams* params, char const * const filename);
212 static int check_filename_exists(PTPParams* params, char const * const filename);
215 * These are to wrap the get/put handlers to convert from the MTP types to PTP types
218 typedef struct _MTPDataHandler {
219 MTPDataGetFunc getfunc;
220 MTPDataPutFunc putfunc;
224 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
225 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen);
228 * Checks if a filename ends with ".ogg". Used in various
229 * situations when the device has no idea that it support
230 * OGG but still does.
232 * @param name string to be checked.
233 * @return 0 if this does not end with ogg, any other
234 * value means it does.
236 static int has_ogg_extension(char *name) {
241 ptype = strrchr(name,'.');
244 if (!strcasecmp (ptype, ".ogg"))
250 * Checks if a filename ends with ".flac". Used in various
251 * situations when the device has no idea that it support
252 * FLAC but still does.
254 * @param name string to be checked.
255 * @return 0 if this does not end with flac, any other
256 * value means it does.
258 static int has_flac_extension(char *name) {
263 ptype = strrchr(name,'.');
266 if (!strcasecmp (ptype, ".flac"))
274 * Create a new file mapping entry
275 * @return a newly allocated filemapping entry.
277 static filemap_t *new_filemap_entry()
281 filemap = (filemap_t *)malloc(sizeof(filemap_t));
283 if( filemap != NULL ) {
284 filemap->description = NULL;
285 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
286 filemap->ptp_id = PTP_OFC_Undefined;
287 filemap->next = NULL;
294 * Register an MTP or PTP filetype for data retrieval
296 * @param description Text description of filetype
297 * @param id libmtp internal filetype id
298 * @param ptp_id PTP filetype id
299 * @return 0 for success any other value means error.
301 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
302 uint16_t const ptp_id)
304 filemap_t *new = NULL, *current;
306 // Has this LIBMTP filetype been registered before ?
308 while (current != NULL) {
309 if(current->id == id) {
312 current = current->next;
316 if(current == NULL) {
317 new = new_filemap_entry();
323 if(description != NULL) {
324 new->description = strdup(description);
326 new->ptp_id = ptp_id;
328 // Add the entry to the list
329 if(g_filemap == NULL) {
333 while (current->next != NULL ) current=current->next;
336 // Update the existing entry
338 if (current->description != NULL) {
339 free(current->description);
341 current->description = NULL;
342 if(description != NULL) {
343 current->description = strdup(description);
345 current->ptp_id = ptp_id;
351 static void init_filemap()
353 register_filetype("Folder", LIBMTP_FILETYPE_FOLDER, PTP_OFC_Association);
354 register_filetype("MediaCard", LIBMTP_FILETYPE_MEDIACARD, PTP_OFC_MTP_MediaCard);
355 register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);
356 register_filetype("ISO MPEG-1 Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);
357 register_filetype("ISO MPEG-1 Audio Layer 2", LIBMTP_FILETYPE_MP2, PTP_OFC_MTP_MP2);
358 register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);
359 register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
360 register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
361 register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
362 register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
363 register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
364 register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
365 register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
366 register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
367 register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);
368 register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);
369 register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);
370 register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);
371 register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);
372 register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);
373 register_filetype("JP2 file", LIBMTP_FILETYPE_JP2, PTP_OFC_JP2);
374 register_filetype("JPX file", LIBMTP_FILETYPE_JPX, PTP_OFC_JPX);
375 register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);
376 register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);
377 register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);
378 register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);
379 register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);
380 register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);
381 register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);
382 register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);
383 register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);
384 register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);
385 register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);
386 register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);
387 register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);
388 register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);
389 register_filetype("XML file", LIBMTP_FILETYPE_XML, PTP_OFC_MTP_XMLDocument);
390 register_filetype("DOC file", LIBMTP_FILETYPE_DOC, PTP_OFC_MTP_MSWordDocument);
391 register_filetype("XLS file", LIBMTP_FILETYPE_XLS, PTP_OFC_MTP_MSExcelSpreadsheetXLS);
392 register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
393 register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
394 register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
395 register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
396 register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
397 register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
401 * Returns the PTP filetype that maps to a certain libmtp internal file type.
402 * @param intype the MTP library interface type
403 * @return the PTP (libgphoto2) interface type
405 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
411 while (current != NULL) {
412 if(current->id == intype) {
413 return current->ptp_id;
415 current = current->next;
417 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
418 return PTP_OFC_Undefined;
423 * Returns the MTP internal interface type that maps to a certain ptp
425 * @param intype the PTP (libgphoto2) interface type
426 * @return the MTP library interface type
428 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
434 while (current != NULL) {
435 if(current->ptp_id == intype) {
438 current = current->next;
440 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
441 return LIBMTP_FILETYPE_UNKNOWN;
445 * Create a new property mapping entry
446 * @return a newly allocated propertymapping entry.
448 static propertymap_t *new_propertymap_entry()
450 propertymap_t *propertymap;
452 propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
454 if( propertymap != NULL ) {
455 propertymap->description = NULL;
456 propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
457 propertymap->ptp_id = 0;
458 propertymap->next = NULL;
465 * Register an MTP or PTP property for data retrieval
467 * @param description Text description of property
468 * @param id libmtp internal property id
469 * @param ptp_id PTP property id
470 * @return 0 for success any other value means error.
472 static int register_property(char const * const description, LIBMTP_property_t const id,
473 uint16_t const ptp_id)
475 propertymap_t *new = NULL, *current;
477 // Has this LIBMTP propety been registered before ?
478 current = g_propertymap;
479 while (current != NULL) {
480 if(current->id == id) {
483 current = current->next;
487 if(current == NULL) {
488 new = new_propertymap_entry();
494 if(description != NULL) {
495 new->description = strdup(description);
497 new->ptp_id = ptp_id;
499 // Add the entry to the list
500 if(g_propertymap == NULL) {
503 current = g_propertymap;
504 while (current->next != NULL ) current=current->next;
507 // Update the existing entry
509 if (current->description != NULL) {
510 free(current->description);
512 current->description = NULL;
513 if(description != NULL) {
514 current->description = strdup(description);
516 current->ptp_id = ptp_id;
522 static void init_propertymap()
524 register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
525 register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
526 register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
527 register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
528 register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
529 register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
530 register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
531 register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
532 register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
533 register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
534 register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
535 register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
536 register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
537 register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
538 register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
539 register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
540 register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
541 register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
542 register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
543 register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
544 register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
545 register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
546 register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
547 register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
548 register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
549 register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
550 register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
551 register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
552 register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
553 register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
554 register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
555 register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
556 register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
557 register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
558 register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
559 register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
560 register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
561 register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
562 register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
563 register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
564 register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
565 register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
566 register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
567 register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
568 register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
569 register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
570 register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
571 register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
572 register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
573 register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
574 register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
575 register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
576 register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
577 register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
578 register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
579 register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
580 register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
581 register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
582 register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
583 register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
584 register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
585 register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
586 register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
587 register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
588 register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
589 register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
590 register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
591 register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
592 register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
593 register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
594 register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
595 register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
596 register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
597 register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
598 register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
599 register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
600 register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
601 register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
602 register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
603 register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
604 register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
605 register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
606 register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
607 register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
608 register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
609 register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
610 register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
611 register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
612 register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
613 register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
614 register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
615 register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
616 register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
617 register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
618 register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
619 register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
620 register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
621 register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
622 register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
623 register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
624 register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
625 register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
626 register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
627 register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
628 register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
629 register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
630 register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
631 register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
632 register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
633 register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
634 register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
635 register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
636 register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
637 register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
638 register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
639 register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
640 register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
641 register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
642 register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
643 register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
644 register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
645 register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
646 register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
647 register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
648 register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
649 register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
650 register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
651 register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
652 register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
653 register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
654 register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
655 register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
656 register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
657 register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
658 register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
659 register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
660 register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
661 register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
662 register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
663 register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
664 register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
665 register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
666 register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
667 register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
668 register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
669 register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
670 register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
671 register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
672 register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
673 register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
674 register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
675 register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
676 register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
677 register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
678 register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
679 register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
680 register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
681 register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
682 register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
683 register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
684 register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
685 register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
686 register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
687 register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
688 register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
689 register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
690 register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
691 register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
695 * Returns the PTP property that maps to a certain libmtp internal property type.
696 * @param inproperty the MTP library interface property
697 * @return the PTP (libgphoto2) property type
699 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
701 propertymap_t *current;
703 current = g_propertymap;
705 while (current != NULL) {
706 if(current->id == inproperty) {
707 return current->ptp_id;
709 current = current->next;
716 * Returns the MTP internal interface property that maps to a certain ptp
717 * interface property.
718 * @param inproperty the PTP (libgphoto2) interface property
719 * @return the MTP library interface property
721 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
723 propertymap_t *current;
725 current = g_propertymap;
727 while (current != NULL) {
728 if(current->ptp_id == inproperty) {
731 current = current->next;
733 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
734 return LIBMTP_PROPERTY_UNKNOWN;
739 * Set the debug level.
741 * By default, the debug level is set to '0' (disable).
743 void LIBMTP_Set_Debug(int level)
745 if (LIBMTP_debug || level)
746 LIBMTP_ERROR("LIBMTP_Set_Debug: Setting debugging level to %d (0x%02x) "
747 "(%s)\n", level, level, level ? "on" : "off");
749 LIBMTP_debug = level;
754 * Initialize the library. You are only supposed to call this
755 * one, before using the library for the first time in a program.
756 * Never re-initialize libmtp!
758 * The only thing this does at the moment is to initialise the
759 * filetype mapping table, as well as load MTPZ data if necessary.
761 void LIBMTP_Init(void)
763 const char *env_debug = getenv("LIBMTP_DEBUG");
765 const long debug_flags = strtol(env_debug, NULL, 0);
766 if (debug_flags != LONG_MIN && debug_flags != LONG_MAX &&
767 INT_MIN <= debug_flags && debug_flags <= INT_MAX) {
768 LIBMTP_Set_Debug(debug_flags);
770 fprintf(stderr, "LIBMTP_Init: error setting debug flags from environment "
771 "value \"%s\"\n", env_debug);
778 if (mtpz_loaddata() == -1)
788 * This helper function returns a textual description for a libmtp
789 * file type to be used in dialog boxes etc.
790 * @param intype the libmtp internal filetype to get a description for.
791 * @return a string representing the filetype, this must <b>NOT</b>
792 * be free():ed by the caller!
794 char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
800 while (current != NULL) {
801 if(current->id == intype) {
802 return current->description;
804 current = current->next;
807 return "Unknown filetype";
811 * This helper function returns a textual description for a libmtp
812 * property to be used in dialog boxes etc.
813 * @param inproperty the libmtp internal property to get a description for.
814 * @return a string representing the filetype, this must <b>NOT</b>
815 * be free():ed by the caller!
817 char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
819 propertymap_t *current;
821 current = g_propertymap;
823 while (current != NULL) {
824 if(current->id == inproperty) {
825 return current->description;
827 current = current->next;
830 return "Unknown property";
834 * This function will do its best to fit a 16bit
835 * value into a PTP object property if the property
836 * is limited in range or step sizes.
838 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd)
840 switch (opd->FormFlag) {
842 if (val < opd->FORM.Range.MinimumValue.u16) {
843 return opd->FORM.Range.MinimumValue.u16;
845 if (val > opd->FORM.Range.MaximumValue.u16) {
846 return opd->FORM.Range.MaximumValue.u16;
848 // Round down to last step.
849 if (val % opd->FORM.Range.StepSize.u16 != 0) {
850 return val - (val % opd->FORM.Range.StepSize.u16);
854 case PTP_DPFF_Enumeration:
857 uint16_t bestfit = opd->FORM.Enum.SupportedValue[0].u16;
859 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
860 if (val == opd->FORM.Enum.SupportedValue[i].u16) {
863 // Rough guess of best fit
864 if (opd->FORM.Enum.SupportedValue[i].u16 < val) {
865 bestfit = opd->FORM.Enum.SupportedValue[i].u16;
868 // Just some default that'll work.
872 // Will accept any value
879 * This function will do its best to fit a 32bit
880 * value into a PTP object property if the property
881 * is limited in range or step sizes.
883 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd)
885 switch (opd->FormFlag) {
887 if (val < opd->FORM.Range.MinimumValue.u32) {
888 return opd->FORM.Range.MinimumValue.u32;
890 if (val > opd->FORM.Range.MaximumValue.u32) {
891 return opd->FORM.Range.MaximumValue.u32;
893 // Round down to last step.
894 if (val % opd->FORM.Range.StepSize.u32 != 0) {
895 return val - (val % opd->FORM.Range.StepSize.u32);
899 case PTP_DPFF_Enumeration:
902 uint32_t bestfit = opd->FORM.Enum.SupportedValue[0].u32;
904 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
905 if (val == opd->FORM.Enum.SupportedValue[i].u32) {
908 // Rough guess of best fit
909 if (opd->FORM.Enum.SupportedValue[i].u32 < val) {
910 bestfit = opd->FORM.Enum.SupportedValue[i].u32;
913 // Just some default that'll work.
917 // Will accept any value
924 * This function returns a newly created ISO 8601 timestamp with the
925 * current time in as high precision as possible. It even adds
926 * the time zone if it can.
928 static char *get_iso8601_stamp(void)
934 curtime = time(NULL);
935 loctime = localtime(&curtime);
936 strftime (tmp, sizeof(tmp), "%Y%m%dT%H%M%S.0%z", loctime);
941 * Gets the allowed values (range or enum) for a property
942 * @param device a pointer to an MTP device
943 * @param property the property to query
944 * @param filetype the filetype of the object you want to set values for
945 * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
946 * receive the allowed values. Call LIBMTP_destroy_allowed_values_t
947 * on this on successful completion.
948 * @return 0 on success, any other value means failure
950 int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
951 LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
953 PTPObjectPropDesc opd;
956 ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
957 if (ret != PTP_RC_OK) {
958 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
962 if (opd.FormFlag == PTP_OPFF_Enumeration) {
965 allowed_vals->is_range = 0;
966 allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
968 switch (opd.DataType)
971 allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
972 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
975 allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
976 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
979 allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
980 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
983 allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
984 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
987 allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
988 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
991 allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
992 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
995 allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
996 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
999 allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
1000 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1004 for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
1005 switch (opd.DataType)
1008 allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
1011 allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
1014 allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
1016 case PTP_DTC_UINT16:
1017 allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
1020 allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
1022 case PTP_DTC_UINT32:
1023 allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
1026 allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
1028 case PTP_DTC_UINT64:
1029 allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
1033 ptp_free_objectpropdesc(&opd);
1035 } else if (opd.FormFlag == PTP_OPFF_Range) {
1036 allowed_vals->is_range = 1;
1038 switch (opd.DataType)
1041 allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
1042 allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
1043 allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
1044 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
1047 allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
1048 allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
1049 allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
1050 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
1053 allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
1054 allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
1055 allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
1056 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
1058 case PTP_DTC_UINT16:
1059 allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
1060 allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
1061 allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
1062 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
1065 allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
1066 allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
1067 allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
1068 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1070 case PTP_DTC_UINT32:
1071 allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
1072 allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
1073 allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
1074 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1077 allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
1078 allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
1079 allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
1080 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1082 case PTP_DTC_UINT64:
1083 allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
1084 allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
1085 allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
1086 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1095 * Destroys a LIBMTP_allowed_values_t struct
1096 * @param allowed_vals the struct to destroy
1098 void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
1100 if (!allowed_vals->is_range)
1102 switch (allowed_vals->datatype)
1104 case LIBMTP_DATATYPE_INT8:
1105 if (allowed_vals->i8vals)
1106 free(allowed_vals->i8vals);
1108 case LIBMTP_DATATYPE_UINT8:
1109 if (allowed_vals->u8vals)
1110 free(allowed_vals->u8vals);
1112 case LIBMTP_DATATYPE_INT16:
1113 if (allowed_vals->i16vals)
1114 free(allowed_vals->i16vals);
1116 case LIBMTP_DATATYPE_UINT16:
1117 if (allowed_vals->u16vals)
1118 free(allowed_vals->u16vals);
1120 case LIBMTP_DATATYPE_INT32:
1121 if (allowed_vals->i32vals)
1122 free(allowed_vals->i32vals);
1124 case LIBMTP_DATATYPE_UINT32:
1125 if (allowed_vals->u32vals)
1126 free(allowed_vals->u32vals);
1128 case LIBMTP_DATATYPE_INT64:
1129 if (allowed_vals->i64vals)
1130 free(allowed_vals->i64vals);
1132 case LIBMTP_DATATYPE_UINT64:
1133 if (allowed_vals->u64vals)
1134 free(allowed_vals->u64vals);
1141 * Determine if a property is supported for a given file type
1142 * @param device a pointer to an MTP device
1143 * @param property the property to query
1144 * @param filetype the filetype of the object you want to set values for
1145 * @return 0 if not supported, positive if supported, negative on error
1147 int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
1148 LIBMTP_filetype_t const filetype)
1150 uint16_t *props = NULL;
1151 uint32_t propcnt = 0;
1155 uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
1157 if (!ptp_operation_issupported(device->params, PTP_OC_MTP_GetObjectPropsSupported))
1160 ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
1161 if (ret != PTP_RC_OK) {
1162 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
1166 for (i = 0; i < propcnt; i++) {
1167 if (props[i] == ptp_prop) {
1179 * Retrieves a string from an object
1181 * @param device a pointer to an MTP device.
1182 * @param object_id Object reference
1183 * @param attribute_id MTP attribute ID
1184 * @return valid string or NULL on failure. The returned string
1185 * must bee <code>free()</code>:ed by the caller after
1188 char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1189 LIBMTP_property_t const attribute_id)
1191 return get_string_from_object(device, object_id, attribute_id);
1195 * Retrieves an unsigned 64-bit integer from an object attribute
1197 * @param device a pointer to an MTP device.
1198 * @param object_id Object reference
1199 * @param attribute_id MTP attribute ID
1200 * @param value_default Default value to return on failure
1203 uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1204 LIBMTP_property_t const attribute_id, uint64_t const value_default)
1206 return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1210 * Retrieves an unsigned 32-bit integer from an object attribute
1212 * @param device a pointer to an MTP device.
1213 * @param object_id Object reference
1214 * @param attribute_id MTP attribute ID
1215 * @param value_default Default value to return on failure
1218 uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1219 LIBMTP_property_t const attribute_id, uint32_t const value_default)
1221 return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1225 * Retrieves an unsigned 16-bit integer from an object attribute
1227 * @param device a pointer to an MTP device.
1228 * @param object_id Object reference
1229 * @param attribute_id MTP attribute ID
1230 * @param value_default Default value to return on failure
1233 uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1234 LIBMTP_property_t const attribute_id, uint16_t const value_default)
1236 return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1240 * Retrieves an unsigned 8-bit integer from an object attribute
1242 * @param device a pointer to an MTP device.
1243 * @param object_id Object reference
1244 * @param attribute_id MTP attribute ID
1245 * @param value_default Default value to return on failure
1248 uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1249 LIBMTP_property_t const attribute_id, uint8_t const value_default)
1251 return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1255 * Sets an object attribute from a string
1257 * @param device a pointer to an MTP device.
1258 * @param object_id Object reference
1259 * @param attribute_id MTP attribute ID
1260 * @param string string value to set
1261 * @return 0 on success, any other value means failure
1263 int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1264 LIBMTP_property_t const attribute_id, char const * const string)
1266 return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
1271 * Sets an object attribute from an unsigned 32-bit integer
1273 * @param device a pointer to an MTP device.
1274 * @param object_id Object reference
1275 * @param attribute_id MTP attribute ID
1276 * @param value 32-bit unsigned integer to set
1277 * @return 0 on success, any other value means failure
1279 int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1280 LIBMTP_property_t const attribute_id, uint32_t const value)
1282 return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1286 * Sets an object attribute from an unsigned 16-bit integer
1288 * @param device a pointer to an MTP device.
1289 * @param object_id Object reference
1290 * @param attribute_id MTP attribute ID
1291 * @param value 16-bit unsigned integer to set
1292 * @return 0 on success, any other value means failure
1294 int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1295 LIBMTP_property_t const attribute_id, uint16_t const value)
1297 return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1301 * Sets an object attribute from an unsigned 8-bit integer
1303 * @param device a pointer to an MTP device.
1304 * @param object_id Object reference
1305 * @param attribute_id MTP attribute ID
1306 * @param value 8-bit unsigned integer to set
1307 * @return 0 on success, any other value means failure
1309 int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1310 LIBMTP_property_t const attribute_id, uint8_t const value)
1312 return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1316 * Retrieves a string from an object
1318 * @param device a pointer to an MTP device.
1319 * @param object_id Object reference
1320 * @param attribute_id PTP attribute ID
1321 * @return valid string or NULL on failure. The returned string
1322 * must bee <code>free()</code>:ed by the caller after
1325 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1326 uint16_t const attribute_id)
1328 PTPPropertyValue propval;
1329 char *retstring = NULL;
1332 MTPProperties *prop;
1334 if (!device || !object_id)
1337 params = (PTPParams *) device->params;
1339 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1341 if (prop->propval.str != NULL)
1342 return strdup(prop->propval.str);
1347 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1348 if (ret == PTP_RC_OK) {
1349 if (propval.str != NULL) {
1350 retstring = (char *) strdup(propval.str);
1354 add_ptp_error_to_errorstack(device, ret, "get_string_from_object(): could not get object string.");
1361 * Retrieves an unsigned 64-bit integer from an object attribute
1363 * @param device a pointer to an MTP device.
1364 * @param object_id Object reference
1365 * @param attribute_id PTP attribute ID
1366 * @param value_default Default value to return on failure
1369 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1370 uint16_t const attribute_id, uint64_t const value_default)
1372 PTPPropertyValue propval;
1373 uint64_t retval = value_default;
1376 MTPProperties *prop;
1379 return value_default;
1381 params = (PTPParams *) device->params;
1383 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1385 return prop->propval.u64;
1387 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1391 if (ret == PTP_RC_OK) {
1392 retval = propval.u64;
1394 add_ptp_error_to_errorstack(device, ret, "get_u64_from_object(): could not get unsigned 64bit integer from object.");
1401 * Retrieves an unsigned 32-bit integer from an object attribute
1403 * @param device a pointer to an MTP device.
1404 * @param object_id Object reference
1405 * @param attribute_id PTP attribute ID
1406 * @param value_default Default value to return on failure
1409 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1410 uint16_t const attribute_id, uint32_t const value_default)
1412 PTPPropertyValue propval;
1413 uint32_t retval = value_default;
1416 MTPProperties *prop;
1419 return value_default;
1421 params = (PTPParams *) device->params;
1423 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1425 return prop->propval.u32;
1427 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1431 if (ret == PTP_RC_OK) {
1432 retval = propval.u32;
1434 add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
1440 * Retrieves an unsigned 16-bit integer from an object attribute
1442 * @param device a pointer to an MTP device.
1443 * @param object_id Object reference
1444 * @param attribute_id PTP attribute ID
1445 * @param value_default Default value to return on failure
1448 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1449 uint16_t const attribute_id, uint16_t const value_default)
1451 PTPPropertyValue propval;
1452 uint16_t retval = value_default;
1455 MTPProperties *prop;
1458 return value_default;
1460 params = (PTPParams *) device->params;
1462 // This O(n) search should not be used so often, since code
1463 // using the cached properties don't usually call this function.
1464 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1466 return prop->propval.u16;
1468 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1472 if (ret == PTP_RC_OK) {
1473 retval = propval.u16;
1475 add_ptp_error_to_errorstack(device, ret, "get_u16_from_object(): could not get unsigned 16bit integer from object.");
1482 * Retrieves an unsigned 8-bit integer from an object attribute
1484 * @param device a pointer to an MTP device.
1485 * @param object_id Object reference
1486 * @param attribute_id PTP attribute ID
1487 * @param value_default Default value to return on failure
1490 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1491 uint16_t const attribute_id, uint8_t const value_default)
1493 PTPPropertyValue propval;
1494 uint8_t retval = value_default;
1497 MTPProperties *prop;
1500 return value_default;
1502 params = (PTPParams *) device->params;
1504 // This O(n) search should not be used so often, since code
1505 // using the cached properties don't usually call this function.
1506 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1508 return prop->propval.u8;
1510 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1514 if (ret == PTP_RC_OK) {
1515 retval = propval.u8;
1517 add_ptp_error_to_errorstack(device, ret, "get_u8_from_object(): could not get unsigned 8bit integer from object.");
1524 * Sets an object attribute from a string
1526 * @param device a pointer to an MTP device.
1527 * @param object_id Object reference
1528 * @param attribute_id PTP attribute ID
1529 * @param string string value to set
1530 * @return 0 on success, any other value means failure
1532 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1533 uint16_t const attribute_id, char const * const string)
1535 PTPPropertyValue propval;
1539 if (!device || !string)
1542 params = (PTPParams *) device->params;
1544 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1545 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_string(): could not set object string: "
1546 "PTP_OC_MTP_SetObjectPropValue not supported.");
1549 propval.str = (char *) string;
1550 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1551 if (ret != PTP_RC_OK) {
1552 add_ptp_error_to_errorstack(device, ret, "set_object_string(): could not set object string.");
1561 * Sets an object attribute from an unsigned 32-bit integer
1563 * @param device a pointer to an MTP device.
1564 * @param object_id Object reference
1565 * @param attribute_id PTP attribute ID
1566 * @param value 32-bit unsigned integer to set
1567 * @return 0 on success, any other value means failure
1569 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1570 uint16_t const attribute_id, uint32_t const value)
1572 PTPPropertyValue propval;
1579 params = (PTPParams *) device->params;
1581 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1582 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u32(): could not set unsigned 32bit integer property: "
1583 "PTP_OC_MTP_SetObjectPropValue not supported.");
1587 propval.u32 = value;
1588 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
1589 if (ret != PTP_RC_OK) {
1590 add_ptp_error_to_errorstack(device, ret, "set_object_u32(): could not set unsigned 32bit integer property.");
1598 * Sets an object attribute from an unsigned 16-bit integer
1600 * @param device a pointer to an MTP device.
1601 * @param object_id Object reference
1602 * @param attribute_id PTP attribute ID
1603 * @param value 16-bit unsigned integer to set
1604 * @return 0 on success, any other value means failure
1606 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1607 uint16_t const attribute_id, uint16_t const value)
1609 PTPPropertyValue propval;
1616 params = (PTPParams *) device->params;
1618 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1619 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u16(): could not set unsigned 16bit integer property: "
1620 "PTP_OC_MTP_SetObjectPropValue not supported.");
1623 propval.u16 = value;
1624 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
1625 if (ret != PTP_RC_OK) {
1626 add_ptp_error_to_errorstack(device, ret, "set_object_u16(): could not set unsigned 16bit integer property.");
1634 * Sets an object attribute from an unsigned 8-bit integer
1636 * @param device a pointer to an MTP device.
1637 * @param object_id Object reference
1638 * @param attribute_id PTP attribute ID
1639 * @param value 8-bit unsigned integer to set
1640 * @return 0 on success, any other value means failure
1642 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1643 uint16_t const attribute_id, uint8_t const value)
1645 PTPPropertyValue propval;
1652 params = (PTPParams *) device->params;
1654 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1655 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u8(): could not set unsigned 8bit integer property: "
1656 "PTP_OC_MTP_SetObjectPropValue not supported.");
1660 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
1661 if (ret != PTP_RC_OK) {
1662 add_ptp_error_to_errorstack(device, ret, "set_object_u8(): could not set unsigned 8bit integer property.");
1670 * Get the first (as in "first in the list of") connected MTP device.
1671 * @return a device pointer.
1672 * @see LIBMTP_Get_Connected_Devices()
1674 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1676 LIBMTP_mtpdevice_t *first_device = NULL;
1677 LIBMTP_raw_device_t *devices;
1679 LIBMTP_error_number_t ret;
1681 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1682 if (ret != LIBMTP_ERROR_NONE) {
1686 if (devices == NULL || numdevs == 0) {
1691 first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1693 return first_device;
1697 * Overriding debug function.
1698 * This way we can disable debug prints.
1702 __attribute__((__format__(printf,2,0)))
1704 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1706 if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1707 vfprintf (stderr, format, args);
1708 fprintf (stderr, "\n");
1714 * Overriding error function.
1715 * This way we can capture all error etc to our errorstack.
1719 __attribute__((__format__(printf,2,0)))
1721 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1723 // if (data == NULL) {
1724 vfprintf (stderr, format, args);
1727 FIXME: find out how we shall get the device here.
1729 PTP_USB *ptp_usb = data;
1730 LIBMTP_mtpdevice_t *device = ...;
1733 vsnprintf (buf, sizeof (buf), format, args);
1734 add_error_to_errorstack(device,
1735 LIBMTP_ERROR_PTP_LAYER,
1742 * Parses the extension descriptor, there may be stuff in
1743 * this that we want to know about.
1745 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1751 /* NULL on Canon A70 */
1755 /* descriptors are divided by semicolons */
1756 while (end < strlen(desc)) {
1757 /* Skip past initial whitespace */
1758 while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1762 /* Detect extension */
1763 while ((end < strlen(desc)) && (desc[end] != ';'))
1765 if (end < strlen(desc)) {
1766 char *element = strndup(desc + start, end-start);
1769 // printf(" Element: \"%s\"\n", element);
1771 /* Parse for an extension */
1772 while ((i < strlen(element)) && (element[i] != ':'))
1774 if (i < strlen(element)) {
1775 char *name = strndup(element, i);
1777 // printf(" Extension: \"%s\"\n", name);
1779 /* Parse for minor/major punctuation mark for this extension */
1780 while ((i < strlen(element)) && (element[i] != '.'))
1782 if (i > majstart && i < strlen(element)) {
1783 LIBMTP_device_extension_t *extension;
1786 char *majorstr = strndup(element + majstart, i - majstart);
1787 char *minorstr = strndup(element + i + 1, strlen(element) - i - 1);
1788 major = atoi(majorstr);
1789 minor = atoi(minorstr);
1790 // printf(" Major: \"%s\" (parsed %d) Minor: \"%s\" (parsed %d)\n",
1791 // majorstr, major, minorstr, minor);
1794 extension = malloc(sizeof(LIBMTP_device_extension_t));
1795 extension->name = name;
1796 extension->major = major;
1797 extension->minor = minor;
1798 extension->next = NULL;
1799 if (mtpdevice->extensions == NULL) {
1800 mtpdevice->extensions = extension;
1802 LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1803 while (tmp->next != NULL)
1805 tmp->next = extension;
1808 LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1821 * This function opens a device from a raw device. It is the
1822 * preferred way to access devices in the new interface where
1823 * several devices can come and go as the library is working
1824 * on a certain device.
1825 * @param rawdevice the raw device to open a "real" device for.
1826 * @return an open device.
1828 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1830 LIBMTP_mtpdevice_t *mtp_device;
1832 PTPParams *current_params;
1834 LIBMTP_error_number_t err;
1837 /* Allocate dynamic space for our device */
1838 mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1839 /* Check if there was a memory allocation error */
1840 if(mtp_device == NULL) {
1841 /* There has been an memory allocation error. We are going to ignore this
1842 device and attempt to continue */
1844 /* TODO: This error statement could probably be a bit more robust */
1845 LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1846 "allocation error with device %d on bus %d, trying to continue",
1847 rawdevice->devnum, rawdevice->bus_location);
1851 memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1852 // Non-cached by default
1853 mtp_device->cached = 0;
1855 /* Create PTP params */
1856 current_params = (PTPParams *) malloc(sizeof(PTPParams));
1857 if (current_params == NULL) {
1861 memset(current_params, 0, sizeof(PTPParams));
1862 current_params->device_flags = rawdevice->device_entry.device_flags;
1863 current_params->nrofobjects = 0;
1864 current_params->objects = NULL;
1865 current_params->response_packet_size = 0;
1866 current_params->response_packet = NULL;
1867 /* This will be a pointer to PTP_USB later */
1868 current_params->data = NULL;
1869 /* Set upp local debug and error functions */
1870 current_params->debug_func = LIBMTP_ptp_debug;
1871 current_params->error_func = LIBMTP_ptp_error;
1872 /* TODO: Will this always be little endian? */
1873 current_params->byteorder = PTP_DL_LE;
1874 current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1875 current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1877 if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1878 current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1879 LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1880 "Too old stdlibc, glibc and libiconv?\n");
1881 free(current_params);
1885 mtp_device->params = current_params;
1887 /* Create usbinfo, this also opens the session */
1888 err = configure_usb_device(rawdevice,
1890 &mtp_device->usbinfo);
1891 if (err != LIBMTP_ERROR_NONE) {
1892 free(current_params);
1896 ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1897 /* Set pointer back to params */
1898 ptp_usb->params = current_params;
1900 /* Cache the device information for later use */
1901 if (ptp_getdeviceinfo(current_params,
1902 ¤t_params->deviceinfo) != PTP_RC_OK) {
1903 LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1904 "%d on bus %d, trying to continue",
1905 rawdevice->devnum, rawdevice->bus_location);
1907 /* Prevent memory leaks for this device */
1908 free(mtp_device->usbinfo);
1909 free(mtp_device->params);
1910 current_params = NULL;
1915 /* Check: if this is a PTP device, is it really tagged as MTP? */
1916 if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1917 LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1919 rawdevice->devnum, rawdevice->bus_location);
1920 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1921 current_params->deviceinfo.VendorExtensionID);
1922 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1923 current_params->deviceinfo.VendorExtensionDesc);
1924 LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1925 "(i.e. a camera) but not an MTP device at all. "
1926 "Trying to continue anyway.");
1929 parse_extension_descriptor(mtp_device,
1930 current_params->deviceinfo.VendorExtensionDesc);
1933 * Android has a number of bugs, force-assign these bug flags
1934 * if Android is encountered. Same thing for devices we detect
1935 * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1936 * I just know only NWZs have it.
1939 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1940 int is_microsoft_com_wpdna = 0;
1942 int is_sony_net_wmfu = 0;
1943 int is_sonyericsson_com_se = 0;
1945 /* Loop over extensions and set flags */
1946 while (tmpext != NULL) {
1947 if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1948 is_microsoft_com_wpdna = 1;
1949 if (!strcmp(tmpext->name, "android.com"))
1951 if (!strcmp(tmpext->name, "sony.net/WMFU"))
1952 is_sony_net_wmfu = 1;
1953 if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1954 is_sonyericsson_com_se = 1;
1955 tmpext = tmpext->next;
1958 /* Check for specific stacks */
1959 if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1961 * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1962 * extension and NO Android extension.
1964 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1965 LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1967 else if (is_android) {
1969 * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1971 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1972 LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1974 else if (is_sony_net_wmfu) {
1975 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1976 LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
1981 * If the OGG or FLAC filetypes are flagged as "unknown", check
1982 * if the firmware has been updated to actually support it.
1984 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
1985 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1986 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_OGG) {
1987 /* This is not unknown anymore, unflag it */
1988 ptp_usb->rawdevice.device_entry.device_flags &=
1989 ~DEVICE_FLAG_OGG_IS_UNKNOWN;
1994 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
1995 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1996 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
1997 /* This is not unknown anymore, unflag it */
1998 ptp_usb->rawdevice.device_entry.device_flags &=
1999 ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2005 /* Determine if the object size supported is 32 or 64 bit wide */
2006 if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2007 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2008 PTPObjectPropDesc opd;
2010 if (ptp_mtp_getobjectpropdesc(current_params,
2012 current_params->deviceinfo.ImageFormats[i],
2013 &opd) != PTP_RC_OK) {
2014 LIBMTP_ERROR("LIBMTP PANIC: "
2015 "could not inspect object property descriptions!\n");
2017 if (opd.DataType == PTP_DTC_UINT32) {
2020 } else if (bs != 32) {
2021 LIBMTP_ERROR("LIBMTP PANIC: "
2022 "different objects support different object sizes!\n");
2026 } else if (opd.DataType == PTP_DTC_UINT64) {
2029 } else if (bs != 64) {
2030 LIBMTP_ERROR("LIBMTP PANIC: "
2031 "different objects support different object sizes!\n");
2036 // Ignore if other size.
2037 LIBMTP_ERROR("LIBMTP PANIC: "
2038 "awkward object size data type: %04x\n", opd.DataType);
2046 // Could not detect object bitsize, assume 32 bits
2049 mtp_device->object_bitsize = bs;
2051 /* No Errors yet for this device */
2052 mtp_device->errorstack = NULL;
2054 /* Default Max Battery Level, we will adjust this if possible */
2055 mtp_device->maximum_battery_level = 100;
2057 /* Check if device supports reading maximum battery level */
2058 if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2059 ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2060 PTPDevicePropDesc dpd;
2062 /* Try to read maximum battery level */
2063 if(ptp_getdevicepropdesc(current_params,
2064 PTP_DPC_BatteryLevel,
2065 &dpd) != PTP_RC_OK) {
2066 add_error_to_errorstack(mtp_device,
2067 LIBMTP_ERROR_CONNECTING,
2068 "Unable to read Maximum Battery Level for this "
2069 "device even though the device supposedly "
2070 "supports this functionality");
2073 /* TODO: is this appropriate? */
2074 /* If max battery level is 0 then leave the default, otherwise assign */
2075 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2076 mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2079 ptp_free_devicepropdesc(&dpd);
2082 /* Set all default folders to 0xffffffffU (root directory) */
2083 mtp_device->default_music_folder = 0xffffffffU;
2084 mtp_device->default_playlist_folder = 0xffffffffU;
2085 mtp_device->default_picture_folder = 0xffffffffU;
2086 mtp_device->default_video_folder = 0xffffffffU;
2087 mtp_device->default_organizer_folder = 0xffffffffU;
2088 mtp_device->default_zencast_folder = 0xffffffffU;
2089 mtp_device->default_album_folder = 0xffffffffU;
2090 mtp_device->default_text_folder = 0xffffffffU;
2092 /* Set initial storage information */
2093 mtp_device->storage = NULL;
2094 if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2095 add_error_to_errorstack(mtp_device,
2096 LIBMTP_ERROR_GENERAL,
2097 "Get Storage information failed.");
2098 mtp_device->storage = NULL;
2105 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2107 LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2109 if (mtp_device == NULL)
2112 /* Check for MTPZ devices. */
2114 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2116 while (tmpext != NULL) {
2117 if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2118 LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2119 if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2120 LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2122 LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2126 tmpext = tmpext->next;
2130 // Set up this device as cached
2131 mtp_device->cached = 1;
2133 * Then get the handles and try to locate the default folders.
2134 * This has the desired side effect of caching all handles from
2135 * the device which speeds up later operations.
2137 flush_handles(mtp_device);
2142 * To read events sent by the device, repeatedly call this function from a secondary
2143 * thread until the return value is < 0.
2145 * @param device a pointer to the MTP device to poll for events.
2146 * @param event contains a pointer to be filled in with the event retrieved if the call
2148 * @param out1 contains the param1 value from the raw event.
2149 * @return 0 on success, any other value means the polling loop shall be
2150 * terminated immediately for this session.
2152 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2155 * FIXME: Potential race-condition here, if client deallocs device
2156 * while we're *not* waiting for input. As we'll be waiting for
2157 * input most of the time, it's unlikely but still worth considering
2158 * for improvement. Also we cannot affect the state of the cache etc
2159 * unless we know we are the sole user on the device. A spinlock or
2160 * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2162 PTPParams *params = (PTPParams *) device->params;
2163 PTPContainer ptp_event;
2164 uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2166 uint32_t session_id;
2169 if (ret != PTP_RC_OK) {
2170 /* Device is closing down or other fatal stuff, exit thread */
2174 *event = LIBMTP_EVENT_NONE;
2176 /* Process the event */
2177 code = ptp_event.Code;
2178 session_id = ptp_event.SessionID;
2179 param1 = ptp_event.Param1;
2182 case PTP_EC_Undefined:
2183 LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2185 case PTP_EC_CancelTransaction:
2186 LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2188 case PTP_EC_ObjectAdded:
2189 LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2190 *event = LIBMTP_EVENT_OBJECT_ADDED;
2193 case PTP_EC_ObjectRemoved:
2194 LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2195 *event = LIBMTP_EVENT_OBJECT_REMOVED;
2198 case PTP_EC_StoreAdded:
2199 LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2200 /* TODO: rescan storages */
2201 *event = LIBMTP_EVENT_STORE_ADDED;
2204 case PTP_EC_StoreRemoved:
2205 LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2206 /* TODO: rescan storages */
2207 *event = LIBMTP_EVENT_STORE_REMOVED;
2210 case PTP_EC_DevicePropChanged:
2211 LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2212 /* TODO: update device properties */
2214 case PTP_EC_ObjectInfoChanged:
2215 LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2216 /* TODO: rescan object cache or just for this one object */
2218 case PTP_EC_DeviceInfoChanged:
2219 LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2220 /* TODO: update device info */
2222 case PTP_EC_RequestObjectTransfer:
2223 LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2225 case PTP_EC_StoreFull:
2226 LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2228 case PTP_EC_DeviceReset:
2229 LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2231 case PTP_EC_StorageInfoChanged :
2232 LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2233 /* TODO: update storage info */
2235 case PTP_EC_CaptureComplete :
2236 LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2238 case PTP_EC_UnreportedStatus :
2239 LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2242 LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2250 * Recursive function that adds MTP devices to a linked list
2251 * @param devices a list of raw devices to have real devices created for.
2252 * @return a device pointer to a newly created mtpdevice (used in linked
2255 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2258 LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2259 LIBMTP_mtpdevice_t *current_device = NULL;
2261 for (i=0; i < numdevs; i++) {
2262 LIBMTP_mtpdevice_t *mtp_device;
2263 mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2265 /* On error, try next device */
2266 if (mtp_device == NULL)
2269 /* Add the device to the list */
2270 mtp_device->next = NULL;
2271 if (mtp_device_list == NULL) {
2272 mtp_device_list = current_device = mtp_device;
2274 current_device->next = mtp_device;
2275 current_device = mtp_device;
2278 return mtp_device_list;
2282 * Get the number of devices that are available in the listed device list
2283 * @param device_list Pointer to a linked list of devices
2284 * @return Number of devices in the device list device_list
2285 * @see LIBMTP_Get_Connected_Devices()
2287 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2289 uint32_t numdevices = 0;
2290 LIBMTP_mtpdevice_t *iter;
2291 for(iter = device_list; iter != NULL; iter = iter->next)
2298 * Get the first connected MTP device node in the linked list of devices.
2299 * Currently this only provides access to USB devices
2300 * @param device_list A list of devices ready to be used by the caller. You
2301 * need to know how many there are.
2302 * @return Any error information gathered from device connections
2303 * @see LIBMTP_Number_Devices_In_List()
2305 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2307 LIBMTP_raw_device_t *devices;
2309 LIBMTP_error_number_t ret;
2311 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2312 if (ret != LIBMTP_ERROR_NONE) {
2313 *device_list = NULL;
2317 /* Assign linked list of devices */
2318 if (devices == NULL || numdevs == 0) {
2319 *device_list = NULL;
2321 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2324 *device_list = create_usb_mtp_devices(devices, numdevs);
2327 /* TODO: Add wifi device access here */
2329 /* We have found some devices but create failed */
2330 if (*device_list == NULL)
2331 return LIBMTP_ERROR_CONNECTING;
2333 return LIBMTP_ERROR_NONE;
2337 * This closes and releases an allocated MTP device.
2338 * @param device a pointer to the MTP device to release.
2340 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2344 if(device->next != NULL)
2346 LIBMTP_Release_Device_List(device->next);
2349 LIBMTP_Release_Device(device);
2354 * This closes and releases an allocated MTP device.
2355 * @param device a pointer to the MTP device to release.
2357 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2359 PTPParams *params = (PTPParams *) device->params;
2360 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2362 close_device(ptp_usb, params);
2363 // Clear error stack
2364 LIBMTP_Clear_Errorstack(device);
2365 // Free iconv() converters...
2366 iconv_close(params->cd_locale_to_ucs2);
2367 iconv_close(params->cd_ucs2_to_locale);
2369 ptp_free_params(params);
2371 free_storage_list(device);
2372 // Free extension list...
2373 if (device->extensions != NULL) {
2374 LIBMTP_device_extension_t *tmp = device->extensions;
2376 while (tmp != NULL) {
2377 LIBMTP_device_extension_t *next = tmp->next;
2389 * This can be used by any libmtp-intrinsic code that
2390 * need to stack up an error on the stack. You are only
2391 * supposed to add errors to the error stack using this
2392 * function, do not create and reference error entries
2395 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2396 LIBMTP_error_number_t errornumber,
2397 char const * const error_text)
2399 LIBMTP_error_t *newerror;
2401 if (device == NULL) {
2402 LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2405 newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2406 newerror->errornumber = errornumber;
2407 newerror->error_text = strdup(error_text);
2408 newerror->next = NULL;
2409 if (device->errorstack == NULL) {
2410 device->errorstack = newerror;
2412 LIBMTP_error_t *tmp = device->errorstack;
2414 while (tmp->next != NULL) {
2417 tmp->next = newerror;
2422 * Adds an error from the PTP layer to the error stack.
2424 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2426 char const * const error_text)
2428 if (device == NULL) {
2429 LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2433 snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2434 outstr[sizeof(outstr)-1] = '\0';
2435 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2437 snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error));
2438 outstr[sizeof(outstr)-1] = '\0';
2439 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2444 * This returns the error stack for a device in case you
2445 * need to either reference the error numbers (e.g. when
2446 * creating multilingual apps with multiple-language text
2447 * representations for each error number) or when you need
2448 * to build a multi-line error text widget or something like
2449 * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2450 * to clear it when you're finished with it.
2451 * @param device a pointer to the MTP device to get the error
2453 * @return the error stack or NULL if there are no errors
2455 * @see LIBMTP_Clear_Errorstack()
2456 * @see LIBMTP_Dump_Errorstack()
2458 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2460 if (device == NULL) {
2461 LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2464 return device->errorstack;
2468 * This function clears the error stack of a device and frees
2469 * any memory used by it. Call this when you're finished with
2471 * @param device a pointer to the MTP device to clear the error
2474 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2476 if (device == NULL) {
2477 LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2479 LIBMTP_error_t *tmp = device->errorstack;
2481 while (tmp != NULL) {
2482 LIBMTP_error_t *tmp2;
2484 if (tmp->error_text != NULL) {
2485 free(tmp->error_text);
2491 device->errorstack = NULL;
2496 * This function dumps the error stack to <code>stderr</code>.
2497 * (You still have to clear the stack though.)
2498 * @param device a pointer to the MTP device to dump the error
2501 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2503 if (device == NULL) {
2504 LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2506 LIBMTP_error_t *tmp = device->errorstack;
2508 while (tmp != NULL) {
2509 if (tmp->error_text != NULL) {
2510 LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2512 LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2520 * This command gets all handles and stuff by FAST directory retrieveal
2521 * which is available by getting all metadata for object
2522 * <code>0xffffffff</code> which simply means "all metadata for all objects".
2523 * This works on the vast majority of MTP devices (there ARE exceptions!)
2524 * and is quite quick. Check the error stack to see if there were
2525 * problems getting the metadata.
2526 * @return 0 if all was OK, -1 on failure.
2528 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2530 PTPParams *params = (PTPParams *) device->params;
2532 int i, j, nrofprops;
2533 uint32_t lasthandle = 0xffffffff;
2534 MTPProperties *props = NULL;
2535 MTPProperties *prop;
2538 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2541 * The follow request causes the device to generate
2542 * a list of every file on the device and return it
2543 * in a single response.
2545 * Some slow devices as well as devices with very
2546 * large file systems can easily take longer then
2547 * the standard timeout value before it is able
2548 * to return a response.
2550 * Temporarly set timeout to allow working with
2551 * widest range of devices.
2553 get_usb_device_timeout(ptp_usb, &oldtimeout);
2554 set_usb_device_timeout(ptp_usb, 60000);
2556 ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2557 set_usb_device_timeout(ptp_usb, oldtimeout);
2559 if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2560 // What's the point in the device implementing this command if
2561 // you cannot use it to get all props for AT LEAST one object?
2562 // Well, whatever...
2563 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2564 "cannot retrieve all metadata for an object on this device.");
2567 if (ret != PTP_RC_OK) {
2568 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2569 "could not get proplist of all objects.");
2572 if (props == NULL && nrofprops != 0) {
2573 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2574 "get_all_metadata_fast(): "
2575 "call to ptp_mtp_getobjectproplist() returned "
2576 "inconsistent results.");
2580 * We count the number of objects by counting the ObjectHandle
2581 * references, whenever it changes we get a new object, when it's
2582 * the same, it is just different properties of the same object.
2585 for (i=0;i<nrofprops;i++) {
2586 if (lasthandle != prop->ObjectHandle) {
2588 lasthandle = prop->ObjectHandle;
2592 lasthandle = 0xffffffff;
2593 params->objects = calloc (cnt, sizeof(PTPObject));
2596 for (j=0;j<nrofprops;j++) {
2597 if (lasthandle != prop->ObjectHandle) {
2599 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2600 if (!params->objects[i].oi.Filename) {
2601 /* I have one such file on my Creative (Marcus) */
2602 params->objects[i].oi.Filename = strdup("<null>");
2606 lasthandle = prop->ObjectHandle;
2607 params->objects[i].oid = prop->ObjectHandle;
2609 switch (prop->property) {
2610 case PTP_OPC_ParentObject:
2611 params->objects[i].oi.ParentObject = prop->propval.u32;
2612 params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2614 case PTP_OPC_ObjectFormat:
2615 params->objects[i].oi.ObjectFormat = prop->propval.u16;
2617 case PTP_OPC_ObjectSize:
2618 // We loose precision here, up to 32 bits! However the commands that
2619 // retrieve metadata for files and tracks will make sure that the
2620 // PTP_OPC_ObjectSize is read in and duplicated again.
2621 if (device->object_bitsize == 64) {
2622 params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2624 params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2627 case PTP_OPC_StorageID:
2628 params->objects[i].oi.StorageID = prop->propval.u32;
2629 params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2631 case PTP_OPC_ObjectFileName:
2632 if (prop->propval.str != NULL)
2633 params->objects[i].oi.Filename = strdup(prop->propval.str);
2636 MTPProperties *newprops;
2638 /* Copy all of the other MTP oprierties into the per-object proplist */
2639 if (params->objects[i].nrofmtpprops) {
2640 newprops = realloc(params->objects[i].mtpprops,
2641 (params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2643 newprops = calloc(1,sizeof(MTPProperties));
2645 if (!newprops) return 0; /* FIXME: error handling? */
2646 params->objects[i].mtpprops = newprops;
2647 memcpy(¶ms->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2648 &props[j],sizeof(props[j]));
2649 params->objects[i].nrofmtpprops++;
2650 params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2656 /* mark last entry also */
2657 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2658 params->nrofobjects = i+1;
2660 /* The device might not give the list in linear ascending order */
2661 ptp_objects_sort (params);
2666 * This function will recurse through all the directories on the device,
2667 * starting at the root directory, gathering metadata as it moves along.
2668 * It works better on some devices that will only return data for a
2669 * certain directory and does not respect the option to get all metadata
2672 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2677 PTPObjectHandles currentHandles;
2679 uint16_t ret = ptp_getobjecthandles(params,
2681 PTP_GOH_ALL_FORMATS,
2685 if (ret != PTP_RC_OK) {
2686 add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2690 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2693 // Now descend into any subdirectories found
2694 for (i = 0; i < currentHandles.n; i++) {
2696 ret = ptp_object_want(params,currentHandles.Handler[i],
2697 PTPOBJECT_OBJECTINFO_LOADED, &ob);
2698 if (ret == PTP_RC_OK) {
2699 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2700 get_handles_recursively(device, params,
2701 storageid, currentHandles.Handler[i]);
2703 add_error_to_errorstack(device,
2704 LIBMTP_ERROR_CONNECTING,
2705 "Found a bad handle, trying to ignore it.");
2708 free(currentHandles.Handler);
2712 * This function refresh the internal handle list whenever
2713 * the items stored inside the device is altered. On operations
2714 * that do not add or remove objects, this is typically not
2716 * @param device a pointer to the MTP device to flush handles for.
2718 static void flush_handles(LIBMTP_mtpdevice_t *device)
2720 PTPParams *params = (PTPParams *) device->params;
2721 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2725 if (!device->cached) {
2729 if (params->objects != NULL) {
2730 for (i=0;i<params->nrofobjects;i++)
2731 ptp_free_object (¶ms->objects[i]);
2732 free(params->objects);
2733 params->objects = NULL;
2734 params->nrofobjects = 0;
2737 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2738 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2739 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2740 // Use the fast method. Ignore return value for now.
2741 ret = get_all_metadata_fast(device);
2744 // If the previous failed or returned no objects, use classic
2746 if (params->nrofobjects == 0) {
2747 // Get all the handles using just standard commands.
2748 if (device->storage == NULL) {
2749 get_handles_recursively(device, params,
2750 PTP_GOH_ALL_STORAGE,
2751 PTP_GOH_ROOT_PARENT);
2753 // Get handles for each storage in turn.
2754 LIBMTP_devicestorage_t *storage = device->storage;
2755 while(storage != NULL) {
2756 get_handles_recursively(device, params,
2758 PTP_GOH_ROOT_PARENT);
2759 storage = storage->next;
2765 * Loop over the handles, fix up any NULL filenames or
2766 * keywords, then attempt to locate some default folders
2767 * in the root directory of the primary storage.
2769 for(i = 0; i < params->nrofobjects; i++) {
2770 PTPObject *ob, *xob;
2772 ob = ¶ms->objects[i];
2773 ret = ptp_object_want(params,params->objects[i].oid,
2774 PTPOBJECT_OBJECTINFO_LOADED, &xob);
2775 if (ret != PTP_RC_OK) {
2776 LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2778 if (ob->oi.Filename == NULL)
2779 ob->oi.Filename = strdup("<null>");
2780 if (ob->oi.Keywords == NULL)
2781 ob->oi.Keywords = strdup("<null>");
2783 /* Ignore handles that point to non-folders */
2784 if(ob->oi.ObjectFormat != PTP_OFC_Association)
2786 /* Only look in the root folder */
2787 if (ob->oi.ParentObject == 0xffffffffU) {
2788 LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2790 } else if (ob->oi.ParentObject != 0x00000000U)
2792 /* Only look in the primary storage */
2793 if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2796 /* Is this the Music Folder */
2797 if (!strcasecmp(ob->oi.Filename, "My Music") ||
2798 !strcasecmp(ob->oi.Filename, "My_Music") ||
2799 !strcasecmp(ob->oi.Filename, "Music")) {
2800 device->default_music_folder = ob->oid;
2802 else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2803 !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2804 !strcasecmp(ob->oi.Filename, "Playlists")) {
2805 device->default_playlist_folder = ob->oid;
2807 else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2808 !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2809 !strcasecmp(ob->oi.Filename, "Pictures")) {
2810 device->default_picture_folder = ob->oid;
2812 else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2813 !strcasecmp(ob->oi.Filename, "My_Video") ||
2814 !strcasecmp(ob->oi.Filename, "Video")) {
2815 device->default_video_folder = ob->oid;
2817 else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2818 !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2819 device->default_organizer_folder = ob->oid;
2821 else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2822 !strcasecmp(ob->oi.Filename, "Datacasts")) {
2823 device->default_zencast_folder = ob->oid;
2825 else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2826 !strcasecmp(ob->oi.Filename, "My_Albums") ||
2827 !strcasecmp(ob->oi.Filename, "Albums")) {
2828 device->default_album_folder = ob->oid;
2830 else if (!strcasecmp(ob->oi.Filename, "Text") ||
2831 !strcasecmp(ob->oi.Filename, "Texts")) {
2832 device->default_text_folder = ob->oid;
2838 * This function traverses a devices storage list freeing up the
2839 * strings and the structs.
2840 * @param device a pointer to the MTP device to free the storage
2843 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2845 LIBMTP_devicestorage_t *storage;
2846 LIBMTP_devicestorage_t *tmp;
2848 storage = device->storage;
2849 while(storage != NULL) {
2850 if (storage->StorageDescription != NULL) {
2851 free(storage->StorageDescription);
2853 if (storage->VolumeIdentifier != NULL) {
2854 free(storage->VolumeIdentifier);
2857 storage = storage->next;
2860 device->storage = NULL;
2866 * This function traverses a devices storage list freeing up the
2867 * strings and the structs.
2868 * @param device a pointer to the MTP device to free the storage
2871 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2873 LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2875 if (device->storage == NULL)
2877 if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2880 oldhead = ptr1 = ptr2 = device->storage;
2884 while(oldhead != NULL) {
2885 ptr1 = ptr2 = oldhead;
2886 while(ptr1 != NULL) {
2888 if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2890 if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2896 // Make our previous entries next point to our next
2897 if(ptr2->prev != NULL) {
2899 ptr1->next = ptr2->next;
2901 oldhead = ptr2->next;
2903 oldhead->prev = NULL;
2906 // Make our next entries previous point to our previous
2909 ptr1->prev = ptr2->prev;
2916 if(newlist == NULL) {
2918 newlist->prev = NULL;
2920 ptr2->prev = newlist;
2921 newlist->next = ptr2;
2922 newlist = newlist->next;
2926 if (newlist != NULL) {
2927 newlist->next = NULL;
2928 while(newlist->prev != NULL)
2929 newlist = newlist->prev;
2930 device->storage = newlist;
2937 * This function grabs the first writeable storageid from the
2938 * device storage list.
2939 * @param device a pointer to the MTP device to locate writeable
2941 * @param fitsize a file of this file must fit on the device.
2943 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
2946 LIBMTP_devicestorage_t *storage;
2947 uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
2950 // See if there is some storage we can fit this file on.
2951 storage = device->storage;
2952 if (storage == NULL) {
2953 // Sometimes the storage just cannot be detected.
2954 store = 0x00000000U;
2956 while(storage != NULL) {
2957 // These storages cannot be used.
2958 if (storage->StorageType == PTP_ST_FixedROM ||
2959 storage->StorageType == PTP_ST_RemovableROM) {
2960 storage = storage->next;
2963 // Storage IDs with the lower 16 bits 0x0000 are not supposed
2965 if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
2966 storage = storage->next;
2969 // Also check the access capability to avoid e.g. deletable only storages
2970 if (storage->AccessCapability == PTP_AC_ReadOnly ||
2971 storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
2972 storage = storage->next;
2975 // Then see if we can fit the file.
2976 subcall_ret = check_if_file_fits(device, storage, fitsize);
2977 if (subcall_ret != 0) {
2978 storage = storage->next;
2980 // We found a storage that is writable and can fit the file!
2984 if (storage == NULL) {
2985 add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
2986 "get_writeable_storageid(): "
2987 "all device storage is full or corrupt.");
2990 store = storage->id;
2997 * Tries to suggest a storage_id of a given ID when we have a parent
2998 * @param device a pointer to the device where to search for the storage ID
2999 * @param fitsize a file of this file must fit on the device.
3000 * @param parent_id look for this ID
3003 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3007 PTPParams *params = (PTPParams *) device->params;
3011 ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3012 if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3013 add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3014 "could not get storage id from parent id.");
3015 return get_writeable_storageid(device, fitsize);
3017 /* OK we know the parent storage, then use that */
3018 return ob->oi.StorageID;
3023 * This function grabs the freespace from a certain storage in
3024 * device storage list.
3025 * @param device a pointer to the MTP device to free the storage
3027 * @param storageid the storage ID for the storage to flush and
3028 * get free space for.
3029 * @param freespace the free space on this storage will be returned
3032 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3033 LIBMTP_devicestorage_t *storage,
3034 uint64_t *freespace)
3036 PTPParams *params = (PTPParams *) device->params;
3038 // Always query the device about this, since some models explicitly
3039 // needs that. We flush all data on queries storage here.
3040 if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3041 PTPStorageInfo storageInfo;
3044 ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3045 if (ret != PTP_RC_OK) {
3046 add_ptp_error_to_errorstack(device, ret,
3047 "get_storage_freespace(): could not get storage info.");
3050 if (storage->StorageDescription != NULL) {
3051 free(storage->StorageDescription);
3053 if (storage->VolumeIdentifier != NULL) {
3054 free(storage->VolumeIdentifier);
3056 storage->StorageType = storageInfo.StorageType;
3057 storage->FilesystemType = storageInfo.FilesystemType;
3058 storage->AccessCapability = storageInfo.AccessCapability;
3059 storage->MaxCapacity = storageInfo.MaxCapability;
3060 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3061 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3062 storage->StorageDescription = storageInfo.StorageDescription;
3063 storage->VolumeIdentifier = storageInfo.VolumeLabel;
3065 if(storage->FreeSpaceInBytes == (uint64_t) -1)
3067 *freespace = storage->FreeSpaceInBytes;
3072 * This function dumps out a large chunk of textual information
3073 * provided from the PTP protocol and additionally some extra
3074 * MTP-specific information where applicable.
3075 * @param device a pointer to the MTP device to report info from.
3077 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3080 PTPParams *params = (PTPParams *) device->params;
3081 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3082 LIBMTP_devicestorage_t *storage = device->storage;
3083 LIBMTP_device_extension_t *tmpext = device->extensions;
3085 printf("USB low-level info:\n");
3086 dump_usbinfo(ptp_usb);
3087 /* Print out some verbose information */
3088 printf("Device info:\n");
3089 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3090 printf(" Model: %s\n", params->deviceinfo.Model);
3091 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
3092 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
3093 printf(" Vendor extension ID: 0x%08x\n",
3094 params->deviceinfo.VendorExtensionID);
3095 printf(" Vendor extension description: %s\n",
3096 params->deviceinfo.VendorExtensionDesc);
3097 printf(" Detected object size: %d bits\n",
3098 device->object_bitsize);
3099 printf(" Extensions:\n");
3100 while (tmpext != NULL) {
3101 printf(" %s: %d.%d\n",
3105 tmpext = tmpext->next;
3107 printf("Supported operations:\n");
3108 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
3111 (void) ptp_render_opcode(params, params->deviceinfo.OperationsSupported[i],
3113 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
3115 printf("Events supported:\n");
3116 if (params->deviceinfo.EventsSupported_len == 0) {
3119 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3120 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
3123 printf("Device Properties Supported:\n");
3124 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3125 char const *propdesc = ptp_get_property_description(params,
3126 params->deviceinfo.DevicePropertiesSupported[i]);
3128 if (propdesc != NULL) {
3129 printf(" 0x%04x: %s\n",
3130 params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3132 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3133 printf(" 0x%04x: Unknown property\n", prop);
3137 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3138 printf("Playable File (Object) Types and Object Properties Supported:\n");
3139 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3142 uint16_t *props = NULL;
3143 uint32_t propcnt = 0;
3146 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3148 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3150 ret = ptp_mtp_getobjectpropssupported (params,
3151 params->deviceinfo.ImageFormats[i], &propcnt, &props);
3152 if (ret != PTP_RC_OK) {
3153 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3154 "error on query for object properties.");
3156 for (j=0;j<propcnt;j++) {
3157 PTPObjectPropDesc opd;
3160 printf(" %04x: %s", props[j],
3161 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3162 // Get a more verbose description
3163 ret = ptp_mtp_getobjectpropdesc(params, props[j],
3164 params->deviceinfo.ImageFormats[i],
3166 if (ret != PTP_RC_OK) {
3167 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3168 "LIBMTP_Dump_Device_Info(): "
3169 "could not get property description.");
3173 if (opd.DataType == PTP_DTC_STR) {
3174 printf(" STRING data type");
3175 switch (opd.FormFlag) {
3176 case PTP_OPFF_DateTime:
3177 printf(" DATETIME FORM");
3179 case PTP_OPFF_RegularExpression:
3180 printf(" REGULAR EXPRESSION FORM");
3182 case PTP_OPFF_LongString:
3183 printf(" LONG STRING FORM");
3189 if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3190 printf(" array of");
3193 switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3196 printf(" UNDEFINED data type");
3199 printf(" INT8 data type");
3200 switch (opd.FormFlag) {
3201 case PTP_OPFF_Range:
3202 printf(" range: MIN %d, MAX %d, STEP %d",
3203 opd.FORM.Range.MinimumValue.i8,
3204 opd.FORM.Range.MaximumValue.i8,
3205 opd.FORM.Range.StepSize.i8);
3207 case PTP_OPFF_Enumeration:
3208 printf(" enumeration: ");
3209 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3210 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3213 case PTP_OPFF_ByteArray:
3214 printf(" byte array: ");
3217 printf(" ANY 8BIT VALUE form");
3223 printf(" UINT8 data type");
3224 switch (opd.FormFlag) {
3225 case PTP_OPFF_Range:
3226 printf(" range: MIN %d, MAX %d, STEP %d",
3227 opd.FORM.Range.MinimumValue.u8,
3228 opd.FORM.Range.MaximumValue.u8,
3229 opd.FORM.Range.StepSize.u8);
3231 case PTP_OPFF_Enumeration:
3232 printf(" enumeration: ");
3233 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3234 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3237 case PTP_OPFF_ByteArray:
3238 printf(" byte array: ");
3241 printf(" ANY 8BIT VALUE form");
3247 printf(" INT16 data type");
3248 switch (opd.FormFlag) {
3249 case PTP_OPFF_Range:
3250 printf(" range: MIN %d, MAX %d, STEP %d",
3251 opd.FORM.Range.MinimumValue.i16,
3252 opd.FORM.Range.MaximumValue.i16,
3253 opd.FORM.Range.StepSize.i16);
3255 case PTP_OPFF_Enumeration:
3256 printf(" enumeration: ");
3257 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3258 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3262 printf(" ANY 16BIT VALUE form");
3267 case PTP_DTC_UINT16:
3268 printf(" UINT16 data type");
3269 switch (opd.FormFlag) {
3270 case PTP_OPFF_Range:
3271 printf(" range: MIN %d, MAX %d, STEP %d",
3272 opd.FORM.Range.MinimumValue.u16,
3273 opd.FORM.Range.MaximumValue.u16,
3274 opd.FORM.Range.StepSize.u16);
3276 case PTP_OPFF_Enumeration:
3277 printf(" enumeration: ");
3278 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3279 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3283 printf(" ANY 16BIT VALUE form");
3289 printf(" INT32 data type");
3290 switch (opd.FormFlag) {
3291 case PTP_OPFF_Range:
3292 printf(" range: MIN %d, MAX %d, STEP %d",
3293 opd.FORM.Range.MinimumValue.i32,
3294 opd.FORM.Range.MaximumValue.i32,
3295 opd.FORM.Range.StepSize.i32);
3297 case PTP_OPFF_Enumeration:
3298 printf(" enumeration: ");
3299 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3300 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3304 printf(" ANY 32BIT VALUE form");
3309 case PTP_DTC_UINT32:
3310 printf(" UINT32 data type");
3311 switch (opd.FormFlag) {
3312 case PTP_OPFF_Range:
3313 printf(" range: MIN %d, MAX %d, STEP %d",
3314 opd.FORM.Range.MinimumValue.u32,
3315 opd.FORM.Range.MaximumValue.u32,
3316 opd.FORM.Range.StepSize.u32);
3318 case PTP_OPFF_Enumeration:
3319 // Special pretty-print for FOURCC codes
3320 if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3321 printf(" enumeration of u32 casted FOURCC: ");
3322 for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3323 if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3327 fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3328 fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3329 fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3330 fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3333 printf("\"%s\", ", fourcc);
3337 printf(" enumeration: ");
3338 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3339 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3344 printf(" ANY 32BIT VALUE form");
3350 printf(" INT64 data type");
3353 case PTP_DTC_UINT64:
3354 printf(" UINT64 data type");
3357 case PTP_DTC_INT128:
3358 printf(" INT128 data type");
3361 case PTP_DTC_UINT128:
3362 printf(" UINT128 data type");
3366 printf(" UNKNOWN data type");
3373 printf(" READ ONLY");
3376 ptp_free_objectpropdesc(&opd);
3383 if(storage != NULL &&
3384 ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3385 printf("Storage Devices:\n");
3386 while(storage != NULL) {
3387 printf(" StorageID: 0x%08x\n",storage->id);
3388 printf(" StorageType: 0x%04x ",storage->StorageType);
3389 switch (storage->StorageType) {
3390 case PTP_ST_Undefined:
3391 printf("(undefined)\n");
3393 case PTP_ST_FixedROM:
3394 printf("fixed ROM storage\n");
3396 case PTP_ST_RemovableROM:
3397 printf("removable ROM storage\n");
3399 case PTP_ST_FixedRAM:
3400 printf("fixed RAM storage\n");
3402 case PTP_ST_RemovableRAM:
3403 printf("removable RAM storage\n");
3406 printf("UNKNOWN storage\n");
3409 printf(" FilesystemType: 0x%04x ",storage->FilesystemType);
3410 switch(storage->FilesystemType) {
3411 case PTP_FST_Undefined:
3412 printf("(undefined)\n");
3414 case PTP_FST_GenericFlat:
3415 printf("generic flat filesystem\n");
3417 case PTP_FST_GenericHierarchical:
3418 printf("generic hierarchical\n");
3424 printf("UNKNONWN filesystem type\n");
3427 printf(" AccessCapability: 0x%04x ",storage->AccessCapability);
3428 switch(storage->AccessCapability) {
3429 case PTP_AC_ReadWrite:
3430 printf("read/write\n");
3432 case PTP_AC_ReadOnly:
3433 printf("read only\n");
3435 case PTP_AC_ReadOnly_with_Object_Deletion:
3436 printf("read only + object deletion\n");
3439 printf("UNKNOWN access capability\n");
3442 printf(" MaxCapacity: %llu\n",
3443 (long long unsigned int) storage->MaxCapacity);
3444 printf(" FreeSpaceInBytes: %llu\n",
3445 (long long unsigned int) storage->FreeSpaceInBytes);
3446 printf(" FreeSpaceInObjects: %llu\n",
3447 (long long unsigned int) storage->FreeSpaceInObjects);
3448 printf(" StorageDescription: %s\n",storage->StorageDescription);
3449 printf(" VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3450 storage = storage->next;
3454 printf("Special directories:\n");
3455 printf(" Default music folder: 0x%08x\n",
3456 device->default_music_folder);
3457 printf(" Default playlist folder: 0x%08x\n",
3458 device->default_playlist_folder);
3459 printf(" Default picture folder: 0x%08x\n",
3460 device->default_picture_folder);
3461 printf(" Default video folder: 0x%08x\n",
3462 device->default_video_folder);
3463 printf(" Default organizer folder: 0x%08x\n",
3464 device->default_organizer_folder);
3465 printf(" Default zencast folder: 0x%08x\n",
3466 device->default_zencast_folder);
3467 printf(" Default album folder: 0x%08x\n",
3468 device->default_album_folder);
3469 printf(" Default text folder: 0x%08x\n",
3470 device->default_text_folder);
3474 * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3475 * operation code (0x1010).
3476 * @param device a pointer to the device to reset.
3477 * @return 0 on success, any other value means failure.
3479 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3481 PTPParams *params = (PTPParams *) device->params;
3484 if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3485 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3486 "LIBMTP_Reset_Device(): "
3487 "device does not support resetting.");
3490 ret = ptp_resetdevice(params);
3491 if (ret != PTP_RC_OK) {
3492 add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3499 * This retrieves the manufacturer name of an MTP device.
3500 * @param device a pointer to the device to get the manufacturer name for.
3501 * @return a newly allocated UTF-8 string representing the manufacturer name.
3502 * The string must be freed by the caller after use. If the call
3503 * was unsuccessful this will contain NULL.
3505 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3507 char *retmanuf = NULL;
3508 PTPParams *params = (PTPParams *) device->params;
3510 if (params->deviceinfo.Manufacturer != NULL) {
3511 retmanuf = strdup(params->deviceinfo.Manufacturer);
3517 * This retrieves the model name (often equal to product name)
3519 * @param device a pointer to the device to get the model name for.
3520 * @return a newly allocated UTF-8 string representing the model name.
3521 * The string must be freed by the caller after use. If the call
3522 * was unsuccessful this will contain NULL.
3524 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3526 char *retmodel = NULL;
3527 PTPParams *params = (PTPParams *) device->params;
3529 if (params->deviceinfo.Model != NULL) {
3530 retmodel = strdup(params->deviceinfo.Model);
3536 * This retrieves the serial number of an MTP device.
3537 * @param device a pointer to the device to get the serial number for.
3538 * @return a newly allocated UTF-8 string representing the serial number.
3539 * The string must be freed by the caller after use. If the call
3540 * was unsuccessful this will contain NULL.
3542 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3544 char *retnumber = NULL;
3545 PTPParams *params = (PTPParams *) device->params;
3547 if (params->deviceinfo.SerialNumber != NULL) {
3548 retnumber = strdup(params->deviceinfo.SerialNumber);
3554 * This retrieves the device version (hardware and firmware version) of an
3556 * @param device a pointer to the device to get the device version for.
3557 * @return a newly allocated UTF-8 string representing the device version.
3558 * The string must be freed by the caller after use. If the call
3559 * was unsuccessful this will contain NULL.
3561 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3563 char *retversion = NULL;
3564 PTPParams *params = (PTPParams *) device->params;
3566 if (params->deviceinfo.DeviceVersion != NULL) {
3567 retversion = strdup(params->deviceinfo.DeviceVersion);
3574 * This retrieves the "friendly name" of an MTP device. Usually
3575 * this is simply the name of the owner or something like
3576 * "John Doe's Digital Audio Player". This property should be supported
3577 * by all MTP devices.
3578 * @param device a pointer to the device to get the friendly name for.
3579 * @return a newly allocated UTF-8 string representing the friendly name.
3580 * The string must be freed by the caller after use.
3581 * @see LIBMTP_Set_Friendlyname()
3583 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3585 PTPPropertyValue propval;
3586 char *retstring = NULL;
3587 PTPParams *params = (PTPParams *) device->params;
3590 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3594 ret = ptp_getdevicepropvalue(params,
3595 PTP_DPC_MTP_DeviceFriendlyName,
3598 if (ret != PTP_RC_OK) {
3599 add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3602 if (propval.str != NULL) {
3603 retstring = strdup(propval.str);
3610 * Sets the "friendly name" of an MTP device.
3611 * @param device a pointer to the device to set the friendly name for.
3612 * @param friendlyname the new friendly name for the device.
3613 * @return 0 on success, any other value means failure.
3614 * @see LIBMTP_Get_Friendlyname()
3616 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3617 char const * const friendlyname)
3619 PTPPropertyValue propval;
3620 PTPParams *params = (PTPParams *) device->params;
3623 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3626 propval.str = (char *) friendlyname;
3627 ret = ptp_setdevicepropvalue(params,
3628 PTP_DPC_MTP_DeviceFriendlyName,
3631 if (ret != PTP_RC_OK) {
3632 add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3639 * This retrieves the syncronization partner of an MTP device. This
3640 * property should be supported by all MTP devices.
3641 * @param device a pointer to the device to get the sync partner for.
3642 * @return a newly allocated UTF-8 string representing the synchronization
3643 * partner. The string must be freed by the caller after use.
3644 * @see LIBMTP_Set_Syncpartner()
3646 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3648 PTPPropertyValue propval;
3649 char *retstring = NULL;
3650 PTPParams *params = (PTPParams *) device->params;
3653 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3657 ret = ptp_getdevicepropvalue(params,
3658 PTP_DPC_MTP_SynchronizationPartner,
3661 if (ret != PTP_RC_OK) {
3662 add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3665 if (propval.str != NULL) {
3666 retstring = strdup(propval.str);
3674 * Sets the synchronization partner of an MTP device. Note that
3675 * we have no idea what the effect of setting this to "foobar"
3676 * may be. But the general idea seems to be to tell which program
3677 * shall synchronize with this device and tell others to leave
3679 * @param device a pointer to the device to set the sync partner for.
3680 * @param syncpartner the new synchronization partner for the device.
3681 * @return 0 on success, any other value means failure.
3682 * @see LIBMTP_Get_Syncpartner()
3684 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3685 char const * const syncpartner)
3687 PTPPropertyValue propval;
3688 PTPParams *params = (PTPParams *) device->params;
3691 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3694 propval.str = (char *) syncpartner;
3695 ret = ptp_setdevicepropvalue(params,
3696 PTP_DPC_MTP_SynchronizationPartner,
3699 if (ret != PTP_RC_OK) {
3700 add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3707 * Checks if the device can stora a file of this size or
3709 * @param device a pointer to the device.
3710 * @param filesize the size of the file to check whether it will fit.
3711 * @param storageid the ID of the storage to try to fit the file on.
3712 * @return 0 if the file fits, any other value means failure.
3714 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3715 LIBMTP_devicestorage_t *storage,
3716 uint64_t const filesize) {
3717 PTPParams *params = (PTPParams *) device->params;
3721 // If we cannot check the storage, no big deal.
3722 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3726 ret = get_storage_freespace(device, storage, &freebytes);
3728 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3729 "check_if_file_fits(): error checking free storage.");
3733 if (filesize > freebytes) {
3742 * This function retrieves the current battery level on the device.
3743 * @param device a pointer to the device to get the battery level for.
3744 * @param maximum_level a pointer to a variable that will hold the
3745 * maximum level of the battery if the call was successful.
3746 * @param current_level a pointer to a variable that will hold the
3747 * current level of the battery if the call was successful.
3748 * A value of 0 means that the device is on external power.
3749 * @return 0 if the storage info was successfully retrieved, any other
3750 * means failure. A typical cause of failure is that
3751 * the device does not support the battery level property.
3753 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3754 uint8_t * const maximum_level,
3755 uint8_t * const current_level)
3757 PTPPropertyValue propval;
3759 PTPParams *params = (PTPParams *) device->params;
3760 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3765 if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3766 !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3770 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3771 &propval, PTP_DTC_UINT8);
3772 if (ret != PTP_RC_OK) {
3773 add_ptp_error_to_errorstack(device, ret,
3774 "LIBMTP_Get_Batterylevel(): "
3775 "could not get device property value.");
3779 *maximum_level = device->maximum_battery_level;
3780 *current_level = propval.u8;
3787 * Formats device storage (if the device supports the operation).
3788 * WARNING: This WILL delete all data from the device. Make sure you've
3789 * got confirmation from the user BEFORE you call this function.
3791 * @param device a pointer to the device containing the storage to format.
3792 * @param storage the actual storage to format.
3793 * @return 0 on success, any other value means failure.
3795 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3796 LIBMTP_devicestorage_t *storage)
3799 PTPParams *params = (PTPParams *) device->params;
3801 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3802 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3803 "LIBMTP_Format_Storage(): "
3804 "device does not support formatting storage.");
3807 ret = ptp_formatstore(params, storage->id);
3808 if (ret != PTP_RC_OK) {
3809 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3810 "failed to format storage.");
3817 * Helper function to extract a unicode property off a device.
3818 * This is the standard way of retrieveing unicode device
3819 * properties as described by the PTP spec.
3820 * @param device a pointer to the device to get the property from.
3821 * @param unicstring a pointer to a pointer that will hold the
3822 * property after this call is completed.
3823 * @param property the property to retrieve.
3824 * @return 0 on success, any other value means failure.
3826 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3827 char **unicstring, uint16_t property)
3829 PTPPropertyValue propval;
3830 PTPParams *params = (PTPParams *) device->params;
3835 if (!ptp_property_issupported(params, property)) {
3839 // Unicode strings are 16bit unsigned integer arrays.
3840 ret = ptp_getdevicepropvalue(params,
3844 if (ret != PTP_RC_OK) {
3845 // TODO: add a note on WHICH property that we failed to get.
3847 add_ptp_error_to_errorstack(device, ret,
3848 "get_device_unicode_property(): "
3849 "failed to get unicode property.");
3853 // Extract the actual array.
3854 // printf("Array of %d elements\n", propval.a.count);
3855 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3856 for (i = 0; i < propval.a.count; i++) {
3857 tmp[i] = propval.a.v[i].u16;
3858 // printf("%04x ", tmp[i]);
3860 tmp[propval.a.count] = 0x0000U;
3863 *unicstring = utf16_to_utf8(device, tmp);
3871 * This function returns the secure time as an XML document string from
3873 * @param device a pointer to the device to get the secure time for.
3874 * @param sectime the secure time string as an XML document or NULL if the call
3875 * failed or the secure time property is not supported. This string
3876 * must be <code>free()</code>:ed by the caller after use.
3877 * @return 0 on success, any other value means failure.
3879 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3881 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3885 * This function returns the device (public key) certificate as an
3886 * XML document string from the device.
3887 * @param device a pointer to the device to get the device certificate for.
3888 * @param devcert the device certificate as an XML string or NULL if the call
3889 * failed or the device certificate property is not supported. This
3890 * string must be <code>free()</code>:ed by the caller after use.
3891 * @return 0 on success, any other value means failure.
3893 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3895 return get_device_unicode_property(device, devcert,
3896 PTP_DPC_MTP_DeviceCertificate);
3900 * This function retrieves a list of supported file types, i.e. the file
3901 * types that this device claims it supports, e.g. audio file types that
3902 * the device can play etc. This list is mitigated to
3903 * inlcude the file types that libmtp can handle, i.e. it will not list
3904 * filetypes that libmtp will handle internally like playlists and folders.
3905 * @param device a pointer to the device to get the filetype capabilities for.
3906 * @param filetypes a pointer to a pointer that will hold the list of
3907 * supported filetypes if the call was successful. This list must
3908 * be <code>free()</code>:ed by the caller after use.
3909 * @param length a pointer to a variable that will hold the length of the
3910 * list of supported filetypes if the call was successful.
3911 * @return 0 on success, any other value means failure.
3912 * @see LIBMTP_Get_Filetype_Description()
3914 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3915 uint16_t * const length)
3917 PTPParams *params = (PTPParams *) device->params;
3918 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3919 uint16_t *localtypes;
3920 uint16_t localtypelen;
3923 // This is more memory than needed if there are unknown types, but what the heck.
3924 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
3927 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3928 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
3929 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
3930 localtypes[localtypelen] = localtype;
3934 // The forgotten Ogg support on YP-10 and others...
3935 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
3936 localtypes = (uint16_t *) realloc(localtypes,
3937 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3938 localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
3941 // The forgotten FLAC support on Cowon iAudio S9 and others...
3942 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
3943 localtypes = (uint16_t *) realloc(localtypes,
3944 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3945 localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
3949 *filetypes = localtypes;
3950 *length = localtypelen;
3956 * This function checks if the device has some specific capabilities, in
3957 * order to avoid calling APIs that may disturb the device.
3959 * @param device a pointer to the device to check the capability on.
3960 * @param cap the capability to check.
3961 * @return 0 if not supported, any other value means the device has the
3962 * requested capability.
3964 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
3967 case LIBMTP_DEVICECAP_GetPartialObject:
3968 return (ptp_operation_issupported(device->params,
3969 PTP_OC_GetPartialObject) ||
3970 ptp_operation_issupported(device->params,
3971 PTP_OC_ANDROID_GetPartialObject64));
3972 case LIBMTP_DEVICECAP_SendPartialObject:
3973 return ptp_operation_issupported(device->params,
3974 PTP_OC_ANDROID_SendPartialObject);
3975 case LIBMTP_DEVICECAP_EditObjects:
3976 return (ptp_operation_issupported(device->params,
3977 PTP_OC_ANDROID_TruncateObject) &&
3978 ptp_operation_issupported(device->params,
3979 PTP_OC_ANDROID_BeginEditObject) &&
3980 ptp_operation_issupported(device->params,
3981 PTP_OC_ANDROID_EndEditObject));
3983 * Handle other capabilities here, this is also a good place to
3984 * blacklist some advanced operations on specific devices if need
3995 * This function updates all the storage id's of a device and their
3996 * properties, then creates a linked list and puts the list head into
3997 * the device struct. It also optionally sorts this list. If you want
3998 * to display storage information in your application you should call
3999 * this function, then dereference the device struct
4000 * (<code>device->storage</code>) to get out information on the storage.
4002 * You need to call this everytime you want to update the
4003 * <code>device->storage</code> list, for example anytime you need
4004 * to check available storage somewhere.
4006 * <b>WARNING:</b> since this list is dynamically updated, do not
4007 * reference its fields in external applications by pointer! E.g
4008 * do not put a reference to any <code>char *</code> field. instead
4009 * <code>strncpy()</code> it!
4011 * @param device a pointer to the device to get the storage for.
4012 * @param sortby an integer that determines the sorting of the storage list.
4013 * Valid sort methods are defined in libmtp.h with beginning with
4014 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4016 * @return 0 on success, 1 success but only with storage id's, storage
4017 * properities could not be retrieved and -1 means failure.
4019 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4022 PTPStorageInfo storageInfo;
4023 PTPParams *params = (PTPParams *) device->params;
4024 PTPStorageIDs storageIDs;
4025 LIBMTP_devicestorage_t *storage = NULL;
4026 LIBMTP_devicestorage_t *storageprev = NULL;
4028 if (device->storage != NULL)
4029 free_storage_list(device);
4031 // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4033 if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4035 if (storageIDs.n < 1)
4038 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4039 for (i = 0; i < storageIDs.n; i++) {
4041 storage = (LIBMTP_devicestorage_t *)
4042 malloc(sizeof(LIBMTP_devicestorage_t));
4043 storage->prev = storageprev;
4044 if (storageprev != NULL)
4045 storageprev->next = storage;
4046 if (device->storage == NULL)
4047 device->storage = storage;
4049 storage->id = storageIDs.Storage[i];
4050 storage->StorageType = PTP_ST_Undefined;
4051 storage->FilesystemType = PTP_FST_Undefined;
4052 storage->AccessCapability = PTP_AC_ReadWrite;
4053 storage->MaxCapacity = (uint64_t) -1;
4054 storage->FreeSpaceInBytes = (uint64_t) -1;
4055 storage->FreeSpaceInObjects = (uint64_t) -1;
4056 storage->StorageDescription = strdup("Unknown storage");
4057 storage->VolumeIdentifier = strdup("Unknown volume");
4058 storage->next = NULL;
4060 storageprev = storage;
4062 free(storageIDs.Storage);
4065 for (i = 0; i < storageIDs.n; i++) {
4067 ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4068 if (ret != PTP_RC_OK) {
4069 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4070 "Could not get storage info.");
4071 if (device->storage != NULL) {
4072 free_storage_list(device);
4077 storage = (LIBMTP_devicestorage_t *)
4078 malloc(sizeof(LIBMTP_devicestorage_t));
4079 storage->prev = storageprev;
4080 if (storageprev != NULL)
4081 storageprev->next = storage;
4082 if (device->storage == NULL)
4083 device->storage = storage;
4085 storage->id = storageIDs.Storage[i];
4086 storage->StorageType = storageInfo.StorageType;
4087 storage->FilesystemType = storageInfo.FilesystemType;
4088 storage->AccessCapability = storageInfo.AccessCapability;
4089 storage->MaxCapacity = storageInfo.MaxCapability;
4090 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4091 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4092 storage->StorageDescription = storageInfo.StorageDescription;
4093 storage->VolumeIdentifier = storageInfo.VolumeLabel;
4094 storage->next = NULL;
4096 storageprev = storage;
4099 if (storage != NULL)
4100 storage->next = NULL;
4102 sort_storage_by(device,sortby);
4103 free(storageIDs.Storage);
4109 * This creates a new file metadata structure and allocates memory
4110 * for it. Notice that if you add strings to this structure they
4111 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4112 * operation later, so be careful of using strdup() when assigning
4116 * LIBMTP_file_t *file = LIBMTP_new_file_t();
4117 * file->filename = strdup(namestr);
4119 * LIBMTP_destroy_file_t(file);
4122 * @return a pointer to the newly allocated metadata structure.
4123 * @see LIBMTP_destroy_file_t()
4125 LIBMTP_file_t *LIBMTP_new_file_t(void)
4127 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4131 new->filename = NULL;
4134 new->storage_id = 0;
4136 new->modificationdate = 0;
4137 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4143 * This destroys a file metadata structure and deallocates the memory
4144 * used by it, including any strings. Never use a file metadata
4145 * structure again after calling this function on it.
4146 * @param file the file metadata to destroy.
4147 * @see LIBMTP_new_file_t()
4149 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4154 if (file->filename != NULL)
4155 free(file->filename);
4161 * Helper function that takes one PTP object and creates a
4162 * LIBMTP_file_t metadata entry.
4164 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4166 PTPParams *params = (PTPParams *) device->params;
4167 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4168 LIBMTP_file_t *file;
4171 // Allocate a new file type
4172 file = LIBMTP_new_file_t();
4174 file->parent_id = ob->oi.ParentObject;
4175 file->storage_id = ob->oi.StorageID;
4178 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4181 * A special quirk for devices that doesn't quite
4182 * remember that some files marked as "unknown" type are
4183 * actually OGG or FLAC files. We look at the filename extension
4184 * and see if it happens that this was atleast named "ogg" or "flac"
4185 * and fall back on this heuristic approach in that case,
4186 * for these bugged devices only.
4188 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4189 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4190 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4191 has_ogg_extension(file->filename)) {
4192 file->filetype = LIBMTP_FILETYPE_OGG;
4195 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4196 file->filetype = LIBMTP_FILETYPE_FLAC;
4200 // Set the modification date
4201 file->modificationdate = ob->oi.ModificationDate;
4203 // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4204 file->filesize = ob->oi.ObjectCompressedSize;
4205 if (ob->oi.Filename != NULL) {
4206 file->filename = strdup(ob->oi.Filename);
4209 // This is a unique ID so we can keep track of the file.
4210 file->item_id = ob->oid;
4213 * If we have a cached, large set of metadata, then use it!
4216 MTPProperties *prop = ob->mtpprops;
4218 for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4219 // Pick ObjectSize here...
4220 if (prop->property == PTP_OPC_ObjectSize) {
4221 // This may already be set, but this 64bit precision value
4222 // is better than the PTP 32bit value, so let it override.
4223 if (device->object_bitsize == 64) {
4224 file->filesize = prop->propval.u64;
4226 file->filesize = prop->propval.u32;
4231 } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4232 uint16_t *props = NULL;
4233 uint32_t propcnt = 0;
4236 // First see which properties can be retrieved for this object format
4237 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4238 if (ret != PTP_RC_OK) {
4239 add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4240 // Silently fall through.
4242 for (i = 0; i < propcnt; i++) {
4244 case PTP_OPC_ObjectSize:
4245 if (device->object_bitsize == 64) {
4246 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4248 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4264 * This function retrieves the metadata for a single file off
4267 * Do not call this function repeatedly! The file handles are linearly
4268 * searched O(n) and the call may involve (slow) USB traffic, so use
4269 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4270 * as an efficient data structure such as a hash list.
4272 * Incidentally this function will return metadata for
4273 * a folder (association) as well, but this is not a proper use
4274 * of it, it is intended for file manipulation, not folder manipulation.
4276 * @param device a pointer to the device to get the file metadata from.
4277 * @param fileid the object ID of the file that you want the metadata for.
4278 * @return a metadata entry on success or NULL on failure.
4279 * @see LIBMTP_Get_Filelisting()
4281 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4283 PTPParams *params = (PTPParams *) device->params;
4287 // Get all the handles if we haven't already done that
4288 // (Only on cached devices.)
4289 if (device->cached && params->nrofobjects == 0) {
4290 flush_handles(device);
4293 ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4294 if (ret != PTP_RC_OK)
4297 return obj2file(device, ob);
4301 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4303 * @see LIBMTP_Get_Filelisting_With_Callback()
4305 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4307 LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4308 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4309 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4313 * This returns a long list of all files available
4314 * on the current MTP device. Folders will not be returned, but abstract
4315 * entities like playlists and albums will show up as "files". Typical usage:
4318 * LIBMTP_file_t *filelist;
4320 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4321 * while (filelist != NULL) {
4322 * LIBMTP_file_t *tmp;
4324 * // Do something on each element in the list here...
4326 * filelist = filelist->next;
4327 * LIBMTP_destroy_file_t(tmp);
4331 * If you want to group your file listing by storage (per storage unit) or
4332 * arrange files into folders, you must dereference the <code>storage_id</code>
4333 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4334 * struct. To arrange by folders or files you typically have to create the proper
4335 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4336 * <code>LIBMTP_Get_Folder_List()</code> first.
4338 * @param device a pointer to the device to get the file listing for.
4339 * @param callback a function to be called during the tracklisting retrieveal
4340 * for displaying progress bars etc, or NULL if you don't want
4342 * @param data a user-defined pointer that is passed along to
4343 * the <code>progress</code> function in order to
4344 * pass along some user defined data to the progress
4345 * updates. If not used, set this to NULL.
4346 * @return a list of files that can be followed using the <code>next</code>
4347 * field of the <code>LIBMTP_file_t</code> data structure.
4348 * Each of the metadata tags must be freed after use, and may
4349 * contain only partial metadata information, i.e. one or several
4350 * fields may be NULL or 0.
4351 * @see LIBMTP_Get_Filemetadata()
4353 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4354 LIBMTP_progressfunc_t const callback,
4355 void const * const data)
4358 LIBMTP_file_t *retfiles = NULL;
4359 LIBMTP_file_t *curfile = NULL;
4360 PTPParams *params = (PTPParams *) device->params;
4362 // Get all the handles if we haven't already done that
4363 if (params->nrofobjects == 0) {
4364 flush_handles(device);
4367 for (i = 0; i < params->nrofobjects; i++) {
4368 LIBMTP_file_t *file;
4371 if (callback != NULL)
4372 callback(i, params->nrofobjects, data);
4374 ob = ¶ms->objects[i];
4376 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4377 // MTP use this object format for folders which means
4378 // these "files" will turn up on a folder listing instead.
4383 file = obj2file(device, ob);
4388 // Add track to a list that will be returned afterwards.
4389 if (retfiles == NULL) {
4393 curfile->next = file;
4397 // Call listing callback
4398 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4400 } // Handle counting loop
4405 * This function retrieves the contents of a certain folder
4406 * with id parent on a certain storage on a certain device.
4407 * The result contains both files and folders.
4408 * The device used with this operations must have been opened with
4409 * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4411 * NOTE: the request will always perform I/O with the device.
4412 * @param device a pointer to the MTP device to report info from.
4413 * @param storage a storage on the device to report info from. If
4414 * 0 is passed in, the files for the given parent will be
4415 * searched across all available storages.
4416 * @param parent the parent folder id.
4418 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4419 uint32_t const storage,
4420 uint32_t const parent)
4422 PTPParams *params = (PTPParams *) device->params;
4423 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4424 LIBMTP_file_t *retfiles = NULL;
4425 LIBMTP_file_t *curfile = NULL;
4426 PTPObjectHandles currentHandles;
4431 if (device->cached) {
4432 // This function is only supposed to be used by devices
4433 // opened as uncached!
4434 LIBMTP_ERROR("tried to use %s on a cached device!\n",
4439 if (FLAG_BROKEN_GET_OBJECT_PROPVAL(ptp_usb)) {
4440 // These devices cannot handle the commands needed for
4442 LIBMTP_ERROR("tried to use %s on an unsupported device, "
4443 "this command does not work on all devices "
4444 "due to missing low-level support to read "
4445 "information on individual tracks\n",
4451 storageid = PTP_GOH_ALL_STORAGE;
4453 storageid = storage;
4455 ret = ptp_getobjecthandles(params,
4457 PTP_GOH_ALL_FORMATS,
4461 if (ret != PTP_RC_OK) {
4462 add_ptp_error_to_errorstack(device, ret,
4463 "LIBMTP_Get_Files_And_Folders(): could not get object handles.");
4467 if (currentHandles.Handler == NULL || currentHandles.n == 0)
4470 for (i = 0; i < currentHandles.n; i++) {
4471 LIBMTP_file_t *file;
4473 // Get metadata for one file, if it fails, try next file
4474 file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4478 // Add track to a list that will be returned afterwards.
4479 if (curfile == NULL) {
4483 curfile->next = file;
4488 free(currentHandles.Handler);
4490 // Return a pointer to the original first file
4497 * This creates a new track metadata structure and allocates memory
4498 * for it. Notice that if you add strings to this structure they
4499 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4500 * operation later, so be careful of using strdup() when assigning
4504 * LIBMTP_track_t *track = LIBMTP_new_track_t();
4505 * track->title = strdup(titlestr);
4507 * LIBMTP_destroy_track_t(track);
4510 * @return a pointer to the newly allocated metadata structure.
4511 * @see LIBMTP_destroy_track_t()
4513 LIBMTP_track_t *LIBMTP_new_track_t(void)
4515 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4521 new->storage_id = 0;
4524 new->composer = NULL;
4528 new->filename = NULL;
4530 new->tracknumber = 0;
4532 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4533 new->samplerate = 0;
4534 new->nochannels = 0;
4537 new->bitratetype = 0;
4540 new->modificationdate = 0;
4546 * This destroys a track metadata structure and deallocates the memory
4547 * used by it, including any strings. Never use a track metadata
4548 * structure again after calling this function on it.
4549 * @param track the track metadata to destroy.
4550 * @see LIBMTP_new_track_t()
4552 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4554 if (track == NULL) {
4557 if (track->title != NULL)
4559 if (track->artist != NULL)
4560 free(track->artist);
4561 if (track->composer != NULL)
4562 free(track->composer);
4563 if (track->album != NULL)
4565 if (track->genre != NULL)
4567 if (track->date != NULL)
4569 if (track->filename != NULL)
4570 free(track->filename);
4576 * This function maps and copies a property onto the track metadata if applicable.
4578 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4580 switch (prop->property) {
4582 if (prop->propval.str != NULL)
4583 track->title = strdup(prop->propval.str);
4585 track->title = NULL;
4587 case PTP_OPC_Artist:
4588 if (prop->propval.str != NULL)
4589 track->artist = strdup(prop->propval.str);
4591 track->artist = NULL;
4593 case PTP_OPC_Composer:
4594 if (prop->propval.str != NULL)
4595 track->composer = strdup(prop->propval.str);
4597 track->composer = NULL;
4599 case PTP_OPC_Duration:
4600 track->duration = prop->propval.u32;
4603 track->tracknumber = prop->propval.u16;
4606 if (prop->propval.str != NULL)
4607 track->genre = strdup(prop->propval.str);
4609 track->genre = NULL;
4611 case PTP_OPC_AlbumName:
4612 if (prop->propval.str != NULL)
4613 track->album = strdup(prop->propval.str);
4615 track->album = NULL;
4617 case PTP_OPC_OriginalReleaseDate:
4618 if (prop->propval.str != NULL)
4619 track->date = strdup(prop->propval.str);
4623 // These are, well not so important.
4624 case PTP_OPC_SampleRate:
4625 track->samplerate = prop->propval.u32;
4627 case PTP_OPC_NumberOfChannels:
4628 track->nochannels = prop->propval.u16;
4630 case PTP_OPC_AudioWAVECodec:
4631 track->wavecodec = prop->propval.u32;
4633 case PTP_OPC_AudioBitRate:
4634 track->bitrate = prop->propval.u32;
4636 case PTP_OPC_BitRateType:
4637 track->bitratetype = prop->propval.u16;
4639 case PTP_OPC_Rating:
4640 track->rating = prop->propval.u16;
4642 case PTP_OPC_UseCount:
4643 track->usecount = prop->propval.u32;
4645 case PTP_OPC_ObjectSize:
4646 if (device->object_bitsize == 64) {
4647 track->filesize = prop->propval.u64;
4649 track->filesize = prop->propval.u32;
4658 * This function retrieves the track metadata for a track
4659 * given by a unique ID.
4660 * @param device a pointer to the device to get the track metadata off.
4661 * @param trackid the unique ID of the track.
4662 * @param objectformat the object format of this track, so we know what it supports.
4663 * @param track a metadata set to fill in.
4665 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4666 LIBMTP_track_t *track)
4669 PTPParams *params = (PTPParams *) device->params;
4671 MTPProperties *prop;
4675 * If we have a cached, large set of metadata, then use it!
4677 ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4679 prop = ob->mtpprops;
4680 for (i=0;i<ob->nrofmtpprops;i++,prop++)
4681 pick_property_to_track_metadata(device, prop, track);
4683 uint16_t *props = NULL;
4684 uint32_t propcnt = 0;
4686 // First see which properties can be retrieved for this object format
4687 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4688 if (ret != PTP_RC_OK) {
4689 add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4690 // Just bail out for now, nothing is ever set.
4693 for (i=0;i<propcnt;i++) {
4696 track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4698 case PTP_OPC_Artist:
4699 track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4701 case PTP_OPC_Composer:
4702 track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4704 case PTP_OPC_Duration:
4705 track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4708 track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4711 track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4713 case PTP_OPC_AlbumName:
4714 track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4716 case PTP_OPC_OriginalReleaseDate:
4717 track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4719 // These are, well not so important.
4720 case PTP_OPC_SampleRate:
4721 track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4723 case PTP_OPC_NumberOfChannels:
4724 track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4726 case PTP_OPC_AudioWAVECodec:
4727 track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4729 case PTP_OPC_AudioBitRate:
4730 track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4732 case PTP_OPC_BitRateType:
4733 track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4735 case PTP_OPC_Rating:
4736 track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4738 case PTP_OPC_UseCount:
4739 track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4741 case PTP_OPC_ObjectSize:
4742 if (device->object_bitsize == 64) {
4743 track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4745 track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4756 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4758 * @see LIBMTP_Get_Tracklisting_With_Callback()
4760 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4762 LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4763 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4764 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4768 * This returns a long list of all tracks available on the current MTP device.
4769 * Tracks include multimedia objects, both music tracks and video tracks.
4773 * LIBMTP_track_t *tracklist;
4775 * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4776 * while (tracklist != NULL) {
4777 * LIBMTP_track_t *tmp;
4779 * // Do something on each element in the list here...
4781 * tracklist = tracklist->next;
4782 * LIBMTP_destroy_track_t(tmp);
4786 * If you want to group your track listing by storage (per storage unit) or
4787 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4788 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4789 * struct. To arrange by folders or files you typically have to create the proper
4790 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4791 * <code>LIBMTP_Get_Folder_List()</code> first.
4793 * @param device a pointer to the device to get the track listing for.
4794 * @param callback a function to be called during the tracklisting retrieveal
4795 * for displaying progress bars etc, or NULL if you don't want
4797 * @param data a user-defined pointer that is passed along to
4798 * the <code>progress</code> function in order to
4799 * pass along some user defined data to the progress
4800 * updates. If not used, set this to NULL.
4801 * @return a list of tracks that can be followed using the <code>next</code>
4802 * field of the <code>LIBMTP_track_t</code> data structure.
4803 * Each of the metadata tags must be freed after use, and may
4804 * contain only partial metadata information, i.e. one or several
4805 * fields may be NULL or 0.
4806 * @see LIBMTP_Get_Trackmetadata()
4808 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4809 LIBMTP_progressfunc_t const callback,
4810 void const * const data)
4812 return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4817 * This returns a long list of all tracks available on the current MTP device.
4818 * Tracks include multimedia objects, both music tracks and video tracks.
4822 * LIBMTP_track_t *tracklist;
4824 * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4825 * while (tracklist != NULL) {
4826 * LIBMTP_track_t *tmp;
4828 * // Do something on each element in the list here...
4830 * tracklist = tracklist->next;
4831 * LIBMTP_destroy_track_t(tmp);
4835 * If you want to group your track listing by storage (per storage unit) or
4836 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4837 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4838 * struct. To arrange by folders or files you typically have to create the proper
4839 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4840 * <code>LIBMTP_Get_Folder_List()</code> first.
4842 * @param device a pointer to the device to get the track listing for.
4843 * @param storage_id ID of device storage (if null, no filter)
4844 * @param callback a function to be called during the tracklisting retrieveal
4845 * for displaying progress bars etc, or NULL if you don't want
4847 * @param data a user-defined pointer that is passed along to
4848 * the <code>progress</code> function in order to
4849 * pass along some user defined data to the progress
4850 * updates. If not used, set this to NULL.
4851 * @return a list of tracks that can be followed using the <code>next</code>
4852 * field of the <code>LIBMTP_track_t</code> data structure.
4853 * Each of the metadata tags must be freed after use, and may
4854 * contain only partial metadata information, i.e. one or several
4855 * fields may be NULL or 0.
4856 * @see LIBMTP_Get_Trackmetadata()
4858 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4859 LIBMTP_progressfunc_t const callback,
4860 void const * const data)
4863 LIBMTP_track_t *retracks = NULL;
4864 LIBMTP_track_t *curtrack = NULL;
4865 PTPParams *params = (PTPParams *) device->params;
4866 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4868 // Get all the handles if we haven't already done that
4869 if (params->nrofobjects == 0) {
4870 flush_handles(device);
4873 for (i = 0; i < params->nrofobjects; i++) {
4874 LIBMTP_track_t *track;
4876 LIBMTP_filetype_t mtptype;
4878 if (callback != NULL)
4879 callback(i, params->nrofobjects, data);
4881 ob = ¶ms->objects[i];
4882 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4884 // Ignore stuff we don't know how to handle...
4885 // TODO: get this list as an intersection of the sets
4886 // supported by the device and the from the device and
4887 // all known track files?
4888 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4889 // This row lets through undefined files for examination since they may be forgotten OGG files.
4890 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4891 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4892 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4893 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4895 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4899 // Ignore stuff that isn't into the storage device
4900 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4903 // Allocate a new track type
4904 track = LIBMTP_new_track_t();
4906 // This is some sort of unique ID so we can keep track of the track.
4907 track->item_id = ob->oid;
4908 track->parent_id = ob->oi.ParentObject;
4909 track->storage_id = ob->oi.StorageID;
4910 track->modificationdate = ob->oi.ModificationDate;
4912 track->filetype = mtptype;
4914 // Original file-specific properties
4915 track->filesize = ob->oi.ObjectCompressedSize;
4916 if (ob->oi.Filename != NULL) {
4917 track->filename = strdup(ob->oi.Filename);
4920 get_track_metadata(device, ob->oi.ObjectFormat, track);
4923 * A special quirk for iriver devices that doesn't quite
4924 * remember that some files marked as "unknown" type are
4925 * actually OGG or FLAC files. We look at the filename extension
4926 * and see if it happens that this was atleast named "ogg" or "flac"
4927 * and fall back on this heuristic approach in that case,
4928 * for these bugged devices only.
4930 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
4931 track->filename != NULL) {
4932 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4933 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4934 has_ogg_extension(track->filename))
4935 track->filetype = LIBMTP_FILETYPE_OGG;
4936 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
4937 has_flac_extension(track->filename))
4938 track->filetype = LIBMTP_FILETYPE_FLAC;
4940 // This was not an OGG/FLAC file so discard it and continue
4941 LIBMTP_destroy_track_t(track);
4946 // Add track to a list that will be returned afterwards.
4947 if (retracks == NULL) {
4951 curtrack->next = track;
4955 // Call listing callback
4956 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4958 } // Handle counting loop
4963 * This function retrieves the metadata for a single track off
4966 * Do not call this function repeatedly! The track handles are linearly
4967 * searched O(n) and the call may involve (slow) USB traffic, so use
4968 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
4969 * as an efficient data structure such as a hash list.
4971 * @param device a pointer to the device to get the track metadata from.
4972 * @param trackid the object ID of the track that you want the metadata for.
4973 * @return a track metadata entry on success or NULL on failure.
4974 * @see LIBMTP_Get_Tracklisting()
4976 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
4978 PTPParams *params = (PTPParams *) device->params;
4979 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4981 LIBMTP_track_t *track;
4982 LIBMTP_filetype_t mtptype;
4985 // Get all the handles if we haven't already done that
4986 if (params->nrofobjects == 0)
4987 flush_handles(device);
4989 ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
4990 if (ret != PTP_RC_OK)
4993 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4995 // Ignore stuff we don't know how to handle...
4996 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4998 * This row lets through undefined files for examination
4999 * since they may be forgotten OGG or FLAC files.
5001 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5002 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5003 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5004 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5006 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5010 // Allocate a new track type
5011 track = LIBMTP_new_track_t();
5013 // This is some sort of unique ID so we can keep track of the track.
5014 track->item_id = ob->oid;
5015 track->parent_id = ob->oi.ParentObject;
5016 track->storage_id = ob->oi.StorageID;
5017 track->modificationdate = ob->oi.ModificationDate;
5019 track->filetype = mtptype;
5021 // Original file-specific properties
5022 track->filesize = ob->oi.ObjectCompressedSize;
5023 if (ob->oi.Filename != NULL) {
5024 track->filename = strdup(ob->oi.Filename);
5028 * A special quirk for devices that doesn't quite
5029 * remember that some files marked as "unknown" type are
5030 * actually OGG or FLAC files. We look at the filename extension
5031 * and see if it happens that this was atleast named "ogg"
5032 * and fall back on this heuristic approach in that case,
5033 * for these bugged devices only.
5035 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5036 track->filename != NULL) {
5037 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5038 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5039 has_ogg_extension(track->filename))
5040 track->filetype = LIBMTP_FILETYPE_OGG;
5041 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5042 has_flac_extension(track->filename))
5043 track->filetype = LIBMTP_FILETYPE_FLAC;
5045 // This was not an OGG/FLAC file so discard it
5046 LIBMTP_destroy_track_t(track);
5050 get_track_metadata(device, ob->oi.ObjectFormat, track);
5055 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5056 * to isolate the internal type.
5058 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5060 MTPDataHandler *handler = (MTPDataHandler *)priv;
5062 uint32_t local_gotlen = 0;
5063 ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5064 *gotlen = local_gotlen;
5067 case LIBMTP_HANDLER_RETURN_OK:
5069 case LIBMTP_HANDLER_RETURN_ERROR:
5070 return PTP_ERROR_IO;
5071 case LIBMTP_HANDLER_RETURN_CANCEL:
5072 return PTP_ERROR_CANCEL;
5074 return PTP_ERROR_IO;
5079 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5080 * to isolate the internal type.
5082 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen)
5084 MTPDataHandler *handler = (MTPDataHandler *)priv;
5086 uint32_t local_putlen = 0;
5087 ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5088 *putlen = local_putlen;
5091 case LIBMTP_HANDLER_RETURN_OK:
5093 case LIBMTP_HANDLER_RETURN_ERROR:
5094 return PTP_ERROR_IO;
5095 case LIBMTP_HANDLER_RETURN_CANCEL:
5096 return PTP_ERROR_CANCEL;
5098 return PTP_ERROR_IO;
5103 * This gets a file off the device to a local file identified
5105 * @param device a pointer to the device to get the track from.
5106 * @param id the file ID of the file to retrieve.
5107 * @param path a filename to use for the retrieved file.
5108 * @param callback a progress indicator function or NULL to ignore.
5109 * @param data a user-defined pointer that is passed along to
5110 * the <code>progress</code> function in order to
5111 * pass along some user defined data to the progress
5112 * updates. If not used, set this to NULL.
5113 * @return 0 if the transfer was successful, any other value means
5115 * @see LIBMTP_Get_File_To_File_Descriptor()
5117 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5118 char const * const path, LIBMTP_progressfunc_t const callback,
5119 void const * const data)
5126 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5132 #ifdef USE_WINDOWS_IO_H
5133 if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5135 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5138 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5140 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5144 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5149 // Delete partial file.
5158 * This gets a file off the device to a file identified
5159 * by a file descriptor.
5161 * This function can potentially be used for streaming
5162 * files off the device for playback or broadcast for example,
5163 * by downloading the file into a stream sink e.g. a socket.
5165 * @param device a pointer to the device to get the file from.
5166 * @param id the file ID of the file to retrieve.
5167 * @param fd a local file descriptor to write the file to.
5168 * @param callback a progress indicator function or NULL to ignore.
5169 * @param data a user-defined pointer that is passed along to
5170 * the <code>progress</code> function in order to
5171 * pass along some user defined data to the progress
5172 * updates. If not used, set this to NULL.
5173 * @return 0 if the transfer was successful, any other value means
5175 * @see LIBMTP_Get_File_To_File()
5177 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5180 LIBMTP_progressfunc_t const callback,
5181 void const * const data)
5184 PTPParams *params = (PTPParams *) device->params;
5185 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5188 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5189 if (ret != PTP_RC_OK) {
5190 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5193 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5194 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5199 ptp_usb->callback_active = 1;
5200 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5201 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5202 ptp_usb->current_transfer_complete = 0;
5203 ptp_usb->current_transfer_callback = callback;
5204 ptp_usb->current_transfer_callback_data = data;
5206 ret = ptp_getobject_tofd(params, id, fd);
5208 ptp_usb->callback_active = 0;
5209 ptp_usb->current_transfer_callback = NULL;
5210 ptp_usb->current_transfer_callback_data = NULL;
5212 if (ret == PTP_ERROR_CANCEL) {
5213 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5216 if (ret != PTP_RC_OK) {
5217 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5225 * This gets a file off the device and calls put_func
5226 * with chunks of data
5228 * @param device a pointer to the device to get the file from.
5229 * @param id the file ID of the file to retrieve.
5230 * @param put_func the function to call when we have data.
5231 * @param priv the user-defined pointer that is passed to
5232 * <code>put_func</code>.
5233 * @param callback a progress indicator function or NULL to ignore.
5234 * @param data a user-defined pointer that is passed along to
5235 * the <code>progress</code> function in order to
5236 * pass along some user defined data to the progress
5237 * updates. If not used, set this to NULL.
5238 * @return 0 if the transfer was successful, any other value means
5241 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5243 MTPDataPutFunc put_func,
5245 LIBMTP_progressfunc_t const callback,
5246 void const * const data)
5250 PTPParams *params = (PTPParams *) device->params;
5251 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5253 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5254 if (ret != PTP_RC_OK) {
5255 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5258 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5259 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5264 ptp_usb->callback_active = 1;
5265 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5266 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5267 ptp_usb->current_transfer_complete = 0;
5268 ptp_usb->current_transfer_callback = callback;
5269 ptp_usb->current_transfer_callback_data = data;
5271 MTPDataHandler mtp_handler;
5272 mtp_handler.getfunc = NULL;
5273 mtp_handler.putfunc = put_func;
5274 mtp_handler.priv = priv;
5276 PTPDataHandler handler;
5277 handler.getfunc = NULL;
5278 handler.putfunc = put_func_wrapper;
5279 handler.priv = &mtp_handler;
5281 ret = ptp_getobject_to_handler(params, id, &handler);
5283 ptp_usb->callback_active = 0;
5284 ptp_usb->current_transfer_callback = NULL;
5285 ptp_usb->current_transfer_callback_data = NULL;
5287 if (ret == PTP_ERROR_CANCEL) {
5288 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5291 if (ret != PTP_RC_OK) {
5292 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5301 * This gets a track off the device to a file identified
5302 * by a filename. This is actually just a wrapper for the
5303 * \c LIBMTP_Get_Track_To_File() function.
5304 * @param device a pointer to the device to get the track from.
5305 * @param id the track ID of the track to retrieve.
5306 * @param path a filename to use for the retrieved track.
5307 * @param callback a progress indicator function or NULL to ignore.
5308 * @param data a user-defined pointer that is passed along to
5309 * the <code>progress</code> function in order to
5310 * pass along some user defined data to the progress
5311 * updates. If not used, set this to NULL.
5312 * @return 0 if the transfer was successful, any other value means
5314 * @see LIBMTP_Get_Track_To_File_Descriptor()
5316 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5317 char const * const path, LIBMTP_progressfunc_t const callback,
5318 void const * const data)
5320 // This is just a wrapper
5321 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5325 * This gets a track off the device to a file identified
5326 * by a file descriptor. This is actually just a wrapper for
5327 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5328 * @param device a pointer to the device to get the track from.
5329 * @param id the track ID of the track to retrieve.
5330 * @param fd a file descriptor to write the track to.
5331 * @param callback a progress indicator function or NULL to ignore.
5332 * @param data a user-defined pointer that is passed along to
5333 * the <code>progress</code> function in order to
5334 * pass along some user defined data to the progress
5335 * updates. If not used, set this to NULL.
5336 * @return 0 if the transfer was successful, any other value means
5338 * @see LIBMTP_Get_Track_To_File()
5340 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5343 LIBMTP_progressfunc_t const callback,
5344 void const * const data)
5346 // This is just a wrapper
5347 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5351 * This gets a track off the device to a handler function.
5352 * This is actually just a wrapper for
5353 * the \c LIBMTP_Get_File_To_Handler() function.
5354 * @param device a pointer to the device to get the track from.
5355 * @param id the track ID of the track to retrieve.
5356 * @param put_func the function to call when we have data.
5357 * @param priv the user-defined pointer that is passed to
5358 * <code>put_func</code>.
5359 * @param callback a progress indicator function or NULL to ignore.
5360 * @param data a user-defined pointer that is passed along to
5361 * the <code>progress</code> function in order to
5362 * pass along some user defined data to the progress
5363 * updates. If not used, set this to NULL.
5364 * @return 0 if the transfer was successful, any other value means
5367 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5369 MTPDataPutFunc put_func,
5371 LIBMTP_progressfunc_t const callback,
5372 void const * const data)
5374 // This is just a wrapper
5375 return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5379 * This function sends a track from a local file to an
5380 * MTP device. A filename and a set of metadata must be
5382 * @param device a pointer to the device to send the track to.
5383 * @param path the filename of a local file which will be sent.
5384 * @param metadata a track metadata set to be written along with the file.
5385 * After this call the field <code>metadata->item_id</code>
5386 * will contain the new track ID. Other fields such
5387 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5388 * or <code>metadata->storage_id</code> may also change during this
5389 * operation due to device restrictions, so do not rely on the
5390 * contents of this struct to be preserved in any way.
5392 * <li><code>metadata->parent_id</code> should be set to the parent
5393 * (e.g. folder) to store this track in. Since some
5394 * devices are a bit picky about where files
5395 * are placed, a default folder will be chosen if libmtp
5396 * has detected one for the current filetype and this
5397 * parameter is set to 0. If this is 0 and no default folder
5398 * can be found, the file will be stored in the root folder.
5399 * <li><code>metadata->storage_id</code> should be set to the
5400 * desired storage (e.g. memory card or whatever your device
5401 * presents) to store this track in. Setting this to 0 will store
5402 * the track on the primary storage.
5404 * @param callback a progress indicator function or NULL to ignore.
5405 * @param data a user-defined pointer that is passed along to
5406 * the <code>progress</code> function in order to
5407 * pass along some user defined data to the progress
5408 * updates. If not used, set this to NULL.
5409 * @return 0 if the transfer was successful, any other value means
5411 * @see LIBMTP_Send_Track_From_File_Descriptor()
5412 * @see LIBMTP_Send_File_From_File()
5413 * @see LIBMTP_Delete_Object()
5415 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5416 char const * const path, LIBMTP_track_t * const metadata,
5417 LIBMTP_progressfunc_t const callback,
5418 void const * const data)
5425 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5431 #ifdef USE_WINDOWS_IO_H
5432 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5434 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5437 if ( (fd = open(path, O_RDONLY)) == -1) {
5439 LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5443 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5446 #ifdef USE_WINDOWS_IO_H
5458 * This helper function checks if a filename already exists on the device
5460 * @param string representing the filename
5461 * @return 0 if the filename doesn't exist, -1 if it does
5463 static int check_filename_exists(PTPParams* params, char const * const filename)
5467 for (i = 0; i < params->nrofobjects; i++) {
5468 char *fname = params->objects[i].oi.Filename;
5469 if ((fname != NULL) && (strcmp(filename, fname) == 0))
5479 * This helper function returns a unique filename, with a random string before the extension
5480 * @param string representing the original filename
5481 * @return a string representing the unique filename
5483 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5486 char * extension_position;
5488 if (check_filename_exists(params, filename))
5490 extension_position = strrchr(filename,'.');
5492 char basename[extension_position - filename + 1];
5493 strncpy(basename, filename, extension_position - filename);
5494 basename[extension_position - filename] = '\0';
5497 char newname[ strlen(basename) + 6 + strlen(extension_position)];
5498 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5499 while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5501 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5503 return strdup(newname);
5507 return strdup(filename);
5512 * This function sends a track from a file descriptor to an
5513 * MTP device. A filename and a set of metadata must be
5515 * @param device a pointer to the device to send the track to.
5516 * @param fd the filedescriptor for a local file which will be sent.
5517 * @param metadata a track metadata set to be written along with the file.
5518 * After this call the field <code>metadata->item_id</code>
5519 * will contain the new track ID. Other fields such
5520 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5521 * or <code>metadata->storage_id</code> may also change during this
5522 * operation due to device restrictions, so do not rely on the
5523 * contents of this struct to be preserved in any way.
5525 * <li><code>metadata->parent_id</code> should be set to the parent
5526 * (e.g. folder) to store this track in. Since some
5527 * devices are a bit picky about where files
5528 * are placed, a default folder will be chosen if libmtp
5529 * has detected one for the current filetype and this
5530 * parameter is set to 0. If this is 0 and no default folder
5531 * can be found, the file will be stored in the root folder.
5532 * <li><code>metadata->storage_id</code> should be set to the
5533 * desired storage (e.g. memory card or whatever your device
5534 * presents) to store this track in. Setting this to 0 will store
5535 * the track on the primary storage.
5537 * @param callback a progress indicator function or NULL to ignore.
5538 * @param data a user-defined pointer that is passed along to
5539 * the <code>progress</code> function in order to
5540 * pass along some user defined data to the progress
5541 * updates. If not used, set this to NULL.
5542 * @return 0 if the transfer was successful, any other value means
5544 * @see LIBMTP_Send_Track_From_File()
5545 * @see LIBMTP_Delete_Object()
5547 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5548 int const fd, LIBMTP_track_t * const metadata,
5549 LIBMTP_progressfunc_t const callback,
5550 void const * const data)
5553 LIBMTP_file_t filedata;
5554 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5555 PTPParams *params = (PTPParams *) device->params;
5557 // Sanity check, is this really a track?
5558 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5559 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5560 "LIBMTP_Send_Track_From_File_Descriptor(): "
5561 "I don't think this is actually a track, strange filetype...");
5564 // Wrap around the file transfer function
5565 filedata.item_id = metadata->item_id;
5566 filedata.parent_id = metadata->parent_id;
5567 filedata.storage_id = metadata->storage_id;
5568 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5569 filedata.filename = generate_unique_filename(params, metadata->filename);
5572 filedata.filename = metadata->filename;
5574 filedata.filesize = metadata->filesize;
5575 filedata.filetype = metadata->filetype;
5576 filedata.next = NULL;
5578 subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5584 if (subcall_ret != 0) {
5585 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5586 "LIBMTP_Send_Track_From_File_Descriptor(): "
5587 "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5588 // We used to delete the file here, but don't... It might be OK after all.
5589 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5593 // Pick up new item (and parent, storage) ID
5594 metadata->item_id = filedata.item_id;
5595 metadata->parent_id = filedata.parent_id;
5596 metadata->storage_id = filedata.storage_id;
5598 // Set track metadata for the new fine track
5599 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5600 if (subcall_ret != 0) {
5601 // Subcall will add error to errorstack
5602 // We used to delete the file here, but don't... It might be OK after all.
5603 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5607 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5608 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5614 * This function sends a track from a handler function to an
5615 * MTP device. A filename and a set of metadata must be
5617 * @param device a pointer to the device to send the track to.
5618 * @param get_func the function to call when we have data.
5619 * @param priv the user-defined pointer that is passed to
5620 * <code>get_func</code>.
5621 * @param metadata a track metadata set to be written along with the file.
5622 * After this call the field <code>metadata->item_id</code>
5623 * will contain the new track ID. Other fields such
5624 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5625 * or <code>metadata->storage_id</code> may also change during this
5626 * operation due to device restrictions, so do not rely on the
5627 * contents of this struct to be preserved in any way.
5629 * <li><code>metadata->parent_id</code> should be set to the parent
5630 * (e.g. folder) to store this track in. Since some
5631 * devices are a bit picky about where files
5632 * are placed, a default folder will be chosen if libmtp
5633 * has detected one for the current filetype and this
5634 * parameter is set to 0. If this is 0 and no default folder
5635 * can be found, the file will be stored in the root folder.
5636 * <li><code>metadata->storage_id</code> should be set to the
5637 * desired storage (e.g. memory card or whatever your device
5638 * presents) to store this track in. Setting this to 0 will store
5639 * the track on the primary storage.
5641 * @param callback a progress indicator function or NULL to ignore.
5642 * @param data a user-defined pointer that is passed along to
5643 * the <code>progress</code> function in order to
5644 * pass along some user defined data to the progress
5645 * updates. If not used, set this to NULL.
5646 * @return 0 if the transfer was successful, any other value means
5648 * @see LIBMTP_Send_Track_From_File()
5649 * @see LIBMTP_Delete_Object()
5651 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5652 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5653 LIBMTP_progressfunc_t const callback,
5654 void const * const data)
5657 LIBMTP_file_t filedata;
5658 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5659 PTPParams *params = (PTPParams *) device->params;
5661 // Sanity check, is this really a track?
5662 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5663 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5664 "LIBMTP_Send_Track_From_Handler(): "
5665 "I don't think this is actually a track, strange filetype...");
5668 // Wrap around the file transfer function
5669 filedata.item_id = metadata->item_id;
5670 filedata.parent_id = metadata->parent_id;
5671 filedata.storage_id = metadata->storage_id;
5672 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5673 filedata.filename = generate_unique_filename(params, metadata->filename);
5676 filedata.filename = metadata->filename;
5678 filedata.filesize = metadata->filesize;
5679 filedata.filetype = metadata->filetype;
5680 filedata.next = NULL;
5682 subcall_ret = LIBMTP_Send_File_From_Handler(device,
5689 if (subcall_ret != 0) {
5690 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5691 "LIBMTP_Send_Track_From_Handler(): "
5692 "subcall to LIBMTP_Send_File_From_Handler failed.");
5693 // We used to delete the file here, but don't... It might be OK after all.
5694 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5698 // Pick up new item (and parent, storage) ID
5699 metadata->item_id = filedata.item_id;
5700 metadata->parent_id = filedata.parent_id;
5701 metadata->storage_id = filedata.storage_id;
5703 // Set track metadata for the new fine track
5704 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5705 if (subcall_ret != 0) {
5706 // Subcall will add error to errorstack
5707 // We used to delete the file here, but don't... It might be OK after all.
5708 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5712 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5713 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5719 * This function sends a local file to an MTP device.
5720 * A filename and a set of metadata must be
5722 * @param device a pointer to the device to send the track to.
5723 * @param path the filename of a local file which will be sent.
5724 * @param filedata a file metadata set to be written along with the file.
5725 * After this call the field <code>filedata->item_id</code>
5726 * will contain the new file ID. Other fields such
5727 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5728 * or <code>filedata->storage_id</code> may also change during this
5729 * operation due to device restrictions, so do not rely on the
5730 * contents of this struct to be preserved in any way.
5732 * <li><code>filedata->parent_id</code> should be set to the parent
5733 * (e.g. folder) to store this file in. If this is 0,
5734 * the file will be stored in the root folder.
5735 * <li><code>filedata->storage_id</code> should be set to the
5736 * desired storage (e.g. memory card or whatever your device
5737 * presents) to store this file in. Setting this to 0 will store
5738 * the file on the primary storage.
5740 * @param callback a progress indicator function or NULL to ignore.
5741 * @param data a user-defined pointer that is passed along to
5742 * the <code>progress</code> function in order to
5743 * pass along some user defined data to the progress
5744 * updates. If not used, set this to NULL.
5745 * @return 0 if the transfer was successful, any other value means
5747 * @see LIBMTP_Send_File_From_File_Descriptor()
5748 * @see LIBMTP_Delete_Object()
5750 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5751 char const * const path, LIBMTP_file_t * const filedata,
5752 LIBMTP_progressfunc_t const callback,
5753 void const * const data)
5760 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5766 #ifdef USE_WINDOWS_IO_H
5767 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5769 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5772 if ( (fd = open(path, O_RDONLY)) == -1) {
5774 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5778 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5781 #ifdef USE_WINDOWS_IO_H
5791 * This function sends a generic file from a file descriptor to an
5792 * MTP device. A filename and a set of metadata must be
5795 * This can potentially be used for sending in a stream of unknown
5796 * length. Send music files with
5797 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5799 * @param device a pointer to the device to send the file to.
5800 * @param fd the filedescriptor for a local file which will be sent.
5801 * @param filedata a file metadata set to be written along with the file.
5802 * After this call the field <code>filedata->item_id</code>
5803 * will contain the new file ID. Other fields such
5804 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5805 * or <code>filedata->storage_id</code> may also change during this
5806 * operation due to device restrictions, so do not rely on the
5807 * contents of this struct to be preserved in any way.
5809 * <li><code>filedata->parent_id</code> should be set to the parent
5810 * (e.g. folder) to store this file in. If this is 0,
5811 * the file will be stored in the root folder.
5812 * <li><code>filedata->storage_id</code> should be set to the
5813 * desired storage (e.g. memory card or whatever your device
5814 * presents) to store this file in. Setting this to 0 will store
5815 * the file on the primary storage.
5817 * @param callback a progress indicator function or NULL to ignore.
5818 * @param data a user-defined pointer that is passed along to
5819 * the <code>progress</code> function in order to
5820 * pass along some user defined data to the progress
5821 * updates. If not used, set this to NULL.
5822 * @return 0 if the transfer was successful, any other value means
5824 * @see LIBMTP_Send_File_From_File()
5825 * @see LIBMTP_Send_Track_From_File_Descriptor()
5826 * @see LIBMTP_Delete_Object()
5828 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5829 int const fd, LIBMTP_file_t * const filedata,
5830 LIBMTP_progressfunc_t const callback,
5831 void const * const data)
5834 PTPParams *params = (PTPParams *) device->params;
5835 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5836 LIBMTP_file_t *newfilemeta;
5840 if (send_file_object_info(device, filedata))
5842 // no need to output an error since send_file_object_info will already have done so
5847 ptp_usb->callback_active = 1;
5848 // The callback will deactivate itself after this amount of data has been sent
5849 // One BULK header for the request, one for the data phase. No parameters to the request.
5850 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5851 ptp_usb->current_transfer_complete = 0;
5852 ptp_usb->current_transfer_callback = callback;
5853 ptp_usb->current_transfer_callback_data = data;
5856 * We might need to increase the timeout here, files can be pretty
5857 * large. Take the default timeout and add the calculated time for
5860 get_usb_device_timeout(ptp_usb, &oldtimeout);
5861 timeout = oldtimeout +
5862 (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5863 set_usb_device_timeout(ptp_usb, timeout);
5865 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5867 ptp_usb->callback_active = 0;
5868 ptp_usb->current_transfer_callback = NULL;
5869 ptp_usb->current_transfer_callback_data = NULL;
5870 set_usb_device_timeout(ptp_usb, oldtimeout);
5872 if (ret == PTP_ERROR_CANCEL) {
5873 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5876 if (ret != PTP_RC_OK) {
5877 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5878 "Could not send object.");
5882 add_object_to_cache(device, filedata->item_id);
5885 * Get the device-assigned parent_id from the cache.
5886 * The operation that adds it to the cache will
5887 * look it up from the device, so we get the new
5888 * parent_id from the cache.
5890 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5891 if (newfilemeta != NULL) {
5892 filedata->parent_id = newfilemeta->parent_id;
5893 filedata->storage_id = newfilemeta->storage_id;
5894 LIBMTP_destroy_file_t(newfilemeta);
5896 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5897 "LIBMTP_Send_File_From_File_Descriptor(): "
5898 "Could not retrieve updated metadata.");
5906 * This function sends a generic file from a handler function to an
5907 * MTP device. A filename and a set of metadata must be
5910 * This can potentially be used for sending in a stream of unknown
5911 * length. Send music files with
5912 * <code>LIBMTP_Send_Track_From_Handler()</code>
5914 * @param device a pointer to the device to send the file to.
5915 * @param get_func the function to call to get data to write
5916 * @param priv a user-defined pointer that is passed along to
5917 * <code>get_func</code>. If not used, this is set to NULL.
5918 * @param filedata a file metadata set to be written along with the file.
5919 * After this call the field <code>filedata->item_id</code>
5920 * will contain the new file ID. Other fields such
5921 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5922 * or <code>filedata->storage_id</code> may also change during this
5923 * operation due to device restrictions, so do not rely on the
5924 * contents of this struct to be preserved in any way.
5926 * <li><code>filedata->parent_id</code> should be set to the parent
5927 * (e.g. folder) to store this file in. If this is 0,
5928 * the file will be stored in the root folder.
5929 * <li><code>filedata->storage_id</code> should be set to the
5930 * desired storage (e.g. memory card or whatever your device
5931 * presents) to store this file in. Setting this to 0 will store
5932 * the file on the primary storage.
5934 * @param callback a progress indicator function or NULL to ignore.
5935 * @param data a user-defined pointer that is passed along to
5936 * the <code>progress</code> function in order to
5937 * pass along some user defined data to the progress
5938 * updates. If not used, set this to NULL.
5939 * @return 0 if the transfer was successful, any other value means
5941 * @see LIBMTP_Send_File_From_File()
5942 * @see LIBMTP_Send_Track_From_File_Descriptor()
5943 * @see LIBMTP_Delete_Object()
5945 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
5946 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
5947 LIBMTP_progressfunc_t const callback, void const * const data)
5950 PTPParams *params = (PTPParams *) device->params;
5951 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5952 LIBMTP_file_t *newfilemeta;
5954 if (send_file_object_info(device, filedata))
5956 // no need to output an error since send_file_object_info will already have done so
5961 ptp_usb->callback_active = 1;
5962 // The callback will deactivate itself after this amount of data has been sent
5963 // One BULK header for the request, one for the data phase. No parameters to the request.
5964 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5965 ptp_usb->current_transfer_complete = 0;
5966 ptp_usb->current_transfer_callback = callback;
5967 ptp_usb->current_transfer_callback_data = data;
5969 MTPDataHandler mtp_handler;
5970 mtp_handler.getfunc = get_func;
5971 mtp_handler.putfunc = NULL;
5972 mtp_handler.priv = priv;
5974 PTPDataHandler handler;
5975 handler.getfunc = get_func_wrapper;
5976 handler.putfunc = NULL;
5977 handler.priv = &mtp_handler;
5979 ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
5981 ptp_usb->callback_active = 0;
5982 ptp_usb->current_transfer_callback = NULL;
5983 ptp_usb->current_transfer_callback_data = NULL;
5985 if (ret == PTP_ERROR_CANCEL) {
5986 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
5989 if (ret != PTP_RC_OK) {
5990 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
5991 "Could not send object.");
5995 add_object_to_cache(device, filedata->item_id);
5998 * Get the device-assined parent_id from the cache.
5999 * The operation that adds it to the cache will
6000 * look it up from the device, so we get the new
6001 * parent_id from the cache.
6003 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6004 if (newfilemeta != NULL) {
6005 filedata->parent_id = newfilemeta->parent_id;
6006 filedata->storage_id = newfilemeta->storage_id;
6007 LIBMTP_destroy_file_t(newfilemeta);
6009 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6010 "LIBMTP_Send_File_From_Handler(): "
6011 "Could not retrieve updated metadata.");
6019 * This function sends the file object info, ready for sendobject
6020 * @param device a pointer to the device to send the file to.
6021 * @param filedata a file metadata set to be written along with the file.
6022 * @return 0 if the transfer was successful, any other value means
6025 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6027 PTPParams *params = (PTPParams *) device->params;
6028 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6030 int use_primary_storage = 1;
6031 uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6032 LIBMTP_devicestorage_t *storage;
6033 uint32_t localph = filedata->parent_id;
6038 // Sanity check: no zerolength files on some devices?
6039 // If the zerolength files cause problems on some devices,
6040 // then add a bug flag for this.
6041 if (filedata->filesize == 0) {
6042 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6043 "File of zero size.");
6047 if (filedata->storage_id != 0) {
6048 store = filedata->storage_id;
6050 store = get_suggested_storage_id(device, filedata->filesize, localph);
6053 // Detect if something non-primary is in use.
6054 storage = device->storage;
6055 if (storage != NULL && store != storage->id) {
6056 use_primary_storage = 0;
6060 * If no destination folder was given, look up a default
6061 * folder if possible. Perhaps there is some way of retrieveing
6062 * the default folder for different forms of content, what
6063 * do I know, we use a fixed list in lack of any better method.
6064 * Some devices obviously need to have their files in certain
6065 * folders in order to find/display them at all (hello Creative),
6066 * so we have to have a method for this. We only do this if the
6067 * primary storage is in use.
6070 if (localph == 0 && use_primary_storage) {
6071 if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6072 localph = device->default_music_folder;
6073 } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6074 localph = device->default_video_folder;
6075 } else if (of == PTP_OFC_EXIF_JPEG ||
6076 of == PTP_OFC_JP2 ||
6077 of == PTP_OFC_JPX ||
6078 of == PTP_OFC_JFIF ||
6079 of == PTP_OFC_TIFF ||
6080 of == PTP_OFC_TIFF_IT ||
6081 of == PTP_OFC_BMP ||
6082 of == PTP_OFC_GIF ||
6083 of == PTP_OFC_PICT ||
6084 of == PTP_OFC_PNG ||
6085 of == PTP_OFC_MTP_WindowsImageFormat) {
6086 localph = device->default_picture_folder;
6087 } else if (of == PTP_OFC_MTP_vCalendar1 ||
6088 of == PTP_OFC_MTP_vCalendar2 ||
6089 of == PTP_OFC_MTP_UndefinedContact ||
6090 of == PTP_OFC_MTP_vCard2 ||
6091 of == PTP_OFC_MTP_vCard3 ||
6092 of == PTP_OFC_MTP_UndefinedCalendarItem) {
6093 localph = device->default_organizer_folder;
6094 } else if (of == PTP_OFC_Text) {
6095 localph = device->default_text_folder;
6099 // Here we wire the type to unknown on bugged, but
6100 // Ogg or FLAC-supportive devices.
6101 if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6102 of = PTP_OFC_Undefined;
6104 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6105 of = PTP_OFC_Undefined;
6108 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6109 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6111 * MTP enhanched does it this way (from a sniff):
6112 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6113 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6114 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6115 * Length: 0x00000020
6116 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
6118 * Transaction ID: 0x0000001B
6119 * Param1: 0x00010001 <- store
6120 * Param2: 0xffffffff <- parent handle (-1 ?)
6121 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6122 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
6123 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6125 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6126 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6127 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6128 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6129 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6130 * 00 4F DC 02 00 01 - dc4f = non consumable
6131 * Length: 0x00000046
6132 * Type: 0x0002 PTP_USB_CONTAINER_DATA
6134 * Transaction ID: 0x0000001B
6136 * 0x00000003 <- Number of metadata items
6137 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6138 * 0xdc07 <- metadata type: file name
6139 * 0xffff <- metadata type: string
6140 * 0x0d <- number of (uint16_t) characters
6141 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6142 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6143 * 0xdc03 <- metadata type: protection status
6144 * 0x0004 <- metadata type: uint16_t
6145 * 0x0000 <- not protected
6146 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6147 * 0xdc4f <- non consumable
6148 * 0x0002 <- metadata type: uint8_t
6149 * 0x01 <- non-consumable (this device cannot display PDF)
6151 * <- Read 0x18 bytes back
6152 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6153 * 00 00 00 00 01 40 00 00
6154 * Length: 0x000000018
6155 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
6156 * Code: 0x2001 PTP_OK
6157 * Transaction ID: 0x0000001B
6158 * Param1: 0x00010001 <- store
6159 * Param2: 0x00000000 <- parent handle
6160 * Param3: 0x00004001 <- new file/object ID
6162 * -> PTP_OC_SendObject (0x100d)
6163 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
6164 * -> ... all the bytes ...
6165 * <- Read 0x0c bytes back
6166 * 0C 00 00 00 03 00 01 20 1C 00 00 00
6167 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
6169 MTPProperties *props = NULL;
6171 MTPProperties *prop = NULL;
6172 uint16_t *properties = NULL;
6173 uint32_t propcnt = 0;
6175 // default parent handle
6177 localph = 0xFFFFFFFFU; // Set to -1
6179 // Must be 0x00000000U for new objects
6180 filedata->item_id = 0x00000000U;
6182 ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6184 for (i=0;i<propcnt;i++) {
6185 PTPObjectPropDesc opd;
6187 ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6188 if (ret != PTP_RC_OK) {
6189 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6190 "could not get property description.");
6191 } else if (opd.GetSet) {
6192 switch (properties[i]) {
6193 case PTP_OPC_ObjectFileName:
6194 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6195 prop->ObjectHandle = filedata->item_id;
6196 prop->property = PTP_OPC_ObjectFileName;
6197 prop->datatype = PTP_DTC_STR;
6198 if (filedata->filename != NULL) {
6199 prop->propval.str = strdup(filedata->filename);
6200 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6201 strip_7bit_from_utf8(prop->propval.str);
6205 case PTP_OPC_ProtectionStatus:
6206 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6207 prop->ObjectHandle = filedata->item_id;
6208 prop->property = PTP_OPC_ProtectionStatus;
6209 prop->datatype = PTP_DTC_UINT16;
6210 prop->propval.u16 = 0x0000U; /* Not protected */
6212 case PTP_OPC_NonConsumable:
6213 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6214 prop->ObjectHandle = filedata->item_id;
6215 prop->property = PTP_OPC_NonConsumable;
6216 prop->datatype = PTP_DTC_UINT8;
6217 prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6220 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6221 prop->ObjectHandle = filedata->item_id;
6222 prop->property = PTP_OPC_Name;
6223 prop->datatype = PTP_DTC_STR;
6224 if (filedata->filename != NULL)
6225 prop->propval.str = strdup(filedata->filename);
6227 case PTP_OPC_DateModified:
6228 // Tag with current time if that is supported
6229 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6230 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6231 prop->ObjectHandle = filedata->item_id;
6232 prop->property = PTP_OPC_DateModified;
6233 prop->datatype = PTP_DTC_STR;
6234 prop->propval.str = get_iso8601_stamp();
6235 filedata->modificationdate = time(NULL);
6240 ptp_free_objectpropdesc(&opd);
6244 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6245 of, filedata->filesize, props, nrofprops);
6247 /* Free property list */
6248 ptp_destroy_object_prop_list(props, nrofprops);
6250 if (ret != PTP_RC_OK) {
6251 add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6252 "Could not send object property list.");
6253 if (ret == PTP_RC_AccessDenied) {
6254 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6258 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6259 PTPObjectInfo new_file;
6261 memset(&new_file, 0, sizeof(PTPObjectInfo));
6263 new_file.Filename = filedata->filename;
6264 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6265 strip_7bit_from_utf8(new_file.Filename);
6267 if (filedata->filesize > 0xFFFFFFFFL) {
6268 // This is a kludge in the MTP standard for large files.
6269 new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6271 new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6273 new_file.ObjectFormat = of;
6274 new_file.StorageID = store;
6275 new_file.ParentObject = localph;
6276 new_file.ModificationDate = time(NULL);
6278 // Create the object
6279 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6281 if (ret != PTP_RC_OK) {
6282 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6283 "Could not send object info.");
6284 if (ret == PTP_RC_AccessDenied) {
6285 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6289 // NOTE: the char* pointers inside new_file are not copies so don't
6290 // try to destroy this objectinfo!
6293 // Now there IS an object with this parent handle.
6294 filedata->parent_id = localph;
6300 * This function updates the MTP track object metadata on a
6301 * single file identified by an object ID.
6302 * @param device a pointer to the device to update the track
6304 * @param metadata a track metadata set to be written to the file.
6305 * notice that the <code>track_id</code> field of the
6306 * metadata structure must be correct so that the
6307 * function can update the right file. If some properties
6308 * of this metadata are set to NULL (strings) or 0
6309 * (numerical values) they will be discarded and the
6310 * track will not be tagged with these blank values.
6311 * @return 0 on success, any other value means failure. If some
6312 * or all of the properties fail to update we will still
6313 * return success. On some devices (notably iRiver T30)
6314 * properties that exist cannot be updated.
6316 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6317 LIBMTP_track_t const * const metadata)
6320 PTPParams *params = (PTPParams *) device->params;
6321 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6323 uint16_t *properties = NULL;
6324 uint32_t propcnt = 0;
6326 // First see which properties can be set on this file format and apply accordingly
6327 // i.e only try to update this metadata for object tags that exist on the current player.
6328 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6329 if (ret != PTP_RC_OK) {
6330 // Just bail out for now, nothing is ever set.
6331 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6332 "could not retrieve supported object properties.");
6335 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6336 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6337 MTPProperties *props = NULL;
6338 MTPProperties *prop = NULL;
6341 for (i=0;i<propcnt;i++) {
6342 PTPObjectPropDesc opd;
6344 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6345 if (ret != PTP_RC_OK) {
6346 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6347 "could not get property description.");
6348 } else if (opd.GetSet) {
6349 switch (properties[i]) {
6351 if (metadata->title == NULL)
6353 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6354 prop->ObjectHandle = metadata->item_id;
6355 prop->property = PTP_OPC_Name;
6356 prop->datatype = PTP_DTC_STR;
6357 prop->propval.str = strdup(metadata->title);
6359 case PTP_OPC_AlbumName:
6360 if (metadata->album == NULL)
6362 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6363 prop->ObjectHandle = metadata->item_id;
6364 prop->property = PTP_OPC_AlbumName;
6365 prop->datatype = PTP_DTC_STR;
6366 prop->propval.str = strdup(metadata->album);
6368 case PTP_OPC_Artist:
6369 if (metadata->artist == NULL)
6371 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6372 prop->ObjectHandle = metadata->item_id;
6373 prop->property = PTP_OPC_Artist;
6374 prop->datatype = PTP_DTC_STR;
6375 prop->propval.str = strdup(metadata->artist);
6377 case PTP_OPC_Composer:
6378 if (metadata->composer == NULL)
6380 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6381 prop->ObjectHandle = metadata->item_id;
6382 prop->property = PTP_OPC_Composer;
6383 prop->datatype = PTP_DTC_STR;
6384 prop->propval.str = strdup(metadata->composer);
6387 if (metadata->genre == NULL)
6389 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6390 prop->ObjectHandle = metadata->item_id;
6391 prop->property = PTP_OPC_Genre;
6392 prop->datatype = PTP_DTC_STR;
6393 prop->propval.str = strdup(metadata->genre);
6395 case PTP_OPC_Duration:
6396 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6397 prop->ObjectHandle = metadata->item_id;
6398 prop->property = PTP_OPC_Duration;
6399 prop->datatype = PTP_DTC_UINT32;
6400 prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6403 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6404 prop->ObjectHandle = metadata->item_id;
6405 prop->property = PTP_OPC_Track;
6406 prop->datatype = PTP_DTC_UINT16;
6407 prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6409 case PTP_OPC_OriginalReleaseDate:
6410 if (metadata->date == NULL)
6412 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6413 prop->ObjectHandle = metadata->item_id;
6414 prop->property = PTP_OPC_OriginalReleaseDate;
6415 prop->datatype = PTP_DTC_STR;
6416 prop->propval.str = strdup(metadata->date);
6418 case PTP_OPC_SampleRate:
6419 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6420 prop->ObjectHandle = metadata->item_id;
6421 prop->property = PTP_OPC_SampleRate;
6422 prop->datatype = PTP_DTC_UINT32;
6423 prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6425 case PTP_OPC_NumberOfChannels:
6426 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6427 prop->ObjectHandle = metadata->item_id;
6428 prop->property = PTP_OPC_NumberOfChannels;
6429 prop->datatype = PTP_DTC_UINT16;
6430 prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6432 case PTP_OPC_AudioWAVECodec:
6433 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6434 prop->ObjectHandle = metadata->item_id;
6435 prop->property = PTP_OPC_AudioWAVECodec;
6436 prop->datatype = PTP_DTC_UINT32;
6437 prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6439 case PTP_OPC_AudioBitRate:
6440 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6441 prop->ObjectHandle = metadata->item_id;
6442 prop->property = PTP_OPC_AudioBitRate;
6443 prop->datatype = PTP_DTC_UINT32;
6444 prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6446 case PTP_OPC_BitRateType:
6447 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6448 prop->ObjectHandle = metadata->item_id;
6449 prop->property = PTP_OPC_BitRateType;
6450 prop->datatype = PTP_DTC_UINT16;
6451 prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6453 case PTP_OPC_Rating:
6454 // TODO: shall this be set for rating 0?
6455 if (metadata->rating == 0)
6457 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6458 prop->ObjectHandle = metadata->item_id;
6459 prop->property = PTP_OPC_Rating;
6460 prop->datatype = PTP_DTC_UINT16;
6461 prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6463 case PTP_OPC_UseCount:
6464 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6465 prop->ObjectHandle = metadata->item_id;
6466 prop->property = PTP_OPC_UseCount;
6467 prop->datatype = PTP_DTC_UINT32;
6468 prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6470 case PTP_OPC_DateModified:
6471 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6472 // Tag with current time if that is supported
6473 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6474 prop->ObjectHandle = metadata->item_id;
6475 prop->property = PTP_OPC_DateModified;
6476 prop->datatype = PTP_DTC_STR;
6477 prop->propval.str = get_iso8601_stamp();
6484 ptp_free_objectpropdesc(&opd);
6487 // NOTE: File size is not updated, this should not change anyway.
6488 // neither will we change the filename.
6490 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6492 ptp_destroy_object_prop_list(props, nrofprops);
6494 if (ret != PTP_RC_OK) {
6495 // TODO: return error of which property we couldn't set
6496 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6497 "could not set object property list.");
6502 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6503 for (i=0;i<propcnt;i++) {
6504 PTPObjectPropDesc opd;
6506 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6507 if (ret != PTP_RC_OK) {
6508 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6509 "could not get property description.");
6510 } else if (opd.GetSet) {
6511 switch (properties[i]) {
6514 ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6516 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6517 "could not set track title.");
6520 case PTP_OPC_AlbumName:
6522 ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6524 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6525 "could not set track album name.");
6528 case PTP_OPC_Artist:
6530 ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6532 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6533 "could not set track artist name.");
6536 case PTP_OPC_Composer:
6538 ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6540 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6541 "could not set track composer name.");
6545 // Update genre (but only if valid)
6546 if (metadata->genre) {
6547 ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6549 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6550 "could not set genre.");
6554 case PTP_OPC_Duration:
6556 if (metadata->duration != 0) {
6557 ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6559 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6560 "could not set track duration.");
6565 // Update track number.
6566 if (metadata->tracknumber != 0) {
6567 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6569 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6570 "could not set track tracknumber.");
6574 case PTP_OPC_OriginalReleaseDate:
6575 // Update creation datetime
6576 // The date can be zero, but some devices do not support setting zero
6577 // dates (and it seems that a zero date should never be set anyway)
6578 if (metadata->date) {
6579 ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6581 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6582 "could not set track release date.");
6586 // These are, well not so important.
6587 case PTP_OPC_SampleRate:
6588 // Update sample rate
6589 if (metadata->samplerate != 0) {
6590 ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6592 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6593 "could not set samplerate.");
6597 case PTP_OPC_NumberOfChannels:
6598 // Update number of channels
6599 if (metadata->nochannels != 0) {
6600 ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6602 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6603 "could not set number of channels.");
6607 case PTP_OPC_AudioWAVECodec:
6608 // Update WAVE codec
6609 if (metadata->wavecodec != 0) {
6610 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6612 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6613 "could not set WAVE codec.");
6617 case PTP_OPC_AudioBitRate:
6619 if (metadata->bitrate != 0) {
6620 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6622 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6623 "could not set bitrate.");
6627 case PTP_OPC_BitRateType:
6628 // Update bitrate type
6629 if (metadata->bitratetype != 0) {
6630 ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6632 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6633 "could not set bitratetype.");
6637 case PTP_OPC_Rating:
6638 // Update user rating
6639 // TODO: shall this be set for rating 0?
6640 if (metadata->rating != 0) {
6641 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6643 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6644 "could not set user rating.");
6648 case PTP_OPC_UseCount:
6649 // Update use count, set even to zero if desired.
6650 ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6652 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6653 "could not set use count.");
6656 case PTP_OPC_DateModified:
6657 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6658 // Update modification time if supported
6659 char *tmpstamp = get_iso8601_stamp();
6660 ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6662 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6663 "could not set modification date.");
6669 // NOTE: File size is not updated, this should not change anyway.
6670 // neither will we change the filename.
6675 ptp_free_objectpropdesc(&opd);
6678 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6679 "Your device doesn't seem to support any known way of setting metadata.");
6684 // update cached object properties if metadata cache exists
6685 update_metadata_cache(device, metadata->item_id);
6693 * This function deletes a single file, track, playlist, folder or
6694 * any other object off the MTP device, identified by the object ID.
6696 * If you delete a folder, there is no guarantee that the device will
6697 * really delete all the files that were in that folder, rather it is
6698 * expected that they will not be deleted, and will turn up in object
6699 * listings with parent set to a non-existant object ID. The safe way
6700 * to do this is to recursively delete all files (and folders) contained
6701 * in the folder, then the folder itself.
6703 * @param device a pointer to the device to delete the object from.
6704 * @param object_id the object to delete.
6705 * @return 0 on success, any other value means failure.
6707 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6711 PTPParams *params = (PTPParams *) device->params;
6713 ret = ptp_deleteobject(params, object_id, 0);
6714 if (ret != PTP_RC_OK) {
6715 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6723 * Internal function to update an object filename property.
6725 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6726 uint32_t object_id, uint16_t ptp_type,
6727 const char **newname_ptr)
6729 PTPParams *params = (PTPParams *) device->params;
6730 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6731 PTPObjectPropDesc opd;
6735 // See if we can modify the filename on this kind of files.
6736 ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6737 if (ret != PTP_RC_OK) {
6738 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6739 "could not get property description.");
6744 ptp_free_objectpropdesc(&opd);
6745 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6746 " property is not settable.");
6747 // TODO: we COULD actually upload/download the object here, if we feel
6748 // like wasting time for the user.
6752 newname = strdup(*newname_ptr);
6754 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6755 strip_7bit_from_utf8(newname);
6758 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6759 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6760 MTPProperties *props = NULL;
6761 MTPProperties *prop = NULL;
6764 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6765 prop->ObjectHandle = object_id;
6766 prop->property = PTP_OPC_ObjectFileName;
6767 prop->datatype = PTP_DTC_STR;
6768 prop->propval.str = newname;
6770 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6772 ptp_destroy_object_prop_list(props, nrofprops);
6774 if (ret != PTP_RC_OK) {
6775 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6776 " could not set object property list.");
6777 ptp_free_objectpropdesc(&opd);
6780 } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6781 ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6783 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6784 " could not set object filename.");
6785 ptp_free_objectpropdesc(&opd);
6790 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6791 " your device doesn't seem to support any known way of setting metadata.");
6792 ptp_free_objectpropdesc(&opd);
6796 ptp_free_objectpropdesc(&opd);
6798 // update cached object properties if metadata cache exists
6799 update_metadata_cache(device, object_id);
6805 * This function renames a single file.
6806 * This simply means that the PTP_OPC_ObjectFileName property
6807 * is updated, if this is supported by the device.
6809 * @param device a pointer to the device that contains the file.
6810 * @param file the file metadata of the file to rename.
6811 * On success, the filename member is updated. Be aware, that
6812 * this name can be different than newname depending of device restrictions.
6813 * @param newname the new filename for this object.
6814 * @return 0 on success, any other value means failure.
6816 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6817 LIBMTP_file_t *file, const char *newname)
6821 ret = set_object_filename(device, file->item_id,
6822 map_libmtp_type_to_ptp_type(file->filetype),
6829 free(file->filename);
6830 file->filename = strdup(newname);
6835 * This function renames a single folder.
6836 * This simply means that the PTP_OPC_ObjectFileName property
6837 * is updated, if this is supported by the device.
6839 * @param device a pointer to the device that contains the file.
6840 * @param folder the folder metadata of the folder to rename.
6841 * On success, the name member is updated. Be aware, that
6842 * this name can be different than newname depending of device restrictions.
6843 * @param newname the new name for this object.
6844 * @return 0 on success, any other value means failure.
6846 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6847 LIBMTP_folder_t *folder, const char* newname)
6851 ret = set_object_filename(device, folder->folder_id,
6852 PTP_OFC_Association,
6860 folder->name = strdup(newname);
6865 * This function renames a single track.
6866 * This simply means that the PTP_OPC_ObjectFileName property
6867 * is updated, if this is supported by the device.
6869 * @param device a pointer to the device that contains the file.
6870 * @param track the track metadata of the track to rename.
6871 * On success, the filename member is updated. Be aware, that
6872 * this name can be different than newname depending of device restrictions.
6873 * @param newname the new filename for this object.
6874 * @return 0 on success, any other value means failure.
6876 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6877 LIBMTP_track_t *track, const char* newname)
6881 ret = set_object_filename(device, track->item_id,
6882 map_libmtp_type_to_ptp_type(track->filetype),
6889 free(track->filename);
6890 track->filename = strdup(newname);
6895 * This function renames a single playlist object file holder.
6896 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6897 * property is updated, if this is supported by the device.
6898 * The playlist filename should nominally end with an extension
6901 * NOTE: if you want to change the metadata the device display
6902 * about a playlist you must <i>not</i> use this function,
6903 * use <code>LIBMTP_Update_Playlist()</code> instead!
6905 * @param device a pointer to the device that contains the file.
6906 * @param playlist the playlist metadata of the playlist to rename.
6907 * On success, the name member is updated. Be aware, that
6908 * this name can be different than newname depending of device restrictions.
6909 * @param newname the new name for this object.
6910 * @return 0 on success, any other value means failure.
6911 * @see LIBMTP_Update_Playlist()
6913 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
6914 LIBMTP_playlist_t *playlist, const char* newname)
6918 ret = set_object_filename(device, playlist->playlist_id,
6919 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
6926 free(playlist->name);
6927 playlist->name = strdup(newname);
6932 * This function renames a single album.
6933 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6934 * property is updated, if this is supported by the device.
6935 * The album filename should nominally end with an extension
6938 * NOTE: if you want to change the metadata the device display
6939 * about a playlist you must <i>not</i> use this function,
6940 * use <code>LIBMTP_Update_Album()</code> instead!
6942 * @param device a pointer to the device that contains the file.
6943 * @param album the album metadata of the album to rename.
6944 * On success, the name member is updated. Be aware, that
6945 * this name can be different than newname depending of device restrictions.
6946 * @param newname the new name for this object.
6947 * @return 0 on success, any other value means failure.
6948 * @see LIBMTP_Update_Album()
6950 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
6951 LIBMTP_album_t *album, const char* newname)
6955 ret = set_object_filename(device, album->album_id,
6956 PTP_OFC_MTP_AbstractAudioAlbum,
6964 album->name = strdup(newname);
6969 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
6972 * @see LIBMTP_Set_File_Name()
6973 * @see LIBMTP_Set_Track_Name()
6974 * @see LIBMTP_Set_Folder_Name()
6975 * @see LIBMTP_Set_Playlist_Name()
6976 * @see LIBMTP_Set_Album_Name()
6978 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
6979 uint32_t object_id, char* newname)
6982 LIBMTP_file_t *file;
6984 file = LIBMTP_Get_Filemetadata(device, object_id);
6987 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
6988 "could not get file metadata for target object.");
6992 ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7000 * Helper function. This indicates if a track exists on the device
7001 * @param device a pointer to the device to get the track from.
7002 * @param id the track ID of the track to retrieve.
7003 * @return TRUE (!=0) if the track exists, FALSE (0) if not
7005 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7008 PTPParams *params = (PTPParams *) device->params;
7012 ret = ptp_object_want (params, id, 0, &ob);
7013 if (ret == PTP_RC_OK)
7019 * This creates a new folder structure and allocates memory
7020 * for it. Notice that if you add strings to this structure they
7021 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7022 * operation later, so be careful of using strdup() when assigning
7025 * @return a pointer to the newly allocated folder structure.
7026 * @see LIBMTP_destroy_folder_t()
7028 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7030 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7036 new->storage_id = 0;
7038 new->sibling = NULL;
7044 * This recursively deletes the memory for a folder structure.
7045 * This shall typically be called on a top-level folder list to
7046 * detsroy the entire folder tree.
7048 * @param folder folder structure to destroy
7049 * @see LIBMTP_new_folder_t()
7051 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7054 if(folder == NULL) {
7058 //Destroy from the bottom up
7059 if(folder->child != NULL) {
7060 LIBMTP_destroy_folder_t(folder->child);
7063 if(folder->sibling != NULL) {
7064 LIBMTP_destroy_folder_t(folder->sibling);
7067 if(folder->name != NULL) {
7075 * Helper function. Returns a folder structure for a
7078 * @param folderlist list of folders to search
7079 * @id id of folder to look for
7080 * @return a folder or NULL if not found
7082 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7084 LIBMTP_folder_t *ret = NULL;
7086 if(folderlist == NULL) {
7090 if(folderlist->folder_id == id) {
7094 if(folderlist->sibling) {
7095 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7098 if(folderlist->child && ret == NULL) {
7099 ret = LIBMTP_Find_Folder(folderlist->child, id);
7106 * Function used to recursively get subfolders from params.
7108 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7110 LIBMTP_folder_t *retfolders = NULL;
7111 LIBMTP_folder_t *children, *iter, *curr;
7113 iter = list->sibling;
7114 while(iter != list) {
7115 if (iter->parent_id != parent) {
7116 iter = iter->sibling;
7120 /* We know that iter is a child of 'parent', therefore we can safely
7121 * hold on to 'iter' locally since no one else will steal it
7122 * from the 'list' as we recurse. */
7123 children = get_subfolders_for_folder(list, iter->folder_id);
7126 iter = iter->sibling;
7128 // Remove curr from the list.
7129 curr->child->sibling = curr->sibling;
7130 curr->sibling->child = curr->child;
7132 // Attach the children to curr.
7133 curr->child = children;
7135 // Put this folder into the list of siblings.
7136 curr->sibling = retfolders;
7144 * This returns a list of all folders available
7145 * on the current MTP device.
7147 * @param device a pointer to the device to get the folder listing for.
7148 * @param storage a storage ID to get the folder list from
7149 * @return a list of folders
7151 LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7152 uint32_t const storage)
7154 PTPParams *params = (PTPParams *) device->params;
7155 LIBMTP_folder_t head, *rv;
7158 // Get all the handles if we haven't already done that
7159 if (params->nrofobjects == 0) {
7160 flush_handles(device);
7164 * This creates a temporary list of the folders, this is in a
7165 * reverse order and uses the Folder pointers that are already
7166 * in the Folder structure. From this we can then build up the
7167 * folder hierarchy with only looking at this temporary list,
7168 * and removing the folders from this temporary list as we go.
7169 * This significantly reduces the number of operations that we
7170 * have to do in building the folder hierarchy. Also since the
7171 * temp list is in reverse order, when we prepend to the sibling
7172 * list things are in the same order as they were originally
7173 * in the handle list.
7175 head.sibling = &head;
7177 for (i = 0; i < params->nrofobjects; i++) {
7178 LIBMTP_folder_t *folder;
7181 ob = ¶ms->objects[i];
7182 if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7186 if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7191 * Do we know how to handle these? They are part
7192 * of the MTP 1.0 specification paragraph 3.6.4.
7193 * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7194 * should be called on these to get the contained objects, but
7195 * we basically don't care. Hopefully parent_id is maintained for all
7196 * children, because we rely on that instead.
7198 if (ob->oi.AssociationDesc != 0x00000000U) {
7199 LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7202 // Create a folder struct...
7203 folder = LIBMTP_new_folder_t();
7204 if (folder == NULL) {
7205 // malloc failure or so.
7208 folder->folder_id = ob->oid;
7209 folder->parent_id = ob->oi.ParentObject;
7210 folder->storage_id = ob->oi.StorageID;
7211 folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7213 // pretend sibling says next, and child says prev.
7214 folder->sibling = head.sibling;
7215 folder->child = &head;
7216 head.sibling->child = folder;
7217 head.sibling = folder;
7220 // We begin at the given root folder and get them all recursively
7221 rv = get_subfolders_for_folder(&head, 0x00000000U);
7223 // Some buggy devices may have some files in the "root folder"
7224 // 0xffffffff so if 0x00000000 didn't return any folders,
7225 // look for children of the root 0xffffffffU
7227 rv = get_subfolders_for_folder(&head, 0xffffffffU);
7229 LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7230 "this is a firmware bug (but continuing)\n");
7233 // The temp list should be empty. Clean up any orphans just in case.
7234 while(head.sibling != &head) {
7235 LIBMTP_folder_t *curr = head.sibling;
7237 LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7240 curr->sibling->child = curr->child;
7241 curr->child->sibling = curr->sibling;
7243 curr->sibling = NULL;
7244 LIBMTP_destroy_folder_t(curr);
7251 * This returns a list of all folders available
7252 * on the current MTP device.
7254 * @param device a pointer to the device to get the folder listing for.
7255 * @return a list of folders
7257 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7259 return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7263 * This create a folder on the current MTP device. The PTP name
7264 * for a folder is "association". The PTP/MTP devices does not
7265 * have an internal "folder" concept really, it contains a flat
7266 * list of all files and some file are "associations" that other
7267 * files and folders may refer to as its "parent".
7269 * @param device a pointer to the device to create the folder on.
7270 * @param name the name of the new folder. Note this can be modified
7271 * if the device does not support all the characters in the
7273 * @param parent_id id of parent folder to add the new folder to,
7274 * or 0xFFFFFFFF to put it in the root directory.
7275 * @param storage_id id of the storage to add this new folder to.
7276 * notice that you cannot mismatch storage id and parent id:
7277 * they must both be on the same storage! Pass in 0 if you
7278 * want to create this folder on the default storage.
7279 * @return id to new folder or 0 if an error occured
7281 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7282 uint32_t parent_id, uint32_t storage_id)
7284 PTPParams *params = (PTPParams *) device->params;
7285 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7286 uint32_t parenthandle = 0;
7288 PTPObjectInfo new_folder;
7290 uint32_t new_id = 0;
7292 if (storage_id == 0) {
7293 // I'm just guessing that a folder may require 512 bytes
7294 store = get_suggested_storage_id(device, 512, parent_id);
7298 parenthandle = parent_id;
7300 memset(&new_folder, 0, sizeof(new_folder));
7301 new_folder.Filename = name;
7302 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7303 strip_7bit_from_utf8(new_folder.Filename);
7305 new_folder.ObjectCompressedSize = 0;
7306 new_folder.ObjectFormat = PTP_OFC_Association;
7307 new_folder.ProtectionStatus = PTP_PS_NoProtection;
7308 new_folder.AssociationType = PTP_AT_GenericFolder;
7309 new_folder.ParentObject = parent_id;
7310 new_folder.StorageID = store;
7312 // Create the object
7313 if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7314 ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7315 MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7317 props[0].property = PTP_OPC_ObjectFileName;
7318 props[0].datatype = PTP_DTC_STR;
7319 props[0].propval.str = name;
7321 props[1].property = PTP_OPC_Name;
7322 props[1].datatype = PTP_DTC_STR;
7323 props[1].propval.str = name;
7325 ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7329 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7332 if (ret != PTP_RC_OK) {
7333 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7334 if (ret == PTP_RC_AccessDenied) {
7335 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7339 // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7342 add_object_to_cache(device, new_id);
7348 * This creates a new playlist metadata structure and allocates memory
7349 * for it. Notice that if you add strings to this structure they
7350 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7351 * operation later, so be careful of using strdup() when assigning
7355 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7356 * pl->name = strdup(str);
7358 * LIBMTP_destroy_playlist_t(pl);
7361 * @return a pointer to the newly allocated metadata structure.
7362 * @see LIBMTP_destroy_playlist_t()
7364 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7366 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7370 new->playlist_id = 0;
7372 new->storage_id = 0;
7381 * This destroys a playlist metadata structure and deallocates the memory
7382 * used by it, including any strings. Never use a track metadata
7383 * structure again after calling this function on it.
7384 * @param playlist the playlist metadata to destroy.
7385 * @see LIBMTP_new_playlist_t()
7387 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7389 if (playlist == NULL) {
7392 if (playlist->name != NULL)
7393 free(playlist->name);
7394 if (playlist->tracks != NULL)
7395 free(playlist->tracks);
7401 * This function returns a list of the playlists available on the
7402 * device. Typical usage:
7407 * @param device a pointer to the device to get the playlist listing from.
7408 * @return a playlist list on success, else NULL. If there are no playlists
7409 * on the device, NULL will be returned as well.
7410 * @see LIBMTP_Get_Playlist()
7412 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7414 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7415 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7416 PTPParams *params = (PTPParams *) device->params;
7417 LIBMTP_playlist_t *retlists = NULL;
7418 LIBMTP_playlist_t *curlist = NULL;
7421 // Get all the handles if we haven't already done that
7422 if (params->nrofobjects == 0) {
7423 flush_handles(device);
7426 for (i = 0; i < params->nrofobjects; i++) {
7427 LIBMTP_playlist_t *pl;
7431 ob = ¶ms->objects[i];
7433 // Ignore stuff that isn't playlists
7435 // For Samsung players we must look for the .spl extension explicitly since
7436 // playlists are not stored as playlist objects.
7437 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7438 // Allocate a new playlist type
7439 pl = LIBMTP_new_playlist_t();
7440 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7442 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7446 // Allocate a new playlist type
7447 pl = LIBMTP_new_playlist_t();
7449 // Try to look up proper name, else use the oi->Filename field.
7450 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7451 if (pl->name == NULL) {
7452 pl->name = strdup(ob->oi.Filename);
7454 pl->playlist_id = ob->oid;
7455 pl->parent_id = ob->oi.ParentObject;
7456 pl->storage_id = ob->oi.StorageID;
7458 // Then get the track listing for this playlist
7459 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7460 if (ret != PTP_RC_OK) {
7461 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7462 "could not get object references.");
7468 // Add playlist to a list that will be returned afterwards.
7469 if (retlists == NULL) {
7477 // Call callback here if we decide to add that possibility...
7484 * This function retrieves an individual playlist from the device.
7485 * @param device a pointer to the device to get the playlist from.
7486 * @param plid the unique ID of the playlist to retrieve.
7487 * @return a valid playlist metadata post or NULL on failure.
7488 * @see LIBMTP_Get_Playlist_List()
7490 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7492 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7493 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7494 PTPParams *params = (PTPParams *) device->params;
7496 LIBMTP_playlist_t *pl;
7499 // Get all the handles if we haven't already done that
7500 if (params->nrofobjects == 0) {
7501 flush_handles(device);
7504 ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7505 if (ret != PTP_RC_OK)
7508 // For Samsung players we must look for the .spl extension explicitly since
7509 // playlists are not stored as playlist objects.
7510 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7511 // Allocate a new playlist type
7512 pl = LIBMTP_new_playlist_t();
7513 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7517 // Ignore stuff that isn't playlists
7518 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7522 // Allocate a new playlist type
7523 pl = LIBMTP_new_playlist_t();
7525 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7526 if (pl->name == NULL) {
7527 pl->name = strdup(ob->oi.Filename);
7529 pl->playlist_id = ob->oid;
7530 pl->parent_id = ob->oi.ParentObject;
7531 pl->storage_id = ob->oi.StorageID;
7533 // Then get the track listing for this playlist
7534 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7535 if (ret != PTP_RC_OK) {
7536 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7545 * This function creates a new abstract list such as a playlist
7548 * @param device a pointer to the device to create the new abstract list
7550 * @param name the name of the new abstract list.
7551 * @param artist the artist of the new abstract list or NULL.
7552 * @param genre the genre of the new abstract list or NULL.
7553 * @param parenthandle the handle of the parent or 0 for no parent
7554 * i.e. the root folder.
7555 * @param objectformat the abstract list type to create.
7556 * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7557 * "file" created by this operation.
7558 * @param newid a pointer to a variable that will hold the new object
7559 * ID if this call is successful.
7560 * @param tracks an array of tracks to associate with this list.
7561 * @param no_tracks the number of tracks in the list.
7562 * @return 0 on success, any other value means failure.
7564 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7565 char const * const name,
7566 char const * const artist,
7567 char const * const composer,
7568 char const * const genre,
7569 uint32_t const parenthandle,
7570 uint32_t const storageid,
7571 uint16_t const objectformat,
7572 char const * const suffix,
7573 uint32_t * const newid,
7574 uint32_t const * const tracks,
7575 uint32_t const no_tracks)
7581 uint16_t *properties = NULL;
7582 uint32_t propcnt = 0;
7584 uint32_t localph = parenthandle;
7585 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7586 PTPParams *params = (PTPParams *) device->params;
7587 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7593 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7597 if (storageid == 0) {
7598 // I'm just guessing that an abstract list may require 512 bytes
7599 store = get_suggested_storage_id(device, 512, localph);
7604 // Check if we can create an object of this type
7605 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7606 if (params->deviceinfo.ImageFormats[i] == objectformat) {
7612 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7613 LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7617 // add the new suffix if it isn't there
7619 if (strlen(name) > strlen(suffix)) {
7620 char const * const suff = &name[strlen(name)-strlen(suffix)];
7621 if (!strcmp(suff, suffix)) {
7623 strncpy(fname, name, sizeof(fname));
7626 // If it didn't end with "<suffix>" then add that here.
7627 if (fname[0] == '\0') {
7628 strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7629 strcat(fname, suffix);
7630 fname[sizeof(fname)-1] = '\0';
7633 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7634 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7635 MTPProperties *props = NULL;
7636 MTPProperties *prop = NULL;
7639 *newid = 0x00000000U;
7641 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7643 for (i=0;i<propcnt;i++) {
7644 PTPObjectPropDesc opd;
7646 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7647 if (ret != PTP_RC_OK) {
7648 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7649 "could not get property description.");
7650 } else if (opd.GetSet) {
7651 switch (properties[i]) {
7652 case PTP_OPC_ObjectFileName:
7653 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7654 prop->ObjectHandle = *newid;
7655 prop->property = PTP_OPC_ObjectFileName;
7656 prop->datatype = PTP_DTC_STR;
7657 prop->propval.str = strdup(fname);
7658 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7659 strip_7bit_from_utf8(prop->propval.str);
7662 case PTP_OPC_ProtectionStatus:
7663 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7664 prop->ObjectHandle = *newid;
7665 prop->property = PTP_OPC_ProtectionStatus;
7666 prop->datatype = PTP_DTC_UINT16;
7667 prop->propval.u16 = 0x0000U; /* Not protected */
7669 case PTP_OPC_NonConsumable:
7670 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7671 prop->ObjectHandle = *newid;
7672 prop->property = PTP_OPC_NonConsumable;
7673 prop->datatype = PTP_DTC_UINT8;
7674 prop->propval.u8 = nonconsumable;
7678 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7679 prop->ObjectHandle = *newid;
7680 prop->property = PTP_OPC_Name;
7681 prop->datatype = PTP_DTC_STR;
7682 prop->propval.str = strdup(name);
7685 case PTP_OPC_AlbumArtist:
7686 if (artist != NULL) {
7687 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7688 prop->ObjectHandle = *newid;
7689 prop->property = PTP_OPC_AlbumArtist;
7690 prop->datatype = PTP_DTC_STR;
7691 prop->propval.str = strdup(artist);
7694 case PTP_OPC_Artist:
7695 if (artist != NULL) {
7696 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7697 prop->ObjectHandle = *newid;
7698 prop->property = PTP_OPC_Artist;
7699 prop->datatype = PTP_DTC_STR;
7700 prop->propval.str = strdup(artist);
7703 case PTP_OPC_Composer:
7704 if (composer != NULL) {
7705 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7706 prop->ObjectHandle = *newid;
7707 prop->property = PTP_OPC_Composer;
7708 prop->datatype = PTP_DTC_STR;
7709 prop->propval.str = strdup(composer);
7713 if (genre != NULL) {
7714 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7715 prop->ObjectHandle = *newid;
7716 prop->property = PTP_OPC_Genre;
7717 prop->datatype = PTP_DTC_STR;
7718 prop->propval.str = strdup(genre);
7721 case PTP_OPC_DateModified:
7722 // Tag with current time if that is supported
7723 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7724 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7725 prop->ObjectHandle = *newid;
7726 prop->property = PTP_OPC_DateModified;
7727 prop->datatype = PTP_DTC_STR;
7728 prop->propval.str = get_iso8601_stamp();
7733 ptp_free_objectpropdesc(&opd);
7737 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7738 objectformat, 0, props, nrofprops);
7740 /* Free property list */
7741 ptp_destroy_object_prop_list(props, nrofprops);
7743 if (ret != PTP_RC_OK) {
7744 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7745 if (ret == PTP_RC_AccessDenied) {
7746 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7751 // now send the blank object
7752 ret = ptp_sendobject(params, NULL, 0);
7753 if (ret != PTP_RC_OK) {
7754 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7758 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7759 PTPObjectInfo new_object;
7761 new_object.Filename = fname;
7762 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7763 strip_7bit_from_utf8(new_object.Filename);
7765 // At one point this had to be one
7766 new_object.ObjectCompressedSize = 0;
7767 new_object.ObjectFormat = objectformat;
7769 // Create the object
7770 ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7771 if (ret != PTP_RC_OK) {
7772 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7773 if (ret == PTP_RC_AccessDenied) {
7774 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7778 // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7783 * At one time we had to send this one blank data byte.
7784 * If we didn't, the handle will not be created and thus there is
7785 * no playlist. Possibly this was masking some bug, so removing it
7790 ret = ptp_sendobject(params, data, 1);
7791 if (ret != PTP_RC_OK) {
7792 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7797 // set the properties one by one
7798 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7800 for (i=0;i<propcnt;i++) {
7801 PTPObjectPropDesc opd;
7803 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7804 if (ret != PTP_RC_OK) {
7805 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7806 "could not get property description.");
7807 } else if (opd.GetSet) {
7808 switch (properties[i]) {
7811 ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7813 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7818 case PTP_OPC_AlbumArtist:
7819 if (artist != NULL) {
7820 ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7822 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7827 case PTP_OPC_Artist:
7828 if (artist != NULL) {
7829 ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7831 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7836 case PTP_OPC_Composer:
7837 if (composer != NULL) {
7838 ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7840 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7846 if (genre != NULL) {
7847 ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7849 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7854 case PTP_OPC_DateModified:
7855 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7856 ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7858 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7865 ptp_free_objectpropdesc(&opd);
7870 if (no_tracks > 0) {
7871 // Add tracks to the list as object references.
7872 ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7873 if (ret != PTP_RC_OK) {
7874 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7879 add_object_to_cache(device, *newid);
7885 * This updates the metadata and track listing
7886 * for an abstract list.
7887 * @param device a pointer to the device that the abstract list
7889 * @param name the name of the abstract list.
7890 * @param artist the artist of the abstract list or NULL.
7891 * @param genre the genre of the abstract list or NULL.
7892 * @param objecthandle the object to be updated.
7893 * @param objectformat the abstract list type to update.
7894 * @param tracks an array of tracks to associate with this list.
7895 * @param no_tracks the number of tracks in the list.
7896 * @return 0 on success, any other value means failure.
7898 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7899 char const * const name,
7900 char const * const artist,
7901 char const * const composer,
7902 char const * const genre,
7903 uint32_t const objecthandle,
7904 uint16_t const objectformat,
7905 uint32_t const * const tracks,
7906 uint32_t const no_tracks)
7909 PTPParams *params = (PTPParams *) device->params;
7910 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7911 uint16_t *properties = NULL;
7912 uint32_t propcnt = 0;
7915 // First see which properties can be set
7916 // i.e only try to update this metadata for object tags that exist on the current player.
7917 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7918 if (ret != PTP_RC_OK) {
7919 // Just bail out for now, nothing is ever set.
7920 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7921 "could not retrieve supported object properties.");
7924 if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
7925 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
7926 MTPProperties *props = NULL;
7927 MTPProperties *prop = NULL;
7930 for (i=0;i<propcnt;i++) {
7931 PTPObjectPropDesc opd;
7933 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7934 if (ret != PTP_RC_OK) {
7935 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7936 "could not get property description.");
7937 } else if (opd.GetSet) {
7938 switch (properties[i]) {
7940 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7941 prop->ObjectHandle = objecthandle;
7942 prop->property = PTP_OPC_Name;
7943 prop->datatype = PTP_DTC_STR;
7945 prop->propval.str = strdup(name);
7947 case PTP_OPC_AlbumArtist:
7948 if (artist != NULL) {
7949 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7950 prop->ObjectHandle = objecthandle;
7951 prop->property = PTP_OPC_AlbumArtist;
7952 prop->datatype = PTP_DTC_STR;
7953 prop->propval.str = strdup(artist);
7956 case PTP_OPC_Artist:
7957 if (artist != NULL) {
7958 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7959 prop->ObjectHandle = objecthandle;
7960 prop->property = PTP_OPC_Artist;
7961 prop->datatype = PTP_DTC_STR;
7962 prop->propval.str = strdup(artist);
7965 case PTP_OPC_Composer:
7966 if (composer != NULL) {
7967 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7968 prop->ObjectHandle = objecthandle;
7969 prop->property = PTP_OPC_Composer;
7970 prop->datatype = PTP_DTC_STR;
7971 prop->propval.str = strdup(composer);
7975 if (genre != NULL) {
7976 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7977 prop->ObjectHandle = objecthandle;
7978 prop->property = PTP_OPC_Genre;
7979 prop->datatype = PTP_DTC_STR;
7980 prop->propval.str = strdup(genre);
7983 case PTP_OPC_DateModified:
7984 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7985 // Tag with current time if that is supported
7986 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7987 prop->ObjectHandle = objecthandle;
7988 prop->property = PTP_OPC_DateModified;
7989 prop->datatype = PTP_DTC_STR;
7990 prop->propval.str = get_iso8601_stamp();
7997 ptp_free_objectpropdesc(&opd);
8000 // proplist could be NULL if we can't write any properties
8001 if (props != NULL) {
8002 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8004 ptp_destroy_object_prop_list(props, nrofprops);
8006 if (ret != PTP_RC_OK) {
8007 // TODO: return error of which property we couldn't set
8008 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8009 "could not set object property list.");
8015 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8016 for (i=0;i<propcnt;i++) {
8017 switch (properties[i]) {
8020 ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8022 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8023 "could not set title.");
8026 case PTP_OPC_AlbumArtist:
8027 // Update album artist
8028 ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8030 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8031 "could not set album artist name.");
8034 case PTP_OPC_Artist:
8036 ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8038 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8039 "could not set artist name.");
8042 case PTP_OPC_Composer:
8044 ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8046 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8047 "could not set composer name.");
8051 // Update genre (but only if valid)
8053 ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8055 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8056 "could not set genre.");
8060 case PTP_OPC_DateModified:
8061 // Update date modified
8062 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8063 char *tmpdate = get_iso8601_stamp();
8064 ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8066 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8067 "could not set modification date.");
8077 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8078 "Your device doesn't seem to support any known way of setting metadata.");
8083 // Then the object references...
8084 ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8085 if (ret != PTP_RC_OK) {
8086 add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8093 update_metadata_cache(device, objecthandle);
8100 * This routine creates a new playlist based on the metadata
8101 * supplied. If the <code>tracks</code> field of the metadata
8102 * contains a track listing, these tracks will be added to the
8104 * @param device a pointer to the device to create the new playlist on.
8105 * @param metadata the metadata for the new playlist. If the function
8106 * exits with success, the <code>playlist_id</code> field of this
8107 * struct will contain the new playlist ID of the playlist.
8109 * <li><code>metadata->parent_id</code> should be set to the parent
8110 * (e.g. folder) to store this track in. Since some
8111 * devices are a bit picky about where files
8112 * are placed, a default folder will be chosen if libmtp
8113 * has detected one for the current filetype and this
8114 * parameter is set to 0. If this is 0 and no default folder
8115 * can be found, the file will be stored in the root folder.
8116 * <li><code>metadata->storage_id</code> should be set to the
8117 * desired storage (e.g. memory card or whatever your device
8118 * presents) to store this track in. Setting this to 0 will store
8119 * the track on the primary storage.
8121 * @return 0 on success, any other value means failure.
8122 * @see LIBMTP_Update_Playlist()
8123 * @see LIBMTP_Delete_Object()
8125 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8126 LIBMTP_playlist_t * const metadata)
8128 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8129 uint32_t localph = metadata->parent_id;
8131 // Use a default folder if none given
8133 if (device->default_playlist_folder != 0)
8134 localph = device->default_playlist_folder;
8136 localph = device->default_music_folder;
8138 metadata->parent_id = localph;
8140 // Samsung needs its own special type of playlists
8141 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8142 return playlist_t_to_spl(device, metadata);
8145 // Just create a new abstract audio/video playlist...
8146 return create_new_abstract_list(device,
8152 metadata->storage_id,
8153 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8154 get_playlist_extension(ptp_usb),
8155 &metadata->playlist_id,
8157 metadata->no_tracks);
8161 * This routine updates a playlist based on the metadata
8162 * supplied. If the <code>tracks</code> field of the metadata
8163 * contains a track listing, these tracks will be added to the
8164 * playlist in place of those already present, i.e. the
8165 * previous track listing will be deleted. For Samsung devices the
8166 * playlist id (metadata->playlist_id) is likely to change.
8167 * @param device a pointer to the device to create the new playlist on.
8168 * @param metadata the metadata for the playlist to be updated.
8169 * notice that the field <code>playlist_id</code>
8170 * must contain the apropriate playlist ID. Playlist ID
8171 * be modified to a new playlist ID by the time the
8172 * function returns since edit-in-place is not always possible.
8173 * @return 0 on success, any other value means failure.
8174 * @see LIBMTP_Create_New_Playlist()
8175 * @see LIBMTP_Delete_Object()
8177 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8178 LIBMTP_playlist_t * const metadata)
8181 // Samsung needs its own special type of playlists
8182 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8183 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8184 return update_spl_playlist(device, metadata);
8187 return update_abstract_list(device,
8192 metadata->playlist_id,
8193 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8195 metadata->no_tracks);
8199 * This creates a new album metadata structure and allocates memory
8200 * for it. Notice that if you add strings to this structure they
8201 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8202 * operation later, so be careful of using strdup() when assigning
8205 * @return a pointer to the newly allocated metadata structure.
8206 * @see LIBMTP_destroy_album_t()
8208 LIBMTP_album_t *LIBMTP_new_album_t(void)
8210 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8216 new->storage_id = 0;
8219 new->composer = NULL;
8228 * This recursively deletes the memory for an album structure
8230 * @param album structure to destroy
8231 * @see LIBMTP_new_album_t()
8233 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8235 if (album == NULL) {
8238 if (album->name != NULL)
8240 if (album->artist != NULL)
8241 free(album->artist);
8242 if (album->composer != NULL)
8243 free(album->composer);
8244 if (album->genre != NULL)
8246 if (album->tracks != NULL)
8247 free(album->tracks);
8253 * This function maps and copies a property onto the album metadata if applicable.
8255 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8256 MTPProperties *prop, LIBMTP_album_t *alb)
8258 switch (prop->property) {
8260 if (prop->propval.str != NULL)
8261 alb->name = strdup(prop->propval.str);
8265 case PTP_OPC_AlbumArtist:
8266 if (prop->propval.str != NULL) {
8267 // This should take precedence over plain "Artist"
8268 if (alb->artist != NULL)
8270 alb->artist = strdup(prop->propval.str);
8274 case PTP_OPC_Artist:
8275 if (prop->propval.str != NULL) {
8276 // Only use of AlbumArtist is not set
8277 if (alb->artist == NULL)
8278 alb->artist = strdup(prop->propval.str);
8282 case PTP_OPC_Composer:
8283 if (prop->propval.str != NULL)
8284 alb->composer = strdup(prop->propval.str);
8286 alb->composer = NULL;
8289 if (prop->propval.str != NULL)
8290 alb->genre = strdup(prop->propval.str);
8298 * This function retrieves the album metadata for an album
8299 * given by a unique ID.
8300 * @param device a pointer to the device to get the track metadata off.
8301 * @param alb an album metadata metadata set to fill in.
8303 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8304 LIBMTP_album_t *alb)
8307 PTPParams *params = (PTPParams *) device->params;
8309 MTPProperties *prop;
8313 * If we have a cached, large set of metadata, then use it!
8315 ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8317 prop = ob->mtpprops;
8318 for (i=0;i<ob->nrofmtpprops;i++,prop++)
8319 pick_property_to_album_metadata(device, prop, alb);
8321 uint16_t *props = NULL;
8322 uint32_t propcnt = 0;
8324 // First see which properties can be retrieved for albums
8325 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8326 if (ret != PTP_RC_OK) {
8327 add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8328 // Just bail out for now, nothing is ever set.
8331 for (i=0;i<propcnt;i++) {
8334 alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8336 case PTP_OPC_AlbumArtist:
8337 if (alb->artist != NULL)
8339 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8341 case PTP_OPC_Artist:
8342 if (alb->artist == NULL)
8343 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8345 case PTP_OPC_Composer:
8346 alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8349 alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8362 * This function returns a list of the albums available on the
8365 * @param device a pointer to the device to get the album listing from.
8366 * @return an album list on success, else NULL. If there are no albums
8367 * on the device, NULL will be returned as well.
8368 * @see LIBMTP_Get_Album()
8370 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8372 // Read all storage devices
8373 return LIBMTP_Get_Album_List_For_Storage(device, 0);
8378 * This function returns a list of the albums available on the
8379 * device. You can filter on the storage ID.
8381 * @param device a pointer to the device to get the album listing from.
8382 * @param storage_id ID of device storage (if null, all storages)
8384 * @return an album list on success, else NULL. If there are no albums
8385 * on the device, NULL will be returned as well.
8386 * @see LIBMTP_Get_Album()
8388 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8390 PTPParams *params = (PTPParams *) device->params;
8391 LIBMTP_album_t *retalbums = NULL;
8392 LIBMTP_album_t *curalbum = NULL;
8395 // Get all the handles if we haven't already done that
8396 if (params->nrofobjects == 0)
8397 flush_handles(device);
8399 for (i = 0; i < params->nrofobjects; i++) {
8400 LIBMTP_album_t *alb;
8404 ob = ¶ms->objects[i];
8406 // Ignore stuff that isn't an album
8407 if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8410 // Ignore stuff that isn't into the storage device
8411 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8414 // Allocate a new album type
8415 alb = LIBMTP_new_album_t();
8416 alb->album_id = ob->oid;
8417 alb->parent_id = ob->oi.ParentObject;
8418 alb->storage_id = ob->oi.StorageID;
8420 // Fetch supported metadata
8421 get_album_metadata(device, alb);
8423 // Then get the track listing for this album
8424 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8425 if (ret != PTP_RC_OK) {
8426 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8431 // Add album to a list that will be returned afterwards.
8432 if (retalbums == NULL) {
8436 curalbum->next = alb;
8445 * This function retrieves an individual album from the device.
8446 * @param device a pointer to the device to get the album from.
8447 * @param albid the unique ID of the album to retrieve.
8448 * @return a valid album metadata or NULL on failure.
8449 * @see LIBMTP_Get_Album_List()
8451 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8453 PTPParams *params = (PTPParams *) device->params;
8456 LIBMTP_album_t *alb;
8458 // Get all the handles if we haven't already done that
8459 if (params->nrofobjects == 0)
8460 flush_handles(device);
8462 ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8463 if (ret != PTP_RC_OK)
8466 // Ignore stuff that isn't an album
8467 if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8470 // Allocate a new album type
8471 alb = LIBMTP_new_album_t();
8472 alb->album_id = ob->oid;
8473 alb->parent_id = ob->oi.ParentObject;
8474 alb->storage_id = ob->oi.StorageID;
8476 // Fetch supported metadata
8477 get_album_metadata(device, alb);
8479 // Then get the track listing for this album
8480 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8481 if (ret != PTP_RC_OK) {
8482 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8491 * This routine creates a new album based on the metadata
8492 * supplied. If the <code>tracks</code> field of the metadata
8493 * contains a track listing, these tracks will be added to the
8495 * @param device a pointer to the device to create the new album on.
8496 * @param metadata the metadata for the new album. If the function
8497 * exits with success, the <code>album_id</code> field of this
8498 * struct will contain the new ID of the album.
8500 * <li><code>metadata->parent_id</code> should be set to the parent
8501 * (e.g. folder) to store this track in. Since some
8502 * devices are a bit picky about where files
8503 * are placed, a default folder will be chosen if libmtp
8504 * has detected one for the current filetype and this
8505 * parameter is set to 0. If this is 0 and no default folder
8506 * can be found, the file will be stored in the root folder.
8507 * <li><code>metadata->storage_id</code> should be set to the
8508 * desired storage (e.g. memory card or whatever your device
8509 * presents) to store this track in. Setting this to 0 will store
8510 * the track on the primary storage.
8512 * @return 0 on success, any other value means failure.
8513 * @see LIBMTP_Update_Album()
8514 * @see LIBMTP_Delete_Object()
8516 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8517 LIBMTP_album_t * const metadata)
8519 uint32_t localph = metadata->parent_id;
8521 // Use a default folder if none given
8523 if (device->default_album_folder != 0)
8524 localph = device->default_album_folder;
8526 localph = device->default_music_folder;
8528 metadata->parent_id = localph;
8530 // Just create a new abstract album...
8531 return create_new_abstract_list(device,
8537 metadata->storage_id,
8538 PTP_OFC_MTP_AbstractAudioAlbum,
8540 &metadata->album_id,
8542 metadata->no_tracks);
8546 * This creates a new sample data metadata structure and allocates memory
8547 * for it. Notice that if you add strings to this structure they
8548 * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8549 * operation later, so be careful of using strdup() when assigning
8552 * @return a pointer to the newly allocated metadata structure.
8553 * @see LIBMTP_destroy_sampledata_t()
8555 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8557 LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8570 * This destroys a file sample metadata type.
8571 * @param sample the file sample metadata to be destroyed.
8573 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8575 if (sample == NULL) {
8578 if (sample->data != NULL) {
8585 * This routine figures out whether a certain filetype supports
8586 * representative samples (small thumbnail images) or not. This
8587 * typically applies to JPEG files, MP3 files and Album abstract
8588 * playlists, but in theory any filetype could support representative
8590 * @param device a pointer to the device which is to be examined.
8591 * @param filetype the fileype to examine, and return the representative sample
8593 * @param sample this will contain a new sample type with the fields
8594 * filled in with suitable default values. For example, the
8595 * supported sample type will be set, the supported height and
8596 * width will be set to max values if it is an image sample,
8597 * and duration will also be given some suitable default value
8598 * which should not be exceeded on audio samples. If the
8599 * device does not support samples for this filetype, this
8600 * pointer will be NULL. If it is not NULL, the user must
8601 * destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8603 * @return 0 on success, any other value means failure.
8604 * @see LIBMTP_Send_Representative_Sample()
8605 * @see LIBMTP_Create_New_Album()
8607 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8608 LIBMTP_filetype_t const filetype,
8609 LIBMTP_filesampledata_t ** sample)
8612 PTPParams *params = (PTPParams *) device->params;
8613 uint16_t *props = NULL;
8614 uint32_t propcnt = 0;
8616 // TODO: Get rid of these when we can properly query the device.
8617 int support_data = 0;
8618 int support_format = 0;
8619 int support_height = 0;
8620 int support_width = 0;
8621 int support_duration = 0;
8622 int support_size = 0;
8624 PTPObjectPropDesc opd_height;
8625 PTPObjectPropDesc opd_width;
8626 PTPObjectPropDesc opd_format;
8627 PTPObjectPropDesc opd_duration;
8628 PTPObjectPropDesc opd_size;
8630 // Default to no type supported.
8633 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8634 if (ret != PTP_RC_OK) {
8635 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8639 * TODO: when walking through these object properties, make calls to
8640 * a new function in ptp.h/ptp.c that can send the command
8641 * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8644 for (i = 0; i < propcnt; i++) {
8646 case PTP_OPC_RepresentativeSampleData:
8649 case PTP_OPC_RepresentativeSampleFormat:
8652 case PTP_OPC_RepresentativeSampleSize:
8655 case PTP_OPC_RepresentativeSampleHeight:
8658 case PTP_OPC_RepresentativeSampleWidth:
8661 case PTP_OPC_RepresentativeSampleDuration:
8662 support_duration = 1;
8670 if (support_data && support_format && support_height && support_width && !support_duration) {
8671 // Something that supports height and width and not duration is likely to be JPEG
8672 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8674 * Populate the sample format with the first supported format
8676 * TODO: figure out how to pass back more than one format if more are
8677 * supported by the device.
8679 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8680 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8681 ptp_free_objectpropdesc(&opd_format);
8682 /* Populate the maximum image height */
8683 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8684 retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8685 ptp_free_objectpropdesc(&opd_width);
8686 /* Populate the maximum image width */
8687 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8688 retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8689 ptp_free_objectpropdesc(&opd_height);
8690 /* Populate the maximum size */
8692 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8693 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8694 ptp_free_objectpropdesc(&opd_size);
8697 } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8698 // Another qualified guess
8699 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8701 * Populate the sample format with the first supported format
8703 * TODO: figure out how to pass back more than one format if more are
8704 * supported by the device.
8706 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8707 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8708 ptp_free_objectpropdesc(&opd_format);
8709 /* Populate the maximum duration */
8710 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8711 retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8712 ptp_free_objectpropdesc(&opd_duration);
8713 /* Populate the maximum size */
8715 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8716 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8717 ptp_free_objectpropdesc(&opd_size);
8725 * This routine sends representative sample data for an object.
8726 * This uses the RepresentativeSampleData property of the album,
8727 * if the device supports it. The data should be of a format acceptable
8728 * to the player (for iRiver and Creative, this seems to be JPEG) and
8729 * must not be too large. (for a Creative, max seems to be about 20KB.)
8730 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8731 * maximum size, dimensions, etc..
8732 * @param device a pointer to the device which the object is on.
8733 * @param id unique id of the object to set artwork for.
8734 * @param pointer to LIBMTP_filesampledata_t struct containing data
8735 * @return 0 on success, any other value means failure.
8736 * @see LIBMTP_Get_Representative_Sample()
8737 * @see LIBMTP_Get_Representative_Sample_Format()
8738 * @see LIBMTP_Create_New_Album()
8740 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8742 LIBMTP_filesampledata_t *sampledata)
8745 PTPParams *params = (PTPParams *) device->params;
8746 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8747 PTPPropertyValue propval;
8750 uint16_t *props = NULL;
8751 uint32_t propcnt = 0;
8754 // get the file format for the object we're going to send representative data for
8755 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8756 if (ret != PTP_RC_OK) {
8757 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8761 // check that we can send representative sample data for this object format
8762 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8763 if (ret != PTP_RC_OK) {
8764 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8768 for (i = 0; i < propcnt; i++) {
8769 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8776 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8781 // Go ahead and send the data
8782 propval.a.count = sampledata->size;
8783 propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8784 for (i = 0; i < sampledata->size; i++) {
8785 propval.a.v[i].u8 = sampledata->data[i];
8788 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8789 &propval,PTP_DTC_AUINT8);
8790 if (ret != PTP_RC_OK) {
8791 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8797 /* Set the height and width if the sample is an image, otherwise just
8798 * set the duration and size */
8799 switch(sampledata->filetype) {
8800 case LIBMTP_FILETYPE_JPEG:
8801 case LIBMTP_FILETYPE_JFIF:
8802 case LIBMTP_FILETYPE_TIFF:
8803 case LIBMTP_FILETYPE_BMP:
8804 case LIBMTP_FILETYPE_GIF:
8805 case LIBMTP_FILETYPE_PICT:
8806 case LIBMTP_FILETYPE_PNG:
8807 if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8808 // For images, set the height and width
8809 set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8810 set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8814 // For anything not an image, set the duration and size
8815 set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8816 set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8824 * This routine gets representative sample data for an object.
8825 * This uses the RepresentativeSampleData property of the album,
8826 * if the device supports it.
8827 * @param device a pointer to the device which the object is on.
8828 * @param id unique id of the object to get data for.
8829 * @param pointer to LIBMTP_filesampledata_t struct to receive data
8830 * @return 0 on success, any other value means failure.
8831 * @see LIBMTP_Send_Representative_Sample()
8832 * @see LIBMTP_Get_Representative_Sample_Format()
8833 * @see LIBMTP_Create_New_Album()
8835 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8837 LIBMTP_filesampledata_t *sampledata)
8840 PTPParams *params = (PTPParams *) device->params;
8841 PTPPropertyValue propval;
8844 uint16_t *props = NULL;
8845 uint32_t propcnt = 0;
8848 // get the file format for the object we're going to send representative data for
8849 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8850 if (ret != PTP_RC_OK) {
8851 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8855 // check that we can store representative sample data for this object format
8856 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8857 if (ret != PTP_RC_OK) {
8858 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8862 for (i = 0; i < propcnt; i++) {
8863 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8870 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8876 ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8877 &propval,PTP_DTC_AUINT8);
8878 if (ret != PTP_RC_OK) {
8879 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8884 sampledata->size = propval.a.count;
8885 sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8886 for (i = 0; i < propval.a.count; i++) {
8887 sampledata->data[i] = propval.a.v[i].u8;
8891 // Get the other properties
8892 sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8893 sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8894 sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8895 sampledata->filetype = map_ptp_type_to_libmtp_type(
8896 get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8902 * Retrieve the thumbnail for a file.
8903 * @param device a pointer to the device to get the thumbnail from.
8904 * @param id the object ID of the file to retrieve the thumbnail for.
8905 * @return 0 on success, any other value means failure.
8907 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
8908 unsigned char **data, unsigned int *size)
8910 PTPParams *params = (PTPParams *) device->params;
8913 ret = ptp_getthumb(params, id, data, size);
8914 if (ret == PTP_RC_OK)
8920 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
8921 uint64_t offset, uint32_t maxbytes,
8922 unsigned char **data, unsigned int *size)
8924 PTPParams *params = (PTPParams *) device->params;
8927 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_GetPartialObject64)) {
8928 if (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
8929 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8930 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
8934 if (offset >> 32 != 0) {
8935 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8936 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject only supports 32bit offsets");
8940 ret = ptp_getpartialobject(params, id, (uint32_t)offset, maxbytes, data, size);
8942 ret = ptp_android_getpartialobject64(params, id, offset, maxbytes, data, size);
8944 if (ret == PTP_RC_OK)
8950 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
8951 uint64_t offset, unsigned char *data, unsigned int size)
8953 PTPParams *params = (PTPParams *) device->params;
8956 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
8957 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8958 "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
8962 ret = ptp_android_sendpartialobject(params, id, offset, data, size);
8963 if (ret == PTP_RC_OK)
8969 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
8971 PTPParams *params = (PTPParams *) device->params;
8974 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
8975 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8976 "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
8980 ret = ptp_android_begineditobject(params, id);
8981 if (ret == PTP_RC_OK)
8987 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
8989 PTPParams *params = (PTPParams *) device->params;
8992 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
8993 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8994 "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
8998 ret = ptp_android_endeditobject(params, id);
8999 if (ret == PTP_RC_OK) {
9000 // update cached object properties if metadata cache exists
9001 update_metadata_cache(device, id);
9008 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9011 PTPParams *params = (PTPParams *) device->params;
9014 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9015 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9016 "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9020 ret = ptp_android_truncate(params, id, offset);
9021 if (ret == PTP_RC_OK)
9028 * This routine updates an album based on the metadata
9029 * supplied. If the <code>tracks</code> field of the metadata
9030 * contains a track listing, these tracks will be added to the
9031 * album in place of those already present, i.e. the
9032 * previous track listing will be deleted.
9033 * @param device a pointer to the device to create the new album on.
9034 * @param metadata the metadata for the album to be updated.
9035 * notice that the field <code>album_id</code>
9036 * must contain the apropriate album ID.
9037 * @return 0 on success, any other value means failure.
9038 * @see LIBMTP_Create_New_Album()
9039 * @see LIBMTP_Delete_Object()
9041 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9042 LIBMTP_album_t const * const metadata)
9044 return update_abstract_list(device,
9050 PTP_OFC_MTP_AbstractAudioAlbum,
9052 metadata->no_tracks);
9056 * Dummy function needed to interface to upstream
9057 * ptp.c/ptp.h files.
9059 void ptp_nikon_getptpipguid (unsigned char* guid) {
9064 * Add an object to cache.
9065 * @param device the device which may have a cache to which the object should be added.
9066 * @param object_id the object to add to the cache.
9068 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9070 PTPParams *params = (PTPParams *)device->params;
9073 ret = ptp_add_object_to_cache(params, object_id);
9074 if (ret != PTP_RC_OK) {
9075 add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9081 * Update cache after object has been modified
9082 * @param device the device which may have a cache to which the object should be updated.
9083 * @param object_id the object to update.
9085 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9087 PTPParams *params = (PTPParams *)device->params;
9089 ptp_remove_object_from_cache(params, object_id);
9090 add_object_to_cache(device, object_id);