1 /**
2 * \file libmtp.c
3 *
4 * Copyright (C) 2005-2009 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>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
24 *
25 * This file provides an interface "glue" to the underlying
26 * PTP implementation from libgphoto2. It uses some local
27 * code to convert from/to UTF-8 (stored in unicode.c/.h)
28 * and some small utility functions, mainly for debugging
29 * (stored in util.c/.h).
30 *
31 * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are
32 * plain copied from the libhphoto2 codebase.
33 *
34 * The files libusb-glue.c/.h are just what they say: an
35 * interface to libusb for the actual, physical USB traffic.
36 */
37 #include "config.h"
38 #include "libmtp.h"
39 #include "unicode.h"
40 #include "ptp.h"
41 #include "libusb-glue.h"
42 #include "device-flags.h"
43 #include "playlist-spl.h"
44
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <string.h>
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <fcntl.h>
51 #include <time.h>
52 #include <errno.h>
53 #ifdef _MSC_VER // For MSVC++
54 #define USE_WINDOWS_IO_H
55 #include <io.h>
56 #endif
57
58 /* To enable PTP level debug prints (all ptp_debug(...)), switch on this */
59 //#define ENABLE_PTP_DEBUG
60
61 /*
62 * This is a mapping between libmtp internal MTP filetypes and
63 * the libgphoto2/PTP equivalent defines. We need this because
64 * otherwise the libmtp.h device has to be dependent on ptp.h
65 * to be installed too, and we don't want that.
66 */
67 //typedef struct filemap_struct filemap_t;
68 typedef struct filemap_struct {
69 char *description; /**< Text description for the file type */
70 LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */
71 uint16_t ptp_id; /**< PTP ID for the filetype */
72 struct filemap_struct *next;
73 } filemap_t;
74
75 /*
76 * This is a mapping between libmtp internal MTP properties and
77 * the libgphoto2/PTP equivalent defines. We need this because
78 * otherwise the libmtp.h device has to be dependent on ptp.h
79 * to be installed too, and we don't want that.
80 */
81 typedef struct propertymap_struct {
82 char *description; /**< Text description for the property */
83 LIBMTP_property_t id; /**< LIBMTP internal type for the property */
84 uint16_t ptp_id; /**< PTP ID for the property */
85 struct propertymap_struct *next;
86 } propertymap_t;
87
88 // Global variables
89 // This holds the global filetype mapping table
90 static filemap_t *filemap = NULL;
91 // This holds the global property mapping table
92 static propertymap_t *propertymap = NULL;
93
94 static int load_cache_on_demand = 0;
95 /*
96 * Forward declarations of local (static) functions.
97 */
98 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
99 uint16_t const ptp_id);
100 static void init_filemap();
101 static int register_property(char const * const description, LIBMTP_property_t const id,
102 uint16_t const ptp_id);
103 static void init_propertymap();
104 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
105 LIBMTP_error_number_t errornumber,
106 char const * const error_text);
107 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
108 uint16_t ptp_error,
109 char const * const error_text);
110 static void flush_handles(LIBMTP_mtpdevice_t *device);
111 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
112 PTPParams *params,
113 uint32_t storageid,
114 uint32_t parent);
115 static void free_storage_list(LIBMTP_mtpdevice_t *device);
116 static int sort_storage_by(LIBMTP_mtpdevice_t *device, int const sortby);
117 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device, uint64_t fitsize);
118 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
119 LIBMTP_devicestorage_t *storage,
120 uint64_t *freespace);
121 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
122 LIBMTP_devicestorage_t *storage,
123 uint64_t const filesize);
124 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
125 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
126 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
127 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
128 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
129 char **unicstring, uint16_t property);
130 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
131 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd);
132 static char *get_iso8601_stamp(void);
133 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
134 uint16_t const attribute_id);
135 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
136 uint16_t const attribute_id, uint64_t const value_default);
137 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
138 uint16_t const attribute_id, uint32_t const value_default);
139 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
140 uint16_t const attribute_id, uint16_t const value_default);
141 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
142 uint16_t const attribute_id, uint8_t const value_default);
143 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
144 uint16_t const attribute_id, char const * const string);
145 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
146 uint16_t const attribute_id, uint32_t const value);
147 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
148 uint16_t const attribute_id, uint16_t const value);
149 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
150 uint16_t const attribute_id, uint8_t const value);
151 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
152 LIBMTP_track_t *track);
153 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent);
154 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
155 char const * const name,
156 char const * const artist,
157 char const * const composer,
158 char const * const genre,
159 uint32_t const parenthandle,
160 uint32_t const storageid,
161 uint16_t const objectformat,
162 char const * const suffix,
163 uint32_t * const newid,
164 uint32_t const * const tracks,
165 uint32_t const no_tracks);
166 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
167 char const * const name,
168 char const * const artist,
169 char const * const composer,
170 char const * const genre,
171 uint32_t const objecthandle,
172 uint16_t const objectformat,
173 uint32_t const * const tracks,
174 uint32_t const no_tracks);
175 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
176 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
177 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
178 static int set_object_filename(LIBMTP_mtpdevice_t *device,
179 uint32_t object_id,
180 uint16_t ptp_type,
181 const char **newname);
182
183 /**
184 * These are to wrap the get/put handlers to convert from the MTP types to PTP types
185 * in a reliable way
186 */
187 typedef struct _MTPDataHandler {
188 MTPDataGetFunc getfunc;
189 MTPDataPutFunc putfunc;
190 void *priv;
191 } MTPDataHandler;
192
193 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
194 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen);
195
196 /**
197 * Checks if a filename ends with ".ogg". Used in various
198 * situations when the device has no idea that it support
199 * OGG but still does.
200 *
201 * @param name string to be checked.
202 * @return 0 if this does not end with ogg, any other
203 * value means it does.
204 */
has_ogg_extension(char * name)205 static int has_ogg_extension(char *name) {
206 char *ptype;
207
208 if (name == NULL)
209 return 0;
210 ptype = strrchr(name,'.');
211 if (ptype == NULL)
212 return 0;
213 if (!strcasecmp (ptype, ".ogg"))
214 return 1;
215 return 0;
216 }
217
218 /**
219 * Checks if a filename ends with ".flac". Used in various
220 * situations when the device has no idea that it support
221 * FLAC but still does.
222 *
223 * @param name string to be checked.
224 * @return 0 if this does not end with flac, any other
225 * value means it does.
226 */
has_flac_extension(char * name)227 static int has_flac_extension(char *name) {
228 char *ptype;
229
230 if (name == NULL)
231 return 0;
232 ptype = strrchr(name,'.');
233 if (ptype == NULL)
234 return 0;
235 if (!strcasecmp (ptype, ".flac"))
236 return 1;
237 return 0;
238 }
239
240
241
242 /**
243 * Create a new file mapping entry
244 * @return a newly allocated filemapping entry.
245 */
new_filemap_entry()246 static filemap_t *new_filemap_entry()
247 {
248 filemap_t *filemap;
249
250 filemap = (filemap_t *)malloc(sizeof(filemap_t));
251
252 if( filemap != NULL ) {
253 filemap->description = NULL;
254 filemap->id = LIBMTP_FILETYPE_UNKNOWN;
255 filemap->ptp_id = PTP_OFC_Undefined;
256 filemap->next = NULL;
257 }
258
259 return filemap;
260 }
261
262 /**
263 * Register an MTP or PTP filetype for data retrieval
264 *
265 * @param description Text description of filetype
266 * @param id libmtp internal filetype id
267 * @param ptp_id PTP filetype id
268 * @return 0 for success any other value means error.
269 */
register_filetype(char const * const description,LIBMTP_filetype_t const id,uint16_t const ptp_id)270 static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
271 uint16_t const ptp_id)
272 {
273 filemap_t *new = NULL, *current;
274
275 // Has this LIBMTP filetype been registered before ?
276 current = filemap;
277 while (current != NULL) {
278 if(current->id == id) {
279 break;
280 }
281 current = current->next;
282 }
283
284 // Create the entry
285 if(current == NULL) {
286 new = new_filemap_entry();
287 if(new == NULL) {
288 return 1;
289 }
290
291 new->id = id;
292 if(description != NULL) {
293 new->description = strdup(description);
294 }
295 new->ptp_id = ptp_id;
296
297 // Add the entry to the list
298 if(filemap == NULL) {
299 filemap = new;
300 } else {
301 current = filemap;
302 while (current->next != NULL ) current=current->next;
303 current->next = new;
304 }
305 // Update the existing entry
306 } else {
307 if (current->description != NULL) {
308 free(current->description);
309 }
310 current->description = NULL;
311 if(description != NULL) {
312 current->description = strdup(description);
313 }
314 current->ptp_id = ptp_id;
315 }
316
317 return 0;
318 }
319
init_filemap()320 static void init_filemap()
321 {
322 register_filetype("Folder", LIBMTP_FILETYPE_FOLDER, PTP_OFC_Association);
323 register_filetype("MediaCard", LIBMTP_FILETYPE_MEDIACARD, PTP_OFC_MTP_MediaCard);
324 register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);
325 register_filetype("ISO MPEG-1 Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);
326 register_filetype("ISO MPEG-1 Audio Layer 2", LIBMTP_FILETYPE_MP2, PTP_OFC_MTP_MP2);
327 register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);
328 register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
329 register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
330 register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
331 register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
332 register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
333 register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
334 register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
335 register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
336 register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);
337 register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);
338 register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);
339 register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);
340 register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);
341 register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);
342 register_filetype("JP2 file", LIBMTP_FILETYPE_JP2, PTP_OFC_JP2);
343 register_filetype("JPX file", LIBMTP_FILETYPE_JPX, PTP_OFC_JPX);
344 register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);
345 register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);
346 register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);
347 register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);
348 register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);
349 register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);
350 register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);
351 register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);
352 register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);
353 register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);
354 register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);
355 register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);
356 register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);
357 register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);
358 register_filetype("XML file", LIBMTP_FILETYPE_XML, PTP_OFC_MTP_XMLDocument);
359 register_filetype("DOC file", LIBMTP_FILETYPE_DOC, PTP_OFC_MTP_MSWordDocument);
360 register_filetype("XLS file", LIBMTP_FILETYPE_XLS, PTP_OFC_MTP_MSExcelSpreadsheetXLS);
361 register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
362 register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
363 register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
364 register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
365 register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
366 register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
367 }
368
369 /**
370 * Returns the PTP filetype that maps to a certain libmtp internal file type.
371 * @param intype the MTP library interface type
372 * @return the PTP (libgphoto2) interface type
373 */
map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)374 static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype)
375 {
376 filemap_t *current;
377
378 current = filemap;
379
380 while (current != NULL) {
381 if(current->id == intype) {
382 return current->ptp_id;
383 }
384 current = current->next;
385 }
386 // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");
387 return PTP_OFC_Undefined;
388 }
389
390
391 /**
392 * Returns the MTP internal interface type that maps to a certain ptp
393 * interface type.
394 * @param intype the PTP (libgphoto2) interface type
395 * @return the MTP library interface type
396 */
map_ptp_type_to_libmtp_type(uint16_t intype)397 static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype)
398 {
399 filemap_t *current;
400
401 current = filemap;
402
403 while (current != NULL) {
404 if(current->ptp_id == intype) {
405 return current->id;
406 }
407 current = current->next;
408 }
409 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
410 return LIBMTP_FILETYPE_UNKNOWN;
411 }
412
413 /**
414 * Create a new property mapping entry
415 * @return a newly allocated propertymapping entry.
416 */
new_propertymap_entry()417 static propertymap_t *new_propertymap_entry()
418 {
419 propertymap_t *propertymap;
420
421 propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
422
423 if( propertymap != NULL ) {
424 propertymap->description = NULL;
425 propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
426 propertymap->ptp_id = 0;
427 propertymap->next = NULL;
428 }
429
430 return propertymap;
431 }
432
433 /**
434 * Register an MTP or PTP property for data retrieval
435 *
436 * @param description Text description of property
437 * @param id libmtp internal property id
438 * @param ptp_id PTP property id
439 * @return 0 for success any other value means error.
440 */
register_property(char const * const description,LIBMTP_property_t const id,uint16_t const ptp_id)441 static int register_property(char const * const description, LIBMTP_property_t const id,
442 uint16_t const ptp_id)
443 {
444 propertymap_t *new = NULL, *current;
445
446 // Has this LIBMTP propety been registered before ?
447 current = propertymap;
448 while (current != NULL) {
449 if(current->id == id) {
450 break;
451 }
452 current = current->next;
453 }
454
455 // Create the entry
456 if(current == NULL) {
457 new = new_propertymap_entry();
458 if(new == NULL) {
459 return 1;
460 }
461
462 new->id = id;
463 if(description != NULL) {
464 new->description = strdup(description);
465 }
466 new->ptp_id = ptp_id;
467
468 // Add the entry to the list
469 if(propertymap == NULL) {
470 propertymap = new;
471 } else {
472 current = propertymap;
473 while (current->next != NULL ) current=current->next;
474 current->next = new;
475 }
476 // Update the existing entry
477 } else {
478 if (current->description != NULL) {
479 free(current->description);
480 }
481 current->description = NULL;
482 if(description != NULL) {
483 current->description = strdup(description);
484 }
485 current->ptp_id = ptp_id;
486 }
487
488 return 0;
489 }
490
init_propertymap()491 static void init_propertymap()
492 {
493 register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
494 register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
495 register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
496 register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
497 register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
498 register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
499 register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
500 register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
501 register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
502 register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
503 register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
504 register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
505 register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
506 register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
507 register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
508 register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
509 register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
510 register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
511 register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
512 register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
513 register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
514 register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
515 register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
516 register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
517 register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
518 register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
519 register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
520 register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
521 register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
522 register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
523 register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
524 register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
525 register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
526 register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
527 register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
528 register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
529 register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
530 register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
531 register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
532 register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
533 register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
534 register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
535 register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
536 register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
537 register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
538 register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
539 register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
540 register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
541 register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
542 register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
543 register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
544 register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
545 register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
546 register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
547 register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
548 register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
549 register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
550 register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
551 register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
552 register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
553 register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
554 register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
555 register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
556 register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
557 register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
558 register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
559 register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
560 register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
561 register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
562 register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
563 register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
564 register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
565 register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
566 register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
567 register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
568 register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
569 register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
570 register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
571 register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
572 register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
573 register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
574 register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
575 register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
576 register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
577 register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
578 register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
579 register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
580 register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
581 register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
582 register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
583 register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
584 register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
585 register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
586 register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
587 register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
588 register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
589 register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
590 register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
591 register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
592 register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
593 register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
594 register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
595 register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
596 register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
597 register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
598 register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
599 register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
600 register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
601 register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
602 register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
603 register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
604 register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
605 register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
606 register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
607 register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
608 register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
609 register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
610 register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
611 register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
612 register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
613 register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
614 register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
615 register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
616 register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
617 register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
618 register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
619 register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
620 register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
621 register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
622 register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
623 register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
624 register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
625 register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
626 register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
627 register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
628 register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
629 register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
630 register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
631 register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
632 register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
633 register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
634 register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
635 register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
636 register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
637 register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
638 register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
639 register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
640 register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
641 register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
642 register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
643 register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
644 register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
645 register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
646 register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
647 register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
648 register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
649 register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
650 register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
651 register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
652 register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
653 register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
654 register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
655 register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
656 register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
657 register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
658 register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
659 register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
660 register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
661 }
662
663 /**
664 * Returns the PTP property that maps to a certain libmtp internal property type.
665 * @param inproperty the MTP library interface property
666 * @return the PTP (libgphoto2) property type
667 */
map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)668 static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
669 {
670 propertymap_t *current;
671
672 current = propertymap;
673
674 while (current != NULL) {
675 if(current->id == inproperty) {
676 return current->ptp_id;
677 }
678 current = current->next;
679 }
680 return 0;
681 }
682
683
684 /**
685 * Returns the MTP internal interface property that maps to a certain ptp
686 * interface property.
687 * @param inproperty the PTP (libgphoto2) interface property
688 * @return the MTP library interface property
689 */
map_ptp_property_to_libmtp_property(uint16_t inproperty)690 static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
691 {
692 propertymap_t *current;
693
694 current = propertymap;
695
696 while (current != NULL) {
697 if(current->ptp_id == inproperty) {
698 return current->id;
699 }
700 current = current->next;
701 }
702 // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
703 return LIBMTP_PROPERTY_UNKNOWN;
704 }
705
706
707 /**
708 * Initialize the library. You are only supposed to call this
709 * one, before using the library for the first time in a program.
710 * Never re-initialize libmtp!
711 *
712 * The only thing this does at the moment is to initialise the
713 * filetype mapping table.
714 */
LIBMTP_Init(void)715 void LIBMTP_Init(void)
716 {
717 init_filemap();
718 init_propertymap();
719 return;
720 }
721
722
723 /**
724 * This helper function returns a textual description for a libmtp
725 * file type to be used in dialog boxes etc.
726 * @param intype the libmtp internal filetype to get a description for.
727 * @return a string representing the filetype, this must <b>NOT</b>
728 * be free():ed by the caller!
729 */
LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)730 char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype)
731 {
732 filemap_t *current;
733
734 current = filemap;
735
736 while (current != NULL) {
737 if(current->id == intype) {
738 return current->description;
739 }
740 current = current->next;
741 }
742
743 return "Unknown filetype";
744 }
745
746 /**
747 * This helper function returns a textual description for a libmtp
748 * property to be used in dialog boxes etc.
749 * @param inproperty the libmtp internal property to get a description for.
750 * @return a string representing the filetype, this must <b>NOT</b>
751 * be free():ed by the caller!
752 */
LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)753 char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
754 {
755 propertymap_t *current;
756
757 current = propertymap;
758
759 while (current != NULL) {
760 if(current->id == inproperty) {
761 return current->description;
762 }
763 current = current->next;
764 }
765
766 return "Unknown property";
767 }
768
769 /**
770 * This function will do its best to fit a 16bit
771 * value into a PTP object property if the property
772 * is limited in range or step sizes.
773 */
adjust_u16(uint16_t val,PTPObjectPropDesc * opd)774 static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd)
775 {
776 switch (opd->FormFlag) {
777 case PTP_DPFF_Range:
778 if (val < opd->FORM.Range.MinimumValue.u16) {
779 return opd->FORM.Range.MinimumValue.u16;
780 }
781 if (val > opd->FORM.Range.MaximumValue.u16) {
782 return opd->FORM.Range.MaximumValue.u16;
783 }
784 // Round down to last step.
785 if (val % opd->FORM.Range.StepSize.u16 != 0) {
786 return val - (val % opd->FORM.Range.StepSize.u16);
787 }
788 return val;
789 break;
790 case PTP_DPFF_Enumeration:
791 {
792 int i;
793 uint16_t bestfit = opd->FORM.Enum.SupportedValue[0].u16;
794
795 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
796 if (val == opd->FORM.Enum.SupportedValue[i].u16) {
797 return val;
798 }
799 // Rough guess of best fit
800 if (opd->FORM.Enum.SupportedValue[i].u16 < val) {
801 bestfit = opd->FORM.Enum.SupportedValue[i].u16;
802 }
803 }
804 // Just some default that'll work.
805 return bestfit;
806 }
807 default:
808 // Will accept any value
809 break;
810 }
811 return val;
812 }
813
814 /**
815 * This function will do its best to fit a 32bit
816 * value into a PTP object property if the property
817 * is limited in range or step sizes.
818 */
adjust_u32(uint32_t val,PTPObjectPropDesc * opd)819 static uint32_t adjust_u32(uint32_t val, PTPObjectPropDesc *opd)
820 {
821 switch (opd->FormFlag) {
822 case PTP_DPFF_Range:
823 if (val < opd->FORM.Range.MinimumValue.u32) {
824 return opd->FORM.Range.MinimumValue.u32;
825 }
826 if (val > opd->FORM.Range.MaximumValue.u32) {
827 return opd->FORM.Range.MaximumValue.u32;
828 }
829 // Round down to last step.
830 if (val % opd->FORM.Range.StepSize.u32 != 0) {
831 return val - (val % opd->FORM.Range.StepSize.u32);
832 }
833 return val;
834 break;
835 case PTP_DPFF_Enumeration:
836 {
837 int i;
838 uint32_t bestfit = opd->FORM.Enum.SupportedValue[0].u32;
839
840 for (i=0; i<opd->FORM.Enum.NumberOfValues; i++) {
841 if (val == opd->FORM.Enum.SupportedValue[i].u32) {
842 return val;
843 }
844 // Rough guess of best fit
845 if (opd->FORM.Enum.SupportedValue[i].u32 < val) {
846 bestfit = opd->FORM.Enum.SupportedValue[i].u32;
847 }
848 }
849 // Just some default that'll work.
850 return bestfit;
851 }
852 default:
853 // Will accept any value
854 break;
855 }
856 return val;
857 }
858
859 /**
860 * This function returns a newly created ISO 8601 timestamp with the
861 * current time in as high precision as possible. It even adds
862 * the time zone if it can.
863 */
get_iso8601_stamp(void)864 static char *get_iso8601_stamp(void)
865 {
866 time_t curtime;
867 struct tm *loctime;
868 char tmp[64];
869
870 curtime = time(NULL);
871 loctime = localtime(&curtime);
872 strftime (tmp, sizeof(tmp), "%Y%m%dT%H%M%S.0%z", loctime);
873 return strdup(tmp);
874 }
875
876 /**
877 * Gets the allowed values (range or enum) for a property
878 * @param device a pointer to an MTP device
879 * @param property the property to query
880 * @param filetype the filetype of the object you want to set values for
881 * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
882 * receive the allowed values. Call LIBMTP_destroy_allowed_values_t
883 * on this on successful completion.
884 * @return 0 on success, any other value means failure
885 */
LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype,LIBMTP_allowed_values_t * allowed_vals)886 int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
887 LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
888 {
889 PTPObjectPropDesc opd;
890 uint16_t ret = 0;
891
892 ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
893 if (ret != PTP_RC_OK) {
894 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
895 return -1;
896 }
897
898 if (opd.FormFlag == PTP_OPFF_Enumeration) {
899 int i = 0;
900
901 allowed_vals->is_range = 0;
902 allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
903
904 switch (opd.DataType)
905 {
906 case PTP_DTC_INT8:
907 allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
908 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
909 break;
910 case PTP_DTC_UINT8:
911 allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
912 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
913 break;
914 case PTP_DTC_INT16:
915 allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
916 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
917 break;
918 case PTP_DTC_UINT16:
919 allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
920 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
921 break;
922 case PTP_DTC_INT32:
923 allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
924 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
925 break;
926 case PTP_DTC_UINT32:
927 allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
928 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
929 break;
930 case PTP_DTC_INT64:
931 allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
932 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
933 break;
934 case PTP_DTC_UINT64:
935 allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
936 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
937 break;
938 }
939
940 for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
941 switch (opd.DataType)
942 {
943 case PTP_DTC_INT8:
944 allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
945 break;
946 case PTP_DTC_UINT8:
947 allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
948 break;
949 case PTP_DTC_INT16:
950 allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
951 break;
952 case PTP_DTC_UINT16:
953 allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
954 break;
955 case PTP_DTC_INT32:
956 allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
957 break;
958 case PTP_DTC_UINT32:
959 allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
960 break;
961 case PTP_DTC_INT64:
962 allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
963 break;
964 case PTP_DTC_UINT64:
965 allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
966 break;
967 }
968 }
969 ptp_free_objectpropdesc(&opd);
970 return 0;
971 } else if (opd.FormFlag == PTP_OPFF_Range) {
972 allowed_vals->is_range = 1;
973
974 switch (opd.DataType)
975 {
976 case PTP_DTC_INT8:
977 allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
978 allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
979 allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
980 allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
981 break;
982 case PTP_DTC_UINT8:
983 allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
984 allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
985 allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
986 allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
987 break;
988 case PTP_DTC_INT16:
989 allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
990 allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
991 allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
992 allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
993 break;
994 case PTP_DTC_UINT16:
995 allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
996 allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
997 allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
998 allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
999 break;
1000 case PTP_DTC_INT32:
1001 allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
1002 allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
1003 allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
1004 allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
1005 break;
1006 case PTP_DTC_UINT32:
1007 allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
1008 allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
1009 allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
1010 allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
1011 break;
1012 case PTP_DTC_INT64:
1013 allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
1014 allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
1015 allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
1016 allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
1017 break;
1018 case PTP_DTC_UINT64:
1019 allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
1020 allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
1021 allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
1022 allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
1023 break;
1024 }
1025 return 0;
1026 } else
1027 return -1;
1028 }
1029
1030 /**
1031 * Destroys a LIBMTP_allowed_values_t struct
1032 * @param allowed_vals the struct to destroy
1033 */
LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t * allowed_vals)1034 void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
1035 {
1036 if (!allowed_vals->is_range)
1037 {
1038 switch (allowed_vals->datatype)
1039 {
1040 case LIBMTP_DATATYPE_INT8:
1041 if (allowed_vals->i8vals)
1042 free(allowed_vals->i8vals);
1043 break;
1044 case LIBMTP_DATATYPE_UINT8:
1045 if (allowed_vals->u8vals)
1046 free(allowed_vals->u8vals);
1047 break;
1048 case LIBMTP_DATATYPE_INT16:
1049 if (allowed_vals->i16vals)
1050 free(allowed_vals->i16vals);
1051 break;
1052 case LIBMTP_DATATYPE_UINT16:
1053 if (allowed_vals->u16vals)
1054 free(allowed_vals->u16vals);
1055 break;
1056 case LIBMTP_DATATYPE_INT32:
1057 if (allowed_vals->i32vals)
1058 free(allowed_vals->i32vals);
1059 break;
1060 case LIBMTP_DATATYPE_UINT32:
1061 if (allowed_vals->u32vals)
1062 free(allowed_vals->u32vals);
1063 break;
1064 case LIBMTP_DATATYPE_INT64:
1065 if (allowed_vals->i64vals)
1066 free(allowed_vals->i64vals);
1067 break;
1068 case LIBMTP_DATATYPE_UINT64:
1069 if (allowed_vals->u64vals)
1070 free(allowed_vals->u64vals);
1071 break;
1072 }
1073 }
1074 }
1075
1076 /**
1077 * Determine if a property is supported for a given file type
1078 * @param device a pointer to an MTP device
1079 * @param property the property to query
1080 * @param filetype the filetype of the object you want to set values for
1081 * @return 0 if not supported, positive if supported, negative on error
1082 */
LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t * device,LIBMTP_property_t const property,LIBMTP_filetype_t const filetype)1083 int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
1084 LIBMTP_filetype_t const filetype)
1085 {
1086 uint16_t *props = NULL;
1087 uint32_t propcnt = 0;
1088 uint16_t ret = 0;
1089 int i = 0;
1090 int supported = 0;
1091 uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
1092
1093 ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
1094 if (ret != PTP_RC_OK) {
1095 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
1096 return -1;
1097 }
1098
1099 for (i = 0; i < propcnt; i++) {
1100 if (props[i] == ptp_prop) {
1101 supported = 1;
1102 break;
1103 }
1104 }
1105
1106 free(props);
1107
1108 return supported;
1109 }
1110
1111 /**
1112 * Retrieves a string from an object
1113 *
1114 * @param device a pointer to an MTP device.
1115 * @param object_id Object reference
1116 * @param attribute_id MTP attribute ID
1117 * @return valid string or NULL on failure. The returned string
1118 * must bee <code>free()</code>:ed by the caller after
1119 * use.
1120 */
LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id)1121 char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1122 LIBMTP_property_t const attribute_id)
1123 {
1124 return get_string_from_object(device, object_id, attribute_id);
1125 }
1126
1127 /**
1128 * Retrieves an unsigned 64-bit integer from an object attribute
1129 *
1130 * @param device a pointer to an MTP device.
1131 * @param object_id Object reference
1132 * @param attribute_id MTP attribute ID
1133 * @param value_default Default value to return on failure
1134 * @return the value
1135 */
LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint64_t const value_default)1136 uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1137 LIBMTP_property_t const attribute_id, uint64_t const value_default)
1138 {
1139 return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1140 }
1141
1142 /**
1143 * Retrieves an unsigned 32-bit integer from an object attribute
1144 *
1145 * @param device a pointer to an MTP device.
1146 * @param object_id Object reference
1147 * @param attribute_id MTP attribute ID
1148 * @param value_default Default value to return on failure
1149 * @return the value
1150 */
LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value_default)1151 uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1152 LIBMTP_property_t const attribute_id, uint32_t const value_default)
1153 {
1154 return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1155 }
1156
1157 /**
1158 * Retrieves an unsigned 16-bit integer from an object attribute
1159 *
1160 * @param device a pointer to an MTP device.
1161 * @param object_id Object reference
1162 * @param attribute_id MTP attribute ID
1163 * @param value_default Default value to return on failure
1164 * @return a value
1165 */
LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value_default)1166 uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1167 LIBMTP_property_t const attribute_id, uint16_t const value_default)
1168 {
1169 return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1170 }
1171
1172 /**
1173 * Retrieves an unsigned 8-bit integer from an object attribute
1174 *
1175 * @param device a pointer to an MTP device.
1176 * @param object_id Object reference
1177 * @param attribute_id MTP attribute ID
1178 * @param value_default Default value to return on failure
1179 * @return a value
1180 */
LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value_default)1181 uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1182 LIBMTP_property_t const attribute_id, uint8_t const value_default)
1183 {
1184 return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
1185 }
1186
1187 /**
1188 * Sets an object attribute from a string
1189 *
1190 * @param device a pointer to an MTP device.
1191 * @param object_id Object reference
1192 * @param attribute_id MTP attribute ID
1193 * @param string string value to set
1194 * @return 0 on success, any other value means failure
1195 */
LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,char const * const string)1196 int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1197 LIBMTP_property_t const attribute_id, char const * const string)
1198 {
1199 return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
1200 }
1201
1202
1203 /**
1204 * Sets an object attribute from an unsigned 32-bit integer
1205 *
1206 * @param device a pointer to an MTP device.
1207 * @param object_id Object reference
1208 * @param attribute_id MTP attribute ID
1209 * @param value 32-bit unsigned integer to set
1210 * @return 0 on success, any other value means failure
1211 */
LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint32_t const value)1212 int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1213 LIBMTP_property_t const attribute_id, uint32_t const value)
1214 {
1215 return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1216 }
1217
1218 /**
1219 * Sets an object attribute from an unsigned 16-bit integer
1220 *
1221 * @param device a pointer to an MTP device.
1222 * @param object_id Object reference
1223 * @param attribute_id MTP attribute ID
1224 * @param value 16-bit unsigned integer to set
1225 * @return 0 on success, any other value means failure
1226 */
LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint16_t const value)1227 int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1228 LIBMTP_property_t const attribute_id, uint16_t const value)
1229 {
1230 return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1231 }
1232
1233 /**
1234 * Sets an object attribute from an unsigned 8-bit integer
1235 *
1236 * @param device a pointer to an MTP device.
1237 * @param object_id Object reference
1238 * @param attribute_id MTP attribute ID
1239 * @param value 8-bit unsigned integer to set
1240 * @return 0 on success, any other value means failure
1241 */
LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,LIBMTP_property_t const attribute_id,uint8_t const value)1242 int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1243 LIBMTP_property_t const attribute_id, uint8_t const value)
1244 {
1245 return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
1246 }
1247
1248 /**
1249 * Retrieves a string from an object
1250 *
1251 * @param device a pointer to an MTP device.
1252 * @param object_id Object reference
1253 * @param attribute_id PTP attribute ID
1254 * @return valid string or NULL on failure. The returned string
1255 * must bee <code>free()</code>:ed by the caller after
1256 * use.
1257 */
get_string_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id)1258 static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1259 uint16_t const attribute_id)
1260 {
1261 PTPPropertyValue propval;
1262 char *retstring = NULL;
1263 PTPParams *params = (PTPParams *) device->params;
1264 uint16_t ret;
1265 MTPProperties *prop;
1266
1267 if ( device == NULL || object_id == 0) {
1268 return NULL;
1269 }
1270
1271 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1272 if (prop) {
1273 if (prop->propval.str != NULL)
1274 return strdup(prop->propval.str);
1275 else
1276 return NULL;
1277 }
1278
1279 ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1280 if (ret == PTP_RC_OK) {
1281 if (propval.str != NULL) {
1282 retstring = (char *) strdup(propval.str);
1283 free(propval.str);
1284 }
1285 } else {
1286 add_ptp_error_to_errorstack(device, ret, "get_string_from_object(): could not get object string.");
1287 }
1288
1289 return retstring;
1290 }
1291
1292 /**
1293 * Retrieves an unsigned 64-bit integer from an object attribute
1294 *
1295 * @param device a pointer to an MTP device.
1296 * @param object_id Object reference
1297 * @param attribute_id PTP attribute ID
1298 * @param value_default Default value to return on failure
1299 * @return the value
1300 */
get_u64_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint64_t const value_default)1301 static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1302 uint16_t const attribute_id, uint64_t const value_default)
1303 {
1304 PTPPropertyValue propval;
1305 uint64_t retval = value_default;
1306 PTPParams *params = (PTPParams *) device->params;
1307 uint16_t ret;
1308 MTPProperties *prop;
1309
1310 if ( device == NULL ) {
1311 return value_default;
1312 }
1313
1314 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1315 if (prop)
1316 return prop->propval.u64;
1317
1318 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1319 attribute_id,
1320 &propval,
1321 PTP_DTC_UINT64);
1322 if (ret == PTP_RC_OK) {
1323 retval = propval.u64;
1324 } else {
1325 add_ptp_error_to_errorstack(device, ret, "get_u64_from_object(): could not get unsigned 64bit integer from object.");
1326 }
1327
1328 return retval;
1329 }
1330
1331 /**
1332 * Retrieves an unsigned 32-bit integer from an object attribute
1333 *
1334 * @param device a pointer to an MTP device.
1335 * @param object_id Object reference
1336 * @param attribute_id PTP attribute ID
1337 * @param value_default Default value to return on failure
1338 * @return the value
1339 */
get_u32_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value_default)1340 static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
1341 uint16_t const attribute_id, uint32_t const value_default)
1342 {
1343 PTPPropertyValue propval;
1344 uint32_t retval = value_default;
1345 PTPParams *params = (PTPParams *) device->params;
1346 uint16_t ret;
1347 MTPProperties *prop;
1348
1349 if ( device == NULL ) {
1350 return value_default;
1351 }
1352
1353 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1354 if (prop)
1355 return prop->propval.u32;
1356
1357 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1358 attribute_id,
1359 &propval,
1360 PTP_DTC_UINT32);
1361 if (ret == PTP_RC_OK) {
1362 retval = propval.u32;
1363 } else {
1364 add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
1365 }
1366 return retval;
1367 }
1368
1369 /**
1370 * Retrieves an unsigned 16-bit integer from an object attribute
1371 *
1372 * @param device a pointer to an MTP device.
1373 * @param object_id Object reference
1374 * @param attribute_id PTP attribute ID
1375 * @param value_default Default value to return on failure
1376 * @return a value
1377 */
get_u16_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value_default)1378 static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1379 uint16_t const attribute_id, uint16_t const value_default)
1380 {
1381 PTPPropertyValue propval;
1382 uint16_t retval = value_default;
1383 PTPParams *params = (PTPParams *) device->params;
1384 uint16_t ret;
1385 MTPProperties *prop;
1386
1387 if ( device == NULL ) {
1388 return value_default;
1389 }
1390
1391 // This O(n) search should not be used so often, since code
1392 // using the cached properties don't usually call this function.
1393 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1394 if (prop)
1395 return prop->propval.u16;
1396
1397 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1398 attribute_id,
1399 &propval,
1400 PTP_DTC_UINT16);
1401 if (ret == PTP_RC_OK) {
1402 retval = propval.u16;
1403 } else {
1404 add_ptp_error_to_errorstack(device, ret, "get_u16_from_object(): could not get unsigned 16bit integer from object.");
1405 }
1406
1407 return retval;
1408 }
1409
1410 /**
1411 * Retrieves an unsigned 8-bit integer from an object attribute
1412 *
1413 * @param device a pointer to an MTP device.
1414 * @param object_id Object reference
1415 * @param attribute_id PTP attribute ID
1416 * @param value_default Default value to return on failure
1417 * @return a value
1418 */
get_u8_from_object(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value_default)1419 static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1420 uint16_t const attribute_id, uint8_t const value_default)
1421 {
1422 PTPPropertyValue propval;
1423 uint8_t retval = value_default;
1424 PTPParams *params = (PTPParams *) device->params;
1425 uint16_t ret;
1426 MTPProperties *prop;
1427
1428 if ( device == NULL ) {
1429 return value_default;
1430 }
1431
1432 // This O(n) search should not be used so often, since code
1433 // using the cached properties don't usually call this function.
1434 prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
1435 if (prop)
1436 return prop->propval.u8;
1437
1438 ret = ptp_mtp_getobjectpropvalue(params, object_id,
1439 attribute_id,
1440 &propval,
1441 PTP_DTC_UINT8);
1442 if (ret == PTP_RC_OK) {
1443 retval = propval.u8;
1444 } else {
1445 add_ptp_error_to_errorstack(device, ret, "get_u8_from_object(): could not get unsigned 8bit integer from object.");
1446 }
1447
1448 return retval;
1449 }
1450
1451 /**
1452 * Sets an object attribute from a string
1453 *
1454 * @param device a pointer to an MTP device.
1455 * @param object_id Object reference
1456 * @param attribute_id PTP attribute ID
1457 * @param string string value to set
1458 * @return 0 on success, any other value means failure
1459 */
set_object_string(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,char const * const string)1460 static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1461 uint16_t const attribute_id, char const * const string)
1462 {
1463 PTPPropertyValue propval;
1464 PTPParams *params = (PTPParams *) device->params;
1465 uint16_t ret;
1466
1467 if (device == NULL || string == NULL) {
1468 return -1;
1469 }
1470
1471 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1472 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_string(): could not set object string: "
1473 "PTP_OC_MTP_SetObjectPropValue not supported.");
1474 return -1;
1475 }
1476 propval.str = (char *) string;
1477 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
1478 if (ret != PTP_RC_OK) {
1479 add_ptp_error_to_errorstack(device, ret, "set_object_string(): could not set object string.");
1480 return -1;
1481 }
1482
1483 return 0;
1484 }
1485
1486
1487 /**
1488 * Sets an object attribute from an unsigned 32-bit integer
1489 *
1490 * @param device a pointer to an MTP device.
1491 * @param object_id Object reference
1492 * @param attribute_id PTP attribute ID
1493 * @param value 32-bit unsigned integer to set
1494 * @return 0 on success, any other value means failure
1495 */
set_object_u32(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint32_t const value)1496 static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1497 uint16_t const attribute_id, uint32_t const value)
1498 {
1499 PTPPropertyValue propval;
1500 PTPParams *params = (PTPParams *) device->params;
1501 uint16_t ret;
1502
1503 if (device == NULL) {
1504 return -1;
1505 }
1506
1507 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1508 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u32(): could not set unsigned 32bit integer property: "
1509 "PTP_OC_MTP_SetObjectPropValue not supported.");
1510 return -1;
1511 }
1512
1513 propval.u32 = value;
1514 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT32);
1515 if (ret != PTP_RC_OK) {
1516 add_ptp_error_to_errorstack(device, ret, "set_object_u32(): could not set unsigned 32bit integer property.");
1517 return -1;
1518 }
1519
1520 return 0;
1521 }
1522
1523 /**
1524 * Sets an object attribute from an unsigned 16-bit integer
1525 *
1526 * @param device a pointer to an MTP device.
1527 * @param object_id Object reference
1528 * @param attribute_id PTP attribute ID
1529 * @param value 16-bit unsigned integer to set
1530 * @return 0 on success, any other value means failure
1531 */
set_object_u16(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint16_t const value)1532 static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1533 uint16_t const attribute_id, uint16_t const value)
1534 {
1535 PTPPropertyValue propval;
1536 PTPParams *params = (PTPParams *) device->params;
1537 uint16_t ret;
1538
1539 if (device == NULL) {
1540 return 1;
1541 }
1542
1543 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1544 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u16(): could not set unsigned 16bit integer property: "
1545 "PTP_OC_MTP_SetObjectPropValue not supported.");
1546 return -1;
1547 }
1548 propval.u16 = value;
1549 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT16);
1550 if (ret != PTP_RC_OK) {
1551 add_ptp_error_to_errorstack(device, ret, "set_object_u16(): could not set unsigned 16bit integer property.");
1552 return 1;
1553 }
1554
1555 return 0;
1556 }
1557
1558 /**
1559 * Sets an object attribute from an unsigned 8-bit integer
1560 *
1561 * @param device a pointer to an MTP device.
1562 * @param object_id Object reference
1563 * @param attribute_id PTP attribute ID
1564 * @param value 8-bit unsigned integer to set
1565 * @return 0 on success, any other value means failure
1566 */
set_object_u8(LIBMTP_mtpdevice_t * device,uint32_t const object_id,uint16_t const attribute_id,uint8_t const value)1567 static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
1568 uint16_t const attribute_id, uint8_t const value)
1569 {
1570 PTPPropertyValue propval;
1571 PTPParams *params = (PTPParams *) device->params;
1572 uint16_t ret;
1573
1574 if (device == NULL) {
1575 return 1;
1576 }
1577
1578 if (!ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
1579 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_u8(): could not set unsigned 8bit integer property: "
1580 "PTP_OC_MTP_SetObjectPropValue not supported.");
1581 return -1;
1582 }
1583 propval.u8 = value;
1584 ret = ptp_mtp_setobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_UINT8);
1585 if (ret != PTP_RC_OK) {
1586 add_ptp_error_to_errorstack(device, ret, "set_object_u8(): could not set unsigned 8bit integer property.");
1587 return 1;
1588 }
1589
1590 return 0;
1591 }
1592
1593 /**
1594 * Get the first (as in "first in the list of") connected MTP device.
1595 * @return a device pointer.
1596 * @see LIBMTP_Get_Connected_Devices()
1597 */
LIBMTP_Get_First_Device(void)1598 LIBMTP_mtpdevice_t *LIBMTP_Get_First_Device(void)
1599 {
1600 LIBMTP_mtpdevice_t *first_device = NULL;
1601 LIBMTP_raw_device_t *devices;
1602 int numdevs;
1603 LIBMTP_error_number_t ret;
1604
1605 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1606 if (ret != LIBMTP_ERROR_NONE) {
1607 return NULL;
1608 }
1609
1610 if (devices == NULL || numdevs == 0) {
1611 return NULL;
1612 }
1613
1614 first_device = LIBMTP_Open_Raw_Device(&devices[0]);
1615 free(devices);
1616 return first_device;
1617 }
1618
1619 /**
1620 * Overriding debug function.
1621 * This way we can disable debug prints.
1622 */
1623 static void
1624 #ifdef __GNUC__
1625 __attribute__((__format__(printf,2,0)))
1626 #endif
LIBMTP_ptp_debug(void * data,const char * format,va_list args)1627 LIBMTP_ptp_debug(void *data, const char *format, va_list args)
1628 {
1629 #ifdef ENABLE_PTP_DEBUG
1630 vfprintf (stderr, format, args);
1631 fflush (stderr);
1632 #endif
1633 }
1634
1635 /**
1636 * Overriding error function.
1637 * This way we can capture all error etc to our errorstack.
1638 */
1639 static void
1640 #ifdef __GNUC__
1641 __attribute__((__format__(printf,2,0)))
1642 #endif
LIBMTP_ptp_error(void * data,const char * format,va_list args)1643 LIBMTP_ptp_error(void *data, const char *format, va_list args)
1644 {
1645 // if (data == NULL) {
1646 vfprintf (stderr, format, args);
1647 fflush (stderr);
1648 /*
1649 FIXME: find out how we shall get the device here.
1650 } else {
1651 PTP_USB *ptp_usb = data;
1652 LIBMTP_mtpdevice_t *device = ...;
1653 char buf[2048];
1654
1655 vsnprintf (buf, sizeof (buf), format, args);
1656 add_error_to_errorstack(device,
1657 LIBMTP_ERROR_PTP_LAYER,
1658 buf);
1659 }
1660 */
1661 }
1662
1663 /**
1664 * This function opens a device from a raw device. It is the
1665 * preferred way to access devices in the new interface where
1666 * several devices can come and go as the library is working
1667 * on a certain device.
1668 * @param rawdevice the raw device to open a "real" device for.
1669 * @return an open device.
1670 */
LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t * rawdevice)1671 LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
1672 {
1673 LIBMTP_mtpdevice_t *mtp_device;
1674 uint8_t bs = 0;
1675 PTPParams *current_params;
1676 PTP_USB *ptp_usb;
1677 LIBMTP_error_number_t err;
1678 int i;
1679
1680 /* Allocate dynamic space for our device */
1681 mtp_device = (LIBMTP_mtpdevice_t *) malloc(sizeof(LIBMTP_mtpdevice_t));
1682 memset(mtp_device, 0, sizeof(LIBMTP_mtpdevice_t));
1683 /* Check if there was a memory allocation error */
1684 if(mtp_device == NULL) {
1685 /* There has been an memory allocation error. We are going to ignore this
1686 device and attempt to continue */
1687
1688 /* TODO: This error statement could probably be a bit more robust */
1689 fprintf(stderr, "LIBMTP PANIC: connect_usb_devices encountered a memory "
1690 "allocation error with device %d on bus %d, trying to continue",
1691 rawdevice->devnum, rawdevice->bus_location);
1692
1693 return NULL;
1694 }
1695
1696 /* Create PTP params */
1697 current_params = (PTPParams *) malloc(sizeof(PTPParams));
1698 if (current_params == NULL) {
1699 free(mtp_device);
1700 return NULL;
1701 }
1702 memset(current_params, 0, sizeof(PTPParams));
1703 current_params->device_flags = rawdevice->device_entry.device_flags;
1704 current_params->nrofobjects = 0;
1705 current_params->objects = NULL;
1706 current_params->response_packet_size = 0;
1707 current_params->response_packet = NULL;
1708 /* This will be a pointer to PTP_USB later */
1709 current_params->data = NULL;
1710 /* Set upp local debug and error functions */
1711 current_params->debug_func = LIBMTP_ptp_debug;
1712 current_params->error_func = LIBMTP_ptp_error;
1713 /* TODO: Will this always be little endian? */
1714 current_params->byteorder = PTP_DL_LE;
1715 current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1716 current_params->cd_ucs2_to_locale = iconv_open("UTF-8", "UCS-2LE");
1717
1718 if(current_params->cd_locale_to_ucs2 == (iconv_t) -1 ||
1719 current_params->cd_ucs2_to_locale == (iconv_t) -1) {
1720 fprintf(stderr, "LIBMTP PANIC: Cannot open iconv() converters to/from UCS-2!\n"
1721 "Too old stdlibc, glibc and libiconv?\n");
1722 free(current_params);
1723 free(mtp_device);
1724 return NULL;
1725 }
1726 mtp_device->params = current_params;
1727
1728
1729 /* Create usbinfo, this also opens the session */
1730 err = configure_usb_device(rawdevice,
1731 current_params,
1732 &mtp_device->usbinfo);
1733 if (err != LIBMTP_ERROR_NONE) {
1734 free(current_params);
1735 free(mtp_device);
1736 return NULL;
1737 }
1738 ptp_usb = (PTP_USB*) mtp_device->usbinfo;
1739 /* Set pointer back to params */
1740 ptp_usb->params = current_params;
1741
1742
1743 /* Cache the device information for later use */
1744 if (ptp_getdeviceinfo(current_params,
1745 ¤t_params->deviceinfo) != PTP_RC_OK) {
1746 fprintf(stderr, "LIBMTP PANIC: Unable to read device information on device "
1747 "%d on bus %d, trying to continue",
1748 rawdevice->devnum, rawdevice->bus_location);
1749
1750 /* Prevent memory leaks for this device */
1751 free(mtp_device->usbinfo);
1752 free(mtp_device->params);
1753 current_params = NULL;
1754 free(mtp_device);
1755 return NULL;
1756 }
1757
1758 /* Determine if the object size supported is 32 or 64 bit wide */
1759 for (i=0;i<current_params->deviceinfo.ImageFormats_len;i++) {
1760 PTPObjectPropDesc opd;
1761
1762 if (ptp_mtp_getobjectpropdesc(current_params,
1763 PTP_OPC_ObjectSize,
1764 current_params->deviceinfo.ImageFormats[i],
1765 &opd) != PTP_RC_OK) {
1766 printf("LIBMTP PANIC: "
1767 "could not inspect object property descriptions!\n");
1768 } else {
1769 if (opd.DataType == PTP_DTC_UINT32) {
1770 if (bs == 0) {
1771 bs = 32;
1772 } else if (bs != 32) {
1773 printf("LIBMTP PANIC: "
1774 "different objects support different object sizes!\n");
1775 bs = 0;
1776 break;
1777 }
1778 } else if (opd.DataType == PTP_DTC_UINT64) {
1779 if (bs == 0) {
1780 bs = 64;
1781 } else if (bs != 64) {
1782 printf("LIBMTP PANIC: "
1783 "different objects support different object sizes!\n");
1784 bs = 0;
1785 break;
1786 }
1787 } else {
1788 // Ignore if other size.
1789 printf("LIBMTP PANIC: "
1790 "awkward object size data type: %04x\n", opd.DataType);
1791 bs = 0;
1792 break;
1793 }
1794 }
1795 }
1796 if (bs == 0) {
1797 // Could not detect object bitsize, assume 32 bits
1798 bs = 32;
1799 }
1800 mtp_device->object_bitsize = bs;
1801
1802 /* No Errors yet for this device */
1803 mtp_device->errorstack = NULL;
1804
1805 /* Default Max Battery Level, we will adjust this if possible */
1806 mtp_device->maximum_battery_level = 100;
1807
1808 /* Check if device supports reading maximum battery level */
1809 if(!FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) &&
1810 ptp_property_issupported( current_params, PTP_DPC_BatteryLevel)) {
1811 PTPDevicePropDesc dpd;
1812
1813 /* Try to read maximum battery level */
1814 if(ptp_getdevicepropdesc(current_params,
1815 PTP_DPC_BatteryLevel,
1816 &dpd) != PTP_RC_OK) {
1817 add_error_to_errorstack(mtp_device,
1818 LIBMTP_ERROR_CONNECTING,
1819 "Unable to read Maximum Battery Level for this "
1820 "device even though the device supposedly "
1821 "supports this functionality");
1822 }
1823
1824 /* TODO: is this appropriate? */
1825 /* If max battery level is 0 then leave the default, otherwise assign */
1826 if (dpd.FORM.Range.MaximumValue.u8 != 0) {
1827 mtp_device->maximum_battery_level = dpd.FORM.Range.MaximumValue.u8;
1828 }
1829
1830 ptp_free_devicepropdesc(&dpd);
1831 }
1832
1833 /* Set all default folders to 0 (root directory) */
1834 mtp_device->default_music_folder = 0;
1835 mtp_device->default_playlist_folder = 0;
1836 mtp_device->default_picture_folder = 0;
1837 mtp_device->default_video_folder = 0;
1838 mtp_device->default_organizer_folder = 0;
1839 mtp_device->default_zencast_folder = 0;
1840 mtp_device->default_album_folder = 0;
1841 mtp_device->default_text_folder = 0;
1842
1843 /* Set initial storage information */
1844 mtp_device->storage = NULL;
1845 if (LIBMTP_Get_Storage(mtp_device, LIBMTP_STORAGE_SORTBY_NOTSORTED) == -1) {
1846 add_error_to_errorstack(mtp_device,
1847 LIBMTP_ERROR_GENERAL,
1848 "Get Storage information failed.");
1849 mtp_device->storage = NULL;
1850 }
1851
1852 /*
1853 * Then get the handles and try to locate the default folders.
1854 * This has the desired side effect of caching all handles from
1855 * the device which speeds up later operations.
1856 */
1857 flush_handles(mtp_device);
1858
1859 return mtp_device;
1860 }
1861
1862 /**
1863 * Recursive function that adds MTP devices to a linked list
1864 * @param devices a list of raw devices to have real devices created for.
1865 * @return a device pointer to a newly created mtpdevice (used in linked
1866 * list creation).
1867 */
create_usb_mtp_devices(LIBMTP_raw_device_t * devices,int numdevs)1868 static LIBMTP_mtpdevice_t * create_usb_mtp_devices(LIBMTP_raw_device_t *devices, int numdevs)
1869 {
1870 uint8_t i;
1871 LIBMTP_mtpdevice_t *mtp_device_list = NULL;
1872 LIBMTP_mtpdevice_t *current_device = NULL;
1873
1874 for (i=0; i < numdevs; i++) {
1875 LIBMTP_mtpdevice_t *mtp_device;
1876 mtp_device = LIBMTP_Open_Raw_Device(&devices[i]);
1877
1878 /* On error, try next device */
1879 if (mtp_device == NULL)
1880 continue;
1881
1882 /* Add the device to the list */
1883 mtp_device->next = NULL;
1884 if (mtp_device_list == NULL) {
1885 mtp_device_list = current_device = mtp_device;
1886 } else {
1887 current_device->next = mtp_device;
1888 current_device = mtp_device;
1889 }
1890 }
1891 return mtp_device_list;
1892 }
1893
1894 /**
1895 * Get the number of devices that are available in the listed device list
1896 * @param device_list Pointer to a linked list of devices
1897 * @return Number of devices in the device list device_list
1898 * @see LIBMTP_Get_Connected_Devices()
1899 */
LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t * device_list)1900 uint32_t LIBMTP_Number_Devices_In_List(LIBMTP_mtpdevice_t *device_list)
1901 {
1902 uint32_t numdevices = 0;
1903 LIBMTP_mtpdevice_t *iter;
1904 for(iter = device_list; iter != NULL; iter = iter->next)
1905 numdevices++;
1906
1907 return numdevices;
1908 }
1909
1910 /**
1911 * Get the first connected MTP device node in the linked list of devices.
1912 * Currently this only provides access to USB devices
1913 * @param device_list A list of devices ready to be used by the caller. You
1914 * need to know how many there are.
1915 * @return Any error information gathered from device connections
1916 * @see LIBMTP_Number_Devices_In_List()
1917 */
LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t ** device_list)1918 LIBMTP_error_number_t LIBMTP_Get_Connected_Devices(LIBMTP_mtpdevice_t **device_list)
1919 {
1920 LIBMTP_raw_device_t *devices;
1921 int numdevs;
1922 LIBMTP_error_number_t ret;
1923
1924 ret = LIBMTP_Detect_Raw_Devices(&devices, &numdevs);
1925 if (ret != LIBMTP_ERROR_NONE) {
1926 *device_list = NULL;
1927 return ret;
1928 }
1929
1930 /* Assign linked list of devices */
1931 if (devices == NULL || numdevs == 0) {
1932 *device_list = NULL;
1933 return LIBMTP_ERROR_NO_DEVICE_ATTACHED;
1934 }
1935
1936 *device_list = create_usb_mtp_devices(devices, numdevs);
1937 free(devices);
1938
1939 /* TODO: Add wifi device access here */
1940
1941 /* We have found some devices but create failed */
1942 if (*device_list == NULL)
1943 return LIBMTP_ERROR_CONNECTING;
1944
1945 return LIBMTP_ERROR_NONE;
1946 }
1947
1948 /**
1949 * This closes and releases an allocated MTP device.
1950 * @param device a pointer to the MTP device to release.
1951 */
LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t * device)1952 void LIBMTP_Release_Device_List(LIBMTP_mtpdevice_t *device)
1953 {
1954 if(device != NULL)
1955 {
1956 if(device->next != NULL)
1957 {
1958 LIBMTP_Release_Device_List(device->next);
1959 }
1960
1961 LIBMTP_Release_Device(device);
1962 }
1963 }
1964
1965 /**
1966 * This closes and releases an allocated MTP device.
1967 * @param device a pointer to the MTP device to release.
1968 */
LIBMTP_Release_Device(LIBMTP_mtpdevice_t * device)1969 void LIBMTP_Release_Device(LIBMTP_mtpdevice_t *device)
1970 {
1971 PTPParams *params = (PTPParams *) device->params;
1972 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
1973
1974 close_device(ptp_usb, params);
1975 // Clear error stack
1976 LIBMTP_Clear_Errorstack(device);
1977 // Free iconv() converters...
1978 iconv_close(params->cd_locale_to_ucs2);
1979 iconv_close(params->cd_ucs2_to_locale);
1980 free(ptp_usb);
1981 ptp_free_params(params);
1982 free_storage_list(device);
1983 free(device);
1984 }
1985
1986 /**
1987 * This can be used by any libmtp-intrinsic code that
1988 * need to stack up an error on the stack. You are only
1989 * supposed to add errors to the error stack using this
1990 * function, do not create and reference error entries
1991 * directly.
1992 */
add_error_to_errorstack(LIBMTP_mtpdevice_t * device,LIBMTP_error_number_t errornumber,char const * const error_text)1993 static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
1994 LIBMTP_error_number_t errornumber,
1995 char const * const error_text)
1996 {
1997 LIBMTP_error_t *newerror;
1998
1999 if (device == NULL) {
2000 fprintf(stderr, "LIBMTP PANIC: Trying to add error to a NULL device!\n");
2001 return;
2002 }
2003 newerror = (LIBMTP_error_t *) malloc(sizeof(LIBMTP_error_t));
2004 newerror->errornumber = errornumber;
2005 newerror->error_text = strdup(error_text);
2006 newerror->next = NULL;
2007 if (device->errorstack == NULL) {
2008 device->errorstack = newerror;
2009 } else {
2010 LIBMTP_error_t *tmp = device->errorstack;
2011
2012 while (tmp->next != NULL) {
2013 tmp = tmp->next;
2014 }
2015 tmp->next = newerror;
2016 }
2017 }
2018
2019 /**
2020 * Adds an error from the PTP layer to the error stack.
2021 */
add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t * device,uint16_t ptp_error,char const * const error_text)2022 static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
2023 uint16_t ptp_error,
2024 char const * const error_text)
2025 {
2026 if (device == NULL) {
2027 fprintf(stderr, "LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
2028 return;
2029 } else {
2030 char outstr[256];
2031 snprintf(outstr, sizeof(outstr), "PTP Layer error %04x: %s", ptp_error, error_text);
2032 outstr[sizeof(outstr)-1] = '\0';
2033 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
2034 add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, "(Look this up in ptp.h for an explanation.)");
2035 }
2036 }
2037
2038 /**
2039 * This returns the error stack for a device in case you
2040 * need to either reference the error numbers (e.g. when
2041 * creating multilingual apps with multiple-language text
2042 * representations for each error number) or when you need
2043 * to build a multi-line error text widget or something like
2044 * that. You need to call the <code>LIBMTP_Clear_Errorstack</code>
2045 * to clear it when you're finished with it.
2046 * @param device a pointer to the MTP device to get the error
2047 * stack for.
2048 * @return the error stack or NULL if there are no errors
2049 * on the stack.
2050 * @see LIBMTP_Clear_Errorstack()
2051 * @see LIBMTP_Dump_Errorstack()
2052 */
LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t * device)2053 LIBMTP_error_t *LIBMTP_Get_Errorstack(LIBMTP_mtpdevice_t *device)
2054 {
2055 if (device == NULL) {
2056 fprintf(stderr, "LIBMTP PANIC: Trying to get the error stack of a NULL device!\n");
2057 return NULL;
2058 }
2059 return device->errorstack;
2060 }
2061
2062 /**
2063 * This function clears the error stack of a device and frees
2064 * any memory used by it. Call this when you're finished with
2065 * using the errors.
2066 * @param device a pointer to the MTP device to clear the error
2067 * stack for.
2068 */
LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t * device)2069 void LIBMTP_Clear_Errorstack(LIBMTP_mtpdevice_t *device)
2070 {
2071 if (device == NULL) {
2072 fprintf(stderr, "LIBMTP PANIC: Trying to clear the error stack of a NULL device!\n");
2073 } else {
2074 LIBMTP_error_t *tmp = device->errorstack;
2075
2076 while (tmp != NULL) {
2077 LIBMTP_error_t *tmp2;
2078
2079 if (tmp->error_text != NULL) {
2080 free(tmp->error_text);
2081 }
2082 tmp2 = tmp;
2083 tmp = tmp->next;
2084 free(tmp2);
2085 }
2086 device->errorstack = NULL;
2087 }
2088 }
2089
2090 /**
2091 * This function dumps the error stack to <code>stderr</code>.
2092 * (You still have to clear the stack though.)
2093 * @param device a pointer to the MTP device to dump the error
2094 * stack for.
2095 */
LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t * device)2096 void LIBMTP_Dump_Errorstack(LIBMTP_mtpdevice_t *device)
2097 {
2098 if (device == NULL) {
2099 fprintf(stderr, "LIBMTP PANIC: Trying to dump the error stack of a NULL device!\n");
2100 } else {
2101 LIBMTP_error_t *tmp = device->errorstack;
2102
2103 while (tmp != NULL) {
2104 if (tmp->error_text != NULL) {
2105 fprintf(stderr, "Error %d: %s\n", tmp->errornumber, tmp->error_text);
2106 } else {
2107 fprintf(stderr, "Error %d: (unknown)\n", tmp->errornumber);
2108 }
2109 tmp = tmp->next;
2110 }
2111 }
2112 }
2113
LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t * device,int milliseconds)2114 void LIBMTP_Set_Device_Timeout(LIBMTP_mtpdevice_t *device, int milliseconds)
2115 {
2116 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2117 set_usb_device_timeout(ptp_usb, milliseconds);
2118 }
2119
LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t * device,int * milliseconds)2120 void LIBMTP_Get_Device_Timeout(LIBMTP_mtpdevice_t *device, int * milliseconds)
2121 {
2122 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2123 get_usb_device_timeout(ptp_usb, milliseconds);
2124 }
2125
2126 /**
2127 * This command gets all handles and stuff by FAST directory retrieveal
2128 * which is available by getting all metadata for object
2129 * <code>0xffffffff</code> which simply means "all metadata for all objects".
2130 * This works on the vast majority of MTP devices (there ARE exceptions!)
2131 * and is quite quick. Check the error stack to see if there were
2132 * problems getting the metadata.
2133 * @return 0 if all was OK, -1 on failure.
2134 */
get_all_metadata_fast(LIBMTP_mtpdevice_t * device,uint32_t storage)2135 static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device,
2136 uint32_t storage)
2137 {
2138 PTPParams *params = (PTPParams *) device->params;
2139 int cnt = 0;
2140 int i, j, nrofprops;
2141 uint32_t lasthandle = 0xffffffff;
2142 MTPProperties *props = NULL;
2143 MTPProperties *prop;
2144 uint16_t ret;
2145 int oldtimeout;
2146 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2147
2148 /* The follow request causes the device to generate
2149 * a list of very file on the device and return it
2150 * in a single response.
2151 *
2152 * Some slow devices as well as devices with very
2153 * large file systems can easily take longer then
2154 * the standard timeout value before it is able
2155 * to return a response.
2156 *
2157 * Temporarly set timeout to allow working with
2158 * widest range of devices.
2159 */
2160 get_usb_device_timeout(ptp_usb, &oldtimeout);
2161 set_usb_device_timeout(ptp_usb, 60000);
2162
2163 ret = ptp_mtp_getobjectproplist(params, 0xffffffff, &props, &nrofprops);
2164 set_usb_device_timeout(ptp_usb, oldtimeout);
2165
2166 if (ret == PTP_RC_MTP_Specification_By_Group_Unsupported) {
2167 // What's the point in the device implementing this command if
2168 // you cannot use it to get all props for AT LEAST one object?
2169 // Well, whatever...
2170 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2171 "cannot retrieve all metadata for an object on this device.");
2172 return -1;
2173 }
2174 if (ret != PTP_RC_OK) {
2175 add_ptp_error_to_errorstack(device, ret, "get_all_metadata_fast(): "
2176 "could not get proplist of all objects.");
2177 return -1;
2178 }
2179 if (props == NULL && nrofprops != 0) {
2180 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
2181 "get_all_metadata_fast(): "
2182 "call to ptp_mtp_getobjectproplist() returned "
2183 "inconsistent results.");
2184 return -1;
2185 }
2186 /*
2187 * We count the number of objects by counting the ObjectHandle
2188 * references, whenever it changes we get a new object, when it's
2189 * the same, it is just different properties of the same object.
2190 */
2191 prop = props;
2192 for (i=0;i<nrofprops;i++) {
2193 if (lasthandle != prop->ObjectHandle) {
2194 cnt++;
2195 lasthandle = prop->ObjectHandle;
2196 }
2197 prop++;
2198 }
2199 lasthandle = 0xffffffff;
2200 params->objects = calloc (sizeof(PTPObject),cnt);
2201 prop = props;
2202 i = -1;
2203 for (j=0;j<nrofprops;j++) {
2204 if (lasthandle != prop->ObjectHandle) {
2205 if (i >= 0) {
2206 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2207 if (!params->objects[i].oi.Filename) {
2208 /* I have one such file on my Creative (Marcus) */
2209 params->objects[i].oi.Filename = strdup("<null>");
2210 }
2211 }
2212 i++;
2213 lasthandle = prop->ObjectHandle;
2214 params->objects[i].oid = prop->ObjectHandle;
2215 }
2216 switch (prop->property) {
2217 case PTP_OPC_ParentObject:
2218 params->objects[i].oi.ParentObject = prop->propval.u32;
2219 params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
2220 break;
2221 case PTP_OPC_ObjectFormat:
2222 params->objects[i].oi.ObjectFormat = prop->propval.u16;
2223 break;
2224 case PTP_OPC_ObjectSize:
2225 // We loose precision here, up to 32 bits! However the commands that
2226 // retrieve metadata for files and tracks will make sure that the
2227 // PTP_OPC_ObjectSize is read in and duplicated again.
2228 if (device->object_bitsize == 64) {
2229 params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
2230 } else {
2231 params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
2232 }
2233 break;
2234 case PTP_OPC_StorageID:
2235 params->objects[i].oi.StorageID = prop->propval.u32;
2236 params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
2237 break;
2238 case PTP_OPC_ObjectFileName:
2239 if (prop->propval.str != NULL)
2240 params->objects[i].oi.Filename = strdup(prop->propval.str);
2241 break;
2242 default: {
2243 MTPProperties *newprops;
2244
2245 /* Copy all of the other MTP oprierties into the per-object proplist */
2246 if (params->objects[i].nrofmtpprops) {
2247 newprops = realloc(params->objects[i].mtpprops,(params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
2248 } else {
2249 newprops = calloc(sizeof(MTPProperties),1);
2250 }
2251 if (!newprops) return 0; /* FIXME: error handling? */
2252 params->objects[i].mtpprops = newprops;
2253 memcpy(¶ms->objects[i].mtpprops[params->objects[i].nrofmtpprops],&props[j],sizeof(props[j]));
2254 params->objects[i].nrofmtpprops++;
2255 params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
2256 break;
2257 }
2258 }
2259 prop++;
2260 }
2261 /* mark last entry also */
2262 params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
2263 params->nrofobjects = i+1;
2264 /* The device might not give the list in linear ascending order */
2265 ptp_objects_sort (params);
2266 return 0;
2267 }
2268
2269 /**
2270 * This function will recurse through all the directories on the device,
2271 * starting at the root directory, gathering metadata as it moves along.
2272 * It works better on some devices that will only return data for a
2273 * certain directory and does not respect the option to get all metadata
2274 * for all objects.
2275 */
get_handles_recursively(LIBMTP_mtpdevice_t * device,PTPParams * params,uint32_t storageid,uint32_t parent)2276 static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
2277 PTPParams *params,
2278 uint32_t storageid,
2279 uint32_t parent)
2280 {
2281 PTPObjectHandles currentHandles;
2282 int i = 0;
2283 uint16_t ret = ptp_getobjecthandles(params,
2284 storageid,
2285 PTP_GOH_ALL_FORMATS,
2286 parent,
2287 ¤tHandles);
2288
2289 if (ret != PTP_RC_OK) {
2290 add_ptp_error_to_errorstack(device, ret, "get_handles_recursively(): could not get object handles.");
2291 return;
2292 }
2293
2294 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2295 return;
2296
2297 // Now descend into any subdirectories found
2298 for (i = 0; i < currentHandles.n; i++) {
2299 PTPObject *ob;
2300 ret = ptp_object_want(params,currentHandles.Handler[i],PTPOBJECT_OBJECTINFO_LOADED, &ob);
2301 if (ret == PTP_RC_OK) {
2302 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2303 get_handles_recursively(device, params, storageid, currentHandles.Handler[i]);
2304 } else {
2305 add_error_to_errorstack(device,
2306 LIBMTP_ERROR_CONNECTING,
2307 "Found a bad handle, trying to ignore it.");
2308 }
2309 }
2310 free(currentHandles.Handler);
2311 }
2312
2313
obj2file(LIBMTP_mtpdevice_t * device,PTPObject * ob)2314 LIBMTP_file_t * obj2file(LIBMTP_mtpdevice_t *device, PTPObject *ob)
2315 {
2316 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2317 PTPParams *params = (PTPParams *) device->params;
2318 LIBMTP_file_t *file;
2319 PTPObject *xob;
2320 uint16_t ret;
2321
2322
2323 if (ob->oi.Filename == NULL)
2324 ob->oi.Filename = strdup("<null>");
2325
2326 if (ob->oi.Keywords == NULL)
2327 ob->oi.Keywords = strdup("<null>");
2328
2329 // Allocate a new file type
2330 file = LIBMTP_new_file_t();
2331
2332 file->parent_id = ob->oi.ParentObject;
2333 file->storage_id = ob->oi.StorageID;
2334
2335 // This is some sort of unique ID so we can keep track of the track.
2336 file->item_id = ob->oid;
2337
2338 // Set the filetype
2339 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
2340
2341 // Set the modification date
2342 file->modificationdate = ob->oi.ModificationDate;
2343
2344 // Original file-specific properties
2345 // We only have 32-bit file size here; if we find it, we use the
2346 // PTP_OPC_ObjectSize property which has 64bit precision.
2347 file->filesize = ob->oi.ObjectCompressedSize;
2348 if (ob->oi.Filename != NULL) {
2349 file->filename = strdup(ob->oi.Filename);
2350 }
2351
2352 /*
2353 * A special quirk for devices that doesn't quite
2354 * remember that some files marked as "unknown" type are
2355 * actually OGG or FLAC files. We look at the filename extension
2356 * and see if it happens that this was atleast named "ogg" or "flac"
2357 * and fall back on this heuristic approach in that case,
2358 * for these bugged devices only.
2359 */
2360 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
2361 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
2362 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
2363 has_ogg_extension(file->filename))
2364
2365 file->filetype = LIBMTP_FILETYPE_OGG;
2366
2367 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && has_flac_extension(file->filename))
2368 file->filetype = LIBMTP_FILETYPE_FLAC;
2369 }
2370
2371 /*
2372 * If we have a cached, large set of metadata, then use it!
2373 */
2374 ret = ptp_object_want (params, ob->oid, PTPOBJECT_MTPPROPLIST_LOADED, &xob);
2375 if (ob->mtpprops) {
2376 MTPProperties *prop = ob->mtpprops;
2377 int i;
2378
2379 for (i=0;i<ob->nrofmtpprops;i++) {
2380 // Pick ObjectSize here...
2381 if (prop->property == PTP_OPC_ObjectSize) {
2382 if (device->object_bitsize == 64) {
2383 file->filesize = prop->propval.u64;
2384 } else {
2385 file->filesize = prop->propval.u32;
2386 }
2387 break;
2388 }
2389 prop++;
2390 }
2391 } else {
2392 uint16_t *props = NULL;
2393 uint32_t propcnt = 0;
2394
2395 // First see which properties can be retrieved for this object format
2396 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
2397 if (ret != PTP_RC_OK) {
2398 add_ptp_error_to_errorstack(device, ret, "obj2file(): call to ptp_mtp_getobjectpropssupported() failed.");
2399 // Silently fall through.
2400 } else {
2401 int i;
2402 for (i=0;i<propcnt;i++) {
2403
2404 /*
2405 TODO: (yavor) See what is a sensible thing to do for Folders
2406 if (ob->oi.ObjectFormat == PTP_OFC_Association)
2407 */
2408 switch (props[i]) {
2409 case PTP_OPC_ObjectSize:
2410 if (device->object_bitsize == 64) {
2411 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
2412 } else {
2413 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
2414 }
2415 break;
2416 default:
2417 break;
2418 }
2419 }
2420 free(props);
2421 }
2422 }
2423
2424 return file;
2425 }
2426
2427
2428
get_files(LIBMTP_mtpdevice_t * device,PTPParams * params,uint32_t storageid,uint32_t parentId)2429 static LIBMTP_file_t * get_files(LIBMTP_mtpdevice_t *device,
2430 PTPParams *params,
2431 uint32_t storageid,
2432 uint32_t parentId
2433 )
2434 {
2435 int i = 0;
2436 LIBMTP_file_t *curfile = NULL;
2437 LIBMTP_file_t *retfiles = NULL;
2438 PTPObjectHandles currentHandles;
2439
2440 uint16_t ret = ptp_getobjecthandles(params,
2441 storageid,
2442 PTP_GOH_ALL_FORMATS,
2443 parentId,
2444 ¤tHandles);
2445
2446 if (ret != PTP_RC_OK) {
2447 add_ptp_error_to_errorstack(device, ret, "get_files(): could not get object handles.");
2448 return NULL;
2449 }
2450
2451 if (currentHandles.Handler == NULL || currentHandles.n == 0)
2452 return NULL;
2453
2454 for (i = 0; i < currentHandles.n; i++) {
2455 PTPObject *ob;
2456 LIBMTP_file_t *file;
2457
2458 ret = ptp_object_want(params, currentHandles.Handler[i],PTPOBJECT_OBJECTINFO_LOADED, &ob);
2459 if (ret != PTP_RC_OK)
2460 return NULL;
2461
2462 file = obj2file(device, ob);
2463
2464 if (file == NULL)
2465 continue;
2466
2467 // Add track to a list that will be returned afterwards.
2468 if (curfile == NULL) {
2469 curfile = file;
2470 retfiles = file;
2471 } else {
2472 curfile->next = file;
2473 curfile = file;
2474 }
2475 }
2476
2477 free(currentHandles.Handler);
2478
2479 // Return a pointer to the original first file
2480 // in the big list.
2481 return retfiles;
2482 }
2483
2484 /**
2485 * This function controls the usage of the internal object cache.
2486 * The default configuration loads all object handles on initialization.
2487 * In order to handle large number of files turn on the on demand
2488 * loading by calling this function with parameter 1, and use
2489 * LIBMTP_Get_Files_And_Folders() to load content when needed.
2490 *
2491 * @param flag - 0 means turn off on demand loading.
2492 * - 1 means turn on on demand loading.
2493 */
LIBMTP_Set_Load_Cache_On_Demand(int flag)2494 void LIBMTP_Set_Load_Cache_On_Demand(int flag)
2495 {
2496 load_cache_on_demand = flag;
2497 }
2498
2499 /**
2500 * This function retrieves the content of a folder with id - parentId.
2501 * The result contains both files and folders.
2502 * NOTE: the request will always perform I/O with the device.
2503 * @param device a pointer to the MTP device to report info from.
2504 * @storageId the id for the storage.
2505 * @param parentId the parent folder id.
2506 */
LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t * device,uint32_t storageId,uint32_t parentId)2507 LIBMTP_file_t * LIBMTP_Get_Files_And_Folders(LIBMTP_mtpdevice_t *device, uint32_t storageId, uint32_t parentId)
2508 {
2509 LIBMTP_file_t *retfiles = NULL;
2510 PTPParams *params = (PTPParams *) device->params;
2511 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2512 int ret;
2513 uint32_t i;
2514
2515 #if 0
2516 //TODO: (yavor) Try to use get_all_metadata_fast for a parendId.
2517 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2518 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2519 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2520 // Use the fast method. Ignore return value for now.
2521 ret = get_all_metadata_fast(device, PTP_GOH_ALL_STORAGE);
2522 }
2523 #endif
2524
2525
2526 retfiles = get_files(device, params, storageId, parentId);
2527
2528 return retfiles;
2529 }
2530
2531 /**
2532 * This function refresh the internal handle list whenever
2533 * the items stored inside the device is altered. On operations
2534 * that do not add or remove objects, this is typically not
2535 * called.
2536 * @param device a pointer to the MTP device to flush handles for.
2537 */
flush_handles(LIBMTP_mtpdevice_t * device)2538 static void flush_handles(LIBMTP_mtpdevice_t *device)
2539 {
2540 PTPParams *params = (PTPParams *) device->params;
2541 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2542 int ret;
2543 uint32_t i;
2544
2545 if (load_cache_on_demand) {
2546 return;
2547 }
2548
2549 if (params->objects != NULL) {
2550 for (i=0;i<params->nrofobjects;i++)
2551 ptp_free_object (¶ms->objects[i]);
2552 free(params->objects);
2553 params->objects = NULL;
2554 params->nrofobjects = 0;
2555 }
2556
2557 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
2558 && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
2559 && !FLAG_BROKEN_MTPGETOBJPROPLIST_ALL(ptp_usb)) {
2560 // Use the fast method. Ignore return value for now.
2561 ret = get_all_metadata_fast(device, PTP_GOH_ALL_STORAGE);
2562 }
2563
2564 // If the previous failed or returned no objects, use classic
2565 // methods instead.
2566 if (params->nrofobjects == 0) {
2567 // Get all the handles using just standard commands.
2568 if (device->storage == NULL) {
2569 get_handles_recursively(device, params,
2570 PTP_GOH_ALL_STORAGE,
2571 PTP_GOH_ROOT_PARENT);
2572 } else {
2573 // Get handles for each storage in turn.
2574 LIBMTP_devicestorage_t *storage = device->storage;
2575 while(storage != NULL) {
2576 get_handles_recursively(device, params,
2577 storage->id,
2578 PTP_GOH_ROOT_PARENT);
2579 storage = storage->next;
2580 }
2581 }
2582 }
2583
2584 /*
2585 * Loop over the handles, fix up any NULL filenames or
2586 * keywords, then attempt to locate some default folders
2587 * in the root directory of the primary storage.
2588 */
2589 for(i = 0; i < params->nrofobjects; i++) {
2590 PTPObject *ob, *xob;
2591
2592 ob = ¶ms->objects[i];
2593 ret = ptp_object_want(params,params->objects[i].oid,PTPOBJECT_OBJECTINFO_LOADED, &xob);
2594 if (ret != PTP_RC_OK) {
2595 fprintf(stderr,"broken! %x not found\n", params->objects[i].oid);
2596 }
2597 if (ob->oi.Filename == NULL)
2598 ob->oi.Filename = strdup("<null>");
2599 if (ob->oi.Keywords == NULL)
2600 ob->oi.Keywords = strdup("<null>");
2601
2602 /* Ignore handles that point to non-folders */
2603 if(ob->oi.ObjectFormat != PTP_OFC_Association)
2604 continue;
2605 /* Only look in the root folder */
2606 if (ob->oi.ParentObject != 0x00000000U)
2607 continue;
2608 /* Only look in the primary storage */
2609 if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
2610 continue;
2611
2612
2613 /* Is this the Music Folder */
2614 if (!strcasecmp(ob->oi.Filename, "My Music") ||
2615 !strcasecmp(ob->oi.Filename, "Music")) {
2616 device->default_music_folder = ob->oid;
2617 }
2618 else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
2619 !strcasecmp(ob->oi.Filename, "Playlists")) {
2620 device->default_playlist_folder = ob->oid;
2621 }
2622 else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
2623 !strcasecmp(ob->oi.Filename, "Pictures")) {
2624 device->default_picture_folder = ob->oid;
2625 }
2626 else if (!strcasecmp(ob->oi.Filename, "My Video") ||
2627 !strcasecmp(ob->oi.Filename, "Video")) {
2628 device->default_video_folder = ob->oid;
2629 }
2630 else if (!strcasecmp(ob->oi.Filename, "My Organizer")) {
2631 device->default_organizer_folder = ob->oid;
2632 }
2633 else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
2634 !strcasecmp(ob->oi.Filename, "Datacasts")) {
2635 device->default_zencast_folder = ob->oid;
2636 }
2637 else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
2638 !strcasecmp(ob->oi.Filename, "Albums")) {
2639 device->default_album_folder = ob->oid;
2640 }
2641 else if (!strcasecmp(ob->oi.Filename, "Text") ||
2642 !strcasecmp(ob->oi.Filename, "Texts")) {
2643 device->default_text_folder = ob->oid;
2644 }
2645 }
2646 }
2647
2648 /**
2649 * This function traverses a devices storage list freeing up the
2650 * strings and the structs.
2651 * @param device a pointer to the MTP device to free the storage
2652 * list for.
2653 */
free_storage_list(LIBMTP_mtpdevice_t * device)2654 static void free_storage_list(LIBMTP_mtpdevice_t *device)
2655 {
2656 LIBMTP_devicestorage_t *storage;
2657 LIBMTP_devicestorage_t *tmp;
2658
2659 storage = device->storage;
2660 while(storage != NULL) {
2661 if (storage->StorageDescription != NULL) {
2662 free(storage->StorageDescription);
2663 }
2664 if (storage->VolumeIdentifier != NULL) {
2665 free(storage->VolumeIdentifier);
2666 }
2667 tmp = storage;
2668 storage = storage->next;
2669 free(tmp);
2670 }
2671 device->storage = NULL;
2672
2673 return;
2674 }
2675
2676 /**
2677 * This function traverses a devices storage list freeing up the
2678 * strings and the structs.
2679 * @param device a pointer to the MTP device to free the storage
2680 * list for.
2681 */
sort_storage_by(LIBMTP_mtpdevice_t * device,int const sortby)2682 static int sort_storage_by(LIBMTP_mtpdevice_t *device,int const sortby)
2683 {
2684 LIBMTP_devicestorage_t *oldhead, *ptr1, *ptr2, *newlist;
2685
2686 if (device->storage == NULL)
2687 return -1;
2688 if (sortby == LIBMTP_STORAGE_SORTBY_NOTSORTED)
2689 return 0;
2690
2691 oldhead = ptr1 = ptr2 = device->storage;
2692
2693 newlist = NULL;
2694
2695 while(oldhead != NULL) {
2696 ptr1 = ptr2 = oldhead;
2697 while(ptr1 != NULL) {
2698
2699 if (sortby == LIBMTP_STORAGE_SORTBY_FREESPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2700 ptr2 = ptr1;
2701 if (sortby == LIBMTP_STORAGE_SORTBY_MAXSPACE && ptr1->FreeSpaceInBytes > ptr2->FreeSpaceInBytes)
2702 ptr2 = ptr1;
2703
2704 ptr1 = ptr1->next;
2705 }
2706
2707 // Make our previous entries next point to our next
2708 if(ptr2->prev != NULL) {
2709 ptr1 = ptr2->prev;
2710 ptr1->next = ptr2->next;
2711 } else {
2712 oldhead = ptr2->next;
2713 if(oldhead != NULL)
2714 oldhead->prev = NULL;
2715 }
2716
2717 // Make our next entries previous point to our previous
2718 ptr1 = ptr2->next;
2719 if(ptr1 != NULL) {
2720 ptr1->prev = ptr2->prev;
2721 } else {
2722 ptr1 = ptr2->prev;
2723 if(ptr1 != NULL)
2724 ptr1->next = NULL;
2725 }
2726
2727 if(newlist == NULL) {
2728 newlist = ptr2;
2729 newlist->prev = NULL;
2730 } else {
2731 ptr2->prev = newlist;
2732 newlist->next = ptr2;
2733 newlist = newlist->next;
2734 }
2735 }
2736
2737 if (newlist != NULL) {
2738 newlist->next = NULL;
2739 while(newlist->prev != NULL)
2740 newlist = newlist->prev;
2741 device->storage = newlist;
2742 }
2743
2744 return 0;
2745 }
2746
2747 /**
2748 * This function grabs the first writeable storageid from the
2749 * device storage list.
2750 * @param device a pointer to the MTP device to locate writeable
2751 * storage for.
2752 * @param fitsize a file of this file must fit on the device.
2753 */
get_writeable_storageid(LIBMTP_mtpdevice_t * device,uint64_t fitsize)2754 static uint32_t get_writeable_storageid(LIBMTP_mtpdevice_t *device, uint64_t fitsize)
2755 {
2756 LIBMTP_devicestorage_t *storage;
2757 uint32_t store = 0x00000000; //Should this be 0xffffffffu instead?
2758 int subcall_ret;
2759
2760 // See if there is some storage we can fit this file on.
2761 storage = device->storage;
2762 if (storage == NULL) {
2763 // Sometimes the storage just cannot be detected.
2764 store = 0x00000000U;
2765 } else {
2766 while(storage != NULL) {
2767 // These storages cannot be used.
2768 if (storage->StorageType == PTP_ST_FixedROM || storage->StorageType == PTP_ST_RemovableROM) {
2769 storage = storage->next;
2770 continue;
2771 }
2772 // Storage IDs with the lower 16 bits 0x0000 are not supposed
2773 // to be writeable.
2774 if ((storage->id & 0x0000FFFFU) == 0x00000000U) {
2775 storage = storage->next;
2776 continue;
2777 }
2778 // Also check the access capability to avoid e.g. deletable only storages
2779 if (storage->AccessCapability == PTP_AC_ReadOnly || storage->AccessCapability == PTP_AC_ReadOnly_with_Object_Deletion) {
2780 storage = storage->next;
2781 continue;
2782 }
2783 // Then see if we can fit the file.
2784 subcall_ret = check_if_file_fits(device, storage, fitsize);
2785 if (subcall_ret != 0) {
2786 storage = storage->next;
2787 } else {
2788 // We found a storage that is writable and can fit the file!
2789 break;
2790 }
2791 }
2792 if (storage == NULL) {
2793 add_error_to_errorstack(device, LIBMTP_ERROR_STORAGE_FULL, "LIBMTP_Send_File_From_File_Descriptor(): "
2794 "all device storage is full or corrupt.");
2795 return -1;
2796 }
2797 store = storage->id;
2798 }
2799
2800 return store;
2801 }
2802
2803 /**
2804 * This function grabs the freespace from a certain storage in
2805 * device storage list.
2806 * @param device a pointer to the MTP device to free the storage
2807 * list for.
2808 * @param storageid the storage ID for the storage to flush and
2809 * get free space for.
2810 * @param freespace the free space on this storage will be returned
2811 * in this variable.
2812 */
get_storage_freespace(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t * freespace)2813 static int get_storage_freespace(LIBMTP_mtpdevice_t *device,
2814 LIBMTP_devicestorage_t *storage,
2815 uint64_t *freespace)
2816 {
2817 PTPParams *params = (PTPParams *) device->params;
2818
2819 // Always query the device about this, since some models explicitly
2820 // needs that. We flush all data on queries storage here.
2821 if (ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
2822 PTPStorageInfo storageInfo;
2823 uint16_t ret;
2824
2825 ret = ptp_getstorageinfo(params, storage->id, &storageInfo);
2826 if (ret != PTP_RC_OK) {
2827 add_ptp_error_to_errorstack(device, ret, "get_first_storage_freespace(): could not get storage info.");
2828 return -1;
2829 }
2830 if (storage->StorageDescription != NULL) {
2831 free(storage->StorageDescription);
2832 }
2833 if (storage->VolumeIdentifier != NULL) {
2834 free(storage->VolumeIdentifier);
2835 }
2836 storage->StorageType = storageInfo.StorageType;
2837 storage->FilesystemType = storageInfo.FilesystemType;
2838 storage->AccessCapability = storageInfo.AccessCapability;
2839 storage->MaxCapacity = storageInfo.MaxCapability;
2840 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
2841 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
2842 storage->StorageDescription = storageInfo.StorageDescription;
2843 storage->VolumeIdentifier = storageInfo.VolumeLabel;
2844 }
2845 if(storage->FreeSpaceInBytes == (uint64_t) -1)
2846 return -1;
2847 *freespace = storage->FreeSpaceInBytes;
2848 return 0;
2849 }
2850
2851 /**
2852 * This function dumps out a large chunk of textual information
2853 * provided from the PTP protocol and additionally some extra
2854 * MTP-specific information where applicable.
2855 * @param device a pointer to the MTP device to report info from.
2856 */
LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t * device)2857 void LIBMTP_Dump_Device_Info(LIBMTP_mtpdevice_t *device)
2858 {
2859 int i;
2860 PTPParams *params = (PTPParams *) device->params;
2861 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
2862 LIBMTP_devicestorage_t *storage = device->storage;
2863
2864 printf("USB low-level info:\n");
2865 dump_usbinfo(ptp_usb);
2866 /* Print out some verbose information */
2867 printf("Device info:\n");
2868 printf(" Manufacturer: %s\n", params->deviceinfo.Manufacturer);
2869 printf(" Model: %s\n", params->deviceinfo.Model);
2870 printf(" Device version: %s\n", params->deviceinfo.DeviceVersion);
2871 printf(" Serial number: %s\n", params->deviceinfo.SerialNumber);
2872 printf(" Vendor extension ID: 0x%08x\n", params->deviceinfo.VendorExtensionID);
2873 printf(" Vendor extension description: %s\n", params->deviceinfo.VendorExtensionDesc);
2874 printf(" Detected object size: %d bits\n", device->object_bitsize);
2875 printf("Supported operations:\n");
2876 for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
2877 char txt[256];
2878
2879 (void) ptp_render_opcode (params, params->deviceinfo.OperationsSupported[i], sizeof(txt), txt);
2880 printf(" %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
2881 }
2882 printf("Events supported:\n");
2883 if (params->deviceinfo.EventsSupported_len == 0) {
2884 printf(" None.\n");
2885 } else {
2886 for (i=0;i<params->deviceinfo.EventsSupported_len;i++) {
2887 printf(" 0x%04x\n", params->deviceinfo.EventsSupported[i]);
2888 }
2889 }
2890 printf("Device Properties Supported:\n");
2891 for (i=0;i<params->deviceinfo.DevicePropertiesSupported_len;i++) {
2892 char const *propdesc = ptp_get_property_description(params, params->deviceinfo.DevicePropertiesSupported[i]);
2893
2894 if (propdesc != NULL) {
2895 printf(" 0x%04x: %s\n", params->deviceinfo.DevicePropertiesSupported[i], propdesc);
2896 } else {
2897 uint16_t prop = params->deviceinfo.DevicePropertiesSupported[i];
2898 printf(" 0x%04x: Unknown property\n", prop);
2899 }
2900 }
2901
2902 if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjectPropsSupported)) {
2903 printf("Playable File (Object) Types and Object Properties Supported:\n");
2904 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
2905 char txt[256];
2906 uint16_t ret;
2907 uint16_t *props = NULL;
2908 uint32_t propcnt = 0;
2909 int j;
2910
2911 (void) ptp_render_ofc (params, params->deviceinfo.ImageFormats[i], sizeof(txt), txt);
2912 printf(" %04x: %s\n", params->deviceinfo.ImageFormats[i], txt);
2913
2914 ret = ptp_mtp_getobjectpropssupported (params, params->deviceinfo.ImageFormats[i], &propcnt, &props);
2915 if (ret != PTP_RC_OK) {
2916 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Dump_Device_Info(): error on query for object properties.");
2917 } else {
2918 for (j=0;j<propcnt;j++) {
2919 PTPObjectPropDesc opd;
2920 int k;
2921
2922 printf(" %04x: %s", props[j], LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
2923 // Get a more verbose description
2924 ret = ptp_mtp_getobjectpropdesc(params, props[j], params->deviceinfo.ImageFormats[i], &opd);
2925 if (ret != PTP_RC_OK) {
2926 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Dump_Device_Info(): "
2927 "could not get property description.");
2928 break;
2929 }
2930
2931 if (opd.DataType == PTP_DTC_STR) {
2932 printf(" STRING data type");
2933 switch (opd.FormFlag) {
2934 case PTP_OPFF_DateTime:
2935 printf(" DATETIME FORM");
2936 break;
2937 case PTP_OPFF_RegularExpression:
2938 printf(" REGULAR EXPRESSION FORM");
2939 break;
2940 case PTP_OPFF_LongString:
2941 printf(" LONG STRING FORM");
2942 break;
2943 default:
2944 break;
2945 }
2946 } else {
2947 if (opd.DataType & PTP_DTC_ARRAY_MASK) {
2948 printf(" array of");
2949 }
2950
2951 switch (opd.DataType & (~PTP_DTC_ARRAY_MASK)) {
2952
2953 case PTP_DTC_UNDEF:
2954 printf(" UNDEFINED data type");
2955 break;
2956
2957 case PTP_DTC_INT8:
2958 printf(" INT8 data type");
2959 switch (opd.FormFlag) {
2960 case PTP_OPFF_Range:
2961 printf(" range: MIN %d, MAX %d, STEP %d",
2962 opd.FORM.Range.MinimumValue.i8,
2963 opd.FORM.Range.MaximumValue.i8,
2964 opd.FORM.Range.StepSize.i8);
2965 break;
2966 case PTP_OPFF_Enumeration:
2967 printf(" enumeration: ");
2968 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
2969 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i8);
2970 }
2971 break;
2972 case PTP_OPFF_ByteArray:
2973 printf(" byte array: ");
2974 break;
2975 default:
2976 printf(" ANY 8BIT VALUE form");
2977 break;
2978 }
2979 break;
2980
2981 case PTP_DTC_UINT8:
2982 printf(" UINT8 data type");
2983 switch (opd.FormFlag) {
2984 case PTP_OPFF_Range:
2985 printf(" range: MIN %d, MAX %d, STEP %d",
2986 opd.FORM.Range.MinimumValue.u8,
2987 opd.FORM.Range.MaximumValue.u8,
2988 opd.FORM.Range.StepSize.u8);
2989 break;
2990 case PTP_OPFF_Enumeration:
2991 printf(" enumeration: ");
2992 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
2993 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u8);
2994 }
2995 break;
2996 case PTP_OPFF_ByteArray:
2997 printf(" byte array: ");
2998 break;
2999 default:
3000 printf(" ANY 8BIT VALUE form");
3001 break;
3002 }
3003 break;
3004
3005 case PTP_DTC_INT16:
3006 printf(" INT16 data type");
3007 switch (opd.FormFlag) {
3008 case PTP_OPFF_Range:
3009 printf(" range: MIN %d, MAX %d, STEP %d",
3010 opd.FORM.Range.MinimumValue.i16,
3011 opd.FORM.Range.MaximumValue.i16,
3012 opd.FORM.Range.StepSize.i16);
3013 break;
3014 case PTP_OPFF_Enumeration:
3015 printf(" enumeration: ");
3016 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3017 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i16);
3018 }
3019 break;
3020 default:
3021 printf(" ANY 16BIT VALUE form");
3022 break;
3023 }
3024 break;
3025
3026 case PTP_DTC_UINT16:
3027 printf(" UINT16 data type");
3028 switch (opd.FormFlag) {
3029 case PTP_OPFF_Range:
3030 printf(" range: MIN %d, MAX %d, STEP %d",
3031 opd.FORM.Range.MinimumValue.u16,
3032 opd.FORM.Range.MaximumValue.u16,
3033 opd.FORM.Range.StepSize.u16);
3034 break;
3035 case PTP_OPFF_Enumeration:
3036 printf(" enumeration: ");
3037 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3038 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u16);
3039 }
3040 break;
3041 default:
3042 printf(" ANY 16BIT VALUE form");
3043 break;
3044 }
3045 break;
3046
3047 case PTP_DTC_INT32:
3048 printf(" INT32 data type");
3049 switch (opd.FormFlag) {
3050 case PTP_OPFF_Range:
3051 printf(" range: MIN %d, MAX %d, STEP %d",
3052 opd.FORM.Range.MinimumValue.i32,
3053 opd.FORM.Range.MaximumValue.i32,
3054 opd.FORM.Range.StepSize.i32);
3055 break;
3056 case PTP_OPFF_Enumeration:
3057 printf(" enumeration: ");
3058 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3059 printf("%d, ", opd.FORM.Enum.SupportedValue[k].i32);
3060 }
3061 break;
3062 default:
3063 printf(" ANY 32BIT VALUE form");
3064 break;
3065 }
3066 break;
3067
3068 case PTP_DTC_UINT32:
3069 printf(" UINT32 data type");
3070 switch (opd.FormFlag) {
3071 case PTP_OPFF_Range:
3072 printf(" range: MIN %d, MAX %d, STEP %d",
3073 opd.FORM.Range.MinimumValue.u32,
3074 opd.FORM.Range.MaximumValue.u32,
3075 opd.FORM.Range.StepSize.u32);
3076 break;
3077 case PTP_OPFF_Enumeration:
3078 // Special pretty-print for FOURCC codes
3079 if (params->deviceinfo.ImageFormats[i] == PTP_OPC_VideoFourCCCodec) {
3080 printf(" enumeration of u32 casted FOURCC: ");
3081 for (k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3082 if (opd.FORM.Enum.SupportedValue[k].u32 == 0) {
3083 printf("ANY, ");
3084 } else {
3085 char fourcc[6];
3086 fourcc[0] = (opd.FORM.Enum.SupportedValue[k].u32 >> 24) & 0xFFU;
3087 fourcc[1] = (opd.FORM.Enum.SupportedValue[k].u32 >> 16) & 0xFFU;
3088 fourcc[2] = (opd.FORM.Enum.SupportedValue[k].u32 >> 8) & 0xFFU;
3089 fourcc[3] = opd.FORM.Enum.SupportedValue[k].u32 & 0xFFU;
3090 fourcc[4] = '\n';
3091 fourcc[5] = '\0';
3092 printf("\"%s\", ", fourcc);
3093 }
3094 }
3095 } else {
3096 printf(" enumeration: ");
3097 for(k=0;k<opd.FORM.Enum.NumberOfValues;k++) {
3098 printf("%d, ", opd.FORM.Enum.SupportedValue[k].u32);
3099 }
3100 }
3101 break;
3102 default:
3103 printf(" ANY 32BIT VALUE form");
3104 break;
3105 }
3106 break;
3107
3108 case PTP_DTC_INT64:
3109 printf(" INT64 data type");
3110 break;
3111
3112 case PTP_DTC_UINT64:
3113 printf(" UINT64 data type");
3114 break;
3115
3116 case PTP_DTC_INT128:
3117 printf(" INT128 data type");
3118 break;
3119
3120 case PTP_DTC_UINT128:
3121 printf(" UINT128 data type");
3122 break;
3123
3124 default:
3125 printf(" UNKNOWN data type");
3126 break;
3127 }
3128 }
3129 if (opd.GetSet) {
3130 printf(" GET/SET");
3131 } else {
3132 printf(" READ ONLY");
3133 }
3134 printf("\n");
3135 ptp_free_objectpropdesc(&opd);
3136 }
3137 free(props);
3138 }
3139 }
3140 }
3141
3142 if(storage != NULL && ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3143 printf("Storage Devices:\n");
3144 while(storage != NULL) {
3145 printf(" StorageID: 0x%08x\n",storage->id);
3146 printf(" StorageType: 0x%04x ",storage->StorageType);
3147 switch (storage->StorageType) {
3148 case PTP_ST_Undefined:
3149 printf("(undefined)\n");
3150 break;
3151 case PTP_ST_FixedROM:
3152 printf("fixed ROM storage\n");
3153 break;
3154 case PTP_ST_RemovableROM:
3155 printf("removable ROM storage\n");
3156 break;
3157 case PTP_ST_FixedRAM:
3158 printf("fixed RAM storage\n");
3159 break;
3160 case PTP_ST_RemovableRAM:
3161 printf("removable RAM storage\n");
3162 break;
3163 default:
3164 printf("UNKNOWN storage\n");
3165 break;
3166 }
3167 printf(" FilesystemType: 0x%04x ",storage->FilesystemType);
3168 switch(storage->FilesystemType) {
3169 case PTP_FST_Undefined:
3170 printf("(undefined)\n");
3171 break;
3172 case PTP_FST_GenericFlat:
3173 printf("generic flat filesystem\n");
3174 break;
3175 case PTP_FST_GenericHierarchical:
3176 printf("generic hierarchical\n");
3177 break;
3178 case PTP_FST_DCF:
3179 printf("DCF\n");
3180 break;
3181 default:
3182 printf("UNKNONWN filesystem type\n");
3183 break;
3184 }
3185 printf(" AccessCapability: 0x%04x ",storage->AccessCapability);
3186 switch(storage->AccessCapability) {
3187 case PTP_AC_ReadWrite:
3188 printf("read/write\n");
3189 break;
3190 case PTP_AC_ReadOnly:
3191 printf("read only\n");
3192 break;
3193 case PTP_AC_ReadOnly_with_Object_Deletion:
3194 printf("read only + object deletion\n");
3195 break;
3196 default:
3197 printf("UNKNOWN access capability\n");
3198 break;
3199 }
3200 printf(" MaxCapacity: %llu\n", (long long unsigned int) storage->MaxCapacity);
3201 printf(" FreeSpaceInBytes: %llu\n", (long long unsigned int) storage->FreeSpaceInBytes);
3202 printf(" FreeSpaceInObjects: %llu\n", (long long unsigned int) storage->FreeSpaceInObjects);
3203 printf(" StorageDescription: %s\n",storage->StorageDescription);
3204 printf(" VolumeIdentifier: %s\n",storage->VolumeIdentifier);
3205 storage = storage->next;
3206 }
3207 }
3208
3209 printf("Special directories:\n");
3210 printf(" Default music folder: 0x%08x\n", device->default_music_folder);
3211 printf(" Default playlist folder: 0x%08x\n", device->default_playlist_folder);
3212 printf(" Default picture folder: 0x%08x\n", device->default_picture_folder);
3213 printf(" Default video folder: 0x%08x\n", device->default_video_folder);
3214 printf(" Default organizer folder: 0x%08x\n", device->default_organizer_folder);
3215 printf(" Default zencast folder: 0x%08x\n", device->default_zencast_folder);
3216 printf(" Default album folder: 0x%08x\n", device->default_album_folder);
3217 printf(" Default text folder: 0x%08x\n", device->default_text_folder);
3218 }
3219
3220 /**
3221 * This resets a device in case it supports the <code>PTP_OC_ResetDevice</code>
3222 * operation code (0x1010).
3223 * @param device a pointer to the device to reset.
3224 * @return 0 on success, any other value means failure.
3225 */
LIBMTP_Reset_Device(LIBMTP_mtpdevice_t * device)3226 int LIBMTP_Reset_Device(LIBMTP_mtpdevice_t *device)
3227 {
3228 PTPParams *params = (PTPParams *) device->params;
3229 uint16_t ret;
3230
3231 if (!ptp_operation_issupported(params,PTP_OC_ResetDevice)) {
3232 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3233 "LIBMTP_Reset_Device(): device does not support resetting.");
3234 return -1;
3235 }
3236 ret = ptp_resetdevice(params);
3237 if (ret != PTP_RC_OK) {
3238 add_ptp_error_to_errorstack(device, ret, "Error resetting.");
3239 return -1;
3240 }
3241 return 0;
3242 }
3243
3244 /**
3245 * This retrieves the manufacturer name of an MTP device.
3246 * @param device a pointer to the device to get the manufacturer name for.
3247 * @return a newly allocated UTF-8 string representing the manufacturer name.
3248 * The string must be freed by the caller after use. If the call
3249 * was unsuccessful this will contain NULL.
3250 */
LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t * device)3251 char *LIBMTP_Get_Manufacturername(LIBMTP_mtpdevice_t *device)
3252 {
3253 char *retmanuf = NULL;
3254 PTPParams *params = (PTPParams *) device->params;
3255
3256 if (params->deviceinfo.Manufacturer != NULL) {
3257 retmanuf = strdup(params->deviceinfo.Manufacturer);
3258 }
3259 return retmanuf;
3260 }
3261
3262 /**
3263 * This retrieves the model name (often equal to product name)
3264 * of an MTP device.
3265 * @param device a pointer to the device to get the model name for.
3266 * @return a newly allocated UTF-8 string representing the model name.
3267 * The string must be freed by the caller after use. If the call
3268 * was unsuccessful this will contain NULL.
3269 */
LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t * device)3270 char *LIBMTP_Get_Modelname(LIBMTP_mtpdevice_t *device)
3271 {
3272 char *retmodel = NULL;
3273 PTPParams *params = (PTPParams *) device->params;
3274
3275 if (params->deviceinfo.Model != NULL) {
3276 retmodel = strdup(params->deviceinfo.Model);
3277 }
3278 return retmodel;
3279 }
3280
3281 /**
3282 * This retrieves the serial number of an MTP device.
3283 * @param device a pointer to the device to get the serial number for.
3284 * @return a newly allocated UTF-8 string representing the serial number.
3285 * The string must be freed by the caller after use. If the call
3286 * was unsuccessful this will contain NULL.
3287 */
LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t * device)3288 char *LIBMTP_Get_Serialnumber(LIBMTP_mtpdevice_t *device)
3289 {
3290 char *retnumber = NULL;
3291 PTPParams *params = (PTPParams *) device->params;
3292
3293 if (params->deviceinfo.SerialNumber != NULL) {
3294 retnumber = strdup(params->deviceinfo.SerialNumber);
3295 }
3296 return retnumber;
3297 }
3298
3299 /**
3300 * This retrieves the device version (hardware and firmware version) of an
3301 * MTP device.
3302 * @param device a pointer to the device to get the device version for.
3303 * @return a newly allocated UTF-8 string representing the device version.
3304 * The string must be freed by the caller after use. If the call
3305 * was unsuccessful this will contain NULL.
3306 */
LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t * device)3307 char *LIBMTP_Get_Deviceversion(LIBMTP_mtpdevice_t *device)
3308 {
3309 char *retversion = NULL;
3310 PTPParams *params = (PTPParams *) device->params;
3311
3312 if (params->deviceinfo.DeviceVersion != NULL) {
3313 retversion = strdup(params->deviceinfo.DeviceVersion);
3314 }
3315 return retversion;
3316 }
3317
3318
3319 /**
3320 * This retrieves the "friendly name" of an MTP device. Usually
3321 * this is simply the name of the owner or something like
3322 * "John Doe's Digital Audio Player". This property should be supported
3323 * by all MTP devices.
3324 * @param device a pointer to the device to get the friendly name for.
3325 * @return a newly allocated UTF-8 string representing the friendly name.
3326 * The string must be freed by the caller after use.
3327 * @see LIBMTP_Set_Friendlyname()
3328 */
LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t * device)3329 char *LIBMTP_Get_Friendlyname(LIBMTP_mtpdevice_t *device)
3330 {
3331 PTPPropertyValue propval;
3332 char *retstring = NULL;
3333 PTPParams *params = (PTPParams *) device->params;
3334 uint16_t ret;
3335
3336 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3337 return NULL;
3338 }
3339
3340 ret = ptp_getdevicepropvalue(params,
3341 PTP_DPC_MTP_DeviceFriendlyName,
3342 &propval,
3343 PTP_DTC_STR);
3344 if (ret != PTP_RC_OK) {
3345 add_ptp_error_to_errorstack(device, ret, "Error getting friendlyname.");
3346 return NULL;
3347 }
3348 if (propval.str != NULL) {
3349 retstring = strdup(propval.str);
3350 free(propval.str);
3351 }
3352 return retstring;
3353 }
3354
3355 /**
3356 * Sets the "friendly name" of an MTP device.
3357 * @param device a pointer to the device to set the friendly name for.
3358 * @param friendlyname the new friendly name for the device.
3359 * @return 0 on success, any other value means failure.
3360 * @see LIBMTP_Get_Friendlyname()
3361 */
LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t * device,char const * const friendlyname)3362 int LIBMTP_Set_Friendlyname(LIBMTP_mtpdevice_t *device,
3363 char const * const friendlyname)
3364 {
3365 PTPPropertyValue propval;
3366 PTPParams *params = (PTPParams *) device->params;
3367 uint16_t ret;
3368
3369 if (!ptp_property_issupported(params, PTP_DPC_MTP_DeviceFriendlyName)) {
3370 return -1;
3371 }
3372 propval.str = (char *) friendlyname;
3373 ret = ptp_setdevicepropvalue(params,
3374 PTP_DPC_MTP_DeviceFriendlyName,
3375 &propval,
3376 PTP_DTC_STR);
3377 if (ret != PTP_RC_OK) {
3378 add_ptp_error_to_errorstack(device, ret, "Error setting friendlyname.");
3379 return -1;
3380 }
3381 return 0;
3382 }
3383
3384 /**
3385 * This retrieves the syncronization partner of an MTP device. This
3386 * property should be supported by all MTP devices.
3387 * @param device a pointer to the device to get the sync partner for.
3388 * @return a newly allocated UTF-8 string representing the synchronization
3389 * partner. The string must be freed by the caller after use.
3390 * @see LIBMTP_Set_Syncpartner()
3391 */
LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t * device)3392 char *LIBMTP_Get_Syncpartner(LIBMTP_mtpdevice_t *device)
3393 {
3394 PTPPropertyValue propval;
3395 char *retstring = NULL;
3396 PTPParams *params = (PTPParams *) device->params;
3397 uint16_t ret;
3398
3399 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3400 return NULL;
3401 }
3402
3403 ret = ptp_getdevicepropvalue(params,
3404 PTP_DPC_MTP_SynchronizationPartner,
3405 &propval,
3406 PTP_DTC_STR);
3407 if (ret != PTP_RC_OK) {
3408 add_ptp_error_to_errorstack(device, ret, "Error getting syncpartner.");
3409 return NULL;
3410 }
3411 if (propval.str != NULL) {
3412 retstring = strdup(propval.str);
3413 free(propval.str);
3414 }
3415 return retstring;
3416 }
3417
3418
3419 /**
3420 * Sets the synchronization partner of an MTP device. Note that
3421 * we have no idea what the effect of setting this to "foobar"
3422 * may be. But the general idea seems to be to tell which program
3423 * shall synchronize with this device and tell others to leave
3424 * it alone.
3425 * @param device a pointer to the device to set the sync partner for.
3426 * @param syncpartner the new synchronization partner for the device.
3427 * @return 0 on success, any other value means failure.
3428 * @see LIBMTP_Get_Syncpartner()
3429 */
LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t * device,char const * const syncpartner)3430 int LIBMTP_Set_Syncpartner(LIBMTP_mtpdevice_t *device,
3431 char const * const syncpartner)
3432 {
3433 PTPPropertyValue propval;
3434 PTPParams *params = (PTPParams *) device->params;
3435 uint16_t ret;
3436
3437 if (!ptp_property_issupported(params, PTP_DPC_MTP_SynchronizationPartner)) {
3438 return -1;
3439 }
3440 propval.str = (char *) syncpartner;
3441 ret = ptp_setdevicepropvalue(params,
3442 PTP_DPC_MTP_SynchronizationPartner,
3443 &propval,
3444 PTP_DTC_STR);
3445 if (ret != PTP_RC_OK) {
3446 add_ptp_error_to_errorstack(device, ret, "Error setting syncpartner.");
3447 return -1;
3448 }
3449 return 0;
3450 }
3451
3452 /**
3453 * Checks if the device can stora a file of this size or
3454 * if it's too big.
3455 * @param device a pointer to the device.
3456 * @param filesize the size of the file to check whether it will fit.
3457 * @param storageid the ID of the storage to try to fit the file on.
3458 * @return 0 if the file fits, any other value means failure.
3459 */
check_if_file_fits(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage,uint64_t const filesize)3460 static int check_if_file_fits(LIBMTP_mtpdevice_t *device,
3461 LIBMTP_devicestorage_t *storage,
3462 uint64_t const filesize) {
3463 PTPParams *params = (PTPParams *) device->params;
3464 uint64_t freebytes;
3465 int ret;
3466
3467 // If we cannot check the storage, no big deal.
3468 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3469 return 0;
3470 }
3471
3472 ret = get_storage_freespace(device, storage, &freebytes);
3473 if (ret != 0) {
3474 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3475 "check_if_file_fits(): error checking free storage.");
3476 return -1;
3477 } else {
3478 // See if it fits.
3479 if (filesize > freebytes) {
3480 return -1;
3481 }
3482 }
3483 return 0;
3484 }
3485
3486
3487 /**
3488 * This function retrieves the current battery level on the device.
3489 * @param device a pointer to the device to get the battery level for.
3490 * @param maximum_level a pointer to a variable that will hold the
3491 * maximum level of the battery if the call was successful.
3492 * @param current_level a pointer to a variable that will hold the
3493 * current level of the battery if the call was successful.
3494 * A value of 0 means that the device is on external power.
3495 * @return 0 if the storage info was successfully retrieved, any other
3496 * means failure. A typical cause of failure is that
3497 * the device does not support the battery level property.
3498 */
LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t * device,uint8_t * const maximum_level,uint8_t * const current_level)3499 int LIBMTP_Get_Batterylevel(LIBMTP_mtpdevice_t *device,
3500 uint8_t * const maximum_level,
3501 uint8_t * const current_level)
3502 {
3503 PTPPropertyValue propval;
3504 uint16_t ret;
3505 PTPParams *params = (PTPParams *) device->params;
3506 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3507
3508 *maximum_level = 0;
3509 *current_level = 0;
3510
3511 if (FLAG_BROKEN_BATTERY_LEVEL(ptp_usb) ||
3512 !ptp_property_issupported(params, PTP_DPC_BatteryLevel)) {
3513 return -1;
3514 }
3515
3516 ret = ptp_getdevicepropvalue(params, PTP_DPC_BatteryLevel, &propval, PTP_DTC_UINT8);
3517 if (ret != PTP_RC_OK) {
3518 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Batterylevel(): could not get device property value.");
3519 return -1;
3520 }
3521
3522 *maximum_level = device->maximum_battery_level;
3523 *current_level = propval.u8;
3524
3525 return 0;
3526 }
3527
3528
3529 /**
3530 * Formats device storage (if the device supports the operation).
3531 * WARNING: This WILL delete all data from the device. Make sure you've
3532 * got confirmation from the user BEFORE you call this function.
3533 *
3534 * @param device a pointer to the device containing the storage to format.
3535 * @param storage the actual storage to format.
3536 * @return 0 on success, any other value means failure.
3537 */
LIBMTP_Format_Storage(LIBMTP_mtpdevice_t * device,LIBMTP_devicestorage_t * storage)3538 int LIBMTP_Format_Storage(LIBMTP_mtpdevice_t *device, LIBMTP_devicestorage_t *storage)
3539 {
3540 uint16_t ret;
3541 PTPParams *params = (PTPParams *) device->params;
3542
3543 if (!ptp_operation_issupported(params,PTP_OC_FormatStore)) {
3544 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3545 "LIBMTP_Format_Storage(): device does not support formatting storage.");
3546 return -1;
3547 }
3548 ret = ptp_formatstore(params, storage->id);
3549 if (ret != PTP_RC_OK) {
3550 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Format_Storage(): failed to format storage.");
3551 return -1;
3552 }
3553 return 0;
3554 }
3555
3556 /**
3557 * Helper function to extract a unicode property off a device.
3558 * This is the standard way of retrieveing unicode device
3559 * properties as described by the PTP spec.
3560 * @param device a pointer to the device to get the property from.
3561 * @param unicstring a pointer to a pointer that will hold the
3562 * property after this call is completed.
3563 * @param property the property to retrieve.
3564 * @return 0 on success, any other value means failure.
3565 */
get_device_unicode_property(LIBMTP_mtpdevice_t * device,char ** unicstring,uint16_t property)3566 static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
3567 char **unicstring, uint16_t property)
3568 {
3569 PTPPropertyValue propval;
3570 PTPParams *params = (PTPParams *) device->params;
3571 uint16_t *tmp;
3572 uint16_t ret;
3573 int i;
3574
3575 if (!ptp_property_issupported(params, property)) {
3576 return -1;
3577 }
3578
3579 // Unicode strings are 16bit unsigned integer arrays.
3580 ret = ptp_getdevicepropvalue(params,
3581 property,
3582 &propval,
3583 PTP_DTC_AUINT16);
3584 if (ret != PTP_RC_OK) {
3585 // TODO: add a note on WHICH property that we failed to get.
3586 *unicstring = NULL;
3587 add_ptp_error_to_errorstack(device, ret, "get_device_unicode_property(): failed to get unicode property.");
3588 return -1;
3589 }
3590
3591 // Extract the actual array.
3592 // printf("Array of %d elements\n", propval.a.count);
3593 tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));
3594 for (i = 0; i < propval.a.count; i++) {
3595 tmp[i] = propval.a.v[i].u16;
3596 // printf("%04x ", tmp[i]);
3597 }
3598 tmp[propval.a.count] = 0x0000U;
3599 free(propval.a.v);
3600
3601 *unicstring = utf16_to_utf8(device, tmp);
3602
3603 free(tmp);
3604
3605 return 0;
3606 }
3607
3608 /**
3609 * This function returns the secure time as an XML document string from
3610 * the device.
3611 * @param device a pointer to the device to get the secure time for.
3612 * @param sectime the secure time string as an XML document or NULL if the call
3613 * failed or the secure time property is not supported. This string
3614 * must be <code>free()</code>:ed by the caller after use.
3615 * @return 0 on success, any other value means failure.
3616 */
LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t * device,char ** const sectime)3617 int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime)
3618 {
3619 return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);
3620 }
3621
3622 /**
3623 * This function returns the device (public key) certificate as an
3624 * XML document string from the device.
3625 * @param device a pointer to the device to get the device certificate for.
3626 * @param devcert the device certificate as an XML string or NULL if the call
3627 * failed or the device certificate property is not supported. This
3628 * string must be <code>free()</code>:ed by the caller after use.
3629 * @return 0 on success, any other value means failure.
3630 */
LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t * device,char ** const devcert)3631 int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert)
3632 {
3633 return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);
3634 }
3635
3636 /**
3637 * This function retrieves a list of supported file types, i.e. the file
3638 * types that this device claims it supports, e.g. audio file types that
3639 * the device can play etc. This list is mitigated to
3640 * inlcude the file types that libmtp can handle, i.e. it will not list
3641 * filetypes that libmtp will handle internally like playlists and folders.
3642 * @param device a pointer to the device to get the filetype capabilities for.
3643 * @param filetypes a pointer to a pointer that will hold the list of
3644 * supported filetypes if the call was successful. This list must
3645 * be <code>free()</code>:ed by the caller after use.
3646 * @param length a pointer to a variable that will hold the length of the
3647 * list of supported filetypes if the call was successful.
3648 * @return 0 on success, any other value means failure.
3649 * @see LIBMTP_Get_Filetype_Description()
3650 */
LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t * device,uint16_t ** const filetypes,uint16_t * const length)3651 int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,
3652 uint16_t * const length)
3653 {
3654 PTPParams *params = (PTPParams *) device->params;
3655 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3656 uint16_t *localtypes;
3657 uint16_t localtypelen;
3658 uint32_t i;
3659
3660 // This is more memory than needed if there are unknown types, but what the heck.
3661 localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));
3662 localtypelen = 0;
3663
3664 for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {
3665 uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);
3666 if (localtype != LIBMTP_FILETYPE_UNKNOWN) {
3667 localtypes[localtypelen] = localtype;
3668 localtypelen++;
3669 }
3670 }
3671 // The forgotten Ogg support on YP-10 and others...
3672 if (FLAG_OGG_IS_UNKNOWN(ptp_usb)) {
3673 localtypes = (uint16_t *) realloc(localtypes, (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3674 localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
3675 localtypelen++;
3676 }
3677 // The forgotten FLAC support on Cowon iAudio S9 and others...
3678 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
3679 localtypes = (uint16_t *) realloc(localtypes, (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
3680 localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
3681 localtypelen++;
3682 }
3683
3684 *filetypes = localtypes;
3685 *length = localtypelen;
3686
3687 return 0;
3688 }
3689
3690 /**
3691 * This function updates all the storage id's of a device and their
3692 * properties, then creates a linked list and puts the list head into
3693 * the device struct. It also optionally sorts this list. If you want
3694 * to display storage information in your application you should call
3695 * this function, then dereference the device struct
3696 * (<code>device->storage</code>) to get out information on the storage.
3697 *
3698 * You need to call this everytime you want to update the
3699 * <code>device->storage</code> list, for example anytime you need
3700 * to check available storage somewhere.
3701 *
3702 * <b>WARNING:</b> since this list is dynamically updated, do not
3703 * reference its fields in external applications by pointer! E.g
3704 * do not put a reference to any <code>char *</code> field. instead
3705 * <code>strncpy()</code> it!
3706 *
3707 * @param device a pointer to the device to get the storage for.
3708 * @param sortby an integer that determines the sorting of the storage list.
3709 * Valid sort methods are defined in libmtp.h with beginning with
3710 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
3711 * sort.
3712 * @return 0 on success, 1 success but only with storage id's, storage
3713 * properities could not be retrieved and -1 means failure.
3714 */
LIBMTP_Get_Storage(LIBMTP_mtpdevice_t * device,int const sortby)3715 int LIBMTP_Get_Storage(LIBMTP_mtpdevice_t *device, int const sortby)
3716 {
3717 uint32_t i = 0;
3718 PTPStorageInfo storageInfo;
3719 PTPParams *params = (PTPParams *) device->params;
3720 PTPStorageIDs storageIDs;
3721 LIBMTP_devicestorage_t *storage = NULL;
3722 LIBMTP_devicestorage_t *storageprev = NULL;
3723
3724 if (device->storage != NULL)
3725 free_storage_list(device);
3726
3727 // if (!ptp_operation_issupported(params,PTP_OC_GetStorageIDs))
3728 // return -1;
3729 if (ptp_getstorageids (params, &storageIDs) != PTP_RC_OK)
3730 return -1;
3731 if (storageIDs.n < 1)
3732 return -1;
3733
3734 if (!ptp_operation_issupported(params,PTP_OC_GetStorageInfo)) {
3735 for (i = 0; i < storageIDs.n; i++) {
3736
3737 storage = (LIBMTP_devicestorage_t *) malloc(sizeof(LIBMTP_devicestorage_t));
3738 storage->prev = storageprev;
3739 if (storageprev != NULL)
3740 storageprev->next = storage;
3741 if (device->storage == NULL)
3742 device->storage = storage;
3743
3744 storage->id = storageIDs.Storage[i];
3745 storage->StorageType = PTP_ST_Undefined;
3746 storage->FilesystemType = PTP_FST_Undefined;
3747 storage->AccessCapability = PTP_AC_ReadWrite;
3748 storage->MaxCapacity = (uint64_t) -1;
3749 storage->FreeSpaceInBytes = (uint64_t) -1;
3750 storage->FreeSpaceInObjects = (uint64_t) -1;
3751 storage->StorageDescription = strdup("Unknown storage");
3752 storage->VolumeIdentifier = strdup("Unknown volume");
3753 storage->next = NULL;
3754
3755 storageprev = storage;
3756 }
3757 free(storageIDs.Storage);
3758 return 1;
3759 } else {
3760 for (i = 0; i < storageIDs.n; i++) {
3761 uint16_t ret;
3762 ret = ptp_getstorageinfo(params, storageIDs.Storage[i], &storageInfo);
3763 if (ret != PTP_RC_OK) {
3764 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Storage(): Could not get storage info.");
3765 if (device->storage != NULL) {
3766 free_storage_list(device);
3767 }
3768 return -1;
3769 }
3770
3771 storage = (LIBMTP_devicestorage_t *) malloc(sizeof(LIBMTP_devicestorage_t));
3772 storage->prev = storageprev;
3773 if (storageprev != NULL)
3774 storageprev->next = storage;
3775 if (device->storage == NULL)
3776 device->storage = storage;
3777
3778 storage->id = storageIDs.Storage[i];
3779 storage->StorageType = storageInfo.StorageType;
3780 storage->FilesystemType = storageInfo.FilesystemType;
3781 storage->AccessCapability = storageInfo.AccessCapability;
3782 storage->MaxCapacity = storageInfo.MaxCapability;
3783 storage->FreeSpaceInBytes = storageInfo.FreeSpaceInBytes;
3784 storage->FreeSpaceInObjects = storageInfo.FreeSpaceInImages;
3785 storage->StorageDescription = storageInfo.StorageDescription;
3786 storage->VolumeIdentifier = storageInfo.VolumeLabel;
3787 storage->next = NULL;
3788
3789 storageprev = storage;
3790 }
3791
3792 if (storage != NULL)
3793 storage->next = NULL;
3794
3795 sort_storage_by(device,sortby);
3796 free(storageIDs.Storage);
3797 return 0;
3798 }
3799 }
3800
3801 /**
3802 * This creates a new file metadata structure and allocates memory
3803 * for it. Notice that if you add strings to this structure they
3804 * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code>
3805 * operation later, so be careful of using strdup() when assigning
3806 * strings, e.g.:
3807 *
3808 * <pre>
3809 * LIBMTP_file_t *file = LIBMTP_new_file_t();
3810 * file->filename = strdup(namestr);
3811 * ....
3812 * LIBMTP_destroy_file_t(file);
3813 * </pre>
3814 *
3815 * @return a pointer to the newly allocated metadata structure.
3816 * @see LIBMTP_destroy_file_t()
3817 */
LIBMTP_new_file_t(void)3818 LIBMTP_file_t *LIBMTP_new_file_t(void)
3819 {
3820 LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));
3821 if (new == NULL) {
3822 return NULL;
3823 }
3824 new->filename = NULL;
3825 new->item_id = 0;
3826 new->parent_id = 0;
3827 new->storage_id = 0;
3828 new->filesize = 0;
3829 new->modificationdate = 0;
3830 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
3831 new->next = NULL;
3832 return new;
3833 }
3834
3835 /**
3836 * This destroys a file metadata structure and deallocates the memory
3837 * used by it, including any strings. Never use a file metadata
3838 * structure again after calling this function on it.
3839 * @param file the file metadata to destroy.
3840 * @see LIBMTP_new_file_t()
3841 */
LIBMTP_destroy_file_t(LIBMTP_file_t * file)3842 void LIBMTP_destroy_file_t(LIBMTP_file_t *file)
3843 {
3844 if (file == NULL) {
3845 return;
3846 }
3847 if (file->filename != NULL)
3848 free(file->filename);
3849 free(file);
3850 return;
3851 }
3852
3853 /**
3854 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
3855 * NOT TO USE IT.
3856 * @see LIBMTP_Get_Filelisting_With_Callback()
3857 */
LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t * device)3858 LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device)
3859 {
3860 printf("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");
3861 printf("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");
3862 return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
3863 }
3864
3865 /**
3866 * This returns a long list of all files available
3867 * on the current MTP device. Folders will not be returned, but abstract
3868 * entities like playlists and albums will show up as "files". Typical usage:
3869 *
3870 * <pre>
3871 * LIBMTP_file_t *filelist;
3872 *
3873 * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data);
3874 * while (filelist != NULL) {
3875 * LIBMTP_file_t *tmp;
3876 *
3877 * // Do something on each element in the list here...
3878 * tmp = filelist;
3879 * filelist = filelist->next;
3880 * LIBMTP_destroy_file_t(tmp);
3881 * }
3882 * </pre>
3883 *
3884 * If you want to group your file listing by storage (per storage unit) or
3885 * arrange files into folders, you must dereference the <code>storage_id</code>
3886 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code>
3887 * struct. To arrange by folders or files you typically have to create the proper
3888 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
3889 * <code>LIBMTP_Get_Folder_List()</code> first.
3890 *
3891 * @param device a pointer to the device to get the file listing for.
3892 * @param callback a function to be called during the tracklisting retrieveal
3893 * for displaying progress bars etc, or NULL if you don't want
3894 * any callbacks.
3895 * @param data a user-defined pointer that is passed along to
3896 * the <code>progress</code> function in order to
3897 * pass along some user defined data to the progress
3898 * updates. If not used, set this to NULL.
3899 * @return a list of files that can be followed using the <code>next</code>
3900 * field of the <code>LIBMTP_file_t</code> data structure.
3901 * Each of the metadata tags must be freed after use, and may
3902 * contain only partial metadata information, i.e. one or several
3903 * fields may be NULL or 0.
3904 * @see LIBMTP_Get_Filemetadata()
3905 */
LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)3906 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
3907 LIBMTP_progressfunc_t const callback,
3908 void const * const data)
3909 {
3910 uint32_t i = 0;
3911 LIBMTP_file_t *retfiles = NULL;
3912 LIBMTP_file_t *curfile = NULL;
3913 PTPParams *params = (PTPParams *) device->params;
3914 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3915 uint16_t ret;
3916
3917 // Get all the handles if we haven't already done that
3918 if (params->nrofobjects == 0) {
3919 flush_handles(device);
3920 }
3921
3922 for (i = 0; i < params->nrofobjects; i++) {
3923 LIBMTP_file_t *file;
3924 PTPObject *ob, *xob;
3925
3926 if (callback != NULL)
3927 callback(i, params->nrofobjects, data);
3928
3929 ob = ¶ms->objects[i];
3930
3931 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
3932 // MTP use this object format for folders which means
3933 // these "files" will turn up on a folder listing instead.
3934 continue;
3935 }
3936
3937 // Allocate a new file type
3938 file = LIBMTP_new_file_t();
3939
3940 file->parent_id = ob->oi.ParentObject;
3941 file->storage_id = ob->oi.StorageID;
3942
3943 // This is some sort of unique ID so we can keep track of the track.
3944 file->item_id = ob->oid;
3945
3946 // Set the filetype
3947 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
3948
3949 // Set the modification date
3950 file->modificationdate = ob->oi.ModificationDate;
3951
3952 // Original file-specific properties
3953 // We only have 32-bit file size here; if we find it, we use the
3954 // PTP_OPC_ObjectSize property which has 64bit precision.
3955 file->filesize = ob->oi.ObjectCompressedSize;
3956 if (ob->oi.Filename != NULL) {
3957 file->filename = strdup(ob->oi.Filename);
3958 }
3959
3960 /*
3961 * A special quirk for devices that doesn't quite
3962 * remember that some files marked as "unknown" type are
3963 * actually OGG or FLAC files. We look at the filename extension
3964 * and see if it happens that this was atleast named "ogg" or "flac"
3965 * and fall back on this heuristic approach in that case,
3966 * for these bugged devices only.
3967 */
3968 if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
3969 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
3970 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
3971 has_ogg_extension(file->filename))
3972 file->filetype = LIBMTP_FILETYPE_OGG;
3973 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
3974 has_flac_extension(file->filename))
3975 file->filetype = LIBMTP_FILETYPE_FLAC;
3976 }
3977
3978 /*
3979 * If we have a cached, large set of metadata, then use it!
3980 */
3981 ret = ptp_object_want (params, ob->oid, PTPOBJECT_MTPPROPLIST_LOADED, &xob);
3982 if (ob->mtpprops) {
3983 MTPProperties *prop = ob->mtpprops;
3984 int i;
3985
3986 for (i=0;i<ob->nrofmtpprops;i++) {
3987 // Pick ObjectSize here...
3988 if (prop->property == PTP_OPC_ObjectSize) {
3989 if (device->object_bitsize == 64) {
3990 file->filesize = prop->propval.u64;
3991 } else {
3992 file->filesize = prop->propval.u32;
3993 }
3994 break;
3995 }
3996 prop++;
3997 }
3998 } else {
3999 uint16_t *props = NULL;
4000 uint32_t propcnt = 0;
4001
4002 // First see which properties can be retrieved for this object format
4003 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
4004 if (ret != PTP_RC_OK) {
4005 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): call to ptp_mtp_getobjectpropssupported() failed.");
4006 // Silently fall through.
4007 } else {
4008 int i;
4009 for (i=0;i<propcnt;i++) {
4010 switch (props[i]) {
4011 case PTP_OPC_ObjectSize:
4012 if (device->object_bitsize == 64) {
4013 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4014 } else {
4015 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4016 }
4017 break;
4018 default:
4019 break;
4020 }
4021 }
4022 free(props);
4023 }
4024 }
4025
4026 // Add track to a list that will be returned afterwards.
4027 if (retfiles == NULL) {
4028 retfiles = file;
4029 curfile = file;
4030 } else {
4031 curfile->next = file;
4032 curfile = file;
4033 }
4034
4035 // Call listing callback
4036 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4037
4038 } // Handle counting loop
4039 return retfiles;
4040 }
4041
4042 /**
4043 * This function retrieves the metadata for a single file off
4044 * the device.
4045 *
4046 * Do not call this function repeatedly! The file handles are linearly
4047 * searched O(n) and the call may involve (slow) USB traffic, so use
4048 * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably
4049 * as an efficient data structure such as a hash list.
4050 *
4051 * Incidentally this function will return metadata for
4052 * a folder (association) as well, but this is not a proper use
4053 * of it, it is intended for file manipulation, not folder manipulation.
4054 *
4055 * @param device a pointer to the device to get the file metadata from.
4056 * @param fileid the object ID of the file that you want the metadata for.
4057 * @return a metadata entry on success or NULL on failure.
4058 * @see LIBMTP_Get_Filelisting()
4059 */
LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t * device,uint32_t const fileid)4060 LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid)
4061 {
4062 uint32_t i = 0;
4063 PTPParams *params = (PTPParams *) device->params;
4064 uint16_t ret;
4065 PTPObject *ob;
4066 LIBMTP_file_t *file;
4067
4068 // Get all the handles if we haven't already done that
4069 if (params->nrofobjects == 0) {
4070 flush_handles(device);
4071 }
4072
4073 ret = ptp_object_want (params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4074 if (ret != PTP_RC_OK)
4075 return NULL;
4076
4077 // Allocate a new file type
4078 file = LIBMTP_new_file_t();
4079
4080 file->parent_id = ob->oi.ParentObject;
4081 file->storage_id = ob->oi.StorageID;
4082
4083 // Set the filetype
4084 file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4085
4086 // Original file-specific properties
4087
4088 // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
4089 file->filesize = ob->oi.ObjectCompressedSize;
4090 if (ob->oi.Filename != NULL) {
4091 file->filename = strdup(ob->oi.Filename);
4092 }
4093
4094 // This is some sort of unique ID so we can keep track of the file.
4095 file->item_id = fileid;
4096
4097 /*
4098 * If we have a cached, large set of metadata, then use it!
4099 */
4100 if (ob->mtpprops) {
4101 MTPProperties *prop = ob->mtpprops;
4102
4103 for (i=0;i<ob->nrofmtpprops;i++,prop++) {
4104 // Pick ObjectSize here...
4105 if (prop->property == PTP_OPC_ObjectSize) {
4106 // This may already be set, but this 64bit precision value
4107 // is better than the PTP 32bit value, so let it override.
4108 if (device->object_bitsize == 64) {
4109 file->filesize = prop->propval.u64;
4110 } else {
4111 file->filesize = prop->propval.u32;
4112 }
4113 break;
4114 }
4115 }
4116 } else {
4117 uint16_t *props = NULL;
4118 uint32_t propcnt = 0;
4119
4120 // First see which properties can be retrieved for this object format
4121 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
4122 if (ret != PTP_RC_OK) {
4123 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filemetadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4124 // Silently fall through.
4125 } else {
4126 for (i=0;i<propcnt;i++) {
4127 switch (props[i]) {
4128 case PTP_OPC_ObjectSize:
4129 if (device->object_bitsize == 64) {
4130 file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4131 } else {
4132 file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
4133 }
4134 break;
4135 default:
4136 break;
4137 }
4138 }
4139 free(props);
4140 }
4141 }
4142
4143 return file;
4144 }
4145
4146 /**
4147 * This creates a new track metadata structure and allocates memory
4148 * for it. Notice that if you add strings to this structure they
4149 * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code>
4150 * operation later, so be careful of using strdup() when assigning
4151 * strings, e.g.:
4152 *
4153 * <pre>
4154 * LIBMTP_track_t *track = LIBMTP_new_track_t();
4155 * track->title = strdup(titlestr);
4156 * ....
4157 * LIBMTP_destroy_track_t(track);
4158 * </pre>
4159 *
4160 * @return a pointer to the newly allocated metadata structure.
4161 * @see LIBMTP_destroy_track_t()
4162 */
LIBMTP_new_track_t(void)4163 LIBMTP_track_t *LIBMTP_new_track_t(void)
4164 {
4165 LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));
4166 if (new == NULL) {
4167 return NULL;
4168 }
4169 new->item_id = 0;
4170 new->parent_id = 0;
4171 new->storage_id = 0;
4172 new->title = NULL;
4173 new->artist = NULL;
4174 new->composer = NULL;
4175 new->album = NULL;
4176 new->genre = NULL;
4177 new->date = NULL;
4178 new->filename = NULL;
4179 new->duration = 0;
4180 new->tracknumber = 0;
4181 new->filesize = 0;
4182 new->filetype = LIBMTP_FILETYPE_UNKNOWN;
4183 new->samplerate = 0;
4184 new->nochannels = 0;
4185 new->wavecodec = 0;
4186 new->bitrate = 0;
4187 new->bitratetype = 0;
4188 new->rating = 0;
4189 new->usecount = 0;
4190 new->modificationdate = 0;
4191 new->next = NULL;
4192 return new;
4193 }
4194
4195 /**
4196 * This destroys a track metadata structure and deallocates the memory
4197 * used by it, including any strings. Never use a track metadata
4198 * structure again after calling this function on it.
4199 * @param track the track metadata to destroy.
4200 * @see LIBMTP_new_track_t()
4201 */
LIBMTP_destroy_track_t(LIBMTP_track_t * track)4202 void LIBMTP_destroy_track_t(LIBMTP_track_t *track)
4203 {
4204 if (track == NULL) {
4205 return;
4206 }
4207 if (track->title != NULL)
4208 free(track->title);
4209 if (track->artist != NULL)
4210 free(track->artist);
4211 if (track->composer != NULL)
4212 free(track->composer);
4213 if (track->album != NULL)
4214 free(track->album);
4215 if (track->genre != NULL)
4216 free(track->genre);
4217 if (track->date != NULL)
4218 free(track->date);
4219 if (track->filename != NULL)
4220 free(track->filename);
4221 free(track);
4222 return;
4223 }
4224
4225 /**
4226 * This function maps and copies a property onto the track metadata if applicable.
4227 */
pick_property_to_track_metadata(LIBMTP_mtpdevice_t * device,MTPProperties * prop,LIBMTP_track_t * track)4228 static void pick_property_to_track_metadata(LIBMTP_mtpdevice_t *device, MTPProperties *prop, LIBMTP_track_t *track)
4229 {
4230 switch (prop->property) {
4231 case PTP_OPC_Name:
4232 if (prop->propval.str != NULL)
4233 track->title = strdup(prop->propval.str);
4234 else
4235 track->title = NULL;
4236 break;
4237 case PTP_OPC_Artist:
4238 if (prop->propval.str != NULL)
4239 track->artist = strdup(prop->propval.str);
4240 else
4241 track->artist = NULL;
4242 break;
4243 case PTP_OPC_Composer:
4244 if (prop->propval.str != NULL)
4245 track->composer = strdup(prop->propval.str);
4246 else
4247 track->composer = NULL;
4248 break;
4249 case PTP_OPC_Duration:
4250 track->duration = prop->propval.u32;
4251 break;
4252 case PTP_OPC_Track:
4253 track->tracknumber = prop->propval.u16;
4254 break;
4255 case PTP_OPC_Genre:
4256 if (prop->propval.str != NULL)
4257 track->genre = strdup(prop->propval.str);
4258 else
4259 track->genre = NULL;
4260 break;
4261 case PTP_OPC_AlbumName:
4262 if (prop->propval.str != NULL)
4263 track->album = strdup(prop->propval.str);
4264 else
4265 track->album = NULL;
4266 break;
4267 case PTP_OPC_OriginalReleaseDate:
4268 if (prop->propval.str != NULL)
4269 track->date = strdup(prop->propval.str);
4270 else
4271 track->date = NULL;
4272 break;
4273 // These are, well not so important.
4274 case PTP_OPC_SampleRate:
4275 track->samplerate = prop->propval.u32;
4276 break;
4277 case PTP_OPC_NumberOfChannels:
4278 track->nochannels = prop->propval.u16;
4279 break;
4280 case PTP_OPC_AudioWAVECodec:
4281 track->wavecodec = prop->propval.u32;
4282 break;
4283 case PTP_OPC_AudioBitRate:
4284 track->bitrate = prop->propval.u32;
4285 break;
4286 case PTP_OPC_BitRateType:
4287 track->bitratetype = prop->propval.u16;
4288 break;
4289 case PTP_OPC_Rating:
4290 track->rating = prop->propval.u16;
4291 break;
4292 case PTP_OPC_UseCount:
4293 track->usecount = prop->propval.u32;
4294 break;
4295 case PTP_OPC_ObjectSize:
4296 if (device->object_bitsize == 64) {
4297 track->filesize = prop->propval.u64;
4298 } else {
4299 track->filesize = prop->propval.u32;
4300 }
4301 break;
4302 default:
4303 break;
4304 }
4305 }
4306
4307 /**
4308 * This function retrieves the track metadata for a track
4309 * given by a unique ID.
4310 * @param device a pointer to the device to get the track metadata off.
4311 * @param trackid the unique ID of the track.
4312 * @param objectformat the object format of this track, so we know what it supports.
4313 * @param track a metadata set to fill in.
4314 */
get_track_metadata(LIBMTP_mtpdevice_t * device,uint16_t objectformat,LIBMTP_track_t * track)4315 static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,
4316 LIBMTP_track_t *track)
4317 {
4318 uint16_t ret;
4319 PTPParams *params = (PTPParams *) device->params;
4320 uint32_t i;
4321 MTPProperties *prop;
4322 PTPObject *ob;
4323
4324 /*
4325 * If we have a cached, large set of metadata, then use it!
4326 */
4327 ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
4328 if (ob->mtpprops) {
4329 prop = ob->mtpprops;
4330 for (i=0;i<ob->nrofmtpprops;i++,prop++)
4331 pick_property_to_track_metadata(device, prop, track);
4332 } else {
4333 uint16_t *props = NULL;
4334 uint32_t propcnt = 0;
4335
4336 // First see which properties can be retrieved for this object format
4337 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(track->filetype), &propcnt, &props);
4338 if (ret != PTP_RC_OK) {
4339 add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
4340 // Just bail out for now, nothing is ever set.
4341 return;
4342 } else {
4343 for (i=0;i<propcnt;i++) {
4344 switch (props[i]) {
4345 case PTP_OPC_Name:
4346 track->title = get_string_from_object(device, track->item_id, PTP_OPC_Name);
4347 break;
4348 case PTP_OPC_Artist:
4349 track->artist = get_string_from_object(device, track->item_id, PTP_OPC_Artist);
4350 break;
4351 case PTP_OPC_Composer:
4352 track->composer = get_string_from_object(device, track->item_id, PTP_OPC_Composer);
4353 break;
4354 case PTP_OPC_Duration:
4355 track->duration = get_u32_from_object(device, track->item_id, PTP_OPC_Duration, 0);
4356 break;
4357 case PTP_OPC_Track:
4358 track->tracknumber = get_u16_from_object(device, track->item_id, PTP_OPC_Track, 0);
4359 break;
4360 case PTP_OPC_Genre:
4361 track->genre = get_string_from_object(device, track->item_id, PTP_OPC_Genre);
4362 break;
4363 case PTP_OPC_AlbumName:
4364 track->album = get_string_from_object(device, track->item_id, PTP_OPC_AlbumName);
4365 break;
4366 case PTP_OPC_OriginalReleaseDate:
4367 track->date = get_string_from_object(device, track->item_id, PTP_OPC_OriginalReleaseDate);
4368 break;
4369 // These are, well not so important.
4370 case PTP_OPC_SampleRate:
4371 track->samplerate = get_u32_from_object(device, track->item_id, PTP_OPC_SampleRate, 0);
4372 break;
4373 case PTP_OPC_NumberOfChannels:
4374 track->nochannels = get_u16_from_object(device, track->item_id, PTP_OPC_NumberOfChannels, 0);
4375 break;
4376 case PTP_OPC_AudioWAVECodec:
4377 track->wavecodec = get_u32_from_object(device, track->item_id, PTP_OPC_AudioWAVECodec, 0);
4378 break;
4379 case PTP_OPC_AudioBitRate:
4380 track->bitrate = get_u32_from_object(device, track->item_id, PTP_OPC_AudioBitRate, 0);
4381 break;
4382 case PTP_OPC_BitRateType:
4383 track->bitratetype = get_u16_from_object(device, track->item_id, PTP_OPC_BitRateType, 0);
4384 break;
4385 case PTP_OPC_Rating:
4386 track->rating = get_u16_from_object(device, track->item_id, PTP_OPC_Rating, 0);
4387 break;
4388 case PTP_OPC_UseCount:
4389 track->usecount = get_u32_from_object(device, track->item_id, PTP_OPC_UseCount, 0);
4390 break;
4391 case PTP_OPC_ObjectSize:
4392 if (device->object_bitsize == 64) {
4393 track->filesize = get_u64_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4394 } else {
4395 track->filesize = (uint64_t) get_u32_from_object(device, track->item_id, PTP_OPC_ObjectSize, 0);
4396 }
4397 break;
4398 }
4399 }
4400 free(props);
4401 }
4402 }
4403 }
4404
4405 /**
4406 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
4407 * NOT TO USE IT.
4408 * @see LIBMTP_Get_Tracklisting_With_Callback()
4409 */
LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t * device)4410 LIBMTP_track_t *LIBMTP_Get_Tracklisting(LIBMTP_mtpdevice_t *device)
4411 {
4412 printf("WARNING: LIBMTP_Get_Tracklisting() is deprecated.\n");
4413 printf("WARNING: please update your code to use LIBMTP_Get_Tracklisting_With_Callback()\n");
4414 return LIBMTP_Get_Tracklisting_With_Callback(device, NULL, NULL);
4415 }
4416
4417 /**
4418 * This returns a long list of all tracks available on the current MTP device.
4419 * Tracks include multimedia objects, both music tracks and video tracks.
4420 * Typical usage:
4421 *
4422 * <pre>
4423 * LIBMTP_track_t *tracklist;
4424 *
4425 * tracklist = LIBMTP_Get_Tracklisting_With_Callback(device, callback, data);
4426 * while (tracklist != NULL) {
4427 * LIBMTP_track_t *tmp;
4428 *
4429 * // Do something on each element in the list here...
4430 * tmp = tracklist;
4431 * tracklist = tracklist->next;
4432 * LIBMTP_destroy_track_t(tmp);
4433 * }
4434 * </pre>
4435 *
4436 * If you want to group your track listing by storage (per storage unit) or
4437 * arrange tracks into folders, you must dereference the <code>storage_id</code>
4438 * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code>
4439 * struct. To arrange by folders or files you typically have to create the proper
4440 * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or
4441 * <code>LIBMTP_Get_Folder_List()</code> first.
4442 *
4443 * @param device a pointer to the device to get the track listing for.
4444 * @param callback a function to be called during the tracklisting retrieveal
4445 * for displaying progress bars etc, or NULL if you don't want
4446 * any callbacks.
4447 * @param data a user-defined pointer that is passed along to
4448 * the <code>progress</code> function in order to
4449 * pass along some user defined data to the progress
4450 * updates. If not used, set this to NULL.
4451 * @return a list of tracks that can be followed using the <code>next</code>
4452 * field of the <code>LIBMTP_track_t</code> data structure.
4453 * Each of the metadata tags must be freed after use, and may
4454 * contain only partial metadata information, i.e. one or several
4455 * fields may be NULL or 0.
4456 * @see LIBMTP_Get_Trackmetadata()
4457 */
LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t * device,LIBMTP_progressfunc_t const callback,void const * const data)4458 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
4459 LIBMTP_progressfunc_t const callback,
4460 void const * const data)
4461 {
4462 uint32_t i = 0;
4463 LIBMTP_track_t *retracks = NULL;
4464 LIBMTP_track_t *curtrack = NULL;
4465 PTPParams *params = (PTPParams *) device->params;
4466 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4467
4468 // Get all the handles if we haven't already done that
4469 if (params->nrofobjects == 0) {
4470 flush_handles(device);
4471 }
4472
4473 for (i = 0; i < params->nrofobjects; i++) {
4474 LIBMTP_track_t *track;
4475 PTPObject *ob;
4476 LIBMTP_filetype_t mtptype;
4477
4478 if (callback != NULL)
4479 callback(i, params->nrofobjects, data);
4480
4481 ob = ¶ms->objects[i];
4482 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4483
4484 // Ignore stuff we don't know how to handle...
4485 // TODO: get this list as an intersection of the sets
4486 // supported by the device and the from the device and
4487 // all known track files?
4488 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4489 // This row lets through undefined files for examination since they may be forgotten OGG files.
4490 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4491 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4492 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4493 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4494 ) {
4495 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4496 continue;
4497 }
4498
4499 // Allocate a new track type
4500 track = LIBMTP_new_track_t();
4501
4502 // This is some sort of unique ID so we can keep track of the track.
4503 track->item_id = ob->oid;
4504 track->parent_id = ob->oi.ParentObject;
4505 track->storage_id = ob->oi.StorageID;
4506 track->modificationdate = ob->oi.ModificationDate;
4507
4508 track->filetype = mtptype;
4509
4510 // Original file-specific properties
4511 track->filesize = ob->oi.ObjectCompressedSize;
4512 if (ob->oi.Filename != NULL) {
4513 track->filename = strdup(ob->oi.Filename);
4514 }
4515
4516 get_track_metadata(device, ob->oi.ObjectFormat, track);
4517
4518 /*
4519 * A special quirk for iriver devices that doesn't quite
4520 * remember that some files marked as "unknown" type are
4521 * actually OGG or FLAC files. We look at the filename extension
4522 * and see if it happens that this was atleast named "ogg" or "flac"
4523 * and fall back on this heuristic approach in that case,
4524 * for these bugged devices only.
4525 */
4526 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
4527 track->filename != NULL) {
4528 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4529 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4530 has_ogg_extension(track->filename))
4531 track->filetype = LIBMTP_FILETYPE_OGG;
4532 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
4533 has_flac_extension(track->filename))
4534 track->filetype = LIBMTP_FILETYPE_FLAC;
4535 else {
4536 // This was not an OGG/FLAC file so discard it and continue
4537 LIBMTP_destroy_track_t(track);
4538 continue;
4539 }
4540 }
4541
4542 // Add track to a list that will be returned afterwards.
4543 if (retracks == NULL) {
4544 retracks = track;
4545 curtrack = track;
4546 } else {
4547 curtrack->next = track;
4548 curtrack = track;
4549 }
4550
4551 // Call listing callback
4552 // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;
4553
4554
4555 } // Handle counting loop
4556 return retracks;
4557 }
4558
4559 /**
4560 * This function retrieves the metadata for a single track off
4561 * the device.
4562 *
4563 * Do not call this function repeatedly! The track handles are linearly
4564 * searched O(n) and the call may involve (slow) USB traffic, so use
4565 * <code>LIBMTP_Get_Tracklisting()</code> and cache the tracks, preferably
4566 * as an efficient data structure such as a hash list.
4567 *
4568 * @param device a pointer to the device to get the track metadata from.
4569 * @param trackid the object ID of the track that you want the metadata for.
4570 * @return a track metadata entry on success or NULL on failure.
4571 * @see LIBMTP_Get_Tracklisting()
4572 */
LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t * device,uint32_t const trackid)4573 LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
4574 {
4575 PTPParams *params = (PTPParams *) device->params;
4576 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4577 PTPObject *ob;
4578 LIBMTP_track_t *track;
4579 LIBMTP_filetype_t mtptype;
4580 uint16_t ret;
4581
4582 // Get all the handles if we haven't already done that
4583 if (params->nrofobjects == 0)
4584 flush_handles(device);
4585
4586 ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
4587 if (ret != PTP_RC_OK)
4588 return NULL;
4589
4590 mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
4591
4592 // Ignore stuff we don't know how to handle...
4593 if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
4594 /*
4595 * This row lets through undefined files for examination
4596 * since they may be forgotten OGG or FLAC files.
4597 */
4598 (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
4599 (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
4600 !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
4601 !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
4602 ) {
4603 //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
4604 return NULL;
4605 }
4606
4607 // Allocate a new track type
4608 track = LIBMTP_new_track_t();
4609
4610 // This is some sort of unique ID so we can keep track of the track.
4611 track->item_id = ob->oid;
4612 track->parent_id = ob->oi.ParentObject;
4613 track->storage_id = ob->oi.StorageID;
4614 track->modificationdate = ob->oi.ModificationDate;
4615
4616 track->filetype = mtptype;
4617
4618 // Original file-specific properties
4619 track->filesize = ob->oi.ObjectCompressedSize;
4620 if (ob->oi.Filename != NULL) {
4621 track->filename = strdup(ob->oi.Filename);
4622 }
4623
4624 /*
4625 * A special quirk for devices that doesn't quite
4626 * remember that some files marked as "unknown" type are
4627 * actually OGG or FLAC files. We look at the filename extension
4628 * and see if it happens that this was atleast named "ogg"
4629 * and fall back on this heuristic approach in that case,
4630 * for these bugged devices only.
4631 */
4632 if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
4633 track->filename != NULL) {
4634 if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
4635 FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
4636 has_ogg_extension(track->filename))
4637 track->filetype = LIBMTP_FILETYPE_OGG;
4638 else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
4639 has_flac_extension(track->filename))
4640 track->filetype = LIBMTP_FILETYPE_FLAC;
4641 else {
4642 // This was not an OGG/FLAC file so discard it
4643 LIBMTP_destroy_track_t(track);
4644 return NULL;
4645 }
4646 }
4647 get_track_metadata(device, ob->oi.ObjectFormat, track);
4648 return track;
4649 }
4650
4651 /**
4652 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
4653 * to isolate the internal type.
4654 */
get_func_wrapper(PTPParams * params,void * priv,unsigned long wantlen,unsigned char * data,unsigned long * gotlen)4655 static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
4656 {
4657 MTPDataHandler *handler = (MTPDataHandler *)priv;
4658 uint16_t ret;
4659 uint32_t local_gotlen = 0;
4660 ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
4661 *gotlen = local_gotlen;
4662 switch (ret)
4663 {
4664 case LIBMTP_HANDLER_RETURN_OK:
4665 return PTP_RC_OK;
4666 case LIBMTP_HANDLER_RETURN_ERROR:
4667 return PTP_ERROR_IO;
4668 case LIBMTP_HANDLER_RETURN_CANCEL:
4669 return PTP_ERROR_CANCEL;
4670 default:
4671 return PTP_ERROR_IO;
4672 }
4673 }
4674
4675 /**
4676 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
4677 * to isolate the internal type.
4678 */
put_func_wrapper(PTPParams * params,void * priv,unsigned long sendlen,unsigned char * data,unsigned long * putlen)4679 static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen)
4680 {
4681 MTPDataHandler *handler = (MTPDataHandler *)priv;
4682 uint16_t ret;
4683 uint32_t local_putlen = 0;
4684 ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
4685 *putlen = local_putlen;
4686 switch (ret)
4687 {
4688 case LIBMTP_HANDLER_RETURN_OK:
4689 return PTP_RC_OK;
4690 case LIBMTP_HANDLER_RETURN_ERROR:
4691 return PTP_ERROR_IO;
4692 case LIBMTP_HANDLER_RETURN_CANCEL:
4693 return PTP_ERROR_CANCEL;
4694 default:
4695 return PTP_ERROR_IO;
4696 }
4697 }
4698
4699 /**
4700 * This gets a file off the device to a local file identified
4701 * by a filename.
4702 * @param device a pointer to the device to get the track from.
4703 * @param id the file ID of the file to retrieve.
4704 * @param path a filename to use for the retrieved file.
4705 * @param callback a progress indicator function or NULL to ignore.
4706 * @param data a user-defined pointer that is passed along to
4707 * the <code>progress</code> function in order to
4708 * pass along some user defined data to the progress
4709 * updates. If not used, set this to NULL.
4710 * @return 0 if the transfer was successful, any other value means
4711 * failure.
4712 * @see LIBMTP_Get_File_To_File_Descriptor()
4713 */
LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t * device,uint32_t const id,char const * const path,LIBMTP_progressfunc_t const callback,void const * const data)4714 int LIBMTP_Get_File_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
4715 char const * const path, LIBMTP_progressfunc_t const callback,
4716 void const * const data)
4717 {
4718 int fd = -1;
4719 struct utimbuf mtime;
4720 int ret;
4721
4722 // Sanity check
4723 if (path == NULL) {
4724 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Bad arguments, path was NULL.");
4725 return -1;
4726 }
4727
4728 // Open file
4729 #ifdef __WIN32__
4730 #ifdef USE_WINDOWS_IO_H
4731 if ( (fd = _open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,_S_IREAD)) == -1 ) {
4732 #else
4733 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
4734 #endif
4735 #else
4736 if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
4737 #endif
4738 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
4739 return -1;
4740 }
4741
4742 ret = LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data, &mtime);
4743
4744 // Close file
4745 close(fd);
4746
4747 // Delete partial file.
4748 if (ret == -1) {
4749 unlink(path);
4750 } else {
4751 utime(path, &mtime);
4752 }
4753 return ret;
4754 }
4755
4756 /**
4757 * This gets a file off the device to a file identified
4758 * by a file descriptor.
4759 *
4760 * This function can potentially be used for streaming
4761 * files off the device for playback or broadcast for example,
4762 * by downloading the file into a stream sink e.g. a socket.
4763 *
4764 * @param device a pointer to the device to get the file from.
4765 * @param id the file ID of the file to retrieve.
4766 * @param fd a local file descriptor to write the file to.
4767 * @param callback a progress indicator function or NULL to ignore.
4768 * @param data a user-defined pointer that is passed along to
4769 * the <code>progress</code> function in order to
4770 * pass along some user defined data to the progress
4771 * updates. If not used, set this to NULL.
4772 * @param mtime out parameter to return the timestamp for file on
4773 * the device.
4774 * @return 0 if the transfer was successful, any other value means
4775 * failure.
4776 * @see LIBMTP_Get_File_To_File()
4777 */
4778 int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
4779 uint32_t const id,
4780 int const fd,
4781 LIBMTP_progressfunc_t const callback,
4782 void const * const data,
4783 struct utimbuf * mtime)
4784 {
4785 uint16_t ret;
4786 PTPParams *params = (PTPParams *) device->params;
4787 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4788 PTPObject *ob;
4789
4790 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
4791 if (ret != PTP_RC_OK) {
4792 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
4793 return -1;
4794 }
4795 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4796 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
4797 return -1;
4798 }
4799
4800 if (mtime != NULL) {
4801 mtime->actime = ob->oi.CaptureDate;
4802 mtime->modtime = ob->oi.ModificationDate;
4803 }
4804
4805 // Callbacks
4806 ptp_usb->callback_active = 1;
4807 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
4808 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
4809 ptp_usb->current_transfer_complete = 0;
4810 ptp_usb->current_transfer_callback = callback;
4811 ptp_usb->current_transfer_callback_data = data;
4812
4813 ret = ptp_getobject_tofd(params, id, fd);
4814
4815 ptp_usb->callback_active = 0;
4816 ptp_usb->current_transfer_callback = NULL;
4817 ptp_usb->current_transfer_callback_data = NULL;
4818
4819 if (ret == PTP_ERROR_CANCEL) {
4820 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
4821 return -1;
4822 }
4823 if (ret != PTP_RC_OK) {
4824 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
4825 return -1;
4826 }
4827
4828 return 0;
4829 }
4830
4831 /**
4832 * This gets a file off the device and calls put_func
4833 * with chunks of data
4834 *
4835 * @param device a pointer to the device to get the file from.
4836 * @param id the file ID of the file to retrieve.
4837 * @param put_func the function to call when we have data.
4838 * @param priv the user-defined pointer that is passed to
4839 * <code>put_func</code>.
4840 * @param callback a progress indicator function or NULL to ignore.
4841 * @param data a user-defined pointer that is passed along to
4842 * the <code>progress</code> function in order to
4843 * pass along some user defined data to the progress
4844 * updates. If not used, set this to NULL.
4845 * @return 0 if the transfer was successful, any other value means
4846 * failure.
4847 */
4848 int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
4849 uint32_t const id,
4850 MTPDataPutFunc put_func,
4851 void * priv,
4852 LIBMTP_progressfunc_t const callback,
4853 void const * const data)
4854 {
4855 PTPObject *ob;
4856 uint16_t ret;
4857 PTPParams *params = (PTPParams *) device->params;
4858 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4859
4860 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
4861 if (ret != PTP_RC_OK) {
4862 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
4863 return -1;
4864 }
4865 if (ob->oi.ObjectFormat == PTP_OFC_Association) {
4866 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
4867 return -1;
4868 }
4869
4870 // Callbacks
4871 ptp_usb->callback_active = 1;
4872 ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
4873 PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
4874 ptp_usb->current_transfer_complete = 0;
4875 ptp_usb->current_transfer_callback = callback;
4876 ptp_usb->current_transfer_callback_data = data;
4877
4878 MTPDataHandler mtp_handler;
4879 mtp_handler.getfunc = NULL;
4880 mtp_handler.putfunc = put_func;
4881 mtp_handler.priv = priv;
4882
4883 PTPDataHandler handler;
4884 handler.getfunc = NULL;
4885 handler.putfunc = put_func_wrapper;
4886 handler.priv = &mtp_handler;
4887
4888 ret = ptp_getobject_to_handler(params, id, &handler);
4889
4890 ptp_usb->callback_active = 0;
4891 ptp_usb->current_transfer_callback = NULL;
4892 ptp_usb->current_transfer_callback_data = NULL;
4893
4894 if (ret == PTP_ERROR_CANCEL) {
4895 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
4896 return -1;
4897 }
4898 if (ret != PTP_RC_OK) {
4899 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
4900 return -1;
4901 }
4902
4903 return 0;
4904 }
4905
4906
4907 /**
4908 * This gets a track off the device to a file identified
4909 * by a filename. This is actually just a wrapper for the
4910 * \c LIBMTP_Get_Track_To_File() function.
4911 * @param device a pointer to the device to get the track from.
4912 * @param id the track ID of the track to retrieve.
4913 * @param path a filename to use for the retrieved track.
4914 * @param callback a progress indicator function or NULL to ignore.
4915 * @param data a user-defined pointer that is passed along to
4916 * the <code>progress</code> function in order to
4917 * pass along some user defined data to the progress
4918 * updates. If not used, set this to NULL.
4919 * @return 0 if the transfer was successful, any other value means
4920 * failure.
4921 * @see LIBMTP_Get_Track_To_File_Descriptor()
4922 */
4923 int LIBMTP_Get_Track_To_File(LIBMTP_mtpdevice_t *device, uint32_t const id,
4924 char const * const path, LIBMTP_progressfunc_t const callback,
4925 void const * const data)
4926 {
4927 // This is just a wrapper
4928 return LIBMTP_Get_File_To_File(device, id, path, callback, data);
4929 }
4930
4931 /**
4932 * This gets a track off the device to a file identified
4933 * by a file descriptor. This is actually just a wrapper for
4934 * the \c LIBMTP_Get_File_To_File_Descriptor() function.
4935 * @param device a pointer to the device to get the track from.
4936 * @param id the track ID of the track to retrieve.
4937 * @param fd a file descriptor to write the track to.
4938 * @param callback a progress indicator function or NULL to ignore.
4939 * @param data a user-defined pointer that is passed along to
4940 * the <code>progress</code> function in order to
4941 * pass along some user defined data to the progress
4942 * updates. If not used, set this to NULL.
4943 * @param mtime out parameter to return the timestamp for file on
4944 * the device.
4945 * @return 0 if the transfer was successful, any other value means
4946 * failure.
4947 * @see LIBMTP_Get_Track_To_File()
4948 */
4949 int LIBMTP_Get_Track_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
4950 uint32_t const id,
4951 int const fd,
4952 LIBMTP_progressfunc_t const callback,
4953 void const * const data,
4954 struct utimbuf * mtime)
4955 {
4956 // This is just a wrapper
4957 return LIBMTP_Get_File_To_File_Descriptor(device, id, fd, callback, data, mtime);
4958 }
4959
4960 /**
4961 * This gets a track off the device to a handler function.
4962 * This is actually just a wrapper for
4963 * the \c LIBMTP_Get_File_To_Handler() function.
4964 * @param device a pointer to the device to get the track from.
4965 * @param id the track ID of the track to retrieve.
4966 * @param put_func the function to call when we have data.
4967 * @param priv the user-defined pointer that is passed to
4968 * <code>put_func</code>.
4969 * @param callback a progress indicator function or NULL to ignore.
4970 * @param data a user-defined pointer that is passed along to
4971 * the <code>progress</code> function in order to
4972 * pass along some user defined data to the progress
4973 * updates. If not used, set this to NULL.
4974 * @return 0 if the transfer was successful, any other value means
4975 * failure.
4976 */
4977 int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
4978 uint32_t const id,
4979 MTPDataPutFunc put_func,
4980 void * priv,
4981 LIBMTP_progressfunc_t const callback,
4982 void const * const data)
4983 {
4984 // This is just a wrapper
4985 return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
4986 }
4987
4988 /**
4989 * This function sends a track from a local file to an
4990 * MTP device. A filename and a set of metadata must be
4991 * given as input.
4992 * @param device a pointer to the device to send the track to.
4993 * @param path the filename of a local file which will be sent.
4994 * @param metadata a track metadata set to be written along with the file.
4995 * After this call the field <code>metadata->item_id</code>
4996 * will contain the new track ID. Other fields such
4997 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
4998 * or <code>metadata->storage_id</code> may also change during this
4999 * operation due to device restrictions, so do not rely on the
5000 * contents of this struct to be preserved in any way.
5001 * <ul>
5002 * <li><code>metadata->parent_id</code> should be set to the parent
5003 * (e.g. folder) to store this track in. Since some
5004 * devices are a bit picky about where files
5005 * are placed, a default folder will be chosen if libmtp
5006 * has detected one for the current filetype and this
5007 * parameter is set to 0. If this is 0 and no default folder
5008 * can be found, the file will be stored in the root folder.
5009 * <li><code>metadata->storage_id</code> should be set to the
5010 * desired storage (e.g. memory card or whatever your device
5011 * presents) to store this track in. Setting this to 0 will store
5012 * the track on the primary storage.
5013 * </ul>
5014 * @param callback a progress indicator function or NULL to ignore.
5015 * @param data a user-defined pointer that is passed along to
5016 * the <code>progress</code> function in order to
5017 * pass along some user defined data to the progress
5018 * updates. If not used, set this to NULL.
5019 * @return 0 if the transfer was successful, any other value means
5020 * failure.
5021 * @see LIBMTP_Send_Track_From_File_Descriptor()
5022 * @see LIBMTP_Send_File_From_File()
5023 * @see LIBMTP_Delete_Object()
5024 */
5025 int LIBMTP_Send_Track_From_File(LIBMTP_mtpdevice_t *device,
5026 char const * const path, LIBMTP_track_t * const metadata,
5027 LIBMTP_progressfunc_t const callback,
5028 void const * const data)
5029 {
5030 int fd;
5031 int ret;
5032
5033 // Sanity check
5034 if (path == NULL) {
5035 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Track_From_File(): Bad arguments, path was NULL.");
5036 return -1;
5037 }
5038
5039 // Open file
5040 #ifdef __WIN32__
5041 #ifdef USE_WINDOWS_IO_H
5042 if ( (fd = _open(path, O_RDONLY|O_BINARY) == -1) ) {
5043 #else
5044 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
5045 #endif
5046 #else
5047 if ( (fd = open(path, O_RDONLY)) == -1) {
5048 #endif
5049 printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
5050 return -1;
5051 }
5052
5053 ret = LIBMTP_Send_Track_From_File_Descriptor(device, fd, metadata, callback, data);
5054
5055 // Close file.
5056 #ifdef USE_WINDOWS_IO_H
5057 _close(fd);
5058 #else
5059 close(fd);
5060 #endif
5061
5062 return ret;
5063 }
5064
5065 /**
5066 * This function sends a track from a file descriptor to an
5067 * MTP device. A filename and a set of metadata must be
5068 * given as input.
5069 * @param device a pointer to the device to send the track to.
5070 * @param fd the filedescriptor for a local file which will be sent.
5071 * @param metadata a track metadata set to be written along with the file.
5072 * After this call the field <code>metadata->item_id</code>
5073 * will contain the new track ID. Other fields such
5074 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5075 * or <code>metadata->storage_id</code> may also change during this
5076 * operation due to device restrictions, so do not rely on the
5077 * contents of this struct to be preserved in any way.
5078 * <ul>
5079 * <li><code>metadata->parent_id</code> should be set to the parent
5080 * (e.g. folder) to store this track in. Since some
5081 * devices are a bit picky about where files
5082 * are placed, a default folder will be chosen if libmtp
5083 * has detected one for the current filetype and this
5084 * parameter is set to 0. If this is 0 and no default folder
5085 * can be found, the file will be stored in the root folder.
5086 * <li><code>metadata->storage_id</code> should be set to the
5087 * desired storage (e.g. memory card or whatever your device
5088 * presents) to store this track in. Setting this to 0 will store
5089 * the track on the primary storage.
5090 * </ul>
5091 * @param callback a progress indicator function or NULL to ignore.
5092 * @param data a user-defined pointer that is passed along to
5093 * the <code>progress</code> function in order to
5094 * pass along some user defined data to the progress
5095 * updates. If not used, set this to NULL.
5096 * @return 0 if the transfer was successful, any other value means
5097 * failure.
5098 * @see LIBMTP_Send_Track_From_File()
5099 * @see LIBMTP_Delete_Object()
5100 */
5101 int LIBMTP_Send_Track_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5102 int const fd, LIBMTP_track_t * const metadata,
5103 LIBMTP_progressfunc_t const callback,
5104 void const * const data)
5105 {
5106 int subcall_ret;
5107 LIBMTP_file_t filedata;
5108
5109 // Sanity check, is this really a track?
5110 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5111 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5112 "LIBMTP_Send_Track_From_File_Descriptor(): "
5113 "I don't think this is actually a track, strange filetype...");
5114 }
5115
5116 // Wrap around the file transfer function
5117 filedata.item_id = metadata->item_id;
5118 filedata.parent_id = metadata->parent_id;
5119 filedata.storage_id = metadata->storage_id;
5120 filedata.filename = metadata->filename;
5121 filedata.filesize = metadata->filesize;
5122 filedata.filetype = metadata->filetype;
5123 filedata.next = NULL;
5124
5125 subcall_ret = LIBMTP_Send_File_From_File_Descriptor(device,
5126 fd,
5127 &filedata,
5128 callback,
5129 data);
5130
5131 if (subcall_ret != 0) {
5132 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5133 "LIBMTP_Send_Track_From_File_Descriptor(): "
5134 "subcall to LIBMTP_Send_File_From_File_Descriptor failed.");
5135 // We used to delete the file here, but don't... It might be OK after all.
5136 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5137 return -1;
5138 }
5139
5140 // Pick up new item (and parent, storage) ID
5141 metadata->item_id = filedata.item_id;
5142 metadata->parent_id = filedata.parent_id;
5143 metadata->storage_id = filedata.storage_id;
5144
5145 // Set track metadata for the new fine track
5146 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5147 if (subcall_ret != 0) {
5148 // Subcall will add error to errorstack
5149 // We used to delete the file here, but don't... It might be OK after all.
5150 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5151 return -1;
5152 }
5153
5154 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5155 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5156
5157 return 0;
5158 }
5159
5160 /**
5161 * This function sends a track from a handler function to an
5162 * MTP device. A filename and a set of metadata must be
5163 * given as input.
5164 * @param device a pointer to the device to send the track to.
5165 * @param get_func the function to call when we have data.
5166 * @param priv the user-defined pointer that is passed to
5167 * <code>get_func</code>.
5168 * @param metadata a track metadata set to be written along with the file.
5169 * After this call the field <code>metadata->item_id</code>
5170 * will contain the new track ID. Other fields such
5171 * as the <code>metadata->filename</code>, <code>metadata->parent_id</code>
5172 * or <code>metadata->storage_id</code> may also change during this
5173 * operation due to device restrictions, so do not rely on the
5174 * contents of this struct to be preserved in any way.
5175 * <ul>
5176 * <li><code>metadata->parent_id</code> should be set to the parent
5177 * (e.g. folder) to store this track in. Since some
5178 * devices are a bit picky about where files
5179 * are placed, a default folder will be chosen if libmtp
5180 * has detected one for the current filetype and this
5181 * parameter is set to 0. If this is 0 and no default folder
5182 * can be found, the file will be stored in the root folder.
5183 * <li><code>metadata->storage_id</code> should be set to the
5184 * desired storage (e.g. memory card or whatever your device
5185 * presents) to store this track in. Setting this to 0 will store
5186 * the track on the primary storage.
5187 * </ul>
5188 * @param callback a progress indicator function or NULL to ignore.
5189 * @param data a user-defined pointer that is passed along to
5190 * the <code>progress</code> function in order to
5191 * pass along some user defined data to the progress
5192 * updates. If not used, set this to NULL.
5193 * @return 0 if the transfer was successful, any other value means
5194 * failure.
5195 * @see LIBMTP_Send_Track_From_File()
5196 * @see LIBMTP_Delete_Object()
5197 */
5198 int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
5199 MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
5200 LIBMTP_progressfunc_t const callback,
5201 void const * const data)
5202 {
5203 int subcall_ret;
5204 LIBMTP_file_t filedata;
5205
5206 // Sanity check, is this really a track?
5207 if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
5208 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5209 "LIBMTP_Send_Track_From_Handler(): "
5210 "I don't think this is actually a track, strange filetype...");
5211 }
5212
5213 // Wrap around the file transfer function
5214 filedata.item_id = metadata->item_id;
5215 filedata.parent_id = metadata->parent_id;
5216 filedata.storage_id = metadata->storage_id;
5217 filedata.filename = metadata->filename;
5218 filedata.filesize = metadata->filesize;
5219 filedata.filetype = metadata->filetype;
5220 filedata.next = NULL;
5221
5222 subcall_ret = LIBMTP_Send_File_From_Handler(device,
5223 get_func,
5224 priv,
5225 &filedata,
5226 callback,
5227 data);
5228
5229 if (subcall_ret != 0) {
5230 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5231 "LIBMTP_Send_Track_From_Handler(): "
5232 "subcall to LIBMTP_Send_File_From_Handler failed.");
5233 // We used to delete the file here, but don't... It might be OK after all.
5234 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5235 return -1;
5236 }
5237
5238 // Pick up new item (and parent, storage) ID
5239 metadata->item_id = filedata.item_id;
5240 metadata->parent_id = filedata.parent_id;
5241 metadata->storage_id = filedata.storage_id;
5242
5243 // Set track metadata for the new fine track
5244 subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
5245 if (subcall_ret != 0) {
5246 // Subcall will add error to errorstack
5247 // We used to delete the file here, but don't... It might be OK after all.
5248 // (void) LIBMTP_Delete_Object(device, metadata->item_id);
5249 return -1;
5250 }
5251
5252 // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
5253 // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
5254
5255 return 0;
5256 }
5257
5258 /**
5259 * This function sends a local file to an MTP device.
5260 * A filename and a set of metadata must be
5261 * given as input.
5262 * @param device a pointer to the device to send the track to.
5263 * @param path the filename of a local file which will be sent.
5264 * @param filedata a file metadata set to be written along with the file.
5265 * After this call the field <code>filedata->item_id</code>
5266 * will contain the new file ID. Other fields such
5267 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5268 * or <code>filedata->storage_id</code> may also change during this
5269 * operation due to device restrictions, so do not rely on the
5270 * contents of this struct to be preserved in any way.
5271 * <ul>
5272 * <li><code>filedata->parent_id</code> should be set to the parent
5273 * (e.g. folder) to store this file in. If this is 0,
5274 * the file will be stored in the root folder.
5275 * <li><code>filedata->storage_id</code> should be set to the
5276 * desired storage (e.g. memory card or whatever your device
5277 * presents) to store this file in. Setting this to 0 will store
5278 * the file on the primary storage.
5279 * </ul>
5280 * @param callback a progress indicator function or NULL to ignore.
5281 * @param data a user-defined pointer that is passed along to
5282 * the <code>progress</code> function in order to
5283 * pass along some user defined data to the progress
5284 * updates. If not used, set this to NULL.
5285 * @return 0 if the transfer was successful, any other value means
5286 * failure.
5287 * @see LIBMTP_Send_File_From_File_Descriptor()
5288 * @see LIBMTP_Delete_Object()
5289 */
5290 int LIBMTP_Send_File_From_File(LIBMTP_mtpdevice_t *device,
5291 char const * const path, LIBMTP_file_t * const filedata,
5292 LIBMTP_progressfunc_t const callback,
5293 void const * const data)
5294 {
5295 int fd;
5296 int ret;
5297
5298 // Sanity check
5299 if (path == NULL) {
5300 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Bad arguments, path was NULL.");
5301 return -1;
5302 }
5303
5304 // Open file
5305 #ifdef __WIN32__
5306 #ifdef USE_WINDOWS_IO_H
5307 if ( (fd = _open(path, O_RDONLY|O_BINARY) == -1) ) {
5308 #else
5309 if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
5310 #endif
5311 #else
5312 if ( (fd = open(path, O_RDONLY)) == -1) {
5313 #endif
5314 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
5315 return -1;
5316 }
5317
5318 ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, filedata, callback, data);
5319
5320 // Close file.
5321 #ifdef USE_WINDOWS_IO_H
5322 _close(fd);
5323 #else
5324 close(fd);
5325 #endif
5326
5327 return ret;
5328 }
5329
5330 /**
5331 * This function sends a generic file from a file descriptor to an
5332 * MTP device. A filename and a set of metadata must be
5333 * given as input.
5334 *
5335 * This can potentially be used for sending in a stream of unknown
5336 * length. Send music files with
5337 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
5338 *
5339 * @param device a pointer to the device to send the file to.
5340 * @param fd the filedescriptor for a local file which will be sent.
5341 * @param filedata a file metadata set to be written along with the file.
5342 * After this call the field <code>filedata->item_id</code>
5343 * will contain the new file ID. Other fields such
5344 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5345 * or <code>filedata->storage_id</code> may also change during this
5346 * operation due to device restrictions, so do not rely on the
5347 * contents of this struct to be preserved in any way.
5348 * <ul>
5349 * <li><code>filedata->parent_id</code> should be set to the parent
5350 * (e.g. folder) to store this file in. If this is 0,
5351 * the file will be stored in the root folder.
5352 * <li><code>filedata->storage_id</code> should be set to the
5353 * desired storage (e.g. memory card or whatever your device
5354 * presents) to store this file in. Setting this to 0 will store
5355 * the file on the primary storage.
5356 * </ul>
5357 * @param callback a progress indicator function or NULL to ignore.
5358 * @param data a user-defined pointer that is passed along to
5359 * the <code>progress</code> function in order to
5360 * pass along some user defined data to the progress
5361 * updates. If not used, set this to NULL.
5362 * @return 0 if the transfer was successful, any other value means
5363 * failure.
5364 * @see LIBMTP_Send_File_From_File()
5365 * @see LIBMTP_Send_Track_From_File_Descriptor()
5366 * @see LIBMTP_Delete_Object()
5367 */
5368 int LIBMTP_Send_File_From_File_Descriptor(LIBMTP_mtpdevice_t *device,
5369 int const fd, LIBMTP_file_t * const filedata,
5370 LIBMTP_progressfunc_t const callback,
5371 void const * const data)
5372 {
5373 uint16_t ret;
5374 PTPParams *params = (PTPParams *) device->params;
5375 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5376 LIBMTP_file_t *newfilemeta;
5377
5378 if (send_file_object_info(device, filedata))
5379 {
5380 // no need to output an error since send_file_object_info will already have done so
5381 return -1;
5382 }
5383
5384 // Callbacks
5385 ptp_usb->callback_active = 1;
5386 // The callback will deactivate itself after this amount of data has been sent
5387 // One BULK header for the request, one for the data phase. No parameters to the request.
5388 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5389 ptp_usb->current_transfer_complete = 0;
5390 ptp_usb->current_transfer_callback = callback;
5391 ptp_usb->current_transfer_callback_data = data;
5392
5393 ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
5394
5395 ptp_usb->callback_active = 0;
5396 ptp_usb->current_transfer_callback = NULL;
5397 ptp_usb->current_transfer_callback_data = NULL;
5398
5399 if (ret == PTP_ERROR_CANCEL) {
5400 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
5401 return -1;
5402 }
5403 if (ret != PTP_RC_OK) {
5404 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
5405 "Could not send object.");
5406 return -1;
5407 }
5408
5409 add_object_to_cache(device, filedata->item_id);
5410
5411 /*
5412 * Get the device-assined parent_id from the cache.
5413 * The operation that adds it to the cache will
5414 * look it up from the device, so we get the new
5415 * parent_id from the cache.
5416 */
5417 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5418 if (newfilemeta != NULL) {
5419 filedata->parent_id = newfilemeta->parent_id;
5420 filedata->storage_id = newfilemeta->storage_id;
5421 LIBMTP_destroy_file_t(newfilemeta);
5422 } else {
5423 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5424 "LIBMTP_Send_File_From_File_Descriptor(): "
5425 "Could not retrieve updated metadata.");
5426 return -1;
5427 }
5428
5429 return 0;
5430 }
5431
5432 /**
5433 * This function sends a generic file from a handler function to an
5434 * MTP device. A filename and a set of metadata must be
5435 * given as input.
5436 *
5437 * This can potentially be used for sending in a stream of unknown
5438 * length. Send music files with
5439 * <code>LIBMTP_Send_Track_From_Handler()</code>
5440 *
5441 * @param device a pointer to the device to send the file to.
5442 * @param get_func the function to call to get data to write
5443 * @param priv a user-defined pointer that is passed along to
5444 * <code>get_func</code>. If not used, this is set to NULL.
5445 * @param filedata a file metadata set to be written along with the file.
5446 * After this call the field <code>filedata->item_id</code>
5447 * will contain the new file ID. Other fields such
5448 * as the <code>filedata->filename</code>, <code>filedata->parent_id</code>
5449 * or <code>filedata->storage_id</code> may also change during this
5450 * operation due to device restrictions, so do not rely on the
5451 * contents of this struct to be preserved in any way.
5452 * <ul>
5453 * <li><code>filedata->parent_id</code> should be set to the parent
5454 * (e.g. folder) to store this file in. If this is 0,
5455 * the file will be stored in the root folder.
5456 * <li><code>filedata->storage_id</code> should be set to the
5457 * desired storage (e.g. memory card or whatever your device
5458 * presents) to store this file in. Setting this to 0 will store
5459 * the file on the primary storage.
5460 * </ul>
5461 * @param callback a progress indicator function or NULL to ignore.
5462 * @param data a user-defined pointer that is passed along to
5463 * the <code>progress</code> function in order to
5464 * pass along some user defined data to the progress
5465 * updates. If not used, set this to NULL.
5466 * @return 0 if the transfer was successful, any other value means
5467 * failure.
5468 * @see LIBMTP_Send_File_From_File()
5469 * @see LIBMTP_Send_Track_From_File_Descriptor()
5470 * @see LIBMTP_Delete_Object()
5471 */
5472 int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
5473 MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
5474 LIBMTP_progressfunc_t const callback, void const * const data)
5475 {
5476 uint16_t ret;
5477 PTPParams *params = (PTPParams *) device->params;
5478 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5479 LIBMTP_file_t *newfilemeta;
5480
5481 if (send_file_object_info(device, filedata))
5482 {
5483 // no need to output an error since send_file_object_info will already have done so
5484 return -1;
5485 }
5486
5487 // Callbacks
5488 ptp_usb->callback_active = 1;
5489 // The callback will deactivate itself after this amount of data has been sent
5490 // One BULK header for the request, one for the data phase. No parameters to the request.
5491 ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
5492 ptp_usb->current_transfer_complete = 0;
5493 ptp_usb->current_transfer_callback = callback;
5494 ptp_usb->current_transfer_callback_data = data;
5495
5496 MTPDataHandler mtp_handler;
5497 mtp_handler.getfunc = get_func;
5498 mtp_handler.putfunc = NULL;
5499 mtp_handler.priv = priv;
5500
5501 PTPDataHandler handler;
5502 handler.getfunc = get_func_wrapper;
5503 handler.putfunc = NULL;
5504 handler.priv = &mtp_handler;
5505
5506 ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
5507
5508 ptp_usb->callback_active = 0;
5509 ptp_usb->current_transfer_callback = NULL;
5510 ptp_usb->current_transfer_callback_data = NULL;
5511
5512 if (ret == PTP_ERROR_CANCEL) {
5513 add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
5514 return -1;
5515 }
5516 if (ret != PTP_RC_OK) {
5517 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
5518 "Could not send object.");
5519 return -1;
5520 }
5521
5522 add_object_to_cache(device, filedata->item_id);
5523
5524 /*
5525 * Get the device-assined parent_id from the cache.
5526 * The operation that adds it to the cache will
5527 * look it up from the device, so we get the new
5528 * parent_id from the cache.
5529 */
5530 newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
5531 if (newfilemeta != NULL) {
5532 filedata->parent_id = newfilemeta->parent_id;
5533 filedata->storage_id = newfilemeta->storage_id;
5534 LIBMTP_destroy_file_t(newfilemeta);
5535 } else {
5536 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
5537 "LIBMTP_Send_File_From_Handler(): "
5538 "Could not retrieve updated metadata.");
5539 return -1;
5540 }
5541
5542 return 0;
5543 }
5544
5545 /**
5546 * This function sends the file object info, ready for sendobject
5547 * @param device a pointer to the device to send the file to.
5548 * @param filedata a file metadata set to be written along with the file.
5549 * @return 0 if the transfer was successful, any other value means
5550 * failure.
5551 */
5552 static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
5553 {
5554 PTPParams *params = (PTPParams *) device->params;
5555 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5556 uint32_t store;
5557
5558 #ifdef _AFT_BUILD
5559 int use_primary_storage = 0;
5560 #else
5561 int use_primary_storage = 1;
5562 #endif
5563
5564 uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
5565 LIBMTP_devicestorage_t *storage;
5566 uint32_t localph = filedata->parent_id;
5567 uint16_t ret;
5568 int i;
5569
5570 if (filedata->storage_id != 0) {
5571 store = filedata->storage_id;
5572 } else {
5573 store = get_writeable_storageid(device, filedata->filesize);
5574 }
5575 // Detect if something non-primary is in use.
5576 storage = device->storage;
5577 if (storage != NULL && store != storage->id) {
5578 use_primary_storage = 0;
5579 }
5580
5581 /*
5582 * If no destination folder was given, look up a default
5583 * folder if possible. Perhaps there is some way of retrieveing
5584 * the default folder for different forms of content, what
5585 * do I know, we use a fixed list in lack of any better method.
5586 * Some devices obviously need to have their files in certain
5587 * folders in order to find/display them at all (hello Creative),
5588 * so we have to have a method for this. We only do this if the
5589 * primary storage is in use.
5590 */
5591
5592 if (localph == 0 && use_primary_storage) {
5593 if (LIBMTP_FILETYPE_IS_AUDIO(filedata->filetype)) {
5594 localph = device->default_music_folder;
5595 } else if (LIBMTP_FILETYPE_IS_VIDEO(filedata->filetype)) {
5596 localph = device->default_video_folder;
5597 } else if (of == PTP_OFC_EXIF_JPEG ||
5598 of == PTP_OFC_JP2 ||
5599 of == PTP_OFC_JPX ||
5600 of == PTP_OFC_JFIF ||
5601 of == PTP_OFC_TIFF ||
5602 of == PTP_OFC_TIFF_IT ||
5603 of == PTP_OFC_BMP ||
5604 of == PTP_OFC_GIF ||
5605 of == PTP_OFC_PICT ||
5606 of == PTP_OFC_PNG ||
5607 of == PTP_OFC_MTP_WindowsImageFormat) {
5608 localph = device->default_picture_folder;
5609 } else if (of == PTP_OFC_MTP_vCalendar1 ||
5610 of == PTP_OFC_MTP_vCalendar2 ||
5611 of == PTP_OFC_MTP_UndefinedContact ||
5612 of == PTP_OFC_MTP_vCard2 ||
5613 of == PTP_OFC_MTP_vCard3 ||
5614 of == PTP_OFC_MTP_UndefinedCalendarItem) {
5615 localph = device->default_organizer_folder;
5616 } else if (of == PTP_OFC_Text) {
5617 localph = device->default_text_folder;
5618 }
5619 }
5620
5621 // default parent handle
5622 if (localph == 0) {
5623 localph = 0xFFFFFFFFU; // Set to -1
5624 }
5625
5626 // Here we wire the type to unknown on bugged, but
5627 // Ogg or FLAC-supportive devices.
5628 if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
5629 of = PTP_OFC_Undefined;
5630 }
5631 if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
5632 of = PTP_OFC_Undefined;
5633 }
5634
5635 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
5636 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
5637 /*
5638 * MTP enhanched does it this way (from a sniff):
5639 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
5640 * 20 00 00 00 01 00 08 98 1B 00 00 00 01 00 01 00
5641 * FF FF FF FF 00 30 00 00 00 00 00 00 12 5E 00 00
5642 * Length: 0x00000020
5643 * Type: 0x0001 PTP_USB_CONTAINER_COMMAND
5644 * Code: 0x9808
5645 * Transaction ID: 0x0000001B
5646 * Param1: 0x00010001 <- store
5647 * Param2: 0xffffffff <- parent handle (-1 ?)
5648 * Param3: 0x00003000 <- file type PTP_OFC_Undefined - we don't know about PDF files
5649 * Param4: 0x00000000 <- file length MSB (-0x0c header len)
5650 * Param5: 0x00005e12 <- file length LSB (-0x0c header len)
5651 *
5652 * -> PTP_OC_MTP_SendObjectPropList (0x9808):
5653 * 46 00 00 00 02 00 08 98 1B 00 00 00 03 00 00 00
5654 * 00 00 00 00 07 DC FF FF 0D 4B 00 53 00 30 00 36 - dc07 = file name
5655 * 00 30 00 33 00 30 00 36 00 2E 00 70 00 64 00 66
5656 * 00 00 00 00 00 00 00 03 DC 04 00 00 00 00 00 00 - dc03 = protection status
5657 * 00 4F DC 02 00 01 - dc4f = non consumable
5658 * Length: 0x00000046
5659 * Type: 0x0002 PTP_USB_CONTAINER_DATA
5660 * Code: 0x9808
5661 * Transaction ID: 0x0000001B
5662 * Metadata....
5663 * 0x00000003 <- Number of metadata items
5664 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
5665 * 0xdc07 <- metadata type: file name
5666 * 0xffff <- metadata type: string
5667 * 0x0d <- number of (uint16_t) characters
5668 * 4b 53 30 36 30 33 30 36 2e 50 64 66 00 "KS060306.pdf", null terminated
5669 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
5670 * 0xdc03 <- metadata type: protection status
5671 * 0x0004 <- metadata type: uint16_t
5672 * 0x0000 <- not protected
5673 * 0x00000000 <- Object handle, set to 0x00000000 since it is unknown!
5674 * 0xdc4f <- non consumable
5675 * 0x0002 <- metadata type: uint8_t
5676 * 0x01 <- non-consumable (this device cannot display PDF)
5677 *
5678 * <- Read 0x18 bytes back
5679 * 18 00 00 00 03 00 01 20 1B 00 00 00 01 00 01 00
5680 * 00 00 00 00 01 40 00 00
5681 * Length: 0x000000018
5682 * Type: 0x0003 PTP_USB_CONTAINER_RESPONSE
5683 * Code: 0x2001 PTP_OK
5684 * Transaction ID: 0x0000001B
5685 * Param1: 0x00010001 <- store
5686 * Param2: 0x00000000 <- parent handle
5687 * Param3: 0x00004001 <- new file/object ID
5688 *
5689 * -> PTP_OC_SendObject (0x100d)
5690 * 0C 00 00 00 01 00 0D 10 1C 00 00 00
5691 * -> ... all the bytes ...
5692 * <- Read 0x0c bytes back
5693 * 0C 00 00 00 03 00 01 20 1C 00 00 00
5694 * ... Then update metadata one-by one, actually (instead of sending it first!) ...
5695 */
5696 MTPProperties *props = NULL;
5697 int nrofprops = 0;
5698 MTPProperties *prop = NULL;
5699 uint16_t *properties = NULL;
5700 uint32_t propcnt = 0;
5701
5702 // Must be 0x00000000U for new objects
5703 filedata->item_id = 0x00000000U;
5704
5705 ret = ptp_mtp_getobjectpropssupported(params, of, &propcnt, &properties);
5706
5707 for (i=0;i<propcnt;i++) {
5708 PTPObjectPropDesc opd;
5709
5710 ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
5711 if (ret != PTP_RC_OK) {
5712 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
5713 "could not get property description.");
5714 } else if (opd.GetSet) {
5715 switch (properties[i]) {
5716 case PTP_OPC_ObjectFileName:
5717 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5718 prop->ObjectHandle = filedata->item_id;
5719 prop->property = PTP_OPC_ObjectFileName;
5720 prop->datatype = PTP_DTC_STR;
5721 if (filedata->filename != NULL) {
5722 prop->propval.str = strdup(filedata->filename);
5723 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
5724 strip_7bit_from_utf8(prop->propval.str);
5725 }
5726 }
5727 break;
5728 case PTP_OPC_ProtectionStatus:
5729 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5730 prop->ObjectHandle = filedata->item_id;
5731 prop->property = PTP_OPC_ProtectionStatus;
5732 prop->datatype = PTP_DTC_UINT16;
5733 prop->propval.u16 = 0x0000U; /* Not protected */
5734 break;
5735 case PTP_OPC_NonConsumable:
5736 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5737 prop->ObjectHandle = filedata->item_id;
5738 prop->property = PTP_OPC_NonConsumable;
5739 prop->datatype = PTP_DTC_UINT8;
5740 prop->propval.u8 = 0x00; /* It is supported, then it is consumable */
5741 break;
5742 case PTP_OPC_Name:
5743 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5744 prop->ObjectHandle = filedata->item_id;
5745 prop->property = PTP_OPC_Name;
5746 prop->datatype = PTP_DTC_STR;
5747 if (filedata->filename != NULL)
5748 prop->propval.str = strdup(filedata->filename);
5749 break;
5750 case PTP_OPC_DateModified:
5751 // Tag with current time if that is supported
5752 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
5753 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5754 prop->ObjectHandle = filedata->item_id;
5755 prop->property = PTP_OPC_DateModified;
5756 prop->datatype = PTP_DTC_STR;
5757 prop->propval.str = get_iso8601_stamp();
5758 filedata->modificationdate = time(NULL);
5759 }
5760 break;
5761 }
5762 }
5763 ptp_free_objectpropdesc(&opd);
5764 }
5765 free(properties);
5766
5767 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &filedata->item_id,
5768 of, filedata->filesize, props, nrofprops);
5769
5770 /* Free property list */
5771 ptp_destroy_object_prop_list(props, nrofprops);
5772
5773 if (ret != PTP_RC_OK) {
5774 add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
5775 "Could not send object property list.");
5776 if (ret == PTP_RC_AccessDenied) {
5777 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
5778 }
5779 return -1;
5780 }
5781 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
5782 PTPObjectInfo new_file;
5783
5784 memset(&new_file, 0, sizeof(PTPObjectInfo));
5785
5786 new_file.Filename = filedata->filename;
5787 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
5788 strip_7bit_from_utf8(new_file.Filename);
5789 }
5790 // We lose precision here.
5791 new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
5792 new_file.ObjectFormat = of;
5793 new_file.StorageID = store;
5794 new_file.ParentObject = localph;
5795 new_file.ModificationDate = time(NULL);
5796 // Create the object
5797
5798 ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
5799
5800 if (ret != PTP_RC_OK) {
5801 add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
5802 "Could not send object info.");
5803 if (ret == PTP_RC_AccessDenied) {
5804 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
5805 }
5806 return -1;
5807 }
5808 // NOTE: the char* pointers inside new_file are not copies so don't
5809 // try to destroy this objectinfo!
5810 }
5811
5812 // Now there IS an object with this parent handle.
5813 filedata->parent_id = localph;
5814
5815 return 0;
5816 }
5817
5818 /**
5819 * This function updates the MTP track object metadata on a
5820 * single file identified by an object ID.
5821 * @param device a pointer to the device to update the track
5822 * metadata on.
5823 * @param metadata a track metadata set to be written to the file.
5824 * notice that the <code>track_id</code> field of the
5825 * metadata structure must be correct so that the
5826 * function can update the right file. If some properties
5827 * of this metadata are set to NULL (strings) or 0
5828 * (numerical values) they will be discarded and the
5829 * track will not be tagged with these blank values.
5830 * @return 0 on success, any other value means failure. If some
5831 * or all of the properties fail to update we will still
5832 * return success. On some devices (notably iRiver T30)
5833 * properties that exist cannot be updated.
5834 */
5835 int LIBMTP_Update_Track_Metadata(LIBMTP_mtpdevice_t *device,
5836 LIBMTP_track_t const * const metadata)
5837 {
5838 uint16_t ret;
5839 PTPParams *params = (PTPParams *) device->params;
5840 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5841 uint32_t i;
5842 uint16_t *properties = NULL;
5843 uint32_t propcnt = 0;
5844
5845 // First see which properties can be set on this file format and apply accordingly
5846 // i.e only try to update this metadata for object tags that exist on the current player.
5847 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(metadata->filetype), &propcnt, &properties);
5848 if (ret != PTP_RC_OK) {
5849 // Just bail out for now, nothing is ever set.
5850 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
5851 "could not retrieve supported object properties.");
5852 return -1;
5853 }
5854 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
5855 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
5856 MTPProperties *props = NULL;
5857 MTPProperties *prop = NULL;
5858 int nrofprops = 0;
5859
5860 for (i=0;i<propcnt;i++) {
5861 PTPObjectPropDesc opd;
5862
5863 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
5864 if (ret != PTP_RC_OK) {
5865 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
5866 "could not get property description.");
5867 } else if (opd.GetSet) {
5868 switch (properties[i]) {
5869 case PTP_OPC_Name:
5870 if (metadata->title == NULL)
5871 break;
5872 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5873 prop->ObjectHandle = metadata->item_id;
5874 prop->property = PTP_OPC_Name;
5875 prop->datatype = PTP_DTC_STR;
5876 prop->propval.str = strdup(metadata->title);
5877 break;
5878 case PTP_OPC_AlbumName:
5879 if (metadata->album == NULL)
5880 break;
5881 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5882 prop->ObjectHandle = metadata->item_id;
5883 prop->property = PTP_OPC_AlbumName;
5884 prop->datatype = PTP_DTC_STR;
5885 prop->propval.str = strdup(metadata->album);
5886 break;
5887 case PTP_OPC_Artist:
5888 if (metadata->artist == NULL)
5889 break;
5890 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5891 prop->ObjectHandle = metadata->item_id;
5892 prop->property = PTP_OPC_Artist;
5893 prop->datatype = PTP_DTC_STR;
5894 prop->propval.str = strdup(metadata->artist);
5895 break;
5896 case PTP_OPC_Composer:
5897 if (metadata->composer == NULL)
5898 break;
5899 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5900 prop->ObjectHandle = metadata->item_id;
5901 prop->property = PTP_OPC_Composer;
5902 prop->datatype = PTP_DTC_STR;
5903 prop->propval.str = strdup(metadata->composer);
5904 break;
5905 case PTP_OPC_Genre:
5906 if (metadata->genre == NULL)
5907 break;
5908 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5909 prop->ObjectHandle = metadata->item_id;
5910 prop->property = PTP_OPC_Genre;
5911 prop->datatype = PTP_DTC_STR;
5912 prop->propval.str = strdup(metadata->genre);
5913 break;
5914 case PTP_OPC_Duration:
5915 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5916 prop->ObjectHandle = metadata->item_id;
5917 prop->property = PTP_OPC_Duration;
5918 prop->datatype = PTP_DTC_UINT32;
5919 prop->propval.u32 = adjust_u32(metadata->duration, &opd);
5920 break;
5921 case PTP_OPC_Track:
5922 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5923 prop->ObjectHandle = metadata->item_id;
5924 prop->property = PTP_OPC_Track;
5925 prop->datatype = PTP_DTC_UINT16;
5926 prop->propval.u16 = adjust_u16(metadata->tracknumber, &opd);
5927 break;
5928 case PTP_OPC_OriginalReleaseDate:
5929 if (metadata->date == NULL)
5930 break;
5931 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5932 prop->ObjectHandle = metadata->item_id;
5933 prop->property = PTP_OPC_OriginalReleaseDate;
5934 prop->datatype = PTP_DTC_STR;
5935 prop->propval.str = strdup(metadata->date);
5936 break;
5937 case PTP_OPC_SampleRate:
5938 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5939 prop->ObjectHandle = metadata->item_id;
5940 prop->property = PTP_OPC_SampleRate;
5941 prop->datatype = PTP_DTC_UINT32;
5942 prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
5943 break;
5944 case PTP_OPC_NumberOfChannels:
5945 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5946 prop->ObjectHandle = metadata->item_id;
5947 prop->property = PTP_OPC_NumberOfChannels;
5948 prop->datatype = PTP_DTC_UINT16;
5949 prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
5950 break;
5951 case PTP_OPC_AudioWAVECodec:
5952 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5953 prop->ObjectHandle = metadata->item_id;
5954 prop->property = PTP_OPC_AudioWAVECodec;
5955 prop->datatype = PTP_DTC_UINT32;
5956 prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
5957 break;
5958 case PTP_OPC_AudioBitRate:
5959 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5960 prop->ObjectHandle = metadata->item_id;
5961 prop->property = PTP_OPC_AudioBitRate;
5962 prop->datatype = PTP_DTC_UINT32;
5963 prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
5964 break;
5965 case PTP_OPC_BitRateType:
5966 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5967 prop->ObjectHandle = metadata->item_id;
5968 prop->property = PTP_OPC_BitRateType;
5969 prop->datatype = PTP_DTC_UINT16;
5970 prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
5971 break;
5972 case PTP_OPC_Rating:
5973 // TODO: shall this be set for rating 0?
5974 if (metadata->rating == 0)
5975 break;
5976 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5977 prop->ObjectHandle = metadata->item_id;
5978 prop->property = PTP_OPC_Rating;
5979 prop->datatype = PTP_DTC_UINT16;
5980 prop->propval.u16 = adjust_u16(metadata->rating, &opd);
5981 break;
5982 case PTP_OPC_UseCount:
5983 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5984 prop->ObjectHandle = metadata->item_id;
5985 prop->property = PTP_OPC_UseCount;
5986 prop->datatype = PTP_DTC_UINT32;
5987 prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
5988 break;
5989 case PTP_OPC_DateModified:
5990 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
5991 // Tag with current time if that is supported
5992 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5993 prop->ObjectHandle = metadata->item_id;
5994 prop->property = PTP_OPC_DateModified;
5995 prop->datatype = PTP_DTC_STR;
5996 prop->propval.str = get_iso8601_stamp();
5997 }
5998 break;
5999 default:
6000 break;
6001 }
6002 }
6003 ptp_free_objectpropdesc(&opd);
6004 }
6005
6006 // NOTE: File size is not updated, this should not change anyway.
6007 // neither will we change the filename.
6008
6009 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6010
6011 ptp_destroy_object_prop_list(props, nrofprops);
6012
6013 if (ret != PTP_RC_OK) {
6014 // TODO: return error of which property we couldn't set
6015 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6016 "could not set object property list.");
6017 free(properties);
6018 return -1;
6019 }
6020
6021 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6022 for (i=0;i<propcnt;i++) {
6023 PTPObjectPropDesc opd;
6024
6025 ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
6026 if (ret != PTP_RC_OK) {
6027 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6028 "could not get property description.");
6029 } else if (opd.GetSet) {
6030 switch (properties[i]) {
6031 case PTP_OPC_Name:
6032 // Update title
6033 ret = set_object_string(device, metadata->item_id, PTP_OPC_Name, metadata->title);
6034 if (ret != 0) {
6035 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6036 "could not set track title.");
6037 }
6038 break;
6039 case PTP_OPC_AlbumName:
6040 // Update album
6041 ret = set_object_string(device, metadata->item_id, PTP_OPC_AlbumName, metadata->album);
6042 if (ret != 0) {
6043 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6044 "could not set track album name.");
6045 }
6046 break;
6047 case PTP_OPC_Artist:
6048 // Update artist
6049 ret = set_object_string(device, metadata->item_id, PTP_OPC_Artist, metadata->artist);
6050 if (ret != 0) {
6051 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6052 "could not set track artist name.");
6053 }
6054 break;
6055 case PTP_OPC_Composer:
6056 // Update composer
6057 ret = set_object_string(device, metadata->item_id, PTP_OPC_Composer, metadata->composer);
6058 if (ret != 0) {
6059 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6060 "could not set track composer name.");
6061 }
6062 break;
6063 case PTP_OPC_Genre:
6064 // Update genre
6065 ret = set_object_string(device, metadata->item_id, PTP_OPC_Genre, metadata->genre);
6066 if (ret != 0) {
6067 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6068 "could not set track genre name.");
6069 }
6070 break;
6071 case PTP_OPC_Duration:
6072 // Update duration
6073 if (metadata->duration != 0) {
6074 ret = set_object_u32(device, metadata->item_id, PTP_OPC_Duration, adjust_u32(metadata->duration, &opd));
6075 if (ret != 0) {
6076 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6077 "could not set track duration.");
6078 }
6079 }
6080 break;
6081 case PTP_OPC_Track:
6082 // Update track number.
6083 if (metadata->tracknumber != 0) {
6084 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Track, adjust_u16(metadata->tracknumber, &opd));
6085 if (ret != 0) {
6086 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6087 "could not set track tracknumber.");
6088 }
6089 }
6090 break;
6091 case PTP_OPC_OriginalReleaseDate:
6092 // Update creation datetime
6093 ret = set_object_string(device, metadata->item_id, PTP_OPC_OriginalReleaseDate, metadata->date);
6094 if (ret != 0) {
6095 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6096 "could not set track release date.");
6097 }
6098 break;
6099 // These are, well not so important.
6100 case PTP_OPC_SampleRate:
6101 // Update sample rate
6102 if (metadata->samplerate != 0) {
6103 ret = set_object_u32(device, metadata->item_id, PTP_OPC_SampleRate, adjust_u32(metadata->samplerate, &opd));
6104 if (ret != 0) {
6105 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6106 "could not set samplerate.");
6107 }
6108 }
6109 break;
6110 case PTP_OPC_NumberOfChannels:
6111 // Update number of channels
6112 if (metadata->nochannels != 0) {
6113 ret = set_object_u16(device, metadata->item_id, PTP_OPC_NumberOfChannels, adjust_u16(metadata->nochannels, &opd));
6114 if (ret != 0) {
6115 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6116 "could not set number of channels.");
6117 }
6118 }
6119 break;
6120 case PTP_OPC_AudioWAVECodec:
6121 // Update WAVE codec
6122 if (metadata->wavecodec != 0) {
6123 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioWAVECodec, adjust_u32(metadata->wavecodec, &opd));
6124 if (ret != 0) {
6125 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6126 "could not set WAVE codec.");
6127 }
6128 }
6129 break;
6130 case PTP_OPC_AudioBitRate:
6131 // Update bitrate
6132 if (metadata->bitrate != 0) {
6133 ret = set_object_u32(device, metadata->item_id, PTP_OPC_AudioBitRate, adjust_u32(metadata->bitrate, &opd));
6134 if (ret != 0) {
6135 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6136 "could not set bitrate.");
6137 }
6138 }
6139 break;
6140 case PTP_OPC_BitRateType:
6141 // Update bitrate type
6142 if (metadata->bitratetype != 0) {
6143 ret = set_object_u16(device, metadata->item_id, PTP_OPC_BitRateType, adjust_u16(metadata->bitratetype, &opd));
6144 if (ret != 0) {
6145 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6146 "could not set bitratetype.");
6147 }
6148 }
6149 break;
6150 case PTP_OPC_Rating:
6151 // Update user rating
6152 // TODO: shall this be set for rating 0?
6153 if (metadata->rating != 0) {
6154 ret = set_object_u16(device, metadata->item_id, PTP_OPC_Rating, adjust_u16(metadata->rating, &opd));
6155 if (ret != 0) {
6156 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6157 "could not set user rating.");
6158 }
6159 }
6160 break;
6161 case PTP_OPC_UseCount:
6162 // Update use count, set even to zero if desired.
6163 ret = set_object_u32(device, metadata->item_id, PTP_OPC_UseCount, adjust_u32(metadata->usecount, &opd));
6164 if (ret != 0) {
6165 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6166 "could not set use count.");
6167 }
6168 break;
6169 case PTP_OPC_DateModified:
6170 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
6171 // Update modification time if supported
6172 char *tmpstamp = get_iso8601_stamp();
6173 ret = set_object_string(device, metadata->item_id, PTP_OPC_DateModified, tmpstamp);
6174 if (ret != 0) {
6175 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6176 "could not set modification date.");
6177 }
6178 free(tmpstamp);
6179 }
6180 break;
6181
6182 // NOTE: File size is not updated, this should not change anyway.
6183 // neither will we change the filename.
6184 default:
6185 break;
6186 }
6187 }
6188 ptp_free_objectpropdesc(&opd);
6189 }
6190 } else {
6191 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
6192 "Your device doesn't seem to support any known way of setting metadata.");
6193 free(properties);
6194 return -1;
6195 }
6196
6197 // update cached object properties if metadata cache exists
6198 update_metadata_cache(device, metadata->item_id);
6199
6200 free(properties);
6201
6202 return 0;
6203 }
6204
6205 /**
6206 * This function deletes a single file, track, playlist, folder or
6207 * any other object off the MTP device, identified by the object ID.
6208 *
6209 * If you delete a folder, there is no guarantee that the device will
6210 * really delete all the files that were in that folder, rather it is
6211 * expected that they will not be deleted, and will turn up in object
6212 * listings with parent set to a non-existant object ID. The safe way
6213 * to do this is to recursively delete all files (and folders) contained
6214 * in the folder, then the folder itself.
6215 *
6216 * @param device a pointer to the device to delete the object from.
6217 * @param object_id the object to delete.
6218 * @return 0 on success, any other value means failure.
6219 */
6220 int LIBMTP_Delete_Object(LIBMTP_mtpdevice_t *device,
6221 uint32_t object_id)
6222 {
6223 uint16_t ret;
6224 PTPParams *params = (PTPParams *) device->params;
6225
6226 ret = ptp_deleteobject(params, object_id, 0);
6227 if (ret != PTP_RC_OK) {
6228 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Delete_Object(): could not delete object.");
6229 return -1;
6230 }
6231
6232 return 0;
6233 }
6234
6235 /**
6236 * Internal function to update an object filename property.
6237 */
6238 static int set_object_filename(LIBMTP_mtpdevice_t *device,
6239 uint32_t object_id, uint16_t ptp_type,
6240 const char **newname_ptr)
6241 {
6242 PTPParams *params = (PTPParams *) device->params;
6243 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6244 PTPObjectPropDesc opd;
6245 uint16_t ret;
6246 char *newname;
6247
6248 // See if we can modify the filename on this kind of files.
6249 ret = ptp_mtp_getobjectpropdesc(params, PTP_OPC_ObjectFileName, ptp_type, &opd);
6250 if (ret != PTP_RC_OK) {
6251 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6252 "could not get property description.");
6253 return -1;
6254 }
6255
6256 if (!opd.GetSet) {
6257 ptp_free_objectpropdesc(&opd);
6258 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6259 " property is not settable.");
6260 // TODO: we COULD actually upload/download the object here, if we feel
6261 // like wasting time for the user.
6262 return -1;
6263 }
6264
6265 newname = strdup(*newname_ptr);
6266
6267 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6268 strip_7bit_from_utf8(newname);
6269 }
6270
6271 if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjPropList) &&
6272 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
6273 MTPProperties *props = NULL;
6274 MTPProperties *prop = NULL;
6275 int nrofprops = 0;
6276
6277 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6278 prop->ObjectHandle = object_id;
6279 prop->property = PTP_OPC_ObjectFileName;
6280 prop->datatype = PTP_DTC_STR;
6281 prop->propval.str = newname;
6282
6283 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6284
6285 ptp_destroy_object_prop_list(props, nrofprops);
6286
6287 if (ret != PTP_RC_OK) {
6288 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6289 " could not set object property list.");
6290 ptp_free_objectpropdesc(&opd);
6291 return -1;
6292 }
6293 } else if (ptp_operation_issupported(params, PTP_OC_MTP_SetObjectPropValue)) {
6294 ret = set_object_string(device, object_id, PTP_OPC_ObjectFileName, newname);
6295 if (ret != 0) {
6296 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6297 " could not set object filename.");
6298 ptp_free_objectpropdesc(&opd);
6299 return -1;
6300 }
6301 } else {
6302 free(newname);
6303 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "set_object_filename(): "
6304 " your device doesn't seem to support any known way of setting metadata.");
6305 ptp_free_objectpropdesc(&opd);
6306 return -1;
6307 }
6308
6309 ptp_free_objectpropdesc(&opd);
6310
6311 // update cached object properties if metadata cache exists
6312 update_metadata_cache(device, object_id);
6313
6314 return 0;
6315 }
6316
6317 /**
6318 * This function renames a single file.
6319 * This simply means that the PTP_OPC_ObjectFileName property
6320 * is updated, if this is supported by the device.
6321 *
6322 * @param device a pointer to the device that contains the file.
6323 * @param file the file metadata of the file to rename.
6324 * On success, the filename member is updated. Be aware, that
6325 * this name can be different than newname depending of device restrictions.
6326 * @param newname the new filename for this object.
6327 * @return 0 on success, any other value means failure.
6328 */
6329 int LIBMTP_Set_File_Name(LIBMTP_mtpdevice_t *device,
6330 LIBMTP_file_t *file, const char *newname)
6331 {
6332 int ret;
6333
6334 ret = set_object_filename(device, file->item_id,
6335 map_libmtp_type_to_ptp_type(file->filetype),
6336 &newname);
6337
6338 if (ret != 0) {
6339 return ret;
6340 }
6341
6342 free(file->filename);
6343 file->filename = strdup(newname);
6344 return ret;
6345 }
6346
6347 /**
6348 * This function renames a single folder.
6349 * This simply means that the PTP_OPC_ObjectFileName property
6350 * is updated, if this is supported by the device.
6351 *
6352 * @param device a pointer to the device that contains the file.
6353 * @param folder the folder metadata of the folder to rename.
6354 * On success, the name member is updated. Be aware, that
6355 * this name can be different than newname depending of device restrictions.
6356 * @param newname the new name for this object.
6357 * @return 0 on success, any other value means failure.
6358 */
6359 int LIBMTP_Set_Folder_Name(LIBMTP_mtpdevice_t *device,
6360 LIBMTP_folder_t *folder, const char* newname)
6361 {
6362 int ret;
6363
6364 ret = set_object_filename(device, folder->folder_id,
6365 PTP_OFC_Association,
6366 &newname);
6367
6368 if (ret != 0) {
6369 return ret;
6370 }
6371
6372 free(folder->name);
6373 folder->name = strdup(newname);
6374 return ret;
6375 }
6376
6377 /**
6378 * This function renames a single track.
6379 * This simply means that the PTP_OPC_ObjectFileName property
6380 * is updated, if this is supported by the device.
6381 *
6382 * @param device a pointer to the device that contains the file.
6383 * @param track the track metadata of the track to rename.
6384 * On success, the filename member is updated. Be aware, that
6385 * this name can be different than newname depending of device restrictions.
6386 * @param newname the new filename for this object.
6387 * @return 0 on success, any other value means failure.
6388 */
6389 int LIBMTP_Set_Track_Name(LIBMTP_mtpdevice_t *device,
6390 LIBMTP_track_t *track, const char* newname)
6391 {
6392 int ret;
6393
6394 ret = set_object_filename(device, track->item_id,
6395 map_libmtp_type_to_ptp_type(track->filetype),
6396 &newname);
6397
6398 if (ret != 0) {
6399 return ret;
6400 }
6401
6402 free(track->filename);
6403 track->filename = strdup(newname);
6404 return ret;
6405 }
6406
6407 /**
6408 * This function renames a single playlist object file holder.
6409 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6410 * property is updated, if this is supported by the device.
6411 * The playlist filename should nominally end with an extension
6412 * like ".pla".
6413 *
6414 * NOTE: if you want to change the metadata the device display
6415 * about a playlist you must <i>not</i> use this function,
6416 * use <code>LIBMTP_Update_Playlist()</code> instead!
6417 *
6418 * @param device a pointer to the device that contains the file.
6419 * @param playlist the playlist metadata of the playlist to rename.
6420 * On success, the name member is updated. Be aware, that
6421 * this name can be different than newname depending of device restrictions.
6422 * @param newname the new name for this object.
6423 * @return 0 on success, any other value means failure.
6424 * @see LIBMTP_Update_Playlist()
6425 */
6426 int LIBMTP_Set_Playlist_Name(LIBMTP_mtpdevice_t *device,
6427 LIBMTP_playlist_t *playlist, const char* newname)
6428 {
6429 int ret;
6430
6431 ret = set_object_filename(device, playlist->playlist_id,
6432 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
6433 &newname);
6434
6435 if (ret != 0) {
6436 return ret;
6437 }
6438
6439 free(playlist->name);
6440 playlist->name = strdup(newname);
6441 return ret;
6442 }
6443
6444 /**
6445 * This function renames a single album.
6446 * This simply means that the <code>PTP_OPC_ObjectFileName</code>
6447 * property is updated, if this is supported by the device.
6448 * The album filename should nominally end with an extension
6449 * like ".alb".
6450 *
6451 * NOTE: if you want to change the metadata the device display
6452 * about a playlist you must <i>not</i> use this function,
6453 * use <code>LIBMTP_Update_Album()</code> instead!
6454 *
6455 * @param device a pointer to the device that contains the file.
6456 * @param album the album metadata of the album to rename.
6457 * On success, the name member is updated. Be aware, that
6458 * this name can be different than newname depending of device restrictions.
6459 * @param newname the new name for this object.
6460 * @return 0 on success, any other value means failure.
6461 * @see LIBMTP_Update_Album()
6462 */
6463 int LIBMTP_Set_Album_Name(LIBMTP_mtpdevice_t *device,
6464 LIBMTP_album_t *album, const char* newname)
6465 {
6466 int ret;
6467
6468 ret = set_object_filename(device, album->album_id,
6469 PTP_OFC_MTP_AbstractAudioAlbum,
6470 &newname);
6471
6472 if (ret != 0) {
6473 return ret;
6474 }
6475
6476 free(album->name);
6477 album->name = strdup(newname);
6478 return ret;
6479 }
6480
6481 /**
6482 * THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER
6483 * NOT TO USE IT.
6484 *
6485 * @see LIBMTP_Set_File_Name()
6486 * @see LIBMTP_Set_Track_Name()
6487 * @see LIBMTP_Set_Folder_Name()
6488 * @see LIBMTP_Set_Playlist_Name()
6489 * @see LIBMTP_Set_Album_Name()
6490 */
6491 int LIBMTP_Set_Object_Filename(LIBMTP_mtpdevice_t *device,
6492 uint32_t object_id, char* newname)
6493 {
6494 int ret;
6495 LIBMTP_file_t *file;
6496
6497 file = LIBMTP_Get_Filemetadata(device, object_id);
6498
6499 if (file == NULL) {
6500 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Set_Object_Filename(): "
6501 "could not get file metadata for target object.");
6502 return -1;
6503 }
6504
6505 ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
6506
6507 free(file);
6508
6509 return ret;
6510 }
6511
6512 /**
6513 * Helper function. This indicates if a track exists on the device
6514 * @param device a pointer to the device to get the track from.
6515 * @param id the track ID of the track to retrieve.
6516 * @return TRUE (!=0) if the track exists, FALSE (0) if not
6517 */
6518 int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
6519 uint32_t const id)
6520 {
6521 PTPParams *params = (PTPParams *) device->params;
6522 uint16_t ret;
6523 PTPObject *ob;
6524
6525 ret = ptp_object_want (params, id, 0, &ob);
6526 if (ret == PTP_RC_OK)
6527 return -1;
6528 return 0;
6529 }
6530
6531 /**
6532 * This creates a new folder structure and allocates memory
6533 * for it. Notice that if you add strings to this structure they
6534 * will be freed by the corresponding <code>LIBMTP_folder_track_t</code>
6535 * operation later, so be careful of using strdup() when assigning
6536 * strings, e.g.:
6537 *
6538 * @return a pointer to the newly allocated folder structure.
6539 * @see LIBMTP_destroy_folder_t()
6540 */
6541 LIBMTP_folder_t *LIBMTP_new_folder_t(void)
6542 {
6543 LIBMTP_folder_t *new = (LIBMTP_folder_t *) malloc(sizeof(LIBMTP_folder_t));
6544 if (new == NULL) {
6545 return NULL;
6546 }
6547 new->folder_id = 0;
6548 new->parent_id = 0;
6549 new->storage_id = 0;
6550 new->name = NULL;
6551 new->sibling = NULL;
6552 new->child = NULL;
6553 return new;
6554 }
6555
6556 /**
6557 * This recursively deletes the memory for a folder structure.
6558 * This shall typically be called on a top-level folder list to
6559 * detsroy the entire folder tree.
6560 *
6561 * @param folder folder structure to destroy
6562 * @see LIBMTP_new_folder_t()
6563 */
6564 void LIBMTP_destroy_folder_t(LIBMTP_folder_t *folder)
6565 {
6566
6567 if(folder == NULL) {
6568 return;
6569 }
6570
6571 //Destroy from the bottom up
6572 if(folder->child != NULL) {
6573 LIBMTP_destroy_folder_t(folder->child);
6574 }
6575
6576 if(folder->sibling != NULL) {
6577 LIBMTP_destroy_folder_t(folder->sibling);
6578 }
6579
6580 if(folder->name != NULL) {
6581 free(folder->name);
6582 }
6583
6584 free(folder);
6585 }
6586
6587 /**
6588 * Helper function. Returns a folder structure for a
6589 * specified id.
6590 *
6591 * @param folderlist list of folders to search
6592 * @id id of folder to look for
6593 * @return a folder or NULL if not found
6594 */
6595 LIBMTP_folder_t *LIBMTP_Find_Folder(LIBMTP_folder_t *folderlist, uint32_t id)
6596 {
6597 LIBMTP_folder_t *ret = NULL;
6598
6599 if(folderlist == NULL) {
6600 return NULL;
6601 }
6602
6603 if(folderlist->folder_id == id) {
6604 return folderlist;
6605 }
6606
6607 if(folderlist->sibling) {
6608 ret = LIBMTP_Find_Folder(folderlist->sibling, id);
6609 }
6610
6611 if(folderlist->child && ret == NULL) {
6612 ret = LIBMTP_Find_Folder(folderlist->child, id);
6613 }
6614
6615 return ret;
6616 }
6617
6618 /**
6619 * Function used to recursively get subfolders from params.
6620 */
6621 static LIBMTP_folder_t *get_subfolders_for_folder(LIBMTP_folder_t *list, uint32_t parent)
6622 {
6623 LIBMTP_folder_t *retfolders = NULL, *children, *iter, *curr;
6624
6625 iter = list->sibling;
6626 while(iter != list) {
6627 if (iter->parent_id != parent) {
6628 iter = iter->sibling;
6629 continue;
6630 }
6631
6632 /* We know that iter is a child of 'parent', therefore we can safely
6633 * hold on to 'iter' locally since no one else will steal it
6634 * from the 'list' as we recurse. */
6635 children = get_subfolders_for_folder(list, iter->folder_id);
6636
6637 curr = iter;
6638 iter = iter->sibling;
6639
6640 // Remove curr from the list.
6641 curr->child->sibling = curr->sibling;
6642 curr->sibling->child = curr->child;
6643
6644 // Attach the children to curr.
6645 curr->child = children;
6646
6647 // Put this folder into the list of siblings.
6648 curr->sibling = retfolders;
6649 retfolders = curr;
6650 }
6651
6652 return retfolders;
6653 }
6654
6655 /**
6656 * This returns a list of all folders available
6657 * on the current MTP device.
6658 *
6659 * @param device a pointer to the device to get the folder listing for.
6660 * @return a list of folders
6661 */
6662 LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
6663 {
6664 PTPParams *params = (PTPParams *) device->params;
6665 LIBMTP_folder_t head, *rv;
6666 int i;
6667
6668 // Get all the handles if we haven't already done that
6669 if (params->nrofobjects == 0) {
6670 flush_handles(device);
6671 }
6672
6673 /*
6674 * This creates a temporary list of the folders, this is in a
6675 * reverse order and uses the Folder pointers that are already
6676 * in the Folder structure. From this we can then build up the
6677 * folder hierarchy with only looking at this temporary list,
6678 * and removing the folders from this temporary list as we go.
6679 * This significantly reduces the number of operations that we
6680 * have to do in building the folder hierarchy. Also since the
6681 * temp list is in reverse order, when we prepend to the sibling
6682 * list things are in the same order as they were originally
6683 * in the handle list.
6684 */
6685 head.sibling = &head;
6686 head.child = &head;
6687 for (i = 0; i < params->nrofobjects; i++) {
6688 LIBMTP_folder_t *folder;
6689 PTPObject *ob;
6690
6691 ob = ¶ms->objects[i];
6692 if (ob->oi.ObjectFormat != PTP_OFC_Association) {
6693 continue;
6694 }
6695 /*
6696 * Do we know how to handle these? They are part
6697 * of the MTP 1.0 specification paragraph 3.6.4.
6698 * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
6699 * should be called on these to get the contained objects, but
6700 * we basically don't care. Hopefully parent_id is maintained for all
6701 * children, because we rely on that instead.
6702 */
6703 if (ob->oi.AssociationDesc != 0x00000000U) {
6704 printf("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
6705 }
6706
6707 // Create a folder struct...
6708 folder = LIBMTP_new_folder_t();
6709 if (folder == NULL) {
6710 // malloc failure or so.
6711 return NULL;
6712 }
6713 folder->folder_id = ob->oid;
6714 folder->parent_id = ob->oi.ParentObject;
6715 folder->storage_id = ob->oi.StorageID;
6716 folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
6717
6718 // pretend sibling says next, and child says prev.
6719 folder->sibling = head.sibling;
6720 folder->child = &head;
6721 head.sibling->child = folder;
6722 head.sibling = folder;
6723 }
6724
6725 // We begin at the root folder and get them all recursively
6726 rv = get_subfolders_for_folder(&head, 0x00000000);
6727
6728 // The temp list should be empty. Clean up any orphans just in case.
6729 while(head.sibling != &head) {
6730 LIBMTP_folder_t *curr = head.sibling;
6731
6732 printf("Orphan folder with ID: 0x%08x name: \"%s\" encountered.\n",
6733 curr->folder_id,
6734 curr->name);
6735 curr->sibling->child = curr->child;
6736 curr->child->sibling = curr->sibling;
6737 curr->child = NULL;
6738 curr->sibling = NULL;
6739 LIBMTP_destroy_folder_t(curr);
6740 }
6741
6742 return rv;
6743 }
6744
6745 /**
6746 * This create a folder on the current MTP device. The PTP name
6747 * for a folder is "association". The PTP/MTP devices does not
6748 * have an internal "folder" concept really, it contains a flat
6749 * list of all files and some file are "associations" that other
6750 * files and folders may refer to as its "parent".
6751 *
6752 * @param device a pointer to the device to create the folder on.
6753 * @param name the name of the new folder. Note this can be modified
6754 * if the device does not support all the characters in the
6755 * name.
6756 * @param parent_id id of parent folder to add the new folder to,
6757 * or 0 to put it in the root directory.
6758 * @param storage_id id of the storage to add this new folder to.
6759 * notice that you cannot mismatch storage id and parent id:
6760 * they must both be on the same storage! Pass in 0 if you
6761 * want to create this folder on the default storage.
6762 * @return id to new folder or 0 if an error occured
6763 */
6764 uint32_t LIBMTP_Create_Folder(LIBMTP_mtpdevice_t *device, char *name,
6765 uint32_t parent_id, uint32_t storage_id)
6766 {
6767 PTPParams *params = (PTPParams *) device->params;
6768 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6769 uint32_t parenthandle = 0;
6770 uint32_t store;
6771 PTPObjectInfo new_folder;
6772 uint16_t ret;
6773 uint32_t new_id = 0;
6774
6775 if (storage_id == 0) {
6776 // I'm just guessing that a folder may require 512 bytes
6777 store = get_writeable_storageid(device, 512);
6778 } else {
6779 store = storage_id;
6780 }
6781
6782 if (parent_id == 0) {
6783 parent_id = 0xFFFFFFFFU; // Set to -1
6784 }
6785
6786 parenthandle = parent_id;
6787
6788 memset(&new_folder, 0, sizeof(new_folder));
6789 new_folder.Filename = name;
6790 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
6791 strip_7bit_from_utf8(new_folder.Filename);
6792 }
6793 new_folder.ObjectCompressedSize = 1;
6794 new_folder.ObjectFormat = PTP_OFC_Association;
6795 new_folder.ProtectionStatus = PTP_PS_NoProtection;
6796 new_folder.AssociationType = PTP_AT_GenericFolder;
6797 new_folder.ParentObject = parent_id;
6798 new_folder.StorageID = store;
6799
6800 // Create the object
6801 // FIXME: use send list here if available.
6802 ret = ptp_sendobjectinfo(params, &store, &parenthandle, &new_id, &new_folder);
6803 if (ret != PTP_RC_OK) {
6804 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Create_Folder: Could not send object info.");
6805 if (ret == PTP_RC_AccessDenied) {
6806 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
6807 }
6808 return 0;
6809 }
6810 // NOTE: don't destroy the new_folder objectinfo, because it is statically referencing
6811 // several strings.
6812
6813 add_object_to_cache(device, new_id);
6814
6815 return new_id;
6816 }
6817
6818 /**
6819 * This creates a new playlist metadata structure and allocates memory
6820 * for it. Notice that if you add strings to this structure they
6821 * will be freed by the corresponding <code>LIBMTP_destroy_playlist_t</code>
6822 * operation later, so be careful of using strdup() when assigning
6823 * strings, e.g.:
6824 *
6825 * <pre>
6826 * LIBMTP_playlist_t *pl = LIBMTP_new_playlist_t();
6827 * pl->name = strdup(str);
6828 * ....
6829 * LIBMTP_destroy_playlist_t(pl);
6830 * </pre>
6831 *
6832 * @return a pointer to the newly allocated metadata structure.
6833 * @see LIBMTP_destroy_playlist_t()
6834 */
6835 LIBMTP_playlist_t *LIBMTP_new_playlist_t(void)
6836 {
6837 LIBMTP_playlist_t *new = (LIBMTP_playlist_t *) malloc(sizeof(LIBMTP_playlist_t));
6838 if (new == NULL) {
6839 return NULL;
6840 }
6841 new->playlist_id = 0;
6842 new->parent_id = 0;
6843 new->storage_id = 0;
6844 new->name = NULL;
6845 new->tracks = NULL;
6846 new->no_tracks = 0;
6847 new->next = NULL;
6848 return new;
6849 }
6850
6851 /**
6852 * This destroys a playlist metadata structure and deallocates the memory
6853 * used by it, including any strings. Never use a track metadata
6854 * structure again after calling this function on it.
6855 * @param playlist the playlist metadata to destroy.
6856 * @see LIBMTP_new_playlist_t()
6857 */
6858 void LIBMTP_destroy_playlist_t(LIBMTP_playlist_t *playlist)
6859 {
6860 if (playlist == NULL) {
6861 return;
6862 }
6863 if (playlist->name != NULL)
6864 free(playlist->name);
6865 if (playlist->tracks != NULL)
6866 free(playlist->tracks);
6867 free(playlist);
6868 return;
6869 }
6870
6871 /**
6872 * This function returns a list of the playlists available on the
6873 * device. Typical usage:
6874 *
6875 * <pre>
6876 * </pre>
6877 *
6878 * @param device a pointer to the device to get the playlist listing from.
6879 * @return a playlist list on success, else NULL. If there are no playlists
6880 * on the device, NULL will be returned as well.
6881 * @see LIBMTP_Get_Playlist()
6882 */
6883 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
6884 {
6885 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6886 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
6887 PTPParams *params = (PTPParams *) device->params;
6888 LIBMTP_playlist_t *retlists = NULL;
6889 LIBMTP_playlist_t *curlist = NULL;
6890 uint32_t i;
6891
6892 // Get all the handles if we haven't already done that
6893 if (params->nrofobjects == 0) {
6894 flush_handles(device);
6895 }
6896
6897 for (i = 0; i < params->nrofobjects; i++) {
6898 LIBMTP_playlist_t *pl;
6899 PTPObject *ob;
6900 uint16_t ret;
6901
6902 ob = ¶ms->objects[i];
6903
6904 // Ignore stuff that isn't playlists
6905
6906 // For Samsung players we must look for the .spl extension explicitly since
6907 // playlists are not stored as playlist objects.
6908 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
6909 // Allocate a new playlist type
6910 pl = LIBMTP_new_playlist_t();
6911 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
6912 }
6913 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
6914 continue;
6915 }
6916 else {
6917 // Allocate a new playlist type
6918 pl = LIBMTP_new_playlist_t();
6919
6920 // Try to look up proper name, else use the oi->Filename field.
6921 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
6922 if (pl->name == NULL) {
6923 pl->name = strdup(ob->oi.Filename);
6924 }
6925 pl->playlist_id = ob->oid;
6926 pl->parent_id = ob->oi.ParentObject;
6927 pl->storage_id = ob->oi.StorageID;
6928
6929 // Then get the track listing for this playlist
6930 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
6931 if (ret != PTP_RC_OK) {
6932 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist_List(): "
6933 "could not get object references.");
6934 pl->tracks = NULL;
6935 pl->no_tracks = 0;
6936 }
6937 }
6938
6939 // Add playlist to a list that will be returned afterwards.
6940 if (retlists == NULL) {
6941 retlists = pl;
6942 curlist = pl;
6943 } else {
6944 curlist->next = pl;
6945 curlist = pl;
6946 }
6947
6948 // Call callback here if we decide to add that possibility...
6949 }
6950 return retlists;
6951 }
6952
6953
6954 /**
6955 * This function retrieves an individual playlist from the device.
6956 * @param device a pointer to the device to get the playlist from.
6957 * @param plid the unique ID of the playlist to retrieve.
6958 * @return a valid playlist metadata post or NULL on failure.
6959 * @see LIBMTP_Get_Playlist_List()
6960 */
6961 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
6962 {
6963 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6964 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
6965 PTPParams *params = (PTPParams *) device->params;
6966 PTPObject *ob;
6967 LIBMTP_playlist_t *pl;
6968 uint16_t ret;
6969
6970 // Get all the handles if we haven't already done that
6971 if (params->nrofobjects == 0) {
6972 flush_handles(device);
6973 }
6974
6975 ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
6976 if (ret != PTP_RC_OK)
6977 return NULL;
6978
6979 // For Samsung players we must look for the .spl extension explicitly since
6980 // playlists are not stored as playlist objects.
6981 if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
6982 // Allocate a new playlist type
6983 pl = LIBMTP_new_playlist_t();
6984 spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
6985 return pl;
6986 }
6987
6988 // Ignore stuff that isn't playlists
6989 else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
6990 return NULL;
6991 }
6992
6993 // Allocate a new playlist type
6994 pl = LIBMTP_new_playlist_t();
6995
6996 pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
6997 if (pl->name == NULL) {
6998 pl->name = strdup(ob->oi.Filename);
6999 }
7000 pl->playlist_id = ob->oid;
7001 pl->parent_id = ob->oi.ParentObject;
7002 pl->storage_id = ob->oi.StorageID;
7003
7004 // Then get the track listing for this playlist
7005 ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
7006 if (ret != PTP_RC_OK) {
7007 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
7008 pl->tracks = NULL;
7009 pl->no_tracks = 0;
7010 }
7011
7012 return pl;
7013 }
7014
7015 /**
7016 * This function creates a new abstract list such as a playlist
7017 * or an album.
7018 *
7019 * @param device a pointer to the device to create the new abstract list
7020 * on.
7021 * @param name the name of the new abstract list.
7022 * @param artist the artist of the new abstract list or NULL.
7023 * @param genre the genre of the new abstract list or NULL.
7024 * @param parenthandle the handle of the parent or 0 for no parent
7025 * i.e. the root folder.
7026 * @param objectformat the abstract list type to create.
7027 * @param suffix the ".foo" (4 characters) suffix to use for the virtual
7028 * "file" created by this operation.
7029 * @param newid a pointer to a variable that will hold the new object
7030 * ID if this call is successful.
7031 * @param tracks an array of tracks to associate with this list.
7032 * @param no_tracks the number of tracks in the list.
7033 * @return 0 on success, any other value means failure.
7034 */
7035 static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
7036 char const * const name,
7037 char const * const artist,
7038 char const * const composer,
7039 char const * const genre,
7040 uint32_t const parenthandle,
7041 uint32_t const storageid,
7042 uint16_t const objectformat,
7043 char const * const suffix,
7044 uint32_t * const newid,
7045 uint32_t const * const tracks,
7046 uint32_t const no_tracks)
7047
7048 {
7049 int i;
7050 int supported = 0;
7051 uint16_t ret;
7052 uint16_t *properties = NULL;
7053 uint32_t propcnt = 0;
7054 uint32_t store;
7055 uint32_t localph = parenthandle;
7056 uint8_t nonconsumable = 0x00U; /* By default it is consumable */
7057 PTPParams *params = (PTPParams *) device->params;
7058 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7059 char fname[256];
7060 uint8_t data[2];
7061
7062 if (storageid == 0) {
7063 // I'm just guessing that an abstract list may require 512 bytes
7064 store = get_writeable_storageid(device, 512);
7065 } else {
7066 store = storageid;
7067 }
7068
7069 // Check if we can create an object of this type
7070 for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
7071 if (params->deviceinfo.ImageFormats[i] == objectformat) {
7072 supported = 1;
7073 break;
7074 }
7075 }
7076 if (!supported) {
7077 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): player does not support this abstract type.");
7078 printf("Unsupported abstract list type: %04x\n", objectformat);
7079 return -1;
7080 }
7081
7082 // add the new suffix if it isn't there
7083 fname[0] = '\0';
7084 if (strlen(name) > strlen(suffix)) {
7085 char const * const suff = &name[strlen(name)-strlen(suffix)];
7086 if (!strcmp(suff, suffix)) {
7087 // Home free.
7088 strncpy(fname, name, sizeof(fname));
7089 }
7090 }
7091 // If it didn't end with "<suffix>" then add that here.
7092 if (fname[0] == '\0') {
7093 strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
7094 strcat(fname, suffix);
7095 fname[sizeof(fname)-1] = '\0';
7096 }
7097
7098 if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
7099 !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
7100 MTPProperties *props = NULL;
7101 MTPProperties *prop = NULL;
7102 int nrofprops = 0;
7103
7104 *newid = 0x00000000U;
7105
7106 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7107
7108 for (i=0;i<propcnt;i++) {
7109 PTPObjectPropDesc opd;
7110
7111 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7112 if (ret != PTP_RC_OK) {
7113 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7114 "could not get property description.");
7115 } else if (opd.GetSet) {
7116 switch (properties[i]) {
7117 case PTP_OPC_ObjectFileName:
7118 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7119 prop->ObjectHandle = *newid;
7120 prop->property = PTP_OPC_ObjectFileName;
7121 prop->datatype = PTP_DTC_STR;
7122 prop->propval.str = strdup(fname);
7123 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7124 strip_7bit_from_utf8(prop->propval.str);
7125 }
7126 break;
7127 case PTP_OPC_ProtectionStatus:
7128 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7129 prop->ObjectHandle = *newid;
7130 prop->property = PTP_OPC_ProtectionStatus;
7131 prop->datatype = PTP_DTC_UINT16;
7132 prop->propval.u16 = 0x0000U; /* Not protected */
7133 break;
7134 case PTP_OPC_NonConsumable:
7135 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7136 prop->ObjectHandle = *newid;
7137 prop->property = PTP_OPC_NonConsumable;
7138 prop->datatype = PTP_DTC_UINT8;
7139 prop->propval.u8 = nonconsumable;
7140 break;
7141 case PTP_OPC_Name:
7142 if (name != NULL) {
7143 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7144 prop->ObjectHandle = *newid;
7145 prop->property = PTP_OPC_Name;
7146 prop->datatype = PTP_DTC_STR;
7147 prop->propval.str = strdup(name);
7148 }
7149 break;
7150 case PTP_OPC_AlbumArtist:
7151 if (artist != NULL) {
7152 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7153 prop->ObjectHandle = *newid;
7154 prop->property = PTP_OPC_AlbumArtist;
7155 prop->datatype = PTP_DTC_STR;
7156 prop->propval.str = strdup(artist);
7157 }
7158 break;
7159 case PTP_OPC_Artist:
7160 if (artist != NULL) {
7161 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7162 prop->ObjectHandle = *newid;
7163 prop->property = PTP_OPC_Artist;
7164 prop->datatype = PTP_DTC_STR;
7165 prop->propval.str = strdup(artist);
7166 }
7167 break;
7168 case PTP_OPC_Composer:
7169 if (composer != NULL) {
7170 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7171 prop->ObjectHandle = *newid;
7172 prop->property = PTP_OPC_Composer;
7173 prop->datatype = PTP_DTC_STR;
7174 prop->propval.str = strdup(composer);
7175 }
7176 break;
7177 case PTP_OPC_Genre:
7178 if (genre != NULL) {
7179 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7180 prop->ObjectHandle = *newid;
7181 prop->property = PTP_OPC_Genre;
7182 prop->datatype = PTP_DTC_STR;
7183 prop->propval.str = strdup(genre);
7184 }
7185 break;
7186 case PTP_OPC_DateModified:
7187 // Tag with current time if that is supported
7188 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7189 prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
7190 prop->ObjectHandle = *newid;
7191 prop->property = PTP_OPC_DateModified;
7192 prop->datatype = PTP_DTC_STR;
7193 prop->propval.str = get_iso8601_stamp();
7194 }
7195 break;
7196 }
7197 }
7198 ptp_free_objectpropdesc(&opd);
7199 }
7200 free(properties);
7201
7202 ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
7203 objectformat, 0, props, nrofprops);
7204
7205 /* Free property list */
7206 ptp_destroy_object_prop_list(props, nrofprops);
7207
7208 if (ret != PTP_RC_OK) {
7209 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object property list.");
7210 if (ret == PTP_RC_AccessDenied) {
7211 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7212 }
7213 return -1;
7214 }
7215
7216 // now send the blank object
7217 ret = ptp_sendobject(params, NULL, 0);
7218 if (ret != PTP_RC_OK) {
7219 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7220 return -1;
7221 }
7222
7223 } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
7224 PTPObjectInfo new_object;
7225
7226 new_object.Filename = fname;
7227 if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
7228 strip_7bit_from_utf8(new_object.Filename);
7229 }
7230 new_object.ObjectCompressedSize = 1;
7231 new_object.ObjectFormat = objectformat;
7232
7233 // Create the object
7234 ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
7235 if (ret != PTP_RC_OK) {
7236 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send object info (the playlist itself).");
7237 if (ret == PTP_RC_AccessDenied) {
7238 add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
7239 }
7240 return -1;
7241 }
7242 // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
7243 // not copies.
7244 /*
7245 * We have to send this one blank data byte.
7246 * If we don't, the handle will not be created and thus there is no playlist.
7247 */
7248 data[0] = '\0';
7249 data[1] = '\0';
7250 ret = ptp_sendobject(params, data, 1);
7251 if (ret != PTP_RC_OK) {
7252 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
7253 return -1;
7254 }
7255
7256 // set the properties one by one
7257 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7258
7259 for (i=0;i<propcnt;i++) {
7260 PTPObjectPropDesc opd;
7261
7262 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7263 if (ret != PTP_RC_OK) {
7264 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
7265 "could not get property description.");
7266 } else if (opd.GetSet) {
7267 switch (properties[i]) {
7268 case PTP_OPC_Name:
7269 if (name != NULL) {
7270 ret = set_object_string(device, *newid, PTP_OPC_Name, name);
7271 if (ret != 0) {
7272 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity name.");
7273 return -1;
7274 }
7275 }
7276 break;
7277 case PTP_OPC_AlbumArtist:
7278 if (artist != NULL) {
7279 ret = set_object_string(device, *newid, PTP_OPC_AlbumArtist, artist);
7280 if (ret != 0) {
7281 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity album artist.");
7282 return -1;
7283 }
7284 }
7285 break;
7286 case PTP_OPC_Artist:
7287 if (artist != NULL) {
7288 ret = set_object_string(device, *newid, PTP_OPC_Artist, artist);
7289 if (ret != 0) {
7290 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity artist.");
7291 return -1;
7292 }
7293 }
7294 break;
7295 case PTP_OPC_Composer:
7296 if (composer != NULL) {
7297 ret = set_object_string(device, *newid, PTP_OPC_Composer, composer);
7298 if (ret != 0) {
7299 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity composer.");
7300 return -1;
7301 }
7302 }
7303 break;
7304 case PTP_OPC_Genre:
7305 if (genre != NULL) {
7306 ret = set_object_string(device, *newid, PTP_OPC_Genre, genre);
7307 if (ret != 0) {
7308 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set entity genre.");
7309 return -1;
7310 }
7311 }
7312 break;
7313 case PTP_OPC_DateModified:
7314 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7315 ret = set_object_string(device, *newid, PTP_OPC_DateModified, get_iso8601_stamp());
7316 if (ret != 0) {
7317 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): could not set date modified.");
7318 return -1;
7319 }
7320 }
7321 break;
7322 }
7323 }
7324 ptp_free_objectpropdesc(&opd);
7325 }
7326 free(properties);
7327 }
7328
7329 if (no_tracks > 0) {
7330 // Add tracks to the list as object references.
7331 ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
7332 if (ret != PTP_RC_OK) {
7333 add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): could not add tracks as object references.");
7334 return -1;
7335 }
7336 }
7337
7338 add_object_to_cache(device, *newid);
7339
7340 return 0;
7341 }
7342
7343 /**
7344 * This updates the metadata and track listing
7345 * for an abstract list.
7346 * @param device a pointer to the device that the abstract list
7347 * resides on.
7348 * @param name the name of the abstract list.
7349 * @param artist the artist of the abstract list or NULL.
7350 * @param genre the genre of the abstract list or NULL.
7351 * @param objecthandle the object to be updated.
7352 * @param objectformat the abstract list type to update.
7353 * @param tracks an array of tracks to associate with this list.
7354 * @param no_tracks the number of tracks in the list.
7355 * @return 0 on success, any other value means failure.
7356 */
7357 static int update_abstract_list(LIBMTP_mtpdevice_t *device,
7358 char const * const name,
7359 char const * const artist,
7360 char const * const composer,
7361 char const * const genre,
7362 uint32_t const objecthandle,
7363 uint16_t const objectformat,
7364 uint32_t const * const tracks,
7365 uint32_t const no_tracks)
7366 {
7367 uint16_t ret;
7368 PTPParams *params = (PTPParams *) device->params;
7369 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7370 uint16_t *properties = NULL;
7371 uint32_t propcnt = 0;
7372 int i;
7373
7374 // First see which properties can be set
7375 // i.e only try to update this metadata for object tags that exist on the current player.
7376 ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
7377 if (ret != PTP_RC_OK) {
7378 // Just bail out for now, nothing is ever set.
7379 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7380 "could not retrieve supported object properties.");
7381 return -1;
7382 }
7383 if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjPropList) &&
7384 !FLAG_BROKEN_SET_OBJECT_PROPLIST(ptp_usb)) {
7385 MTPProperties *props = NULL;
7386 MTPProperties *prop = NULL;
7387 int nrofprops = 0;
7388
7389 for (i=0;i<propcnt;i++) {
7390 PTPObjectPropDesc opd;
7391
7392 ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
7393 if (ret != PTP_RC_OK) {
7394 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7395 "could not get property description.");
7396 } else if (opd.GetSet) {
7397 switch (properties[i]) {
7398 case PTP_OPC_Name:
7399 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7400 prop->ObjectHandle = objecthandle;
7401 prop->property = PTP_OPC_Name;
7402 prop->datatype = PTP_DTC_STR;
7403 if (name != NULL)
7404 prop->propval.str = strdup(name);
7405 break;
7406 case PTP_OPC_AlbumArtist:
7407 if (artist != NULL) {
7408 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7409 prop->ObjectHandle = objecthandle;
7410 prop->property = PTP_OPC_AlbumArtist;
7411 prop->datatype = PTP_DTC_STR;
7412 prop->propval.str = strdup(artist);
7413 }
7414 break;
7415 case PTP_OPC_Artist:
7416 if (artist != NULL) {
7417 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7418 prop->ObjectHandle = objecthandle;
7419 prop->property = PTP_OPC_Artist;
7420 prop->datatype = PTP_DTC_STR;
7421 prop->propval.str = strdup(artist);
7422 }
7423 break;
7424 case PTP_OPC_Composer:
7425 if (composer != NULL) {
7426 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7427 prop->ObjectHandle = objecthandle;
7428 prop->property = PTP_OPC_Composer;
7429 prop->datatype = PTP_DTC_STR;
7430 prop->propval.str = strdup(composer);
7431 }
7432 break;
7433 case PTP_OPC_Genre:
7434 if (genre != NULL) {
7435 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7436 prop->ObjectHandle = objecthandle;
7437 prop->property = PTP_OPC_Genre;
7438 prop->datatype = PTP_DTC_STR;
7439 prop->propval.str = strdup(genre);
7440 }
7441 break;
7442 case PTP_OPC_DateModified:
7443 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7444 // Tag with current time if that is supported
7445 prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
7446 prop->ObjectHandle = objecthandle;
7447 prop->property = PTP_OPC_DateModified;
7448 prop->datatype = PTP_DTC_STR;
7449 prop->propval.str = get_iso8601_stamp();
7450 }
7451 break;
7452 default:
7453 break;
7454 }
7455 }
7456 ptp_free_objectpropdesc(&opd);
7457 }
7458
7459 // proplist could be NULL if we can't write any properties
7460 if (props != NULL) {
7461 ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
7462
7463 ptp_destroy_object_prop_list(props, nrofprops);
7464
7465 if (ret != PTP_RC_OK) {
7466 // TODO: return error of which property we couldn't set
7467 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7468 "could not set object property list.");
7469 free(properties);
7470 return -1;
7471 }
7472 }
7473
7474 } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
7475 for (i=0;i<propcnt;i++) {
7476 switch (properties[i]) {
7477 case PTP_OPC_Name:
7478 // Update title
7479 ret = set_object_string(device, objecthandle, PTP_OPC_Name, name);
7480 if (ret != 0) {
7481 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7482 "could not set title.");
7483 }
7484 break;
7485 case PTP_OPC_AlbumArtist:
7486 // Update album artist
7487 ret = set_object_string(device, objecthandle, PTP_OPC_AlbumArtist, artist);
7488 if (ret != 0) {
7489 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7490 "could not set album artist name.");
7491 }
7492 break;
7493 case PTP_OPC_Artist:
7494 // Update artist
7495 ret = set_object_string(device, objecthandle, PTP_OPC_Artist, artist);
7496 if (ret != 0) {
7497 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7498 "could not set artist name.");
7499 }
7500 case PTP_OPC_Composer:
7501 // Update composer
7502 ret = set_object_string(device, objecthandle, PTP_OPC_Composer, composer);
7503 if (ret != 0) {
7504 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7505 "could not set composer name.");
7506 }
7507 break;
7508 case PTP_OPC_Genre:
7509 // Update genre
7510 ret = set_object_string(device, objecthandle, PTP_OPC_Genre, genre);
7511 if (ret != 0) {
7512 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7513 "could not set genre.");
7514 }
7515 break;
7516 case PTP_OPC_DateModified:
7517 // Update date modified
7518 if (!FLAG_CANNOT_HANDLE_DATEMODIFIED(ptp_usb)) {
7519 char *tmpdate = get_iso8601_stamp();
7520 ret = set_object_string(device, objecthandle, PTP_OPC_DateModified, tmpdate);
7521 if (ret != 0) {
7522 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7523 "could not set modification date.");
7524 }
7525 free(tmpdate);
7526 }
7527 default:
7528 break;
7529 }
7530 }
7531 } else {
7532 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
7533 "Your device doesn't seem to support any known way of setting metadata.");
7534 free(properties);
7535 return -1;
7536 }
7537
7538 // Then the object references...
7539 ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
7540 if (ret != PTP_RC_OK) {
7541 add_ptp_error_to_errorstack(device, ret, "update_abstract_list(): could not add tracks as object references.");
7542 free(properties);
7543 return -1;
7544 }
7545
7546 free(properties);
7547
7548 update_metadata_cache(device, objecthandle);
7549
7550 return 0;
7551 }
7552
7553
7554 /**
7555 * This routine creates a new playlist based on the metadata
7556 * supplied. If the <code>tracks</code> field of the metadata
7557 * contains a track listing, these tracks will be added to the
7558 * playlist.
7559 * @param device a pointer to the device to create the new playlist on.
7560 * @param metadata the metadata for the new playlist. If the function
7561 * exits with success, the <code>playlist_id</code> field of this
7562 * struct will contain the new playlist ID of the playlist.
7563 * <ul>
7564 * <li><code>metadata->parent_id</code> should be set to the parent
7565 * (e.g. folder) to store this track in. Since some
7566 * devices are a bit picky about where files
7567 * are placed, a default folder will be chosen if libmtp
7568 * has detected one for the current filetype and this
7569 * parameter is set to 0. If this is 0 and no default folder
7570 * can be found, the file will be stored in the root folder.
7571 * <li><code>metadata->storage_id</code> should be set to the
7572 * desired storage (e.g. memory card or whatever your device
7573 * presents) to store this track in. Setting this to 0 will store
7574 * the track on the primary storage.
7575 * </ul>
7576 * @return 0 on success, any other value means failure.
7577 * @see LIBMTP_Update_Playlist()
7578 * @see LIBMTP_Delete_Object()
7579 */
7580 int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
7581 LIBMTP_playlist_t * const metadata)
7582 {
7583 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7584 uint32_t localph = metadata->parent_id;
7585
7586 // Use a default folder if none given
7587 if (localph == 0) {
7588 if (device->default_playlist_folder != 0)
7589 localph = device->default_playlist_folder;
7590 else
7591 localph = device->default_music_folder;
7592 }
7593 metadata->parent_id = localph;
7594
7595 // Samsung needs its own special type of playlists
7596 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
7597 return playlist_t_to_spl(device, metadata);
7598 }
7599
7600 // Just create a new abstract audio/video playlist...
7601 return create_new_abstract_list(device,
7602 metadata->name,
7603 NULL,
7604 NULL,
7605 NULL,
7606 localph,
7607 metadata->storage_id,
7608 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7609 get_playlist_extension(ptp_usb),
7610 &metadata->playlist_id,
7611 metadata->tracks,
7612 metadata->no_tracks);
7613 }
7614
7615 /**
7616 * This routine updates a playlist based on the metadata
7617 * supplied. If the <code>tracks</code> field of the metadata
7618 * contains a track listing, these tracks will be added to the
7619 * playlist in place of those already present, i.e. the
7620 * previous track listing will be deleted. For Samsung devices the
7621 * playlist id (metadata->playlist_id) is likely to change.
7622 * @param device a pointer to the device to create the new playlist on.
7623 * @param metadata the metadata for the playlist to be updated.
7624 * notice that the field <code>playlist_id</code>
7625 * must contain the apropriate playlist ID. Playlist ID
7626 * be modified to a new playlist ID by the time the
7627 * function returns since edit-in-place is not always possible.
7628 * @return 0 on success, any other value means failure.
7629 * @see LIBMTP_Create_New_Playlist()
7630 * @see LIBMTP_Delete_Object()
7631 */
7632 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
7633 LIBMTP_playlist_t * const metadata)
7634 {
7635
7636 // Samsung needs its own special type of playlists
7637 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
7638 if(FLAG_PLAYLIST_SPL(ptp_usb)) {
7639 return update_spl_playlist(device, metadata);
7640 }
7641
7642 return update_abstract_list(device,
7643 metadata->name,
7644 NULL,
7645 NULL,
7646 NULL,
7647 metadata->playlist_id,
7648 PTP_OFC_MTP_AbstractAudioVideoPlaylist,
7649 metadata->tracks,
7650 metadata->no_tracks);
7651 }
7652
7653 /**
7654 * This creates a new album metadata structure and allocates memory
7655 * for it. Notice that if you add strings to this structure they
7656 * will be freed by the corresponding <code>LIBMTP_destroy_album_t</code>
7657 * operation later, so be careful of using strdup() when assigning
7658 * strings.
7659 *
7660 * @return a pointer to the newly allocated metadata structure.
7661 * @see LIBMTP_destroy_album_t()
7662 */
7663 LIBMTP_album_t *LIBMTP_new_album_t(void)
7664 {
7665 LIBMTP_album_t *new = (LIBMTP_album_t *) malloc(sizeof(LIBMTP_album_t));
7666 if (new == NULL) {
7667 return NULL;
7668 }
7669 new->album_id = 0;
7670 new->parent_id = 0;
7671 new->storage_id = 0;
7672 new->name = NULL;
7673 new->artist = NULL;
7674 new->composer = NULL;
7675 new->genre = NULL;
7676 new->tracks = NULL;
7677 new->no_tracks = 0;
7678 new->next = NULL;
7679 return new;
7680 }
7681
7682 /**
7683 * This recursively deletes the memory for an album structure
7684 *
7685 * @param album structure to destroy
7686 * @see LIBMTP_new_album_t()
7687 */
7688 void LIBMTP_destroy_album_t(LIBMTP_album_t *album)
7689 {
7690 if (album == NULL) {
7691 return;
7692 }
7693 if (album->name != NULL)
7694 free(album->name);
7695 if (album->artist != NULL)
7696 free(album->artist);
7697 if (album->composer != NULL)
7698 free(album->composer);
7699 if (album->genre != NULL)
7700 free(album->genre);
7701 if (album->tracks != NULL)
7702 free(album->tracks);
7703 free(album);
7704 return;
7705 }
7706
7707 /**
7708 * This function maps and copies a property onto the album metadata if applicable.
7709 */
7710 static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
7711 MTPProperties *prop, LIBMTP_album_t *alb)
7712 {
7713 switch (prop->property) {
7714 case PTP_OPC_Name:
7715 if (prop->propval.str != NULL)
7716 alb->name = strdup(prop->propval.str);
7717 else
7718 alb->name = NULL;
7719 break;
7720 case PTP_OPC_AlbumArtist:
7721 if (prop->propval.str != NULL) {
7722 // This should take precedence over plain "Artist"
7723 if (alb->artist != NULL)
7724 free(alb->artist);
7725 alb->artist = strdup(prop->propval.str);
7726 } else
7727 alb->artist = NULL;
7728 break;
7729 case PTP_OPC_Artist:
7730 if (prop->propval.str != NULL) {
7731 // Only use of AlbumArtist is not set
7732 if (alb->artist == NULL)
7733 alb->artist = strdup(prop->propval.str);
7734 } else
7735 alb->artist = NULL;
7736 break;
7737 case PTP_OPC_Composer:
7738 if (prop->propval.str != NULL)
7739 alb->composer = strdup(prop->propval.str);
7740 else
7741 alb->composer = NULL;
7742 break;
7743 case PTP_OPC_Genre:
7744 if (prop->propval.str != NULL)
7745 alb->genre = strdup(prop->propval.str);
7746 else
7747 alb->genre = NULL;
7748 break;
7749 }
7750 }
7751
7752 /**
7753 * This function retrieves the album metadata for an album
7754 * given by a unique ID.
7755 * @param device a pointer to the device to get the track metadata off.
7756 * @param alb an album metadata metadata set to fill in.
7757 */
7758 static void get_album_metadata(LIBMTP_mtpdevice_t *device,
7759 LIBMTP_album_t *alb)
7760 {
7761 uint16_t ret;
7762 PTPParams *params = (PTPParams *) device->params;
7763 uint32_t i;
7764 MTPProperties *prop;
7765 PTPObject *ob;
7766
7767 /*
7768 * If we have a cached, large set of metadata, then use it!
7769 */
7770 ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
7771 if (ob->mtpprops) {
7772 prop = ob->mtpprops;
7773 for (i=0;i<ob->nrofmtpprops;i++,prop++)
7774 pick_property_to_album_metadata(device, prop, alb);
7775 } else {
7776 uint16_t *props = NULL;
7777 uint32_t propcnt = 0;
7778
7779 // First see which properties can be retrieved for albums
7780 ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
7781 if (ret != PTP_RC_OK) {
7782 add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
7783 // Just bail out for now, nothing is ever set.
7784 return;
7785 } else {
7786 for (i=0;i<propcnt;i++) {
7787 switch (props[i]) {
7788 case PTP_OPC_Name:
7789 alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
7790 break;
7791 case PTP_OPC_AlbumArtist:
7792 if (alb->artist != NULL)
7793 free(alb->artist);
7794 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
7795 break;
7796 case PTP_OPC_Artist:
7797 if (alb->artist == NULL)
7798 alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
7799 break;
7800 case PTP_OPC_Composer:
7801 alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
7802 break;
7803 case PTP_OPC_Genre:
7804 alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
7805 break;
7806 default:
7807 break;
7808 }
7809 }
7810 free(props);
7811 }
7812 }
7813 }
7814
7815 /**
7816 * This function returns a list of the albums available on the
7817 * device.
7818 *
7819 * @param device a pointer to the device to get the album listing from.
7820 * @return an album list on success, else NULL. If there are no albums
7821 * on the device, NULL will be returned as well.
7822 * @see LIBMTP_Get_Album()
7823 */
7824 LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
7825 {
7826 PTPParams *params = (PTPParams *) device->params;
7827 LIBMTP_album_t *retalbums = NULL;
7828 LIBMTP_album_t *curalbum = NULL;
7829 uint32_t i;
7830
7831 // Get all the handles if we haven't already done that
7832 if (params->nrofobjects == 0)
7833 flush_handles(device);
7834
7835 for (i = 0; i < params->nrofobjects; i++) {
7836 LIBMTP_album_t *alb;
7837 PTPObject *ob;
7838 uint16_t ret;
7839
7840 ob = ¶ms->objects[i];
7841
7842 // Ignore stuff that isn't an album
7843 if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
7844 continue;
7845
7846 // Allocate a new album type
7847 alb = LIBMTP_new_album_t();
7848 alb->album_id = ob->oid;
7849 alb->parent_id = ob->oi.ParentObject;
7850 alb->storage_id = ob->oi.StorageID;
7851
7852 // Fetch supported metadata
7853 get_album_metadata(device, alb);
7854
7855 // Then get the track listing for this album
7856 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
7857 if (ret != PTP_RC_OK) {
7858 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album_List(): Could not get object references.");
7859 alb->tracks = NULL;
7860 alb->no_tracks = 0;
7861 }
7862
7863 // Add album to a list that will be returned afterwards.
7864 if (retalbums == NULL) {
7865 retalbums = alb;
7866 curalbum = alb;
7867 } else {
7868 curalbum->next = alb;
7869 curalbum = alb;
7870 }
7871
7872 }
7873 return retalbums;
7874 }
7875
7876 /**
7877 * This function retrieves an individual album from the device.
7878 * @param device a pointer to the device to get the album from.
7879 * @param albid the unique ID of the album to retrieve.
7880 * @return a valid album metadata or NULL on failure.
7881 * @see LIBMTP_Get_Album_List()
7882 */
7883 LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
7884 {
7885 PTPParams *params = (PTPParams *) device->params;
7886 uint16_t ret;
7887 PTPObject *ob;
7888 LIBMTP_album_t *alb;
7889
7890 // Get all the handles if we haven't already done that
7891 if (params->nrofobjects == 0)
7892 flush_handles(device);
7893
7894 ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
7895 if (ret != PTP_RC_OK)
7896 return NULL;
7897
7898 // Ignore stuff that isn't an album
7899 if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
7900 return NULL;
7901
7902 // Allocate a new album type
7903 alb = LIBMTP_new_album_t();
7904 alb->album_id = ob->oid;
7905 alb->parent_id = ob->oi.ParentObject;
7906 alb->storage_id = ob->oi.StorageID;
7907
7908 // Fetch supported metadata
7909 get_album_metadata(device, alb);
7910
7911 // Then get the track listing for this album
7912 ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
7913 if (ret != PTP_RC_OK) {
7914 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
7915 alb->tracks = NULL;
7916 alb->no_tracks = 0;
7917 }
7918
7919 return alb;
7920 }
7921
7922 /**
7923 * This routine creates a new album based on the metadata
7924 * supplied. If the <code>tracks</code> field of the metadata
7925 * contains a track listing, these tracks will be added to the
7926 * album.
7927 * @param device a pointer to the device to create the new album on.
7928 * @param metadata the metadata for the new album. If the function
7929 * exits with success, the <code>album_id</code> field of this
7930 * struct will contain the new ID of the album.
7931 * <ul>
7932 * <li><code>metadata->parent_id</code> should be set to the parent
7933 * (e.g. folder) to store this track in. Since some
7934 * devices are a bit picky about where files
7935 * are placed, a default folder will be chosen if libmtp
7936 * has detected one for the current filetype and this
7937 * parameter is set to 0. If this is 0 and no default folder
7938 * can be found, the file will be stored in the root folder.
7939 * <li><code>metadata->storage_id</code> should be set to the
7940 * desired storage (e.g. memory card or whatever your device
7941 * presents) to store this track in. Setting this to 0 will store
7942 * the track on the primary storage.
7943 * </ul>
7944 * @return 0 on success, any other value means failure.
7945 * @see LIBMTP_Update_Album()
7946 * @see LIBMTP_Delete_Object()
7947 */
7948 int LIBMTP_Create_New_Album(LIBMTP_mtpdevice_t *device,
7949 LIBMTP_album_t * const metadata)
7950 {
7951 uint32_t localph = metadata->parent_id;
7952
7953 // Use a default folder if none given
7954 if (localph == 0) {
7955 if (device->default_album_folder != 0)
7956 localph = device->default_album_folder;
7957 else
7958 localph = device->default_music_folder;
7959 }
7960 metadata->parent_id = localph;
7961
7962 // Just create a new abstract album...
7963 return create_new_abstract_list(device,
7964 metadata->name,
7965 metadata->artist,
7966 metadata->composer,
7967 metadata->genre,
7968 localph,
7969 metadata->storage_id,
7970 PTP_OFC_MTP_AbstractAudioAlbum,
7971 ".alb",
7972 &metadata->album_id,
7973 metadata->tracks,
7974 metadata->no_tracks);
7975 }
7976
7977 /**
7978 * This creates a new sample data metadata structure and allocates memory
7979 * for it. Notice that if you add strings to this structure they
7980 * will be freed by the corresponding <code>LIBMTP_destroy_sampledata_t</code>
7981 * operation later, so be careful of using strdup() when assigning
7982 * strings.
7983 *
7984 * @return a pointer to the newly allocated metadata structure.
7985 * @see LIBMTP_destroy_sampledata_t()
7986 */
7987 LIBMTP_filesampledata_t *LIBMTP_new_filesampledata_t(void)
7988 {
7989 LIBMTP_filesampledata_t *new = (LIBMTP_filesampledata_t *) malloc(sizeof(LIBMTP_filesampledata_t));
7990 if (new == NULL) {
7991 return NULL;
7992 }
7993 new->height=0;
7994 new->width = 0;
7995 new->data = NULL;
7996 new->duration = 0;
7997 new->size = 0;
7998 return new;
7999 }
8000
8001 /**
8002 * This destroys a file sample metadata type.
8003 * @param sample the file sample metadata to be destroyed.
8004 */
8005 void LIBMTP_destroy_filesampledata_t(LIBMTP_filesampledata_t * sample)
8006 {
8007 if (sample == NULL) {
8008 return;
8009 }
8010 if (sample->data != NULL) {
8011 free(sample->data);
8012 }
8013 free(sample);
8014 }
8015
8016 /**
8017 * This routine figures out whether a certain filetype supports
8018 * representative samples (small thumbnail images) or not. This
8019 * typically applies to JPEG files, MP3 files and Album abstract
8020 * playlists, but in theory any filetype could support representative
8021 * samples.
8022 * @param device a pointer to the device which is to be examined.
8023 * @param filetype the fileype to examine, and return the representative sample
8024 * properties for.
8025 * @param sample this will contain a new sample type with the fields
8026 * filled in with suitable default values. For example, the
8027 * supported sample type will be set, the supported height and
8028 * width will be set to max values if it is an image sample,
8029 * and duration will also be given some suitable default value
8030 * which should not be exceeded on audio samples. If the
8031 * device does not support samples for this filetype, this
8032 * pointer will be NULL. If it is not NULL, the user must
8033 * destroy this struct with <code>LIBMTP_destroy_filesampledata_t()</code>
8034 * after use.
8035 * @return 0 on success, any other value means failure.
8036 * @see LIBMTP_Send_Representative_Sample()
8037 * @see LIBMTP_Create_New_Album()
8038 */
8039 int LIBMTP_Get_Representative_Sample_Format(LIBMTP_mtpdevice_t *device,
8040 LIBMTP_filetype_t const filetype,
8041 LIBMTP_filesampledata_t ** sample)
8042 {
8043 uint16_t ret;
8044 PTPParams *params = (PTPParams *) device->params;
8045 uint16_t *props = NULL;
8046 uint32_t propcnt = 0;
8047 int i;
8048 // TODO: Get rid of these when we can properly query the device.
8049 int support_data = 0;
8050 int support_format = 0;
8051 int support_height = 0;
8052 int support_width = 0;
8053 int support_duration = 0;
8054 int support_size = 0;
8055
8056 PTPObjectPropDesc opd_height;
8057 PTPObjectPropDesc opd_width;
8058 PTPObjectPropDesc opd_format;
8059 PTPObjectPropDesc opd_duration;
8060 PTPObjectPropDesc opd_size;
8061
8062 // Default to no type supported.
8063 *sample = NULL;
8064
8065 ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
8066 if (ret != PTP_RC_OK) {
8067 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample_Format(): could not get object properties.");
8068 return -1;
8069 }
8070 /*
8071 * TODO: when walking through these object properties, make calls to
8072 * a new function in ptp.h/ptp.c that can send the command
8073 * PTP_OC_MTP_GetObjectPropDesc to get max/min values of the properties
8074 * supported.
8075 */
8076 for (i = 0; i < propcnt; i++) {
8077 switch(props[i]) {
8078 case PTP_OPC_RepresentativeSampleData:
8079 support_data = 1;
8080 break;
8081 case PTP_OPC_RepresentativeSampleFormat:
8082 support_format = 1;
8083 break;
8084 case PTP_OPC_RepresentativeSampleSize:
8085 support_size = 1;
8086 break;
8087 case PTP_OPC_RepresentativeSampleHeight:
8088 support_height = 1;
8089 break;
8090 case PTP_OPC_RepresentativeSampleWidth:
8091 support_width = 1;
8092 break;
8093 case PTP_OPC_RepresentativeSampleDuration:
8094 support_duration = 1;
8095 break;
8096 default:
8097 break;
8098 }
8099 }
8100 free(props);
8101
8102 if (support_data && support_format && support_height && support_width && !support_duration) {
8103 // Something that supports height and width and not duration is likely to be JPEG
8104 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8105 /*
8106 * Populate the sample format with the first supported format
8107 *
8108 * TODO: figure out how to pass back more than one format if more are
8109 * supported by the device.
8110 */
8111 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8112 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8113 ptp_free_objectpropdesc(&opd_format);
8114 /* Populate the maximum image height */
8115 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);
8116 retsam->width = opd_width.FORM.Range.MaximumValue.u32;
8117 ptp_free_objectpropdesc(&opd_width);
8118 /* Populate the maximum image width */
8119 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);
8120 retsam->height = opd_height.FORM.Range.MaximumValue.u32;
8121 ptp_free_objectpropdesc(&opd_height);
8122 /* Populate the maximum size */
8123 if (support_size) {
8124 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8125 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8126 ptp_free_objectpropdesc(&opd_size);
8127 }
8128 *sample = retsam;
8129 } else if (support_data && support_format && !support_height && !support_width && support_duration) {
8130 // Another qualified guess
8131 LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
8132 /*
8133 * Populate the sample format with the first supported format
8134 *
8135 * TODO: figure out how to pass back more than one format if more are
8136 * supported by the device.
8137 */
8138 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);
8139 retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
8140 ptp_free_objectpropdesc(&opd_format);
8141 /* Populate the maximum duration */
8142 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);
8143 retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
8144 ptp_free_objectpropdesc(&opd_duration);
8145 /* Populate the maximum size */
8146 if (support_size) {
8147 ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
8148 retsam->size = opd_size.FORM.Range.MaximumValue.u32;
8149 ptp_free_objectpropdesc(&opd_size);
8150 }
8151 *sample = retsam;
8152 }
8153 return 0;
8154 }
8155
8156 /**
8157 * This routine sends representative sample data for an object.
8158 * This uses the RepresentativeSampleData property of the album,
8159 * if the device supports it. The data should be of a format acceptable
8160 * to the player (for iRiver and Creative, this seems to be JPEG) and
8161 * must not be too large. (for a Creative, max seems to be about 20KB.)
8162 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
8163 * maximum size, dimensions, etc..
8164 * @param device a pointer to the device which the object is on.
8165 * @param id unique id of the object to set artwork for.
8166 * @param pointer to LIBMTP_filesampledata_t struct containing data
8167 * @return 0 on success, any other value means failure.
8168 * @see LIBMTP_Get_Representative_Sample()
8169 * @see LIBMTP_Get_Representative_Sample_Format()
8170 * @see LIBMTP_Create_New_Album()
8171 */
8172 int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
8173 uint32_t const id,
8174 LIBMTP_filesampledata_t *sampledata)
8175 {
8176 uint16_t ret;
8177 PTPParams *params = (PTPParams *) device->params;
8178 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
8179 PTPPropertyValue propval;
8180 PTPObject *ob;
8181 uint32_t i;
8182 uint16_t *props = NULL;
8183 uint32_t propcnt = 0;
8184 int supported = 0;
8185
8186 // get the file format for the object we're going to send representative data for
8187 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8188 if (ret != PTP_RC_OK) {
8189 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
8190 return -1;
8191 }
8192
8193 // check that we can send representative sample data for this object format
8194 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8195 if (ret != PTP_RC_OK) {
8196 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
8197 return -1;
8198 }
8199
8200 for (i = 0; i < propcnt; i++) {
8201 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8202 supported = 1;
8203 break;
8204 }
8205 }
8206 if (!supported) {
8207 free(props);
8208 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8209 return -1;
8210 }
8211 free(props);
8212
8213 // Go ahead and send the data
8214 propval.a.count = sampledata->size;
8215 propval.a.v = malloc(sizeof(PTPPropertyValue) * sampledata->size);
8216 for (i = 0; i < sampledata->size; i++) {
8217 propval.a.v[i].u8 = sampledata->data[i];
8218 }
8219
8220 ret = ptp_mtp_setobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8221 &propval,PTP_DTC_AUINT8);
8222 if (ret != PTP_RC_OK) {
8223 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not send sample data.");
8224 free(propval.a.v);
8225 return -1;
8226 }
8227 free(propval.a.v);
8228
8229 /* Set the height and width if the sample is an image, otherwise just
8230 * set the duration and size */
8231 switch(sampledata->filetype) {
8232 case LIBMTP_FILETYPE_JPEG:
8233 case LIBMTP_FILETYPE_JFIF:
8234 case LIBMTP_FILETYPE_TIFF:
8235 case LIBMTP_FILETYPE_BMP:
8236 case LIBMTP_FILETYPE_GIF:
8237 case LIBMTP_FILETYPE_PICT:
8238 case LIBMTP_FILETYPE_PNG:
8239 if (!FLAG_BROKEN_SET_SAMPLE_DIMENSIONS(ptp_usb)) {
8240 // For images, set the height and width
8241 set_object_u32(device, id, PTP_OPC_RepresentativeSampleHeight, sampledata->height);
8242 set_object_u32(device, id, PTP_OPC_RepresentativeSampleWidth, sampledata->width);
8243 }
8244 break;
8245 default:
8246 // For anything not an image, set the duration and size
8247 set_object_u32(device, id, PTP_OPC_RepresentativeSampleDuration, sampledata->duration);
8248 set_object_u32(device, id, PTP_OPC_RepresentativeSampleSize, sampledata->size);
8249 break;
8250 }
8251
8252 return 0;
8253 }
8254
8255 /**
8256 * This routine gets representative sample data for an object.
8257 * This uses the RepresentativeSampleData property of the album,
8258 * if the device supports it.
8259 * @param device a pointer to the device which the object is on.
8260 * @param id unique id of the object to get data for.
8261 * @param pointer to LIBMTP_filesampledata_t struct to receive data
8262 * @return 0 on success, any other value means failure.
8263 * @see LIBMTP_Send_Representative_Sample()
8264 * @see LIBMTP_Get_Representative_Sample_Format()
8265 * @see LIBMTP_Create_New_Album()
8266 */
8267 int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
8268 uint32_t const id,
8269 LIBMTP_filesampledata_t *sampledata)
8270 {
8271 uint16_t ret;
8272 PTPParams *params = (PTPParams *) device->params;
8273 PTPPropertyValue propval;
8274 PTPObject *ob;
8275 uint32_t i;
8276 uint16_t *props = NULL;
8277 uint32_t propcnt = 0;
8278 int supported = 0;
8279
8280 // get the file format for the object we're going to send representative data for
8281 ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
8282 if (ret != PTP_RC_OK) {
8283 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
8284 return -1;
8285 }
8286
8287 // check that we can store representative sample data for this object format
8288 ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
8289 if (ret != PTP_RC_OK) {
8290 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
8291 return -1;
8292 }
8293
8294 for (i = 0; i < propcnt; i++) {
8295 if (props[i] == PTP_OPC_RepresentativeSampleData) {
8296 supported = 1;
8297 break;
8298 }
8299 }
8300 if (!supported) {
8301 free(props);
8302 add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): object type doesn't support RepresentativeSampleData.");
8303 return -1;
8304 }
8305 free(props);
8306
8307 // Get the data
8308 ret = ptp_mtp_getobjectpropvalue(params,id,PTP_OPC_RepresentativeSampleData,
8309 &propval,PTP_DTC_AUINT8);
8310 if (ret != PTP_RC_OK) {
8311 add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get sample data.");
8312 return -1;
8313 }
8314
8315 // Store it
8316 sampledata->size = propval.a.count;
8317 sampledata->data = malloc(sizeof(PTPPropertyValue) * propval.a.count);
8318 for (i = 0; i < propval.a.count; i++) {
8319 sampledata->data[i] = propval.a.v[i].u8;
8320 }
8321 free(propval.a.v);
8322
8323 // Get the other properties
8324 sampledata->width = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleWidth, 0);
8325 sampledata->height = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleHeight, 0);
8326 sampledata->duration = get_u32_from_object(device, id, PTP_OPC_RepresentativeSampleDuration, 0);
8327 sampledata->filetype = map_ptp_type_to_libmtp_type(
8328 get_u16_from_object(device, id, PTP_OPC_RepresentativeSampleFormat, LIBMTP_FILETYPE_UNKNOWN));
8329
8330 return 0;
8331 }
8332
8333 /**
8334 * This routine updates an album based on the metadata
8335 * supplied. If the <code>tracks</code> field of the metadata
8336 * contains a track listing, these tracks will be added to the
8337 * album in place of those already present, i.e. the
8338 * previous track listing will be deleted.
8339 * @param device a pointer to the device to create the new album on.
8340 * @param metadata the metadata for the album to be updated.
8341 * notice that the field <code>album_id</code>
8342 * must contain the apropriate album ID.
8343 * @return 0 on success, any other value means failure.
8344 * @see LIBMTP_Create_New_Album()
8345 * @see LIBMTP_Delete_Object()
8346 */
8347 int LIBMTP_Update_Album(LIBMTP_mtpdevice_t *device,
8348 LIBMTP_album_t const * const metadata)
8349 {
8350 return update_abstract_list(device,
8351 metadata->name,
8352 metadata->artist,
8353 metadata->composer,
8354 metadata->genre,
8355 metadata->album_id,
8356 PTP_OFC_MTP_AbstractAudioAlbum,
8357 metadata->tracks,
8358 metadata->no_tracks);
8359 }
8360
8361 /**
8362 * Dummy function needed to interface to upstream
8363 * ptp.c/ptp.h files.
8364 */
8365 void ptp_nikon_getptpipguid (unsigned char* guid) {
8366 return;
8367 }
8368
8369 /**
8370 * Add an object to cache.
8371 * @param device the device which may have a cache to which the object should be added.
8372 * @param object_id the object to add to the cache.
8373 */
8374 static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
8375 {
8376 PTPParams *params = (PTPParams *)device->params;
8377 uint16_t ret;
8378
8379 ret = ptp_add_object_to_cache(params, object_id);
8380 if (ret != PTP_RC_OK) {
8381 add_ptp_error_to_errorstack(device, ret, "add_object_to_cache(): couldn't add object to cache");
8382 }
8383 }
8384
8385
8386 /**
8387 * Update cache after object has been modified
8388 * @param device the device which may have a cache to which the object should be updated.
8389 * @param object_id the object to update.
8390 */
8391 static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id)
8392 {
8393 PTPParams *params = (PTPParams *)device->params;
8394
8395 ptp_remove_object_from_cache(params, object_id);
8396 add_object_to_cache(device, object_id);
8397 }
8398