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