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>
58 #include <libexif/exif-data.h>
59 #endif /* TIZEN_EXT */
60 #ifdef _MSC_VER // For MSVC++
61 #define USE_WINDOWS_IO_H
68 * We use a flag system to enable a part of logs.
70 * The LIBMTP_DEBUG environment variable sets the debug flags for any binary
71 * that uses libmtp and calls LIBMTP_Init. The value can be given in decimal
72 * (must not start with "0" or it will be interpreted in octal), or in
73 * hexadecimal (must start with "0x").
75 * The value "-1" enables all debug flags.
77 * Some of the utilities in examples/ also take a command-line flag "-d" that
78 * enables LIBMTP_DEBUG_PTP and LIBMTP_DEBUG_DATA (same as setting
81 * Flags (combine by adding the hex values):
82 * 0x00 [0000 0000] : LIBMTP_DEBUG_NONE : no debug (default)
83 * 0x01 [0000 0001] : LIBMTP_DEBUG_PTP : PTP debug
84 * 0x02 [0000 0010] : LIBMTP_DEBUG_PLST : Playlist debug
85 * 0x04 [0000 0100] : LIBMTP_DEBUG_USB : USB debug
86 * 0x08 [0000 1000] : LIBMTP_DEBUG_DATA : USB data debug
88 * (Please keep this list in sync with libmtp.h.)
90 int LIBMTP_debug = LIBMTP_DEBUG_NONE;
94 * This is a mapping between libmtp internal MTP filetypes and
95 * the libgphoto2/PTP equivalent defines. We need this because
96 * otherwise the libmtp.h device has to be dependent on ptp.h
97 * to be installed too, and we don't want that.
99 //typedef struct filemap_struct filemap_t;
100 typedef struct filemap_struct {
101 char *description; /**< Text description for the file type */
102 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
103 uint16_t ptp_id; /**< PTP ID for the filetype */
104 struct filemap_struct *next;
108 * This is a mapping between libmtp internal MTP properties and
109 * the libgphoto2/PTP equivalent defines. We need this because
110 * otherwise the libmtp.h device has to be dependent on ptp.h
111 * to be installed too, and we don't want that.
113 typedef struct propertymap_struct {
114 char *description; /**< Text description for the property */
115 LIBMTP_property_t id; /**< LIBMTP internal type for the property */
116 uint16_t ptp_id; /**< PTP ID for the property */
117 struct propertymap_struct *next;
121 // This holds the global filetype mapping table
122 static filemap_t *g_filemap = NULL;
123 // This holds the global property mapping table
124 static propertymap_t *g_propertymap = NULL;
127 * Forward declarations of local (static) functions.
129 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
130 uint16_t const ptp_id);
131 static void init_filemap();
132 static int register_property(char const * const description, LIBMTP_property_t const id,
133 uint16_t const ptp_id);
134 static void init_propertymap();
135 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
136 LIBMTP_error_number_t errornumber,
137 char const * const error_text);
138 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
140 char const * const error_text);
141 static void flush_handles(LIBMTP_mtpdevice_t *device);
142 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
146 static void free_storage_list(LIBMTP_mtpdevice_t *device);
147 static int sort_storage_by(LIBMTP_mtpdevice_t *device, int const sortby);
148 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
150 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
151 LIBMTP_devicestorage_t *storage,
152 uint64_t *freespace);
153 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
154 LIBMTP_devicestorage_t *storage,
155 uint64_t const filesize);
156 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
157 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
158 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
159 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
160 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
161 char **unicstring, uint16_t property);
162 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
163 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd);
164 static char *get_iso8601_stamp(void);
165 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
166 uint16_t const attribute_id);
167 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
168 uint16_t const attribute_id, uint64_t const value_default);
169 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
170 uint16_t const attribute_id, uint32_t const value_default);
171 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
172 uint16_t const attribute_id, uint16_t const value_default);
173 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
174 uint16_t const attribute_id, uint8_t const value_default);
175 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
176 uint16_t const attribute_id, char const * const string);
177 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
178 uint16_t const attribute_id, uint32_t const value);
179 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
180 uint16_t const attribute_id, uint16_t const value);
181 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
182 uint16_t const attribute_id, uint8_t const value);
183 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
184 LIBMTP_track_t *track);
185 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent);
186 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
187 char const * const name,
188 char const * const artist,
189 char const * const composer,
190 char const * const genre,
191 uint32_t const parenthandle,
192 uint32_t const storageid,
193 uint16_t const objectformat,
194 char const * const suffix,
195 uint32_t * const newid,
196 uint32_t const * const tracks,
197 uint32_t const no_tracks);
198 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
199 char const * const name,
200 char const * const artist,
201 char const * const composer,
202 char const * const genre,
203 uint32_t const objecthandle,
204 uint16_t const objectformat,
205 uint32_t const * const tracks,
206 uint32_t const no_tracks);
207 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
208 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
209 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
210 static int set_object_filename(LIBMTP_mtpdevice_t *device,
213 const char **newname);
214 static char *generate_unique_filename(PTPParams* params, char const * const filename);
215 static int check_filename_exists(PTPParams* params, char const * const filename);
218 int _is_exist_handler(uint32_t **object_list, int size, int current_handler);
219 #endif /* TIZEN_EXT */
222 * These are to wrap the get/put handlers to convert from the MTP types to PTP types
225 typedef struct _MTPDataHandler {
226 MTPDataGetFunc getfunc;
227 MTPDataPutFunc putfunc;
231 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
232 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen);
235 * Checks if a filename ends with ".ogg". Used in various
236 * situations when the device has no idea that it support
237 * OGG but still does.
239 * @param name string to be checked.
240 * @return 0 if this does not end with ogg, any other
241 * value means it does.
243 static int has_ogg_extension(char *name) {
248 ptype = strrchr(name,'.');
251 if (!strcasecmp (ptype, ".ogg"))
257 * Checks if a filename ends with ".flac". Used in various
258 * situations when the device has no idea that it support
259 * FLAC but still does.
261 * @param name string to be checked.
262 * @return 0 if this does not end with flac, any other
263 * value means it does.
265 static int has_flac_extension(char *name) {
270 ptype = strrchr(name,'.');
273 if (!strcasecmp (ptype, ".flac"))
281 * Create a new file mapping entry
282 * @return a newly allocated filemapping entry.
284 static filemap_t *new_filemap_entry()
288 filemap = (filemap_t *)malloc(sizeof(filemap_t));
290 if( filemap != NULL ) {
291 filemap->description = NULL;
292 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
293 filemap->ptp_id = PTP_OFC_Undefined;
294 filemap->next = NULL;
301 * Register an MTP or PTP filetype for data retrieval
303 * @param description Text description of filetype
304 * @param id libmtp internal filetype id
305 * @param ptp_id PTP filetype id
306 * @return 0 for success any other value means error.
308 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
309 uint16_t const ptp_id)
311 filemap_t *new = NULL, *current;
313 // Has this LIBMTP filetype been registered before ?
315 while (current != NULL) {
316 if(current->id == id) {
319 current = current->next;
323 if(current == NULL) {
324 new = new_filemap_entry();
330 if(description != NULL) {
331 new->description = strdup(description);
333 new->ptp_id = ptp_id;
335 // Add the entry to the list
336 if(g_filemap == NULL) {
340 while (current->next != NULL ) current=current->next;
343 // Update the existing entry
345 if (current->description != NULL) {
346 free(current->description);
348 current->description = NULL;
349 if(description != NULL) {
350 current->description = strdup(description);
352 current->ptp_id = ptp_id;
358 static void init_filemap()
360 register_filetype("Folder", LIBMTP_FILETYPE_FOLDER, PTP_OFC_Association);
361 register_filetype("MediaCard", LIBMTP_FILETYPE_MEDIACARD, PTP_OFC_MTP_MediaCard);
362 register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);
363 register_filetype("ISO MPEG-1 Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);
364 register_filetype("ISO MPEG-1 Audio Layer 2", LIBMTP_FILETYPE_MP2, PTP_OFC_MTP_MP2);
365 register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);
366 register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
367 register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
368 register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
369 register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
370 register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
371 register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
372 register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
373 register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
374 register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);
375 register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);
376 register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);
377 register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);
378 register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);
379 register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);
380 register_filetype("JP2 file", LIBMTP_FILETYPE_JP2, PTP_OFC_JP2);
381 register_filetype("JPX file", LIBMTP_FILETYPE_JPX, PTP_OFC_JPX);
382 register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);
383 register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);
384 register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);
385 register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);
386 register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);
387 register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);
388 register_filetype("HEIF file", LIBMTP_FILETYPE_HEIF, PTP_OFC_HEIF);
389 register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);
390 register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);
391 register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);
392 register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);
393 register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);
394 register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);
395 register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);
396 register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);
397 register_filetype("XML file", LIBMTP_FILETYPE_XML, PTP_OFC_MTP_XMLDocument);
398 register_filetype("DOC file", LIBMTP_FILETYPE_DOC, PTP_OFC_MTP_MSWordDocument);
399 register_filetype("XLS file", LIBMTP_FILETYPE_XLS, PTP_OFC_MTP_MSExcelSpreadsheetXLS);
400 register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
401 register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
402 register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
403 register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
404 register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
405 register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
409 * Returns the PTP filetype that maps to a certain libmtp internal file type.
410 * @param intype the MTP library interface type
411 * @return the PTP (libgphoto2) interface type
413 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
419 while (current != NULL) {
420 if(current->id == intype) {
421 return current->ptp_id;
423 current = current->next;
425 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
426 return PTP_OFC_Undefined;
431 * Returns the MTP internal interface type that maps to a certain ptp
433 * @param intype the PTP (libgphoto2) interface type
434 * @return the MTP library interface type
436 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
442 while (current != NULL) {
443 if(current->ptp_id == intype) {
446 current = current->next;
448 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
449 return LIBMTP_FILETYPE_UNKNOWN;
453 * Create a new property mapping entry
454 * @return a newly allocated propertymapping entry.
456 static propertymap_t *new_propertymap_entry()
458 propertymap_t *propertymap;
460 propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
462 if( propertymap != NULL ) {
463 propertymap->description = NULL;
464 propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
465 propertymap->ptp_id = 0;
466 propertymap->next = NULL;
473 * Register an MTP or PTP property for data retrieval
475 * @param description Text description of property
476 * @param id libmtp internal property id
477 * @param ptp_id PTP property id
478 * @return 0 for success any other value means error.
480 static int register_property(char const * const description, LIBMTP_property_t const id,
481 uint16_t const ptp_id)
483 propertymap_t *new = NULL, *current;
485 // Has this LIBMTP propety been registered before ?
486 current = g_propertymap;
487 while (current != NULL) {
488 if(current->id == id) {
491 current = current->next;
495 if(current == NULL) {
496 new = new_propertymap_entry();
502 if(description != NULL) {
503 new->description = strdup(description);
505 new->ptp_id = ptp_id;
507 // Add the entry to the list
508 if(g_propertymap == NULL) {
511 current = g_propertymap;
512 while (current->next != NULL ) current=current->next;
515 // Update the existing entry
517 if (current->description != NULL) {
518 free(current->description);
520 current->description = NULL;
521 if(description != NULL) {
522 current->description = strdup(description);
524 current->ptp_id = ptp_id;
530 static void init_propertymap()
532 register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
533 register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
534 register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
535 register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
536 register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
537 register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
538 register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
539 register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
540 register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
541 register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
542 register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
543 register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
544 register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
545 register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
546 register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
547 register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
548 register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
549 register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
550 register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
551 register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
552 register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
553 register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
554 register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
555 register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
556 register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
557 register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
558 register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
559 register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
560 register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
561 register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
562 register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
563 register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
564 register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
565 register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
566 register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
567 register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
568 register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
569 register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
570 register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
571 register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
572 register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
573 register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
574 register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
575 register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
576 register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
577 register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
578 register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
579 register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
580 register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
581 register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
582 register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
583 register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
584 register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
585 register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
586 register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
587 register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
588 register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
589 register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
590 register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
591 register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
592 register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
593 register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
594 register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
595 register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
596 register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
597 register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
598 register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
599 register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
600 register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
601 register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
602 register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
603 register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
604 register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
605 register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
606 register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
607 register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
608 register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
609 register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
610 register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
611 register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
612 register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
613 register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
614 register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
615 register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
616 register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
617 register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
618 register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
619 register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
620 register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
621 register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
622 register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
623 register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
624 register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
625 register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
626 register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
627 register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
628 register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
629 register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
630 register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
631 register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
632 register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
633 register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
634 register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
635 register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
636 register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
637 register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
638 register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
639 register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
640 register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
641 register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
642 register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
643 register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
644 register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
645 register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
646 register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
647 register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
648 register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
649 register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
650 register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
651 register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
652 register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
653 register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
654 register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
655 register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
656 register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
657 register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
658 register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
659 register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
660 register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
661 register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
662 register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
663 register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
664 register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
665 register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
666 register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
667 register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
668 register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
669 register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
670 register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
671 register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
672 register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
673 register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
674 register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
675 register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
676 register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
677 register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
678 register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
679 register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
680 register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
681 register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
682 register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
683 register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
684 register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
685 register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
686 register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
687 register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
688 register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
689 register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
690 register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
691 register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
692 register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
693 register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
694 register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
695 register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
696 register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
697 register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
698 register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
699 register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
703 * Returns the PTP property that maps to a certain libmtp internal property type.
704 * @param inproperty the MTP library interface property
705 * @return the PTP (libgphoto2) property type
707 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
709 propertymap_t *current;
711 current = g_propertymap;
713 while (current != NULL) {
714 if(current->id == inproperty) {
715 return current->ptp_id;
717 current = current->next;
724 * Returns the MTP internal interface property that maps to a certain ptp
725 * interface property.
726 * @param inproperty the PTP (libgphoto2) interface property
727 * @return the MTP library interface property
729 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
731 propertymap_t *current;
733 current = g_propertymap;
735 while (current != NULL) {
736 if(current->ptp_id == inproperty) {
739 current = current->next;
741 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
742 return LIBMTP_PROPERTY_UNKNOWN;
747 * Set the debug level.
749 * By default, the debug level is set to '0' (disable).
751 void LIBMTP_Set_Debug(int level)
753 if (LIBMTP_debug || level)
754 LIBMTP_ERROR("LIBMTP_Set_Debug: Setting debugging level to %d (0x%02x) "
755 "(%s)\n", level, level, level ? "on" : "off");
757 LIBMTP_debug = level;
762 * Initialize the library. You are only supposed to call this
763 * one, before using the library for the first time in a program.
764 * Never re-initialize libmtp!
766 * The only thing this does at the moment is to initialise the
767 * filetype mapping table, as well as load MTPZ data if necessary.
769 void LIBMTP_Init(void)
771 const char *env_debug = getenv("LIBMTP_DEBUG");
773 const long debug_flags = strtol(env_debug, NULL, 0);
774 if (debug_flags != LONG_MIN && debug_flags != LONG_MAX &&
775 INT_MIN <= debug_flags && debug_flags <= INT_MAX) {
776 LIBMTP_Set_Debug(debug_flags);
778 fprintf(stderr, "LIBMTP_Init: error setting debug flags from environment "
779 "value \"%s\"\n", env_debug);
786 if (mtpz_loaddata() == -1)
796 * This helper function returns a textual description for a libmtp
797 * file type to be used in dialog boxes etc.
798 * @param intype the libmtp internal filetype to get a description for.
799 * @return a string representing the filetype, this must <b>NOT</b>
800 * be free():ed by the caller!
802 char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
808 while (current != NULL) {
809 if(current->id == intype) {
810 return current->description;
812 current = current->next;
815 return "Unknown filetype";
819 * This helper function returns a textual description for a libmtp
820 * property to be used in dialog boxes etc.
821 * @param inproperty the libmtp internal property to get a description for.
822 * @return a string representing the filetype, this must <b>NOT</b>
823 * be free():ed by the caller!
825 char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
827 propertymap_t *current;
829 current = g_propertymap;
831 while (current != NULL) {
832 if(current->id == inproperty) {
833 return current->description;
835 current = current->next;
838 return "Unknown property";
842 * This function will do its best to fit a 16bit
843 * value into a PTP object property if the property
844 * is limited in range or step sizes.
846 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd)
848 switch (opd->FormFlag) {
850 if (val < opd->FORM.Range.MinimumValue.u16) {
851 return opd->FORM.Range.MinimumValue.u16;
853 if (val > opd->FORM.Range.MaximumValue.u16) {
854 return opd->FORM.Range.MaximumValue.u16;
856 // Round down to last step.
857 if (val % opd->FORM.Range.StepSize.u16 != 0) {
858 return val - (val % opd->FORM.Range.StepSize.u16);
862 case PTP_DPFF_Enumeration:
865 uint16_t bestfit = opd->FORM.Enum.SupportedValue[0].u16;
867 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
868 if (val == opd->FORM.Enum.SupportedValue[i].u16) {
871 // Rough guess of best fit
872 if (opd->FORM.Enum.SupportedValue[i].u16 < val) {
873 bestfit = opd->FORM.Enum.SupportedValue[i].u16;
876 // Just some default that'll work.
880 // Will accept any value
887 * This function will do its best to fit a 32bit
888 * value into a PTP object property if the property
889 * is limited in range or step sizes.
891 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd)
893 switch (opd->FormFlag) {
895 if (val < opd->FORM.Range.MinimumValue.u32) {
896 return opd->FORM.Range.MinimumValue.u32;
898 if (val > opd->FORM.Range.MaximumValue.u32) {
899 return opd->FORM.Range.MaximumValue.u32;
901 // Round down to last step.
902 if (val % opd->FORM.Range.StepSize.u32 != 0) {
903 return val - (val % opd->FORM.Range.StepSize.u32);
907 case PTP_DPFF_Enumeration:
910 uint32_t bestfit = opd->FORM.Enum.SupportedValue[0].u32;
912 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
913 if (val == opd->FORM.Enum.SupportedValue[i].u32) {
916 // Rough guess of best fit
917 if (opd->FORM.Enum.SupportedValue[i].u32 < val) {
918 bestfit = opd->FORM.Enum.SupportedValue[i].u32;
921 // Just some default that'll work.
925 // Will accept any value
932 * This function returns a newly created ISO 8601 timestamp with the
933 * current time in as high precision as possible. It even adds
934 * the time zone if it can.
936 static char *get_iso8601_stamp(void)
942 curtime = time(NULL);
943 loctime = localtime(&curtime);
944 strftime (tmp, sizeof(tmp), "%Y%m%dT%H%M%S.0%z", loctime);
949 * Gets the allowed values (range or enum) for a property
950 * @param device a pointer to an MTP device
951 * @param property the property to query
952 * @param filetype the filetype of the object you want to set values for
953 * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
954 * receive the allowed values. Call LIBMTP_destroy_allowed_values_t
955 * on this on successful completion.
956 * @return 0 on success, any other value means failure
958 int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
959 LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
961 PTPObjectPropDesc opd;
964 ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
965 if (ret != PTP_RC_OK) {
966 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
970 if (opd.FormFlag == PTP_OPFF_Enumeration) {
973 allowed_vals->is_range = 0;
974 allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
976 switch (opd.DataType)
979 allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
980 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
983 allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
984 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
987 allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
988 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
991 allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
992 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
995 allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
996 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
999 allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
1000 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1003 allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
1004 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1006 case PTP_DTC_UINT64:
1007 allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
1008 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1012 for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
1013 switch (opd.DataType)
1016 allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
1019 allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
1022 allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
1024 case PTP_DTC_UINT16:
1025 allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
1028 allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
1030 case PTP_DTC_UINT32:
1031 allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
1034 allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
1036 case PTP_DTC_UINT64:
1037 allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
1041 ptp_free_objectpropdesc(&opd);
1043 } else if (opd.FormFlag == PTP_OPFF_Range) {
1044 allowed_vals->is_range = 1;
1046 switch (opd.DataType)
1049 allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
1050 allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
1051 allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
1052 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
1055 allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
1056 allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
1057 allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
1058 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
1061 allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
1062 allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
1063 allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
1064 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
1066 case PTP_DTC_UINT16:
1067 allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
1068 allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
1069 allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
1070 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
1073 allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
1074 allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
1075 allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
1076 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1078 case PTP_DTC_UINT32:
1079 allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
1080 allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
1081 allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
1082 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1085 allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
1086 allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
1087 allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
1088 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1090 case PTP_DTC_UINT64:
1091 allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
1092 allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
1093 allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
1094 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1103 * Destroys a LIBMTP_allowed_values_t struct
1104 * @param allowed_vals the struct to destroy
1106 void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
1108 if (!allowed_vals->is_range)
1110 switch (allowed_vals->datatype)
1112 case LIBMTP_DATATYPE_INT8:
1113 if (allowed_vals->i8vals)
1114 free(allowed_vals->i8vals);
1116 case LIBMTP_DATATYPE_UINT8:
1117 if (allowed_vals->u8vals)
1118 free(allowed_vals->u8vals);
1120 case LIBMTP_DATATYPE_INT16:
1121 if (allowed_vals->i16vals)
1122 free(allowed_vals->i16vals);
1124 case LIBMTP_DATATYPE_UINT16:
1125 if (allowed_vals->u16vals)
1126 free(allowed_vals->u16vals);
1128 case LIBMTP_DATATYPE_INT32:
1129 if (allowed_vals->i32vals)
1130 free(allowed_vals->i32vals);
1132 case LIBMTP_DATATYPE_UINT32:
1133 if (allowed_vals->u32vals)
1134 free(allowed_vals->u32vals);
1136 case LIBMTP_DATATYPE_INT64:
1137 if (allowed_vals->i64vals)
1138 free(allowed_vals->i64vals);
1140 case LIBMTP_DATATYPE_UINT64:
1141 if (allowed_vals->u64vals)
1142 free(allowed_vals->u64vals);
1149 * Determine if a property is supported for a given file type
1150 * @param device a pointer to an MTP device
1151 * @param property the property to query
1152 * @param filetype the filetype of the object you want to set values for
1153 * @return 0 if not supported, positive if supported, negative on error
1155 int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
1156 LIBMTP_filetype_t const filetype)
1158 uint16_t *props = NULL;
1159 uint32_t propcnt = 0;
1163 uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
1165 if (!ptp_operation_issupported(device->params, PTP_OC_MTP_GetObjectPropsSupported))
1168 ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
1169 if (ret != PTP_RC_OK) {
1170 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
1174 for (i = 0; i < propcnt; i++) {
1175 if (props[i] == ptp_prop) {
1187 * Retrieves a string from an object
1189 * @param device a pointer to an MTP device.
1190 * @param object_id Object reference
1191 * @param attribute_id MTP attribute ID
1192 * @return valid string or NULL on failure. The returned string
1193 * must bee <code>free()</code>:ed by the caller after
1196 char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1197 LIBMTP_property_t const attribute_id)
1199 return get_string_from_object(device, object_id, attribute_id);
1203 * Retrieves an unsigned 64-bit integer from an object attribute
1205 * @param device a pointer to an MTP device.
1206 * @param object_id Object reference
1207 * @param attribute_id MTP attribute ID
1208 * @param value_default Default value to return on failure
1211 uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1212 LIBMTP_property_t const attribute_id, uint64_t const value_default)
1214 return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1218 * Retrieves an unsigned 32-bit integer from an object attribute
1220 * @param device a pointer to an MTP device.
1221 * @param object_id Object reference
1222 * @param attribute_id MTP attribute ID
1223 * @param value_default Default value to return on failure
1226 uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1227 LIBMTP_property_t const attribute_id, uint32_t const value_default)
1229 return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1233 * Retrieves an unsigned 16-bit integer from an object attribute
1235 * @param device a pointer to an MTP device.
1236 * @param object_id Object reference
1237 * @param attribute_id MTP attribute ID
1238 * @param value_default Default value to return on failure
1241 uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1242 LIBMTP_property_t const attribute_id, uint16_t const value_default)
1244 return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1248 * Retrieves an unsigned 8-bit integer from an object attribute
1250 * @param device a pointer to an MTP device.
1251 * @param object_id Object reference
1252 * @param attribute_id MTP attribute ID
1253 * @param value_default Default value to return on failure
1256 uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1257 LIBMTP_property_t const attribute_id, uint8_t const value_default)
1259 return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1263 * Sets an object attribute from a string
1265 * @param device a pointer to an MTP device.
1266 * @param object_id Object reference
1267 * @param attribute_id MTP attribute ID
1268 * @param string string value to set
1269 * @return 0 on success, any other value means failure
1271 int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1272 LIBMTP_property_t const attribute_id, char const * const string)
1274 return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
1279 * Sets an object attribute from an unsigned 32-bit integer
1281 * @param device a pointer to an MTP device.
1282 * @param object_id Object reference
1283 * @param attribute_id MTP attribute ID
1284 * @param value 32-bit unsigned integer to set
1285 * @return 0 on success, any other value means failure
1287 int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1288 LIBMTP_property_t const attribute_id, uint32_t const value)
1290 return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1294 * Sets an object attribute from an unsigned 16-bit integer
1296 * @param device a pointer to an MTP device.
1297 * @param object_id Object reference
1298 * @param attribute_id MTP attribute ID
1299 * @param value 16-bit unsigned integer to set
1300 * @return 0 on success, any other value means failure
1302 int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1303 LIBMTP_property_t const attribute_id, uint16_t const value)
1305 return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1309 * Sets an object attribute from an unsigned 8-bit integer
1311 * @param device a pointer to an MTP device.
1312 * @param object_id Object reference
1313 * @param attribute_id MTP attribute ID
1314 * @param value 8-bit unsigned integer to set
1315 * @return 0 on success, any other value means failure
1317 int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1318 LIBMTP_property_t const attribute_id, uint8_t const value)
1320 return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1324 * Retrieves a string from an object
1326 * @param device a pointer to an MTP device.
1327 * @param object_id Object reference
1328 * @param attribute_id PTP attribute ID
1329 * @return valid string or NULL on failure. The returned string
1330 * must bee <code>free()</code>:ed by the caller after
1333 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1334 uint16_t const attribute_id)
1336 PTPPropertyValue propval;
1337 char *retstring = NULL;
1340 MTPProperties *prop;
1342 if (!device || !object_id)
1345 params = (PTPParams *) device->params;
1347 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1349 if (prop->propval.str != NULL)
1350 return strdup(prop->propval.str);
1355 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1356 if (ret == PTP_RC_OK) {
1357 if (propval.str != NULL) {
1358 retstring = (char *) strdup(propval.str);
1362 add_ptp_error_to_errorstack(device, ret, "get_string_from_object(): could not get object string.");
1369 * Retrieves an unsigned 64-bit integer from an object attribute
1371 * @param device a pointer to an MTP device.
1372 * @param object_id Object reference
1373 * @param attribute_id PTP attribute ID
1374 * @param value_default Default value to return on failure
1377 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1378 uint16_t const attribute_id, uint64_t const value_default)
1380 PTPPropertyValue propval;
1381 uint64_t retval = value_default;
1384 MTPProperties *prop;
1387 return value_default;
1389 params = (PTPParams *) device->params;
1391 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1393 return prop->propval.u64;
1395 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1399 if (ret == PTP_RC_OK) {
1400 retval = propval.u64;
1402 add_ptp_error_to_errorstack(device, ret, "get_u64_from_object(): could not get unsigned 64bit integer from object.");
1409 * Retrieves an unsigned 32-bit integer from an object attribute
1411 * @param device a pointer to an MTP device.
1412 * @param object_id Object reference
1413 * @param attribute_id PTP attribute ID
1414 * @param value_default Default value to return on failure
1417 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1418 uint16_t const attribute_id, uint32_t const value_default)
1420 PTPPropertyValue propval;
1421 uint32_t retval = value_default;
1424 MTPProperties *prop;
1427 return value_default;
1429 params = (PTPParams *) device->params;
1431 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1433 return prop->propval.u32;
1435 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1439 if (ret == PTP_RC_OK) {
1440 retval = propval.u32;
1442 add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
1448 * Retrieves an unsigned 16-bit integer from an object attribute
1450 * @param device a pointer to an MTP device.
1451 * @param object_id Object reference
1452 * @param attribute_id PTP attribute ID
1453 * @param value_default Default value to return on failure
1456 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1457 uint16_t const attribute_id, uint16_t const value_default)
1459 PTPPropertyValue propval;
1460 uint16_t retval = value_default;
1463 MTPProperties *prop;
1466 return value_default;
1468 params = (PTPParams *) device->params;
1470 // This O(n) search should not be used so often, since code
1471 // using the cached properties don't usually call this function.
1472 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1474 return prop->propval.u16;
1476 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1480 if (ret == PTP_RC_OK) {
1481 retval = propval.u16;
1483 add_ptp_error_to_errorstack(device, ret, "get_u16_from_object(): could not get unsigned 16bit integer from object.");
1490 * Retrieves an unsigned 8-bit integer from an object attribute
1492 * @param device a pointer to an MTP device.
1493 * @param object_id Object reference
1494 * @param attribute_id PTP attribute ID
1495 * @param value_default Default value to return on failure
1498 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1499 uint16_t const attribute_id, uint8_t const value_default)
1501 PTPPropertyValue propval;
1502 uint8_t retval = value_default;
1505 MTPProperties *prop;
1508 return value_default;
1510 params = (PTPParams *) device->params;
1512 // This O(n) search should not be used so often, since code
1513 // using the cached properties don't usually call this function.
1514 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1516 return prop->propval.u8;
1518 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1522 if (ret == PTP_RC_OK) {
1523 retval = propval.u8;
1525 add_ptp_error_to_errorstack(device, ret, "get_u8_from_object(): could not get unsigned 8bit integer from object.");
1532 * Sets an object attribute from a string
1534 * @param device a pointer to an MTP device.
1535 * @param object_id Object reference
1536 * @param attribute_id PTP attribute ID
1537 * @param string string value to set
1538 * @return 0 on success, any other value means failure
1540 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1541 uint16_t const attribute_id, char const * const string)
1543 PTPPropertyValue propval;
1547 if (!device || !string)
1550 params = (PTPParams *) device->params;
1552 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1553 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_string(): could not set object string: "
1554 "PTP_OC_MTP_SetObjectPropValue not supported.");
1557 propval.str = (char *) string;
1558 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1559 if (ret != PTP_RC_OK) {
1560 add_ptp_error_to_errorstack(device, ret, "set_object_string(): could not set object string.");
1569 * Sets an object attribute from an unsigned 32-bit integer
1571 * @param device a pointer to an MTP device.
1572 * @param object_id Object reference
1573 * @param attribute_id PTP attribute ID
1574 * @param value 32-bit unsigned integer to set
1575 * @return 0 on success, any other value means failure
1577 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1578 uint16_t const attribute_id, uint32_t const value)
1580 PTPPropertyValue propval;
1587 params = (PTPParams *) device->params;
1589 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1590 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u32(): could not set unsigned 32bit integer property: "
1591 "PTP_OC_MTP_SetObjectPropValue not supported.");
1595 propval.u32 = value;
1596 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
1597 if (ret != PTP_RC_OK) {
1598 add_ptp_error_to_errorstack(device, ret, "set_object_u32(): could not set unsigned 32bit integer property.");
1606 * Sets an object attribute from an unsigned 16-bit integer
1608 * @param device a pointer to an MTP device.
1609 * @param object_id Object reference
1610 * @param attribute_id PTP attribute ID
1611 * @param value 16-bit unsigned integer to set
1612 * @return 0 on success, any other value means failure
1614 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1615 uint16_t const attribute_id, uint16_t const value)
1617 PTPPropertyValue propval;
1624 params = (PTPParams *) device->params;
1626 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1627 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u16(): could not set unsigned 16bit integer property: "
1628 "PTP_OC_MTP_SetObjectPropValue not supported.");
1631 propval.u16 = value;
1632 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
1633 if (ret != PTP_RC_OK) {
1634 add_ptp_error_to_errorstack(device, ret, "set_object_u16(): could not set unsigned 16bit integer property.");
1642 * Sets an object attribute from an unsigned 8-bit integer
1644 * @param device a pointer to an MTP device.
1645 * @param object_id Object reference
1646 * @param attribute_id PTP attribute ID
1647 * @param value 8-bit unsigned integer to set
1648 * @return 0 on success, any other value means failure
1650 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1651 uint16_t const attribute_id, uint8_t const value)
1653 PTPPropertyValue propval;
1660 params = (PTPParams *) device->params;
1662 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1663 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u8(): could not set unsigned 8bit integer property: "
1664 "PTP_OC_MTP_SetObjectPropValue not supported.");
1668 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
1669 if (ret != PTP_RC_OK) {
1670 add_ptp_error_to_errorstack(device, ret, "set_object_u8(): could not set unsigned 8bit integer property.");
1678 * Get the first (as in "first in the list of") connected MTP device.
1679 * @return a device pointer.
1680 * @see LIBMTP_Get_Connected_Devices()
1682 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1684 LIBMTP_mtpdevice_t *first_device = NULL;
1685 LIBMTP_raw_device_t *devices;
1687 LIBMTP_error_number_t ret;
1689 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1690 if (ret != LIBMTP_ERROR_NONE) {
1695 if (devices == NULL) {
1705 #else /* TIZEN_EXT */
1706 if (devices == NULL || numdevs == 0) {
1709 #endif /* TIZEN_EXT */
1711 first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1713 return first_device;
1717 * Overriding debug function.
1718 * This way we can disable debug prints.
1722 __attribute__((__format__(printf,2,0)))
1724 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1726 if ((LIBMTP_debug & LIBMTP_DEBUG_PTP) != 0) {
1727 vfprintf (stderr, format, args);
1728 fprintf (stderr, "\n");
1734 * Overriding error function.
1735 * This way we can capture all error etc to our errorstack.
1739 __attribute__((__format__(printf,2,0)))
1741 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1743 // if (data == NULL) {
1744 vfprintf (stderr, format, args);
1747 FIXME: find out how we shall get the device here.
1749 PTP_USB *ptp_usb = data;
1750 LIBMTP_mtpdevice_t *device = ...;
1753 vsnprintf (buf, sizeof (buf), format, args);
1754 add_error_to_errorstack(device,
1755 LIBMTP_ERROR_PTP_LAYER,
1762 * Parses the extension descriptor, there may be stuff in
1763 * this that we want to know about.
1765 static void parse_extension_descriptor(LIBMTP_mtpdevice_t *mtpdevice,
1771 /* NULL on Canon A70 */
1775 /* descriptors are divided by semicolons */
1776 while (end < strlen(desc)) {
1777 /* Skip past initial whitespace */
1778 while ((end < strlen(desc)) && (desc[start] == ' ' )) {
1782 /* Detect extension */
1783 while ((end < strlen(desc)) && (desc[end] != ';'))
1785 if (end < strlen(desc)) {
1786 char *element = strndup(desc + start, end-start);
1789 // printf(" Element: \"%s\"\n", element);
1791 /* Parse for an extension */
1792 while ((i < strlen(element)) && (element[i] != ':'))
1794 if (i < strlen(element)) {
1795 char *name = strndup(element, i);
1797 // printf(" Extension: \"%s\"\n", name);
1799 /* Parse for minor/major punctuation mark for this extension */
1800 while ((i < strlen(element)) && (element[i] != '.'))
1802 if (i > majstart && i < strlen(element)) {
1803 LIBMTP_device_extension_t *extension;
1806 char *majorstr = strndup(element + majstart, i - majstart);
1807 char *minorstr = strndup(element + i + 1, strlen(element) - i - 1);
1808 major = atoi(majorstr);
1809 minor = atoi(minorstr);
1810 // printf(" Major: \"%s\" (parsed %d) Minor: \"%s\" (parsed %d)\n",
1811 // majorstr, major, minorstr, minor);
1814 extension = malloc(sizeof(LIBMTP_device_extension_t));
1815 if (extension != NULL) {
1816 extension->name = name;
1817 extension->major = major;
1818 extension->minor = minor;
1819 extension->next = NULL;
1821 if (mtpdevice->extensions == NULL) {
1822 mtpdevice->extensions = extension;
1824 LIBMTP_device_extension_t *tmp = mtpdevice->extensions;
1825 while (tmp->next != NULL)
1827 tmp->next = extension;
1830 LIBMTP_ERROR("LIBMTP ERROR: couldnt parse extension %s\n",
1843 * This function opens a device from a raw device. It is the
1844 * preferred way to access devices in the new interface where
1845 * several devices can come and go as the library is working
1846 * on a certain device.
1847 * @param rawdevice the raw device to open a "real" device for.
1848 * @return an open device.
1850 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevice)
1852 LIBMTP_mtpdevice_t *mtp_device;
1854 PTPParams *current_params;
1856 LIBMTP_error_number_t err;
1859 /* Allocate dynamic space for our device */
1860 mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1861 /* Check if there was a memory allocation error */
1862 if(mtp_device == NULL) {
1863 /* There has been an memory allocation error. We are going to ignore this
1864 device and attempt to continue */
1866 /* TODO: This error statement could probably be a bit more robust */
1867 LIBMTP_ERROR("LIBMTP PANIC: connect_usb_devices encountered a memory "
1868 "allocation error with device %d on bus %d, trying to continue",
1869 rawdevice->devnum, rawdevice->bus_location);
1873 memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1874 // Non-cached by default
1875 mtp_device->cached = 0;
1877 /* Create PTP params */
1878 current_params = (PTPParams *) malloc(sizeof(PTPParams));
1879 if (current_params == NULL) {
1883 memset(current_params, 0, sizeof(PTPParams));
1884 current_params->device_flags = rawdevice->device_entry.device_flags;
1885 current_params->nrofobjects = 0;
1886 current_params->objects = NULL;
1887 current_params->response_packet_size = 0;
1888 current_params->response_packet = NULL;
1889 /* This will be a pointer to PTP_USB later */
1890 current_params->data = NULL;
1891 /* Set upp local debug and error functions */
1892 current_params->debug_func = LIBMTP_ptp_debug;
1893 current_params->error_func = LIBMTP_ptp_error;
1894 /* TODO: Will this always be little endian? */
1895 current_params->byteorder = PTP_DL_LE;
1896 current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1897 current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1899 if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1900 current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1901 LIBMTP_ERROR("LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1902 "Too old stdlibc, glibc and libiconv?\n");
1903 free(current_params);
1907 mtp_device->params = current_params;
1909 /* Create usbinfo, this also opens the session */
1910 err = configure_usb_device(rawdevice,
1912 &mtp_device->usbinfo);
1913 if (err != LIBMTP_ERROR_NONE) {
1914 free(current_params);
1918 ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1919 /* Set pointer back to params */
1920 ptp_usb->params = current_params;
1922 /* Cache the device information for later use */
1923 if (ptp_getdeviceinfo(current_params,
1924 ¤t_params->deviceinfo) != PTP_RC_OK) {
1925 LIBMTP_ERROR("LIBMTP PANIC: Unable to read device information on device "
1926 "%d on bus %d, trying to continue",
1927 rawdevice->devnum, rawdevice->bus_location);
1929 /* Prevent memory leaks for this device */
1930 free(mtp_device->usbinfo);
1931 free(mtp_device->params);
1932 current_params = NULL;
1937 /* Check: if this is a PTP device, is it really tagged as MTP? */
1938 if (current_params->deviceinfo.VendorExtensionID != 0x00000006) {
1939 LIBMTP_ERROR("LIBMTP WARNING: no MTP vendor extension on device "
1941 rawdevice->devnum, rawdevice->bus_location);
1942 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionID: %08x",
1943 current_params->deviceinfo.VendorExtensionID);
1944 LIBMTP_ERROR("LIBMTP WARNING: VendorExtensionDesc: %s",
1945 current_params->deviceinfo.VendorExtensionDesc);
1946 LIBMTP_ERROR("LIBMTP WARNING: this typically means the device is PTP "
1947 "(i.e. a camera) but not an MTP device at all. "
1948 "Trying to continue anyway.");
1951 parse_extension_descriptor(mtp_device,
1952 current_params->deviceinfo.VendorExtensionDesc);
1955 * Android has a number of bugs, force-assign these bug flags
1956 * if Android is encountered. Same thing for devices we detect
1957 * as SONY NWZ Walkmen. I have no clue what "sony.net/WMFU" means
1958 * I just know only NWZs have it.
1961 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
1962 int is_microsoft_com_wpdna = 0;
1964 int is_sony_net_wmfu = 0;
1965 int is_sonyericsson_com_se = 0;
1967 /* Loop over extensions and set flags */
1968 while (tmpext != NULL) {
1969 if (!strcmp(tmpext->name, "microsoft.com/WPDNA"))
1970 is_microsoft_com_wpdna = 1;
1971 if (!strcmp(tmpext->name, "android.com"))
1973 if (!strcmp(tmpext->name, "sony.net/WMFU"))
1974 is_sony_net_wmfu = 1;
1975 if (!strcmp(tmpext->name, "sonyericsson.com/SE"))
1976 is_sonyericsson_com_se = 1;
1977 tmpext = tmpext->next;
1980 /* Check for specific stacks */
1981 if (is_microsoft_com_wpdna && is_sonyericsson_com_se && !is_android) {
1983 * The Aricent stack seems to be detected by providing WPDNA, the SonyEricsson
1984 * extension and NO Android extension.
1986 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ARICENT_BUGS;
1987 LIBMTP_INFO("Aricent MTP stack device detected, assigning default bug flags\n");
1989 else if (is_android) {
1991 * If bugs are fixed in later versions, test on tmpext->major, tmpext->minor
1993 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_ANDROID_BUGS;
1994 LIBMTP_INFO("Android device detected, assigning default bug flags\n");
1996 else if (is_sony_net_wmfu) {
1997 ptp_usb->rawdevice.device_entry.device_flags |= DEVICE_FLAGS_SONY_NWZ_BUGS;
1998 LIBMTP_INFO("SONY NWZ device detected, assigning default bug flags\n");
2003 * If the OGG or FLAC filetypes are flagged as "unknown", check
2004 * if the firmware has been updated to actually support it.
2006 if (FLAG_OGG_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_OGG) {
2009 /* This is not unknown anymore, unflag it */
2010 ptp_usb->rawdevice.device_entry.device_flags &=
2011 ~DEVICE_FLAG_OGG_IS_UNKNOWN;
2016 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
2017 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2018 if (current_params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_FLAC) {
2019 /* This is not unknown anymore, unflag it */
2020 ptp_usb->rawdevice.device_entry.device_flags &=
2021 ~DEVICE_FLAG_FLAC_IS_UNKNOWN;
2027 /* Determine if the object size supported is 32 or 64 bit wide */
2028 if (ptp_operation_issupported(current_params,PTP_OC_MTP_GetObjectPropsSupported)) {
2029 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
2030 PTPObjectPropDesc opd;
2032 if (ptp_mtp_getobjectpropdesc(current_params,
2034 current_params->deviceinfo.ImageFormats[i],
2035 &opd) != PTP_RC_OK) {
2036 LIBMTP_ERROR("LIBMTP PANIC: "
2037 "could not inspect object property descriptions!\n");
2039 if (opd.DataType == PTP_DTC_UINT32) {
2042 } else if (bs != 32) {
2043 LIBMTP_ERROR("LIBMTP PANIC: "
2044 "different objects support different object sizes!\n");
2048 } else if (opd.DataType == PTP_DTC_UINT64) {
2051 } else if (bs != 64) {
2052 LIBMTP_ERROR("LIBMTP PANIC: "
2053 "different objects support different object sizes!\n");
2058 // Ignore if other size.
2059 LIBMTP_ERROR("LIBMTP PANIC: "
2060 "awkward object size data type: %04x\n", opd.DataType);
2068 // Could not detect object bitsize, assume 32 bits
2071 mtp_device->object_bitsize = bs;
2073 /* No Errors yet for this device */
2074 mtp_device->errorstack = NULL;
2076 /* Default Max Battery Level, we will adjust this if possible */
2077 mtp_device->maximum_battery_level = 100;
2079 /* Check if device supports reading maximum battery level */
2080 if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
2081 ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
2082 PTPDevicePropDesc dpd;
2084 /* Try to read maximum battery level */
2085 if(ptp_getdevicepropdesc(current_params,
2086 PTP_DPC_BatteryLevel,
2087 &dpd) != PTP_RC_OK) {
2088 add_error_to_errorstack(mtp_device,
2089 LIBMTP_ERROR_CONNECTING,
2090 "Unable to read Maximum Battery Level for this "
2091 "device even though the device supposedly "
2092 "supports this functionality");
2095 /* TODO: is this appropriate? */
2096 /* If max battery level is 0 then leave the default, otherwise assign */
2097 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
2098 mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
2101 ptp_free_devicepropdesc(&dpd);
2104 /* Set all default folders to 0xffffffffU (root directory) */
2105 mtp_device->default_music_folder = 0xffffffffU;
2106 mtp_device->default_playlist_folder = 0xffffffffU;
2107 mtp_device->default_picture_folder = 0xffffffffU;
2108 mtp_device->default_video_folder = 0xffffffffU;
2109 mtp_device->default_organizer_folder = 0xffffffffU;
2110 mtp_device->default_zencast_folder = 0xffffffffU;
2111 mtp_device->default_album_folder = 0xffffffffU;
2112 mtp_device->default_text_folder = 0xffffffffU;
2114 /* Set initial storage information */
2115 mtp_device->storage = NULL;
2116 if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
2117 add_error_to_errorstack(mtp_device,
2118 LIBMTP_ERROR_GENERAL,
2119 "Get Storage information failed.");
2120 mtp_device->storage = NULL;
2127 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
2129 LIBMTP_mtpdevice_t *mtp_device = LIBMTP_Open_Raw_Device_Uncached(rawdevice);
2131 if (mtp_device == NULL)
2134 /* Check for MTPZ devices. */
2136 LIBMTP_device_extension_t *tmpext = mtp_device->extensions;
2138 while (tmpext != NULL) {
2139 if (!strcmp(tmpext->name, "microsoft.com/MTPZ")) {
2140 LIBMTP_INFO("MTPZ device detected. Authenticating...\n");
2141 if (PTP_RC_OK == ptp_mtpz_handshake(mtp_device->params)) {
2142 LIBMTP_INFO ("(MTPZ) Successfully authenticated with device.\n");
2144 LIBMTP_INFO ("(MTPZ) Failure - could not authenticate with device.\n");
2148 tmpext = tmpext->next;
2152 // Set up this device as cached
2153 mtp_device->cached = 1;
2155 * Then get the handles and try to locate the default folders.
2156 * This has the desired side effect of caching all handles from
2157 * the device which speeds up later operations.
2159 flush_handles(mtp_device);
2164 * To read events sent by the device, repeatedly call this function from a secondary
2165 * thread until the return value is < 0.
2167 * @param device a pointer to the MTP device to poll for events.
2168 * @param event contains a pointer to be filled in with the event retrieved if the call
2170 * @param out1 contains the param1 value from the raw event.
2171 * @return 0 on success, any other value means the polling loop shall be
2172 * terminated immediately for this session.
2174 int LIBMTP_Read_Event(LIBMTP_mtpdevice_t *device, LIBMTP_event_t *event, uint32_t *out1)
2177 * FIXME: Potential race-condition here, if client deallocs device
2178 * while we're *not* waiting for input. As we'll be waiting for
2179 * input most of the time, it's unlikely but still worth considering
2180 * for improvement. Also we cannot affect the state of the cache etc
2181 * unless we know we are the sole user on the device. A spinlock or
2182 * mutex in the LIBMTP_mtpdevice_t is needed for this to work.
2184 PTPParams *params = (PTPParams *) device->params;
2185 PTPContainer ptp_event;
2186 uint16_t ret = ptp_usb_event_wait(params, &ptp_event);
2188 uint32_t session_id;
2191 if (ret != PTP_RC_OK) {
2192 /* Device is closing down or other fatal stuff, exit thread */
2193 LIBMTP_INFO("ptp_usb_event_wait ret %u\n", ret);
2197 *event = LIBMTP_EVENT_NONE;
2199 /* Process the event */
2200 code = ptp_event.Code;
2201 session_id = ptp_event.SessionID;
2202 param1 = ptp_event.Param1;
2205 case PTP_EC_Undefined:
2206 LIBMTP_INFO("Received event PTP_EC_Undefined in session %u\n", session_id);
2208 case PTP_EC_CancelTransaction:
2209 LIBMTP_INFO("Received event PTP_EC_CancelTransaction in session %u\n", session_id);
2211 case PTP_EC_ObjectAdded:
2212 LIBMTP_INFO("Received event PTP_EC_ObjectAdded in session %u\n", session_id);
2213 *event = LIBMTP_EVENT_OBJECT_ADDED;
2216 case PTP_EC_ObjectRemoved:
2217 LIBMTP_INFO("Received event PTP_EC_ObjectRemoved in session %u\n", session_id);
2218 *event = LIBMTP_EVENT_OBJECT_REMOVED;
2221 case PTP_EC_StoreAdded:
2222 LIBMTP_INFO("Received event PTP_EC_StoreAdded in session %u\n", session_id);
2223 /* TODO: rescan storages */
2224 *event = LIBMTP_EVENT_STORE_ADDED;
2227 case PTP_EC_StoreRemoved:
2228 LIBMTP_INFO("Received event PTP_EC_StoreRemoved in session %u\n", session_id);
2229 /* TODO: rescan storages */
2230 *event = LIBMTP_EVENT_STORE_REMOVED;
2233 case PTP_EC_DevicePropChanged:
2234 LIBMTP_INFO("Received event PTP_EC_DevicePropChanged in session %u\n", session_id);
2235 /* TODO: update device properties */
2237 case PTP_EC_ObjectInfoChanged:
2238 LIBMTP_INFO("Received event PTP_EC_ObjectInfoChanged in session %u\n", session_id);
2239 /* TODO: rescan object cache or just for this one object */
2241 case PTP_EC_DeviceInfoChanged:
2242 LIBMTP_INFO("Received event PTP_EC_DeviceInfoChanged in session %u\n", session_id);
2243 /* TODO: update device info */
2245 case PTP_EC_RequestObjectTransfer:
2246 LIBMTP_INFO("Received event PTP_EC_RequestObjectTransfer in session %u\n", session_id);
2248 case PTP_EC_StoreFull:
2249 LIBMTP_INFO("Received event PTP_EC_StoreFull in session %u\n", session_id);
2251 case PTP_EC_DeviceReset:
2252 LIBMTP_INFO("Received event PTP_EC_DeviceReset in session %u\n", session_id);
2254 case PTP_EC_StorageInfoChanged :
2255 LIBMTP_INFO( "Received event PTP_EC_StorageInfoChanged in session %u\n", session_id);
2256 /* TODO: update storage info */
2258 case PTP_EC_CaptureComplete :
2259 LIBMTP_INFO( "Received event PTP_EC_CaptureComplete in session %u\n", session_id);
2261 case PTP_EC_UnreportedStatus :
2262 LIBMTP_INFO( "Received event PTP_EC_UnreportedStatus in session %u\n", session_id);
2265 LIBMTP_INFO( "Received unknown event in session %u\n", session_id);
2273 * Recursive function that adds MTP devices to a linked list
2274 * @param devices a list of raw devices to have real devices created for.
2275 * @return a device pointer to a newly created mtpdevice (used in linked
2278 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
2281 LIBMTP_mtpdevice_t *mtp_device_list = NULL;
2282 LIBMTP_mtpdevice_t *current_device = NULL;
2284 for (i=0; i < numdevs; i++) {
2285 LIBMTP_mtpdevice_t *mtp_device;
2286 mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
2288 /* On error, try next device */
2289 if (mtp_device == NULL)
2292 /* Add the device to the list */
2293 mtp_device->next = NULL;
2294 if (mtp_device_list == NULL) {
2295 mtp_device_list = current_device = mtp_device;
2297 current_device->next = mtp_device;
2298 current_device = mtp_device;
2301 return mtp_device_list;
2305 * Get the number of devices that are available in the listed device list
2306 * @param device_list Pointer to a linked list of devices
2307 * @return Number of devices in the device list device_list
2308 * @see LIBMTP_Get_Connected_Devices()
2310 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
2312 uint32_t numdevices = 0;
2313 LIBMTP_mtpdevice_t *iter;
2314 for(iter = device_list; iter != NULL; iter = iter->next)
2321 * Get the first connected MTP device node in the linked list of devices.
2322 * Currently this only provides access to USB devices
2323 * @param device_list A list of devices ready to be used by the caller. You
2324 * need to know how many there are.
2325 * @return Any error information gathered from device connections
2326 * @see LIBMTP_Number_Devices_In_List()
2328 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
2330 LIBMTP_raw_device_t *devices;
2332 LIBMTP_error_number_t ret;
2334 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
2335 if (ret != LIBMTP_ERROR_NONE) {
2336 *device_list = NULL;
2340 /* Assign linked list of devices */
2342 if (devices == NULL) {
2343 *device_list = NULL;
2344 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2351 *device_list = NULL;
2352 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2354 #else /* TIZEN_EXT */
2355 if (devices == NULL || numdevs == 0) {
2356 *device_list = NULL;
2357 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
2359 #endif /* TIZEN_EXT */
2361 *device_list = create_usb_mtp_devices(devices, numdevs);
2364 /* TODO: Add wifi device access here */
2366 /* We have found some devices but create failed */
2367 if (*device_list == NULL)
2368 return LIBMTP_ERROR_CONNECTING;
2370 return LIBMTP_ERROR_NONE;
2374 * This closes and releases an allocated MTP device.
2375 * @param device a pointer to the MTP device to release.
2377 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
2381 if(device->next != NULL)
2383 LIBMTP_Release_Device_List(device->next);
2386 LIBMTP_Release_Device(device);
2391 * This closes and releases an allocated MTP device.
2392 * @param device a pointer to the MTP device to release.
2394 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
2396 PTPParams *params = (PTPParams *) device->params;
2397 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2399 close_device(ptp_usb, params);
2400 // Clear error stack
2401 LIBMTP_Clear_Errorstack(device);
2402 // Free iconv() converters...
2403 iconv_close(params->cd_locale_to_ucs2);
2404 iconv_close(params->cd_ucs2_to_locale);
2406 ptp_free_params(params);
2408 free_storage_list(device);
2409 // Free extension list...
2410 if (device->extensions != NULL) {
2411 LIBMTP_device_extension_t *tmp = device->extensions;
2413 while (tmp != NULL) {
2414 LIBMTP_device_extension_t *next = tmp->next;
2426 * This can be used by any libmtp-intrinsic code that
2427 * need to stack up an error on the stack. You are only
2428 * supposed to add errors to the error stack using this
2429 * function, do not create and reference error entries
2432 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2433 LIBMTP_error_number_t errornumber,
2434 char const * const error_text)
2436 LIBMTP_error_t *newerror;
2438 if (device == NULL) {
2439 LIBMTP_ERROR("LIBMTP PANIC: Trying to add error to a NULL device!\n");
2442 newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2443 if (newerror != NULL) {
2444 newerror->errornumber = errornumber;
2445 newerror->error_text = strdup(error_text);
2446 newerror->next = NULL;
2448 if (device->errorstack == NULL) {
2449 device->errorstack = newerror;
2451 LIBMTP_error_t *tmp = device->errorstack;
2453 while (tmp->next != NULL) {
2456 tmp->next = newerror;
2461 * Adds an error from the PTP layer to the error stack.
2463 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2465 char const * const error_text)
2467 if (device == NULL) {
2468 LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2472 snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2473 outstr[sizeof(outstr)-1] = '\0';
2474 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2476 snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error));
2477 outstr[sizeof(outstr)-1] = '\0';
2478 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2483 * This returns the error stack for a device in case you
2484 * need to either reference the error numbers (e.g. when
2485 * creating multilingual apps with multiple-language text
2486 * representations for each error number) or when you need
2487 * to build a multi-line error text widget or something like
2488 * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2489 * to clear it when you're finished with it.
2490 * @param device a pointer to the MTP device to get the error
2492 * @return the error stack or NULL if there are no errors
2494 * @see LIBMTP_Clear_Errorstack()
2495 * @see LIBMTP_Dump_Errorstack()
2497 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2499 if (device == NULL) {
2500 LIBMTP_ERROR("LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2503 return device->errorstack;
2507 * This function clears the error stack of a device and frees
2508 * any memory used by it. Call this when you're finished with
2510 * @param device a pointer to the MTP device to clear the error
2513 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2515 if (device == NULL) {
2516 LIBMTP_ERROR("LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2518 LIBMTP_error_t *tmp = device->errorstack;
2520 while (tmp != NULL) {
2521 LIBMTP_error_t *tmp2;
2523 if (tmp->error_text != NULL) {
2524 free(tmp->error_text);
2530 device->errorstack = NULL;
2535 * This function dumps the error stack to <code>stderr</code>.
2536 * (You still have to clear the stack though.)
2537 * @param device a pointer to the MTP device to dump the error
2540 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2542 if (device == NULL) {
2543 LIBMTP_ERROR("LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2545 LIBMTP_error_t *tmp = device->errorstack;
2547 while (tmp != NULL) {
2548 if (tmp->error_text != NULL) {
2549 LIBMTP_ERROR("Error %d: %s\n", tmp->errornumber, tmp->error_text);
2551 LIBMTP_ERROR("Error %d: (unknown)\n", tmp->errornumber);
2559 * This command gets all handles and stuff by FAST directory retrieveal
2560 * which is available by getting all metadata for object
2561 * <code>0xffffffff</code> which simply means "all metadata for all objects".
2562 * This works on the vast majority of MTP devices (there ARE exceptions!)
2563 * and is quite quick. Check the error stack to see if there were
2564 * problems getting the metadata.
2565 * @return 0 if all was OK, -1 on failure.
2567 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device)
2569 PTPParams *params = (PTPParams *) device->params;
2571 int i, j, nrofprops;
2572 uint32_t lasthandle = 0xffffffff;
2573 MTPProperties *props = NULL;
2574 MTPProperties *prop;
2577 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2580 * The follow request causes the device to generate
2581 * a list of every file on the device and return it
2582 * in a single response.
2584 * Some slow devices as well as devices with very
2585 * large file systems can easily take longer then
2586 * the standard timeout value before it is able
2587 * to return a response.
2589 * Temporarly set timeout to allow working with
2590 * widest range of devices.
2592 get_usb_device_timeout(ptp_usb, &oldtimeout);
2593 set_usb_device_timeout(ptp_usb, 60000);
2595 ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2596 set_usb_device_timeout(ptp_usb, oldtimeout);
2598 if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2599 // What's the point in the device implementing this command if
2600 // you cannot use it to get all props for AT LEAST one object?
2601 // Well, whatever...
2602 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2603 "cannot retrieve all metadata for an object on this device.");
2606 if (ret != PTP_RC_OK) {
2607 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2608 "could not get proplist of all objects.");
2611 if (props == NULL && nrofprops != 0) {
2612 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2613 "get_all_metadata_fast(): "
2614 "call to ptp_mtp_getobjectproplist() returned "
2615 "inconsistent results.");
2619 * We count the number of objects by counting the ObjectHandle
2620 * references, whenever it changes we get a new object, when it's
2621 * the same, it is just different properties of the same object.
2624 for (i=0;i<nrofprops;i++) {
2625 if (lasthandle != prop->ObjectHandle) {
2627 lasthandle = prop->ObjectHandle;
2631 lasthandle = 0xffffffff;
2632 params->objects = calloc (cnt, sizeof(PTPObject));
2633 if (params->objects == NULL) {
2640 for (j=0;j<nrofprops;j++) {
2641 if (lasthandle != prop->ObjectHandle) {
2643 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2644 if (!params->objects[i].oi.Filename) {
2645 /* I have one such file on my Creative (Marcus) */
2646 params->objects[i].oi.Filename = strdup("<null>");
2650 lasthandle = prop->ObjectHandle;
2651 params->objects[i].oid = prop->ObjectHandle;
2653 switch (prop->property) {
2654 case PTP_OPC_ParentObject:
2655 params->objects[i].oi.ParentObject = prop->propval.u32;
2656 params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2658 case PTP_OPC_ObjectFormat:
2659 params->objects[i].oi.ObjectFormat = prop->propval.u16;
2661 case PTP_OPC_ObjectSize:
2662 // We loose precision here, up to 32 bits! However the commands that
2663 // retrieve metadata for files and tracks will make sure that the
2664 // PTP_OPC_ObjectSize is read in and duplicated again.
2665 if (device->object_bitsize == 64) {
2666 params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2668 params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2671 case PTP_OPC_StorageID:
2672 params->objects[i].oi.StorageID = prop->propval.u32;
2673 params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2675 case PTP_OPC_ObjectFileName:
2676 if (prop->propval.str != NULL)
2677 params->objects[i].oi.Filename = strdup(prop->propval.str);
2680 MTPProperties *newprops;
2682 /* Copy all of the other MTP oprierties into the per-object proplist */
2683 if (params->objects[i].nrofmtpprops) {
2684 newprops = realloc(params->objects[i].mtpprops,
2685 (params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2687 newprops = calloc(1,sizeof(MTPProperties));
2689 if (!newprops) return 0; /* FIXME: error handling? */
2690 params->objects[i].mtpprops = newprops;
2691 memcpy(¶ms->objects[i].mtpprops[params->objects[i].nrofmtpprops],
2692 &props[j],sizeof(props[j]));
2693 params->objects[i].nrofmtpprops++;
2694 params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2700 /* mark last entry also */
2701 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2702 params->nrofobjects = i+1;
2704 /* The device might not give the list in linear ascending order */
2705 ptp_objects_sort (params);
2710 * This function will recurse through all the directories on the device,
2711 * starting at the root directory, gathering metadata as it moves along.
2712 * It works better on some devices that will only return data for a
2713 * certain directory and does not respect the option to get all metadata
2716 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2721 PTPObjectHandles currentHandles;
2723 uint16_t ret = ptp_getobjecthandles(params,
2725 PTP_GOH_ALL_FORMATS,
2729 if (ret != PTP_RC_OK) {
2730 add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2734 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2737 // Now descend into any subdirectories found
2738 for (i = 0; i < currentHandles.n; i++) {
2740 ret = ptp_object_want(params,currentHandles.Handler[i],
2741 PTPOBJECT_OBJECTINFO_LOADED, &ob);
2742 if (ret == PTP_RC_OK) {
2743 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2744 get_handles_recursively(device, params,
2745 storageid, currentHandles.Handler[i]);
2747 add_error_to_errorstack(device,
2748 LIBMTP_ERROR_CONNECTING,
2749 "Found a bad handle, trying to ignore it.");
2752 free(currentHandles.Handler);
2756 * This function refresh the internal handle list whenever
2757 * the items stored inside the device is altered. On operations
2758 * that do not add or remove objects, this is typically not
2760 * @param device a pointer to the MTP device to flush handles for.
2762 static void flush_handles(LIBMTP_mtpdevice_t *device)
2764 PTPParams *params = (PTPParams *) device->params;
2765 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2769 if (!device->cached) {
2773 if (params->objects != NULL) {
2774 for (i=0;i<params->nrofobjects;i++)
2775 ptp_free_object (¶ms->objects[i]);
2776 free(params->objects);
2777 params->objects = NULL;
2778 params->nrofobjects = 0;
2781 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2782 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2783 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2784 // Use the fast method. Ignore return value for now.
2785 ret = get_all_metadata_fast(device);
2788 // If the previous failed or returned no objects, use classic
2790 if (params->nrofobjects == 0) {
2791 // Get all the handles using just standard commands.
2792 if (device->storage == NULL) {
2793 get_handles_recursively(device, params,
2794 PTP_GOH_ALL_STORAGE,
2795 PTP_GOH_ROOT_PARENT);
2797 // Get handles for each storage in turn.
2798 LIBMTP_devicestorage_t *storage = device->storage;
2799 while(storage != NULL) {
2800 get_handles_recursively(device, params,
2802 PTP_GOH_ROOT_PARENT);
2803 storage = storage->next;
2809 * Loop over the handles, fix up any NULL filenames or
2810 * keywords, then attempt to locate some default folders
2811 * in the root directory of the primary storage.
2813 for(i = 0; i < params->nrofobjects; i++) {
2814 PTPObject *ob, *xob;
2816 ob = ¶ms->objects[i];
2817 ret = ptp_object_want(params,params->objects[i].oid,
2818 PTPOBJECT_OBJECTINFO_LOADED, &xob);
2819 if (ret != PTP_RC_OK) {
2820 LIBMTP_ERROR("broken! %x not found\n", params->objects[i].oid);
2822 if (ob->oi.Filename == NULL)
2823 ob->oi.Filename = strdup("<null>");
2824 if (ob->oi.Keywords == NULL)
2825 ob->oi.Keywords = strdup("<null>");
2827 /* Ignore handles that point to non-folders */
2828 if(ob->oi.ObjectFormat != PTP_OFC_Association)
2830 /* Only look in the root folder */
2831 if (ob->oi.ParentObject == 0xffffffffU) {
2832 LIBMTP_ERROR("object %x has parent 0xffffffff (-1) continuing anyway\n",
2834 } else if (ob->oi.ParentObject != 0x00000000U)
2836 /* Only look in the primary storage */
2837 if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2840 /* Is this the Music Folder */
2841 if (!strcasecmp(ob->oi.Filename, "My Music") ||
2842 !strcasecmp(ob->oi.Filename, "My_Music") ||
2843 !strcasecmp(ob->oi.Filename, "Music")) {
2844 device->default_music_folder = ob->oid;
2846 else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2847 !strcasecmp(ob->oi.Filename, "My_Playlists") ||
2848 !strcasecmp(ob->oi.Filename, "Playlists")) {
2849 device->default_playlist_folder = ob->oid;
2851 else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2852 !strcasecmp(ob->oi.Filename, "My_Pictures") ||
2853 !strcasecmp(ob->oi.Filename, "Pictures")) {
2854 device->default_picture_folder = ob->oid;
2856 else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2857 !strcasecmp(ob->oi.Filename, "My_Video") ||
2858 !strcasecmp(ob->oi.Filename, "Video")) {
2859 device->default_video_folder = ob->oid;
2861 else if (!strcasecmp(ob->oi.Filename, "My Organizer") ||
2862 !strcasecmp(ob->oi.Filename, "My_Organizer")) {
2863 device->default_organizer_folder = ob->oid;
2865 else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2866 !strcasecmp(ob->oi.Filename, "Datacasts")) {
2867 device->default_zencast_folder = ob->oid;
2869 else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2870 !strcasecmp(ob->oi.Filename, "My_Albums") ||
2871 !strcasecmp(ob->oi.Filename, "Albums")) {
2872 device->default_album_folder = ob->oid;
2874 else if (!strcasecmp(ob->oi.Filename, "Text") ||
2875 !strcasecmp(ob->oi.Filename, "Texts")) {
2876 device->default_text_folder = ob->oid;
2882 * This function traverses a devices storage list freeing up the
2883 * strings and the structs.
2884 * @param device a pointer to the MTP device to free the storage
2887 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2889 LIBMTP_devicestorage_t *storage;
2890 LIBMTP_devicestorage_t *tmp;
2892 storage = device->storage;
2893 while(storage != NULL) {
2894 if (storage->StorageDescription != NULL) {
2895 free(storage->StorageDescription);
2897 if (storage->VolumeIdentifier != NULL) {
2898 free(storage->VolumeIdentifier);
2901 storage = storage->next;
2904 device->storage = NULL;
2910 * This function traverses a devices storage list freeing up the
2911 * strings and the structs.
2912 * @param device a pointer to the MTP device to free the storage
2915 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2917 LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2919 if (device->storage == NULL)
2921 if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2924 oldhead = ptr1 = ptr2 = device->storage;
2928 while(oldhead != NULL) {
2929 ptr1 = ptr2 = oldhead;
2930 while(ptr1 != NULL) {
2932 if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2934 if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2940 // Make our previous entries next point to our next
2941 if(ptr2->prev != NULL) {
2943 ptr1->next = ptr2->next;
2945 oldhead = ptr2->next;
2947 oldhead->prev = NULL;
2950 // Make our next entries previous point to our previous
2953 ptr1->prev = ptr2->prev;
2960 if(newlist == NULL) {
2962 newlist->prev = NULL;
2964 ptr2->prev = newlist;
2965 newlist->next = ptr2;
2966 newlist = newlist->next;
2970 if (newlist != NULL) {
2971 newlist->next = NULL;
2972 while(newlist->prev != NULL)
2973 newlist = newlist->prev;
2974 device->storage = newlist;
2981 * This function grabs the first writeable storageid from the
2982 * device storage list.
2983 * @param device a pointer to the MTP device to locate writeable
2985 * @param fitsize a file of this file must fit on the device.
2987 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device,
2990 LIBMTP_devicestorage_t *storage;
2991 uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
2994 // See if there is some storage we can fit this file on.
2995 storage = device->storage;
2996 if (storage == NULL) {
2997 // Sometimes the storage just cannot be detected.
2998 store = 0x00000000U;
3000 while(storage != NULL) {
3001 // These storages cannot be used.
3002 if (storage->StorageType == PTP_ST_FixedROM ||
3003 storage->StorageType == PTP_ST_RemovableROM) {
3004 storage = storage->next;
3007 // Storage IDs with the lower 16 bits 0x0000 are not supposed
3009 if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
3010 storage = storage->next;
3013 // Also check the access capability to avoid e.g. deletable only storages
3014 if (storage->AccessCapability == PTP_AC_ReadOnly ||
3015 storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
3016 storage = storage->next;
3019 // Then see if we can fit the file.
3020 subcall_ret = check_if_file_fits(device, storage, fitsize);
3021 if (subcall_ret != 0) {
3022 storage = storage->next;
3024 // We found a storage that is writable and can fit the file!
3028 if (storage == NULL) {
3029 add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL,
3030 "get_writeable_storageid(): "
3031 "all device storage is full or corrupt.");
3034 store = storage->id;
3041 * Tries to suggest a storage_id of a given ID when we have a parent
3042 * @param device a pointer to the device where to search for the storage ID
3043 * @param fitsize a file of this file must fit on the device.
3044 * @param parent_id look for this ID
3047 static int get_suggested_storage_id(LIBMTP_mtpdevice_t *device,
3051 PTPParams *params = (PTPParams *) device->params;
3055 ret = ptp_object_want(params, parent_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
3056 if ((ret != PTP_RC_OK) || (ob->oi.StorageID == 0)) {
3057 add_ptp_error_to_errorstack(device, ret, "get_suggested_storage_id(): "
3058 "could not get storage id from parent id.");
3059 return get_writeable_storageid(device, fitsize);
3061 /* OK we know the parent storage, then use that */
3062 return ob->oi.StorageID;
3067 * This function grabs the freespace from a certain storage in
3068 * device storage list.
3069 * @param device a pointer to the MTP device to free the storage
3071 * @param storageid the storage ID for the storage to flush and
3072 * get free space for.
3073 * @param freespace the free space on this storage will be returned
3076 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
3077 LIBMTP_devicestorage_t *storage,
3078 uint64_t *freespace)
3080 PTPParams *params = (PTPParams *) device->params;
3082 // Always query the device about this, since some models explicitly
3083 // needs that. We flush all data on queries storage here.
3084 if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3085 PTPStorageInfo storageInfo;
3088 ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
3089 if (ret != PTP_RC_OK) {
3090 add_ptp_error_to_errorstack(device, ret,
3091 "get_storage_freespace(): could not get storage info.");
3094 if (storage->StorageDescription != NULL) {
3095 free(storage->StorageDescription);
3097 if (storage->VolumeIdentifier != NULL) {
3098 free(storage->VolumeIdentifier);
3100 storage->StorageType = storageInfo.StorageType;
3101 storage->FilesystemType = storageInfo.FilesystemType;
3102 storage->AccessCapability = storageInfo.AccessCapability;
3103 storage->MaxCapacity = storageInfo.MaxCapability;
3104 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3105 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3106 storage->StorageDescription = storageInfo.StorageDescription;
3107 storage->VolumeIdentifier = storageInfo.VolumeLabel;
3109 if(storage->FreeSpaceInBytes == (uint64_t) -1)
3111 *freespace = storage->FreeSpaceInBytes;
3116 * This function dumps out a large chunk of textual information
3117 * provided from the PTP protocol and additionally some extra
3118 * MTP-specific information where applicable.
3119 * @param device a pointer to the MTP device to report info from.
3121 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
3124 PTPParams *params = (PTPParams *) device->params;
3125 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3126 LIBMTP_devicestorage_t *storage = device->storage;
3127 LIBMTP_device_extension_t *tmpext = device->extensions;
3129 printf("USB low-level info:\n");
3130 dump_usbinfo(ptp_usb);
3131 /* Print out some verbose information */
3132 printf("Device info:\n");
3133 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
3134 printf(" Model: %s\n", params->deviceinfo.Model);
3135 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
3136 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
3137 printf(" Vendor extension ID: 0x%08x\n",
3138 params->deviceinfo.VendorExtensionID);
3139 printf(" Vendor extension description: %s\n",
3140 params->deviceinfo.VendorExtensionDesc);
3141 printf(" Detected object size: %d bits\n",
3142 device->object_bitsize);
3143 printf(" Extensions:\n");
3144 while (tmpext != NULL) {
3145 printf(" %s: %d.%d\n",
3149 tmpext = tmpext->next;
3151 LIBMTP_INFO("Supported operations:");
3152 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
3155 (void) ptp_render_opcode(params, params->deviceinfo.OperationsSupported[i],
3157 LIBMTP_INFO(" %04x: %s", params->deviceinfo.OperationsSupported[i], txt);
3159 LIBMTP_INFO("Events supported:\n");
3160 if (params->deviceinfo.EventsSupported_len == 0) {
3161 LIBMTP_INFO(" None.\n");
3163 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
3164 LIBMTP_INFO(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
3167 LIBMTP_INFO("Device Properties Supported:\n");
3168 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
3169 char const *propdesc = ptp_get_property_description(params,
3170 params->deviceinfo.DevicePropertiesSupported[i]);
3172 if (propdesc != NULL) {
3173 LIBMTP_INFO(" 0x%04x: %s\n",
3174 params->deviceinfo.DevicePropertiesSupported[i], propdesc);
3176 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
3177 LIBMTP_INFO(" 0x%04x: Unknown property\n", prop);
3181 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
3182 printf("Playable File (Object) Types and Object Properties Supported:\n");
3183 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3186 uint16_t *props = NULL;
3187 uint32_t propcnt = 0;
3190 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i],
3192 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
3194 ret = ptp_mtp_getobjectpropssupported (params,
3195 params->deviceinfo.ImageFormats[i], &propcnt, &props);
3196 if (ret != PTP_RC_OK) {
3197 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): "
3198 "error on query for object properties.");
3200 for (j=0;j<propcnt;j++) {
3201 PTPObjectPropDesc opd;
3204 printf(" %04x: %s", props[j],
3205 LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
3206 // Get a more verbose description
3207 ret = ptp_mtp_getobjectpropdesc(params, props[j],
3208 params->deviceinfo.ImageFormats[i],
3210 if (ret != PTP_RC_OK) {
3211 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3212 "LIBMTP_Dump_Device_Info(): "
3213 "could not get property description.");
3217 if (opd.DataType == PTP_DTC_STR) {
3218 printf(" STRING data type");
3219 switch (opd.FormFlag) {
3220 case PTP_OPFF_DateTime:
3221 printf(" DATETIME FORM");
3223 case PTP_OPFF_RegularExpression:
3224 printf(" REGULAR EXPRESSION FORM");
3226 case PTP_OPFF_LongString:
3227 printf(" LONG STRING FORM");
3233 if (opd.DataType & PTP_DTC_ARRAY_MASK) {
3234 printf(" array of");
3237 switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
3240 printf(" UNDEFINED data type");
3243 printf(" INT8 data type");
3244 switch (opd.FormFlag) {
3245 case PTP_OPFF_Range:
3246 printf(" range: MIN %d, MAX %d, STEP %d",
3247 opd.FORM.Range.MinimumValue.i8,
3248 opd.FORM.Range.MaximumValue.i8,
3249 opd.FORM.Range.StepSize.i8);
3251 case PTP_OPFF_Enumeration:
3252 printf(" enumeration: ");
3253 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3254 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
3257 case PTP_OPFF_ByteArray:
3258 printf(" byte array: ");
3261 printf(" ANY 8BIT VALUE form");
3267 printf(" UINT8 data type");
3268 switch (opd.FormFlag) {
3269 case PTP_OPFF_Range:
3270 printf(" range: MIN %d, MAX %d, STEP %d",
3271 opd.FORM.Range.MinimumValue.u8,
3272 opd.FORM.Range.MaximumValue.u8,
3273 opd.FORM.Range.StepSize.u8);
3275 case PTP_OPFF_Enumeration:
3276 printf(" enumeration: ");
3277 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3278 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
3281 case PTP_OPFF_ByteArray:
3282 printf(" byte array: ");
3285 printf(" ANY 8BIT VALUE form");
3291 printf(" INT16 data type");
3292 switch (opd.FormFlag) {
3293 case PTP_OPFF_Range:
3294 printf(" range: MIN %d, MAX %d, STEP %d",
3295 opd.FORM.Range.MinimumValue.i16,
3296 opd.FORM.Range.MaximumValue.i16,
3297 opd.FORM.Range.StepSize.i16);
3299 case PTP_OPFF_Enumeration:
3300 printf(" enumeration: ");
3301 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3302 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3306 printf(" ANY 16BIT VALUE form");
3311 case PTP_DTC_UINT16:
3312 printf(" UINT16 data type");
3313 switch (opd.FormFlag) {
3314 case PTP_OPFF_Range:
3315 printf(" range: MIN %d, MAX %d, STEP %d",
3316 opd.FORM.Range.MinimumValue.u16,
3317 opd.FORM.Range.MaximumValue.u16,
3318 opd.FORM.Range.StepSize.u16);
3320 case PTP_OPFF_Enumeration:
3321 printf(" enumeration: ");
3322 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3323 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3327 printf(" ANY 16BIT VALUE form");
3333 printf(" INT32 data type");
3334 switch (opd.FormFlag) {
3335 case PTP_OPFF_Range:
3336 printf(" range: MIN %d, MAX %d, STEP %d",
3337 opd.FORM.Range.MinimumValue.i32,
3338 opd.FORM.Range.MaximumValue.i32,
3339 opd.FORM.Range.StepSize.i32);
3341 case PTP_OPFF_Enumeration:
3342 printf(" enumeration: ");
3343 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3344 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3348 printf(" ANY 32BIT VALUE form");
3353 case PTP_DTC_UINT32:
3354 printf(" UINT32 data type");
3355 switch (opd.FormFlag) {
3356 case PTP_OPFF_Range:
3357 printf(" range: MIN %d, MAX %d, STEP %d",
3358 opd.FORM.Range.MinimumValue.u32,
3359 opd.FORM.Range.MaximumValue.u32,
3360 opd.FORM.Range.StepSize.u32);
3362 case PTP_OPFF_Enumeration:
3363 // Special pretty-print for FOURCC codes
3364 if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3365 printf(" enumeration of u32 casted FOURCC: ");
3366 for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3367 if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3371 fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3372 fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3373 fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3374 fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3377 printf("\"%s\", ", fourcc);
3381 printf(" enumeration: ");
3382 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3383 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3388 printf(" ANY 32BIT VALUE form");
3394 printf(" INT64 data type");
3397 case PTP_DTC_UINT64:
3398 printf(" UINT64 data type");
3401 case PTP_DTC_INT128:
3402 printf(" INT128 data type");
3405 case PTP_DTC_UINT128:
3406 printf(" UINT128 data type");
3410 printf(" UNKNOWN data type");
3417 printf(" READ ONLY");
3420 ptp_free_objectpropdesc(&opd);
3427 if(storage != NULL &&
3428 ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3429 printf("Storage Devices:\n");
3430 while(storage != NULL) {
3431 printf(" StorageID: 0x%08x\n",storage->id);
3432 printf(" StorageType: 0x%04x ",storage->StorageType);
3433 switch (storage->StorageType) {
3434 case PTP_ST_Undefined:
3435 printf("(undefined)\n");
3437 case PTP_ST_FixedROM:
3438 printf("fixed ROM storage\n");
3440 case PTP_ST_RemovableROM:
3441 printf("removable ROM storage\n");
3443 case PTP_ST_FixedRAM:
3444 printf("fixed RAM storage\n");
3446 case PTP_ST_RemovableRAM:
3447 printf("removable RAM storage\n");
3450 printf("UNKNOWN storage\n");
3453 printf(" FilesystemType: 0x%04x ",storage->FilesystemType);
3454 switch(storage->FilesystemType) {
3455 case PTP_FST_Undefined:
3456 printf("(undefined)\n");
3458 case PTP_FST_GenericFlat:
3459 printf("generic flat filesystem\n");
3461 case PTP_FST_GenericHierarchical:
3462 printf("generic hierarchical\n");
3468 printf("UNKNONWN filesystem type\n");
3471 printf(" AccessCapability: 0x%04x ",storage->AccessCapability);
3472 switch(storage->AccessCapability) {
3473 case PTP_AC_ReadWrite:
3474 printf("read/write\n");
3476 case PTP_AC_ReadOnly:
3477 printf("read only\n");
3479 case PTP_AC_ReadOnly_with_Object_Deletion:
3480 printf("read only + object deletion\n");
3483 printf("UNKNOWN access capability\n");
3486 printf(" MaxCapacity: %llu\n",
3487 (long long unsigned int) storage->MaxCapacity);
3488 printf(" FreeSpaceInBytes: %llu\n",
3489 (long long unsigned int) storage->FreeSpaceInBytes);
3490 printf(" FreeSpaceInObjects: %llu\n",
3491 (long long unsigned int) storage->FreeSpaceInObjects);
3492 printf(" StorageDescription: %s\n",storage->StorageDescription);
3493 printf(" VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3494 storage = storage->next;
3498 printf("Special directories:\n");
3499 printf(" Default music folder: 0x%08x\n",
3500 device->default_music_folder);
3501 printf(" Default playlist folder: 0x%08x\n",
3502 device->default_playlist_folder);
3503 printf(" Default picture folder: 0x%08x\n",
3504 device->default_picture_folder);
3505 printf(" Default video folder: 0x%08x\n",
3506 device->default_video_folder);
3507 printf(" Default organizer folder: 0x%08x\n",
3508 device->default_organizer_folder);
3509 printf(" Default zencast folder: 0x%08x\n",
3510 device->default_zencast_folder);
3511 printf(" Default album folder: 0x%08x\n",
3512 device->default_album_folder);
3513 printf(" Default text folder: 0x%08x\n",
3514 device->default_text_folder);
3518 * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3519 * operation code (0x1010).
3520 * @param device a pointer to the device to reset.
3521 * @return 0 on success, any other value means failure.
3523 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3525 PTPParams *params = (PTPParams *) device->params;
3528 if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3529 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3530 "LIBMTP_Reset_Device(): "
3531 "device does not support resetting.");
3534 ret = ptp_resetdevice(params);
3535 if (ret != PTP_RC_OK) {
3536 add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3543 * This retrieves the manufacturer name of an MTP device.
3544 * @param device a pointer to the device to get the manufacturer name for.
3545 * @return a newly allocated UTF-8 string representing the manufacturer 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_Manufacturername(LIBMTP_mtpdevice_t *device)
3551 char *retmanuf = NULL;
3552 PTPParams *params = (PTPParams *) device->params;
3554 if (params->deviceinfo.Manufacturer != NULL) {
3555 retmanuf = strdup(params->deviceinfo.Manufacturer);
3561 * This retrieves the model name (often equal to product name)
3563 * @param device a pointer to the device to get the model name for.
3564 * @return a newly allocated UTF-8 string representing the model name.
3565 * The string must be freed by the caller after use. If the call
3566 * was unsuccessful this will contain NULL.
3568 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3570 char *retmodel = NULL;
3571 PTPParams *params = (PTPParams *) device->params;
3573 if (params->deviceinfo.Model != NULL) {
3574 retmodel = strdup(params->deviceinfo.Model);
3580 * This retrieves the serial number of an MTP device.
3581 * @param device a pointer to the device to get the serial number for.
3582 * @return a newly allocated UTF-8 string representing the serial number.
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_Serialnumber(LIBMTP_mtpdevice_t *device)
3588 char *retnumber = NULL;
3589 PTPParams *params = (PTPParams *) device->params;
3591 if (params->deviceinfo.SerialNumber != NULL) {
3592 retnumber = strdup(params->deviceinfo.SerialNumber);
3598 * This retrieves the device version (hardware and firmware version) of an
3600 * @param device a pointer to the device to get the device version for.
3601 * @return a newly allocated UTF-8 string representing the device version.
3602 * The string must be freed by the caller after use. If the call
3603 * was unsuccessful this will contain NULL.
3605 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3607 char *retversion = NULL;
3608 PTPParams *params = (PTPParams *) device->params;
3610 if (params->deviceinfo.DeviceVersion != NULL) {
3611 retversion = strdup(params->deviceinfo.DeviceVersion);
3618 * This retrieves the "friendly name" of an MTP device. Usually
3619 * this is simply the name of the owner or something like
3620 * "John Doe's Digital Audio Player". This property should be supported
3621 * by all MTP devices.
3622 * @param device a pointer to the device to get the friendly name for.
3623 * @return a newly allocated UTF-8 string representing the friendly name.
3624 * The string must be freed by the caller after use.
3625 * @see LIBMTP_Set_Friendlyname()
3627 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3629 PTPPropertyValue propval;
3630 char *retstring = NULL;
3631 PTPParams *params = (PTPParams *) device->params;
3634 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3638 ret = ptp_getdevicepropvalue(params,
3639 PTP_DPC_MTP_DeviceFriendlyName,
3642 if (ret != PTP_RC_OK) {
3643 add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3646 if (propval.str != NULL) {
3647 retstring = strdup(propval.str);
3654 * Sets the "friendly name" of an MTP device.
3655 * @param device a pointer to the device to set the friendly name for.
3656 * @param friendlyname the new friendly name for the device.
3657 * @return 0 on success, any other value means failure.
3658 * @see LIBMTP_Get_Friendlyname()
3660 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3661 char const * const friendlyname)
3663 PTPPropertyValue propval;
3664 PTPParams *params = (PTPParams *) device->params;
3667 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3670 propval.str = (char *) friendlyname;
3671 ret = ptp_setdevicepropvalue(params,
3672 PTP_DPC_MTP_DeviceFriendlyName,
3675 if (ret != PTP_RC_OK) {
3676 add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3683 * This retrieves the syncronization partner of an MTP device. This
3684 * property should be supported by all MTP devices.
3685 * @param device a pointer to the device to get the sync partner for.
3686 * @return a newly allocated UTF-8 string representing the synchronization
3687 * partner. The string must be freed by the caller after use.
3688 * @see LIBMTP_Set_Syncpartner()
3690 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3692 PTPPropertyValue propval;
3693 char *retstring = NULL;
3694 PTPParams *params = (PTPParams *) device->params;
3697 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3701 ret = ptp_getdevicepropvalue(params,
3702 PTP_DPC_MTP_SynchronizationPartner,
3705 if (ret != PTP_RC_OK) {
3706 add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3709 if (propval.str != NULL) {
3710 retstring = strdup(propval.str);
3718 * Sets the synchronization partner of an MTP device. Note that
3719 * we have no idea what the effect of setting this to "foobar"
3720 * may be. But the general idea seems to be to tell which program
3721 * shall synchronize with this device and tell others to leave
3723 * @param device a pointer to the device to set the sync partner for.
3724 * @param syncpartner the new synchronization partner for the device.
3725 * @return 0 on success, any other value means failure.
3726 * @see LIBMTP_Get_Syncpartner()
3728 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3729 char const * const syncpartner)
3731 PTPPropertyValue propval;
3732 PTPParams *params = (PTPParams *) device->params;
3735 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3738 propval.str = (char *) syncpartner;
3739 ret = ptp_setdevicepropvalue(params,
3740 PTP_DPC_MTP_SynchronizationPartner,
3743 if (ret != PTP_RC_OK) {
3744 add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3751 * Checks if the device can stora a file of this size or
3753 * @param device a pointer to the device.
3754 * @param filesize the size of the file to check whether it will fit.
3755 * @param storageid the ID of the storage to try to fit the file on.
3756 * @return 0 if the file fits, any other value means failure.
3758 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3759 LIBMTP_devicestorage_t *storage,
3760 uint64_t const filesize) {
3761 PTPParams *params = (PTPParams *) device->params;
3765 // If we cannot check the storage, no big deal.
3766 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3770 ret = get_storage_freespace(device, storage, &freebytes);
3772 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3773 "check_if_file_fits(): error checking free storage.");
3777 if (filesize > freebytes) {
3786 * This function retrieves the current battery level on the device.
3787 * @param device a pointer to the device to get the battery level for.
3788 * @param maximum_level a pointer to a variable that will hold the
3789 * maximum level of the battery if the call was successful.
3790 * @param current_level a pointer to a variable that will hold the
3791 * current level of the battery if the call was successful.
3792 * A value of 0 means that the device is on external power.
3793 * @return 0 if the storage info was successfully retrieved, any other
3794 * means failure. A typical cause of failure is that
3795 * the device does not support the battery level property.
3797 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3798 uint8_t * const maximum_level,
3799 uint8_t * const current_level)
3801 PTPPropertyValue propval;
3803 PTPParams *params = (PTPParams *) device->params;
3804 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3809 if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3810 !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3814 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel,
3815 &propval, PTP_DTC_UINT8);
3816 if (ret != PTP_RC_OK) {
3817 add_ptp_error_to_errorstack(device, ret,
3818 "LIBMTP_Get_Batterylevel(): "
3819 "could not get device property value.");
3823 *maximum_level = device->maximum_battery_level;
3824 *current_level = propval.u8;
3831 * Formats device storage (if the device supports the operation).
3832 * WARNING: This WILL delete all data from the device. Make sure you've
3833 * got confirmation from the user BEFORE you call this function.
3835 * @param device a pointer to the device containing the storage to format.
3836 * @param storage the actual storage to format.
3837 * @return 0 on success, any other value means failure.
3839 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device,
3840 LIBMTP_devicestorage_t *storage)
3843 PTPParams *params = (PTPParams *) device->params;
3845 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3846 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3847 "LIBMTP_Format_Storage(): "
3848 "device does not support formatting storage.");
3851 ret = ptp_formatstore(params, storage->id);
3852 if (ret != PTP_RC_OK) {
3853 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): "
3854 "failed to format storage.");
3861 * Helper function to extract a unicode property off a device.
3862 * This is the standard way of retrieveing unicode device
3863 * properties as described by the PTP spec.
3864 * @param device a pointer to the device to get the property from.
3865 * @param unicstring a pointer to a pointer that will hold the
3866 * property after this call is completed.
3867 * @param property the property to retrieve.
3868 * @return 0 on success, any other value means failure.
3870 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3871 char **unicstring, uint16_t property)
3873 PTPPropertyValue propval;
3874 PTPParams *params = (PTPParams *) device->params;
3879 if (!ptp_property_issupported(params, property)) {
3883 // Unicode strings are 16bit unsigned integer arrays.
3884 ret = ptp_getdevicepropvalue(params,
3888 if (ret != PTP_RC_OK) {
3889 // TODO: add a note on WHICH property that we failed to get.
3891 add_ptp_error_to_errorstack(device, ret,
3892 "get_device_unicode_property(): "
3893 "failed to get unicode property.");
3897 // Extract the actual array.
3898 // printf("Array of %d elements\n", propval.a.count);
3899 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3905 for (i = 0; i < propval.a.count; i++) {
3906 tmp[i] = propval.a.v[i].u16;
3907 // printf("%04x ", tmp[i]);
3909 tmp[propval.a.count] = 0x0000U;
3912 *unicstring = utf16_to_utf8(device, tmp);
3920 * This function returns the secure time as an XML document string from
3922 * @param device a pointer to the device to get the secure time for.
3923 * @param sectime the secure time string as an XML document or NULL if the call
3924 * failed or the secure time property is not supported. This string
3925 * must be <code>free()</code>:ed by the caller after use.
3926 * @return 0 on success, any other value means failure.
3928 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3930 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3934 * This function returns the device (public key) certificate as an
3935 * XML document string from the device.
3936 * @param device a pointer to the device to get the device certificate for.
3937 * @param devcert the device certificate as an XML string or NULL if the call
3938 * failed or the device certificate property is not supported. This
3939 * string must be <code>free()</code>:ed by the caller after use.
3940 * @return 0 on success, any other value means failure.
3942 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3944 return get_device_unicode_property(device, devcert,
3945 PTP_DPC_MTP_DeviceCertificate);
3949 * This function retrieves a list of supported file types, i.e. the file
3950 * types that this device claims it supports, e.g. audio file types that
3951 * the device can play etc. This list is mitigated to
3952 * inlcude the file types that libmtp can handle, i.e. it will not list
3953 * filetypes that libmtp will handle internally like playlists and folders.
3954 * @param device a pointer to the device to get the filetype capabilities for.
3955 * @param filetypes a pointer to a pointer that will hold the list of
3956 * supported filetypes if the call was successful. This list must
3957 * be <code>free()</code>:ed by the caller after use.
3958 * @param length a pointer to a variable that will hold the length of the
3959 * list of supported filetypes if the call was successful.
3960 * @return 0 on success, any other value means failure.
3961 * @see LIBMTP_Get_Filetype_Description()
3963 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3964 uint16_t * const length)
3966 PTPParams *params = (PTPParams *) device->params;
3967 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3968 uint16_t *localtypes;
3969 uint16_t localtypelen;
3972 // This is more memory than needed if there are unknown types, but what the heck.
3973 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
3974 if (localtypes == NULL)
3979 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3980 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
3981 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
3982 localtypes[localtypelen] = localtype;
3986 // The forgotten Ogg support on YP-10 and others...
3987 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
3988 localtypes = (uint16_t *) realloc(localtypes,
3989 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3990 if (localtypes == NULL)
3993 localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
3996 // The forgotten FLAC support on Cowon iAudio S9 and others...
3997 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
3998 localtypes = (uint16_t *) realloc(localtypes,
3999 (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
4000 if (localtypes == NULL)
4003 localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
4007 *filetypes = localtypes;
4008 *length = localtypelen;
4014 * This function checks if the device has some specific capabilities, in
4015 * order to avoid calling APIs that may disturb the device.
4017 * @param device a pointer to the device to check the capability on.
4018 * @param cap the capability to check.
4019 * @return 0 if not supported, any other value means the device has the
4020 * requested capability.
4022 int LIBMTP_Check_Capability(LIBMTP_mtpdevice_t *device, LIBMTP_devicecap_t cap)
4025 case LIBMTP_DEVICECAP_GetPartialObject:
4026 return (ptp_operation_issupported(device->params,
4027 PTP_OC_GetPartialObject) ||
4028 ptp_operation_issupported(device->params,
4029 PTP_OC_ANDROID_GetPartialObject64));
4030 case LIBMTP_DEVICECAP_SendPartialObject:
4031 return ptp_operation_issupported(device->params,
4032 PTP_OC_ANDROID_SendPartialObject);
4033 case LIBMTP_DEVICECAP_EditObjects:
4034 return (ptp_operation_issupported(device->params,
4035 PTP_OC_ANDROID_TruncateObject) &&
4036 ptp_operation_issupported(device->params,
4037 PTP_OC_ANDROID_BeginEditObject) &&
4038 ptp_operation_issupported(device->params,
4039 PTP_OC_ANDROID_EndEditObject));
4041 * Handle other capabilities here, this is also a good place to
4042 * blacklist some advanced operations on specific devices if need
4053 * This function updates all the storage id's of a device and their
4054 * properties, then creates a linked list and puts the list head into
4055 * the device struct. It also optionally sorts this list. If you want
4056 * to display storage information in your application you should call
4057 * this function, then dereference the device struct
4058 * (<code>device->storage</code>) to get out information on the storage.
4060 * You need to call this everytime you want to update the
4061 * <code>device->storage</code> list, for example anytime you need
4062 * to check available storage somewhere.
4064 * <b>WARNING:</b> since this list is dynamically updated, do not
4065 * reference its fields in external applications by pointer! E.g
4066 * do not put a reference to any <code>char *</code> field. instead
4067 * <code>strncpy()</code> it!
4069 * @param device a pointer to the device to get the storage for.
4070 * @param sortby an integer that determines the sorting of the storage list.
4071 * Valid sort methods are defined in libmtp.h with beginning with
4072 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
4074 * @return 0 on success, 1 success but only with storage id's, storage
4075 * properities could not be retrieved and -1 means failure.
4077 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
4080 PTPStorageInfo storageInfo;
4081 PTPParams *params = (PTPParams *) device->params;
4082 PTPStorageIDs storageIDs;
4083 LIBMTP_devicestorage_t *storage = NULL;
4084 LIBMTP_devicestorage_t *storageprev = NULL;
4086 if (device->storage != NULL)
4087 free_storage_list(device);
4089 // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
4091 if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
4093 if (storageIDs.n < 1)
4096 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
4097 for (i = 0; i < storageIDs.n; i++) {
4099 storage = (LIBMTP_devicestorage_t *)
4100 malloc(sizeof(LIBMTP_devicestorage_t));
4101 if (storage == NULL)
4103 storage->prev = storageprev;
4104 if (storageprev != NULL)
4105 storageprev->next = storage;
4106 if (device->storage == NULL)
4107 device->storage = storage;
4109 storage->id = storageIDs.Storage[i];
4110 storage->StorageType = PTP_ST_Undefined;
4111 storage->FilesystemType = PTP_FST_Undefined;
4112 storage->AccessCapability = PTP_AC_ReadWrite;
4113 storage->MaxCapacity = (uint64_t) -1;
4114 storage->FreeSpaceInBytes = (uint64_t) -1;
4115 storage->FreeSpaceInObjects = (uint64_t) -1;
4116 storage->StorageDescription = strdup("Unknown storage");
4117 storage->VolumeIdentifier = strdup("Unknown volume");
4118 storage->next = NULL;
4120 storageprev = storage;
4122 free(storageIDs.Storage);
4125 for (i = 0; i < storageIDs.n; i++) {
4127 ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
4128 if (ret != PTP_RC_OK) {
4129 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): "
4130 "Could not get storage info.");
4131 if (device->storage != NULL) {
4132 free_storage_list(device);
4137 storage = (LIBMTP_devicestorage_t *)
4138 malloc(sizeof(LIBMTP_devicestorage_t));
4139 if (storage == NULL)
4141 storage->prev = storageprev;
4142 if (storageprev != NULL)
4143 storageprev->next = storage;
4144 if (device->storage == NULL)
4145 device->storage = storage;
4147 storage->id = storageIDs.Storage[i];
4148 storage->StorageType = storageInfo.StorageType;
4149 storage->FilesystemType = storageInfo.FilesystemType;
4150 storage->AccessCapability = storageInfo.AccessCapability;
4151 storage->MaxCapacity = storageInfo.MaxCapability;
4152 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
4153 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
4154 storage->StorageDescription = storageInfo.StorageDescription;
4155 storage->VolumeIdentifier = storageInfo.VolumeLabel;
4156 storage->next = NULL;
4158 storageprev = storage;
4161 if (storage != NULL)
4162 storage->next = NULL;
4164 sort_storage_by(device,sortby);
4165 free(storageIDs.Storage);
4171 * This creates a new file metadata structure and allocates memory
4172 * for it. Notice that if you add strings to this structure they
4173 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
4174 * operation later, so be careful of using strdup() when assigning
4178 * LIBMTP_file_t *file = LIBMTP_new_file_t();
4179 * file->filename = strdup(namestr);
4181 * LIBMTP_destroy_file_t(file);
4184 * @return a pointer to the newly allocated metadata structure.
4185 * @see LIBMTP_destroy_file_t()
4187 LIBMTP_file_t *LIBMTP_new_file_t(void)
4189 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
4193 new->filename = NULL;
4196 new->storage_id = 0;
4198 new->modificationdate = 0;
4199 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4205 * This destroys a file metadata structure and deallocates the memory
4206 * used by it, including any strings. Never use a file metadata
4207 * structure again after calling this function on it.
4208 * @param file the file metadata to destroy.
4209 * @see LIBMTP_new_file_t()
4211 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
4216 if (file->filename != NULL)
4217 free(file->filename);
4223 * Helper function that takes one PTP object and creates a
4224 * LIBMTP_file_t metadata entry.
4226 static LIBMTP_file_t *obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
4228 PTPParams *params = (PTPParams *) device->params;
4229 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4230 LIBMTP_file_t *file;
4233 // Allocate a new file type
4234 file = LIBMTP_new_file_t();
4236 file->parent_id = ob->oi.ParentObject;
4237 file->storage_id = ob->oi.StorageID;
4240 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4243 * A special quirk for devices that doesn't quite
4244 * remember that some files marked as "unknown" type are
4245 * actually OGG or FLAC files. We look at the filename extension
4246 * and see if it happens that this was atleast named "ogg" or "flac"
4247 * and fall back on this heuristic approach in that case,
4248 * for these bugged devices only.
4250 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
4251 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4252 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4253 has_ogg_extension(file->filename)) {
4254 file->filetype = LIBMTP_FILETYPE_OGG;
4257 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename)) {
4258 file->filetype = LIBMTP_FILETYPE_FLAC;
4262 // Set the modification date
4263 file->modificationdate = ob->oi.ModificationDate;
4265 // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4266 file->filesize = ob->oi.ObjectCompressedSize;
4267 if (ob->oi.Filename != NULL) {
4268 file->filename = strdup(ob->oi.Filename);
4271 // This is a unique ID so we can keep track of the file.
4272 file->item_id = ob->oid;
4275 * If we have a cached, large set of metadata, then use it!
4278 MTPProperties *prop = ob->mtpprops;
4280 for (i=0; i < ob->nrofmtpprops; i++, prop++) {
4281 // Pick ObjectSize here...
4282 if (prop->property == PTP_OPC_ObjectSize) {
4283 // This may already be set, but this 64bit precision value
4284 // is better than the PTP 32bit value, so let it override.
4285 if (device->object_bitsize == 64) {
4286 file->filesize = prop->propval.u64;
4288 file->filesize = prop->propval.u32;
4293 } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
4294 uint16_t *props = NULL;
4295 uint32_t propcnt = 0;
4298 // First see which properties can be retrieved for this object format
4299 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4300 if (ret != PTP_RC_OK) {
4301 add_ptp_error_to_errorstack(device, ret, "obj2file: call to ptp_mtp_getobjectpropssupported() failed.");
4302 // Silently fall through.
4304 for (i = 0; i < propcnt; i++) {
4306 case PTP_OPC_ObjectSize:
4307 if (device->object_bitsize == 64) {
4308 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4310 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4326 * This function retrieves the metadata for a single file off
4329 * Do not call this function repeatedly! The file handles are linearly
4330 * searched O(n) and the call may involve (slow) USB traffic, so use
4331 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4332 * as an efficient data structure such as a hash list.
4334 * Incidentally this function will return metadata for
4335 * a folder (association) as well, but this is not a proper use
4336 * of it, it is intended for file manipulation, not folder manipulation.
4338 * @param device a pointer to the device to get the file metadata from.
4339 * @param fileid the object ID of the file that you want the metadata for.
4340 * @return a metadata entry on success or NULL on failure.
4341 * @see LIBMTP_Get_Filelisting()
4343 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4345 PTPParams *params = (PTPParams *) device->params;
4349 // Get all the handles if we haven't already done that
4350 // (Only on cached devices.)
4351 if (device->cached && params->nrofobjects == 0) {
4352 flush_handles(device);
4355 ret = ptp_object_want(params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4356 if (ret != PTP_RC_OK)
4359 return obj2file(device, ob);
4363 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4365 * @see LIBMTP_Get_Filelisting_With_Callback()
4367 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
4369 LIBMTP_INFO("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
4370 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
4371 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
4375 * This returns a long list of all files available
4376 * on the current MTP device. Folders will not be returned, but abstract
4377 * entities like playlists and albums will show up as "files". Typical usage:
4380 * LIBMTP_file_t *filelist;
4382 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
4383 * while (filelist != NULL) {
4384 * LIBMTP_file_t *tmp;
4386 * // Do something on each element in the list here...
4388 * filelist = filelist->next;
4389 * LIBMTP_destroy_file_t(tmp);
4393 * If you want to group your file listing by storage (per storage unit) or
4394 * arrange files into folders, you must dereference the <code>storage_id</code>
4395 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
4396 * struct. To arrange by folders or files you typically have to create the proper
4397 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4398 * <code>LIBMTP_Get_Folder_List()</code> first.
4400 * @param device a pointer to the device to get the file listing for.
4401 * @param callback a function to be called during the tracklisting retrieveal
4402 * for displaying progress bars etc, or NULL if you don't want
4404 * @param data a user-defined pointer that is passed along to
4405 * the <code>progress</code> function in order to
4406 * pass along some user defined data to the progress
4407 * updates. If not used, set this to NULL.
4408 * @return a list of files that can be followed using the <code>next</code>
4409 * field of the <code>LIBMTP_file_t</code> data structure.
4410 * Each of the metadata tags must be freed after use, and may
4411 * contain only partial metadata information, i.e. one or several
4412 * fields may be NULL or 0.
4413 * @see LIBMTP_Get_Filemetadata()
4415 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
4416 LIBMTP_progressfunc_t const callback,
4417 void const * const data)
4420 LIBMTP_file_t *retfiles = NULL;
4421 LIBMTP_file_t *curfile = NULL;
4422 PTPParams *params = (PTPParams *) device->params;
4424 // Get all the handles if we haven't already done that
4425 if (params->nrofobjects == 0) {
4426 flush_handles(device);
4429 for (i = 0; i < params->nrofobjects; i++) {
4430 LIBMTP_file_t *file;
4433 if (callback != NULL)
4434 callback(i, params->nrofobjects, data);
4436 ob = ¶ms->objects[i];
4438 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4439 // MTP use this object format for folders which means
4440 // these "files" will turn up on a folder listing instead.
4445 file = obj2file(device, ob);
4450 // Add track to a list that will be returned afterwards.
4451 if (retfiles == NULL) {
4455 curfile->next = file;
4459 // Call listing callback
4460 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4462 } // Handle counting loop
4467 * This function retrieves the contents of a certain folder
4468 * with id parent on a certain storage on a certain device.
4469 * The result contains both files and folders.
4470 * The device used with this operations must have been opened with
4471 * LIBMTP_Open_Raw_Device_Uncached() or it will fail.
4473 * NOTE: the request will always perform I/O with the device.
4474 * @param device a pointer to the MTP device to report info from.
4475 * @param storage a storage on the device to report info from. If
4476 * 0 is passed in, the files for the given parent will be
4477 * searched across all available storages.
4478 * @param parent the parent folder id.
4480 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device,
4481 uint32_t const storage,
4482 uint32_t const parent)
4484 PTPParams *params = (PTPParams *) device->params;
4485 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4486 LIBMTP_file_t *retfiles = NULL;
4487 LIBMTP_file_t *curfile = NULL;
4488 PTPObjectHandles currentHandles;
4493 if (device->cached) {
4494 // This function is only supposed to be used by devices
4495 // opened as uncached!
4496 LIBMTP_ERROR("tried to use %s on a cached device!\n",
4501 if (FLAG_BROKEN_GET_OBJECT_PROPVAL(ptp_usb)) {
4502 // These devices cannot handle the commands needed for
4504 LIBMTP_ERROR("tried to use %s on an unsupported device, "
4505 "this command does not work on all devices "
4506 "due to missing low-level support to read "
4507 "information on individual tracks\n",
4513 storageid = PTP_GOH_ALL_STORAGE;
4515 storageid = storage;
4517 ret = ptp_getobjecthandles(params,
4519 PTP_GOH_ALL_FORMATS,
4523 if (ret != PTP_RC_OK) {
4524 add_ptp_error_to_errorstack(device, ret,
4525 "LIBMTP_Get_Files_And_Folders(): could not get object handles.");
4529 if (currentHandles.Handler == NULL || currentHandles.n == 0)
4532 for (i = 0; i < currentHandles.n; i++) {
4533 LIBMTP_file_t *file;
4535 // Get metadata for one file, if it fails, try next file
4536 file = LIBMTP_Get_Filemetadata(device, currentHandles.Handler[i]);
4540 // Add track to a list that will be returned afterwards.
4541 if (curfile == NULL) {
4545 curfile->next = file;
4550 free(currentHandles.Handler);
4552 // Return a pointer to the original first file
4559 * This creates a new track metadata structure and allocates memory
4560 * for it. Notice that if you add strings to this structure they
4561 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4562 * operation later, so be careful of using strdup() when assigning
4566 * LIBMTP_track_t *track = LIBMTP_new_track_t();
4567 * track->title = strdup(titlestr);
4569 * LIBMTP_destroy_track_t(track);
4572 * @return a pointer to the newly allocated metadata structure.
4573 * @see LIBMTP_destroy_track_t()
4575 LIBMTP_track_t *LIBMTP_new_track_t(void)
4577 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4583 new->storage_id = 0;
4586 new->composer = NULL;
4590 new->filename = NULL;
4592 new->tracknumber = 0;
4594 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4595 new->samplerate = 0;
4596 new->nochannels = 0;
4599 new->bitratetype = 0;
4602 new->modificationdate = 0;
4608 * This destroys a track metadata structure and deallocates the memory
4609 * used by it, including any strings. Never use a track metadata
4610 * structure again after calling this function on it.
4611 * @param track the track metadata to destroy.
4612 * @see LIBMTP_new_track_t()
4614 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4616 if (track == NULL) {
4619 if (track->title != NULL)
4621 if (track->artist != NULL)
4622 free(track->artist);
4623 if (track->composer != NULL)
4624 free(track->composer);
4625 if (track->album != NULL)
4627 if (track->genre != NULL)
4629 if (track->date != NULL)
4631 if (track->filename != NULL)
4632 free(track->filename);
4638 * This function maps and copies a property onto the track metadata if applicable.
4640 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4642 switch (prop->property) {
4644 if (prop->propval.str != NULL)
4645 track->title = strdup(prop->propval.str);
4647 track->title = NULL;
4649 case PTP_OPC_Artist:
4650 if (prop->propval.str != NULL)
4651 track->artist = strdup(prop->propval.str);
4653 track->artist = NULL;
4655 case PTP_OPC_Composer:
4656 if (prop->propval.str != NULL)
4657 track->composer = strdup(prop->propval.str);
4659 track->composer = NULL;
4661 case PTP_OPC_Duration:
4662 track->duration = prop->propval.u32;
4665 track->tracknumber = prop->propval.u16;
4668 if (prop->propval.str != NULL)
4669 track->genre = strdup(prop->propval.str);
4671 track->genre = NULL;
4673 case PTP_OPC_AlbumName:
4674 if (prop->propval.str != NULL)
4675 track->album = strdup(prop->propval.str);
4677 track->album = NULL;
4679 case PTP_OPC_OriginalReleaseDate:
4680 if (prop->propval.str != NULL)
4681 track->date = strdup(prop->propval.str);
4685 // These are, well not so important.
4686 case PTP_OPC_SampleRate:
4687 track->samplerate = prop->propval.u32;
4689 case PTP_OPC_NumberOfChannels:
4690 track->nochannels = prop->propval.u16;
4692 case PTP_OPC_AudioWAVECodec:
4693 track->wavecodec = prop->propval.u32;
4695 case PTP_OPC_AudioBitRate:
4696 track->bitrate = prop->propval.u32;
4698 case PTP_OPC_BitRateType:
4699 track->bitratetype = prop->propval.u16;
4701 case PTP_OPC_Rating:
4702 track->rating = prop->propval.u16;
4704 case PTP_OPC_UseCount:
4705 track->usecount = prop->propval.u32;
4707 case PTP_OPC_ObjectSize:
4708 if (device->object_bitsize == 64) {
4709 track->filesize = prop->propval.u64;
4711 track->filesize = prop->propval.u32;
4720 * This function retrieves the track metadata for a track
4721 * given by a unique ID.
4722 * @param device a pointer to the device to get the track metadata off.
4723 * @param trackid the unique ID of the track.
4724 * @param objectformat the object format of this track, so we know what it supports.
4725 * @param track a metadata set to fill in.
4727 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4728 LIBMTP_track_t *track)
4731 PTPParams *params = (PTPParams *) device->params;
4733 MTPProperties *prop;
4737 * If we have a cached, large set of metadata, then use it!
4739 ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4741 prop = ob->mtpprops;
4742 for (i=0;i<ob->nrofmtpprops;i++,prop++)
4743 pick_property_to_track_metadata(device, prop, track);
4745 uint16_t *props = NULL;
4746 uint32_t propcnt = 0;
4748 // First see which properties can be retrieved for this object format
4749 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4750 if (ret != PTP_RC_OK) {
4751 add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4752 // Just bail out for now, nothing is ever set.
4755 for (i=0;i<propcnt;i++) {
4758 track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4760 case PTP_OPC_Artist:
4761 track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4763 case PTP_OPC_Composer:
4764 track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4766 case PTP_OPC_Duration:
4767 track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4770 track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4773 track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4775 case PTP_OPC_AlbumName:
4776 track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4778 case PTP_OPC_OriginalReleaseDate:
4779 track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4781 // These are, well not so important.
4782 case PTP_OPC_SampleRate:
4783 track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4785 case PTP_OPC_NumberOfChannels:
4786 track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4788 case PTP_OPC_AudioWAVECodec:
4789 track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4791 case PTP_OPC_AudioBitRate:
4792 track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4794 case PTP_OPC_BitRateType:
4795 track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4797 case PTP_OPC_Rating:
4798 track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4800 case PTP_OPC_UseCount:
4801 track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4803 case PTP_OPC_ObjectSize:
4804 if (device->object_bitsize == 64) {
4805 track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4807 track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4818 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4820 * @see LIBMTP_Get_Tracklisting_With_Callback()
4822 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4824 LIBMTP_INFO("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4825 LIBMTP_INFO("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4826 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4830 * This returns a long list of all tracks available on the current MTP device.
4831 * Tracks include multimedia objects, both music tracks and video tracks.
4835 * LIBMTP_track_t *tracklist;
4837 * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4838 * while (tracklist != NULL) {
4839 * LIBMTP_track_t *tmp;
4841 * // Do something on each element in the list here...
4843 * tracklist = tracklist->next;
4844 * LIBMTP_destroy_track_t(tmp);
4848 * If you want to group your track listing by storage (per storage unit) or
4849 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4850 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4851 * struct. To arrange by folders or files you typically have to create the proper
4852 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4853 * <code>LIBMTP_Get_Folder_List()</code> first.
4855 * @param device a pointer to the device to get the track listing for.
4856 * @param callback a function to be called during the tracklisting retrieveal
4857 * for displaying progress bars etc, or NULL if you don't want
4859 * @param data a user-defined pointer that is passed along to
4860 * the <code>progress</code> function in order to
4861 * pass along some user defined data to the progress
4862 * updates. If not used, set this to NULL.
4863 * @return a list of tracks that can be followed using the <code>next</code>
4864 * field of the <code>LIBMTP_track_t</code> data structure.
4865 * Each of the metadata tags must be freed after use, and may
4866 * contain only partial metadata information, i.e. one or several
4867 * fields may be NULL or 0.
4868 * @see LIBMTP_Get_Trackmetadata()
4870 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4871 LIBMTP_progressfunc_t const callback,
4872 void const * const data)
4874 return LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, 0, callback, data);
4879 * This returns a long list of all tracks available on the current MTP device.
4880 * Tracks include multimedia objects, both music tracks and video tracks.
4884 * LIBMTP_track_t *tracklist;
4886 * tracklist = LIBMTP_Get_Tracklisting_With_Callback_For_Storage(device, storage_id, callback, data);
4887 * while (tracklist != NULL) {
4888 * LIBMTP_track_t *tmp;
4890 * // Do something on each element in the list here...
4892 * tracklist = tracklist->next;
4893 * LIBMTP_destroy_track_t(tmp);
4897 * If you want to group your track listing by storage (per storage unit) or
4898 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4899 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4900 * struct. To arrange by folders or files you typically have to create the proper
4901 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4902 * <code>LIBMTP_Get_Folder_List()</code> first.
4904 * @param device a pointer to the device to get the track listing for.
4905 * @param storage_id ID of device storage (if null, no filter)
4906 * @param callback a function to be called during the tracklisting retrieveal
4907 * for displaying progress bars etc, or NULL if you don't want
4909 * @param data a user-defined pointer that is passed along to
4910 * the <code>progress</code> function in order to
4911 * pass along some user defined data to the progress
4912 * updates. If not used, set this to NULL.
4913 * @return a list of tracks that can be followed using the <code>next</code>
4914 * field of the <code>LIBMTP_track_t</code> data structure.
4915 * Each of the metadata tags must be freed after use, and may
4916 * contain only partial metadata information, i.e. one or several
4917 * fields may be NULL or 0.
4918 * @see LIBMTP_Get_Trackmetadata()
4920 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id,
4921 LIBMTP_progressfunc_t const callback,
4922 void const * const data)
4925 LIBMTP_track_t *retracks = NULL;
4926 LIBMTP_track_t *curtrack = NULL;
4927 PTPParams *params = (PTPParams *) device->params;
4928 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4930 // Get all the handles if we haven't already done that
4931 if (params->nrofobjects == 0) {
4932 flush_handles(device);
4935 for (i = 0; i < params->nrofobjects; i++) {
4936 LIBMTP_track_t *track;
4938 LIBMTP_filetype_t mtptype;
4940 if (callback != NULL)
4941 callback(i, params->nrofobjects, data);
4943 ob = ¶ms->objects[i];
4944 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4946 // Ignore stuff we don't know how to handle...
4947 // TODO: get this list as an intersection of the sets
4948 // supported by the device and the from the device and
4949 // all known track files?
4950 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4951 // This row lets through undefined files for examination since they may be forgotten OGG files.
4952 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4953 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4954 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4955 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4957 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4961 // Ignore stuff that isn't into the storage device
4962 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
4965 // Allocate a new track type
4966 track = LIBMTP_new_track_t();
4968 // This is some sort of unique ID so we can keep track of the track.
4969 track->item_id = ob->oid;
4970 track->parent_id = ob->oi.ParentObject;
4971 track->storage_id = ob->oi.StorageID;
4972 track->modificationdate = ob->oi.ModificationDate;
4974 track->filetype = mtptype;
4976 // Original file-specific properties
4977 track->filesize = ob->oi.ObjectCompressedSize;
4978 if (ob->oi.Filename != NULL) {
4979 track->filename = strdup(ob->oi.Filename);
4982 get_track_metadata(device, ob->oi.ObjectFormat, track);
4985 * A special quirk for iriver devices that doesn't quite
4986 * remember that some files marked as "unknown" type are
4987 * actually OGG or FLAC files. We look at the filename extension
4988 * and see if it happens that this was atleast named "ogg" or "flac"
4989 * and fall back on this heuristic approach in that case,
4990 * for these bugged devices only.
4992 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
4993 track->filename != NULL) {
4994 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4995 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4996 has_ogg_extension(track->filename))
4997 track->filetype = LIBMTP_FILETYPE_OGG;
4998 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
4999 has_flac_extension(track->filename))
5000 track->filetype = LIBMTP_FILETYPE_FLAC;
5002 // This was not an OGG/FLAC file so discard it and continue
5003 LIBMTP_destroy_track_t(track);
5008 // Add track to a list that will be returned afterwards.
5009 if (retracks == NULL) {
5013 curtrack->next = track;
5017 // Call listing callback
5018 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
5020 } // Handle counting loop
5025 * This function retrieves the metadata for a single track off
5028 * Do not call this function repeatedly! The track handles are linearly
5029 * searched O(n) and the call may involve (slow) USB traffic, so use
5030 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
5031 * as an efficient data structure such as a hash list.
5033 * @param device a pointer to the device to get the track metadata from.
5034 * @param trackid the object ID of the track that you want the metadata for.
5035 * @return a track metadata entry on success or NULL on failure.
5036 * @see LIBMTP_Get_Tracklisting()
5038 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
5040 PTPParams *params = (PTPParams *) device->params;
5041 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5043 LIBMTP_track_t *track;
5044 LIBMTP_filetype_t mtptype;
5047 // Get all the handles if we haven't already done that
5048 if (params->nrofobjects == 0)
5049 flush_handles(device);
5051 ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5052 if (ret != PTP_RC_OK)
5055 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
5057 // Ignore stuff we don't know how to handle...
5058 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
5060 * This row lets through undefined files for examination
5061 * since they may be forgotten OGG or FLAC files.
5063 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
5064 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
5065 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
5066 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
5068 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
5072 // Allocate a new track type
5073 track = LIBMTP_new_track_t();
5075 // This is some sort of unique ID so we can keep track of the track.
5076 track->item_id = ob->oid;
5077 track->parent_id = ob->oi.ParentObject;
5078 track->storage_id = ob->oi.StorageID;
5079 track->modificationdate = ob->oi.ModificationDate;
5081 track->filetype = mtptype;
5083 // Original file-specific properties
5084 track->filesize = ob->oi.ObjectCompressedSize;
5085 if (ob->oi.Filename != NULL) {
5086 track->filename = strdup(ob->oi.Filename);
5090 * A special quirk for devices that doesn't quite
5091 * remember that some files marked as "unknown" type are
5092 * actually OGG or FLAC files. We look at the filename extension
5093 * and see if it happens that this was atleast named "ogg"
5094 * and fall back on this heuristic approach in that case,
5095 * for these bugged devices only.
5097 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
5098 track->filename != NULL) {
5099 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
5100 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
5101 has_ogg_extension(track->filename))
5102 track->filetype = LIBMTP_FILETYPE_OGG;
5103 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
5104 has_flac_extension(track->filename))
5105 track->filetype = LIBMTP_FILETYPE_FLAC;
5107 // This was not an OGG/FLAC file so discard it
5108 LIBMTP_destroy_track_t(track);
5112 get_track_metadata(device, ob->oi.ObjectFormat, track);
5117 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
5118 * to isolate the internal type.
5120 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
5122 MTPDataHandler *handler = (MTPDataHandler *)priv;
5124 uint32_t local_gotlen = 0;
5125 ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
5126 *gotlen = local_gotlen;
5129 case LIBMTP_HANDLER_RETURN_OK:
5131 case LIBMTP_HANDLER_RETURN_ERROR:
5132 return PTP_ERROR_IO;
5133 case LIBMTP_HANDLER_RETURN_CANCEL:
5134 return PTP_ERROR_CANCEL;
5136 return PTP_ERROR_IO;
5141 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
5142 * to isolate the internal type.
5144 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen)
5146 MTPDataHandler *handler = (MTPDataHandler *)priv;
5148 uint32_t local_putlen = 0;
5149 ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
5150 *putlen = local_putlen;
5153 case LIBMTP_HANDLER_RETURN_OK:
5155 case LIBMTP_HANDLER_RETURN_ERROR:
5156 return PTP_ERROR_IO;
5157 case LIBMTP_HANDLER_RETURN_CANCEL:
5158 return PTP_ERROR_CANCEL;
5160 return PTP_ERROR_IO;
5165 * This gets a file off the device to a local file identified
5167 * @param device a pointer to the device to get the track from.
5168 * @param id the file ID of the file to retrieve.
5169 * @param path a filename to use for the retrieved file.
5170 * @param callback a progress indicator function or NULL to ignore.
5171 * @param data a user-defined pointer that is passed along to
5172 * the <code>progress</code> function in order to
5173 * pass along some user defined data to the progress
5174 * updates. If not used, set this to NULL.
5175 * @return 0 if the transfer was successful, any other value means
5177 * @see LIBMTP_Get_File_To_File_Descriptor()
5179 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5180 char const * const path, LIBMTP_progressfunc_t const callback,
5181 void const * const data)
5188 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
5194 #ifdef USE_WINDOWS_IO_H
5195 if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
5197 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
5200 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
5202 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
5206 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5211 // Delete partial file.
5220 * This gets a file off the device to a file identified
5221 * by a file descriptor.
5223 * This function can potentially be used for streaming
5224 * files off the device for playback or broadcast for example,
5225 * by downloading the file into a stream sink e.g. a socket.
5227 * @param device a pointer to the device to get the file from.
5228 * @param id the file ID of the file to retrieve.
5229 * @param fd a local file descriptor to write the file to.
5230 * @param callback a progress indicator function or NULL to ignore.
5231 * @param data a user-defined pointer that is passed along to
5232 * the <code>progress</code> function in order to
5233 * pass along some user defined data to the progress
5234 * updates. If not used, set this to NULL.
5235 * @return 0 if the transfer was successful, any other value means
5237 * @see LIBMTP_Get_File_To_File()
5239 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5242 LIBMTP_progressfunc_t const callback,
5243 void const * const data)
5246 PTPParams *params = (PTPParams *) device->params;
5247 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5252 get_usb_device_timeout(ptp_usb, &oldtimeout);
5253 set_usb_device_timeout(ptp_usb, 5000);
5255 LIBMTP_INFO("priv set timeout value : %d, now, set timeout value to 5 sec", oldtimeout);
5257 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5258 if (ret != PTP_RC_OK) {
5259 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5260 set_usb_device_timeout(ptp_usb, oldtimeout);
5263 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5264 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5265 set_usb_device_timeout(ptp_usb, oldtimeout);
5270 ptp_usb->callback_active = 1;
5271 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5272 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5273 ptp_usb->current_transfer_complete = 0;
5274 ptp_usb->current_transfer_callback = callback;
5275 ptp_usb->current_transfer_callback_data = data;
5277 ret = ptp_getobject_tofd(params, id, fd);
5279 ptp_usb->callback_active = 0;
5280 ptp_usb->current_transfer_callback = NULL;
5281 ptp_usb->current_transfer_callback_data = NULL;
5283 set_usb_device_timeout(ptp_usb, oldtimeout);
5285 if (ret == PTP_ERROR_CANCEL) {
5286 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5289 if (ret != PTP_RC_OK) {
5290 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5298 * This gets a file off the device and calls put_func
5299 * with chunks of data
5301 * @param device a pointer to the device to get the file from.
5302 * @param id the file ID of the file to retrieve.
5303 * @param put_func the function to call when we have data.
5304 * @param priv the user-defined pointer that is passed to
5305 * <code>put_func</code>.
5306 * @param callback a progress indicator function or NULL to ignore.
5307 * @param data a user-defined pointer that is passed along to
5308 * the <code>progress</code> function in order to
5309 * pass along some user defined data to the progress
5310 * updates. If not used, set this to NULL.
5311 * @return 0 if the transfer was successful, any other value means
5314 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
5316 MTPDataPutFunc put_func,
5318 LIBMTP_progressfunc_t const callback,
5319 void const * const data)
5323 PTPParams *params = (PTPParams *) device->params;
5324 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5326 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
5327 if (ret != PTP_RC_OK) {
5328 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
5331 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
5332 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
5337 ptp_usb->callback_active = 1;
5338 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
5339 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
5340 ptp_usb->current_transfer_complete = 0;
5341 ptp_usb->current_transfer_callback = callback;
5342 ptp_usb->current_transfer_callback_data = data;
5344 MTPDataHandler mtp_handler;
5345 mtp_handler.getfunc = NULL;
5346 mtp_handler.putfunc = put_func;
5347 mtp_handler.priv = priv;
5349 PTPDataHandler handler;
5350 handler.getfunc = NULL;
5351 handler.putfunc = put_func_wrapper;
5352 handler.priv = &mtp_handler;
5354 ret = ptp_getobject_to_handler(params, id, &handler);
5356 ptp_usb->callback_active = 0;
5357 ptp_usb->current_transfer_callback = NULL;
5358 ptp_usb->current_transfer_callback_data = NULL;
5360 if (ret == PTP_ERROR_CANCEL) {
5361 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
5364 if (ret != PTP_RC_OK) {
5365 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
5374 * This gets a track off the device to a file identified
5375 * by a filename. This is actually just a wrapper for the
5376 * \c LIBMTP_Get_Track_To_File() function.
5377 * @param device a pointer to the device to get the track from.
5378 * @param id the track ID of the track to retrieve.
5379 * @param path a filename to use for the retrieved track.
5380 * @param callback a progress indicator function or NULL to ignore.
5381 * @param data a user-defined pointer that is passed along to
5382 * the <code>progress</code> function in order to
5383 * pass along some user defined data to the progress
5384 * updates. If not used, set this to NULL.
5385 * @return 0 if the transfer was successful, any other value means
5387 * @see LIBMTP_Get_Track_To_File_Descriptor()
5389 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
5390 char const * const path, LIBMTP_progressfunc_t const callback,
5391 void const * const data)
5393 // This is just a wrapper
5394 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
5398 * This gets a track off the device to a file identified
5399 * by a file descriptor. This is actually just a wrapper for
5400 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
5401 * @param device a pointer to the device to get the track from.
5402 * @param id the track ID of the track to retrieve.
5403 * @param fd a file descriptor to write the track to.
5404 * @param callback a progress indicator function or NULL to ignore.
5405 * @param data a user-defined pointer that is passed along to
5406 * the <code>progress</code> function in order to
5407 * pass along some user defined data to the progress
5408 * updates. If not used, set this to NULL.
5409 * @return 0 if the transfer was successful, any other value means
5411 * @see LIBMTP_Get_Track_To_File()
5413 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
5416 LIBMTP_progressfunc_t const callback,
5417 void const * const data)
5419 // This is just a wrapper
5420 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data);
5424 * This gets a track off the device to a handler function.
5425 * This is actually just a wrapper for
5426 * the \c LIBMTP_Get_File_To_Handler() function.
5427 * @param device a pointer to the device to get the track from.
5428 * @param id the track ID of the track to retrieve.
5429 * @param put_func the function to call when we have data.
5430 * @param priv the user-defined pointer that is passed to
5431 * <code>put_func</code>.
5432 * @param callback a progress indicator function or NULL to ignore.
5433 * @param data a user-defined pointer that is passed along to
5434 * the <code>progress</code> function in order to
5435 * pass along some user defined data to the progress
5436 * updates. If not used, set this to NULL.
5437 * @return 0 if the transfer was successful, any other value means
5440 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
5442 MTPDataPutFunc put_func,
5444 LIBMTP_progressfunc_t const callback,
5445 void const * const data)
5447 // This is just a wrapper
5448 return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
5452 * This function sends a track from a local file to an
5453 * MTP device. A filename and a set of metadata must be
5455 * @param device a pointer to the device to send the track to.
5456 * @param path the filename of a local file which will be sent.
5457 * @param metadata a track metadata set to be written along with the file.
5458 * After this call the field <code>metadata->item_id</code>
5459 * will contain the new track ID. Other fields such
5460 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5461 * or <code>metadata->storage_id</code> may also change during this
5462 * operation due to device restrictions, so do not rely on the
5463 * contents of this struct to be preserved in any way.
5465 * <li><code>metadata->parent_id</code> should be set to the parent
5466 * (e.g. folder) to store this track in. Since some
5467 * devices are a bit picky about where files
5468 * are placed, a default folder will be chosen if libmtp
5469 * has detected one for the current filetype and this
5470 * parameter is set to 0. If this is 0 and no default folder
5471 * can be found, the file will be stored in the root folder.
5472 * <li><code>metadata->storage_id</code> should be set to the
5473 * desired storage (e.g. memory card or whatever your device
5474 * presents) to store this track in. Setting this to 0 will store
5475 * the track on the primary storage.
5477 * @param callback a progress indicator function or NULL to ignore.
5478 * @param data a user-defined pointer that is passed along to
5479 * the <code>progress</code> function in order to
5480 * pass along some user defined data to the progress
5481 * updates. If not used, set this to NULL.
5482 * @return 0 if the transfer was successful, any other value means
5484 * @see LIBMTP_Send_Track_From_File_Descriptor()
5485 * @see LIBMTP_Send_File_From_File()
5486 * @see LIBMTP_Delete_Object()
5488 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5489 char const * const path, LIBMTP_track_t * const metadata,
5490 LIBMTP_progressfunc_t const callback,
5491 void const * const data)
5498 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5504 #ifdef USE_WINDOWS_IO_H
5505 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5507 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5510 if ( (fd = open(path, O_RDONLY)) == -1) {
5512 LIBMTP_ERROR("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5516 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5519 #ifdef USE_WINDOWS_IO_H
5531 * This helper function checks if a filename already exists on the device
5533 * @param string representing the filename
5534 * @return 0 if the filename doesn't exist, -1 if it does
5536 static int check_filename_exists(PTPParams* params, char const * const filename)
5540 for (i = 0; i < params->nrofobjects; i++) {
5541 char *fname = params->objects[i].oi.Filename;
5542 if ((fname != NULL) && (strcmp(filename, fname) == 0))
5552 * This helper function returns a unique filename, with a random string before the extension
5553 * @param string representing the original filename
5554 * @return a string representing the unique filename
5556 static char *generate_unique_filename(PTPParams* params, char const * const filename)
5559 char * extension_position;
5561 if (check_filename_exists(params, filename))
5563 extension_position = strrchr(filename,'.');
5565 if (extension_position == NULL)
5568 char basename[extension_position - filename + 1];
5569 strncpy(basename, filename, extension_position - filename);
5570 basename[extension_position - filename] = '\0';
5573 char newname[ strlen(basename) + 6 + strlen(extension_position)];
5574 snprintf(newname, strlen(basename) + 5 + strlen(extension_position), "%s_%d%s", basename, suffix, extension_position);
5575 while ((check_filename_exists(params, newname)) && (suffix < 1000000)) {
5577 snprintf(newname, strlen(basename) + 5 + strlen(extension_position), "%s_%d%s", basename, suffix, extension_position);
5579 return strdup(newname);
5583 return strdup(filename);
5588 * This function sends a track from a file descriptor to an
5589 * MTP device. A filename and a set of metadata must be
5591 * @param device a pointer to the device to send the track to.
5592 * @param fd the filedescriptor for a local file which will be sent.
5593 * @param metadata a track metadata set to be written along with the file.
5594 * After this call the field <code>metadata->item_id</code>
5595 * will contain the new track ID. Other fields such
5596 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5597 * or <code>metadata->storage_id</code> may also change during this
5598 * operation due to device restrictions, so do not rely on the
5599 * contents of this struct to be preserved in any way.
5601 * <li><code>metadata->parent_id</code> should be set to the parent
5602 * (e.g. folder) to store this track in. Since some
5603 * devices are a bit picky about where files
5604 * are placed, a default folder will be chosen if libmtp
5605 * has detected one for the current filetype and this
5606 * parameter is set to 0. If this is 0 and no default folder
5607 * can be found, the file will be stored in the root folder.
5608 * <li><code>metadata->storage_id</code> should be set to the
5609 * desired storage (e.g. memory card or whatever your device
5610 * presents) to store this track in. Setting this to 0 will store
5611 * the track on the primary storage.
5613 * @param callback a progress indicator function or NULL to ignore.
5614 * @param data a user-defined pointer that is passed along to
5615 * the <code>progress</code> function in order to
5616 * pass along some user defined data to the progress
5617 * updates. If not used, set this to NULL.
5618 * @return 0 if the transfer was successful, any other value means
5620 * @see LIBMTP_Send_Track_From_File()
5621 * @see LIBMTP_Delete_Object()
5623 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5624 int const fd, LIBMTP_track_t * const metadata,
5625 LIBMTP_progressfunc_t const callback,
5626 void const * const data)
5629 LIBMTP_file_t filedata;
5630 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5631 PTPParams *params = (PTPParams *) device->params;
5633 // Sanity check, is this really a track?
5634 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5635 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5636 "LIBMTP_Send_Track_From_File_Descriptor(): "
5637 "I don't think this is actually a track, strange filetype...");
5640 // Wrap around the file transfer function
5641 filedata.item_id = metadata->item_id;
5642 filedata.parent_id = metadata->parent_id;
5643 filedata.storage_id = metadata->storage_id;
5644 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5645 filedata.filename = generate_unique_filename(params, metadata->filename);
5648 filedata.filename = metadata->filename;
5650 filedata.filesize = metadata->filesize;
5651 filedata.filetype = metadata->filetype;
5652 filedata.next = NULL;
5654 subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5660 if (subcall_ret != 0) {
5661 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5662 "LIBMTP_Send_Track_From_File_Descriptor(): "
5663 "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5664 // We used to delete the file here, but don't... It might be OK after all.
5665 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5669 // Pick up new item (and parent, storage) ID
5670 metadata->item_id = filedata.item_id;
5671 metadata->parent_id = filedata.parent_id;
5672 metadata->storage_id = filedata.storage_id;
5674 // Set track metadata for the new fine track
5675 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5676 if (subcall_ret != 0) {
5677 // Subcall will add error to errorstack
5678 // We used to delete the file here, but don't... It might be OK after all.
5679 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5683 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5684 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5690 * This function sends a track from a handler function to an
5691 * MTP device. A filename and a set of metadata must be
5693 * @param device a pointer to the device to send the track to.
5694 * @param get_func the function to call when we have data.
5695 * @param priv the user-defined pointer that is passed to
5696 * <code>get_func</code>.
5697 * @param metadata a track metadata set to be written along with the file.
5698 * After this call the field <code>metadata->item_id</code>
5699 * will contain the new track ID. Other fields such
5700 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5701 * or <code>metadata->storage_id</code> may also change during this
5702 * operation due to device restrictions, so do not rely on the
5703 * contents of this struct to be preserved in any way.
5705 * <li><code>metadata->parent_id</code> should be set to the parent
5706 * (e.g. folder) to store this track in. Since some
5707 * devices are a bit picky about where files
5708 * are placed, a default folder will be chosen if libmtp
5709 * has detected one for the current filetype and this
5710 * parameter is set to 0. If this is 0 and no default folder
5711 * can be found, the file will be stored in the root folder.
5712 * <li><code>metadata->storage_id</code> should be set to the
5713 * desired storage (e.g. memory card or whatever your device
5714 * presents) to store this track in. Setting this to 0 will store
5715 * the track on the primary storage.
5717 * @param callback a progress indicator function or NULL to ignore.
5718 * @param data a user-defined pointer that is passed along to
5719 * the <code>progress</code> function in order to
5720 * pass along some user defined data to the progress
5721 * updates. If not used, set this to NULL.
5722 * @return 0 if the transfer was successful, any other value means
5724 * @see LIBMTP_Send_Track_From_File()
5725 * @see LIBMTP_Delete_Object()
5727 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5728 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5729 LIBMTP_progressfunc_t const callback,
5730 void const * const data)
5733 LIBMTP_file_t filedata;
5734 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5735 PTPParams *params = (PTPParams *) device->params;
5737 // Sanity check, is this really a track?
5738 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5739 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5740 "LIBMTP_Send_Track_From_Handler(): "
5741 "I don't think this is actually a track, strange filetype...");
5744 // Wrap around the file transfer function
5745 filedata.item_id = metadata->item_id;
5746 filedata.parent_id = metadata->parent_id;
5747 filedata.storage_id = metadata->storage_id;
5748 if FLAG_UNIQUE_FILENAMES(ptp_usb) {
5749 filedata.filename = generate_unique_filename(params, metadata->filename);
5752 filedata.filename = metadata->filename;
5754 filedata.filesize = metadata->filesize;
5755 filedata.filetype = metadata->filetype;
5756 filedata.next = NULL;
5758 subcall_ret = LIBMTP_Send_File_From_Handler(device,
5765 if (subcall_ret != 0) {
5766 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5767 "LIBMTP_Send_Track_From_Handler(): "
5768 "subcall to LIBMTP_Send_File_From_Handler failed.");
5769 // We used to delete the file here, but don't... It might be OK after all.
5770 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5774 // Pick up new item (and parent, storage) ID
5775 metadata->item_id = filedata.item_id;
5776 metadata->parent_id = filedata.parent_id;
5777 metadata->storage_id = filedata.storage_id;
5779 // Set track metadata for the new fine track
5780 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5781 if (subcall_ret != 0) {
5782 // Subcall will add error to errorstack
5783 // We used to delete the file here, but don't... It might be OK after all.
5784 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5788 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5789 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5795 * This function sends a local file to an MTP device.
5796 * A filename and a set of metadata must be
5798 * @param device a pointer to the device to send the track to.
5799 * @param path the filename of a local file which will be sent.
5800 * @param filedata a file metadata set to be written along with the file.
5801 * After this call the field <code>filedata->item_id</code>
5802 * will contain the new file ID. Other fields such
5803 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5804 * or <code>filedata->storage_id</code> may also change during this
5805 * operation due to device restrictions, so do not rely on the
5806 * contents of this struct to be preserved in any way.
5808 * <li><code>filedata->parent_id</code> should be set to the parent
5809 * (e.g. folder) to store this file in. If this is 0,
5810 * the file will be stored in the root folder.
5811 * <li><code>filedata->storage_id</code> should be set to the
5812 * desired storage (e.g. memory card or whatever your device
5813 * presents) to store this file in. Setting this to 0 will store
5814 * the file on the primary storage.
5816 * @param callback a progress indicator function or NULL to ignore.
5817 * @param data a user-defined pointer that is passed along to
5818 * the <code>progress</code> function in order to
5819 * pass along some user defined data to the progress
5820 * updates. If not used, set this to NULL.
5821 * @return 0 if the transfer was successful, any other value means
5823 * @see LIBMTP_Send_File_From_File_Descriptor()
5824 * @see LIBMTP_Delete_Object()
5826 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5827 char const * const path, LIBMTP_file_t * const filedata,
5828 LIBMTP_progressfunc_t const callback,
5829 void const * const data)
5836 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5842 #ifdef USE_WINDOWS_IO_H
5843 if ( (fd = _open(path, O_RDONLY|O_BINARY)) == -1 ) {
5845 if ( (fd = open(path, O_RDONLY|O_BINARY)) == -1 ) {
5848 if ( (fd = open(path, O_RDONLY)) == -1) {
5850 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5854 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5857 #ifdef USE_WINDOWS_IO_H
5867 * This function sends a generic file from a file descriptor to an
5868 * MTP device. A filename and a set of metadata must be
5871 * This can potentially be used for sending in a stream of unknown
5872 * length. Send music files with
5873 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5875 * @param device a pointer to the device to send the file to.
5876 * @param fd the filedescriptor for a local file which will be sent.
5877 * @param filedata a file metadata set to be written along with the file.
5878 * After this call the field <code>filedata->item_id</code>
5879 * will contain the new file ID. Other fields such
5880 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5881 * or <code>filedata->storage_id</code> may also change during this
5882 * operation due to device restrictions, so do not rely on the
5883 * contents of this struct to be preserved in any way.
5885 * <li><code>filedata->parent_id</code> should be set to the parent
5886 * (e.g. folder) to store this file in. If this is 0,
5887 * the file will be stored in the root folder.
5888 * <li><code>filedata->storage_id</code> should be set to the
5889 * desired storage (e.g. memory card or whatever your device
5890 * presents) to store this file in. Setting this to 0 will store
5891 * the file on the primary storage.
5893 * @param callback a progress indicator function or NULL to ignore.
5894 * @param data a user-defined pointer that is passed along to
5895 * the <code>progress</code> function in order to
5896 * pass along some user defined data to the progress
5897 * updates. If not used, set this to NULL.
5898 * @return 0 if the transfer was successful, any other value means
5900 * @see LIBMTP_Send_File_From_File()
5901 * @see LIBMTP_Send_Track_From_File_Descriptor()
5902 * @see LIBMTP_Delete_Object()
5904 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5905 int const fd, LIBMTP_file_t * const filedata,
5906 LIBMTP_progressfunc_t const callback,
5907 void const * const data)
5910 PTPParams *params = (PTPParams *) device->params;
5911 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5912 LIBMTP_file_t *newfilemeta;
5916 if (send_file_object_info(device, filedata))
5918 // no need to output an error since send_file_object_info will already have done so
5923 ptp_usb->callback_active = 1;
5924 // The callback will deactivate itself after this amount of data has been sent
5925 // One BULK header for the request, one for the data phase. No parameters to the request.
5926 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5927 ptp_usb->current_transfer_complete = 0;
5928 ptp_usb->current_transfer_callback = callback;
5929 ptp_usb->current_transfer_callback_data = data;
5932 * We might need to increase the timeout here, files can be pretty
5933 * large. Take the default timeout and add the calculated time for
5936 get_usb_device_timeout(ptp_usb, &oldtimeout);
5937 timeout = oldtimeout +
5938 (ptp_usb->current_transfer_total / guess_usb_speed(ptp_usb)) * 1000;
5939 set_usb_device_timeout(ptp_usb, timeout);
5941 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5943 ptp_usb->callback_active = 0;
5944 ptp_usb->current_transfer_callback = NULL;
5945 ptp_usb->current_transfer_callback_data = NULL;
5946 set_usb_device_timeout(ptp_usb, oldtimeout);
5948 if (ret == PTP_ERROR_CANCEL) {
5949 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5952 if (ret != PTP_RC_OK) {
5953 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5954 "Could not send object.");
5958 add_object_to_cache(device, filedata->item_id);
5961 * Get the device-assigned parent_id from the cache.
5962 * The operation that adds it to the cache will
5963 * look it up from the device, so we get the new
5964 * parent_id from the cache.
5966 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5967 if (newfilemeta != NULL) {
5968 filedata->parent_id = newfilemeta->parent_id;
5969 filedata->storage_id = newfilemeta->storage_id;
5970 LIBMTP_destroy_file_t(newfilemeta);
5972 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5973 "LIBMTP_Send_File_From_File_Descriptor(): "
5974 "Could not retrieve updated metadata.");
5982 * This function sends a generic file from a handler function to an
5983 * MTP device. A filename and a set of metadata must be
5986 * This can potentially be used for sending in a stream of unknown
5987 * length. Send music files with
5988 * <code>LIBMTP_Send_Track_From_Handler()</code>
5990 * @param device a pointer to the device to send the file to.
5991 * @param get_func the function to call to get data to write
5992 * @param priv a user-defined pointer that is passed along to
5993 * <code>get_func</code>. If not used, this is set to NULL.
5994 * @param filedata a file metadata set to be written along with the file.
5995 * After this call the field <code>filedata->item_id</code>
5996 * will contain the new file ID. Other fields such
5997 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5998 * or <code>filedata->storage_id</code> may also change during this
5999 * operation due to device restrictions, so do not rely on the
6000 * contents of this struct to be preserved in any way.
6002 * <li><code>filedata->parent_id</code> should be set to the parent
6003 * (e.g. folder) to store this file in. If this is 0,
6004 * the file will be stored in the root folder.
6005 * <li><code>filedata->storage_id</code> should be set to the
6006 * desired storage (e.g. memory card or whatever your device
6007 * presents) to store this file in. Setting this to 0 will store
6008 * the file on the primary storage.
6010 * @param callback a progress indicator function or NULL to ignore.
6011 * @param data a user-defined pointer that is passed along to
6012 * the <code>progress</code> function in order to
6013 * pass along some user defined data to the progress
6014 * updates. If not used, set this to NULL.
6015 * @return 0 if the transfer was successful, any other value means
6017 * @see LIBMTP_Send_File_From_File()
6018 * @see LIBMTP_Send_Track_From_File_Descriptor()
6019 * @see LIBMTP_Delete_Object()
6021 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
6022 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
6023 LIBMTP_progressfunc_t const callback, void const * const data)
6026 PTPParams *params = (PTPParams *) device->params;
6027 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6028 LIBMTP_file_t *newfilemeta;
6030 if (send_file_object_info(device, filedata))
6032 // no need to output an error since send_file_object_info will already have done so
6037 ptp_usb->callback_active = 1;
6038 // The callback will deactivate itself after this amount of data has been sent
6039 // One BULK header for the request, one for the data phase. No parameters to the request.
6040 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
6041 ptp_usb->current_transfer_complete = 0;
6042 ptp_usb->current_transfer_callback = callback;
6043 ptp_usb->current_transfer_callback_data = data;
6045 MTPDataHandler mtp_handler;
6046 mtp_handler.getfunc = get_func;
6047 mtp_handler.putfunc = NULL;
6048 mtp_handler.priv = priv;
6050 PTPDataHandler handler;
6051 handler.getfunc = get_func_wrapper;
6052 handler.putfunc = NULL;
6053 handler.priv = &mtp_handler;
6055 ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
6057 ptp_usb->callback_active = 0;
6058 ptp_usb->current_transfer_callback = NULL;
6059 ptp_usb->current_transfer_callback_data = NULL;
6061 if (ret == PTP_ERROR_CANCEL) {
6062 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
6065 if (ret != PTP_RC_OK) {
6066 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
6067 "Could not send object.");
6071 add_object_to_cache(device, filedata->item_id);
6074 * Get the device-assined parent_id from the cache.
6075 * The operation that adds it to the cache will
6076 * look it up from the device, so we get the new
6077 * parent_id from the cache.
6079 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
6080 if (newfilemeta != NULL) {
6081 filedata->parent_id = newfilemeta->parent_id;
6082 filedata->storage_id = newfilemeta->storage_id;
6083 LIBMTP_destroy_file_t(newfilemeta);
6085 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
6086 "LIBMTP_Send_File_From_Handler(): "
6087 "Could not retrieve updated metadata.");
6095 * This function sends the file object info, ready for sendobject
6096 * @param device a pointer to the device to send the file to.
6097 * @param filedata a file metadata set to be written along with the file.
6098 * @return 0 if the transfer was successful, any other value means
6101 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
6103 PTPParams *params = (PTPParams *) device->params;
6104 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6106 int use_primary_storage = 1;
6107 uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
6108 LIBMTP_devicestorage_t *storage;
6109 uint32_t localph = filedata->parent_id;
6114 // Sanity check: no zerolength files on some devices?
6115 // If the zerolength files cause problems on some devices,
6116 // then add a bug flag for this.
6117 if (filedata->filesize == 0) {
6118 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
6119 "File of zero size.");
6123 if (filedata->storage_id != 0) {
6124 store = filedata->storage_id;
6126 store = get_suggested_storage_id(device, filedata->filesize, localph);
6129 // Detect if something non-primary is in use.
6130 storage = device->storage;
6131 if (storage != NULL && store != storage->id) {
6132 use_primary_storage = 0;
6136 * If no destination folder was given, look up a default
6137 * folder if possible. Perhaps there is some way of retrieveing
6138 * the default folder for different forms of content, what
6139 * do I know, we use a fixed list in lack of any better method.
6140 * Some devices obviously need to have their files in certain
6141 * folders in order to find/display them at all (hello Creative),
6142 * so we have to have a method for this. We only do this if the
6143 * primary storage is in use.
6146 if (localph == 0 && use_primary_storage) {
6147 if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
6148 localph = device->default_music_folder;
6149 } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
6150 localph = device->default_video_folder;
6151 } else if (of == PTP_OFC_EXIF_JPEG ||
6152 of == PTP_OFC_JP2 ||
6153 of == PTP_OFC_JPX ||
6154 of == PTP_OFC_JFIF ||
6155 of == PTP_OFC_TIFF ||
6156 of == PTP_OFC_TIFF_IT ||
6157 of == PTP_OFC_BMP ||
6158 of == PTP_OFC_GIF ||
6159 of == PTP_OFC_PICT ||
6160 of == PTP_OFC_PNG ||
6161 of == PTP_OFC_MTP_WindowsImageFormat) {
6162 localph = device->default_picture_folder;
6163 } else if (of == PTP_OFC_MTP_vCalendar1 ||
6164 of == PTP_OFC_MTP_vCalendar2 ||
6165 of == PTP_OFC_MTP_UndefinedContact ||
6166 of == PTP_OFC_MTP_vCard2 ||
6167 of == PTP_OFC_MTP_vCard3 ||
6168 of == PTP_OFC_MTP_UndefinedCalendarItem) {
6169 localph = device->default_organizer_folder;
6170 } else if (of == PTP_OFC_Text) {
6171 localph = device->default_text_folder;
6175 // Here we wire the type to unknown on bugged, but
6176 // Ogg or FLAC-supportive devices.
6177 if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
6178 of = PTP_OFC_Undefined;
6180 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
6181 of = PTP_OFC_Undefined;
6184 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
6185 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
6187 * MTP enhanched does it this way (from a sniff):
6188 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6189 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
6190 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
6191 * Length: 0x00000020
6192 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
6194 * Transaction ID: 0x0000001B
6195 * Param1: 0x00010001 <- store
6196 * Param2: 0xffffffff <- parent handle (-1 ?)
6197 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
6198 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
6199 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
6201 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
6202 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
6203 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
6204 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
6205 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
6206 * 00 4F DC 02 00 01 - dc4f = non consumable
6207 * Length: 0x00000046
6208 * Type: 0x0002 PTP_USB_CONTAINER_DATA
6210 * Transaction ID: 0x0000001B
6212 * 0x00000003 <- Number of metadata items
6213 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6214 * 0xdc07 <- metadata type: file name
6215 * 0xffff <- metadata type: string
6216 * 0x0d <- number of (uint16_t) characters
6217 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
6218 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6219 * 0xdc03 <- metadata type: protection status
6220 * 0x0004 <- metadata type: uint16_t
6221 * 0x0000 <- not protected
6222 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
6223 * 0xdc4f <- non consumable
6224 * 0x0002 <- metadata type: uint8_t
6225 * 0x01 <- non-consumable (this device cannot display PDF)
6227 * <- Read 0x18 bytes back
6228 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
6229 * 00 00 00 00 01 40 00 00
6230 * Length: 0x000000018
6231 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
6232 * Code: 0x2001 PTP_OK
6233 * Transaction ID: 0x0000001B
6234 * Param1: 0x00010001 <- store
6235 * Param2: 0x00000000 <- parent handle
6236 * Param3: 0x00004001 <- new file/object ID
6238 * -> PTP_OC_SendObject (0x100d)
6239 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
6240 * -> ... all the bytes ...
6241 * <- Read 0x0c bytes back
6242 * 0C 00 00 00 03 00 01 20 1C 00 00 00
6243 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
6245 MTPProperties *props = NULL;
6247 MTPProperties *prop = NULL;
6248 uint16_t *properties = NULL;
6249 uint32_t propcnt = 0;
6251 // default parent handle
6253 localph = 0xFFFFFFFFU; // Set to -1
6255 // Must be 0x00000000U for new objects
6256 filedata->item_id = 0x00000000U;
6258 ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
6260 for (i=0;i<propcnt;i++) {
6261 PTPObjectPropDesc opd;
6263 ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
6264 if (ret != PTP_RC_OK) {
6265 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6266 "could not get property description.");
6267 } else if (opd.GetSet) {
6268 switch (properties[i]) {
6269 case PTP_OPC_ObjectFileName:
6270 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6271 prop->ObjectHandle = filedata->item_id;
6272 prop->property = PTP_OPC_ObjectFileName;
6273 prop->datatype = PTP_DTC_STR;
6274 if (filedata->filename != NULL) {
6275 prop->propval.str = strdup(filedata->filename);
6276 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6277 strip_7bit_from_utf8(prop->propval.str);
6281 case PTP_OPC_ProtectionStatus:
6282 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6283 prop->ObjectHandle = filedata->item_id;
6284 prop->property = PTP_OPC_ProtectionStatus;
6285 prop->datatype = PTP_DTC_UINT16;
6286 prop->propval.u16 = 0x0000U; /* Not protected */
6288 case PTP_OPC_NonConsumable:
6289 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6290 prop->ObjectHandle = filedata->item_id;
6291 prop->property = PTP_OPC_NonConsumable;
6292 prop->datatype = PTP_DTC_UINT8;
6293 prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
6296 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6297 prop->ObjectHandle = filedata->item_id;
6298 prop->property = PTP_OPC_Name;
6299 prop->datatype = PTP_DTC_STR;
6300 if (filedata->filename != NULL)
6301 prop->propval.str = strdup(filedata->filename);
6303 case PTP_OPC_DateModified:
6304 // Tag with current time if that is supported
6305 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6306 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
6307 prop->ObjectHandle = filedata->item_id;
6308 prop->property = PTP_OPC_DateModified;
6309 prop->datatype = PTP_DTC_STR;
6310 prop->propval.str = get_iso8601_stamp();
6311 filedata->modificationdate = time(NULL);
6316 ptp_free_objectpropdesc(&opd);
6320 if (nrofprops == 0 || props == NULL) {
6321 LIBMTP_INFO("prop list doesn't exist");
6325 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
6326 of, filedata->filesize, props, nrofprops);
6328 /* Free property list */
6329 ptp_destroy_object_prop_list(props, nrofprops);
6331 if (ret != PTP_RC_OK) {
6332 add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
6333 "Could not send object property list.");
6334 if (ret == PTP_RC_AccessDenied) {
6335 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6339 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
6340 PTPObjectInfo new_file;
6342 memset(&new_file, 0, sizeof(PTPObjectInfo));
6344 new_file.Filename = filedata->filename;
6345 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6346 strip_7bit_from_utf8(new_file.Filename);
6348 if (filedata->filesize > 0xFFFFFFFFL) {
6349 // This is a kludge in the MTP standard for large files.
6350 new_file.ObjectCompressedSize = (uint32_t) 0xFFFFFFFF;
6352 new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
6354 new_file.ObjectFormat = of;
6355 new_file.StorageID = store;
6356 new_file.ParentObject = localph;
6357 new_file.ModificationDate = time(NULL);
6359 // Create the object
6360 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
6362 if (ret != PTP_RC_OK) {
6363 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
6364 "Could not send object info.");
6365 if (ret == PTP_RC_AccessDenied) {
6366 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6370 // NOTE: the char* pointers inside new_file are not copies so don't
6371 // try to destroy this objectinfo!
6374 // Now there IS an object with this parent handle.
6375 filedata->parent_id = localph;
6381 * This function updates the MTP track object metadata on a
6382 * single file identified by an object ID.
6383 * @param device a pointer to the device to update the track
6385 * @param metadata a track metadata set to be written to the file.
6386 * notice that the <code>track_id</code> field of the
6387 * metadata structure must be correct so that the
6388 * function can update the right file. If some properties
6389 * of this metadata are set to NULL (strings) or 0
6390 * (numerical values) they will be discarded and the
6391 * track will not be tagged with these blank values.
6392 * @return 0 on success, any other value means failure. If some
6393 * or all of the properties fail to update we will still
6394 * return success. On some devices (notably iRiver T30)
6395 * properties that exist cannot be updated.
6397 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
6398 LIBMTP_track_t const * const metadata)
6401 PTPParams *params = (PTPParams *) device->params;
6402 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6404 uint16_t *properties = NULL;
6405 uint32_t propcnt = 0;
6407 // First see which properties can be set on this file format and apply accordingly
6408 // i.e only try to update this metadata for object tags that exist on the current player.
6409 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
6410 if (ret != PTP_RC_OK) {
6411 // Just bail out for now, nothing is ever set.
6412 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6413 "could not retrieve supported object properties.");
6416 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6417 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6418 MTPProperties *props = NULL;
6419 MTPProperties *prop = NULL;
6422 for (i=0;i<propcnt;i++) {
6423 PTPObjectPropDesc opd;
6425 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6426 if (ret != PTP_RC_OK) {
6427 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6428 "could not get property description.");
6429 } else if (opd.GetSet) {
6430 switch (properties[i]) {
6432 if (metadata->title == NULL)
6434 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6435 prop->ObjectHandle = metadata->item_id;
6436 prop->property = PTP_OPC_Name;
6437 prop->datatype = PTP_DTC_STR;
6438 prop->propval.str = strdup(metadata->title);
6440 case PTP_OPC_AlbumName:
6441 if (metadata->album == NULL)
6443 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6444 prop->ObjectHandle = metadata->item_id;
6445 prop->property = PTP_OPC_AlbumName;
6446 prop->datatype = PTP_DTC_STR;
6447 prop->propval.str = strdup(metadata->album);
6449 case PTP_OPC_Artist:
6450 if (metadata->artist == NULL)
6452 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6453 prop->ObjectHandle = metadata->item_id;
6454 prop->property = PTP_OPC_Artist;
6455 prop->datatype = PTP_DTC_STR;
6456 prop->propval.str = strdup(metadata->artist);
6458 case PTP_OPC_Composer:
6459 if (metadata->composer == NULL)
6461 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6462 prop->ObjectHandle = metadata->item_id;
6463 prop->property = PTP_OPC_Composer;
6464 prop->datatype = PTP_DTC_STR;
6465 prop->propval.str = strdup(metadata->composer);
6468 if (metadata->genre == NULL)
6470 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6471 prop->ObjectHandle = metadata->item_id;
6472 prop->property = PTP_OPC_Genre;
6473 prop->datatype = PTP_DTC_STR;
6474 prop->propval.str = strdup(metadata->genre);
6476 case PTP_OPC_Duration:
6477 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6478 prop->ObjectHandle = metadata->item_id;
6479 prop->property = PTP_OPC_Duration;
6480 prop->datatype = PTP_DTC_UINT32;
6481 prop->propval.u32 = adjust_u32(metadata->duration, &opd);
6484 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6485 prop->ObjectHandle = metadata->item_id;
6486 prop->property = PTP_OPC_Track;
6487 prop->datatype = PTP_DTC_UINT16;
6488 prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
6490 case PTP_OPC_OriginalReleaseDate:
6491 if (metadata->date == NULL)
6493 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6494 prop->ObjectHandle = metadata->item_id;
6495 prop->property = PTP_OPC_OriginalReleaseDate;
6496 prop->datatype = PTP_DTC_STR;
6497 prop->propval.str = strdup(metadata->date);
6499 case PTP_OPC_SampleRate:
6500 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6501 prop->ObjectHandle = metadata->item_id;
6502 prop->property = PTP_OPC_SampleRate;
6503 prop->datatype = PTP_DTC_UINT32;
6504 prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
6506 case PTP_OPC_NumberOfChannels:
6507 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6508 prop->ObjectHandle = metadata->item_id;
6509 prop->property = PTP_OPC_NumberOfChannels;
6510 prop->datatype = PTP_DTC_UINT16;
6511 prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
6513 case PTP_OPC_AudioWAVECodec:
6514 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6515 prop->ObjectHandle = metadata->item_id;
6516 prop->property = PTP_OPC_AudioWAVECodec;
6517 prop->datatype = PTP_DTC_UINT32;
6518 prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
6520 case PTP_OPC_AudioBitRate:
6521 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6522 prop->ObjectHandle = metadata->item_id;
6523 prop->property = PTP_OPC_AudioBitRate;
6524 prop->datatype = PTP_DTC_UINT32;
6525 prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
6527 case PTP_OPC_BitRateType:
6528 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6529 prop->ObjectHandle = metadata->item_id;
6530 prop->property = PTP_OPC_BitRateType;
6531 prop->datatype = PTP_DTC_UINT16;
6532 prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
6534 case PTP_OPC_Rating:
6535 // TODO: shall this be set for rating 0?
6536 if (metadata->rating == 0)
6538 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6539 prop->ObjectHandle = metadata->item_id;
6540 prop->property = PTP_OPC_Rating;
6541 prop->datatype = PTP_DTC_UINT16;
6542 prop->propval.u16 = adjust_u16(metadata->rating, &opd);
6544 case PTP_OPC_UseCount:
6545 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6546 prop->ObjectHandle = metadata->item_id;
6547 prop->property = PTP_OPC_UseCount;
6548 prop->datatype = PTP_DTC_UINT32;
6549 prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
6551 case PTP_OPC_DateModified:
6552 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6553 // Tag with current time if that is supported
6554 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6555 prop->ObjectHandle = metadata->item_id;
6556 prop->property = PTP_OPC_DateModified;
6557 prop->datatype = PTP_DTC_STR;
6558 prop->propval.str = get_iso8601_stamp();
6565 ptp_free_objectpropdesc(&opd);
6568 // NOTE: File size is not updated, this should not change anyway.
6569 // neither will we change the filename.
6571 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6573 ptp_destroy_object_prop_list(props, nrofprops);
6575 if (ret != PTP_RC_OK) {
6576 // TODO: return error of which property we couldn't set
6577 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6578 "could not set object property list.");
6583 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6584 for (i=0;i<propcnt;i++) {
6585 PTPObjectPropDesc opd;
6587 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6588 if (ret != PTP_RC_OK) {
6589 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6590 "could not get property description.");
6591 } else if (opd.GetSet) {
6592 switch (properties[i]) {
6595 ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6597 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6598 "could not set track title.");
6601 case PTP_OPC_AlbumName:
6603 ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6605 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6606 "could not set track album name.");
6609 case PTP_OPC_Artist:
6611 ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6613 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6614 "could not set track artist name.");
6617 case PTP_OPC_Composer:
6619 ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6621 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6622 "could not set track composer name.");
6626 // Update genre (but only if valid)
6627 if (metadata->genre) {
6628 ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6630 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6631 "could not set genre.");
6635 case PTP_OPC_Duration:
6637 if (metadata->duration != 0) {
6638 ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6640 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6641 "could not set track duration.");
6646 // Update track number.
6647 if (metadata->tracknumber != 0) {
6648 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6650 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6651 "could not set track tracknumber.");
6655 case PTP_OPC_OriginalReleaseDate:
6656 // Update creation datetime
6657 // The date can be zero, but some devices do not support setting zero
6658 // dates (and it seems that a zero date should never be set anyway)
6659 if (metadata->date) {
6660 ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6662 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6663 "could not set track release date.");
6667 // These are, well not so important.
6668 case PTP_OPC_SampleRate:
6669 // Update sample rate
6670 if (metadata->samplerate != 0) {
6671 ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6673 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6674 "could not set samplerate.");
6678 case PTP_OPC_NumberOfChannels:
6679 // Update number of channels
6680 if (metadata->nochannels != 0) {
6681 ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6683 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6684 "could not set number of channels.");
6688 case PTP_OPC_AudioWAVECodec:
6689 // Update WAVE codec
6690 if (metadata->wavecodec != 0) {
6691 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6693 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6694 "could not set WAVE codec.");
6698 case PTP_OPC_AudioBitRate:
6700 if (metadata->bitrate != 0) {
6701 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6703 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6704 "could not set bitrate.");
6708 case PTP_OPC_BitRateType:
6709 // Update bitrate type
6710 if (metadata->bitratetype != 0) {
6711 ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6713 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6714 "could not set bitratetype.");
6718 case PTP_OPC_Rating:
6719 // Update user rating
6720 // TODO: shall this be set for rating 0?
6721 if (metadata->rating != 0) {
6722 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6724 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6725 "could not set user rating.");
6729 case PTP_OPC_UseCount:
6730 // Update use count, set even to zero if desired.
6731 ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6733 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6734 "could not set use count.");
6737 case PTP_OPC_DateModified:
6738 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6739 // Update modification time if supported
6740 char *tmpstamp = get_iso8601_stamp();
6741 ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6743 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6744 "could not set modification date.");
6750 // NOTE: File size is not updated, this should not change anyway.
6751 // neither will we change the filename.
6756 ptp_free_objectpropdesc(&opd);
6759 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6760 "Your device doesn't seem to support any known way of setting metadata.");
6765 // update cached object properties if metadata cache exists
6766 update_metadata_cache(device, metadata->item_id);
6774 * This function deletes a single file, track, playlist, folder or
6775 * any other object off the MTP device, identified by the object ID.
6777 * If you delete a folder, there is no guarantee that the device will
6778 * really delete all the files that were in that folder, rather it is
6779 * expected that they will not be deleted, and will turn up in object
6780 * listings with parent set to a non-existant object ID. The safe way
6781 * to do this is to recursively delete all files (and folders) contained
6782 * in the folder, then the folder itself.
6784 * @param device a pointer to the device to delete the object from.
6785 * @param object_id the object to delete.
6786 * @return 0 on success, any other value means failure.
6788 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6792 PTPParams *params = (PTPParams *) device->params;
6794 ret = ptp_deleteobject(params, object_id, 0);
6795 if (ret != PTP_RC_OK) {
6796 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6804 * Internal function to update an object filename property.
6806 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6807 uint32_t object_id, uint16_t ptp_type,
6808 const char **newname_ptr)
6810 PTPParams *params = (PTPParams *) device->params;
6811 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6812 PTPObjectPropDesc opd;
6816 // See if we can modify the filename on this kind of files.
6817 ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6818 if (ret != PTP_RC_OK) {
6819 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6820 "could not get property description.");
6825 ptp_free_objectpropdesc(&opd);
6826 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6827 " property is not settable.");
6828 // TODO: we COULD actually upload/download the object here, if we feel
6829 // like wasting time for the user.
6833 newname = strdup(*newname_ptr);
6835 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6836 strip_7bit_from_utf8(newname);
6839 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6840 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6841 MTPProperties *props = NULL;
6842 MTPProperties *prop = NULL;
6845 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6846 prop->ObjectHandle = object_id;
6847 prop->property = PTP_OPC_ObjectFileName;
6848 prop->datatype = PTP_DTC_STR;
6849 prop->propval.str = newname;
6851 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6853 ptp_destroy_object_prop_list(props, nrofprops);
6855 if (ret != PTP_RC_OK) {
6856 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6857 " could not set object property list.");
6858 ptp_free_objectpropdesc(&opd);
6861 } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6862 ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6864 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6865 " could not set object filename.");
6866 ptp_free_objectpropdesc(&opd);
6871 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6872 " your device doesn't seem to support any known way of setting metadata.");
6873 ptp_free_objectpropdesc(&opd);
6877 ptp_free_objectpropdesc(&opd);
6879 // update cached object properties if metadata cache exists
6880 update_metadata_cache(device, object_id);
6886 * This function renames a single file.
6887 * This simply means that the PTP_OPC_ObjectFileName property
6888 * is updated, if this is supported by the device.
6890 * @param device a pointer to the device that contains the file.
6891 * @param file the file metadata of the file to rename.
6892 * On success, the filename member is updated. Be aware, that
6893 * this name can be different than newname depending of device restrictions.
6894 * @param newname the new filename for this object.
6895 * @return 0 on success, any other value means failure.
6897 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6898 LIBMTP_file_t *file, const char *newname)
6902 ret = set_object_filename(device, file->item_id,
6903 map_libmtp_type_to_ptp_type(file->filetype),
6910 free(file->filename);
6911 file->filename = strdup(newname);
6916 * This function renames a single folder.
6917 * This simply means that the PTP_OPC_ObjectFileName property
6918 * is updated, if this is supported by the device.
6920 * @param device a pointer to the device that contains the file.
6921 * @param folder the folder metadata of the folder to rename.
6922 * On success, the name member is updated. Be aware, that
6923 * this name can be different than newname depending of device restrictions.
6924 * @param newname the new name for this object.
6925 * @return 0 on success, any other value means failure.
6927 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6928 LIBMTP_folder_t *folder, const char* newname)
6932 ret = set_object_filename(device, folder->folder_id,
6933 PTP_OFC_Association,
6941 folder->name = strdup(newname);
6946 * This function renames a single track.
6947 * This simply means that the PTP_OPC_ObjectFileName property
6948 * is updated, if this is supported by the device.
6950 * @param device a pointer to the device that contains the file.
6951 * @param track the track metadata of the track to rename.
6952 * On success, the filename member is updated. Be aware, that
6953 * this name can be different than newname depending of device restrictions.
6954 * @param newname the new filename for this object.
6955 * @return 0 on success, any other value means failure.
6957 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6958 LIBMTP_track_t *track, const char* newname)
6962 ret = set_object_filename(device, track->item_id,
6963 map_libmtp_type_to_ptp_type(track->filetype),
6970 free(track->filename);
6971 track->filename = strdup(newname);
6976 * This function renames a single playlist object file holder.
6977 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6978 * property is updated, if this is supported by the device.
6979 * The playlist filename should nominally end with an extension
6982 * NOTE: if you want to change the metadata the device display
6983 * about a playlist you must <i>not</i> use this function,
6984 * use <code>LIBMTP_Update_Playlist()</code> instead!
6986 * @param device a pointer to the device that contains the file.
6987 * @param playlist the playlist metadata of the playlist to rename.
6988 * On success, the name member is updated. Be aware, that
6989 * this name can be different than newname depending of device restrictions.
6990 * @param newname the new name for this object.
6991 * @return 0 on success, any other value means failure.
6992 * @see LIBMTP_Update_Playlist()
6994 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
6995 LIBMTP_playlist_t *playlist, const char* newname)
6999 ret = set_object_filename(device, playlist->playlist_id,
7000 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7007 free(playlist->name);
7008 playlist->name = strdup(newname);
7013 * This function renames a single album.
7014 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
7015 * property is updated, if this is supported by the device.
7016 * The album filename should nominally end with an extension
7019 * NOTE: if you want to change the metadata the device display
7020 * about a playlist you must <i>not</i> use this function,
7021 * use <code>LIBMTP_Update_Album()</code> instead!
7023 * @param device a pointer to the device that contains the file.
7024 * @param album the album metadata of the album to rename.
7025 * On success, the name member is updated. Be aware, that
7026 * this name can be different than newname depending of device restrictions.
7027 * @param newname the new name for this object.
7028 * @return 0 on success, any other value means failure.
7029 * @see LIBMTP_Update_Album()
7031 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
7032 LIBMTP_album_t *album, const char* newname)
7036 ret = set_object_filename(device, album->album_id,
7037 PTP_OFC_MTP_AbstractAudioAlbum,
7045 album->name = strdup(newname);
7050 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
7053 * @see LIBMTP_Set_File_Name()
7054 * @see LIBMTP_Set_Track_Name()
7055 * @see LIBMTP_Set_Folder_Name()
7056 * @see LIBMTP_Set_Playlist_Name()
7057 * @see LIBMTP_Set_Album_Name()
7059 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
7060 uint32_t object_id, char* newname)
7063 LIBMTP_file_t *file;
7065 file = LIBMTP_Get_Filemetadata(device, object_id);
7068 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
7069 "could not get file metadata for target object.");
7073 ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
7081 * Helper function. This indicates if a track exists on the device
7082 * @param device a pointer to the device to get the track from.
7083 * @param id the track ID of the track to retrieve.
7084 * @return TRUE (!=0) if the track exists, FALSE (0) if not
7086 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
7089 PTPParams *params = (PTPParams *) device->params;
7093 ret = ptp_object_want (params, id, 0, &ob);
7094 if (ret == PTP_RC_OK)
7100 * This creates a new folder structure and allocates memory
7101 * for it. Notice that if you add strings to this structure they
7102 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
7103 * operation later, so be careful of using strdup() when assigning
7106 * @return a pointer to the newly allocated folder structure.
7107 * @see LIBMTP_destroy_folder_t()
7109 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
7111 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
7117 new->storage_id = 0;
7119 new->sibling = NULL;
7125 * This recursively deletes the memory for a folder structure.
7126 * This shall typically be called on a top-level folder list to
7127 * detsroy the entire folder tree.
7129 * @param folder folder structure to destroy
7130 * @see LIBMTP_new_folder_t()
7132 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
7135 if(folder == NULL) {
7139 //Destroy from the bottom up
7140 if(folder->child != NULL) {
7141 LIBMTP_destroy_folder_t(folder->child);
7144 if(folder->sibling != NULL) {
7145 LIBMTP_destroy_folder_t(folder->sibling);
7148 if(folder->name != NULL) {
7156 * Helper function. Returns a folder structure for a
7159 * @param folderlist list of folders to search
7160 * @id id of folder to look for
7161 * @return a folder or NULL if not found
7163 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
7165 LIBMTP_folder_t *ret = NULL;
7167 if(folderlist == NULL) {
7171 if(folderlist->folder_id == id) {
7175 if(folderlist->sibling) {
7176 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
7179 if(folderlist->child && ret == NULL) {
7180 ret = LIBMTP_Find_Folder(folderlist->child, id);
7187 * Function used to recursively get subfolders from params.
7189 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
7191 LIBMTP_folder_t *retfolders = NULL;
7192 LIBMTP_folder_t *children, *iter, *curr;
7194 iter = list->sibling;
7195 while(iter != list) {
7196 if (iter->parent_id != parent) {
7197 iter = iter->sibling;
7201 /* We know that iter is a child of 'parent', therefore we can safely
7202 * hold on to 'iter' locally since no one else will steal it
7203 * from the 'list' as we recurse. */
7204 children = get_subfolders_for_folder(list, iter->folder_id);
7207 iter = iter->sibling;
7209 // Remove curr from the list.
7210 curr->child->sibling = curr->sibling;
7211 curr->sibling->child = curr->child;
7213 // Attach the children to curr.
7214 curr->child = children;
7216 // Put this folder into the list of siblings.
7217 curr->sibling = retfolders;
7225 * This returns a list of all folders available
7226 * on the current MTP device.
7228 * @param device a pointer to the device to get the folder listing for.
7229 * @param storage a storage ID to get the folder list from
7230 * @return a list of folders
7232 LIBMTP_folder_t *LIBMTP_Get_Folder_List_For_Storage(LIBMTP_mtpdevice_t *device,
7233 uint32_t const storage)
7235 PTPParams *params = (PTPParams *) device->params;
7236 LIBMTP_folder_t head, *rv;
7239 // Get all the handles if we haven't already done that
7240 if (params->nrofobjects == 0) {
7241 flush_handles(device);
7245 * This creates a temporary list of the folders, this is in a
7246 * reverse order and uses the Folder pointers that are already
7247 * in the Folder structure. From this we can then build up the
7248 * folder hierarchy with only looking at this temporary list,
7249 * and removing the folders from this temporary list as we go.
7250 * This significantly reduces the number of operations that we
7251 * have to do in building the folder hierarchy. Also since the
7252 * temp list is in reverse order, when we prepend to the sibling
7253 * list things are in the same order as they were originally
7254 * in the handle list.
7256 head.sibling = &head;
7258 for (i = 0; i < params->nrofobjects; i++) {
7259 LIBMTP_folder_t *folder;
7262 ob = ¶ms->objects[i];
7263 if (ob->oi.ObjectFormat != PTP_OFC_Association) {
7267 if (storage != PTP_GOH_ALL_STORAGE && storage != ob->oi.StorageID) {
7272 * Do we know how to handle these? They are part
7273 * of the MTP 1.0 specification paragraph 3.6.4.
7274 * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
7275 * should be called on these to get the contained objects, but
7276 * we basically don't care. Hopefully parent_id is maintained for all
7277 * children, because we rely on that instead.
7279 if (ob->oi.AssociationDesc != 0x00000000U) {
7280 LIBMTP_INFO("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
7283 // Create a folder struct...
7284 folder = LIBMTP_new_folder_t();
7285 if (folder == NULL) {
7286 // malloc failure or so.
7289 folder->folder_id = ob->oid;
7290 folder->parent_id = ob->oi.ParentObject;
7291 folder->storage_id = ob->oi.StorageID;
7292 folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
7294 // pretend sibling says next, and child says prev.
7295 folder->sibling = head.sibling;
7296 folder->child = &head;
7297 head.sibling->child = folder;
7298 head.sibling = folder;
7301 // We begin at the given root folder and get them all recursively
7302 rv = get_subfolders_for_folder(&head, 0x00000000U);
7304 // Some buggy devices may have some files in the "root folder"
7305 // 0xffffffff so if 0x00000000 didn't return any folders,
7306 // look for children of the root 0xffffffffU
7308 rv = get_subfolders_for_folder(&head, 0xffffffffU);
7310 LIBMTP_ERROR("Device have files in \"root folder\" 0xffffffffU - "
7311 "this is a firmware bug (but continuing)\n");
7314 // The temp list should be empty. Clean up any orphans just in case.
7315 while(head.sibling != &head) {
7316 LIBMTP_folder_t *curr = head.sibling;
7318 LIBMTP_INFO("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
7321 curr->sibling->child = curr->child;
7322 curr->child->sibling = curr->sibling;
7324 curr->sibling = NULL;
7325 LIBMTP_destroy_folder_t(curr);
7332 * This returns a list of all folders available
7333 * on the current MTP device.
7335 * @param device a pointer to the device to get the folder listing for.
7336 * @return a list of folders
7338 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
7340 return LIBMTP_Get_Folder_List_For_Storage(device, PTP_GOH_ALL_STORAGE);
7344 * This create a folder on the current MTP device. The PTP name
7345 * for a folder is "association". The PTP/MTP devices does not
7346 * have an internal "folder" concept really, it contains a flat
7347 * list of all files and some file are "associations" that other
7348 * files and folders may refer to as its "parent".
7350 * @param device a pointer to the device to create the folder on.
7351 * @param name the name of the new folder. Note this can be modified
7352 * if the device does not support all the characters in the
7354 * @param parent_id id of parent folder to add the new folder to,
7355 * or 0xFFFFFFFF to put it in the root directory.
7356 * @param storage_id id of the storage to add this new folder to.
7357 * notice that you cannot mismatch storage id and parent id:
7358 * they must both be on the same storage! Pass in 0 if you
7359 * want to create this folder on the default storage.
7360 * @return id to new folder or 0 if an error occured
7362 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
7363 uint32_t parent_id, uint32_t storage_id)
7365 PTPParams *params = (PTPParams *) device->params;
7366 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7367 uint32_t parenthandle = 0;
7369 PTPObjectInfo new_folder;
7371 uint32_t new_id = 0;
7373 if (storage_id == 0) {
7374 // I'm just guessing that a folder may require 512 bytes
7375 store = get_suggested_storage_id(device, 512, parent_id);
7379 parenthandle = parent_id;
7381 memset(&new_folder, 0, sizeof(new_folder));
7382 new_folder.Filename = name;
7383 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7384 strip_7bit_from_utf8(new_folder.Filename);
7386 new_folder.ObjectCompressedSize = 0;
7387 new_folder.ObjectFormat = PTP_OFC_Association;
7388 new_folder.ProtectionStatus = PTP_PS_NoProtection;
7389 new_folder.AssociationType = PTP_AT_GenericFolder;
7390 new_folder.ParentObject = parent_id;
7391 new_folder.StorageID = store;
7393 // Create the object
7394 if (!(params->device_flags & DEVICE_FLAG_BROKEN_SEND_OBJECT_PROPLIST) &&
7395 ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
7396 MTPProperties *props = (MTPProperties*)calloc(2,sizeof(MTPProperties));
7400 props[0].property = PTP_OPC_ObjectFileName;
7401 props[0].datatype = PTP_DTC_STR;
7402 props[0].propval.str = name;
7404 props[1].property = PTP_OPC_Name;
7405 props[1].datatype = PTP_DTC_STR;
7406 props[1].propval.str = name;
7408 ret = ptp_mtp_sendobjectproplist(params, &store, &parenthandle, &new_id, PTP_OFC_Association,
7412 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
7415 if (ret != PTP_RC_OK) {
7416 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
7417 if (ret == PTP_RC_AccessDenied) {
7418 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7422 // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
7425 add_object_to_cache(device, new_id);
7431 * This creates a new playlist metadata structure and allocates memory
7432 * for it. Notice that if you add strings to this structure they
7433 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
7434 * operation later, so be careful of using strdup() when assigning
7438 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
7439 * pl->name = strdup(str);
7441 * LIBMTP_destroy_playlist_t(pl);
7444 * @return a pointer to the newly allocated metadata structure.
7445 * @see LIBMTP_destroy_playlist_t()
7447 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
7449 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
7453 new->playlist_id = 0;
7455 new->storage_id = 0;
7464 * This destroys a playlist metadata structure and deallocates the memory
7465 * used by it, including any strings. Never use a track metadata
7466 * structure again after calling this function on it.
7467 * @param playlist the playlist metadata to destroy.
7468 * @see LIBMTP_new_playlist_t()
7470 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
7472 if (playlist == NULL) {
7475 if (playlist->name != NULL)
7476 free(playlist->name);
7477 if (playlist->tracks != NULL)
7478 free(playlist->tracks);
7484 * This function returns a list of the playlists available on the
7485 * device. Typical usage:
7490 * @param device a pointer to the device to get the playlist listing from.
7491 * @return a playlist list on success, else NULL. If there are no playlists
7492 * on the device, NULL will be returned as well.
7493 * @see LIBMTP_Get_Playlist()
7495 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
7497 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7498 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7499 PTPParams *params = (PTPParams *) device->params;
7500 LIBMTP_playlist_t *retlists = NULL;
7501 LIBMTP_playlist_t *curlist = NULL;
7504 // Get all the handles if we haven't already done that
7505 if (params->nrofobjects == 0) {
7506 flush_handles(device);
7509 for (i = 0; i < params->nrofobjects; i++) {
7510 LIBMTP_playlist_t *pl;
7514 ob = ¶ms->objects[i];
7516 // Ignore stuff that isn't playlists
7518 // For Samsung players we must look for the .spl extension explicitly since
7519 // playlists are not stored as playlist objects.
7520 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7521 // Allocate a new playlist type
7522 pl = LIBMTP_new_playlist_t();
7523 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7525 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7529 // Allocate a new playlist type
7530 pl = LIBMTP_new_playlist_t();
7532 // Try to look up proper name, else use the oi->Filename field.
7533 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7534 if (pl->name == NULL) {
7535 pl->name = strdup(ob->oi.Filename);
7537 pl->playlist_id = ob->oid;
7538 pl->parent_id = ob->oi.ParentObject;
7539 pl->storage_id = ob->oi.StorageID;
7541 // Then get the track listing for this playlist
7542 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7543 if (ret != PTP_RC_OK) {
7544 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
7545 "could not get object references.");
7551 // Add playlist to a list that will be returned afterwards.
7552 if (retlists == NULL) {
7560 // Call callback here if we decide to add that possibility...
7567 * This function retrieves an individual playlist from the device.
7568 * @param device a pointer to the device to get the playlist from.
7569 * @param plid the unique ID of the playlist to retrieve.
7570 * @return a valid playlist metadata post or NULL on failure.
7571 * @see LIBMTP_Get_Playlist_List()
7573 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
7575 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7576 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
7577 PTPParams *params = (PTPParams *) device->params;
7579 LIBMTP_playlist_t *pl;
7582 // Get all the handles if we haven't already done that
7583 if (params->nrofobjects == 0) {
7584 flush_handles(device);
7587 ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7588 if (ret != PTP_RC_OK)
7591 // For Samsung players we must look for the .spl extension explicitly since
7592 // playlists are not stored as playlist objects.
7593 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
7594 // Allocate a new playlist type
7595 pl = LIBMTP_new_playlist_t();
7596 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
7600 // Ignore stuff that isn't playlists
7601 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
7605 // Allocate a new playlist type
7606 pl = LIBMTP_new_playlist_t();
7608 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7609 if (pl->name == NULL) {
7610 pl->name = strdup(ob->oi.Filename);
7612 pl->playlist_id = ob->oid;
7613 pl->parent_id = ob->oi.ParentObject;
7614 pl->storage_id = ob->oi.StorageID;
7616 // Then get the track listing for this playlist
7617 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7618 if (ret != PTP_RC_OK) {
7619 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7628 * This function creates a new abstract list such as a playlist
7631 * @param device a pointer to the device to create the new abstract list
7633 * @param name the name of the new abstract list.
7634 * @param artist the artist of the new abstract list or NULL.
7635 * @param genre the genre of the new abstract list or NULL.
7636 * @param parenthandle the handle of the parent or 0 for no parent
7637 * i.e. the root folder.
7638 * @param objectformat the abstract list type to create.
7639 * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7640 * "file" created by this operation.
7641 * @param newid a pointer to a variable that will hold the new object
7642 * ID if this call is successful.
7643 * @param tracks an array of tracks to associate with this list.
7644 * @param no_tracks the number of tracks in the list.
7645 * @return 0 on success, any other value means failure.
7647 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7648 char const * const name,
7649 char const * const artist,
7650 char const * const composer,
7651 char const * const genre,
7652 uint32_t const parenthandle,
7653 uint32_t const storageid,
7654 uint16_t const objectformat,
7655 char const * const suffix,
7656 uint32_t * const newid,
7657 uint32_t const * const tracks,
7658 uint32_t const no_tracks)
7664 uint16_t *properties = NULL;
7665 uint32_t propcnt = 0;
7667 uint32_t localph = parenthandle;
7668 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7669 PTPParams *params = (PTPParams *) device->params;
7670 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7676 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): list name was NULL, using default name \"Unknown\"");
7680 if (storageid == 0) {
7681 // I'm just guessing that an abstract list may require 512 bytes
7682 store = get_suggested_storage_id(device, 512, localph);
7687 // Check if we can create an object of this type
7688 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7689 if (params->deviceinfo.ImageFormats[i] == objectformat) {
7695 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type");
7696 LIBMTP_ERROR("Unsupported abstract list type: %04x\n", objectformat);
7700 // add the new suffix if it isn't there
7702 if (strlen(name) > strlen(suffix)) {
7703 char const * const suff = &name[strlen(name)-strlen(suffix)];
7704 if (!strcmp(suff, suffix)) {
7706 strncpy(fname, name, sizeof(fname));
7709 // If it didn't end with "<suffix>" then add that here.
7710 if (fname[0] == '\0') {
7711 strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7712 strcat(fname, suffix);
7713 fname[sizeof(fname)-1] = '\0';
7716 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7717 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7718 MTPProperties *props = NULL;
7719 MTPProperties *prop = NULL;
7722 *newid = 0x00000000U;
7724 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7726 for (i=0;i<propcnt;i++) {
7727 PTPObjectPropDesc opd;
7729 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7730 if (ret != PTP_RC_OK) {
7731 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7732 "could not get property description.");
7733 } else if (opd.GetSet) {
7734 switch (properties[i]) {
7735 case PTP_OPC_ObjectFileName:
7736 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7737 prop->ObjectHandle = *newid;
7738 prop->property = PTP_OPC_ObjectFileName;
7739 prop->datatype = PTP_DTC_STR;
7740 prop->propval.str = strdup(fname);
7741 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7742 strip_7bit_from_utf8(prop->propval.str);
7745 case PTP_OPC_ProtectionStatus:
7746 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7747 prop->ObjectHandle = *newid;
7748 prop->property = PTP_OPC_ProtectionStatus;
7749 prop->datatype = PTP_DTC_UINT16;
7750 prop->propval.u16 = 0x0000U; /* Not protected */
7752 case PTP_OPC_NonConsumable:
7753 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7754 prop->ObjectHandle = *newid;
7755 prop->property = PTP_OPC_NonConsumable;
7756 prop->datatype = PTP_DTC_UINT8;
7757 prop->propval.u8 = nonconsumable;
7761 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7762 prop->ObjectHandle = *newid;
7763 prop->property = PTP_OPC_Name;
7764 prop->datatype = PTP_DTC_STR;
7765 prop->propval.str = strdup(name);
7768 case PTP_OPC_AlbumArtist:
7769 if (artist != NULL) {
7770 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7771 prop->ObjectHandle = *newid;
7772 prop->property = PTP_OPC_AlbumArtist;
7773 prop->datatype = PTP_DTC_STR;
7774 prop->propval.str = strdup(artist);
7777 case PTP_OPC_Artist:
7778 if (artist != NULL) {
7779 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7780 prop->ObjectHandle = *newid;
7781 prop->property = PTP_OPC_Artist;
7782 prop->datatype = PTP_DTC_STR;
7783 prop->propval.str = strdup(artist);
7786 case PTP_OPC_Composer:
7787 if (composer != NULL) {
7788 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7789 prop->ObjectHandle = *newid;
7790 prop->property = PTP_OPC_Composer;
7791 prop->datatype = PTP_DTC_STR;
7792 prop->propval.str = strdup(composer);
7796 if (genre != NULL) {
7797 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7798 prop->ObjectHandle = *newid;
7799 prop->property = PTP_OPC_Genre;
7800 prop->datatype = PTP_DTC_STR;
7801 prop->propval.str = strdup(genre);
7804 case PTP_OPC_DateModified:
7805 // Tag with current time if that is supported
7806 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7807 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7808 prop->ObjectHandle = *newid;
7809 prop->property = PTP_OPC_DateModified;
7810 prop->datatype = PTP_DTC_STR;
7811 prop->propval.str = get_iso8601_stamp();
7816 ptp_free_objectpropdesc(&opd);
7820 if (nrofprops == 0 || props == NULL) {
7821 LIBMTP_INFO("prop list doesn't exist");
7825 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7826 objectformat, 0, props, nrofprops);
7828 /* Free property list */
7829 ptp_destroy_object_prop_list(props, nrofprops);
7831 if (ret != PTP_RC_OK) {
7832 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7833 if (ret == PTP_RC_AccessDenied) {
7834 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7839 // now send the blank object
7840 ret = ptp_sendobject(params, NULL, 0);
7841 if (ret != PTP_RC_OK) {
7842 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7846 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7847 PTPObjectInfo new_object;
7849 new_object.Filename = fname;
7850 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7851 strip_7bit_from_utf8(new_object.Filename);
7853 // At one point this had to be one
7854 new_object.ObjectCompressedSize = 0;
7855 new_object.ObjectFormat = objectformat;
7857 // Create the object
7858 ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7859 if (ret != PTP_RC_OK) {
7860 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7861 if (ret == PTP_RC_AccessDenied) {
7862 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7866 // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7871 * At one time we had to send this one blank data byte.
7872 * If we didn't, the handle will not be created and thus there is
7873 * no playlist. Possibly this was masking some bug, so removing it
7878 ret = ptp_sendobject(params, data, 1);
7879 if (ret != PTP_RC_OK) {
7880 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7885 // set the properties one by one
7886 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7888 for (i=0;i<propcnt;i++) {
7889 PTPObjectPropDesc opd;
7891 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7892 if (ret != PTP_RC_OK) {
7893 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7894 "could not get property description.");
7895 } else if (opd.GetSet) {
7896 switch (properties[i]) {
7899 ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7901 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7906 case PTP_OPC_AlbumArtist:
7907 if (artist != NULL) {
7908 ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7910 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7915 case PTP_OPC_Artist:
7916 if (artist != NULL) {
7917 ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7919 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7924 case PTP_OPC_Composer:
7925 if (composer != NULL) {
7926 ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7928 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7934 if (genre != NULL) {
7935 ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7937 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7942 case PTP_OPC_DateModified:
7943 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7944 ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7946 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7953 ptp_free_objectpropdesc(&opd);
7958 if (no_tracks > 0) {
7959 // Add tracks to the list as object references.
7960 ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7961 if (ret != PTP_RC_OK) {
7962 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7967 add_object_to_cache(device, *newid);
7973 * This updates the metadata and track listing
7974 * for an abstract list.
7975 * @param device a pointer to the device that the abstract list
7977 * @param name the name of the abstract list.
7978 * @param artist the artist of the abstract list or NULL.
7979 * @param genre the genre of the abstract list or NULL.
7980 * @param objecthandle the object to be updated.
7981 * @param objectformat the abstract list type to update.
7982 * @param tracks an array of tracks to associate with this list.
7983 * @param no_tracks the number of tracks in the list.
7984 * @return 0 on success, any other value means failure.
7986 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7987 char const * const name,
7988 char const * const artist,
7989 char const * const composer,
7990 char const * const genre,
7991 uint32_t const objecthandle,
7992 uint16_t const objectformat,
7993 uint32_t const * const tracks,
7994 uint32_t const no_tracks)
7997 PTPParams *params = (PTPParams *) device->params;
7998 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7999 uint16_t *properties = NULL;
8000 uint32_t propcnt = 0;
8003 // First see which properties can be set
8004 // i.e only try to update this metadata for object tags that exist on the current player.
8005 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
8006 if (ret != PTP_RC_OK) {
8007 // Just bail out for now, nothing is ever set.
8008 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8009 "could not retrieve supported object properties.");
8012 if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
8013 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
8014 MTPProperties *props = NULL;
8015 MTPProperties *prop = NULL;
8018 for (i=0;i<propcnt;i++) {
8019 PTPObjectPropDesc opd;
8021 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
8022 if (ret != PTP_RC_OK) {
8023 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8024 "could not get property description.");
8025 } else if (opd.GetSet) {
8026 switch (properties[i]) {
8028 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8029 prop->ObjectHandle = objecthandle;
8030 prop->property = PTP_OPC_Name;
8031 prop->datatype = PTP_DTC_STR;
8033 prop->propval.str = strdup(name);
8035 case PTP_OPC_AlbumArtist:
8036 if (artist != NULL) {
8037 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8038 prop->ObjectHandle = objecthandle;
8039 prop->property = PTP_OPC_AlbumArtist;
8040 prop->datatype = PTP_DTC_STR;
8041 prop->propval.str = strdup(artist);
8044 case PTP_OPC_Artist:
8045 if (artist != NULL) {
8046 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8047 prop->ObjectHandle = objecthandle;
8048 prop->property = PTP_OPC_Artist;
8049 prop->datatype = PTP_DTC_STR;
8050 prop->propval.str = strdup(artist);
8053 case PTP_OPC_Composer:
8054 if (composer != NULL) {
8055 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8056 prop->ObjectHandle = objecthandle;
8057 prop->property = PTP_OPC_Composer;
8058 prop->datatype = PTP_DTC_STR;
8059 prop->propval.str = strdup(composer);
8063 if (genre != NULL) {
8064 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8065 prop->ObjectHandle = objecthandle;
8066 prop->property = PTP_OPC_Genre;
8067 prop->datatype = PTP_DTC_STR;
8068 prop->propval.str = strdup(genre);
8071 case PTP_OPC_DateModified:
8072 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8073 // Tag with current time if that is supported
8074 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
8075 prop->ObjectHandle = objecthandle;
8076 prop->property = PTP_OPC_DateModified;
8077 prop->datatype = PTP_DTC_STR;
8078 prop->propval.str = get_iso8601_stamp();
8085 ptp_free_objectpropdesc(&opd);
8088 // proplist could be NULL if we can't write any properties
8089 if (props != NULL) {
8090 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
8092 ptp_destroy_object_prop_list(props, nrofprops);
8094 if (ret != PTP_RC_OK) {
8095 // TODO: return error of which property we couldn't set
8096 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8097 "could not set object property list.");
8103 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
8104 for (i=0;i<propcnt;i++) {
8105 switch (properties[i]) {
8108 ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
8110 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8111 "could not set title.");
8114 case PTP_OPC_AlbumArtist:
8115 // Update album artist
8116 ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
8118 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8119 "could not set album artist name.");
8122 case PTP_OPC_Artist:
8124 ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
8126 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8127 "could not set artist name.");
8130 case PTP_OPC_Composer:
8132 ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
8134 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8135 "could not set composer name.");
8139 // Update genre (but only if valid)
8141 ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
8143 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8144 "could not set genre.");
8148 case PTP_OPC_DateModified:
8149 // Update date modified
8150 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
8151 char *tmpdate = get_iso8601_stamp();
8152 ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
8154 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8155 "could not set modification date.");
8165 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
8166 "Your device doesn't seem to support any known way of setting metadata.");
8171 // Then the object references...
8172 ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
8173 if (ret != PTP_RC_OK) {
8174 add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
8181 update_metadata_cache(device, objecthandle);
8188 * This routine creates a new playlist based on the metadata
8189 * supplied. If the <code>tracks</code> field of the metadata
8190 * contains a track listing, these tracks will be added to the
8192 * @param device a pointer to the device to create the new playlist on.
8193 * @param metadata the metadata for the new playlist. If the function
8194 * exits with success, the <code>playlist_id</code> field of this
8195 * struct will contain the new playlist ID of the playlist.
8197 * <li><code>metadata->parent_id</code> should be set to the parent
8198 * (e.g. folder) to store this track in. Since some
8199 * devices are a bit picky about where files
8200 * are placed, a default folder will be chosen if libmtp
8201 * has detected one for the current filetype and this
8202 * parameter is set to 0. If this is 0 and no default folder
8203 * can be found, the file will be stored in the root folder.
8204 * <li><code>metadata->storage_id</code> should be set to the
8205 * desired storage (e.g. memory card or whatever your device
8206 * presents) to store this track in. Setting this to 0 will store
8207 * the track on the primary storage.
8209 * @return 0 on success, any other value means failure.
8210 * @see LIBMTP_Update_Playlist()
8211 * @see LIBMTP_Delete_Object()
8213 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
8214 LIBMTP_playlist_t * const metadata)
8216 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8217 uint32_t localph = metadata->parent_id;
8219 // Use a default folder if none given
8221 if (device->default_playlist_folder != 0)
8222 localph = device->default_playlist_folder;
8224 localph = device->default_music_folder;
8226 metadata->parent_id = localph;
8228 // Samsung needs its own special type of playlists
8229 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8230 return playlist_t_to_spl(device, metadata);
8233 // Just create a new abstract audio/video playlist...
8234 return create_new_abstract_list(device,
8240 metadata->storage_id,
8241 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8242 get_playlist_extension(ptp_usb),
8243 &metadata->playlist_id,
8245 metadata->no_tracks);
8249 * This routine updates a playlist based on the metadata
8250 * supplied. If the <code>tracks</code> field of the metadata
8251 * contains a track listing, these tracks will be added to the
8252 * playlist in place of those already present, i.e. the
8253 * previous track listing will be deleted. For Samsung devices the
8254 * playlist id (metadata->playlist_id) is likely to change.
8255 * @param device a pointer to the device to create the new playlist on.
8256 * @param metadata the metadata for the playlist to be updated.
8257 * notice that the field <code>playlist_id</code>
8258 * must contain the apropriate playlist ID. Playlist ID
8259 * be modified to a new playlist ID by the time the
8260 * function returns since edit-in-place is not always possible.
8261 * @return 0 on success, any other value means failure.
8262 * @see LIBMTP_Create_New_Playlist()
8263 * @see LIBMTP_Delete_Object()
8265 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
8266 LIBMTP_playlist_t * const metadata)
8269 // Samsung needs its own special type of playlists
8270 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8271 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
8272 return update_spl_playlist(device, metadata);
8275 return update_abstract_list(device,
8280 metadata->playlist_id,
8281 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
8283 metadata->no_tracks);
8287 * This creates a new album metadata structure and allocates memory
8288 * for it. Notice that if you add strings to this structure they
8289 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
8290 * operation later, so be careful of using strdup() when assigning
8293 * @return a pointer to the newly allocated metadata structure.
8294 * @see LIBMTP_destroy_album_t()
8296 LIBMTP_album_t *LIBMTP_new_album_t(void)
8298 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
8304 new->storage_id = 0;
8307 new->composer = NULL;
8316 * This recursively deletes the memory for an album structure
8318 * @param album structure to destroy
8319 * @see LIBMTP_new_album_t()
8321 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
8323 if (album == NULL) {
8326 if (album->name != NULL)
8328 if (album->artist != NULL)
8329 free(album->artist);
8330 if (album->composer != NULL)
8331 free(album->composer);
8332 if (album->genre != NULL)
8334 if (album->tracks != NULL)
8335 free(album->tracks);
8341 * This function maps and copies a property onto the album metadata if applicable.
8343 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
8344 MTPProperties *prop, LIBMTP_album_t *alb)
8346 switch (prop->property) {
8348 if (prop->propval.str != NULL)
8349 alb->name = strdup(prop->propval.str);
8353 case PTP_OPC_AlbumArtist:
8354 if (prop->propval.str != NULL) {
8355 // This should take precedence over plain "Artist"
8356 if (alb->artist != NULL)
8358 alb->artist = strdup(prop->propval.str);
8362 case PTP_OPC_Artist:
8363 if (prop->propval.str != NULL) {
8364 // Only use of AlbumArtist is not set
8365 if (alb->artist == NULL)
8366 alb->artist = strdup(prop->propval.str);
8370 case PTP_OPC_Composer:
8371 if (prop->propval.str != NULL)
8372 alb->composer = strdup(prop->propval.str);
8374 alb->composer = NULL;
8377 if (prop->propval.str != NULL)
8378 alb->genre = strdup(prop->propval.str);
8386 * This function retrieves the album metadata for an album
8387 * given by a unique ID.
8388 * @param device a pointer to the device to get the track metadata off.
8389 * @param alb an album metadata metadata set to fill in.
8391 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
8392 LIBMTP_album_t *alb)
8395 PTPParams *params = (PTPParams *) device->params;
8397 MTPProperties *prop;
8401 * If we have a cached, large set of metadata, then use it!
8403 ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
8405 prop = ob->mtpprops;
8406 for (i=0;i<ob->nrofmtpprops;i++,prop++)
8407 pick_property_to_album_metadata(device, prop, alb);
8409 uint16_t *props = NULL;
8410 uint32_t propcnt = 0;
8412 // First see which properties can be retrieved for albums
8413 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
8414 if (ret != PTP_RC_OK) {
8415 add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
8416 // Just bail out for now, nothing is ever set.
8419 for (i=0;i<propcnt;i++) {
8422 alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
8424 case PTP_OPC_AlbumArtist:
8425 if (alb->artist != NULL)
8427 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
8429 case PTP_OPC_Artist:
8430 if (alb->artist == NULL)
8431 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
8433 case PTP_OPC_Composer:
8434 alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
8437 alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
8450 * This function returns a list of the albums available on the
8453 * @param device a pointer to the device to get the album listing from.
8454 * @return an album list on success, else NULL. If there are no albums
8455 * on the device, NULL will be returned as well.
8456 * @see LIBMTP_Get_Album()
8458 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
8460 // Read all storage devices
8461 return LIBMTP_Get_Album_List_For_Storage(device, 0);
8466 * This function returns a list of the albums available on the
8467 * device. You can filter on the storage ID.
8469 * @param device a pointer to the device to get the album listing from.
8470 * @param storage_id ID of device storage (if null, all storages)
8472 * @return an album list on success, else NULL. If there are no albums
8473 * on the device, NULL will be returned as well.
8474 * @see LIBMTP_Get_Album()
8476 LIBMTP_album_t *LIBMTP_Get_Album_List_For_Storage(LIBMTP_mtpdevice_t *device, uint32_t const storage_id)
8478 PTPParams *params = (PTPParams *) device->params;
8479 LIBMTP_album_t *retalbums = NULL;
8480 LIBMTP_album_t *curalbum = NULL;
8483 // Get all the handles if we haven't already done that
8484 if (params->nrofobjects == 0)
8485 flush_handles(device);
8487 for (i = 0; i < params->nrofobjects; i++) {
8488 LIBMTP_album_t *alb;
8492 ob = ¶ms->objects[i];
8494 // Ignore stuff that isn't an album
8495 if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
8498 // Ignore stuff that isn't into the storage device
8499 if ((storage_id != 0) && (ob->oi.StorageID != storage_id ))
8502 // Allocate a new album type
8503 alb = LIBMTP_new_album_t();
8504 alb->album_id = ob->oid;
8505 alb->parent_id = ob->oi.ParentObject;
8506 alb->storage_id = ob->oi.StorageID;
8508 // Fetch supported metadata
8509 get_album_metadata(device, alb);
8511 // Then get the track listing for this album
8512 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8513 if (ret != PTP_RC_OK) {
8514 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
8519 // Add album to a list that will be returned afterwards.
8520 if (retalbums == NULL) {
8524 curalbum->next = alb;
8533 * This function retrieves an individual album from the device.
8534 * @param device a pointer to the device to get the album from.
8535 * @param albid the unique ID of the album to retrieve.
8536 * @return a valid album metadata or NULL on failure.
8537 * @see LIBMTP_Get_Album_List()
8539 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
8541 PTPParams *params = (PTPParams *) device->params;
8544 LIBMTP_album_t *alb;
8546 // Get all the handles if we haven't already done that
8547 if (params->nrofobjects == 0)
8548 flush_handles(device);
8550 ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8551 if (ret != PTP_RC_OK)
8554 // Ignore stuff that isn't an album
8555 if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
8558 // Allocate a new album type
8559 alb = LIBMTP_new_album_t();
8560 alb->album_id = ob->oid;
8561 alb->parent_id = ob->oi.ParentObject;
8562 alb->storage_id = ob->oi.StorageID;
8564 // Fetch supported metadata
8565 get_album_metadata(device, alb);
8567 // Then get the track listing for this album
8568 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
8569 if (ret != PTP_RC_OK) {
8570 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
8579 * This routine creates a new album based on the metadata
8580 * supplied. If the <code>tracks</code> field of the metadata
8581 * contains a track listing, these tracks will be added to the
8583 * @param device a pointer to the device to create the new album on.
8584 * @param metadata the metadata for the new album. If the function
8585 * exits with success, the <code>album_id</code> field of this
8586 * struct will contain the new ID of the album.
8588 * <li><code>metadata->parent_id</code> should be set to the parent
8589 * (e.g. folder) to store this track in. Since some
8590 * devices are a bit picky about where files
8591 * are placed, a default folder will be chosen if libmtp
8592 * has detected one for the current filetype and this
8593 * parameter is set to 0. If this is 0 and no default folder
8594 * can be found, the file will be stored in the root folder.
8595 * <li><code>metadata->storage_id</code> should be set to the
8596 * desired storage (e.g. memory card or whatever your device
8597 * presents) to store this track in. Setting this to 0 will store
8598 * the track on the primary storage.
8600 * @return 0 on success, any other value means failure.
8601 * @see LIBMTP_Update_Album()
8602 * @see LIBMTP_Delete_Object()
8604 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
8605 LIBMTP_album_t * const metadata)
8607 uint32_t localph = metadata->parent_id;
8609 // Use a default folder if none given
8611 if (device->default_album_folder != 0)
8612 localph = device->default_album_folder;
8614 localph = device->default_music_folder;
8616 metadata->parent_id = localph;
8618 // Just create a new abstract album...
8619 return create_new_abstract_list(device,
8625 metadata->storage_id,
8626 PTP_OFC_MTP_AbstractAudioAlbum,
8628 &metadata->album_id,
8630 metadata->no_tracks);
8634 * This creates a new sample data metadata structure and allocates memory
8635 * for it. Notice that if you add strings to this structure they
8636 * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
8637 * operation later, so be careful of using strdup() when assigning
8640 * @return a pointer to the newly allocated metadata structure.
8641 * @see LIBMTP_destroy_sampledata_t()
8643 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
8645 LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
8658 * This destroys a file sample metadata type.
8659 * @param sample the file sample metadata to be destroyed.
8661 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8663 if (sample == NULL) {
8666 if (sample->data != NULL) {
8673 * This routine figures out whether a certain filetype supports
8674 * representative samples (small thumbnail images) or not. This
8675 * typically applies to JPEG files, MP3 files and Album abstract
8676 * playlists, but in theory any filetype could support representative
8678 * @param device a pointer to the device which is to be examined.
8679 * @param filetype the fileype to examine, and return the representative sample
8681 * @param sample this will contain a new sample type with the fields
8682 * filled in with suitable default values. For example, the
8683 * supported sample type will be set, the supported height and
8684 * width will be set to max values if it is an image sample,
8685 * and duration will also be given some suitable default value
8686 * which should not be exceeded on audio samples. If the
8687 * device does not support samples for this filetype, this
8688 * pointer will be NULL. If it is not NULL, the user must
8689 * destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8691 * @return 0 on success, any other value means failure.
8692 * @see LIBMTP_Send_Representative_Sample()
8693 * @see LIBMTP_Create_New_Album()
8695 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8696 LIBMTP_filetype_t const filetype,
8697 LIBMTP_filesampledata_t ** sample)
8700 PTPParams *params = (PTPParams *) device->params;
8701 uint16_t *props = NULL;
8702 uint32_t propcnt = 0;
8704 // TODO: Get rid of these when we can properly query the device.
8705 int support_data = 0;
8706 int support_format = 0;
8707 int support_height = 0;
8708 int support_width = 0;
8709 int support_duration = 0;
8710 int support_size = 0;
8712 PTPObjectPropDesc opd_height;
8713 PTPObjectPropDesc opd_width;
8714 PTPObjectPropDesc opd_format;
8715 PTPObjectPropDesc opd_duration;
8716 PTPObjectPropDesc opd_size;
8718 // Default to no type supported.
8721 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8722 if (ret != PTP_RC_OK) {
8723 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8727 * TODO: when walking through these object properties, make calls to
8728 * a new function in ptp.h/ptp.c that can send the command
8729 * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8732 for (i = 0; i < propcnt; i++) {
8734 case PTP_OPC_RepresentativeSampleData:
8737 case PTP_OPC_RepresentativeSampleFormat:
8740 case PTP_OPC_RepresentativeSampleSize:
8743 case PTP_OPC_RepresentativeSampleHeight:
8746 case PTP_OPC_RepresentativeSampleWidth:
8749 case PTP_OPC_RepresentativeSampleDuration:
8750 support_duration = 1;
8758 if (support_data && support_format && support_height && support_width && !support_duration) {
8759 // Something that supports height and width and not duration is likely to be JPEG
8760 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8762 * Populate the sample format with the first supported format
8764 * TODO: figure out how to pass back more than one format if more are
8765 * supported by the device.
8767 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8768 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8769 ptp_free_objectpropdesc(&opd_format);
8770 /* Populate the maximum image height */
8771 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8772 retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8773 ptp_free_objectpropdesc(&opd_width);
8774 /* Populate the maximum image width */
8775 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8776 retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8777 ptp_free_objectpropdesc(&opd_height);
8778 /* Populate the maximum size */
8780 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8781 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8782 ptp_free_objectpropdesc(&opd_size);
8785 } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8786 // Another qualified guess
8787 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8789 * Populate the sample format with the first supported format
8791 * TODO: figure out how to pass back more than one format if more are
8792 * supported by the device.
8794 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8795 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8796 ptp_free_objectpropdesc(&opd_format);
8797 /* Populate the maximum duration */
8798 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8799 retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8800 ptp_free_objectpropdesc(&opd_duration);
8801 /* Populate the maximum size */
8803 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8804 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8805 ptp_free_objectpropdesc(&opd_size);
8813 * This routine sends representative sample data for an object.
8814 * This uses the RepresentativeSampleData property of the album,
8815 * if the device supports it. The data should be of a format acceptable
8816 * to the player (for iRiver and Creative, this seems to be JPEG) and
8817 * must not be too large. (for a Creative, max seems to be about 20KB.)
8818 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8819 * maximum size, dimensions, etc..
8820 * @param device a pointer to the device which the object is on.
8821 * @param id unique id of the object to set artwork for.
8822 * @param pointer to LIBMTP_filesampledata_t struct containing data
8823 * @return 0 on success, any other value means failure.
8824 * @see LIBMTP_Get_Representative_Sample()
8825 * @see LIBMTP_Get_Representative_Sample_Format()
8826 * @see LIBMTP_Create_New_Album()
8828 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8830 LIBMTP_filesampledata_t *sampledata)
8833 PTPParams *params = (PTPParams *) device->params;
8834 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8835 PTPPropertyValue propval;
8838 uint16_t *props = NULL;
8839 uint32_t propcnt = 0;
8842 // get the file format for the object we're going to send representative data for
8843 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8844 if (ret != PTP_RC_OK) {
8845 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8849 // check that we can send representative sample data for this object format
8850 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8851 if (ret != PTP_RC_OK) {
8852 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8856 for (i = 0; i < propcnt; i++) {
8857 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8864 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8869 // Go ahead and send the data
8870 propval.a.count = sampledata->size;
8871 propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8872 if (propval.a.v == NULL)
8875 for (i = 0; i < sampledata->size; i++) {
8876 propval.a.v[i].u8 = sampledata->data[i];
8879 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8880 &propval,PTP_DTC_AUINT8);
8881 if (ret != PTP_RC_OK) {
8882 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8888 /* Set the height and width if the sample is an image, otherwise just
8889 * set the duration and size */
8890 switch(sampledata->filetype) {
8891 case LIBMTP_FILETYPE_JPEG:
8892 case LIBMTP_FILETYPE_JFIF:
8893 case LIBMTP_FILETYPE_TIFF:
8894 case LIBMTP_FILETYPE_BMP:
8895 case LIBMTP_FILETYPE_GIF:
8896 case LIBMTP_FILETYPE_PICT:
8897 case LIBMTP_FILETYPE_PNG:
8898 if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8899 // For images, set the height and width
8900 set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8901 set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8905 // For anything not an image, set the duration and size
8906 set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8907 set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8915 * This routine gets representative sample data for an object.
8916 * This uses the RepresentativeSampleData property of the album,
8917 * if the device supports it.
8918 * @param device a pointer to the device which the object is on.
8919 * @param id unique id of the object to get data for.
8920 * @param pointer to LIBMTP_filesampledata_t struct to receive data
8921 * @return 0 on success, any other value means failure.
8922 * @see LIBMTP_Send_Representative_Sample()
8923 * @see LIBMTP_Get_Representative_Sample_Format()
8924 * @see LIBMTP_Create_New_Album()
8926 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8928 LIBMTP_filesampledata_t *sampledata)
8931 PTPParams *params = (PTPParams *) device->params;
8932 PTPPropertyValue propval;
8935 uint16_t *props = NULL;
8936 uint32_t propcnt = 0;
8939 // get the file format for the object we're going to send representative data for
8940 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8941 if (ret != PTP_RC_OK) {
8942 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8946 // check that we can store representative sample data for this object format
8947 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8948 if (ret != PTP_RC_OK) {
8949 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8953 for (i = 0; i < propcnt; i++) {
8954 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8961 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8967 ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8968 &propval,PTP_DTC_AUINT8);
8969 if (ret != PTP_RC_OK) {
8970 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8975 sampledata->size = propval.a.count;
8976 sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8977 for (i = 0; i < propval.a.count; i++) {
8978 sampledata->data[i] = propval.a.v[i].u8;
8982 // Get the other properties
8983 sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8984 sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8985 sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8986 sampledata->filetype = map_ptp_type_to_libmtp_type(
8987 get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8993 * Retrieve the thumbnail for a file.
8994 * @param device a pointer to the device to get the thumbnail from.
8995 * @param id the object ID of the file to retrieve the thumbnail for.
8996 * @return 0 on success, any other value means failure.
8998 int LIBMTP_Get_Thumbnail(LIBMTP_mtpdevice_t *device, uint32_t const id,
8999 unsigned char **data, unsigned int *size)
9001 LIBMTP_INFO("LIBMTP_Get_Thumbnail start");
9002 PTPParams *params = (PTPParams *) device->params;
9005 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
9009 get_usb_device_timeout(ptp_usb, &oldtimeout);
9010 set_usb_device_timeout(ptp_usb, 3000);
9012 LIBMTP_INFO("priv set timeout value : %d, now, set timeout value to 3 sec", oldtimeout);
9014 ret = ptp_getthumb(params, id, data, size);
9015 if (ret != PTP_RC_OK) {
9016 LIBMTP_INFO("ptp_getthumb failed : %d", ret);
9017 set_usb_device_timeout(ptp_usb, oldtimeout);
9021 set_usb_device_timeout(ptp_usb, oldtimeout);
9022 LIBMTP_INFO("LIBMTP_Get_Thumbnail end");
9027 int LIBMTP_Get_Thumbnail_From_Exif_Data(LIBMTP_mtpdevice_t *device, uint32_t const id,
9028 unsigned char **data, unsigned int *size)
9030 LIBMTP_INFO("LIBMTP_Get_Thumbnail_From_Exif_Data start");
9031 PTPParams *params = (PTPParams *) device->params;
9035 uint32_t offset, maxbytes;
9036 uint32_t jpeg_header_size, app1_marker_size;
9038 unsigned char *jpeg_header = NULL;
9039 unsigned char *app1_marker = NULL;
9040 ExifData *exif_data = NULL;
9042 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
9046 get_usb_device_timeout(ptp_usb, &oldtimeout);
9048 if (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
9049 LIBMTP_INFO("ptp_operation_issupported fail - id %d", id);
9053 if (ptp_object_want(params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob) != PTP_RC_OK) {
9054 LIBMTP_INFO("ptp_object_want fail - id %d", id);
9058 if (ob->oi.ObjectCompressedSize < 10) {
9059 LIBMTP_INFO("ObjectCompressedSize fail - id %d", id);
9063 if (ob->oi.ObjectFormat != PTP_OFC_EXIF_JPEG) {
9064 LIBMTP_INFO("ObjectFormat fail - id %d", id);
9068 //Get App1 Marker header
9069 set_usb_device_timeout(ptp_usb, 3000);
9071 ret = ptp_getpartialobject (params, id, 0, 10, &jpeg_header, &jpeg_header_size);
9072 if (ret != PTP_RC_OK) {
9073 LIBMTP_INFO("first ptp_getpartialobject fail - id %d", id);
9074 set_usb_device_timeout(ptp_usb, oldtimeout);
9078 set_usb_device_timeout(ptp_usb, oldtimeout);
9080 if (!((jpeg_header[0] == 0xff) && (jpeg_header[1] == 0xd8))) { /* 0XFF 0xD8 means SOI (Start Of Image) */
9081 LIBMTP_INFO("SOI fail - id %d", id);
9086 if (!((jpeg_header[2] == 0xff) && (jpeg_header[3] == 0xe1))) { /* 0xFF 0xE1 means App1 Marker (EXIF) */
9087 LIBMTP_INFO("App1 Marker fail - id %d", id);
9092 if (0 != memcmp(jpeg_header+6, "Exif", 4)) { /* check exif header */
9093 LIBMTP_INFO("Exif Header Check fail");
9099 maxbytes = (jpeg_header[4] << 8 ) + jpeg_header[5];
9100 maxbytes += 2; // include end of Image
9104 LIBMTP_INFO("maxbytes is %d", maxbytes);
9106 //Get App1 Marker : EXIF Data
9107 set_usb_device_timeout(ptp_usb, 3000);
9109 ret = ptp_getpartialobject (params, id, offset, maxbytes, &app1_marker, &app1_marker_size);
9110 if (ret != PTP_RC_OK) {
9111 LIBMTP_INFO("second ptp_getpartialobject fail - id %d", id);
9112 set_usb_device_timeout(ptp_usb, oldtimeout);
9116 set_usb_device_timeout(ptp_usb, oldtimeout);
9118 if (app1_marker == NULL) {
9119 LIBMTP_INFO("app1_marker is NULL - id %d", id);
9123 LIBMTP_INFO("app1_marker_size is %d", app1_marker_size);
9125 exif_data = exif_data_new_from_data(app1_marker, app1_marker_size);
9126 if (exif_data == NULL) {
9127 LIBMTP_INFO("Exif data is NULL - id %d", id);
9132 if (exif_data->data == NULL) {
9133 LIBMTP_INFO("thumbnail is NULL - id %d", id);
9138 *data = (unsigned char *)malloc(sizeof(unsigned char) * exif_data->size);
9139 memcpy(*data, exif_data->data, exif_data->size);
9142 *size = exif_data->size;
9144 LIBMTP_INFO("thumbnail extract success - size : %d, id : %d", exif_data->size, id);
9148 #endif /* TIZEN_EXT */
9150 int LIBMTP_GetPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9151 uint32_t offset, uint32_t maxbytes,
9152 unsigned char **data, unsigned int *size)
9154 PTPParams *params = (PTPParams *) device->params;
9158 if (!ptp_operation_issupported(params, PTP_OC_GetPartialObject)) {
9159 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9160 "LIBMTP_GetPartialObject: PTP_OC_GetPartialObject not supported");
9164 if (ptp_object_want(params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob) != PTP_RC_OK) {
9165 LIBMTP_INFO("ptp_object_want fail - id %d", id);
9169 ret = ptp_getpartialobject(params, id, offset, maxbytes, data, size);
9170 if (ret == PTP_RC_OK)
9176 int LIBMTP_SendPartialObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9177 uint64_t offset, unsigned char *data, unsigned int size)
9179 PTPParams *params = (PTPParams *) device->params;
9182 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_SendPartialObject)) {
9183 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9184 "LIBMTP_SendPartialObject: PTP_OC_ANDROID_SendPartialObject not supported");
9188 ret = ptp_android_sendpartialobject(params, id, offset, data, size);
9189 if (ret == PTP_RC_OK)
9195 int LIBMTP_BeginEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9197 PTPParams *params = (PTPParams *) device->params;
9200 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_BeginEditObject)) {
9201 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9202 "LIBMTP_BeginEditObject: PTP_OC_ANDROID_BeginEditObject not supported");
9206 ret = ptp_android_begineditobject(params, id);
9207 if (ret == PTP_RC_OK)
9213 int LIBMTP_EndEditObject(LIBMTP_mtpdevice_t *device, uint32_t const id)
9215 PTPParams *params = (PTPParams *) device->params;
9218 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_EndEditObject)) {
9219 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9220 "LIBMTP_EndEditObject: PTP_OC_ANDROID_EndEditObject not supported");
9224 ret = ptp_android_endeditobject(params, id);
9225 if (ret == PTP_RC_OK) {
9226 // update cached object properties if metadata cache exists
9227 update_metadata_cache(device, id);
9234 int LIBMTP_TruncateObject(LIBMTP_mtpdevice_t *device, uint32_t const id,
9237 PTPParams *params = (PTPParams *) device->params;
9240 if (!ptp_operation_issupported(params, PTP_OC_ANDROID_TruncateObject)) {
9241 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9242 "LIBMTP_TruncateObject: PTP_OC_ANDROID_TruncateObject not supported");
9246 ret = ptp_android_truncate(params, id, offset);
9247 if (ret == PTP_RC_OK)
9254 * This routine updates an album based on the metadata
9255 * supplied. If the <code>tracks</code> field of the metadata
9256 * contains a track listing, these tracks will be added to the
9257 * album in place of those already present, i.e. the
9258 * previous track listing will be deleted.
9259 * @param device a pointer to the device to create the new album on.
9260 * @param metadata the metadata for the album to be updated.
9261 * notice that the field <code>album_id</code>
9262 * must contain the apropriate album ID.
9263 * @return 0 on success, any other value means failure.
9264 * @see LIBMTP_Create_New_Album()
9265 * @see LIBMTP_Delete_Object()
9267 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
9268 LIBMTP_album_t const * const metadata)
9270 return update_abstract_list(device,
9276 PTP_OFC_MTP_AbstractAudioAlbum,
9278 metadata->no_tracks);
9282 * Dummy function needed to interface to upstream
9283 * ptp.c/ptp.h files.
9285 void ptp_nikon_getptpipguid (unsigned char* guid) {
9290 * Add an object to cache.
9291 * @param device the device which may have a cache to which the object should be added.
9292 * @param object_id the object to add to the cache.
9294 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9296 PTPParams *params = (PTPParams *)device->params;
9299 ret = ptp_add_object_to_cache(params, object_id);
9300 if (ret != PTP_RC_OK) {
9301 add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
9307 * Update cache after object has been modified
9308 * @param device the device which may have a cache to which the object should be updated.
9309 * @param object_id the object to update.
9311 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9313 PTPParams *params = (PTPParams *)device->params;
9315 ptp_remove_object_from_cache(params, object_id);
9316 add_object_to_cache(device, object_id);
9320 int _is_exist_handler(uint32_t **object_list, int size, int current_handler)
9324 for (i = 0; i < size; i++) {
9325 if ((*object_list)[i] == current_handler)
9332 int LIBMTP_Get_Object_Handles(LIBMTP_mtpdevice_t *device, uint32_t storage,
9333 uint32_t format, uint32_t parent, uint32_t **object_list, uint32_t *object_num)
9336 PTPParams *params = (PTPParams *)device->params;
9337 PTPObjectHandles currentHandles;
9343 if (!ptp_operation_issupported(params, PTP_OC_GetObjectHandles)) {
9344 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9345 "LIBMTP_Get_Object_List: LIBMTP_Get_Object_List not supported");
9350 storageid = PTP_GOH_ALL_STORAGE;
9352 storageid = storage;
9355 parentid = PTP_GOH_ROOT_PARENT;
9359 ret = ptp_getobjecthandles(params, storageid, PTP_GOH_ALL_FORMATS, parentid, ¤tHandles);
9361 if (ret != PTP_RC_OK) {
9362 LIBMTP_INFO("LIBMTP_Get_Object_Handles ret %u\n", ret);
9366 LIBMTP_INFO("LIBMTP_Get_Object_Handles currentHandles.n %u\n", currentHandles.n);
9368 if (currentHandles.n == 0) {
9369 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9370 "LIBMTP_Get_Object_List: object handle is not exist");
9374 *object_list = (uint32_t *)malloc(currentHandles.n * sizeof(int));
9375 if (*object_list == NULL) {
9376 LIBMTP_INFO("object list is NULL");
9377 if (currentHandles.Handler != NULL) {
9378 free(currentHandles.Handler);
9379 currentHandles.Handler = NULL;
9385 for (i = 0; i < currentHandles.n; i++) {
9386 if(_is_exist_handler(object_list, temp, currentHandles.Handler[i]))
9389 (*object_list)[temp] = currentHandles.Handler[i];
9395 if (currentHandles.Handler != NULL) {
9396 free(currentHandles.Handler);
9397 currentHandles.Handler = NULL;
9403 static const char *__get_filename_ext(const char *filename) {
9404 const char *dot = strrchr(filename, '.');
9405 if(!dot || dot == filename) return "";
9409 static int __is_high_efficiency_image(char *filename)
9411 if (filename == NULL)
9414 const char *ext = __get_filename_ext(filename);
9418 if (0 == strncmp(ext, "heic", strlen(ext))
9419 || 0 == strncmp(ext, "heif", strlen(ext))) {
9426 MTPObjectInfo *LIBMTP_Get_Object_Info(LIBMTP_mtpdevice_t *device, uint32_t object_id)
9428 PTPParams *params = (PTPParams *)device->params;
9430 MTPObjectInfo *object_info;
9433 if (!ptp_operation_issupported(params, PTP_OC_GetObjectInfo)) {
9434 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9435 "LIBMTP_Get_Object_info: LIBMTP_Get_Object_info not supported");
9439 object_info = (MTPObjectInfo *)malloc(sizeof(MTPObjectInfo));
9440 if (object_info == NULL)
9443 ret = ptp_object_want(params, object_id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
9445 if (ret != PTP_RC_OK) {
9446 if (object_info != NULL)
9451 object_info->StorageID = ob->oi.StorageID;
9452 object_info->ObjectFormat = ob->oi.ObjectFormat;
9453 object_info->ProtectionStatus = ob->oi.ProtectionStatus;
9454 object_info->ObjectCompressedSize = ob->oi.ObjectCompressedSize;
9455 object_info->ThumbFormat = ob->oi.ThumbFormat;
9456 object_info->ThumbCompressedSize = ob->oi.ThumbCompressedSize;
9457 object_info->ThumbPixWidth = ob->oi.ThumbPixWidth;
9458 object_info->ThumbPixHeight = ob->oi.ThumbPixHeight;
9459 object_info->ImagePixWidth = ob->oi.ImagePixWidth;
9460 object_info->ImagePixHeight = ob->oi.ImagePixHeight;
9461 object_info->ImageBitDepth = ob->oi.ImageBitDepth;
9463 object_info->ParentObject = ob->oi.ParentObject;
9464 object_info->AssociationType = ob->oi.AssociationType;
9465 object_info->AssociationDesc = ob->oi.AssociationDesc;
9466 object_info->SequenceNumber = ob->oi.SequenceNumber;
9467 object_info->CaptureDate = ob->oi.CaptureDate;
9468 object_info->ModificationDate = ob->oi.ModificationDate;
9470 if (ob->oi.Filename != NULL)
9471 object_info->Filename = strdup(ob->oi.Filename);
9473 object_info->Filename = NULL;
9475 if (ob->oi.Keywords != NULL)
9476 object_info->Keywords = strdup(ob->oi.Keywords);
9478 object_info->Keywords = NULL;
9480 LIBMTP_INFO("Filename : %s, Object Format : %hu", object_info->Filename, object_info->ObjectFormat);
9481 if (object_info->ObjectFormat == PTP_OFC_Defined && __is_high_efficiency_image(object_info->Filename)) {
9482 LIBMTP_INFO("It is HEIF image");
9483 object_info->ObjectFormat = LIBMTP_FILETYPE_HEIF;
9485 object_info->ObjectFormat = map_ptp_type_to_libmtp_type(object_info->ObjectFormat);
9488 object_info->ThumbFormat = map_ptp_type_to_libmtp_type(object_info->ThumbFormat);
9494 int LIBMTP_Get_Num_Objects(LIBMTP_mtpdevice_t *device, uint32_t format, uint32_t *object_num)
9496 PTPParams *params = (PTPParams *)device->params;
9499 if (!ptp_operation_issupported(params, PTP_OC_GetNumObjects)) {
9500 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
9501 "LIBMTP_Get_Num_Objects: LIBMTP_Get_Num_Objects not supported");
9505 ret = ptp_getnumobjects(params, PTP_GOH_ALL_STORAGE, map_libmtp_type_to_ptp_type(format),
9506 PTP_GOH_ROOT_PARENT, object_num);
9508 if (ret != PTP_RC_OK)
9513 #endif /* TIZEN_EXT */