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 1//defined TIZEN_EXT
1687 if (devices == NULL) {
1697 #else /* TIZEN_EXT */
1698 if (devices == NULL || numdevs == 0) {
1701 #endif /* TIZEN_EXT */
1703 first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1705 return first_device;
1709 * Overriding debug function.
1710 * This way we can disable debug prints.
1714 __attribute__((__format__(printf,2,0)))
1716 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1718 if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1719 vfprintf (stderr, format, args);
1720 fprintf (stderr, "\n");
1726 * Overriding error function.
1727 * This way we can capture all error etc to our errorstack.
1731 __attribute__((__format__(printf,2,0)))
1733 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1735 // if (data == NULL) {
1736 vfprintf (stderr, format, args);
1739 FIXME: find out how we shall get the device here.
1741 PTP_USB *ptp_usb = data;
1742 LIBMTP_mtpdevice_t *device = ...;
1745 vsnprintf (buf, sizeof (buf), format, args);
1746 add_error_to_errorstack(device,
1747 LIBMTP_ERROR_PTP_LAYER,
1754 * Parses the extension descriptor, there may be stuff in
1755 * this that we want to know about.
1757 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1763 /* NULL on Canon A70 */
1767 /* descriptors are divided by semicolons */
1768 while (end < strlen(desc)) {
1769 /* Skip past initial whitespace */
1770 while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1774 /* Detect extension */
1775 while ((end < strlen(desc)) && (desc[end] != ';'))
1777 if (end < strlen(desc)) {
1778 char *element = strndup(desc + start, end-start);
1781 // printf(" Element: \"%s\"\n", element);
1783 /* Parse for an extension */
1784 while ((i < strlen(element)) && (element[i] != ':'))
1786 if (i < strlen(element)) {
1787 char *name = strndup(element, i);
1789 // printf(" Extension: \"%s\"\n", name);
1791 /* Parse for minor/major punctuation mark for this extension */
1792 while ((i < strlen(element)) && (element[i] != '.'))
1794 if (i > majstart && i < strlen(element)) {
1795 LIBMTP_device_extension_t *extension;
1798 char *majorstr = strndup(element + majstart, i - majstart);
1799 char *minorstr = strndup(element + i + 1, strlen(element) - i - 1);
1800 major = atoi(majorstr);
1801 minor = atoi(minorstr);
1802 // printf(" Major: \"%s\" (parsed %d) Minor: \"%s\" (parsed %d)\n",
1803 // majorstr, major, minorstr, minor);
1806 extension = malloc(sizeof(LIBMTP_device_extension_t));
1807 extension->name = name;
1808 extension->major = major;
1809 extension->minor = minor;
1810 extension->next = NULL;
1811 if (mtpdevice->extensions == NULL) {
1812 mtpdevice->extensions = extension;
1814 LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1815 while (tmp->next != NULL)
1817 tmp->next = extension;
1820 LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1833 * This function opens a device from a raw device. It is the
1834 * preferred way to access devices in the new interface where
1835 * several devices can come and go as the library is working
1836 * on a certain device.
1837 * @param rawdevice the raw device to open a "real" device for.
1838 * @return an open device.
1840 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1842 LIBMTP_mtpdevice_t *mtp_device;
1844 PTPParams *current_params;
1846 LIBMTP_error_number_t err;
1849 /* Allocate dynamic space for our device */
1850 mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1851 /* Check if there was a memory allocation error */
1852 if(mtp_device == NULL) {
1853 /* There has been an memory allocation error. We are going to ignore this
1854 device and attempt to continue */
1856 /* TODO: This error statement could probably be a bit more robust */
1857 LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1858 "allocation error with device %d on bus %d, trying to continue",
1859 rawdevice->devnum, rawdevice->bus_location);
1863 memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1864 // Non-cached by default
1865 mtp_device->cached = 0;
1867 /* Create PTP params */
1868 current_params = (PTPParams *) malloc(sizeof(PTPParams));
1869 if (current_params == NULL) {
1873 memset(current_params, 0, sizeof(PTPParams));
1874 current_params->device_flags = rawdevice->device_entry.device_flags;
1875 current_params->nrofobjects = 0;
1876 current_params->objects = NULL;
1877 current_params->response_packet_size = 0;
1878 current_params->response_packet = NULL;
1879 /* This will be a pointer to PTP_USB later */
1880 current_params->data = NULL;
1881 /* Set upp local debug and error functions */
1882 current_params->debug_func = LIBMTP_ptp_debug;
1883 current_params->error_func = LIBMTP_ptp_error;
1884 /* TODO: Will this always be little endian? */
1885 current_params->byteorder = PTP_DL_LE;
1886 current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1887 current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1889 if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1890 current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1891 LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1892 "Too old stdlibc, glibc and libiconv?\n");
1893 free(current_params);
1897 mtp_device->params = current_params;
1899 /* Create usbinfo, this also opens the session */
1900 err = configure_usb_device(rawdevice,
1902 &mtp_device->usbinfo);
1903 if (err != LIBMTP_ERROR_NONE) {
1904 free(current_params);
1908 ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1909 /* Set pointer back to params */
1910 ptp_usb->params = current_params;
1912 /* Cache the device information for later use */
1913 if (ptp_getdeviceinfo(current_params,
1914 ¤t_params->deviceinfo) != PTP_RC_OK) {
1915 LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1916 "%d on bus %d, trying to continue",
1917 rawdevice->devnum, rawdevice->bus_location);
1919 /* Prevent memory leaks for this device */
1920 free(mtp_device->usbinfo);
1921 free(mtp_device->params);
1922 current_params = NULL;
1927 /* Check: if this is a PTP device, is it really tagged as MTP? */
1928 if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1929 LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1931 rawdevice->devnum, rawdevice->bus_location);
1932 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1933 current_params->deviceinfo.VendorExtensionID);
1934 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1935 current_params->deviceinfo.VendorExtensionDesc);
1936 LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1937 "(i.e. a camera) but not an MTP device at all. "
1938 "Trying to continue anyway.");
1941 parse_extension_descriptor(mtp_device,
1942 current_params->deviceinfo.VendorExtensionDesc);
1945 * Android has a number of bugs, force-assign these bug flags
1946 * if Android is encountered. Same thing for devices we detect
1947 * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1948 * I just know only NWZs have it.
1951 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1952 int is_microsoft_com_wpdna = 0;
1954 int is_sony_net_wmfu = 0;
1955 int is_sonyericsson_com_se = 0;
1957 /* Loop over extensions and set flags */
1958 while (tmpext != NULL) {
1959 if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1960 is_microsoft_com_wpdna = 1;
1961 if (!strcmp(tmpext->name, "android.com"))
1963 if (!strcmp(tmpext->name, "sony.net/WMFU"))
1964 is_sony_net_wmfu = 1;
1965 if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1966 is_sonyericsson_com_se = 1;
1967 tmpext = tmpext->next;
1970 /* Check for specific stacks */
1971 if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1973 * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1974 * extension and NO Android extension.
1976 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1977 LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1979 else if (is_android) {
1981 * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1983 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1984 LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1986 else if (is_sony_net_wmfu) {
1987 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1988 LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
1993 * If the OGG or FLAC filetypes are flagged as "unknown", check
1994 * if the firmware has been updated to actually support it.
1996 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
1997 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1998 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_OGG) {
1999 /* This is not unknown anymore, unflag it */
2000 ptp_usb->rawdevice.device_entry.device_flags &=
2001 ~DEVICE_FLAG_OGG_IS_UNKNOWN;
2006 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
2007 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2008 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
2009 /* This is not unknown anymore, unflag it */
2010 ptp_usb->rawdevice.device_entry.device_flags &=
2011 ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2017 /* Determine if the object size supported is 32 or 64 bit wide */
2018 if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2019 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2020 PTPObjectPropDesc opd;
2022 if (ptp_mtp_getobjectpropdesc(current_params,
2024 current_params->deviceinfo.ImageFormats[i],
2025 &opd) != PTP_RC_OK) {
2026 LIBMTP_ERROR("LIBMTP PANIC: "
2027 "could not inspect object property descriptions!\n");
2029 if (opd.DataType == PTP_DTC_UINT32) {
2032 } else if (bs != 32) {
2033 LIBMTP_ERROR("LIBMTP PANIC: "
2034 "different objects support different object sizes!\n");
2038 } else if (opd.DataType == PTP_DTC_UINT64) {
2041 } else if (bs != 64) {
2042 LIBMTP_ERROR("LIBMTP PANIC: "
2043 "different objects support different object sizes!\n");
2048 // Ignore if other size.
2049 LIBMTP_ERROR("LIBMTP PANIC: "
2050 "awkward object size data type: %04x\n", opd.DataType);
2058 // Could not detect object bitsize, assume 32 bits
2061 mtp_device->object_bitsize = bs;
2063 /* No Errors yet for this device */
2064 mtp_device->errorstack = NULL;
2066 /* Default Max Battery Level, we will adjust this if possible */
2067 mtp_device->maximum_battery_level = 100;
2069 /* Check if device supports reading maximum battery level */
2070 if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2071 ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2072 PTPDevicePropDesc dpd;
2074 /* Try to read maximum battery level */
2075 if(ptp_getdevicepropdesc(current_params,
2076 PTP_DPC_BatteryLevel,
2077 &dpd) != PTP_RC_OK) {
2078 add_error_to_errorstack(mtp_device,
2079 LIBMTP_ERROR_CONNECTING,
2080 "Unable to read Maximum Battery Level for this "
2081 "device even though the device supposedly "
2082 "supports this functionality");
2085 /* TODO: is this appropriate? */
2086 /* If max battery level is 0 then leave the default, otherwise assign */
2087 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2088 mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2091 ptp_free_devicepropdesc(&dpd);
2094 /* Set all default folders to 0xffffffffU (root directory) */
2095 mtp_device->default_music_folder = 0xffffffffU;
2096 mtp_device->default_playlist_folder = 0xffffffffU;
2097 mtp_device->default_picture_folder = 0xffffffffU;
2098 mtp_device->default_video_folder = 0xffffffffU;
2099 mtp_device->default_organizer_folder = 0xffffffffU;
2100 mtp_device->default_zencast_folder = 0xffffffffU;
2101 mtp_device->default_album_folder = 0xffffffffU;
2102 mtp_device->default_text_folder = 0xffffffffU;
2104 /* Set initial storage information */
2105 mtp_device->storage = NULL;
2106 if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2107 add_error_to_errorstack(mtp_device,
2108 LIBMTP_ERROR_GENERAL,
2109 "Get Storage information failed.");
2110 mtp_device->storage = NULL;
2117 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2119 LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2121 if (mtp_device == NULL)
2124 /* Check for MTPZ devices. */
2126 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2128 while (tmpext != NULL) {
2129 if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2130 LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2131 if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2132 LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2134 LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2138 tmpext = tmpext->next;
2142 // Set up this device as cached
2143 mtp_device->cached = 1;
2145 * Then get the handles and try to locate the default folders.
2146 * This has the desired side effect of caching all handles from
2147 * the device which speeds up later operations.
2149 flush_handles(mtp_device);
2154 * To read events sent by the device, repeatedly call this function from a secondary
2155 * thread until the return value is < 0.
2157 * @param device a pointer to the MTP device to poll for events.
2158 * @param event contains a pointer to be filled in with the event retrieved if the call
2160 * @param out1 contains the param1 value from the raw event.
2161 * @return 0 on success, any other value means the polling loop shall be
2162 * terminated immediately for this session.
2164 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2167 * FIXME: Potential race-condition here, if client deallocs device
2168 * while we're *not* waiting for input. As we'll be waiting for
2169 * input most of the time, it's unlikely but still worth considering
2170 * for improvement. Also we cannot affect the state of the cache etc
2171 * unless we know we are the sole user on the device. A spinlock or
2172 * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2174 PTPParams *params = (PTPParams *) device->params;
2175 PTPContainer ptp_event;
2176 uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2178 uint32_t session_id;
2181 if (ret != PTP_RC_OK) {
2182 /* Device is closing down or other fatal stuff, exit thread */
2186 *event = LIBMTP_EVENT_NONE;
2188 /* Process the event */
2189 code = ptp_event.Code;
2190 session_id = ptp_event.SessionID;
2191 param1 = ptp_event.Param1;
2194 case PTP_EC_Undefined:
2195 LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2197 case PTP_EC_CancelTransaction:
2198 LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2200 case PTP_EC_ObjectAdded:
2201 LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2202 *event = LIBMTP_EVENT_OBJECT_ADDED;
2205 case PTP_EC_ObjectRemoved:
2206 LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2207 *event = LIBMTP_EVENT_OBJECT_REMOVED;
2210 case PTP_EC_StoreAdded:
2211 LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2212 /* TODO: rescan storages */
2213 *event = LIBMTP_EVENT_STORE_ADDED;
2216 case PTP_EC_StoreRemoved:
2217 LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2218 /* TODO: rescan storages */
2219 *event = LIBMTP_EVENT_STORE_REMOVED;
2222 case PTP_EC_DevicePropChanged:
2223 LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2224 /* TODO: update device properties */
2226 case PTP_EC_ObjectInfoChanged:
2227 LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2228 /* TODO: rescan object cache or just for this one object */
2230 case PTP_EC_DeviceInfoChanged:
2231 LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2232 /* TODO: update device info */
2234 case PTP_EC_RequestObjectTransfer:
2235 LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2237 case PTP_EC_StoreFull:
2238 LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2240 case PTP_EC_DeviceReset:
2241 LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2243 case PTP_EC_StorageInfoChanged :
2244 LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2245 /* TODO: update storage info */
2247 case PTP_EC_CaptureComplete :
2248 LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2250 case PTP_EC_UnreportedStatus :
2251 LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2254 LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2262 * Recursive function that adds MTP devices to a linked list
2263 * @param devices a list of raw devices to have real devices created for.
2264 * @return a device pointer to a newly created mtpdevice (used in linked
2267 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2270 LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2271 LIBMTP_mtpdevice_t *current_device = NULL;
2273 for (i=0; i < numdevs; i++) {
2274 LIBMTP_mtpdevice_t *mtp_device;
2275 mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2277 /* On error, try next device */
2278 if (mtp_device == NULL)
2281 /* Add the device to the list */
2282 mtp_device->next = NULL;
2283 if (mtp_device_list == NULL) {
2284 mtp_device_list = current_device = mtp_device;
2286 current_device->next = mtp_device;
2287 current_device = mtp_device;
2290 return mtp_device_list;
2294 * Get the number of devices that are available in the listed device list
2295 * @param device_list Pointer to a linked list of devices
2296 * @return Number of devices in the device list device_list
2297 * @see LIBMTP_Get_Connected_Devices()
2299 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2301 uint32_t numdevices = 0;
2302 LIBMTP_mtpdevice_t *iter;
2303 for(iter = device_list; iter != NULL; iter = iter->next)
2310 * Get the first connected MTP device node in the linked list of devices.
2311 * Currently this only provides access to USB devices
2312 * @param device_list A list of devices ready to be used by the caller. You
2313 * need to know how many there are.
2314 * @return Any error information gathered from device connections
2315 * @see LIBMTP_Number_Devices_In_List()
2317 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2319 LIBMTP_raw_device_t *devices;
2321 LIBMTP_error_number_t ret;
2323 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2324 if (ret != LIBMTP_ERROR_NONE) {
2325 *device_list = NULL;
2329 /* Assign linked list of devices */
2330 #if 1//defined TIZEN_EXT
2331 if (devices == NULL) {
2332 *device_list = NULL;
2333 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2340 *device_list = NULL;
2341 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2343 #else /* TIZEN_EXT */
2344 if (devices == NULL || numdevs == 0) {
2345 *device_list = NULL;
2346 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2348 #endif /* TIZEN_EXT */
2350 *device_list = create_usb_mtp_devices(devices, numdevs);
2353 /* TODO: Add wifi device access here */
2355 /* We have found some devices but create failed */
2356 if (*device_list == NULL)
2357 return LIBMTP_ERROR_CONNECTING;
2359 return LIBMTP_ERROR_NONE;
2363 * This closes and releases an allocated MTP device.
2364 * @param device a pointer to the MTP device to release.
2366 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2370 if(device->next != NULL)
2372 LIBMTP_Release_Device_List(device->next);
2375 LIBMTP_Release_Device(device);
2380 * This closes and releases an allocated MTP device.
2381 * @param device a pointer to the MTP device to release.
2383 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2385 PTPParams *params = (PTPParams *) device->params;
2386 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2388 close_device(ptp_usb, params);
2389 // Clear error stack
2390 LIBMTP_Clear_Errorstack(device);
2391 // Free iconv() converters...
2392 iconv_close(params->cd_locale_to_ucs2);
2393 iconv_close(params->cd_ucs2_to_locale);
2395 ptp_free_params(params);
2397 free_storage_list(device);
2398 // Free extension list...
2399 if (device->extensions != NULL) {
2400 LIBMTP_device_extension_t *tmp = device->extensions;
2402 while (tmp != NULL) {
2403 LIBMTP_device_extension_t *next = tmp->next;
2415 * This can be used by any libmtp-intrinsic code that
2416 * need to stack up an error on the stack. You are only
2417 * supposed to add errors to the error stack using this
2418 * function, do not create and reference error entries
2421 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2422 LIBMTP_error_number_t errornumber,
2423 char const * const error_text)
2425 LIBMTP_error_t *newerror;
2427 if (device == NULL) {
2428 LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2431 newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2432 newerror->errornumber = errornumber;
2433 newerror->error_text = strdup(error_text);
2434 newerror->next = NULL;
2435 if (device->errorstack == NULL) {
2436 device->errorstack = newerror;
2438 LIBMTP_error_t *tmp = device->errorstack;
2440 while (tmp->next != NULL) {
2443 tmp->next = newerror;
2448 * Adds an error from the PTP layer to the error stack.
2450 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2452 char const * const error_text)
2454 if (device == NULL) {
2455 LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2459 snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2460 outstr[sizeof(outstr)-1] = '\0';
2461 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2463 snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error));
2464 outstr[sizeof(outstr)-1] = '\0';
2465 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2470 * This returns the error stack for a device in case you
2471 * need to either reference the error numbers (e.g. when
2472 * creating multilingual apps with multiple-language text
2473 * representations for each error number) or when you need
2474 * to build a multi-line error text widget or something like
2475 * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2476 * to clear it when you're finished with it.
2477 * @param device a pointer to the MTP device to get the error
2479 * @return the error stack or NULL if there are no errors
2481 * @see LIBMTP_Clear_Errorstack()
2482 * @see LIBMTP_Dump_Errorstack()
2484 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2486 if (device == NULL) {
2487 LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2490 return device->errorstack;
2494 * This function clears the error stack of a device and frees
2495 * any memory used by it. Call this when you're finished with
2497 * @param device a pointer to the MTP device to clear the error
2500 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2502 if (device == NULL) {
2503 LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2505 LIBMTP_error_t *tmp = device->errorstack;
2507 while (tmp != NULL) {
2508 LIBMTP_error_t *tmp2;
2510 if (tmp->error_text != NULL) {
2511 free(tmp->error_text);
2517 device->errorstack = NULL;
2522 * This function dumps the error stack to <code>stderr</code>.
2523 * (You still have to clear the stack though.)
2524 * @param device a pointer to the MTP device to dump the error
2527 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2529 if (device == NULL) {
2530 LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2532 LIBMTP_error_t *tmp = device->errorstack;
2534 while (tmp != NULL) {
2535 if (tmp->error_text != NULL) {
2536 LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2538 LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2546 * This command gets all handles and stuff by FAST directory retrieveal
2547 * which is available by getting all metadata for object
2548 * <code>0xffffffff</code> which simply means "all metadata for all objects".
2549 * This works on the vast majority of MTP devices (there ARE exceptions!)
2550 * and is quite quick. Check the error stack to see if there were
2551 * problems getting the metadata.
2552 * @return 0 if all was OK, -1 on failure.
2554 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2556 PTPParams *params = (PTPParams *) device->params;
2558 int i, j, nrofprops;
2559 uint32_t lasthandle = 0xffffffff;
2560 MTPProperties *props = NULL;
2561 MTPProperties *prop;
2564 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2567 * The follow request causes the device to generate
2568 * a list of every file on the device and return it
2569 * in a single response.
2571 * Some slow devices as well as devices with very
2572 * large file systems can easily take longer then
2573 * the standard timeout value before it is able
2574 * to return a response.
2576 * Temporarly set timeout to allow working with
2577 * widest range of devices.
2579 get_usb_device_timeout(ptp_usb, &oldtimeout);
2580 set_usb_device_timeout(ptp_usb, 60000);
2582 ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2583 set_usb_device_timeout(ptp_usb, oldtimeout);
2585 if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2586 // What's the point in the device implementing this command if
2587 // you cannot use it to get all props for AT LEAST one object?
2588 // Well, whatever...
2589 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2590 "cannot retrieve all metadata for an object on this device.");
2593 if (ret != PTP_RC_OK) {
2594 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2595 "could not get proplist of all objects.");
2598 if (props == NULL && nrofprops != 0) {
2599 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2600 "get_all_metadata_fast(): "
2601 "call to ptp_mtp_getobjectproplist() returned "
2602 "inconsistent results.");
2606 * We count the number of objects by counting the ObjectHandle
2607 * references, whenever it changes we get a new object, when it's
2608 * the same, it is just different properties of the same object.
2611 for (i=0;i<nrofprops;i++) {
2612 if (lasthandle != prop->ObjectHandle) {
2614 lasthandle = prop->ObjectHandle;
2618 lasthandle = 0xffffffff;
2619 params->objects = calloc (sizeof(PTPObject),cnt);
2622 for (j=0;j<nrofprops;j++) {
2623 if (lasthandle != prop->ObjectHandle) {
2625 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2626 if (!params->objects[i].oi.Filename) {
2627 /* I have one such file on my Creative (Marcus) */
2628 params->objects[i].oi.Filename = strdup("<null>");
2632 lasthandle = prop->ObjectHandle;
2633 params->objects[i].oid = prop->ObjectHandle;
2635 switch (prop->property) {
2636 case PTP_OPC_ParentObject:
2637 params->objects[i].oi.ParentObject = prop->propval.u32;
2638 params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2640 case PTP_OPC_ObjectFormat:
2641 params->objects[i].oi.ObjectFormat = prop->propval.u16;
2643 case PTP_OPC_ObjectSize:
2644 // We loose precision here, up to 32 bits! However the commands that
2645 // retrieve metadata for files and tracks will make sure that the
2646 // PTP_OPC_ObjectSize is read in and duplicated again.
2647 if (device->object_bitsize == 64) {
2648 params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2650 params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2653 case PTP_OPC_StorageID:
2654 params->objects[i].oi.StorageID = prop->propval.u32;
2655 params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2657 case PTP_OPC_ObjectFileName:
2658 if (prop->propval.str != NULL)
2659 params->objects[i].oi.Filename = strdup(prop->propval.str);
2662 MTPProperties *newprops;
2664 /* Copy all of the other MTP oprierties into the per-object proplist */
2665 if (params->objects[i].nrofmtpprops) {
2666 newprops = realloc(params->objects[i].mtpprops,
2667 (params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2669 newprops = calloc(sizeof(MTPProperties),1);
2671 if (!newprops) return 0; /* FIXME: error handling? */
2672 params->objects[i].mtpprops = newprops;
2673 memcpy(¶ms->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2674 &props[j],sizeof(props[j]));
2675 params->objects[i].nrofmtpprops++;
2676 params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2682 /* mark last entry also */
2683 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2684 params->nrofobjects = i+1;
2685 /* The device might not give the list in linear ascending order */
2686 ptp_objects_sort (params);
2691 * This function will recurse through all the directories on the device,
2692 * starting at the root directory, gathering metadata as it moves along.
2693 * It works better on some devices that will only return data for a
2694 * certain directory and does not respect the option to get all metadata
2697 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2702 PTPObjectHandles currentHandles;
2704 uint16_t ret = ptp_getobjecthandles(params,
2706 PTP_GOH_ALL_FORMATS,
2710 if (ret != PTP_RC_OK) {
2711 add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2715 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2718 // Now descend into any subdirectories found
2719 for (i = 0; i < currentHandles.n; i++) {
2721 ret = ptp_object_want(params,currentHandles.Handler[i],
2722 PTPOBJECT_OBJECTINFO_LOADED, &ob);
2723 if (ret == PTP_RC_OK) {
2724 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2725 get_handles_recursively(device, params,
2726 storageid, currentHandles.Handler[i]);
2728 add_error_to_errorstack(device,
2729 LIBMTP_ERROR_CONNECTING,
2730 "Found a bad handle, trying to ignore it.");
2733 free(currentHandles.Handler);
2737 * This function refresh the internal handle list whenever
2738 * the items stored inside the device is altered. On operations
2739 * that do not add or remove objects, this is typically not
2741 * @param device a pointer to the MTP device to flush handles for.
2743 static void flush_handles(LIBMTP_mtpdevice_t *device)
2745 PTPParams *params = (PTPParams *) device->params;
2746 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2750 if (!device->cached) {
2754 if (params->objects != NULL) {
2755 for (i=0;i<params->nrofobjects;i++)
2756 ptp_free_object (¶ms->objects[i]);
2757 free(params->objects);
2758 params->objects = NULL;
2759 params->nrofobjects = 0;
2762 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2763 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2764 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2765 // Use the fast method. Ignore return value for now.
2766 ret = get_all_metadata_fast(device);
2769 // If the previous failed or returned no objects, use classic
2771 if (params->nrofobjects == 0) {
2772 // Get all the handles using just standard commands.
2773 if (device->storage == NULL) {
2774 get_handles_recursively(device, params,
2775 PTP_GOH_ALL_STORAGE,
2776 PTP_GOH_ROOT_PARENT);
2778 // Get handles for each storage in turn.
2779 LIBMTP_devicestorage_t *storage = device->storage;
2780 while(storage != NULL) {
2781 get_handles_recursively(device, params,
2783 PTP_GOH_ROOT_PARENT);
2784 storage = storage->next;
2790 * Loop over the handles, fix up any NULL filenames or
2791 * keywords, then attempt to locate some default folders
2792 * in the root directory of the primary storage.
2794 for(i = 0; i < params->nrofobjects; i++) {
2795 PTPObject *ob, *xob;
2797 ob = ¶ms->objects[i];
2798 ret = ptp_object_want(params,params->objects[i].oid,
2799 PTPOBJECT_OBJECTINFO_LOADED, &xob);
2800 if (ret != PTP_RC_OK) {
2801 LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2803 if (ob->oi.Filename == NULL)
2804 ob->oi.Filename = strdup("<null>");
2805 if (ob->oi.Keywords == NULL)
2806 ob->oi.Keywords = strdup("<null>");
2808 /* Ignore handles that point to non-folders */
2809 if(ob->oi.ObjectFormat != PTP_OFC_Association)
2811 /* Only look in the root folder */
2812 if (ob->oi.ParentObject == 0xffffffffU) {
2813 LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2815 } else if (ob->oi.ParentObject != 0x00000000U)
2817 /* Only look in the primary storage */
2818 if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2821 /* Is this the Music Folder */
2822 if (!strcasecmp(ob->oi.Filename, "My Music") ||
2823 !strcasecmp(ob->oi.Filename, "My_Music") ||
2824 !strcasecmp(ob->oi.Filename, "Music")) {
2825 device->default_music_folder = ob->oid;
2827 else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2828 !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2829 !strcasecmp(ob->oi.Filename, "Playlists")) {
2830 device->default_playlist_folder = ob->oid;
2832 else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2833 !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2834 !strcasecmp(ob->oi.Filename, "Pictures")) {
2835 device->default_picture_folder = ob->oid;
2837 else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2838 !strcasecmp(ob->oi.Filename, "My_Video") ||
2839 !strcasecmp(ob->oi.Filename, "Video")) {
2840 device->default_video_folder = ob->oid;
2842 else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2843 !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2844 device->default_organizer_folder = ob->oid;
2846 else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2847 !strcasecmp(ob->oi.Filename, "Datacasts")) {
2848 device->default_zencast_folder = ob->oid;
2850 else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2851 !strcasecmp(ob->oi.Filename, "My_Albums") ||
2852 !strcasecmp(ob->oi.Filename, "Albums")) {
2853 device->default_album_folder = ob->oid;
2855 else if (!strcasecmp(ob->oi.Filename, "Text") ||
2856 !strcasecmp(ob->oi.Filename, "Texts")) {
2857 device->default_text_folder = ob->oid;
2863 * This function traverses a devices storage list freeing up the
2864 * strings and the structs.
2865 * @param device a pointer to the MTP device to free the storage
2868 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2870 LIBMTP_devicestorage_t *storage;
2871 LIBMTP_devicestorage_t *tmp;
2873 storage = device->storage;
2874 while(storage != NULL) {
2875 if (storage->StorageDescription != NULL) {
2876 free(storage->StorageDescription);
2878 if (storage->VolumeIdentifier != NULL) {
2879 free(storage->VolumeIdentifier);
2882 storage = storage->next;
2885 device->storage = NULL;
2891 * This function traverses a devices storage list freeing up the
2892 * strings and the structs.
2893 * @param device a pointer to the MTP device to free the storage
2896 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2898 LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2900 if (device->storage == NULL)
2902 if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2905 oldhead = ptr1 = ptr2 = device->storage;
2909 while(oldhead != NULL) {
2910 ptr1 = ptr2 = oldhead;
2911 while(ptr1 != NULL) {
2913 if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2915 if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2921 // Make our previous entries next point to our next
2922 if(ptr2->prev != NULL) {
2924 ptr1->next = ptr2->next;
2926 oldhead = ptr2->next;
2928 oldhead->prev = NULL;
2931 // Make our next entries previous point to our previous
2934 ptr1->prev = ptr2->prev;
2941 if(newlist == NULL) {
2943 newlist->prev = NULL;
2945 ptr2->prev = newlist;
2946 newlist->next = ptr2;
2947 newlist = newlist->next;
2951 if (newlist != NULL) {
2952 newlist->next = NULL;
2953 while(newlist->prev != NULL)
2954 newlist = newlist->prev;
2955 device->storage = newlist;
2962 * This function grabs the first writeable storageid from the
2963 * device storage list.
2964 * @param device a pointer to the MTP device to locate writeable
2966 * @param fitsize a file of this file must fit on the device.
2968 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
2971 LIBMTP_devicestorage_t *storage;
2972 uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
2975 // See if there is some storage we can fit this file on.
2976 storage = device->storage;
2977 if (storage == NULL) {
2978 // Sometimes the storage just cannot be detected.
2979 store = 0x00000000U;
2981 while(storage != NULL) {
2982 // These storages cannot be used.
2983 if (storage->StorageType == PTP_ST_FixedROM ||
2984 storage->StorageType == PTP_ST_RemovableROM) {
2985 storage = storage->next;
2988 // Storage IDs with the lower 16 bits 0x0000 are not supposed
2990 if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
2991 storage = storage->next;
2994 // Also check the access capability to avoid e.g. deletable only storages
2995 if (storage->AccessCapability == PTP_AC_ReadOnly ||
2996 storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
2997 storage = storage->next;
3000 // Then see if we can fit the file.
3001 subcall_ret = check_if_file_fits(device, storage, fitsize);
3002 if (subcall_ret != 0) {
3003 storage = storage->next;
3005 // We found a storage that is writable and can fit the file!
3009 if (storage == NULL) {
3010 add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
3011 "get_writeable_storageid(): "
3012 "all device storage is full or corrupt.");
3015 store = storage->id;
3022 * Tries to suggest a storage_id of a given ID when we have a parent
3023 * @param device a pointer to the device where to search for the storage ID
3024 * @param fitsize a file of this file must fit on the device.
3025 * @param parent_id look for this ID
3028 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3032 PTPParams *params = (PTPParams *) device->params;
3036 ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3037 if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3038 add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3039 "could not get storage id from parent id.");
3040 return get_writeable_storageid(device, fitsize);
3042 /* OK we know the parent storage, then use that */
3043 return ob->oi.StorageID;
3048 * This function grabs the freespace from a certain storage in
3049 * device storage list.
3050 * @param device a pointer to the MTP device to free the storage
3052 * @param storageid the storage ID for the storage to flush and
3053 * get free space for.
3054 * @param freespace the free space on this storage will be returned
3057 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3058 LIBMTP_devicestorage_t *storage,
3059 uint64_t *freespace)
3061 PTPParams *params = (PTPParams *) device->params;
3063 // Always query the device about this, since some models explicitly
3064 // needs that. We flush all data on queries storage here.
3065 if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3066 PTPStorageInfo storageInfo;
3069 ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3070 if (ret != PTP_RC_OK) {
3071 add_ptp_error_to_errorstack(device, ret,
3072 "get_storage_freespace(): could not get storage info.");
3075 if (storage->StorageDescription != NULL) {
3076 free(storage->StorageDescription);
3078 if (storage->VolumeIdentifier != NULL) {
3079 free(storage->VolumeIdentifier);
3081 storage->StorageType = storageInfo.StorageType;
3082 storage->FilesystemType = storageInfo.FilesystemType;
3083 storage->AccessCapability = storageInfo.AccessCapability;
3084 storage->MaxCapacity = storageInfo.MaxCapability;
3085 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3086 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3087 storage->StorageDescription = storageInfo.StorageDescription;
3088 storage->VolumeIdentifier = storageInfo.VolumeLabel;
3090 if(storage->FreeSpaceInBytes == (uint64_t) -1)
3092 *freespace = storage->FreeSpaceInBytes;
3097 * This function dumps out a large chunk of textual information
3098 * provided from the PTP protocol and additionally some extra
3099 * MTP-specific information where applicable.
3100 * @param device a pointer to the MTP device to report info from.
3102 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3105 PTPParams *params = (PTPParams *) device->params;
3106 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3107 LIBMTP_devicestorage_t *storage = device->storage;
3108 LIBMTP_device_extension_t *tmpext = device->extensions;
3110 printf("USB low-level info:\n");
3111 dump_usbinfo(ptp_usb);
3112 /* Print out some verbose information */
3113 printf("Device info:\n");
3114 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3115 printf(" Model: %s\n", params->deviceinfo.Model);
3116 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
3117 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
3118 printf(" Vendor extension ID: 0x%08x\n",
3119 params->deviceinfo.VendorExtensionID);
3120 printf(" Vendor extension description: %s\n",
3121 params->deviceinfo.VendorExtensionDesc);
3122 printf(" Detected object size: %d bits\n",
3123 device->object_bitsize);
3124 printf(" Extensions:\n");
3125 while (tmpext != NULL) {
3126 printf(" %s: %d.%d\n",
3130 tmpext = tmpext->next;
3132 printf("Supported operations:\n");
3133 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
3136 (void) ptp_render_opcode(params, params->deviceinfo.OperationsSupported[i],
3138 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
3140 printf("Events supported:\n");
3141 if (params->deviceinfo.EventsSupported_len == 0) {
3144 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3145 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
3148 printf("Device Properties Supported:\n");
3149 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3150 char const *propdesc = ptp_get_property_description(params,
3151 params->deviceinfo.DevicePropertiesSupported[i]);
3153 if (propdesc != NULL) {
3154 printf(" 0x%04x: %s\n",
3155 params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3157 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3158 printf(" 0x%04x: Unknown property\n", prop);
3162 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3163 printf("Playable File (Object) Types and Object Properties Supported:\n");
3164 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3167 uint16_t *props = NULL;
3168 uint32_t propcnt = 0;
3171 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3173 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3175 ret = ptp_mtp_getobjectpropssupported (params,
3176 params->deviceinfo.ImageFormats[i], &propcnt, &props);
3177 if (ret != PTP_RC_OK) {
3178 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3179 "error on query for object properties.");
3181 for (j=0;j<propcnt;j++) {
3182 PTPObjectPropDesc opd;
3185 printf(" %04x: %s", props[j],
3186 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3187 // Get a more verbose description
3188 ret = ptp_mtp_getobjectpropdesc(params, props[j],
3189 params->deviceinfo.ImageFormats[i],
3191 if (ret != PTP_RC_OK) {
3192 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3193 "LIBMTP_Dump_Device_Info(): "
3194 "could not get property description.");
3198 if (opd.DataType == PTP_DTC_STR) {
3199 printf(" STRING data type");
3200 switch (opd.FormFlag) {
3201 case PTP_OPFF_DateTime:
3202 printf(" DATETIME FORM");
3204 case PTP_OPFF_RegularExpression:
3205 printf(" REGULAR EXPRESSION FORM");
3207 case PTP_OPFF_LongString:
3208 printf(" LONG STRING FORM");
3214 if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3215 printf(" array of");
3218 switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3221 printf(" UNDEFINED data type");
3224 printf(" INT8 data type");
3225 switch (opd.FormFlag) {
3226 case PTP_OPFF_Range:
3227 printf(" range: MIN %d, MAX %d, STEP %d",
3228 opd.FORM.Range.MinimumValue.i8,
3229 opd.FORM.Range.MaximumValue.i8,
3230 opd.FORM.Range.StepSize.i8);
3232 case PTP_OPFF_Enumeration:
3233 printf(" enumeration: ");
3234 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3235 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3238 case PTP_OPFF_ByteArray:
3239 printf(" byte array: ");
3242 printf(" ANY 8BIT VALUE form");
3248 printf(" UINT8 data type");
3249 switch (opd.FormFlag) {
3250 case PTP_OPFF_Range:
3251 printf(" range: MIN %d, MAX %d, STEP %d",
3252 opd.FORM.Range.MinimumValue.u8,
3253 opd.FORM.Range.MaximumValue.u8,
3254 opd.FORM.Range.StepSize.u8);
3256 case PTP_OPFF_Enumeration:
3257 printf(" enumeration: ");
3258 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3259 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3262 case PTP_OPFF_ByteArray:
3263 printf(" byte array: ");
3266 printf(" ANY 8BIT VALUE form");
3272 printf(" INT16 data type");
3273 switch (opd.FormFlag) {
3274 case PTP_OPFF_Range:
3275 printf(" range: MIN %d, MAX %d, STEP %d",
3276 opd.FORM.Range.MinimumValue.i16,
3277 opd.FORM.Range.MaximumValue.i16,
3278 opd.FORM.Range.StepSize.i16);
3280 case PTP_OPFF_Enumeration:
3281 printf(" enumeration: ");
3282 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3283 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3287 printf(" ANY 16BIT VALUE form");
3292 case PTP_DTC_UINT16:
3293 printf(" UINT16 data type");
3294 switch (opd.FormFlag) {
3295 case PTP_OPFF_Range:
3296 printf(" range: MIN %d, MAX %d, STEP %d",
3297 opd.FORM.Range.MinimumValue.u16,
3298 opd.FORM.Range.MaximumValue.u16,
3299 opd.FORM.Range.StepSize.u16);
3301 case PTP_OPFF_Enumeration:
3302 printf(" enumeration: ");
3303 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3304 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3308 printf(" ANY 16BIT VALUE form");
3314 printf(" INT32 data type");
3315 switch (opd.FormFlag) {
3316 case PTP_OPFF_Range:
3317 printf(" range: MIN %d, MAX %d, STEP %d",
3318 opd.FORM.Range.MinimumValue.i32,
3319 opd.FORM.Range.MaximumValue.i32,
3320 opd.FORM.Range.StepSize.i32);
3322 case PTP_OPFF_Enumeration:
3323 printf(" enumeration: ");
3324 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3325 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3329 printf(" ANY 32BIT VALUE form");
3334 case PTP_DTC_UINT32:
3335 printf(" UINT32 data type");
3336 switch (opd.FormFlag) {
3337 case PTP_OPFF_Range:
3338 printf(" range: MIN %d, MAX %d, STEP %d",
3339 opd.FORM.Range.MinimumValue.u32,
3340 opd.FORM.Range.MaximumValue.u32,
3341 opd.FORM.Range.StepSize.u32);
3343 case PTP_OPFF_Enumeration:
3344 // Special pretty-print for FOURCC codes
3345 if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3346 printf(" enumeration of u32 casted FOURCC: ");
3347 for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3348 if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3352 fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3353 fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3354 fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3355 fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3358 printf("\"%s\", ", fourcc);
3362 printf(" enumeration: ");
3363 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3364 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3369 printf(" ANY 32BIT VALUE form");
3375 printf(" INT64 data type");
3378 case PTP_DTC_UINT64:
3379 printf(" UINT64 data type");
3382 case PTP_DTC_INT128:
3383 printf(" INT128 data type");
3386 case PTP_DTC_UINT128:
3387 printf(" UINT128 data type");
3391 printf(" UNKNOWN data type");
3398 printf(" READ ONLY");
3401 ptp_free_objectpropdesc(&opd);
3408 if(storage != NULL &&
3409 ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3410 printf("Storage Devices:\n");
3411 while(storage != NULL) {
3412 printf(" StorageID: 0x%08x\n",storage->id);
3413 printf(" StorageType: 0x%04x ",storage->StorageType);
3414 switch (storage->StorageType) {
3415 case PTP_ST_Undefined:
3416 printf("(undefined)\n");
3418 case PTP_ST_FixedROM:
3419 printf("fixed ROM storage\n");
3421 case PTP_ST_RemovableROM:
3422 printf("removable ROM storage\n");
3424 case PTP_ST_FixedRAM:
3425 printf("fixed RAM storage\n");
3427 case PTP_ST_RemovableRAM:
3428 printf("removable RAM storage\n");
3431 printf("UNKNOWN storage\n");
3434 printf(" FilesystemType: 0x%04x ",storage->FilesystemType);
3435 switch(storage->FilesystemType) {
3436 case PTP_FST_Undefined:
3437 printf("(undefined)\n");
3439 case PTP_FST_GenericFlat:
3440 printf("generic flat filesystem\n");
3442 case PTP_FST_GenericHierarchical:
3443 printf("generic hierarchical\n");
3449 printf("UNKNONWN filesystem type\n");
3452 printf(" AccessCapability: 0x%04x ",storage->AccessCapability);
3453 switch(storage->AccessCapability) {
3454 case PTP_AC_ReadWrite:
3455 printf("read/write\n");
3457 case PTP_AC_ReadOnly:
3458 printf("read only\n");
3460 case PTP_AC_ReadOnly_with_Object_Deletion:
3461 printf("read only + object deletion\n");
3464 printf("UNKNOWN access capability\n");
3467 printf(" MaxCapacity: %llu\n",
3468 (long long unsigned int) storage->MaxCapacity);
3469 printf(" FreeSpaceInBytes: %llu\n",
3470 (long long unsigned int) storage->FreeSpaceInBytes);
3471 printf(" FreeSpaceInObjects: %llu\n",
3472 (long long unsigned int) storage->FreeSpaceInObjects);
3473 printf(" StorageDescription: %s\n",storage->StorageDescription);
3474 printf(" VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3475 storage = storage->next;
3479 printf("Special directories:\n");
3480 printf(" Default music folder: 0x%08x\n",
3481 device->default_music_folder);
3482 printf(" Default playlist folder: 0x%08x\n",
3483 device->default_playlist_folder);
3484 printf(" Default picture folder: 0x%08x\n",
3485 device->default_picture_folder);
3486 printf(" Default video folder: 0x%08x\n",
3487 device->default_video_folder);
3488 printf(" Default organizer folder: 0x%08x\n",
3489 device->default_organizer_folder);
3490 printf(" Default zencast folder: 0x%08x\n",
3491 device->default_zencast_folder);
3492 printf(" Default album folder: 0x%08x\n",
3493 device->default_album_folder);
3494 printf(" Default text folder: 0x%08x\n",
3495 device->default_text_folder);
3499 * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3500 * operation code (0x1010).
3501 * @param device a pointer to the device to reset.
3502 * @return 0 on success, any other value means failure.
3504 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3506 PTPParams *params = (PTPParams *) device->params;
3509 if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3510 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3511 "LIBMTP_Reset_Device(): "
3512 "device does not support resetting.");
3515 ret = ptp_resetdevice(params);
3516 if (ret != PTP_RC_OK) {
3517 add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3524 * This retrieves the manufacturer name of an MTP device.
3525 * @param device a pointer to the device to get the manufacturer name for.
3526 * @return a newly allocated UTF-8 string representing the manufacturer name.
3527 * The string must be freed by the caller after use. If the call
3528 * was unsuccessful this will contain NULL.
3530 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3532 char *retmanuf = NULL;
3533 PTPParams *params = (PTPParams *) device->params;
3535 if (params->deviceinfo.Manufacturer != NULL) {
3536 retmanuf = strdup(params->deviceinfo.Manufacturer);
3542 * This retrieves the model name (often equal to product name)
3544 * @param device a pointer to the device to get the model name for.
3545 * @return a newly allocated UTF-8 string representing the model name.
3546 * The string must be freed by the caller after use. If the call
3547 * was unsuccessful this will contain NULL.
3549 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3551 char *retmodel = NULL;
3552 PTPParams *params = (PTPParams *) device->params;
3554 if (params->deviceinfo.Model != NULL) {
3555 retmodel = strdup(params->deviceinfo.Model);
3561 * This retrieves the serial number of an MTP device.
3562 * @param device a pointer to the device to get the serial number for.
3563 * @return a newly allocated UTF-8 string representing the serial number.
3564 * The string must be freed by the caller after use. If the call
3565 * was unsuccessful this will contain NULL.
3567 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3569 char *retnumber = NULL;
3570 PTPParams *params = (PTPParams *) device->params;
3572 if (params->deviceinfo.SerialNumber != NULL) {
3573 retnumber = strdup(params->deviceinfo.SerialNumber);
3579 * This retrieves the device version (hardware and firmware version) of an
3581 * @param device a pointer to the device to get the device version for.
3582 * @return a newly allocated UTF-8 string representing the device version.
3583 * The string must be freed by the caller after use. If the call
3584 * was unsuccessful this will contain NULL.
3586 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3588 char *retversion = NULL;
3589 PTPParams *params = (PTPParams *) device->params;
3591 if (params->deviceinfo.DeviceVersion != NULL) {
3592 retversion = strdup(params->deviceinfo.DeviceVersion);
3599 * This retrieves the "friendly name" of an MTP device. Usually
3600 * this is simply the name of the owner or something like
3601 * "John Doe's Digital Audio Player". This property should be supported
3602 * by all MTP devices.
3603 * @param device a pointer to the device to get the friendly name for.
3604 * @return a newly allocated UTF-8 string representing the friendly name.
3605 * The string must be freed by the caller after use.
3606 * @see LIBMTP_Set_Friendlyname()
3608 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3610 PTPPropertyValue propval;
3611 char *retstring = NULL;
3612 PTPParams *params = (PTPParams *) device->params;
3615 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3619 ret = ptp_getdevicepropvalue(params,
3620 PTP_DPC_MTP_DeviceFriendlyName,
3623 if (ret != PTP_RC_OK) {
3624 add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3627 if (propval.str != NULL) {
3628 retstring = strdup(propval.str);
3635 * Sets the "friendly name" of an MTP device.
3636 * @param device a pointer to the device to set the friendly name for.
3637 * @param friendlyname the new friendly name for the device.
3638 * @return 0 on success, any other value means failure.
3639 * @see LIBMTP_Get_Friendlyname()
3641 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3642 char const * const friendlyname)
3644 PTPPropertyValue propval;
3645 PTPParams *params = (PTPParams *) device->params;
3648 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3651 propval.str = (char *) friendlyname;
3652 ret = ptp_setdevicepropvalue(params,
3653 PTP_DPC_MTP_DeviceFriendlyName,
3656 if (ret != PTP_RC_OK) {
3657 add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3664 * This retrieves the syncronization partner of an MTP device. This
3665 * property should be supported by all MTP devices.
3666 * @param device a pointer to the device to get the sync partner for.
3667 * @return a newly allocated UTF-8 string representing the synchronization
3668 * partner. The string must be freed by the caller after use.
3669 * @see LIBMTP_Set_Syncpartner()
3671 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3673 PTPPropertyValue propval;
3674 char *retstring = NULL;
3675 PTPParams *params = (PTPParams *) device->params;
3678 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3682 ret = ptp_getdevicepropvalue(params,
3683 PTP_DPC_MTP_SynchronizationPartner,
3686 if (ret != PTP_RC_OK) {
3687 add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3690 if (propval.str != NULL) {
3691 retstring = strdup(propval.str);
3699 * Sets the synchronization partner of an MTP device. Note that
3700 * we have no idea what the effect of setting this to "foobar"
3701 * may be. But the general idea seems to be to tell which program
3702 * shall synchronize with this device and tell others to leave
3704 * @param device a pointer to the device to set the sync partner for.
3705 * @param syncpartner the new synchronization partner for the device.
3706 * @return 0 on success, any other value means failure.
3707 * @see LIBMTP_Get_Syncpartner()
3709 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3710 char const * const syncpartner)
3712 PTPPropertyValue propval;
3713 PTPParams *params = (PTPParams *) device->params;
3716 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3719 propval.str = (char *) syncpartner;
3720 ret = ptp_setdevicepropvalue(params,
3721 PTP_DPC_MTP_SynchronizationPartner,
3724 if (ret != PTP_RC_OK) {
3725 add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3732 * Checks if the device can stora a file of this size or
3734 * @param device a pointer to the device.
3735 * @param filesize the size of the file to check whether it will fit.
3736 * @param storageid the ID of the storage to try to fit the file on.
3737 * @return 0 if the file fits, any other value means failure.
3739 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3740 LIBMTP_devicestorage_t *storage,
3741 uint64_t const filesize) {
3742 PTPParams *params = (PTPParams *) device->params;
3746 // If we cannot check the storage, no big deal.
3747 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3751 ret = get_storage_freespace(device, storage, &freebytes);
3753 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3754 "check_if_file_fits(): error checking free storage.");
3758 if (filesize > freebytes) {
3767 * This function retrieves the current battery level on the device.
3768 * @param device a pointer to the device to get the battery level for.
3769 * @param maximum_level a pointer to a variable that will hold the
3770 * maximum level of the battery if the call was successful.
3771 * @param current_level a pointer to a variable that will hold the
3772 * current level of the battery if the call was successful.
3773 * A value of 0 means that the device is on external power.
3774 * @return 0 if the storage info was successfully retrieved, any other
3775 * means failure. A typical cause of failure is that
3776 * the device does not support the battery level property.
3778 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3779 uint8_t * const maximum_level,
3780 uint8_t * const current_level)
3782 PTPPropertyValue propval;
3784 PTPParams *params = (PTPParams *) device->params;
3785 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3790 if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3791 !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3795 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3796 &propval, PTP_DTC_UINT8);
3797 if (ret != PTP_RC_OK) {
3798 add_ptp_error_to_errorstack(device, ret,
3799 "LIBMTP_Get_Batterylevel(): "
3800 "could not get device property value.");
3804 *maximum_level = device->maximum_battery_level;
3805 *current_level = propval.u8;
3812 * Formats device storage (if the device supports the operation).
3813 * WARNING: This WILL delete all data from the device. Make sure you've
3814 * got confirmation from the user BEFORE you call this function.
3816 * @param device a pointer to the device containing the storage to format.
3817 * @param storage the actual storage to format.
3818 * @return 0 on success, any other value means failure.
3820 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3821 LIBMTP_devicestorage_t *storage)
3824 PTPParams *params = (PTPParams *) device->params;
3826 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3827 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3828 "LIBMTP_Format_Storage(): "
3829 "device does not support formatting storage.");
3832 ret = ptp_formatstore(params, storage->id);
3833 if (ret != PTP_RC_OK) {
3834 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3835 "failed to format storage.");
3842 * Helper function to extract a unicode property off a device.
3843 * This is the standard way of retrieveing unicode device
3844 * properties as described by the PTP spec.
3845 * @param device a pointer to the device to get the property from.
3846 * @param unicstring a pointer to a pointer that will hold the
3847 * property after this call is completed.
3848 * @param property the property to retrieve.
3849 * @return 0 on success, any other value means failure.
3851 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3852 char **unicstring, uint16_t property)
3854 PTPPropertyValue propval;
3855 PTPParams *params = (PTPParams *) device->params;
3860 if (!ptp_property_issupported(params, property)) {
3864 // Unicode strings are 16bit unsigned integer arrays.
3865 ret = ptp_getdevicepropvalue(params,
3869 if (ret != PTP_RC_OK) {
3870 // TODO: add a note on WHICH property that we failed to get.
3872 add_ptp_error_to_errorstack(device, ret,
3873 "get_device_unicode_property(): "
3874 "failed to get unicode property.");
3878 // Extract the actual array.
3879 // printf("Array of %d elements\n", propval.a.count);
3880 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3881 for (i = 0; i < propval.a.count; i++) {
3882 tmp[i] = propval.a.v[i].u16;
3883 // printf("%04x ", tmp[i]);
3885 tmp[propval.a.count] = 0x0000U;
3888 *unicstring = utf16_to_utf8(device, tmp);
3896 * This function returns the secure time as an XML document string from
3898 * @param device a pointer to the device to get the secure time for.
3899 * @param sectime the secure time string as an XML document or NULL if the call
3900 * failed or the secure time property is not supported. This string
3901 * must be <code>free()</code>:ed by the caller after use.
3902 * @return 0 on success, any other value means failure.
3904 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3906 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3910 * This function returns the device (public key) certificate as an
3911 * XML document string from the device.
3912 * @param device a pointer to the device to get the device certificate for.
3913 * @param devcert the device certificate as an XML string or NULL if the call
3914 * failed or the device certificate property is not supported. This
3915 * string must be <code>free()</code>:ed by the caller after use.
3916 * @return 0 on success, any other value means failure.
3918 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3920 return get_device_unicode_property(device, devcert,
3921 PTP_DPC_MTP_DeviceCertificate);
3925 * This function retrieves a list of supported file types, i.e. the file
3926 * types that this device claims it supports, e.g. audio file types that
3927 * the device can play etc. This list is mitigated to
3928 * inlcude the file types that libmtp can handle, i.e. it will not list
3929 * filetypes that libmtp will handle internally like playlists and folders.
3930 * @param device a pointer to the device to get the filetype capabilities for.
3931 * @param filetypes a pointer to a pointer that will hold the list of
3932 * supported filetypes if the call was successful. This list must
3933 * be <code>free()</code>:ed by the caller after use.
3934 * @param length a pointer to a variable that will hold the length of the
3935 * list of supported filetypes if the call was successful.
3936 * @return 0 on success, any other value means failure.
3937 * @see LIBMTP_Get_Filetype_Description()
3939 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3940 uint16_t * const length)
3942 PTPParams *params = (PTPParams *) device->params;
3943 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3944 uint16_t *localtypes;
3945 uint16_t localtypelen;
3948 // This is more memory than needed if there are unknown types, but what the heck.
3949 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
3952 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3953 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
3954 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
3955 localtypes[localtypelen] = localtype;
3959 // The forgotten Ogg support on YP-10 and others...
3960 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
3961 localtypes = (uint16_t *) realloc(localtypes,
3962 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3963 localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
3966 // The forgotten FLAC support on Cowon iAudio S9 and others...
3967 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
3968 localtypes = (uint16_t *) realloc(localtypes,
3969 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3970 localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
3974 *filetypes = localtypes;
3975 *length = localtypelen;
3981 * This function checks if the device has some specific capabilities, in
3982 * order to avoid calling APIs that may disturb the device.
3984 * @param device a pointer to the device to check the capability on.
3985 * @param cap the capability to check.
3986 * @return 0 if not supported, any other value means the device has the
3987 * requested capability.
3989 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
3992 case LIBMTP_DEVICECAP_GetPartialObject:
3993 return (ptp_operation_issupported(device->params,
3994 PTP_OC_GetPartialObject) ||
3995 ptp_operation_issupported(device->params,
3996 PTP_OC_ANDROID_GetPartialObject64));
3997 case LIBMTP_DEVICECAP_SendPartialObject:
3998 return ptp_operation_issupported(device->params,
3999 PTP_OC_ANDROID_SendPartialObject);
4000 case LIBMTP_DEVICECAP_EditObjects:
4001 return (ptp_operation_issupported(device->params,
4002 PTP_OC_ANDROID_TruncateObject) &&
4003 ptp_operation_issupported(device->params,
4004 PTP_OC_ANDROID_BeginEditObject) &&
4005 ptp_operation_issupported(device->params,
4006 PTP_OC_ANDROID_EndEditObject));
4008 * Handle other capabilities here, this is also a good place to
4009 * blacklist some advanced operations on specific devices if need
4020 * This function updates all the storage id's of a device and their
4021 * properties, then creates a linked list and puts the list head into
4022 * the device struct. It also optionally sorts this list. If you want
4023 * to display storage information in your application you should call
4024 * this function, then dereference the device struct
4025 * (<code>device->storage</code>) to get out information on the storage.
4027 * You need to call this everytime you want to update the
4028 * <code>device->storage</code> list, for example anytime you need
4029 * to check available storage somewhere.
4031 * <b>WARNING:</b> since this list is dynamically updated, do not
4032 * reference its fields in external applications by pointer! E.g
4033 * do not put a reference to any <code>char *</code> field. instead
4034 * <code>strncpy()</code> it!
4036 * @param device a pointer to the device to get the storage for.
4037 * @param sortby an integer that determines the sorting of the storage list.
4038 * Valid sort methods are defined in libmtp.h with beginning with
4039 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4041 * @return 0 on success, 1 success but only with storage id's, storage
4042 * properities could not be retrieved and -1 means failure.
4044 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4047 PTPStorageInfo storageInfo;
4048 PTPParams *params = (PTPParams *) device->params;
4049 PTPStorageIDs storageIDs;
4050 LIBMTP_devicestorage_t *storage = NULL;
4051 LIBMTP_devicestorage_t *storageprev = NULL;
4053 if (device->storage != NULL)
4054 free_storage_list(device);
4056 // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4058 if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4060 if (storageIDs.n < 1)
4063 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4064 for (i = 0; i < storageIDs.n; i++) {
4066 storage = (LIBMTP_devicestorage_t *)
4067 malloc(sizeof(LIBMTP_devicestorage_t));
4068 storage->prev = storageprev;
4069 if (storageprev != NULL)
4070 storageprev->next = storage;
4071 if (device->storage == NULL)
4072 device->storage = storage;
4074 storage->id = storageIDs.Storage[i];
4075 storage->StorageType = PTP_ST_Undefined;
4076 storage->FilesystemType = PTP_FST_Undefined;
4077 storage->AccessCapability = PTP_AC_ReadWrite;
4078 storage->MaxCapacity = (uint64_t) -1;
4079 storage->FreeSpaceInBytes = (uint64_t) -1;
4080 storage->FreeSpaceInObjects = (uint64_t) -1;
4081 storage->StorageDescription = strdup("Unknown storage");
4082 storage->VolumeIdentifier = strdup("Unknown volume");
4083 storage->next = NULL;
4085 storageprev = storage;
4087 free(storageIDs.Storage);
4090 for (i = 0; i < storageIDs.n; i++) {
4092 ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4093 if (ret != PTP_RC_OK) {
4094 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4095 "Could not get storage info.");
4096 if (device->storage != NULL) {
4097 free_storage_list(device);
4102 storage = (LIBMTP_devicestorage_t *)
4103 malloc(sizeof(LIBMTP_devicestorage_t));
4104 storage->prev = storageprev;
4105 if (storageprev != NULL)
4106 storageprev->next = storage;
4107 if (device->storage == NULL)
4108 device->storage = storage;
4110 storage->id = storageIDs.Storage[i];
4111 storage->StorageType = storageInfo.StorageType;
4112 storage->FilesystemType = storageInfo.FilesystemType;
4113 storage->AccessCapability = storageInfo.AccessCapability;
4114 storage->MaxCapacity = storageInfo.MaxCapability;
4115 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4116 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4117 storage->StorageDescription = storageInfo.StorageDescription;
4118 storage->VolumeIdentifier = storageInfo.VolumeLabel;
4119 storage->next = NULL;
4121 storageprev = storage;
4124 if (storage != NULL)
4125 storage->next = NULL;
4127 sort_storage_by(device,sortby);
4128 free(storageIDs.Storage);
4134 * This creates a new file metadata structure and allocates memory
4135 * for it. Notice that if you add strings to this structure they
4136 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4137 * operation later, so be careful of using strdup() when assigning
4141 * LIBMTP_file_t *file = LIBMTP_new_file_t();
4142 * file->filename = strdup(namestr);
4144 * LIBMTP_destroy_file_t(file);
4147 * @return a pointer to the newly allocated metadata structure.
4148 * @see LIBMTP_destroy_file_t()
4150 LIBMTP_file_t *LIBMTP_new_file_t(void)
4152 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4156 new->filename = NULL;
4159 new->storage_id = 0;
4161 new->modificationdate = 0;
4162 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4168 * This destroys a file metadata structure and deallocates the memory
4169 * used by it, including any strings. Never use a file metadata
4170 * structure again after calling this function on it.
4171 * @param file the file metadata to destroy.
4172 * @see LIBMTP_new_file_t()
4174 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4179 if (file->filename != NULL)
4180 free(file->filename);
4186 * Helper function that takes one PTP object and creates a
4187 * LIBMTP_file_t metadata entry.
4189 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4191 PTPParams *params = (PTPParams *) device->params;
4192 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4193 LIBMTP_file_t *file;
4196 // Allocate a new file type
4197 file = LIBMTP_new_file_t();
4199 file->parent_id = ob->oi.ParentObject;
4200 file->storage_id = ob->oi.StorageID;
4203 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4206 * A special quirk for devices that doesn't quite
4207 * remember that some files marked as "unknown" type are
4208 * actually OGG or FLAC files. We look at the filename extension
4209 * and see if it happens that this was atleast named "ogg" or "flac"
4210 * and fall back on this heuristic approach in that case,
4211 * for these bugged devices only.
4213 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4214 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4215 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4216 has_ogg_extension(file->filename)) {
4217 file->filetype = LIBMTP_FILETYPE_OGG;
4220 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4221 file->filetype = LIBMTP_FILETYPE_FLAC;
4225 // Set the modification date
4226 file->modificationdate = ob->oi.ModificationDate;
4228 // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4229 file->filesize = ob->oi.ObjectCompressedSize;
4230 if (ob->oi.Filename != NULL) {
4231 file->filename = strdup(ob->oi.Filename);
4234 // This is a unique ID so we can keep track of the file.
4235 file->item_id = ob->oid;
4238 * If we have a cached, large set of metadata, then use it!
4241 MTPProperties *prop = ob->mtpprops;
4243 for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4244 // Pick ObjectSize here...
4245 if (prop->property == PTP_OPC_ObjectSize) {
4246 // This may already be set, but this 64bit precision value
4247 // is better than the PTP 32bit value, so let it override.
4248 if (device->object_bitsize == 64) {
4249 file->filesize = prop->propval.u64;
4251 file->filesize = prop->propval.u32;
4256 } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4257 uint16_t *props = NULL;
4258 uint32_t propcnt = 0;
4261 // First see which properties can be retrieved for this object format
4262 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4263 if (ret != PTP_RC_OK) {
4264 add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4265 // Silently fall through.
4267 for (i = 0; i < propcnt; i++) {
4269 case PTP_OPC_ObjectSize:
4270 if (device->object_bitsize == 64) {
4271 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4273 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4289 * This function retrieves the metadata for a single file off
4292 * Do not call this function repeatedly! The file handles are linearly
4293 * searched O(n) and the call may involve (slow) USB traffic, so use
4294 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4295 * as an efficient data structure such as a hash list.
4297 * Incidentally this function will return metadata for
4298 * a folder (association) as well, but this is not a proper use
4299 * of it, it is intended for file manipulation, not folder manipulation.
4301 * @param device a pointer to the device to get the file metadata from.
4302 * @param fileid the object ID of the file that you want the metadata for.
4303 * @return a metadata entry on success or NULL on failure.
4304 * @see LIBMTP_Get_Filelisting()
4306 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4308 PTPParams *params = (PTPParams *) device->params;
4312 // Get all the handles if we haven't already done that
4313 // (Only on cached devices.)
4314 if (device->cached && params->nrofobjects == 0) {
4315 flush_handles(device);
4318 ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4319 if (ret != PTP_RC_OK)
4322 return obj2file(device, ob);
4326 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4328 * @see LIBMTP_Get_Filelisting_With_Callback()
4330 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4332 LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4333 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4334 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4338 * This returns a long list of all files available
4339 * on the current MTP device. Folders will not be returned, but abstract
4340 * entities like playlists and albums will show up as "files". Typical usage:
4343 * LIBMTP_file_t *filelist;
4345 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4346 * while (filelist != NULL) {
4347 * LIBMTP_file_t *tmp;
4349 * // Do something on each element in the list here...
4351 * filelist = filelist->next;
4352 * LIBMTP_destroy_file_t(tmp);
4356 * If you want to group your file listing by storage (per storage unit) or
4357 * arrange files into folders, you must dereference the <code>storage_id</code>
4358 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4359 * struct. To arrange by folders or files you typically have to create the proper
4360 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4361 * <code>LIBMTP_Get_Folder_List()</code> first.
4363 * @param device a pointer to the device to get the file listing for.
4364 * @param callback a function to be called during the tracklisting retrieveal
4365 * for displaying progress bars etc, or NULL if you don't want
4367 * @param data a user-defined pointer that is passed along to
4368 * the <code>progress</code> function in order to
4369 * pass along some user defined data to the progress
4370 * updates. If not used, set this to NULL.
4371 * @return a list of files that can be followed using the <code>next</code>
4372 * field of the <code>LIBMTP_file_t</code> data structure.
4373 * Each of the metadata tags must be freed after use, and may
4374 * contain only partial metadata information, i.e. one or several
4375 * fields may be NULL or 0.
4376 * @see LIBMTP_Get_Filemetadata()
4378 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4379 LIBMTP_progressfunc_t const callback,
4380 void const * const data)
4383 LIBMTP_file_t *retfiles = NULL;
4384 LIBMTP_file_t *curfile = NULL;
4385 PTPParams *params = (PTPParams *) device->params;
4387 // Get all the handles if we haven't already done that
4388 if (params->nrofobjects == 0) {
4389 flush_handles(device);
4392 for (i = 0; i < params->nrofobjects; i++) {
4393 LIBMTP_file_t *file;
4396 if (callback != NULL)
4397 callback(i, params->nrofobjects, data);
4399 ob = ¶ms->objects[i];
4401 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4402 // MTP use this object format for folders which means
4403 // these "files" will turn up on a folder listing instead.
4408 file = obj2file(device, ob);
4413 // Add track to a list that will be returned afterwards.
4414 if (retfiles == NULL) {
4418 curfile->next = file;
4422 // Call listing callback
4423 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4425 } // Handle counting loop
4430 * This function retrieves the contents of a certain folder
4431 * with id parent on a certain storage on a certain device.
4432 * The result contains both files and folders.
4433 * The device used with this operations must have been opened with
4434 * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4436 * NOTE: the request will always perform I/O with the device.
4437 * @param device a pointer to the MTP device to report info from.
4438 * @param storage a storage on the device to report info from. If
4439 * 0 is passed in, the files for the given parent will be
4440 * searched across all available storages.
4441 * @param parent the parent folder id.
4443 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4444 uint32_t const storage,
4445 uint32_t const parent)
4447 PTPParams *params = (PTPParams *) device->params;
4448 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4449 LIBMTP_file_t *retfiles = NULL;
4450 LIBMTP_file_t *curfile = NULL;
4451 PTPObjectHandles currentHandles;
4456 if (device->cached) {
4457 // This function is only supposed to be used by devices
4458 // opened as uncached!
4459 LIBMTP_ERROR("tried to use %s on a cached device!\n",
4464 if (FLAG_BROKEN_GET_OBJECT_PROPVAL(ptp_usb)) {
4465 // These devices cannot handle the commands needed for
4467 LIBMTP_ERROR("tried to use %s on an unsupported device, "
4468 "this command does not work on all devices "
4469 "due to missing low-level support to read "
4470 "information on individual tracks\n",
4476 storageid = PTP_GOH_ALL_STORAGE;
4478 storageid = storage;
4480 ret = ptp_getobjecthandles(params,
4482 PTP_GOH_ALL_FORMATS,
4486 if (ret != PTP_RC_OK) {
4487 add_ptp_error_to_errorstack(device, ret,
4488 "LIBMTP_Get_Files_And_Folders(): could not get object handles.");
4492 if (currentHandles.Handler == NULL || currentHandles.n == 0)
4495 for (i = 0; i < currentHandles.n; i++) {
4496 LIBMTP_file_t *file;
4498 // Get metadata for one file, if it fails, try next file
4499 file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4503 // Add track to a list that will be returned afterwards.
4504 if (curfile == NULL) {
4508 curfile->next = file;
4513 free(currentHandles.Handler);
4515 // Return a pointer to the original first file
4522 * This creates a new track metadata structure and allocates memory
4523 * for it. Notice that if you add strings to this structure they
4524 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4525 * operation later, so be careful of using strdup() when assigning
4529 * LIBMTP_track_t *track = LIBMTP_new_track_t();
4530 * track->title = strdup(titlestr);
4532 * LIBMTP_destroy_track_t(track);
4535 * @return a pointer to the newly allocated metadata structure.
4536 * @see LIBMTP_destroy_track_t()
4538 LIBMTP_track_t *LIBMTP_new_track_t(void)
4540 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4546 new->storage_id = 0;
4549 new->composer = NULL;
4553 new->filename = NULL;
4555 new->tracknumber = 0;
4557 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4558 new->samplerate = 0;
4559 new->nochannels = 0;
4562 new->bitratetype = 0;
4565 new->modificationdate = 0;
4571 * This destroys a track metadata structure and deallocates the memory
4572 * used by it, including any strings. Never use a track metadata
4573 * structure again after calling this function on it.
4574 * @param track the track metadata to destroy.
4575 * @see LIBMTP_new_track_t()
4577 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4579 if (track == NULL) {
4582 if (track->title != NULL)
4584 if (track->artist != NULL)
4585 free(track->artist);
4586 if (track->composer != NULL)
4587 free(track->composer);
4588 if (track->album != NULL)
4590 if (track->genre != NULL)
4592 if (track->date != NULL)
4594 if (track->filename != NULL)
4595 free(track->filename);
4601 * This function maps and copies a property onto the track metadata if applicable.
4603 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4605 switch (prop->property) {
4607 if (prop->propval.str != NULL)
4608 track->title = strdup(prop->propval.str);
4610 track->title = NULL;
4612 case PTP_OPC_Artist:
4613 if (prop->propval.str != NULL)
4614 track->artist = strdup(prop->propval.str);
4616 track->artist = NULL;
4618 case PTP_OPC_Composer:
4619 if (prop->propval.str != NULL)
4620 track->composer = strdup(prop->propval.str);
4622 track->composer = NULL;
4624 case PTP_OPC_Duration:
4625 track->duration = prop->propval.u32;
4628 track->tracknumber = prop->propval.u16;
4631 if (prop->propval.str != NULL)
4632 track->genre = strdup(prop->propval.str);
4634 track->genre = NULL;
4636 case PTP_OPC_AlbumName:
4637 if (prop->propval.str != NULL)
4638 track->album = strdup(prop->propval.str);
4640 track->album = NULL;
4642 case PTP_OPC_OriginalReleaseDate:
4643 if (prop->propval.str != NULL)
4644 track->date = strdup(prop->propval.str);
4648 // These are, well not so important.
4649 case PTP_OPC_SampleRate:
4650 track->samplerate = prop->propval.u32;
4652 case PTP_OPC_NumberOfChannels:
4653 track->nochannels = prop->propval.u16;
4655 case PTP_OPC_AudioWAVECodec:
4656 track->wavecodec = prop->propval.u32;
4658 case PTP_OPC_AudioBitRate:
4659 track->bitrate = prop->propval.u32;
4661 case PTP_OPC_BitRateType:
4662 track->bitratetype = prop->propval.u16;
4664 case PTP_OPC_Rating:
4665 track->rating = prop->propval.u16;
4667 case PTP_OPC_UseCount:
4668 track->usecount = prop->propval.u32;
4670 case PTP_OPC_ObjectSize:
4671 if (device->object_bitsize == 64) {
4672 track->filesize = prop->propval.u64;
4674 track->filesize = prop->propval.u32;
4683 * This function retrieves the track metadata for a track
4684 * given by a unique ID.
4685 * @param device a pointer to the device to get the track metadata off.
4686 * @param trackid the unique ID of the track.
4687 * @param objectformat the object format of this track, so we know what it supports.
4688 * @param track a metadata set to fill in.
4690 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4691 LIBMTP_track_t *track)
4694 PTPParams *params = (PTPParams *) device->params;
4696 MTPProperties *prop;
4700 * If we have a cached, large set of metadata, then use it!
4702 ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4704 prop = ob->mtpprops;
4705 for (i=0;i<ob->nrofmtpprops;i++,prop++)
4706 pick_property_to_track_metadata(device, prop, track);
4708 uint16_t *props = NULL;
4709 uint32_t propcnt = 0;
4711 // First see which properties can be retrieved for this object format
4712 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4713 if (ret != PTP_RC_OK) {
4714 add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4715 // Just bail out for now, nothing is ever set.
4718 for (i=0;i<propcnt;i++) {
4721 track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4723 case PTP_OPC_Artist:
4724 track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4726 case PTP_OPC_Composer:
4727 track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4729 case PTP_OPC_Duration:
4730 track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4733 track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4736 track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4738 case PTP_OPC_AlbumName:
4739 track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4741 case PTP_OPC_OriginalReleaseDate:
4742 track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4744 // These are, well not so important.
4745 case PTP_OPC_SampleRate:
4746 track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4748 case PTP_OPC_NumberOfChannels:
4749 track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4751 case PTP_OPC_AudioWAVECodec:
4752 track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4754 case PTP_OPC_AudioBitRate:
4755 track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4757 case PTP_OPC_BitRateType:
4758 track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4760 case PTP_OPC_Rating:
4761 track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4763 case PTP_OPC_UseCount:
4764 track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4766 case PTP_OPC_ObjectSize:
4767 if (device->object_bitsize == 64) {
4768 track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4770 track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4781 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4783 * @see LIBMTP_Get_Tracklisting_With_Callback()
4785 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4787 LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4788 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4789 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4793 * This returns a long list of all tracks available on the current MTP device.
4794 * Tracks include multimedia objects, both music tracks and video tracks.
4798 * LIBMTP_track_t *tracklist;
4800 * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4801 * while (tracklist != NULL) {
4802 * LIBMTP_track_t *tmp;
4804 * // Do something on each element in the list here...
4806 * tracklist = tracklist->next;
4807 * LIBMTP_destroy_track_t(tmp);
4811 * If you want to group your track listing by storage (per storage unit) or
4812 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4813 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4814 * struct. To arrange by folders or files you typically have to create the proper
4815 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4816 * <code>LIBMTP_Get_Folder_List()</code> first.
4818 * @param device a pointer to the device to get the track listing for.
4819 * @param callback a function to be called during the tracklisting retrieveal
4820 * for displaying progress bars etc, or NULL if you don't want
4822 * @param data a user-defined pointer that is passed along to
4823 * the <code>progress</code> function in order to
4824 * pass along some user defined data to the progress
4825 * updates. If not used, set this to NULL.
4826 * @return a list of tracks that can be followed using the <code>next</code>
4827 * field of the <code>LIBMTP_track_t</code> data structure.
4828 * Each of the metadata tags must be freed after use, and may
4829 * contain only partial metadata information, i.e. one or several
4830 * fields may be NULL or 0.
4831 * @see LIBMTP_Get_Trackmetadata()
4833 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4834 LIBMTP_progressfunc_t const callback,
4835 void const * const data)
4837 return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4842 * This returns a long list of all tracks available on the current MTP device.
4843 * Tracks include multimedia objects, both music tracks and video tracks.
4847 * LIBMTP_track_t *tracklist;
4849 * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4850 * while (tracklist != NULL) {
4851 * LIBMTP_track_t *tmp;
4853 * // Do something on each element in the list here...
4855 * tracklist = tracklist->next;
4856 * LIBMTP_destroy_track_t(tmp);
4860 * If you want to group your track listing by storage (per storage unit) or
4861 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4862 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4863 * struct. To arrange by folders or files you typically have to create the proper
4864 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4865 * <code>LIBMTP_Get_Folder_List()</code> first.
4867 * @param device a pointer to the device to get the track listing for.
4868 * @param storage_id ID of device storage (if null, no filter)
4869 * @param callback a function to be called during the tracklisting retrieveal
4870 * for displaying progress bars etc, or NULL if you don't want
4872 * @param data a user-defined pointer that is passed along to
4873 * the <code>progress</code> function in order to
4874 * pass along some user defined data to the progress
4875 * updates. If not used, set this to NULL.
4876 * @return a list of tracks that can be followed using the <code>next</code>
4877 * field of the <code>LIBMTP_track_t</code> data structure.
4878 * Each of the metadata tags must be freed after use, and may
4879 * contain only partial metadata information, i.e. one or several
4880 * fields may be NULL or 0.
4881 * @see LIBMTP_Get_Trackmetadata()
4883 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4884 LIBMTP_progressfunc_t const callback,
4885 void const * const data)
4888 LIBMTP_track_t *retracks = NULL;
4889 LIBMTP_track_t *curtrack = NULL;
4890 PTPParams *params = (PTPParams *) device->params;
4891 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4893 // Get all the handles if we haven't already done that
4894 if (params->nrofobjects == 0) {
4895 flush_handles(device);
4898 for (i = 0; i < params->nrofobjects; i++) {
4899 LIBMTP_track_t *track;
4901 LIBMTP_filetype_t mtptype;
4903 if (callback != NULL)
4904 callback(i, params->nrofobjects, data);
4906 ob = ¶ms->objects[i];
4907 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4909 // Ignore stuff we don't know how to handle...
4910 // TODO: get this list as an intersection of the sets
4911 // supported by the device and the from the device and
4912 // all known track files?
4913 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4914 // This row lets through undefined files for examination since they may be forgotten OGG files.
4915 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4916 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4917 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4918 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4920 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4924 // Ignore stuff that isn't into the storage device
4925 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4928 // Allocate a new track type
4929 track = LIBMTP_new_track_t();
4931 // This is some sort of unique ID so we can keep track of the track.
4932 track->item_id = ob->oid;
4933 track->parent_id = ob->oi.ParentObject;
4934 track->storage_id = ob->oi.StorageID;
4935 track->modificationdate = ob->oi.ModificationDate;
4937 track->filetype = mtptype;
4939 // Original file-specific properties
4940 track->filesize = ob->oi.ObjectCompressedSize;
4941 if (ob->oi.Filename != NULL) {
4942 track->filename = strdup(ob->oi.Filename);
4945 get_track_metadata(device, ob->oi.ObjectFormat, track);
4948 * A special quirk for iriver devices that doesn't quite
4949 * remember that some files marked as "unknown" type are
4950 * actually OGG or FLAC files. We look at the filename extension
4951 * and see if it happens that this was atleast named "ogg" or "flac"
4952 * and fall back on this heuristic approach in that case,
4953 * for these bugged devices only.
4955 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
4956 track->filename != NULL) {
4957 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4958 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4959 has_ogg_extension(track->filename))
4960 track->filetype = LIBMTP_FILETYPE_OGG;
4961 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
4962 has_flac_extension(track->filename))
4963 track->filetype = LIBMTP_FILETYPE_FLAC;
4965 // This was not an OGG/FLAC file so discard it and continue
4966 LIBMTP_destroy_track_t(track);
4971 // Add track to a list that will be returned afterwards.
4972 if (retracks == NULL) {
4976 curtrack->next = track;
4980 // Call listing callback
4981 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4983 } // Handle counting loop
4988 * This function retrieves the metadata for a single track off
4991 * Do not call this function repeatedly! The track handles are linearly
4992 * searched O(n) and the call may involve (slow) USB traffic, so use
4993 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
4994 * as an efficient data structure such as a hash list.
4996 * @param device a pointer to the device to get the track metadata from.
4997 * @param trackid the object ID of the track that you want the metadata for.
4998 * @return a track metadata entry on success or NULL on failure.
4999 * @see LIBMTP_Get_Tracklisting()
5001 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
5003 PTPParams *params = (PTPParams *) device->params;
5004 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5006 LIBMTP_track_t *track;
5007 LIBMTP_filetype_t mtptype;
5010 // Get all the handles if we haven't already done that
5011 if (params->nrofobjects == 0)
5012 flush_handles(device);
5014 ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5015 if (ret != PTP_RC_OK)
5018 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
5020 // Ignore stuff we don't know how to handle...
5021 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
5023 * This row lets through undefined files for examination
5024 * since they may be forgotten OGG or FLAC files.
5026 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5027 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5028 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5029 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5031 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5035 // Allocate a new track type
5036 track = LIBMTP_new_track_t();
5038 // This is some sort of unique ID so we can keep track of the track.
5039 track->item_id = ob->oid;
5040 track->parent_id = ob->oi.ParentObject;
5041 track->storage_id = ob->oi.StorageID;
5042 track->modificationdate = ob->oi.ModificationDate;
5044 track->filetype = mtptype;
5046 // Original file-specific properties
5047 track->filesize = ob->oi.ObjectCompressedSize;
5048 if (ob->oi.Filename != NULL) {
5049 track->filename = strdup(ob->oi.Filename);
5053 * A special quirk for devices that doesn't quite
5054 * remember that some files marked as "unknown" type are
5055 * actually OGG or FLAC files. We look at the filename extension
5056 * and see if it happens that this was atleast named "ogg"
5057 * and fall back on this heuristic approach in that case,
5058 * for these bugged devices only.
5060 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5061 track->filename != NULL) {
5062 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5063 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5064 has_ogg_extension(track->filename))
5065 track->filetype = LIBMTP_FILETYPE_OGG;
5066 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5067 has_flac_extension(track->filename))
5068 track->filetype = LIBMTP_FILETYPE_FLAC;
5070 // This was not an OGG/FLAC file so discard it
5071 LIBMTP_destroy_track_t(track);
5075 get_track_metadata(device, ob->oi.ObjectFormat, track);
5080 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5081 * to isolate the internal type.
5083 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5085 MTPDataHandler *handler = (MTPDataHandler *)priv;
5087 uint32_t local_gotlen = 0;
5088 ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5089 *gotlen = local_gotlen;
5092 case LIBMTP_HANDLER_RETURN_OK:
5094 case LIBMTP_HANDLER_RETURN_ERROR:
5095 return PTP_ERROR_IO;
5096 case LIBMTP_HANDLER_RETURN_CANCEL:
5097 return PTP_ERROR_CANCEL;
5099 return PTP_ERROR_IO;
5104 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5105 * to isolate the internal type.
5107 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen)
5109 MTPDataHandler *handler = (MTPDataHandler *)priv;
5111 uint32_t local_putlen = 0;
5112 ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5113 *putlen = local_putlen;
5116 case LIBMTP_HANDLER_RETURN_OK:
5118 case LIBMTP_HANDLER_RETURN_ERROR:
5119 return PTP_ERROR_IO;
5120 case LIBMTP_HANDLER_RETURN_CANCEL:
5121 return PTP_ERROR_CANCEL;
5123 return PTP_ERROR_IO;
5128 * This gets a file off the device to a local file identified
5130 * @param device a pointer to the device to get the track from.
5131 * @param id the file ID of the file to retrieve.
5132 * @param path a filename to use for the retrieved file.
5133 * @param callback a progress indicator function or NULL to ignore.
5134 * @param data a user-defined pointer that is passed along to
5135 * the <code>progress</code> function in order to
5136 * pass along some user defined data to the progress
5137 * updates. If not used, set this to NULL.
5138 * @return 0 if the transfer was successful, any other value means
5140 * @see LIBMTP_Get_File_To_File_Descriptor()
5142 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5143 char const * const path, LIBMTP_progressfunc_t const callback,
5144 void const * const data)
5151 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5157 #ifdef USE_WINDOWS_IO_H
5158 if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5160 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5163 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5165 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5169 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5174 // Delete partial file.
5183 * This gets a file off the device to a file identified
5184 * by a file descriptor.
5186 * This function can potentially be used for streaming
5187 * files off the device for playback or broadcast for example,
5188 * by downloading the file into a stream sink e.g. a socket.
5190 * @param device a pointer to the device to get the file from.
5191 * @param id the file ID of the file to retrieve.
5192 * @param fd a local file descriptor to write the file to.
5193 * @param callback a progress indicator function or NULL to ignore.
5194 * @param data a user-defined pointer that is passed along to
5195 * the <code>progress</code> function in order to
5196 * pass along some user defined data to the progress
5197 * updates. If not used, set this to NULL.
5198 * @return 0 if the transfer was successful, any other value means
5200 * @see LIBMTP_Get_File_To_File()
5202 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5205 LIBMTP_progressfunc_t const callback,
5206 void const * const data)
5209 PTPParams *params = (PTPParams *) device->params;
5210 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5213 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5214 if (ret != PTP_RC_OK) {
5215 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5218 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5219 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5224 ptp_usb->callback_active = 1;
5225 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5226 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5227 ptp_usb->current_transfer_complete = 0;
5228 ptp_usb->current_transfer_callback = callback;
5229 ptp_usb->current_transfer_callback_data = data;
5231 ret = ptp_getobject_tofd(params, id, fd);
5233 ptp_usb->callback_active = 0;
5234 ptp_usb->current_transfer_callback = NULL;
5235 ptp_usb->current_transfer_callback_data = NULL;
5237 if (ret == PTP_ERROR_CANCEL) {
5238 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5241 if (ret != PTP_RC_OK) {
5242 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5250 * This gets a file off the device and calls put_func
5251 * with chunks of data
5253 * @param device a pointer to the device to get the file from.
5254 * @param id the file ID of the file to retrieve.
5255 * @param put_func the function to call when we have data.
5256 * @param priv the user-defined pointer that is passed to
5257 * <code>put_func</code>.
5258 * @param callback a progress indicator function or NULL to ignore.
5259 * @param data a user-defined pointer that is passed along to
5260 * the <code>progress</code> function in order to
5261 * pass along some user defined data to the progress
5262 * updates. If not used, set this to NULL.
5263 * @return 0 if the transfer was successful, any other value means
5266 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5268 MTPDataPutFunc put_func,
5270 LIBMTP_progressfunc_t const callback,
5271 void const * const data)
5275 PTPParams *params = (PTPParams *) device->params;
5276 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5278 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5279 if (ret != PTP_RC_OK) {
5280 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5283 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5284 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5289 ptp_usb->callback_active = 1;
5290 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5291 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5292 ptp_usb->current_transfer_complete = 0;
5293 ptp_usb->current_transfer_callback = callback;
5294 ptp_usb->current_transfer_callback_data = data;
5296 MTPDataHandler mtp_handler;
5297 mtp_handler.getfunc = NULL;
5298 mtp_handler.putfunc = put_func;
5299 mtp_handler.priv = priv;
5301 PTPDataHandler handler;
5302 handler.getfunc = NULL;
5303 handler.putfunc = put_func_wrapper;
5304 handler.priv = &mtp_handler;
5306 ret = ptp_getobject_to_handler(params, id, &handler);
5308 ptp_usb->callback_active = 0;
5309 ptp_usb->current_transfer_callback = NULL;
5310 ptp_usb->current_transfer_callback_data = NULL;
5312 if (ret == PTP_ERROR_CANCEL) {
5313 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5316 if (ret != PTP_RC_OK) {
5317 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5326 * This gets a track off the device to a file identified
5327 * by a filename. This is actually just a wrapper for the
5328 * \c LIBMTP_Get_Track_To_File() function.
5329 * @param device a pointer to the device to get the track from.
5330 * @param id the track ID of the track to retrieve.
5331 * @param path a filename to use for the retrieved track.
5332 * @param callback a progress indicator function or NULL to ignore.
5333 * @param data a user-defined pointer that is passed along to
5334 * the <code>progress</code> function in order to
5335 * pass along some user defined data to the progress
5336 * updates. If not used, set this to NULL.
5337 * @return 0 if the transfer was successful, any other value means
5339 * @see LIBMTP_Get_Track_To_File_Descriptor()
5341 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5342 char const * const path, LIBMTP_progressfunc_t const callback,
5343 void const * const data)
5345 // This is just a wrapper
5346 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5350 * This gets a track off the device to a file identified
5351 * by a file descriptor. This is actually just a wrapper for
5352 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5353 * @param device a pointer to the device to get the track from.
5354 * @param id the track ID of the track to retrieve.
5355 * @param fd a file descriptor to write the track to.
5356 * @param callback a progress indicator function or NULL to ignore.
5357 * @param data a user-defined pointer that is passed along to
5358 * the <code>progress</code> function in order to
5359 * pass along some user defined data to the progress
5360 * updates. If not used, set this to NULL.
5361 * @return 0 if the transfer was successful, any other value means
5363 * @see LIBMTP_Get_Track_To_File()
5365 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5368 LIBMTP_progressfunc_t const callback,
5369 void const * const data)
5371 // This is just a wrapper
5372 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5376 * This gets a track off the device to a handler function.
5377 * This is actually just a wrapper for
5378 * the \c LIBMTP_Get_File_To_Handler() function.
5379 * @param device a pointer to the device to get the track from.
5380 * @param id the track ID of the track to retrieve.
5381 * @param put_func the function to call when we have data.
5382 * @param priv the user-defined pointer that is passed to
5383 * <code>put_func</code>.
5384 * @param callback a progress indicator function or NULL to ignore.
5385 * @param data a user-defined pointer that is passed along to
5386 * the <code>progress</code> function in order to
5387 * pass along some user defined data to the progress
5388 * updates. If not used, set this to NULL.
5389 * @return 0 if the transfer was successful, any other value means
5392 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5394 MTPDataPutFunc put_func,
5396 LIBMTP_progressfunc_t const callback,
5397 void const * const data)
5399 // This is just a wrapper
5400 return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5404 * This function sends a track from a local file to an
5405 * MTP device. A filename and a set of metadata must be
5407 * @param device a pointer to the device to send the track to.
5408 * @param path the filename of a local file which will be sent.
5409 * @param metadata a track metadata set to be written along with the file.
5410 * After this call the field <code>metadata->item_id</code>
5411 * will contain the new track ID. Other fields such
5412 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5413 * or <code>metadata->storage_id</code> may also change during this
5414 * operation due to device restrictions, so do not rely on the
5415 * contents of this struct to be preserved in any way.
5417 * <li><code>metadata->parent_id</code> should be set to the parent
5418 * (e.g. folder) to store this track in. Since some
5419 * devices are a bit picky about where files
5420 * are placed, a default folder will be chosen if libmtp
5421 * has detected one for the current filetype and this
5422 * parameter is set to 0. If this is 0 and no default folder
5423 * can be found, the file will be stored in the root folder.
5424 * <li><code>metadata->storage_id</code> should be set to the
5425 * desired storage (e.g. memory card or whatever your device
5426 * presents) to store this track in. Setting this to 0 will store
5427 * the track on the primary storage.
5429 * @param callback a progress indicator function or NULL to ignore.
5430 * @param data a user-defined pointer that is passed along to
5431 * the <code>progress</code> function in order to
5432 * pass along some user defined data to the progress
5433 * updates. If not used, set this to NULL.
5434 * @return 0 if the transfer was successful, any other value means
5436 * @see LIBMTP_Send_Track_From_File_Descriptor()
5437 * @see LIBMTP_Send_File_From_File()
5438 * @see LIBMTP_Delete_Object()
5440 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5441 char const * const path, LIBMTP_track_t * const metadata,
5442 LIBMTP_progressfunc_t const callback,
5443 void const * const data)
5450 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5456 #ifdef USE_WINDOWS_IO_H
5457 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5459 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5462 if ( (fd = open(path, O_RDONLY)) == -1) {
5464 LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5468 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5471 #ifdef USE_WINDOWS_IO_H
5483 * This helper function checks if a filename already exists on the device
5485 * @param string representing the filename
5486 * @return 0 if the filename doesn't exist, -1 if it does
5488 static int check_filename_exists(PTPParams* params, char const * const filename)
5492 for (i = 0; i < params->nrofobjects; i++) {
5493 char *fname = params->objects[i].oi.Filename;
5494 if ((fname != NULL) && (strcmp(filename, fname) == 0))
5504 * This helper function returns a unique filename, with a random string before the extension
5505 * @param string representing the original filename
5506 * @return a string representing the unique filename
5508 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5511 char * extension_position;
5513 if (check_filename_exists(params, filename))
5515 extension_position = strrchr(filename,'.');
5517 char basename[extension_position - filename + 1];
5518 strncpy(basename, filename, extension_position - filename);
5519 basename[extension_position - filename] = '\0';
5522 char newname[ strlen(basename) + 6 + strlen(extension_position)];
5523 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5524 while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5526 sprintf(newname, "%s_%d%s", basename, suffix, extension_position);
5528 return strdup(newname);
5532 return strdup(filename);
5537 * This function sends a track from a file descriptor to an
5538 * MTP device. A filename and a set of metadata must be
5540 * @param device a pointer to the device to send the track to.
5541 * @param fd the filedescriptor for a local file which will be sent.
5542 * @param metadata a track metadata set to be written along with the file.
5543 * After this call the field <code>metadata->item_id</code>
5544 * will contain the new track ID. Other fields such
5545 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5546 * or <code>metadata->storage_id</code> may also change during this
5547 * operation due to device restrictions, so do not rely on the
5548 * contents of this struct to be preserved in any way.
5550 * <li><code>metadata->parent_id</code> should be set to the parent
5551 * (e.g. folder) to store this track in. Since some
5552 * devices are a bit picky about where files
5553 * are placed, a default folder will be chosen if libmtp
5554 * has detected one for the current filetype and this
5555 * parameter is set to 0. If this is 0 and no default folder
5556 * can be found, the file will be stored in the root folder.
5557 * <li><code>metadata->storage_id</code> should be set to the
5558 * desired storage (e.g. memory card or whatever your device
5559 * presents) to store this track in. Setting this to 0 will store
5560 * the track on the primary storage.
5562 * @param callback a progress indicator function or NULL to ignore.
5563 * @param data a user-defined pointer that is passed along to
5564 * the <code>progress</code> function in order to
5565 * pass along some user defined data to the progress
5566 * updates. If not used, set this to NULL.
5567 * @return 0 if the transfer was successful, any other value means
5569 * @see LIBMTP_Send_Track_From_File()
5570 * @see LIBMTP_Delete_Object()
5572 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5573 int const fd, LIBMTP_track_t * const metadata,
5574 LIBMTP_progressfunc_t const callback,
5575 void const * const data)
5578 LIBMTP_file_t filedata;
5579 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5580 PTPParams *params = (PTPParams *) device->params;
5582 // Sanity check, is this really a track?
5583 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5584 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5585 "LIBMTP_Send_Track_From_File_Descriptor(): "
5586 "I don't think this is actually a track, strange filetype...");
5589 // Wrap around the file transfer function
5590 filedata.item_id = metadata->item_id;
5591 filedata.parent_id = metadata->parent_id;
5592 filedata.storage_id = metadata->storage_id;
5593 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5594 filedata.filename = generate_unique_filename(params, metadata->filename);
5597 filedata.filename = metadata->filename;
5599 filedata.filesize = metadata->filesize;
5600 filedata.filetype = metadata->filetype;
5601 filedata.next = NULL;
5603 subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5609 if (subcall_ret != 0) {
5610 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5611 "LIBMTP_Send_Track_From_File_Descriptor(): "
5612 "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5613 // We used to delete the file here, but don't... It might be OK after all.
5614 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5618 // Pick up new item (and parent, storage) ID
5619 metadata->item_id = filedata.item_id;
5620 metadata->parent_id = filedata.parent_id;
5621 metadata->storage_id = filedata.storage_id;
5623 // Set track metadata for the new fine track
5624 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5625 if (subcall_ret != 0) {
5626 // Subcall will add error to errorstack
5627 // We used to delete the file here, but don't... It might be OK after all.
5628 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5632 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5633 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5639 * This function sends a track from a handler function to an
5640 * MTP device. A filename and a set of metadata must be
5642 * @param device a pointer to the device to send the track to.
5643 * @param get_func the function to call when we have data.
5644 * @param priv the user-defined pointer that is passed to
5645 * <code>get_func</code>.
5646 * @param metadata a track metadata set to be written along with the file.
5647 * After this call the field <code>metadata->item_id</code>
5648 * will contain the new track ID. Other fields such
5649 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5650 * or <code>metadata->storage_id</code> may also change during this
5651 * operation due to device restrictions, so do not rely on the
5652 * contents of this struct to be preserved in any way.
5654 * <li><code>metadata->parent_id</code> should be set to the parent
5655 * (e.g. folder) to store this track in. Since some
5656 * devices are a bit picky about where files
5657 * are placed, a default folder will be chosen if libmtp
5658 * has detected one for the current filetype and this
5659 * parameter is set to 0. If this is 0 and no default folder
5660 * can be found, the file will be stored in the root folder.
5661 * <li><code>metadata->storage_id</code> should be set to the
5662 * desired storage (e.g. memory card or whatever your device
5663 * presents) to store this track in. Setting this to 0 will store
5664 * the track on the primary storage.
5666 * @param callback a progress indicator function or NULL to ignore.
5667 * @param data a user-defined pointer that is passed along to
5668 * the <code>progress</code> function in order to
5669 * pass along some user defined data to the progress
5670 * updates. If not used, set this to NULL.
5671 * @return 0 if the transfer was successful, any other value means
5673 * @see LIBMTP_Send_Track_From_File()
5674 * @see LIBMTP_Delete_Object()
5676 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5677 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5678 LIBMTP_progressfunc_t const callback,
5679 void const * const data)
5682 LIBMTP_file_t filedata;
5683 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5684 PTPParams *params = (PTPParams *) device->params;
5686 // Sanity check, is this really a track?
5687 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5688 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5689 "LIBMTP_Send_Track_From_Handler(): "
5690 "I don't think this is actually a track, strange filetype...");
5693 // Wrap around the file transfer function
5694 filedata.item_id = metadata->item_id;
5695 filedata.parent_id = metadata->parent_id;
5696 filedata.storage_id = metadata->storage_id;
5697 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5698 filedata.filename = generate_unique_filename(params, metadata->filename);
5701 filedata.filename = metadata->filename;
5703 filedata.filesize = metadata->filesize;
5704 filedata.filetype = metadata->filetype;
5705 filedata.next = NULL;
5707 subcall_ret = LIBMTP_Send_File_From_Handler(device,
5714 if (subcall_ret != 0) {
5715 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5716 "LIBMTP_Send_Track_From_Handler(): "
5717 "subcall to LIBMTP_Send_File_From_Handler failed.");
5718 // We used to delete the file here, but don't... It might be OK after all.
5719 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5723 // Pick up new item (and parent, storage) ID
5724 metadata->item_id = filedata.item_id;
5725 metadata->parent_id = filedata.parent_id;
5726 metadata->storage_id = filedata.storage_id;
5728 // Set track metadata for the new fine track
5729 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5730 if (subcall_ret != 0) {
5731 // Subcall will add error to errorstack
5732 // We used to delete the file here, but don't... It might be OK after all.
5733 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5737 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5738 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5744 * This function sends a local file to an MTP device.
5745 * A filename and a set of metadata must be
5747 * @param device a pointer to the device to send the track to.
5748 * @param path the filename of a local file which will be sent.
5749 * @param filedata a file metadata set to be written along with the file.
5750 * After this call the field <code>filedata->item_id</code>
5751 * will contain the new file ID. Other fields such
5752 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5753 * or <code>filedata->storage_id</code> may also change during this
5754 * operation due to device restrictions, so do not rely on the
5755 * contents of this struct to be preserved in any way.
5757 * <li><code>filedata->parent_id</code> should be set to the parent
5758 * (e.g. folder) to store this file in. If this is 0,
5759 * the file will be stored in the root folder.
5760 * <li><code>filedata->storage_id</code> should be set to the
5761 * desired storage (e.g. memory card or whatever your device
5762 * presents) to store this file in. Setting this to 0 will store
5763 * the file on the primary storage.
5765 * @param callback a progress indicator function or NULL to ignore.
5766 * @param data a user-defined pointer that is passed along to
5767 * the <code>progress</code> function in order to
5768 * pass along some user defined data to the progress
5769 * updates. If not used, set this to NULL.
5770 * @return 0 if the transfer was successful, any other value means
5772 * @see LIBMTP_Send_File_From_File_Descriptor()
5773 * @see LIBMTP_Delete_Object()
5775 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5776 char const * const path, LIBMTP_file_t * const filedata,
5777 LIBMTP_progressfunc_t const callback,
5778 void const * const data)
5785 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5791 #ifdef USE_WINDOWS_IO_H
5792 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5794 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5797 if ( (fd = open(path, O_RDONLY)) == -1) {
5799 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5803 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5806 #ifdef USE_WINDOWS_IO_H
5816 * This function sends a generic file from a file descriptor to an
5817 * MTP device. A filename and a set of metadata must be
5820 * This can potentially be used for sending in a stream of unknown
5821 * length. Send music files with
5822 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5824 * @param device a pointer to the device to send the file to.
5825 * @param fd the filedescriptor for a local file which will be sent.
5826 * @param filedata a file metadata set to be written along with the file.
5827 * After this call the field <code>filedata->item_id</code>
5828 * will contain the new file ID. Other fields such
5829 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5830 * or <code>filedata->storage_id</code> may also change during this
5831 * operation due to device restrictions, so do not rely on the
5832 * contents of this struct to be preserved in any way.
5834 * <li><code>filedata->parent_id</code> should be set to the parent
5835 * (e.g. folder) to store this file in. If this is 0,
5836 * the file will be stored in the root folder.
5837 * <li><code>filedata->storage_id</code> should be set to the
5838 * desired storage (e.g. memory card or whatever your device
5839 * presents) to store this file in. Setting this to 0 will store
5840 * the file on the primary storage.
5842 * @param callback a progress indicator function or NULL to ignore.
5843 * @param data a user-defined pointer that is passed along to
5844 * the <code>progress</code> function in order to
5845 * pass along some user defined data to the progress
5846 * updates. If not used, set this to NULL.
5847 * @return 0 if the transfer was successful, any other value means
5849 * @see LIBMTP_Send_File_From_File()
5850 * @see LIBMTP_Send_Track_From_File_Descriptor()
5851 * @see LIBMTP_Delete_Object()
5853 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5854 int const fd, LIBMTP_file_t * const filedata,
5855 LIBMTP_progressfunc_t const callback,
5856 void const * const data)
5859 PTPParams *params = (PTPParams *) device->params;
5860 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5861 LIBMTP_file_t *newfilemeta;
5865 if (send_file_object_info(device, filedata))
5867 // no need to output an error since send_file_object_info will already have done so
5872 ptp_usb->callback_active = 1;
5873 // The callback will deactivate itself after this amount of data has been sent
5874 // One BULK header for the request, one for the data phase. No parameters to the request.
5875 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5876 ptp_usb->current_transfer_complete = 0;
5877 ptp_usb->current_transfer_callback = callback;
5878 ptp_usb->current_transfer_callback_data = data;
5881 * We might need to increase the timeout here, files can be pretty
5882 * large. Take the default timeout and add the calculated time for
5885 get_usb_device_timeout(ptp_usb, &oldtimeout);
5886 timeout = oldtimeout +
5887 (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5888 set_usb_device_timeout(ptp_usb, timeout);
5890 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5892 ptp_usb->callback_active = 0;
5893 ptp_usb->current_transfer_callback = NULL;
5894 ptp_usb->current_transfer_callback_data = NULL;
5895 set_usb_device_timeout(ptp_usb, oldtimeout);
5897 if (ret == PTP_ERROR_CANCEL) {
5898 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5901 if (ret != PTP_RC_OK) {
5902 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5903 "Could not send object.");
5907 add_object_to_cache(device, filedata->item_id);
5910 * Get the device-assigned parent_id from the cache.
5911 * The operation that adds it to the cache will
5912 * look it up from the device, so we get the new
5913 * parent_id from the cache.
5915 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5916 if (newfilemeta != NULL) {
5917 filedata->parent_id = newfilemeta->parent_id;
5918 filedata->storage_id = newfilemeta->storage_id;
5919 LIBMTP_destroy_file_t(newfilemeta);
5921 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5922 "LIBMTP_Send_File_From_File_Descriptor(): "
5923 "Could not retrieve updated metadata.");
5931 * This function sends a generic file from a handler function to an
5932 * MTP device. A filename and a set of metadata must be
5935 * This can potentially be used for sending in a stream of unknown
5936 * length. Send music files with
5937 * <code>LIBMTP_Send_Track_From_Handler()</code>
5939 * @param device a pointer to the device to send the file to.
5940 * @param get_func the function to call to get data to write
5941 * @param priv a user-defined pointer that is passed along to
5942 * <code>get_func</code>. If not used, this is set to NULL.
5943 * @param filedata a file metadata set to be written along with the file.
5944 * After this call the field <code>filedata->item_id</code>
5945 * will contain the new file ID. Other fields such
5946 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5947 * or <code>filedata->storage_id</code> may also change during this
5948 * operation due to device restrictions, so do not rely on the
5949 * contents of this struct to be preserved in any way.
5951 * <li><code>filedata->parent_id</code> should be set to the parent
5952 * (e.g. folder) to store this file in. If this is 0,
5953 * the file will be stored in the root folder.
5954 * <li><code>filedata->storage_id</code> should be set to the
5955 * desired storage (e.g. memory card or whatever your device
5956 * presents) to store this file in. Setting this to 0 will store
5957 * the file on the primary storage.
5959 * @param callback a progress indicator function or NULL to ignore.
5960 * @param data a user-defined pointer that is passed along to
5961 * the <code>progress</code> function in order to
5962 * pass along some user defined data to the progress
5963 * updates. If not used, set this to NULL.
5964 * @return 0 if the transfer was successful, any other value means
5966 * @see LIBMTP_Send_File_From_File()
5967 * @see LIBMTP_Send_Track_From_File_Descriptor()
5968 * @see LIBMTP_Delete_Object()
5970 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
5971 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
5972 LIBMTP_progressfunc_t const callback, void const * const data)
5975 PTPParams *params = (PTPParams *) device->params;
5976 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5977 LIBMTP_file_t *newfilemeta;
5979 if (send_file_object_info(device, filedata))
5981 // no need to output an error since send_file_object_info will already have done so
5986 ptp_usb->callback_active = 1;
5987 // The callback will deactivate itself after this amount of data has been sent
5988 // One BULK header for the request, one for the data phase. No parameters to the request.
5989 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5990 ptp_usb->current_transfer_complete = 0;
5991 ptp_usb->current_transfer_callback = callback;
5992 ptp_usb->current_transfer_callback_data = data;
5994 MTPDataHandler mtp_handler;
5995 mtp_handler.getfunc = get_func;
5996 mtp_handler.putfunc = NULL;
5997 mtp_handler.priv = priv;
5999 PTPDataHandler handler;
6000 handler.getfunc = get_func_wrapper;
6001 handler.putfunc = NULL;
6002 handler.priv = &mtp_handler;
6004 ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
6006 ptp_usb->callback_active = 0;
6007 ptp_usb->current_transfer_callback = NULL;
6008 ptp_usb->current_transfer_callback_data = NULL;
6010 if (ret == PTP_ERROR_CANCEL) {
6011 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
6014 if (ret != PTP_RC_OK) {
6015 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
6016 "Could not send object.");
6020 add_object_to_cache(device, filedata->item_id);
6023 * Get the device-assined parent_id from the cache.
6024 * The operation that adds it to the cache will
6025 * look it up from the device, so we get the new
6026 * parent_id from the cache.
6028 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6029 if (newfilemeta != NULL) {
6030 filedata->parent_id = newfilemeta->parent_id;
6031 filedata->storage_id = newfilemeta->storage_id;
6032 LIBMTP_destroy_file_t(newfilemeta);
6034 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6035 "LIBMTP_Send_File_From_Handler(): "
6036 "Could not retrieve updated metadata.");
6044 * This function sends the file object info, ready for sendobject
6045 * @param device a pointer to the device to send the file to.
6046 * @param filedata a file metadata set to be written along with the file.
6047 * @return 0 if the transfer was successful, any other value means
6050 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6052 PTPParams *params = (PTPParams *) device->params;
6053 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6055 int use_primary_storage = 1;
6056 uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6057 LIBMTP_devicestorage_t *storage;
6058 uint32_t localph = filedata->parent_id;
6063 // Sanity check: no zerolength files on some devices?
6064 // If the zerolength files cause problems on some devices,
6065 // then add a bug flag for this.
6066 if (filedata->filesize == 0) {
6067 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6068 "File of zero size.");
6072 if (filedata->storage_id != 0) {
6073 store = filedata->storage_id;
6075 store = get_suggested_storage_id(device, filedata->filesize, localph);
6078 // Detect if something non-primary is in use.
6079 storage = device->storage;
6080 if (storage != NULL && store != storage->id) {
6081 use_primary_storage = 0;
6085 * If no destination folder was given, look up a default
6086 * folder if possible. Perhaps there is some way of retrieveing
6087 * the default folder for different forms of content, what
6088 * do I know, we use a fixed list in lack of any better method.
6089 * Some devices obviously need to have their files in certain
6090 * folders in order to find/display them at all (hello Creative),
6091 * so we have to have a method for this. We only do this if the
6092 * primary storage is in use.
6095 if (localph == 0 && use_primary_storage) {
6096 if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6097 localph = device->default_music_folder;
6098 } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6099 localph = device->default_video_folder;
6100 } else if (of == PTP_OFC_EXIF_JPEG ||
6101 of == PTP_OFC_JP2 ||
6102 of == PTP_OFC_JPX ||
6103 of == PTP_OFC_JFIF ||
6104 of == PTP_OFC_TIFF ||
6105 of == PTP_OFC_TIFF_IT ||
6106 of == PTP_OFC_BMP ||
6107 of == PTP_OFC_GIF ||
6108 of == PTP_OFC_PICT ||
6109 of == PTP_OFC_PNG ||
6110 of == PTP_OFC_MTP_WindowsImageFormat) {
6111 localph = device->default_picture_folder;
6112 } else if (of == PTP_OFC_MTP_vCalendar1 ||
6113 of == PTP_OFC_MTP_vCalendar2 ||
6114 of == PTP_OFC_MTP_UndefinedContact ||
6115 of == PTP_OFC_MTP_vCard2 ||
6116 of == PTP_OFC_MTP_vCard3 ||
6117 of == PTP_OFC_MTP_UndefinedCalendarItem) {
6118 localph = device->default_organizer_folder;
6119 } else if (of == PTP_OFC_Text) {
6120 localph = device->default_text_folder;
6124 // Here we wire the type to unknown on bugged, but
6125 // Ogg or FLAC-supportive devices.
6126 if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6127 of = PTP_OFC_Undefined;
6129 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6130 of = PTP_OFC_Undefined;
6133 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6134 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6136 * MTP enhanched does it this way (from a sniff):
6137 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6138 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6139 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6140 * Length: 0x00000020
6141 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
6143 * Transaction ID: 0x0000001B
6144 * Param1: 0x00010001 <- store
6145 * Param2: 0xffffffff <- parent handle (-1 ?)
6146 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6147 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
6148 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6150 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6151 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6152 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6153 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6154 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6155 * 00 4F DC 02 00 01 - dc4f = non consumable
6156 * Length: 0x00000046
6157 * Type: 0x0002 PTP_USB_CONTAINER_DATA
6159 * Transaction ID: 0x0000001B
6161 * 0x00000003 <- Number of metadata items
6162 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6163 * 0xdc07 <- metadata type: file name
6164 * 0xffff <- metadata type: string
6165 * 0x0d <- number of (uint16_t) characters
6166 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6167 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6168 * 0xdc03 <- metadata type: protection status
6169 * 0x0004 <- metadata type: uint16_t
6170 * 0x0000 <- not protected
6171 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6172 * 0xdc4f <- non consumable
6173 * 0x0002 <- metadata type: uint8_t
6174 * 0x01 <- non-consumable (this device cannot display PDF)
6176 * <- Read 0x18 bytes back
6177 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6178 * 00 00 00 00 01 40 00 00
6179 * Length: 0x000000018
6180 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
6181 * Code: 0x2001 PTP_OK
6182 * Transaction ID: 0x0000001B
6183 * Param1: 0x00010001 <- store
6184 * Param2: 0x00000000 <- parent handle
6185 * Param3: 0x00004001 <- new file/object ID
6187 * -> PTP_OC_SendObject (0x100d)
6188 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
6189 * -> ... all the bytes ...
6190 * <- Read 0x0c bytes back
6191 * 0C 00 00 00 03 00 01 20 1C 00 00 00
6192 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
6194 MTPProperties *props = NULL;
6196 MTPProperties *prop = NULL;
6197 uint16_t *properties = NULL;
6198 uint32_t propcnt = 0;
6200 // default parent handle
6202 localph = 0xFFFFFFFFU; // Set to -1
6204 // Must be 0x00000000U for new objects
6205 filedata->item_id = 0x00000000U;
6207 ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6209 for (i=0;i<propcnt;i++) {
6210 PTPObjectPropDesc opd;
6212 ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6213 if (ret != PTP_RC_OK) {
6214 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6215 "could not get property description.");
6216 } else if (opd.GetSet) {
6217 switch (properties[i]) {
6218 case PTP_OPC_ObjectFileName:
6219 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6220 prop->ObjectHandle = filedata->item_id;
6221 prop->property = PTP_OPC_ObjectFileName;
6222 prop->datatype = PTP_DTC_STR;
6223 if (filedata->filename != NULL) {
6224 prop->propval.str = strdup(filedata->filename);
6225 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6226 strip_7bit_from_utf8(prop->propval.str);
6230 case PTP_OPC_ProtectionStatus:
6231 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6232 prop->ObjectHandle = filedata->item_id;
6233 prop->property = PTP_OPC_ProtectionStatus;
6234 prop->datatype = PTP_DTC_UINT16;
6235 prop->propval.u16 = 0x0000U; /* Not protected */
6237 case PTP_OPC_NonConsumable:
6238 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6239 prop->ObjectHandle = filedata->item_id;
6240 prop->property = PTP_OPC_NonConsumable;
6241 prop->datatype = PTP_DTC_UINT8;
6242 prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6245 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6246 prop->ObjectHandle = filedata->item_id;
6247 prop->property = PTP_OPC_Name;
6248 prop->datatype = PTP_DTC_STR;
6249 if (filedata->filename != NULL)
6250 prop->propval.str = strdup(filedata->filename);
6252 case PTP_OPC_DateModified:
6253 // Tag with current time if that is supported
6254 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6255 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6256 prop->ObjectHandle = filedata->item_id;
6257 prop->property = PTP_OPC_DateModified;
6258 prop->datatype = PTP_DTC_STR;
6259 prop->propval.str = get_iso8601_stamp();
6260 filedata->modificationdate = time(NULL);
6265 ptp_free_objectpropdesc(&opd);
6269 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6270 of, filedata->filesize, props, nrofprops);
6272 /* Free property list */
6273 ptp_destroy_object_prop_list(props, nrofprops);
6275 if (ret != PTP_RC_OK) {
6276 add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6277 "Could not send object property list.");
6278 if (ret == PTP_RC_AccessDenied) {
6279 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6283 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6284 PTPObjectInfo new_file;
6286 memset(&new_file, 0, sizeof(PTPObjectInfo));
6288 new_file.Filename = filedata->filename;
6289 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6290 strip_7bit_from_utf8(new_file.Filename);
6292 if (filedata->filesize > 0xFFFFFFFFL) {
6293 // This is a kludge in the MTP standard for large files.
6294 new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6296 new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6298 new_file.ObjectFormat = of;
6299 new_file.StorageID = store;
6300 new_file.ParentObject = localph;
6301 new_file.ModificationDate = time(NULL);
6303 // Create the object
6304 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6306 if (ret != PTP_RC_OK) {
6307 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6308 "Could not send object info.");
6309 if (ret == PTP_RC_AccessDenied) {
6310 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6314 // NOTE: the char* pointers inside new_file are not copies so don't
6315 // try to destroy this objectinfo!
6318 // Now there IS an object with this parent handle.
6319 filedata->parent_id = localph;
6325 * This function updates the MTP track object metadata on a
6326 * single file identified by an object ID.
6327 * @param device a pointer to the device to update the track
6329 * @param metadata a track metadata set to be written to the file.
6330 * notice that the <code>track_id</code> field of the
6331 * metadata structure must be correct so that the
6332 * function can update the right file. If some properties
6333 * of this metadata are set to NULL (strings) or 0
6334 * (numerical values) they will be discarded and the
6335 * track will not be tagged with these blank values.
6336 * @return 0 on success, any other value means failure. If some
6337 * or all of the properties fail to update we will still
6338 * return success. On some devices (notably iRiver T30)
6339 * properties that exist cannot be updated.
6341 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6342 LIBMTP_track_t const * const metadata)
6345 PTPParams *params = (PTPParams *) device->params;
6346 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6348 uint16_t *properties = NULL;
6349 uint32_t propcnt = 0;
6351 // First see which properties can be set on this file format and apply accordingly
6352 // i.e only try to update this metadata for object tags that exist on the current player.
6353 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6354 if (ret != PTP_RC_OK) {
6355 // Just bail out for now, nothing is ever set.
6356 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6357 "could not retrieve supported object properties.");
6360 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6361 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6362 MTPProperties *props = NULL;
6363 MTPProperties *prop = NULL;
6366 for (i=0;i<propcnt;i++) {
6367 PTPObjectPropDesc opd;
6369 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6370 if (ret != PTP_RC_OK) {
6371 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6372 "could not get property description.");
6373 } else if (opd.GetSet) {
6374 switch (properties[i]) {
6376 if (metadata->title == NULL)
6378 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6379 prop->ObjectHandle = metadata->item_id;
6380 prop->property = PTP_OPC_Name;
6381 prop->datatype = PTP_DTC_STR;
6382 prop->propval.str = strdup(metadata->title);
6384 case PTP_OPC_AlbumName:
6385 if (metadata->album == NULL)
6387 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6388 prop->ObjectHandle = metadata->item_id;
6389 prop->property = PTP_OPC_AlbumName;
6390 prop->datatype = PTP_DTC_STR;
6391 prop->propval.str = strdup(metadata->album);
6393 case PTP_OPC_Artist:
6394 if (metadata->artist == NULL)
6396 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6397 prop->ObjectHandle = metadata->item_id;
6398 prop->property = PTP_OPC_Artist;
6399 prop->datatype = PTP_DTC_STR;
6400 prop->propval.str = strdup(metadata->artist);
6402 case PTP_OPC_Composer:
6403 if (metadata->composer == NULL)
6405 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6406 prop->ObjectHandle = metadata->item_id;
6407 prop->property = PTP_OPC_Composer;
6408 prop->datatype = PTP_DTC_STR;
6409 prop->propval.str = strdup(metadata->composer);
6412 if (metadata->genre == NULL)
6414 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6415 prop->ObjectHandle = metadata->item_id;
6416 prop->property = PTP_OPC_Genre;
6417 prop->datatype = PTP_DTC_STR;
6418 prop->propval.str = strdup(metadata->genre);
6420 case PTP_OPC_Duration:
6421 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6422 prop->ObjectHandle = metadata->item_id;
6423 prop->property = PTP_OPC_Duration;
6424 prop->datatype = PTP_DTC_UINT32;
6425 prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6428 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6429 prop->ObjectHandle = metadata->item_id;
6430 prop->property = PTP_OPC_Track;
6431 prop->datatype = PTP_DTC_UINT16;
6432 prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6434 case PTP_OPC_OriginalReleaseDate:
6435 if (metadata->date == NULL)
6437 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6438 prop->ObjectHandle = metadata->item_id;
6439 prop->property = PTP_OPC_OriginalReleaseDate;
6440 prop->datatype = PTP_DTC_STR;
6441 prop->propval.str = strdup(metadata->date);
6443 case PTP_OPC_SampleRate:
6444 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6445 prop->ObjectHandle = metadata->item_id;
6446 prop->property = PTP_OPC_SampleRate;
6447 prop->datatype = PTP_DTC_UINT32;
6448 prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6450 case PTP_OPC_NumberOfChannels:
6451 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6452 prop->ObjectHandle = metadata->item_id;
6453 prop->property = PTP_OPC_NumberOfChannels;
6454 prop->datatype = PTP_DTC_UINT16;
6455 prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6457 case PTP_OPC_AudioWAVECodec:
6458 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6459 prop->ObjectHandle = metadata->item_id;
6460 prop->property = PTP_OPC_AudioWAVECodec;
6461 prop->datatype = PTP_DTC_UINT32;
6462 prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6464 case PTP_OPC_AudioBitRate:
6465 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6466 prop->ObjectHandle = metadata->item_id;
6467 prop->property = PTP_OPC_AudioBitRate;
6468 prop->datatype = PTP_DTC_UINT32;
6469 prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6471 case PTP_OPC_BitRateType:
6472 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6473 prop->ObjectHandle = metadata->item_id;
6474 prop->property = PTP_OPC_BitRateType;
6475 prop->datatype = PTP_DTC_UINT16;
6476 prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6478 case PTP_OPC_Rating:
6479 // TODO: shall this be set for rating 0?
6480 if (metadata->rating == 0)
6482 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6483 prop->ObjectHandle = metadata->item_id;
6484 prop->property = PTP_OPC_Rating;
6485 prop->datatype = PTP_DTC_UINT16;
6486 prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6488 case PTP_OPC_UseCount:
6489 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6490 prop->ObjectHandle = metadata->item_id;
6491 prop->property = PTP_OPC_UseCount;
6492 prop->datatype = PTP_DTC_UINT32;
6493 prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6495 case PTP_OPC_DateModified:
6496 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6497 // Tag with current time if that is supported
6498 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6499 prop->ObjectHandle = metadata->item_id;
6500 prop->property = PTP_OPC_DateModified;
6501 prop->datatype = PTP_DTC_STR;
6502 prop->propval.str = get_iso8601_stamp();
6509 ptp_free_objectpropdesc(&opd);
6512 // NOTE: File size is not updated, this should not change anyway.
6513 // neither will we change the filename.
6515 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6517 ptp_destroy_object_prop_list(props, nrofprops);
6519 if (ret != PTP_RC_OK) {
6520 // TODO: return error of which property we couldn't set
6521 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6522 "could not set object property list.");
6527 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6528 for (i=0;i<propcnt;i++) {
6529 PTPObjectPropDesc opd;
6531 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6532 if (ret != PTP_RC_OK) {
6533 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6534 "could not get property description.");
6535 } else if (opd.GetSet) {
6536 switch (properties[i]) {
6539 ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6541 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6542 "could not set track title.");
6545 case PTP_OPC_AlbumName:
6547 ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6549 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6550 "could not set track album name.");
6553 case PTP_OPC_Artist:
6555 ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6557 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6558 "could not set track artist name.");
6561 case PTP_OPC_Composer:
6563 ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6565 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6566 "could not set track composer name.");
6570 // Update genre (but only if valid)
6571 if (metadata->genre) {
6572 ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6574 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6575 "could not set genre.");
6579 case PTP_OPC_Duration:
6581 if (metadata->duration != 0) {
6582 ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6584 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6585 "could not set track duration.");
6590 // Update track number.
6591 if (metadata->tracknumber != 0) {
6592 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6594 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6595 "could not set track tracknumber.");
6599 case PTP_OPC_OriginalReleaseDate:
6600 // Update creation datetime
6601 // The date can be zero, but some devices do not support setting zero
6602 // dates (and it seems that a zero date should never be set anyway)
6603 if (metadata->date) {
6604 ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6606 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6607 "could not set track release date.");
6611 // These are, well not so important.
6612 case PTP_OPC_SampleRate:
6613 // Update sample rate
6614 if (metadata->samplerate != 0) {
6615 ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6617 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6618 "could not set samplerate.");
6622 case PTP_OPC_NumberOfChannels:
6623 // Update number of channels
6624 if (metadata->nochannels != 0) {
6625 ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6627 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6628 "could not set number of channels.");
6632 case PTP_OPC_AudioWAVECodec:
6633 // Update WAVE codec
6634 if (metadata->wavecodec != 0) {
6635 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6637 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6638 "could not set WAVE codec.");
6642 case PTP_OPC_AudioBitRate:
6644 if (metadata->bitrate != 0) {
6645 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6647 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6648 "could not set bitrate.");
6652 case PTP_OPC_BitRateType:
6653 // Update bitrate type
6654 if (metadata->bitratetype != 0) {
6655 ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6657 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6658 "could not set bitratetype.");
6662 case PTP_OPC_Rating:
6663 // Update user rating
6664 // TODO: shall this be set for rating 0?
6665 if (metadata->rating != 0) {
6666 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6668 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6669 "could not set user rating.");
6673 case PTP_OPC_UseCount:
6674 // Update use count, set even to zero if desired.
6675 ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6677 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6678 "could not set use count.");
6681 case PTP_OPC_DateModified:
6682 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6683 // Update modification time if supported
6684 char *tmpstamp = get_iso8601_stamp();
6685 ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6687 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6688 "could not set modification date.");
6694 // NOTE: File size is not updated, this should not change anyway.
6695 // neither will we change the filename.
6700 ptp_free_objectpropdesc(&opd);
6703 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6704 "Your device doesn't seem to support any known way of setting metadata.");
6709 // update cached object properties if metadata cache exists
6710 update_metadata_cache(device, metadata->item_id);
6718 * This function deletes a single file, track, playlist, folder or
6719 * any other object off the MTP device, identified by the object ID.
6721 * If you delete a folder, there is no guarantee that the device will
6722 * really delete all the files that were in that folder, rather it is
6723 * expected that they will not be deleted, and will turn up in object
6724 * listings with parent set to a non-existant object ID. The safe way
6725 * to do this is to recursively delete all files (and folders) contained
6726 * in the folder, then the folder itself.
6728 * @param device a pointer to the device to delete the object from.
6729 * @param object_id the object to delete.
6730 * @return 0 on success, any other value means failure.
6732 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6736 PTPParams *params = (PTPParams *) device->params;
6738 ret = ptp_deleteobject(params, object_id, 0);
6739 if (ret != PTP_RC_OK) {
6740 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6748 * Internal function to update an object filename property.
6750 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6751 uint32_t object_id, uint16_t ptp_type,
6752 const char **newname_ptr)
6754 PTPParams *params = (PTPParams *) device->params;
6755 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6756 PTPObjectPropDesc opd;
6760 // See if we can modify the filename on this kind of files.
6761 ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6762 if (ret != PTP_RC_OK) {
6763 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6764 "could not get property description.");
6769 ptp_free_objectpropdesc(&opd);
6770 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6771 " property is not settable.");
6772 // TODO: we COULD actually upload/download the object here, if we feel
6773 // like wasting time for the user.
6777 newname = strdup(*newname_ptr);
6779 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6780 strip_7bit_from_utf8(newname);
6783 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6784 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6785 MTPProperties *props = NULL;
6786 MTPProperties *prop = NULL;
6789 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6790 prop->ObjectHandle = object_id;
6791 prop->property = PTP_OPC_ObjectFileName;
6792 prop->datatype = PTP_DTC_STR;
6793 prop->propval.str = newname;
6795 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6797 ptp_destroy_object_prop_list(props, nrofprops);
6799 if (ret != PTP_RC_OK) {
6800 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6801 " could not set object property list.");
6802 ptp_free_objectpropdesc(&opd);
6805 } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6806 ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6808 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6809 " could not set object filename.");
6810 ptp_free_objectpropdesc(&opd);
6815 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6816 " your device doesn't seem to support any known way of setting metadata.");
6817 ptp_free_objectpropdesc(&opd);
6821 ptp_free_objectpropdesc(&opd);
6823 // update cached object properties if metadata cache exists
6824 update_metadata_cache(device, object_id);
6830 * This function renames a single file.
6831 * This simply means that the PTP_OPC_ObjectFileName property
6832 * is updated, if this is supported by the device.
6834 * @param device a pointer to the device that contains the file.
6835 * @param file the file metadata of the file to rename.
6836 * On success, the filename member is updated. Be aware, that
6837 * this name can be different than newname depending of device restrictions.
6838 * @param newname the new filename for this object.
6839 * @return 0 on success, any other value means failure.
6841 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6842 LIBMTP_file_t *file, const char *newname)
6846 ret = set_object_filename(device, file->item_id,
6847 map_libmtp_type_to_ptp_type(file->filetype),
6854 free(file->filename);
6855 file->filename = strdup(newname);
6860 * This function renames a single folder.
6861 * This simply means that the PTP_OPC_ObjectFileName property
6862 * is updated, if this is supported by the device.
6864 * @param device a pointer to the device that contains the file.
6865 * @param folder the folder metadata of the folder to rename.
6866 * On success, the name member is updated. Be aware, that
6867 * this name can be different than newname depending of device restrictions.
6868 * @param newname the new name for this object.
6869 * @return 0 on success, any other value means failure.
6871 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6872 LIBMTP_folder_t *folder, const char* newname)
6876 ret = set_object_filename(device, folder->folder_id,
6877 PTP_OFC_Association,
6885 folder->name = strdup(newname);
6890 * This function renames a single track.
6891 * This simply means that the PTP_OPC_ObjectFileName property
6892 * is updated, if this is supported by the device.
6894 * @param device a pointer to the device that contains the file.
6895 * @param track the track metadata of the track to rename.
6896 * On success, the filename member is updated. Be aware, that
6897 * this name can be different than newname depending of device restrictions.
6898 * @param newname the new filename for this object.
6899 * @return 0 on success, any other value means failure.
6901 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6902 LIBMTP_track_t *track, const char* newname)
6906 ret = set_object_filename(device, track->item_id,
6907 map_libmtp_type_to_ptp_type(track->filetype),
6914 free(track->filename);
6915 track->filename = strdup(newname);
6920 * This function renames a single playlist object file holder.
6921 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6922 * property is updated, if this is supported by the device.
6923 * The playlist filename should nominally end with an extension
6926 * NOTE: if you want to change the metadata the device display
6927 * about a playlist you must <i>not</i> use this function,
6928 * use <code>LIBMTP_Update_Playlist()</code> instead!
6930 * @param device a pointer to the device that contains the file.
6931 * @param playlist the playlist metadata of the playlist to rename.
6932 * On success, the name member is updated. Be aware, that
6933 * this name can be different than newname depending of device restrictions.
6934 * @param newname the new name for this object.
6935 * @return 0 on success, any other value means failure.
6936 * @see LIBMTP_Update_Playlist()
6938 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
6939 LIBMTP_playlist_t *playlist, const char* newname)
6943 ret = set_object_filename(device, playlist->playlist_id,
6944 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
6951 free(playlist->name);
6952 playlist->name = strdup(newname);
6957 * This function renames a single album.
6958 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6959 * property is updated, if this is supported by the device.
6960 * The album filename should nominally end with an extension
6963 * NOTE: if you want to change the metadata the device display
6964 * about a playlist you must <i>not</i> use this function,
6965 * use <code>LIBMTP_Update_Album()</code> instead!
6967 * @param device a pointer to the device that contains the file.
6968 * @param album the album metadata of the album to rename.
6969 * On success, the name member is updated. Be aware, that
6970 * this name can be different than newname depending of device restrictions.
6971 * @param newname the new name for this object.
6972 * @return 0 on success, any other value means failure.
6973 * @see LIBMTP_Update_Album()
6975 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
6976 LIBMTP_album_t *album, const char* newname)
6980 ret = set_object_filename(device, album->album_id,
6981 PTP_OFC_MTP_AbstractAudioAlbum,
6989 album->name = strdup(newname);
6994 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
6997 * @see LIBMTP_Set_File_Name()
6998 * @see LIBMTP_Set_Track_Name()
6999 * @see LIBMTP_Set_Folder_Name()
7000 * @see LIBMTP_Set_Playlist_Name()
7001 * @see LIBMTP_Set_Album_Name()
7003 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
7004 uint32_t object_id, char* newname)
7007 LIBMTP_file_t *file;
7009 file = LIBMTP_Get_Filemetadata(device, object_id);
7012 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
7013 "could not get file metadata for target object.");
7017 ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7025 * Helper function. This indicates if a track exists on the device
7026 * @param device a pointer to the device to get the track from.
7027 * @param id the track ID of the track to retrieve.
7028 * @return TRUE (!=0) if the track exists, FALSE (0) if not
7030 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7033 PTPParams *params = (PTPParams *) device->params;
7037 ret = ptp_object_want (params, id, 0, &ob);
7038 if (ret == PTP_RC_OK)
7044 * This creates a new folder structure and allocates memory
7045 * for it. Notice that if you add strings to this structure they
7046 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7047 * operation later, so be careful of using strdup() when assigning
7050 * @return a pointer to the newly allocated folder structure.
7051 * @see LIBMTP_destroy_folder_t()
7053 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7055 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7061 new->storage_id = 0;
7063 new->sibling = NULL;
7069 * This recursively deletes the memory for a folder structure.
7070 * This shall typically be called on a top-level folder list to
7071 * detsroy the entire folder tree.
7073 * @param folder folder structure to destroy
7074 * @see LIBMTP_new_folder_t()
7076 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7079 if(folder == NULL) {
7083 //Destroy from the bottom up
7084 if(folder->child != NULL) {
7085 LIBMTP_destroy_folder_t(folder->child);
7088 if(folder->sibling != NULL) {
7089 LIBMTP_destroy_folder_t(folder->sibling);
7092 if(folder->name != NULL) {
7100 * Helper function. Returns a folder structure for a
7103 * @param folderlist list of folders to search
7104 * @id id of folder to look for
7105 * @return a folder or NULL if not found
7107 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7109 LIBMTP_folder_t *ret = NULL;
7111 if(folderlist == NULL) {
7115 if(folderlist->folder_id == id) {
7119 if(folderlist->sibling) {
7120 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7123 if(folderlist->child && ret == NULL) {
7124 ret = LIBMTP_Find_Folder(folderlist->child, id);
7131 * Function used to recursively get subfolders from params.
7133 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7135 LIBMTP_folder_t *retfolders = NULL;
7136 LIBMTP_folder_t *children, *iter, *curr;
7138 iter = list->sibling;
7139 while(iter != list) {
7140 if (iter->parent_id != parent) {
7141 iter = iter->sibling;
7145 /* We know that iter is a child of 'parent', therefore we can safely
7146 * hold on to 'iter' locally since no one else will steal it
7147 * from the 'list' as we recurse. */
7148 children = get_subfolders_for_folder(list, iter->folder_id);
7151 iter = iter->sibling;
7153 // Remove curr from the list.
7154 curr->child->sibling = curr->sibling;
7155 curr->sibling->child = curr->child;
7157 // Attach the children to curr.
7158 curr->child = children;
7160 // Put this folder into the list of siblings.
7161 curr->sibling = retfolders;
7169 * This returns a list of all folders available
7170 * on the current MTP device.
7172 * @param device a pointer to the device to get the folder listing for.
7173 * @param storage a storage ID to get the folder list from
7174 * @return a list of folders
7176 LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7177 uint32_t const storage)
7179 PTPParams *params = (PTPParams *) device->params;
7180 LIBMTP_folder_t head, *rv;
7183 // Get all the handles if we haven't already done that
7184 if (params->nrofobjects == 0) {
7185 flush_handles(device);
7189 * This creates a temporary list of the folders, this is in a
7190 * reverse order and uses the Folder pointers that are already
7191 * in the Folder structure. From this we can then build up the
7192 * folder hierarchy with only looking at this temporary list,
7193 * and removing the folders from this temporary list as we go.
7194 * This significantly reduces the number of operations that we
7195 * have to do in building the folder hierarchy. Also since the
7196 * temp list is in reverse order, when we prepend to the sibling
7197 * list things are in the same order as they were originally
7198 * in the handle list.
7200 head.sibling = &head;
7202 for (i = 0; i < params->nrofobjects; i++) {
7203 LIBMTP_folder_t *folder;
7206 ob = ¶ms->objects[i];
7207 if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7211 if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7216 * Do we know how to handle these? They are part
7217 * of the MTP 1.0 specification paragraph 3.6.4.
7218 * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7219 * should be called on these to get the contained objects, but
7220 * we basically don't care. Hopefully parent_id is maintained for all
7221 * children, because we rely on that instead.
7223 if (ob->oi.AssociationDesc != 0x00000000U) {
7224 LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7227 // Create a folder struct...
7228 folder = LIBMTP_new_folder_t();
7229 if (folder == NULL) {
7230 // malloc failure or so.
7233 folder->folder_id = ob->oid;
7234 folder->parent_id = ob->oi.ParentObject;
7235 folder->storage_id = ob->oi.StorageID;
7236 folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7238 // pretend sibling says next, and child says prev.
7239 folder->sibling = head.sibling;
7240 folder->child = &head;
7241 head.sibling->child = folder;
7242 head.sibling = folder;
7245 // We begin at the given root folder and get them all recursively
7246 rv = get_subfolders_for_folder(&head, 0x00000000U);
7248 // Some buggy devices may have some files in the "root folder"
7249 // 0xffffffff so if 0x00000000 didn't return any folders,
7250 // look for children of the root 0xffffffffU
7252 rv = get_subfolders_for_folder(&head, 0xffffffffU);
7254 LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7255 "this is a firmware bug (but continuing)\n");
7258 // The temp list should be empty. Clean up any orphans just in case.
7259 while(head.sibling != &head) {
7260 LIBMTP_folder_t *curr = head.sibling;
7262 LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7265 curr->sibling->child = curr->child;
7266 curr->child->sibling = curr->sibling;
7268 curr->sibling = NULL;
7269 LIBMTP_destroy_folder_t(curr);
7276 * This returns a list of all folders available
7277 * on the current MTP device.
7279 * @param device a pointer to the device to get the folder listing for.
7280 * @return a list of folders
7282 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7284 return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7288 * This create a folder on the current MTP device. The PTP name
7289 * for a folder is "association". The PTP/MTP devices does not
7290 * have an internal "folder" concept really, it contains a flat
7291 * list of all files and some file are "associations" that other
7292 * files and folders may refer to as its "parent".
7294 * @param device a pointer to the device to create the folder on.
7295 * @param name the name of the new folder. Note this can be modified
7296 * if the device does not support all the characters in the
7298 * @param parent_id id of parent folder to add the new folder to,
7299 * or 0 to put it in the root directory.
7300 * @param storage_id id of the storage to add this new folder to.
7301 * notice that you cannot mismatch storage id and parent id:
7302 * they must both be on the same storage! Pass in 0 if you
7303 * want to create this folder on the default storage.
7304 * @return id to new folder or 0 if an error occured
7306 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7307 uint32_t parent_id, uint32_t storage_id)
7309 PTPParams *params = (PTPParams *) device->params;
7310 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7311 uint32_t parenthandle = 0;
7313 PTPObjectInfo new_folder;
7315 uint32_t new_id = 0;
7317 if (storage_id == 0) {
7318 // I'm just guessing that a folder may require 512 bytes
7319 store = get_suggested_storage_id(device, 512, parent_id);
7323 parenthandle = parent_id;
7325 memset(&new_folder, 0, sizeof(new_folder));
7326 new_folder.Filename = name;
7327 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7328 strip_7bit_from_utf8(new_folder.Filename);
7330 new_folder.ObjectCompressedSize = 0;
7331 new_folder.ObjectFormat = PTP_OFC_Association;
7332 new_folder.ProtectionStatus = PTP_PS_NoProtection;
7333 new_folder.AssociationType = PTP_AT_GenericFolder;
7334 new_folder.ParentObject = parent_id;
7335 new_folder.StorageID = store;
7337 // Create the object
7338 if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7339 ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7340 MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7342 props[0].property = PTP_OPC_ObjectFileName;
7343 props[0].datatype = PTP_DTC_STR;
7344 props[0].propval.str = name;
7346 props[1].property = PTP_OPC_Name;
7347 props[1].datatype = PTP_DTC_STR;
7348 props[1].propval.str = name;
7350 ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7354 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7357 if (ret != PTP_RC_OK) {
7358 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7359 if (ret == PTP_RC_AccessDenied) {
7360 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7364 // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7367 add_object_to_cache(device, new_id);
7373 * This creates a new playlist metadata structure and allocates memory
7374 * for it. Notice that if you add strings to this structure they
7375 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7376 * operation later, so be careful of using strdup() when assigning
7380 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7381 * pl->name = strdup(str);
7383 * LIBMTP_destroy_playlist_t(pl);
7386 * @return a pointer to the newly allocated metadata structure.
7387 * @see LIBMTP_destroy_playlist_t()
7389 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7391 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7395 new->playlist_id = 0;
7397 new->storage_id = 0;
7406 * This destroys a playlist metadata structure and deallocates the memory
7407 * used by it, including any strings. Never use a track metadata
7408 * structure again after calling this function on it.
7409 * @param playlist the playlist metadata to destroy.
7410 * @see LIBMTP_new_playlist_t()
7412 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7414 if (playlist == NULL) {
7417 if (playlist->name != NULL)
7418 free(playlist->name);
7419 if (playlist->tracks != NULL)
7420 free(playlist->tracks);
7426 * This function returns a list of the playlists available on the
7427 * device. Typical usage:
7432 * @param device a pointer to the device to get the playlist listing from.
7433 * @return a playlist list on success, else NULL. If there are no playlists
7434 * on the device, NULL will be returned as well.
7435 * @see LIBMTP_Get_Playlist()
7437 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7439 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7440 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7441 PTPParams *params = (PTPParams *) device->params;
7442 LIBMTP_playlist_t *retlists = NULL;
7443 LIBMTP_playlist_t *curlist = NULL;
7446 // Get all the handles if we haven't already done that
7447 if (params->nrofobjects == 0) {
7448 flush_handles(device);
7451 for (i = 0; i < params->nrofobjects; i++) {
7452 LIBMTP_playlist_t *pl;
7456 ob = ¶ms->objects[i];
7458 // Ignore stuff that isn't playlists
7460 // For Samsung players we must look for the .spl extension explicitly since
7461 // playlists are not stored as playlist objects.
7462 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7463 // Allocate a new playlist type
7464 pl = LIBMTP_new_playlist_t();
7465 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7467 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7471 // Allocate a new playlist type
7472 pl = LIBMTP_new_playlist_t();
7474 // Try to look up proper name, else use the oi->Filename field.
7475 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7476 if (pl->name == NULL) {
7477 pl->name = strdup(ob->oi.Filename);
7479 pl->playlist_id = ob->oid;
7480 pl->parent_id = ob->oi.ParentObject;
7481 pl->storage_id = ob->oi.StorageID;
7483 // Then get the track listing for this playlist
7484 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7485 if (ret != PTP_RC_OK) {
7486 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7487 "could not get object references.");
7493 // Add playlist to a list that will be returned afterwards.
7494 if (retlists == NULL) {
7502 // Call callback here if we decide to add that possibility...
7509 * This function retrieves an individual playlist from the device.
7510 * @param device a pointer to the device to get the playlist from.
7511 * @param plid the unique ID of the playlist to retrieve.
7512 * @return a valid playlist metadata post or NULL on failure.
7513 * @see LIBMTP_Get_Playlist_List()
7515 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7517 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7518 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7519 PTPParams *params = (PTPParams *) device->params;
7521 LIBMTP_playlist_t *pl;
7524 // Get all the handles if we haven't already done that
7525 if (params->nrofobjects == 0) {
7526 flush_handles(device);
7529 ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7530 if (ret != PTP_RC_OK)
7533 // For Samsung players we must look for the .spl extension explicitly since
7534 // playlists are not stored as playlist objects.
7535 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7536 // Allocate a new playlist type
7537 pl = LIBMTP_new_playlist_t();
7538 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7542 // Ignore stuff that isn't playlists
7543 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7547 // Allocate a new playlist type
7548 pl = LIBMTP_new_playlist_t();
7550 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7551 if (pl->name == NULL) {
7552 pl->name = strdup(ob->oi.Filename);
7554 pl->playlist_id = ob->oid;
7555 pl->parent_id = ob->oi.ParentObject;
7556 pl->storage_id = ob->oi.StorageID;
7558 // Then get the track listing for this playlist
7559 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7560 if (ret != PTP_RC_OK) {
7561 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7570 * This function creates a new abstract list such as a playlist
7573 * @param device a pointer to the device to create the new abstract list
7575 * @param name the name of the new abstract list.
7576 * @param artist the artist of the new abstract list or NULL.
7577 * @param genre the genre of the new abstract list or NULL.
7578 * @param parenthandle the handle of the parent or 0 for no parent
7579 * i.e. the root folder.
7580 * @param objectformat the abstract list type to create.
7581 * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7582 * "file" created by this operation.
7583 * @param newid a pointer to a variable that will hold the new object
7584 * ID if this call is successful.
7585 * @param tracks an array of tracks to associate with this list.
7586 * @param no_tracks the number of tracks in the list.
7587 * @return 0 on success, any other value means failure.
7589 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7590 char const * const name,
7591 char const * const artist,
7592 char const * const composer,
7593 char const * const genre,
7594 uint32_t const parenthandle,
7595 uint32_t const storageid,
7596 uint16_t const objectformat,
7597 char const * const suffix,
7598 uint32_t * const newid,
7599 uint32_t const * const tracks,
7600 uint32_t const no_tracks)
7606 uint16_t *properties = NULL;
7607 uint32_t propcnt = 0;
7609 uint32_t localph = parenthandle;
7610 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7611 PTPParams *params = (PTPParams *) device->params;
7612 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7618 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7622 if (storageid == 0) {
7623 // I'm just guessing that an abstract list may require 512 bytes
7624 store = get_suggested_storage_id(device, 512, localph);
7629 // Check if we can create an object of this type
7630 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7631 if (params->deviceinfo.ImageFormats[i] == objectformat) {
7637 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7638 LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7642 // add the new suffix if it isn't there
7644 if (strlen(name) > strlen(suffix)) {
7645 char const * const suff = &name[strlen(name)-strlen(suffix)];
7646 if (!strcmp(suff, suffix)) {
7648 strncpy(fname, name, sizeof(fname));
7651 // If it didn't end with "<suffix>" then add that here.
7652 if (fname[0] == '\0') {
7653 strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7654 strcat(fname, suffix);
7655 fname[sizeof(fname)-1] = '\0';
7658 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7659 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7660 MTPProperties *props = NULL;
7661 MTPProperties *prop = NULL;
7664 *newid = 0x00000000U;
7666 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7668 for (i=0;i<propcnt;i++) {
7669 PTPObjectPropDesc opd;
7671 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7672 if (ret != PTP_RC_OK) {
7673 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7674 "could not get property description.");
7675 } else if (opd.GetSet) {
7676 switch (properties[i]) {
7677 case PTP_OPC_ObjectFileName:
7678 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7679 prop->ObjectHandle = *newid;
7680 prop->property = PTP_OPC_ObjectFileName;
7681 prop->datatype = PTP_DTC_STR;
7682 prop->propval.str = strdup(fname);
7683 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7684 strip_7bit_from_utf8(prop->propval.str);
7687 case PTP_OPC_ProtectionStatus:
7688 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7689 prop->ObjectHandle = *newid;
7690 prop->property = PTP_OPC_ProtectionStatus;
7691 prop->datatype = PTP_DTC_UINT16;
7692 prop->propval.u16 = 0x0000U; /* Not protected */
7694 case PTP_OPC_NonConsumable:
7695 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7696 prop->ObjectHandle = *newid;
7697 prop->property = PTP_OPC_NonConsumable;
7698 prop->datatype = PTP_DTC_UINT8;
7699 prop->propval.u8 = nonconsumable;
7703 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7704 prop->ObjectHandle = *newid;
7705 prop->property = PTP_OPC_Name;
7706 prop->datatype = PTP_DTC_STR;
7707 prop->propval.str = strdup(name);
7710 case PTP_OPC_AlbumArtist:
7711 if (artist != NULL) {
7712 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7713 prop->ObjectHandle = *newid;
7714 prop->property = PTP_OPC_AlbumArtist;
7715 prop->datatype = PTP_DTC_STR;
7716 prop->propval.str = strdup(artist);
7719 case PTP_OPC_Artist:
7720 if (artist != NULL) {
7721 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7722 prop->ObjectHandle = *newid;
7723 prop->property = PTP_OPC_Artist;
7724 prop->datatype = PTP_DTC_STR;
7725 prop->propval.str = strdup(artist);
7728 case PTP_OPC_Composer:
7729 if (composer != NULL) {
7730 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7731 prop->ObjectHandle = *newid;
7732 prop->property = PTP_OPC_Composer;
7733 prop->datatype = PTP_DTC_STR;
7734 prop->propval.str = strdup(composer);
7738 if (genre != NULL) {
7739 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7740 prop->ObjectHandle = *newid;
7741 prop->property = PTP_OPC_Genre;
7742 prop->datatype = PTP_DTC_STR;
7743 prop->propval.str = strdup(genre);
7746 case PTP_OPC_DateModified:
7747 // Tag with current time if that is supported
7748 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7749 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7750 prop->ObjectHandle = *newid;
7751 prop->property = PTP_OPC_DateModified;
7752 prop->datatype = PTP_DTC_STR;
7753 prop->propval.str = get_iso8601_stamp();
7758 ptp_free_objectpropdesc(&opd);
7762 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7763 objectformat, 0, props, nrofprops);
7765 /* Free property list */
7766 ptp_destroy_object_prop_list(props, nrofprops);
7768 if (ret != PTP_RC_OK) {
7769 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7770 if (ret == PTP_RC_AccessDenied) {
7771 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7776 // now send the blank object
7777 ret = ptp_sendobject(params, NULL, 0);
7778 if (ret != PTP_RC_OK) {
7779 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7783 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7784 PTPObjectInfo new_object;
7786 new_object.Filename = fname;
7787 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7788 strip_7bit_from_utf8(new_object.Filename);
7790 // At one point this had to be one
7791 new_object.ObjectCompressedSize = 0;
7792 new_object.ObjectFormat = objectformat;
7794 // Create the object
7795 ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7796 if (ret != PTP_RC_OK) {
7797 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7798 if (ret == PTP_RC_AccessDenied) {
7799 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7803 // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7808 * At one time we had to send this one blank data byte.
7809 * If we didn't, the handle will not be created and thus there is
7810 * no playlist. Possibly this was masking some bug, so removing it
7815 ret = ptp_sendobject(params, data, 1);
7816 if (ret != PTP_RC_OK) {
7817 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7822 // set the properties one by one
7823 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7825 for (i=0;i<propcnt;i++) {
7826 PTPObjectPropDesc opd;
7828 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7829 if (ret != PTP_RC_OK) {
7830 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7831 "could not get property description.");
7832 } else if (opd.GetSet) {
7833 switch (properties[i]) {
7836 ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7838 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7843 case PTP_OPC_AlbumArtist:
7844 if (artist != NULL) {
7845 ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7847 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7852 case PTP_OPC_Artist:
7853 if (artist != NULL) {
7854 ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7856 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7861 case PTP_OPC_Composer:
7862 if (composer != NULL) {
7863 ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7865 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7871 if (genre != NULL) {
7872 ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7874 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7879 case PTP_OPC_DateModified:
7880 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7881 ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7883 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7890 ptp_free_objectpropdesc(&opd);
7895 if (no_tracks > 0) {
7896 // Add tracks to the list as object references.
7897 ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7898 if (ret != PTP_RC_OK) {
7899 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7904 add_object_to_cache(device, *newid);
7910 * This updates the metadata and track listing
7911 * for an abstract list.
7912 * @param device a pointer to the device that the abstract list
7914 * @param name the name of the abstract list.
7915 * @param artist the artist of the abstract list or NULL.
7916 * @param genre the genre of the abstract list or NULL.
7917 * @param objecthandle the object to be updated.
7918 * @param objectformat the abstract list type to update.
7919 * @param tracks an array of tracks to associate with this list.
7920 * @param no_tracks the number of tracks in the list.
7921 * @return 0 on success, any other value means failure.
7923 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7924 char const * const name,
7925 char const * const artist,
7926 char const * const composer,
7927 char const * const genre,
7928 uint32_t const objecthandle,
7929 uint16_t const objectformat,
7930 uint32_t const * const tracks,
7931 uint32_t const no_tracks)
7934 PTPParams *params = (PTPParams *) device->params;
7935 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7936 uint16_t *properties = NULL;
7937 uint32_t propcnt = 0;
7940 // First see which properties can be set
7941 // i.e only try to update this metadata for object tags that exist on the current player.
7942 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7943 if (ret != PTP_RC_OK) {
7944 // Just bail out for now, nothing is ever set.
7945 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7946 "could not retrieve supported object properties.");
7949 if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
7950 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
7951 MTPProperties *props = NULL;
7952 MTPProperties *prop = NULL;
7955 for (i=0;i<propcnt;i++) {
7956 PTPObjectPropDesc opd;
7958 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7959 if (ret != PTP_RC_OK) {
7960 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7961 "could not get property description.");
7962 } else if (opd.GetSet) {
7963 switch (properties[i]) {
7965 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7966 prop->ObjectHandle = objecthandle;
7967 prop->property = PTP_OPC_Name;
7968 prop->datatype = PTP_DTC_STR;
7970 prop->propval.str = strdup(name);
7972 case PTP_OPC_AlbumArtist:
7973 if (artist != NULL) {
7974 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7975 prop->ObjectHandle = objecthandle;
7976 prop->property = PTP_OPC_AlbumArtist;
7977 prop->datatype = PTP_DTC_STR;
7978 prop->propval.str = strdup(artist);
7981 case PTP_OPC_Artist:
7982 if (artist != NULL) {
7983 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7984 prop->ObjectHandle = objecthandle;
7985 prop->property = PTP_OPC_Artist;
7986 prop->datatype = PTP_DTC_STR;
7987 prop->propval.str = strdup(artist);
7990 case PTP_OPC_Composer:
7991 if (composer != NULL) {
7992 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7993 prop->ObjectHandle = objecthandle;
7994 prop->property = PTP_OPC_Composer;
7995 prop->datatype = PTP_DTC_STR;
7996 prop->propval.str = strdup(composer);
8000 if (genre != NULL) {
8001 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8002 prop->ObjectHandle = objecthandle;
8003 prop->property = PTP_OPC_Genre;
8004 prop->datatype = PTP_DTC_STR;
8005 prop->propval.str = strdup(genre);
8008 case PTP_OPC_DateModified:
8009 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8010 // Tag with current time if that is supported
8011 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8012 prop->ObjectHandle = objecthandle;
8013 prop->property = PTP_OPC_DateModified;
8014 prop->datatype = PTP_DTC_STR;
8015 prop->propval.str = get_iso8601_stamp();
8022 ptp_free_objectpropdesc(&opd);
8025 // proplist could be NULL if we can't write any properties
8026 if (props != NULL) {
8027 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8029 ptp_destroy_object_prop_list(props, nrofprops);
8031 if (ret != PTP_RC_OK) {
8032 // TODO: return error of which property we couldn't set
8033 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8034 "could not set object property list.");
8040 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8041 for (i=0;i<propcnt;i++) {
8042 switch (properties[i]) {
8045 ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8047 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8048 "could not set title.");
8051 case PTP_OPC_AlbumArtist:
8052 // Update album artist
8053 ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8055 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8056 "could not set album artist name.");
8059 case PTP_OPC_Artist:
8061 ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8063 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8064 "could not set artist name.");
8067 case PTP_OPC_Composer:
8069 ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8071 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8072 "could not set composer name.");
8076 // Update genre (but only if valid)
8078 ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8080 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8081 "could not set genre.");
8085 case PTP_OPC_DateModified:
8086 // Update date modified
8087 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8088 char *tmpdate = get_iso8601_stamp();
8089 ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8091 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8092 "could not set modification date.");
8102 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8103 "Your device doesn't seem to support any known way of setting metadata.");
8108 // Then the object references...
8109 ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8110 if (ret != PTP_RC_OK) {
8111 add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8118 update_metadata_cache(device, objecthandle);
8125 * This routine creates a new playlist based on the metadata
8126 * supplied. If the <code>tracks</code> field of the metadata
8127 * contains a track listing, these tracks will be added to the
8129 * @param device a pointer to the device to create the new playlist on.
8130 * @param metadata the metadata for the new playlist. If the function
8131 * exits with success, the <code>playlist_id</code> field of this
8132 * struct will contain the new playlist ID of the playlist.
8134 * <li><code>metadata->parent_id</code> should be set to the parent
8135 * (e.g. folder) to store this track in. Since some
8136 * devices are a bit picky about where files
8137 * are placed, a default folder will be chosen if libmtp
8138 * has detected one for the current filetype and this
8139 * parameter is set to 0. If this is 0 and no default folder
8140 * can be found, the file will be stored in the root folder.
8141 * <li><code>metadata->storage_id</code> should be set to the
8142 * desired storage (e.g. memory card or whatever your device
8143 * presents) to store this track in. Setting this to 0 will store
8144 * the track on the primary storage.
8146 * @return 0 on success, any other value means failure.
8147 * @see LIBMTP_Update_Playlist()
8148 * @see LIBMTP_Delete_Object()
8150 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8151 LIBMTP_playlist_t * const metadata)
8153 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8154 uint32_t localph = metadata->parent_id;
8156 // Use a default folder if none given
8158 if (device->default_playlist_folder != 0)
8159 localph = device->default_playlist_folder;
8161 localph = device->default_music_folder;
8163 metadata->parent_id = localph;
8165 // Samsung needs its own special type of playlists
8166 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8167 return playlist_t_to_spl(device, metadata);
8170 // Just create a new abstract audio/video playlist...
8171 return create_new_abstract_list(device,
8177 metadata->storage_id,
8178 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8179 get_playlist_extension(ptp_usb),
8180 &metadata->playlist_id,
8182 metadata->no_tracks);
8186 * This routine updates a playlist based on the metadata
8187 * supplied. If the <code>tracks</code> field of the metadata
8188 * contains a track listing, these tracks will be added to the
8189 * playlist in place of those already present, i.e. the
8190 * previous track listing will be deleted. For Samsung devices the
8191 * playlist id (metadata->playlist_id) is likely to change.
8192 * @param device a pointer to the device to create the new playlist on.
8193 * @param metadata the metadata for the playlist to be updated.
8194 * notice that the field <code>playlist_id</code>
8195 * must contain the apropriate playlist ID. Playlist ID
8196 * be modified to a new playlist ID by the time the
8197 * function returns since edit-in-place is not always possible.
8198 * @return 0 on success, any other value means failure.
8199 * @see LIBMTP_Create_New_Playlist()
8200 * @see LIBMTP_Delete_Object()
8202 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8203 LIBMTP_playlist_t * const metadata)
8206 // Samsung needs its own special type of playlists
8207 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8208 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8209 return update_spl_playlist(device, metadata);
8212 return update_abstract_list(device,
8217 metadata->playlist_id,
8218 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8220 metadata->no_tracks);
8224 * This creates a new album metadata structure and allocates memory
8225 * for it. Notice that if you add strings to this structure they
8226 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8227 * operation later, so be careful of using strdup() when assigning
8230 * @return a pointer to the newly allocated metadata structure.
8231 * @see LIBMTP_destroy_album_t()
8233 LIBMTP_album_t *LIBMTP_new_album_t(void)
8235 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8241 new->storage_id = 0;
8244 new->composer = NULL;
8253 * This recursively deletes the memory for an album structure
8255 * @param album structure to destroy
8256 * @see LIBMTP_new_album_t()
8258 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8260 if (album == NULL) {
8263 if (album->name != NULL)
8265 if (album->artist != NULL)
8266 free(album->artist);
8267 if (album->composer != NULL)
8268 free(album->composer);
8269 if (album->genre != NULL)
8271 if (album->tracks != NULL)
8272 free(album->tracks);
8278 * This function maps and copies a property onto the album metadata if applicable.
8280 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8281 MTPProperties *prop, LIBMTP_album_t *alb)
8283 switch (prop->property) {
8285 if (prop->propval.str != NULL)
8286 alb->name = strdup(prop->propval.str);
8290 case PTP_OPC_AlbumArtist:
8291 if (prop->propval.str != NULL) {
8292 // This should take precedence over plain "Artist"
8293 if (alb->artist != NULL)
8295 alb->artist = strdup(prop->propval.str);
8299 case PTP_OPC_Artist:
8300 if (prop->propval.str != NULL) {
8301 // Only use of AlbumArtist is not set
8302 if (alb->artist == NULL)
8303 alb->artist = strdup(prop->propval.str);
8307 case PTP_OPC_Composer:
8308 if (prop->propval.str != NULL)
8309 alb->composer = strdup(prop->propval.str);
8311 alb->composer = NULL;
8314 if (prop->propval.str != NULL)
8315 alb->genre = strdup(prop->propval.str);
8323 * This function retrieves the album metadata for an album
8324 * given by a unique ID.
8325 * @param device a pointer to the device to get the track metadata off.
8326 * @param alb an album metadata metadata set to fill in.
8328 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8329 LIBMTP_album_t *alb)
8332 PTPParams *params = (PTPParams *) device->params;
8334 MTPProperties *prop;
8338 * If we have a cached, large set of metadata, then use it!
8340 ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8342 prop = ob->mtpprops;
8343 for (i=0;i<ob->nrofmtpprops;i++,prop++)
8344 pick_property_to_album_metadata(device, prop, alb);
8346 uint16_t *props = NULL;
8347 uint32_t propcnt = 0;
8349 // First see which properties can be retrieved for albums
8350 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8351 if (ret != PTP_RC_OK) {
8352 add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8353 // Just bail out for now, nothing is ever set.
8356 for (i=0;i<propcnt;i++) {
8359 alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8361 case PTP_OPC_AlbumArtist:
8362 if (alb->artist != NULL)
8364 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8366 case PTP_OPC_Artist:
8367 if (alb->artist == NULL)
8368 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8370 case PTP_OPC_Composer:
8371 alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8374 alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8387 * This function returns a list of the albums available on the
8390 * @param device a pointer to the device to get the album listing from.
8391 * @return an album list on success, else NULL. If there are no albums
8392 * on the device, NULL will be returned as well.
8393 * @see LIBMTP_Get_Album()
8395 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8397 // Read all storage devices
8398 return LIBMTP_Get_Album_List_For_Storage(device, 0);
8403 * This function returns a list of the albums available on the
8404 * device. You can filter on the storage ID.
8406 * @param device a pointer to the device to get the album listing from.
8407 * @param storage_id ID of device storage (if null, all storages)
8409 * @return an album list on success, else NULL. If there are no albums
8410 * on the device, NULL will be returned as well.
8411 * @see LIBMTP_Get_Album()
8413 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8415 PTPParams *params = (PTPParams *) device->params;
8416 LIBMTP_album_t *retalbums = NULL;
8417 LIBMTP_album_t *curalbum = NULL;
8420 // Get all the handles if we haven't already done that
8421 if (params->nrofobjects == 0)
8422 flush_handles(device);
8424 for (i = 0; i < params->nrofobjects; i++) {
8425 LIBMTP_album_t *alb;
8429 ob = ¶ms->objects[i];
8431 // Ignore stuff that isn't an album
8432 if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8435 // Ignore stuff that isn't into the storage device
8436 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8439 // Allocate a new album type
8440 alb = LIBMTP_new_album_t();
8441 alb->album_id = ob->oid;
8442 alb->parent_id = ob->oi.ParentObject;
8443 alb->storage_id = ob->oi.StorageID;
8445 // Fetch supported metadata
8446 get_album_metadata(device, alb);
8448 // Then get the track listing for this album
8449 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8450 if (ret != PTP_RC_OK) {
8451 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8456 // Add album to a list that will be returned afterwards.
8457 if (retalbums == NULL) {
8461 curalbum->next = alb;
8470 * This function retrieves an individual album from the device.
8471 * @param device a pointer to the device to get the album from.
8472 * @param albid the unique ID of the album to retrieve.
8473 * @return a valid album metadata or NULL on failure.
8474 * @see LIBMTP_Get_Album_List()
8476 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8478 PTPParams *params = (PTPParams *) device->params;
8481 LIBMTP_album_t *alb;
8483 // Get all the handles if we haven't already done that
8484 if (params->nrofobjects == 0)
8485 flush_handles(device);
8487 ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8488 if (ret != PTP_RC_OK)
8491 // Ignore stuff that isn't an album
8492 if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8495 // Allocate a new album type
8496 alb = LIBMTP_new_album_t();
8497 alb->album_id = ob->oid;
8498 alb->parent_id = ob->oi.ParentObject;
8499 alb->storage_id = ob->oi.StorageID;
8501 // Fetch supported metadata
8502 get_album_metadata(device, alb);
8504 // Then get the track listing for this album
8505 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8506 if (ret != PTP_RC_OK) {
8507 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8516 * This routine creates a new album based on the metadata
8517 * supplied. If the <code>tracks</code> field of the metadata
8518 * contains a track listing, these tracks will be added to the
8520 * @param device a pointer to the device to create the new album on.
8521 * @param metadata the metadata for the new album. If the function
8522 * exits with success, the <code>album_id</code> field of this
8523 * struct will contain the new ID of the album.
8525 * <li><code>metadata->parent_id</code> should be set to the parent
8526 * (e.g. folder) to store this track in. Since some
8527 * devices are a bit picky about where files
8528 * are placed, a default folder will be chosen if libmtp
8529 * has detected one for the current filetype and this
8530 * parameter is set to 0. If this is 0 and no default folder
8531 * can be found, the file will be stored in the root folder.
8532 * <li><code>metadata->storage_id</code> should be set to the
8533 * desired storage (e.g. memory card or whatever your device
8534 * presents) to store this track in. Setting this to 0 will store
8535 * the track on the primary storage.
8537 * @return 0 on success, any other value means failure.
8538 * @see LIBMTP_Update_Album()
8539 * @see LIBMTP_Delete_Object()
8541 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8542 LIBMTP_album_t * const metadata)
8544 uint32_t localph = metadata->parent_id;
8546 // Use a default folder if none given
8548 if (device->default_album_folder != 0)
8549 localph = device->default_album_folder;
8551 localph = device->default_music_folder;
8553 metadata->parent_id = localph;
8555 // Just create a new abstract album...
8556 return create_new_abstract_list(device,
8562 metadata->storage_id,
8563 PTP_OFC_MTP_AbstractAudioAlbum,
8565 &metadata->album_id,
8567 metadata->no_tracks);
8571 * This creates a new sample data metadata structure and allocates memory
8572 * for it. Notice that if you add strings to this structure they
8573 * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8574 * operation later, so be careful of using strdup() when assigning
8577 * @return a pointer to the newly allocated metadata structure.
8578 * @see LIBMTP_destroy_sampledata_t()
8580 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8582 LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8595 * This destroys a file sample metadata type.
8596 * @param sample the file sample metadata to be destroyed.
8598 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8600 if (sample == NULL) {
8603 if (sample->data != NULL) {
8610 * This routine figures out whether a certain filetype supports
8611 * representative samples (small thumbnail images) or not. This
8612 * typically applies to JPEG files, MP3 files and Album abstract
8613 * playlists, but in theory any filetype could support representative
8615 * @param device a pointer to the device which is to be examined.
8616 * @param filetype the fileype to examine, and return the representative sample
8618 * @param sample this will contain a new sample type with the fields
8619 * filled in with suitable default values. For example, the
8620 * supported sample type will be set, the supported height and
8621 * width will be set to max values if it is an image sample,
8622 * and duration will also be given some suitable default value
8623 * which should not be exceeded on audio samples. If the
8624 * device does not support samples for this filetype, this
8625 * pointer will be NULL. If it is not NULL, the user must
8626 * destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8628 * @return 0 on success, any other value means failure.
8629 * @see LIBMTP_Send_Representative_Sample()
8630 * @see LIBMTP_Create_New_Album()
8632 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8633 LIBMTP_filetype_t const filetype,
8634 LIBMTP_filesampledata_t ** sample)
8637 PTPParams *params = (PTPParams *) device->params;
8638 uint16_t *props = NULL;
8639 uint32_t propcnt = 0;
8641 // TODO: Get rid of these when we can properly query the device.
8642 int support_data = 0;
8643 int support_format = 0;
8644 int support_height = 0;
8645 int support_width = 0;
8646 int support_duration = 0;
8647 int support_size = 0;
8649 PTPObjectPropDesc opd_height;
8650 PTPObjectPropDesc opd_width;
8651 PTPObjectPropDesc opd_format;
8652 PTPObjectPropDesc opd_duration;
8653 PTPObjectPropDesc opd_size;
8655 // Default to no type supported.
8658 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8659 if (ret != PTP_RC_OK) {
8660 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8664 * TODO: when walking through these object properties, make calls to
8665 * a new function in ptp.h/ptp.c that can send the command
8666 * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8669 for (i = 0; i < propcnt; i++) {
8671 case PTP_OPC_RepresentativeSampleData:
8674 case PTP_OPC_RepresentativeSampleFormat:
8677 case PTP_OPC_RepresentativeSampleSize:
8680 case PTP_OPC_RepresentativeSampleHeight:
8683 case PTP_OPC_RepresentativeSampleWidth:
8686 case PTP_OPC_RepresentativeSampleDuration:
8687 support_duration = 1;
8695 if (support_data && support_format && support_height && support_width && !support_duration) {
8696 // Something that supports height and width and not duration is likely to be JPEG
8697 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8699 * Populate the sample format with the first supported format
8701 * TODO: figure out how to pass back more than one format if more are
8702 * supported by the device.
8704 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8705 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8706 ptp_free_objectpropdesc(&opd_format);
8707 /* Populate the maximum image height */
8708 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8709 retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8710 ptp_free_objectpropdesc(&opd_width);
8711 /* Populate the maximum image width */
8712 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8713 retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8714 ptp_free_objectpropdesc(&opd_height);
8715 /* Populate the maximum size */
8717 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8718 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8719 ptp_free_objectpropdesc(&opd_size);
8722 } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8723 // Another qualified guess
8724 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8726 * Populate the sample format with the first supported format
8728 * TODO: figure out how to pass back more than one format if more are
8729 * supported by the device.
8731 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8732 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8733 ptp_free_objectpropdesc(&opd_format);
8734 /* Populate the maximum duration */
8735 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8736 retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8737 ptp_free_objectpropdesc(&opd_duration);
8738 /* Populate the maximum size */
8740 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8741 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8742 ptp_free_objectpropdesc(&opd_size);
8750 * This routine sends representative sample data for an object.
8751 * This uses the RepresentativeSampleData property of the album,
8752 * if the device supports it. The data should be of a format acceptable
8753 * to the player (for iRiver and Creative, this seems to be JPEG) and
8754 * must not be too large. (for a Creative, max seems to be about 20KB.)
8755 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8756 * maximum size, dimensions, etc..
8757 * @param device a pointer to the device which the object is on.
8758 * @param id unique id of the object to set artwork for.
8759 * @param pointer to LIBMTP_filesampledata_t struct containing data
8760 * @return 0 on success, any other value means failure.
8761 * @see LIBMTP_Get_Representative_Sample()
8762 * @see LIBMTP_Get_Representative_Sample_Format()
8763 * @see LIBMTP_Create_New_Album()
8765 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8767 LIBMTP_filesampledata_t *sampledata)
8770 PTPParams *params = (PTPParams *) device->params;
8771 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8772 PTPPropertyValue propval;
8775 uint16_t *props = NULL;
8776 uint32_t propcnt = 0;
8779 // get the file format for the object we're going to send representative data for
8780 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8781 if (ret != PTP_RC_OK) {
8782 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8786 // check that we can send representative sample data for this object format
8787 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8788 if (ret != PTP_RC_OK) {
8789 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8793 for (i = 0; i < propcnt; i++) {
8794 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8801 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8806 // Go ahead and send the data
8807 propval.a.count = sampledata->size;
8808 propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8809 for (i = 0; i < sampledata->size; i++) {
8810 propval.a.v[i].u8 = sampledata->data[i];
8813 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8814 &propval,PTP_DTC_AUINT8);
8815 if (ret != PTP_RC_OK) {
8816 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8822 /* Set the height and width if the sample is an image, otherwise just
8823 * set the duration and size */
8824 switch(sampledata->filetype) {
8825 case LIBMTP_FILETYPE_JPEG:
8826 case LIBMTP_FILETYPE_JFIF:
8827 case LIBMTP_FILETYPE_TIFF:
8828 case LIBMTP_FILETYPE_BMP:
8829 case LIBMTP_FILETYPE_GIF:
8830 case LIBMTP_FILETYPE_PICT:
8831 case LIBMTP_FILETYPE_PNG:
8832 if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8833 // For images, set the height and width
8834 set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8835 set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8839 // For anything not an image, set the duration and size
8840 set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8841 set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8849 * This routine gets representative sample data for an object.
8850 * This uses the RepresentativeSampleData property of the album,
8851 * if the device supports it.
8852 * @param device a pointer to the device which the object is on.
8853 * @param id unique id of the object to get data for.
8854 * @param pointer to LIBMTP_filesampledata_t struct to receive data
8855 * @return 0 on success, any other value means failure.
8856 * @see LIBMTP_Send_Representative_Sample()
8857 * @see LIBMTP_Get_Representative_Sample_Format()
8858 * @see LIBMTP_Create_New_Album()
8860 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8862 LIBMTP_filesampledata_t *sampledata)
8865 PTPParams *params = (PTPParams *) device->params;
8866 PTPPropertyValue propval;
8869 uint16_t *props = NULL;
8870 uint32_t propcnt = 0;
8873 // get the file format for the object we're going to send representative data for
8874 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8875 if (ret != PTP_RC_OK) {
8876 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8880 // check that we can store representative sample data for this object format
8881 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8882 if (ret != PTP_RC_OK) {
8883 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8887 for (i = 0; i < propcnt; i++) {
8888 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8895 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8901 ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8902 &propval,PTP_DTC_AUINT8);
8903 if (ret != PTP_RC_OK) {
8904 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8909 sampledata->size = propval.a.count;
8910 sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8911 for (i = 0; i < propval.a.count; i++) {
8912 sampledata->data[i] = propval.a.v[i].u8;
8916 // Get the other properties
8917 sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8918 sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8919 sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8920 sampledata->filetype = map_ptp_type_to_libmtp_type(
8921 get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8927 * Retrieve the thumbnail for a file.
8928 * @param device a pointer to the device to get the thumbnail from.
8929 * @param id the object ID of the file to retrieve the thumbnail for.
8930 * @return 0 on success, any other value means failure.
8932 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
8933 unsigned char **data, unsigned int *size)
8935 PTPParams *params = (PTPParams *) device->params;
8938 ret = ptp_getthumb(params, id, data, size);
8939 if (ret == PTP_RC_OK)
8945 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
8946 uint64_t offset, uint32_t maxbytes,
8947 unsigned char **data, unsigned int *size)
8949 PTPParams *params = (PTPParams *) device->params;
8952 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_GetPartialObject64)) {
8953 if (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
8954 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8955 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
8959 if (offset >> 32 != 0) {
8960 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8961 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject only supports 32bit offsets");
8965 ret = ptp_getpartialobject(params, id, (uint32_t)offset, maxbytes, data, size);
8967 ret = ptp_android_getpartialobject64(params, id, offset, maxbytes, data, size);
8969 if (ret == PTP_RC_OK)
8975 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
8976 uint64_t offset, unsigned char *data, unsigned int size)
8978 PTPParams *params = (PTPParams *) device->params;
8981 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
8982 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
8983 "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
8987 ret = ptp_android_sendpartialobject(params, id, offset, data, size);
8988 if (ret == PTP_RC_OK)
8994 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
8996 PTPParams *params = (PTPParams *) device->params;
8999 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
9000 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9001 "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
9005 ret = ptp_android_begineditobject(params, id);
9006 if (ret == PTP_RC_OK)
9012 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9014 PTPParams *params = (PTPParams *) device->params;
9017 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
9018 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9019 "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
9023 ret = ptp_android_endeditobject(params, id);
9024 if (ret == PTP_RC_OK) {
9025 // update cached object properties if metadata cache exists
9026 update_metadata_cache(device, id);
9033 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9036 PTPParams *params = (PTPParams *) device->params;
9039 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9040 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9041 "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9045 ret = ptp_android_truncate(params, id, offset);
9046 if (ret == PTP_RC_OK)
9053 * This routine updates an album based on the metadata
9054 * supplied. If the <code>tracks</code> field of the metadata
9055 * contains a track listing, these tracks will be added to the
9056 * album in place of those already present, i.e. the
9057 * previous track listing will be deleted.
9058 * @param device a pointer to the device to create the new album on.
9059 * @param metadata the metadata for the album to be updated.
9060 * notice that the field <code>album_id</code>
9061 * must contain the apropriate album ID.
9062 * @return 0 on success, any other value means failure.
9063 * @see LIBMTP_Create_New_Album()
9064 * @see LIBMTP_Delete_Object()
9066 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9067 LIBMTP_album_t const * const metadata)
9069 return update_abstract_list(device,
9075 PTP_OFC_MTP_AbstractAudioAlbum,
9077 metadata->no_tracks);
9081 * Dummy function needed to interface to upstream
9082 * ptp.c/ptp.h files.
9084 void ptp_nikon_getptpipguid (unsigned char* guid) {
9089 * Add an object to cache.
9090 * @param device the device which may have a cache to which the object should be added.
9091 * @param object_id the object to add to the cache.
9093 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9095 PTPParams *params = (PTPParams *)device->params;
9098 ret = ptp_add_object_to_cache(params, object_id);
9099 if (ret != PTP_RC_OK) {
9100 add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9106 * Update cache after object has been modified
9107 * @param device the device which may have a cache to which the object should be updated.
9108 * @param object_id the object to update.
9110 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9112 PTPParams *params = (PTPParams *)device->params;
9114 ptp_remove_object_from_cache(params, object_id);
9115 add_object_to_cache(device, object_id);
9118 #if 1//defined TIZEN_EXT
9119 int _is_exist_handler(int **object_list, int size, int current_handler)
9123 for (i = 0; i < size; i++) {
9124 if ((*object_list)[i] == current_handler)
9131 int LIBMTP_Get_Object_Handles(LIBMTP_mtpdevice_t *device, uint32_t storage,
9132 uint32_t format, uint32_t parent, uint32_t **object_list, uint32_t *object_num)
9135 PTPParams *params = (PTPParams *)device->params;
9136 PTPObjectHandles currentHandles;
9142 if (!ptp_operation_issupported(params, PTP_OC_GetObjectHandles)) {
9143 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9144 "LIBMTP_Get_Object_List: LIBMTP_Get_Object_List not supported");
9149 storageid = PTP_GOH_ALL_STORAGE;
9151 storageid = storage;
9154 parentid = PTP_GOH_ROOT_PARENT;
9158 ret = ptp_getobjecthandles(params, storageid, PTP_GOH_ALL_FORMATS, parentid, ¤tHandles);
9160 if (ret != PTP_RC_OK)
9163 if (currentHandles.n == 0) {
9164 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9165 "LIBMTP_Get_Object_List: object handle is not exist");
9169 *object_list = (uint32_t *)malloc(currentHandles.n * sizeof(int));
9171 for (i = 0; i < currentHandles.n; i++) {
9172 if(_is_exist_handler(object_list, temp, currentHandles.Handler[i]))
9175 (*object_list)[temp] = currentHandles.Handler[i];
9181 if (currentHandles.Handler != NULL) {
9182 free(currentHandles.Handler);
9183 currentHandles.Handler = NULL;
9189 MTPObjectInfo *LIBMTP_Get_Object_Info(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9191 PTPParams *params = (PTPParams *)device->params;
9192 MTPObjectInfo *object_info;
9195 if (!ptp_operation_issupported(params, PTP_OC_GetObjectInfo)) {
9196 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9197 "LIBMTP_Get_Object_info: LIBMTP_Get_Object_info not supported");
9201 object_info = (MTPObjectInfo *)malloc(sizeof(MTPObjectInfo));
9203 ret = ptp_getobjectinfo(params, object_id, (PTPObjectInfo *)object_info);
9205 if (ret != PTP_RC_OK) {
9206 if (object_info != NULL)
9211 object_info->ObjectFormat = map_ptp_type_to_libmtp_type(object_info->ObjectFormat);
9212 object_info->ThumbFormat = map_ptp_type_to_libmtp_type(object_info->ThumbFormat);
9218 int LIBMTP_Get_Num_Objects(LIBMTP_mtpdevice_t *device, uint32_t format, uint32_t *object_num)
9220 PTPParams *params = (PTPParams *)device->params;
9223 if (!ptp_operation_issupported(params, PTP_OC_GetNumObjects)) {
9224 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9225 "LIBMTP_Get_Num_Objects: LIBMTP_Get_Num_Objects not supported");
9229 ret = ptp_getnumobjects(params, PTP_GOH_ALL_STORAGE, map_libmtp_type_to_ptp_type(format),
9230 PTP_GOH_ROOT_PARENT, object_num);
9232 if (ret != PTP_RC_OK)
9237 #endif /* TIZEN_EXT */