~ubuntu-branches/ubuntu/precise/libmtp/precise-proposed

« back to all changes in this revision

Viewing changes to src/libmtp.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2009-12-14 22:32:10 UTC
  • mto: (16.1.3 sid) (0.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20091214223210-vekc5340wzmz54bw
Tags: upstream-1.0.1
ImportĀ upstreamĀ versionĀ 1.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
 * The files libusb-glue.c/.h are just what they say: an
35
35
 * interface to libusb for the actual, physical USB traffic.
36
36
 */
37
 
#define _LARGEFILE_SOURCE
38
 
#define _LARGEFILE64_SOURCE
39
 
 
 
37
#include "config.h"
40
38
#include "libmtp.h"
41
39
#include "unicode.h"
42
40
#include "ptp.h"
74
72
  struct filemap_struct *next;
75
73
} filemap_t;
76
74
 
 
75
/*
 
76
 * This is a mapping between libmtp internal MTP properties and
 
77
 * the libgphoto2/PTP equivalent defines. We need this because
 
78
 * otherwise the libmtp.h device has to be dependent on ptp.h
 
79
 * to be installed too, and we don't want that.
 
80
 */
 
81
typedef struct propertymap_struct {
 
82
  char *description; /**< Text description for the property */
 
83
  LIBMTP_property_t id; /**< LIBMTP internal type for the property */
 
84
  uint16_t ptp_id; /**< PTP ID for the property */
 
85
  struct propertymap_struct *next;
 
86
} propertymap_t;
 
87
 
77
88
// Global variables
78
89
// This holds the global filetype mapping table
79
90
static filemap_t *filemap = NULL;
 
91
// This holds the global property mapping table
 
92
static propertymap_t *propertymap = NULL;
80
93
 
81
94
/*
82
95
 * Forward declarations of local (static) functions.
84
97
static int register_filetype(char const * const description, LIBMTP_filetype_t const id,
85
98
                             uint16_t const ptp_id);
86
99
static void init_filemap();
 
100
static int register_property(char const * const description, LIBMTP_property_t const id,
 
101
                             uint16_t const ptp_id);
 
102
static void init_propertymap();
87
103
static void add_error_to_errorstack(LIBMTP_mtpdevice_t *device,
88
104
                                    LIBMTP_error_number_t errornumber,
89
105
                                    char const * const error_text);
93
109
static void flush_handles(LIBMTP_mtpdevice_t *device);
94
110
static void get_handles_recursively(LIBMTP_mtpdevice_t *device, 
95
111
                                    PTPParams *params, 
96
 
                                    PTPObjectHandles *handles, 
97
112
                                    uint32_t storageid,
98
113
                                    uint32_t parent);
99
114
static void free_storage_list(LIBMTP_mtpdevice_t *device);
107
122
                              uint64_t const filesize);
108
123
static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);
109
124
static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);
 
125
static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty);
 
126
static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t intype);
110
127
static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,
111
128
                                       char **unicstring, uint16_t property);
112
129
static uint16_t adjust_u16(uint16_t val, PTPObjectPropDesc *opd);
154
171
                                uint16_t const objectformat,
155
172
                                uint32_t const * const tracks,
156
173
                                uint32_t const no_tracks);
 
174
static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata);
157
175
static void add_object_to_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
158
176
static void update_metadata_cache(LIBMTP_mtpdevice_t *device, uint32_t object_id);
159
177
static int set_object_filename(LIBMTP_mtpdevice_t *device,
160
178
                uint32_t object_id,
161
179
                uint16_t ptp_type,
162
180
                const char **newname);
 
181
                
 
182
/**
 
183
 * These are to wrap the get/put handlers to convert from the MTP types to PTP types
 
184
 * in a reliable way
 
185
 */
 
186
typedef struct _MTPDataHandler {
 
187
        MTPDataGetFunc          getfunc;
 
188
        MTPDataPutFunc          putfunc;
 
189
        void                    *priv;
 
190
} MTPDataHandler;
163
191
 
 
192
static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen);
 
193
static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen);
 
194
                
164
195
/**
165
196
 * Checks if a filename ends with ".ogg". Used in various
166
197
 * situations when the device has no idea that it support
183
214
  return 0;
184
215
}
185
216
 
 
217
/**
 
218
 * Checks if a filename ends with ".flac". Used in various
 
219
 * situations when the device has no idea that it support
 
220
 * FLAC but still does.
 
221
 *
 
222
 * @param name string to be checked.
 
223
 * @return 0 if this does not end with flac, any other
 
224
 *           value means it does.
 
225
 */
 
226
static int has_flac_extension(char *name) {
 
227
  char *ptype;
 
228
 
 
229
  if (name == NULL)
 
230
    return 0;
 
231
  ptype = strrchr(name,'.');
 
232
  if (ptype == NULL)
 
233
    return 0;
 
234
  if (!strcasecmp (ptype, ".flac"))
 
235
    return 1;
 
236
  return 0;
 
237
}
 
238
 
 
239
 
186
240
 
187
241
/**
188
242
 * Create a new file mapping entry
272
326
  register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);
273
327
  register_filetype("Free Lossless Audio Codec (FLAC)", LIBMTP_FILETYPE_FLAC, PTP_OFC_MTP_FLAC);
274
328
  register_filetype("Advanced Audio Coding (AAC)/MPEG-2 Part 7/MPEG-4 Part 3", LIBMTP_FILETYPE_AAC, PTP_OFC_MTP_AAC);
275
 
  register_filetype("MPEG-4 Part 14 Container Format (Audio Empahsis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
276
 
  register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Empahsis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
 
329
  register_filetype("MPEG-4 Part 14 Container Format (Audio Emphasis)", LIBMTP_FILETYPE_M4A, PTP_OFC_MTP_M4A);
 
330
  register_filetype("MPEG-4 Part 14 Container Format (Audio+Video Emphasis)", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);
277
331
  register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);
278
332
  register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);
279
333
  register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);
305
359
  register_filetype("PPT file", LIBMTP_FILETYPE_PPT, PTP_OFC_MTP_MSPowerpointPresentationPPT);
306
360
  register_filetype("MHT file", LIBMTP_FILETYPE_MHT, PTP_OFC_MTP_MHTCompiledHTMLDocument);
307
361
  register_filetype("Firmware file", LIBMTP_FILETYPE_FIRMWARE, PTP_OFC_MTP_Firmware);
 
362
  register_filetype("Abstract Album file", LIBMTP_FILETYPE_ALBUM, PTP_OFC_MTP_AbstractAudioAlbum);
 
363
  register_filetype("Abstract Playlist file", LIBMTP_FILETYPE_PLAYLIST, PTP_OFC_MTP_AbstractAudioVideoPlaylist);
308
364
  register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);
309
365
}
310
366
 
352
408
  return LIBMTP_FILETYPE_UNKNOWN;
353
409
}
354
410
 
 
411
/**
 
412
 * Create a new property mapping entry
 
413
 * @return a newly allocated propertymapping entry.
 
414
 */
 
415
static propertymap_t *new_propertymap_entry()
 
416
{
 
417
  propertymap_t *propertymap;
 
418
 
 
419
  propertymap = (propertymap_t *)malloc(sizeof(propertymap_t));
 
420
 
 
421
  if( propertymap != NULL ) {
 
422
    propertymap->description = NULL;
 
423
    propertymap->id = LIBMTP_PROPERTY_UNKNOWN;
 
424
    propertymap->ptp_id = 0;
 
425
    propertymap->next = NULL;
 
426
  }
 
427
 
 
428
  return propertymap;
 
429
}
 
430
 
 
431
/**
 
432
 * Register an MTP or PTP property for data retrieval
 
433
 *
 
434
 * @param description Text description of property
 
435
 * @param id libmtp internal property id
 
436
 * @param ptp_id PTP property id
 
437
 * @return 0 for success any other value means error.
 
438
*/
 
439
static int register_property(char const * const description, LIBMTP_property_t const id,
 
440
                             uint16_t const ptp_id)
 
441
{
 
442
  propertymap_t *new = NULL, *current;
 
443
 
 
444
  // Has this LIBMTP propety been registered before ?
 
445
  current = propertymap;
 
446
  while (current != NULL) {
 
447
    if(current->id == id) {
 
448
      break;
 
449
    }
 
450
    current = current->next;
 
451
  }
 
452
 
 
453
  // Create the entry
 
454
  if(current == NULL) {
 
455
    new = new_propertymap_entry();
 
456
    if(new == NULL) {
 
457
      return 1;
 
458
    }
 
459
 
 
460
    new->id = id;
 
461
    if(description != NULL) {
 
462
      new->description = strdup(description);
 
463
    }
 
464
    new->ptp_id = ptp_id;
 
465
 
 
466
    // Add the entry to the list
 
467
    if(propertymap == NULL) {
 
468
      propertymap = new;
 
469
    } else {
 
470
      current = propertymap;
 
471
      while (current->next != NULL ) current=current->next;
 
472
      current->next = new;
 
473
    }
 
474
    // Update the existing entry
 
475
  } else {
 
476
    if (current->description != NULL) {
 
477
      free(current->description);
 
478
    }
 
479
    current->description = NULL;
 
480
    if(description != NULL) {
 
481
      current->description = strdup(description);
 
482
    }
 
483
    current->ptp_id = ptp_id;
 
484
  }
 
485
 
 
486
  return 0;
 
487
}
 
488
 
 
489
static void init_propertymap()
 
490
{
 
491
  register_property("Storage ID", LIBMTP_PROPERTY_StorageID, PTP_OPC_StorageID);
 
492
  register_property("Object Format", LIBMTP_PROPERTY_ObjectFormat, PTP_OPC_ObjectFormat);
 
493
  register_property("Protection Status", LIBMTP_PROPERTY_ProtectionStatus, PTP_OPC_ProtectionStatus);
 
494
  register_property("Object Size", LIBMTP_PROPERTY_ObjectSize, PTP_OPC_ObjectSize);
 
495
  register_property("Association Type", LIBMTP_PROPERTY_AssociationType, PTP_OPC_AssociationType);
 
496
  register_property("Association Desc", LIBMTP_PROPERTY_AssociationDesc, PTP_OPC_AssociationDesc);
 
497
  register_property("Object File Name", LIBMTP_PROPERTY_ObjectFileName, PTP_OPC_ObjectFileName);
 
498
  register_property("Date Created", LIBMTP_PROPERTY_DateCreated, PTP_OPC_DateCreated);
 
499
  register_property("Date Modified", LIBMTP_PROPERTY_DateModified, PTP_OPC_DateModified);
 
500
  register_property("Keywords", LIBMTP_PROPERTY_Keywords, PTP_OPC_Keywords);
 
501
  register_property("Parent Object", LIBMTP_PROPERTY_ParentObject, PTP_OPC_ParentObject);
 
502
  register_property("Allowed Folder Contents", LIBMTP_PROPERTY_AllowedFolderContents, PTP_OPC_AllowedFolderContents);
 
503
  register_property("Hidden", LIBMTP_PROPERTY_Hidden, PTP_OPC_Hidden);
 
504
  register_property("System Object", LIBMTP_PROPERTY_SystemObject, PTP_OPC_SystemObject);
 
505
  register_property("Persistant Unique Object Identifier", LIBMTP_PROPERTY_PersistantUniqueObjectIdentifier, PTP_OPC_PersistantUniqueObjectIdentifier);
 
506
  register_property("Sync ID", LIBMTP_PROPERTY_SyncID, PTP_OPC_SyncID);
 
507
  register_property("Property Bag", LIBMTP_PROPERTY_PropertyBag, PTP_OPC_PropertyBag);
 
508
  register_property("Name", LIBMTP_PROPERTY_Name, PTP_OPC_Name);
 
509
  register_property("Created By", LIBMTP_PROPERTY_CreatedBy, PTP_OPC_CreatedBy);
 
510
  register_property("Artist", LIBMTP_PROPERTY_Artist, PTP_OPC_Artist);
 
511
  register_property("Date Authored", LIBMTP_PROPERTY_DateAuthored, PTP_OPC_DateAuthored);
 
512
  register_property("Description", LIBMTP_PROPERTY_Description, PTP_OPC_Description);
 
513
  register_property("URL Reference", LIBMTP_PROPERTY_URLReference, PTP_OPC_URLReference);
 
514
  register_property("Language Locale", LIBMTP_PROPERTY_LanguageLocale, PTP_OPC_LanguageLocale);
 
515
  register_property("Copyright Information", LIBMTP_PROPERTY_CopyrightInformation, PTP_OPC_CopyrightInformation);
 
516
  register_property("Source", LIBMTP_PROPERTY_Source, PTP_OPC_Source);
 
517
  register_property("Origin Location", LIBMTP_PROPERTY_OriginLocation, PTP_OPC_OriginLocation);
 
518
  register_property("Date Added", LIBMTP_PROPERTY_DateAdded, PTP_OPC_DateAdded);
 
519
  register_property("Non Consumable", LIBMTP_PROPERTY_NonConsumable, PTP_OPC_NonConsumable);
 
520
  register_property("Corrupt Or Unplayable", LIBMTP_PROPERTY_CorruptOrUnplayable, PTP_OPC_CorruptOrUnplayable);
 
521
  register_property("Producer Serial Number", LIBMTP_PROPERTY_ProducerSerialNumber, PTP_OPC_ProducerSerialNumber);
 
522
  register_property("Representative Sample Format", LIBMTP_PROPERTY_RepresentativeSampleFormat, PTP_OPC_RepresentativeSampleFormat);
 
523
  register_property("Representative Sample Sise", LIBMTP_PROPERTY_RepresentativeSampleSize, PTP_OPC_RepresentativeSampleSize);
 
524
  register_property("Representative Sample Height", LIBMTP_PROPERTY_RepresentativeSampleHeight, PTP_OPC_RepresentativeSampleHeight);
 
525
  register_property("Representative Sample Width", LIBMTP_PROPERTY_RepresentativeSampleWidth, PTP_OPC_RepresentativeSampleWidth);
 
526
  register_property("Representative Sample Duration", LIBMTP_PROPERTY_RepresentativeSampleDuration, PTP_OPC_RepresentativeSampleDuration);
 
527
  register_property("Representative Sample Data", LIBMTP_PROPERTY_RepresentativeSampleData, PTP_OPC_RepresentativeSampleData);
 
528
  register_property("Width", LIBMTP_PROPERTY_Width, PTP_OPC_Width);
 
529
  register_property("Height", LIBMTP_PROPERTY_Height, PTP_OPC_Height);
 
530
  register_property("Duration", LIBMTP_PROPERTY_Duration, PTP_OPC_Duration);
 
531
  register_property("Rating", LIBMTP_PROPERTY_Rating, PTP_OPC_Rating);
 
532
  register_property("Track", LIBMTP_PROPERTY_Track, PTP_OPC_Track);
 
533
  register_property("Genre", LIBMTP_PROPERTY_Genre, PTP_OPC_Genre);
 
534
  register_property("Credits", LIBMTP_PROPERTY_Credits, PTP_OPC_Credits);
 
535
  register_property("Lyrics", LIBMTP_PROPERTY_Lyrics, PTP_OPC_Lyrics);
 
536
  register_property("Subscription Content ID", LIBMTP_PROPERTY_SubscriptionContentID, PTP_OPC_SubscriptionContentID);
 
537
  register_property("Produced By", LIBMTP_PROPERTY_ProducedBy, PTP_OPC_ProducedBy);
 
538
  register_property("Use Count", LIBMTP_PROPERTY_UseCount, PTP_OPC_UseCount);
 
539
  register_property("Skip Count", LIBMTP_PROPERTY_SkipCount, PTP_OPC_SkipCount);
 
540
  register_property("Last Accessed", LIBMTP_PROPERTY_LastAccessed, PTP_OPC_LastAccessed);
 
541
  register_property("Parental Rating", LIBMTP_PROPERTY_ParentalRating, PTP_OPC_ParentalRating);
 
542
  register_property("Meta Genre", LIBMTP_PROPERTY_MetaGenre, PTP_OPC_MetaGenre);
 
543
  register_property("Composer", LIBMTP_PROPERTY_Composer, PTP_OPC_Composer);
 
544
  register_property("Effective Rating", LIBMTP_PROPERTY_EffectiveRating, PTP_OPC_EffectiveRating);
 
545
  register_property("Subtitle", LIBMTP_PROPERTY_Subtitle, PTP_OPC_Subtitle);
 
546
  register_property("Original Release Date", LIBMTP_PROPERTY_OriginalReleaseDate, PTP_OPC_OriginalReleaseDate);
 
547
  register_property("Album Name", LIBMTP_PROPERTY_AlbumName, PTP_OPC_AlbumName);
 
548
  register_property("Album Artist", LIBMTP_PROPERTY_AlbumArtist, PTP_OPC_AlbumArtist);
 
549
  register_property("Mood", LIBMTP_PROPERTY_Mood, PTP_OPC_Mood);
 
550
  register_property("DRM Status", LIBMTP_PROPERTY_DRMStatus, PTP_OPC_DRMStatus);
 
551
  register_property("Sub Description", LIBMTP_PROPERTY_SubDescription, PTP_OPC_SubDescription);
 
552
  register_property("Is Cropped", LIBMTP_PROPERTY_IsCropped, PTP_OPC_IsCropped);
 
553
  register_property("Is Color Corrected", LIBMTP_PROPERTY_IsColorCorrected, PTP_OPC_IsColorCorrected);
 
554
  register_property("Image Bit Depth", LIBMTP_PROPERTY_ImageBitDepth, PTP_OPC_ImageBitDepth);
 
555
  register_property("f Number", LIBMTP_PROPERTY_Fnumber, PTP_OPC_Fnumber);
 
556
  register_property("Exposure Time", LIBMTP_PROPERTY_ExposureTime, PTP_OPC_ExposureTime);
 
557
  register_property("Exposure Index", LIBMTP_PROPERTY_ExposureIndex, PTP_OPC_ExposureIndex);
 
558
  register_property("Display Name", LIBMTP_PROPERTY_DisplayName, PTP_OPC_DisplayName);
 
559
  register_property("Body Text", LIBMTP_PROPERTY_BodyText, PTP_OPC_BodyText);
 
560
  register_property("Subject", LIBMTP_PROPERTY_Subject, PTP_OPC_Subject);
 
561
  register_property("Priority", LIBMTP_PROPERTY_Priority, PTP_OPC_Priority);
 
562
  register_property("Given Name", LIBMTP_PROPERTY_GivenName, PTP_OPC_GivenName);
 
563
  register_property("Middle Names", LIBMTP_PROPERTY_MiddleNames, PTP_OPC_MiddleNames);
 
564
  register_property("Family Name", LIBMTP_PROPERTY_FamilyName, PTP_OPC_FamilyName);
 
565
  register_property("Prefix", LIBMTP_PROPERTY_Prefix, PTP_OPC_Prefix);
 
566
  register_property("Suffix", LIBMTP_PROPERTY_Suffix, PTP_OPC_Suffix);
 
567
  register_property("Phonetic Given Name", LIBMTP_PROPERTY_PhoneticGivenName, PTP_OPC_PhoneticGivenName);
 
568
  register_property("Phonetic Family Name", LIBMTP_PROPERTY_PhoneticFamilyName, PTP_OPC_PhoneticFamilyName);
 
569
  register_property("Email: Primary", LIBMTP_PROPERTY_EmailPrimary, PTP_OPC_EmailPrimary);
 
570
  register_property("Email: Personal 1", LIBMTP_PROPERTY_EmailPersonal1, PTP_OPC_EmailPersonal1);
 
571
  register_property("Email: Personal 2", LIBMTP_PROPERTY_EmailPersonal2, PTP_OPC_EmailPersonal2);
 
572
  register_property("Email: Business 1", LIBMTP_PROPERTY_EmailBusiness1, PTP_OPC_EmailBusiness1);
 
573
  register_property("Email: Business 2", LIBMTP_PROPERTY_EmailBusiness2, PTP_OPC_EmailBusiness2);
 
574
  register_property("Email: Others", LIBMTP_PROPERTY_EmailOthers, PTP_OPC_EmailOthers);
 
575
  register_property("Phone Number: Primary", LIBMTP_PROPERTY_PhoneNumberPrimary, PTP_OPC_PhoneNumberPrimary);
 
576
  register_property("Phone Number: Personal", LIBMTP_PROPERTY_PhoneNumberPersonal, PTP_OPC_PhoneNumberPersonal);
 
577
  register_property("Phone Number: Personal 2", LIBMTP_PROPERTY_PhoneNumberPersonal2, PTP_OPC_PhoneNumberPersonal2);
 
578
  register_property("Phone Number: Business", LIBMTP_PROPERTY_PhoneNumberBusiness, PTP_OPC_PhoneNumberBusiness);
 
579
  register_property("Phone Number: Business 2", LIBMTP_PROPERTY_PhoneNumberBusiness2, PTP_OPC_PhoneNumberBusiness2);
 
580
  register_property("Phone Number: Mobile", LIBMTP_PROPERTY_PhoneNumberMobile, PTP_OPC_PhoneNumberMobile);
 
581
  register_property("Phone Number: Mobile 2", LIBMTP_PROPERTY_PhoneNumberMobile2, PTP_OPC_PhoneNumberMobile2);
 
582
  register_property("Fax Number: Primary", LIBMTP_PROPERTY_FaxNumberPrimary, PTP_OPC_FaxNumberPrimary);
 
583
  register_property("Fax Number: Personal", LIBMTP_PROPERTY_FaxNumberPersonal, PTP_OPC_FaxNumberPersonal);
 
584
  register_property("Fax Number: Business", LIBMTP_PROPERTY_FaxNumberBusiness, PTP_OPC_FaxNumberBusiness);
 
585
  register_property("Pager Number", LIBMTP_PROPERTY_PagerNumber, PTP_OPC_PagerNumber);
 
586
  register_property("Phone Number: Others", LIBMTP_PROPERTY_PhoneNumberOthers, PTP_OPC_PhoneNumberOthers);
 
587
  register_property("Primary Web Address", LIBMTP_PROPERTY_PrimaryWebAddress, PTP_OPC_PrimaryWebAddress);
 
588
  register_property("Personal Web Address", LIBMTP_PROPERTY_PersonalWebAddress, PTP_OPC_PersonalWebAddress);
 
589
  register_property("Business Web Address", LIBMTP_PROPERTY_BusinessWebAddress, PTP_OPC_BusinessWebAddress);
 
590
  register_property("Instant Messenger Address 1", LIBMTP_PROPERTY_InstantMessengerAddress, PTP_OPC_InstantMessengerAddress);
 
591
  register_property("Instant Messenger Address 2", LIBMTP_PROPERTY_InstantMessengerAddress2, PTP_OPC_InstantMessengerAddress2);
 
592
  register_property("Instant Messenger Address 3", LIBMTP_PROPERTY_InstantMessengerAddress3, PTP_OPC_InstantMessengerAddress3);
 
593
  register_property("Postal Address: Personal: Full", LIBMTP_PROPERTY_PostalAddressPersonalFull, PTP_OPC_PostalAddressPersonalFull);
 
594
  register_property("Postal Address: Personal: Line 1", LIBMTP_PROPERTY_PostalAddressPersonalFullLine1, PTP_OPC_PostalAddressPersonalFullLine1);
 
595
  register_property("Postal Address: Personal: Line 2", LIBMTP_PROPERTY_PostalAddressPersonalFullLine2, PTP_OPC_PostalAddressPersonalFullLine2);
 
596
  register_property("Postal Address: Personal: City", LIBMTP_PROPERTY_PostalAddressPersonalFullCity, PTP_OPC_PostalAddressPersonalFullCity);
 
597
  register_property("Postal Address: Personal: Region", LIBMTP_PROPERTY_PostalAddressPersonalFullRegion, PTP_OPC_PostalAddressPersonalFullRegion);
 
598
  register_property("Postal Address: Personal: Postal Code", LIBMTP_PROPERTY_PostalAddressPersonalFullPostalCode, PTP_OPC_PostalAddressPersonalFullPostalCode);
 
599
  register_property("Postal Address: Personal: Country", LIBMTP_PROPERTY_PostalAddressPersonalFullCountry, PTP_OPC_PostalAddressPersonalFullCountry);
 
600
  register_property("Postal Address: Business: Full", LIBMTP_PROPERTY_PostalAddressBusinessFull, PTP_OPC_PostalAddressBusinessFull);
 
601
  register_property("Postal Address: Business: Line 1", LIBMTP_PROPERTY_PostalAddressBusinessLine1, PTP_OPC_PostalAddressBusinessLine1);
 
602
  register_property("Postal Address: Business: Line 2", LIBMTP_PROPERTY_PostalAddressBusinessLine2, PTP_OPC_PostalAddressBusinessLine2);
 
603
  register_property("Postal Address: Business: City", LIBMTP_PROPERTY_PostalAddressBusinessCity, PTP_OPC_PostalAddressBusinessCity);
 
604
  register_property("Postal Address: Business: Region", LIBMTP_PROPERTY_PostalAddressBusinessRegion, PTP_OPC_PostalAddressBusinessRegion);
 
605
  register_property("Postal Address: Business: Postal Code", LIBMTP_PROPERTY_PostalAddressBusinessPostalCode, PTP_OPC_PostalAddressBusinessPostalCode);
 
606
  register_property("Postal Address: Business: Country", LIBMTP_PROPERTY_PostalAddressBusinessCountry, PTP_OPC_PostalAddressBusinessCountry);
 
607
  register_property("Postal Address: Other: Full", LIBMTP_PROPERTY_PostalAddressOtherFull, PTP_OPC_PostalAddressOtherFull);
 
608
  register_property("Postal Address: Other: Line 1", LIBMTP_PROPERTY_PostalAddressOtherLine1, PTP_OPC_PostalAddressOtherLine1);
 
609
  register_property("Postal Address: Other: Line 2", LIBMTP_PROPERTY_PostalAddressOtherLine2, PTP_OPC_PostalAddressOtherLine2);
 
610
  register_property("Postal Address: Other: City", LIBMTP_PROPERTY_PostalAddressOtherCity, PTP_OPC_PostalAddressOtherCity);
 
611
  register_property("Postal Address: Other: Region", LIBMTP_PROPERTY_PostalAddressOtherRegion, PTP_OPC_PostalAddressOtherRegion);
 
612
  register_property("Postal Address: Other: Postal Code", LIBMTP_PROPERTY_PostalAddressOtherPostalCode, PTP_OPC_PostalAddressOtherPostalCode);
 
613
  register_property("Postal Address: Other: Counrtry", LIBMTP_PROPERTY_PostalAddressOtherCountry, PTP_OPC_PostalAddressOtherCountry);
 
614
  register_property("Organization Name", LIBMTP_PROPERTY_OrganizationName, PTP_OPC_OrganizationName);
 
615
  register_property("Phonetic Organization Name", LIBMTP_PROPERTY_PhoneticOrganizationName, PTP_OPC_PhoneticOrganizationName);
 
616
  register_property("Role", LIBMTP_PROPERTY_Role, PTP_OPC_Role);
 
617
  register_property("Birthdate", LIBMTP_PROPERTY_Birthdate, PTP_OPC_Birthdate);
 
618
  register_property("Message To", LIBMTP_PROPERTY_MessageTo, PTP_OPC_MessageTo);
 
619
  register_property("Message CC", LIBMTP_PROPERTY_MessageCC, PTP_OPC_MessageCC);
 
620
  register_property("Message BCC", LIBMTP_PROPERTY_MessageBCC, PTP_OPC_MessageBCC);
 
621
  register_property("Message Read", LIBMTP_PROPERTY_MessageRead, PTP_OPC_MessageRead);
 
622
  register_property("Message Received Time", LIBMTP_PROPERTY_MessageReceivedTime, PTP_OPC_MessageReceivedTime);
 
623
  register_property("Message Sender", LIBMTP_PROPERTY_MessageSender, PTP_OPC_MessageSender);
 
624
  register_property("Activity Begin Time", LIBMTP_PROPERTY_ActivityBeginTime, PTP_OPC_ActivityBeginTime);
 
625
  register_property("Activity End Time", LIBMTP_PROPERTY_ActivityEndTime, PTP_OPC_ActivityEndTime);
 
626
  register_property("Activity Location", LIBMTP_PROPERTY_ActivityLocation, PTP_OPC_ActivityLocation);
 
627
  register_property("Activity Required Attendees", LIBMTP_PROPERTY_ActivityRequiredAttendees, PTP_OPC_ActivityRequiredAttendees);
 
628
  register_property("Optional Attendees", LIBMTP_PROPERTY_ActivityOptionalAttendees, PTP_OPC_ActivityOptionalAttendees);
 
629
  register_property("Activity Resources", LIBMTP_PROPERTY_ActivityResources, PTP_OPC_ActivityResources);
 
630
  register_property("Activity Accepted", LIBMTP_PROPERTY_ActivityAccepted, PTP_OPC_ActivityAccepted);
 
631
  register_property("Owner", LIBMTP_PROPERTY_Owner, PTP_OPC_Owner);
 
632
  register_property("Editor", LIBMTP_PROPERTY_Editor, PTP_OPC_Editor);
 
633
  register_property("Webmaster", LIBMTP_PROPERTY_Webmaster, PTP_OPC_Webmaster);
 
634
  register_property("URL Source", LIBMTP_PROPERTY_URLSource, PTP_OPC_URLSource);
 
635
  register_property("URL Destination", LIBMTP_PROPERTY_URLDestination, PTP_OPC_URLDestination);
 
636
  register_property("Time Bookmark", LIBMTP_PROPERTY_TimeBookmark, PTP_OPC_TimeBookmark);
 
637
  register_property("Object Bookmark", LIBMTP_PROPERTY_ObjectBookmark, PTP_OPC_ObjectBookmark);
 
638
  register_property("Byte Bookmark", LIBMTP_PROPERTY_ByteBookmark, PTP_OPC_ByteBookmark);
 
639
  register_property("Last Build Date", LIBMTP_PROPERTY_LastBuildDate, PTP_OPC_LastBuildDate);
 
640
  register_property("Time To Live", LIBMTP_PROPERTY_TimetoLive, PTP_OPC_TimetoLive);
 
641
  register_property("Media GUID", LIBMTP_PROPERTY_MediaGUID, PTP_OPC_MediaGUID);
 
642
  register_property("Total Bit Rate", LIBMTP_PROPERTY_TotalBitRate, PTP_OPC_TotalBitRate);
 
643
  register_property("Bit Rate Type", LIBMTP_PROPERTY_BitRateType, PTP_OPC_BitRateType);
 
644
  register_property("Sample Rate", LIBMTP_PROPERTY_SampleRate, PTP_OPC_SampleRate);
 
645
  register_property("Number Of Channels", LIBMTP_PROPERTY_NumberOfChannels, PTP_OPC_NumberOfChannels);
 
646
  register_property("Audio Bit Depth", LIBMTP_PROPERTY_AudioBitDepth, PTP_OPC_AudioBitDepth);
 
647
  register_property("Scan Depth", LIBMTP_PROPERTY_ScanDepth, PTP_OPC_ScanDepth);
 
648
  register_property("Audio WAVE Codec", LIBMTP_PROPERTY_AudioWAVECodec, PTP_OPC_AudioWAVECodec);
 
649
  register_property("Audio Bit Rate", LIBMTP_PROPERTY_AudioBitRate, PTP_OPC_AudioBitRate);
 
650
  register_property("Video Four CC Codec", LIBMTP_PROPERTY_VideoFourCCCodec, PTP_OPC_VideoFourCCCodec);
 
651
  register_property("Video Bit Rate", LIBMTP_PROPERTY_VideoBitRate, PTP_OPC_VideoBitRate);
 
652
  register_property("Frames Per Thousand Seconds", LIBMTP_PROPERTY_FramesPerThousandSeconds, PTP_OPC_FramesPerThousandSeconds);
 
653
  register_property("Key Frame Distance", LIBMTP_PROPERTY_KeyFrameDistance, PTP_OPC_KeyFrameDistance);
 
654
  register_property("Buffer Size", LIBMTP_PROPERTY_BufferSize, PTP_OPC_BufferSize);
 
655
  register_property("Encoding Quality", LIBMTP_PROPERTY_EncodingQuality, PTP_OPC_EncodingQuality);
 
656
  register_property("Encoding Profile", LIBMTP_PROPERTY_EncodingProfile, PTP_OPC_EncodingProfile);
 
657
  register_property("Buy flag", LIBMTP_PROPERTY_BuyFlag, PTP_OPC_BuyFlag);
 
658
  register_property("Unknown property", LIBMTP_PROPERTY_UNKNOWN, 0);
 
659
}
 
660
 
 
661
/**
 
662
 * Returns the PTP property that maps to a certain libmtp internal property type.
 
663
 * @param inproperty the MTP library interface property
 
664
 * @return the PTP (libgphoto2) property type
 
665
 */
 
666
static uint16_t map_libmtp_property_to_ptp_property(LIBMTP_property_t inproperty)
 
667
{
 
668
  propertymap_t *current;
 
669
 
 
670
  current = propertymap;
 
671
 
 
672
  while (current != NULL) {
 
673
    if(current->id == inproperty) {
 
674
      return current->ptp_id;
 
675
    }
 
676
    current = current->next;
 
677
  }
 
678
  return 0;
 
679
}
 
680
 
 
681
 
 
682
/**
 
683
 * Returns the MTP internal interface property that maps to a certain ptp
 
684
 * interface property.
 
685
 * @param inproperty the PTP (libgphoto2) interface property
 
686
 * @return the MTP library interface property
 
687
 */
 
688
static LIBMTP_property_t map_ptp_property_to_libmtp_property(uint16_t inproperty)
 
689
{
 
690
  propertymap_t *current;
 
691
 
 
692
  current = propertymap;
 
693
 
 
694
  while (current != NULL) {
 
695
    if(current->ptp_id == inproperty) {
 
696
      return current->id;
 
697
    }
 
698
    current = current->next;
 
699
  }
 
700
  // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");
 
701
  return LIBMTP_PROPERTY_UNKNOWN;
 
702
}
 
703
 
355
704
 
356
705
/**
357
706
 * Initialize the library. You are only supposed to call this
364
713
void LIBMTP_Init(void)
365
714
{
366
715
  init_filemap();
 
716
  init_propertymap();
367
717
  return;
368
718
}
369
719
 
392
742
}
393
743
 
394
744
/**
 
745
 * This helper function returns a textual description for a libmtp
 
746
 * property to be used in dialog boxes etc.
 
747
 * @param inproperty the libmtp internal property to get a description for.
 
748
 * @return a string representing the filetype, this must <b>NOT</b>
 
749
 *         be free():ed by the caller!
 
750
 */
 
751
char const * LIBMTP_Get_Property_Description(LIBMTP_property_t inproperty)
 
752
{
 
753
  propertymap_t *current;
 
754
 
 
755
  current = propertymap;
 
756
 
 
757
  while (current != NULL) {
 
758
    if(current->id == inproperty) {
 
759
      return current->description;
 
760
    }
 
761
    current = current->next;
 
762
  }
 
763
 
 
764
  return "Unknown property";
 
765
}
 
766
 
 
767
/**
395
768
 * This function will do its best to fit a 16bit
396
769
 * value into a PTP object property if the property
397
770
 * is limited in range or step sizes.
499
872
}
500
873
 
501
874
/**
 
875
 * Gets the allowed values (range or enum) for a property
 
876
 * @param device a pointer to an MTP device
 
877
 * @param property the property to query
 
878
 * @param filetype the filetype of the object you want to set values for
 
879
 * @param allowed_vals pointer to a LIBMTP_allowed_values_t struct to
 
880
 *        receive the allowed values.  Call LIBMTP_destroy_allowed_values_t
 
881
 *        on this on successful completion.
 
882
 * @return 0 on success, any other value means failure
 
883
 */
 
884
int LIBMTP_Get_Allowed_Property_Values(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
 
885
            LIBMTP_filetype_t const filetype, LIBMTP_allowed_values_t *allowed_vals)
 
886
{
 
887
  PTPObjectPropDesc opd;
 
888
  uint16_t ret = 0;
 
889
  
 
890
  ret = ptp_mtp_getobjectpropdesc(device->params, map_libmtp_property_to_ptp_property(property), map_libmtp_type_to_ptp_type(filetype), &opd);
 
891
  if (ret != PTP_RC_OK) {
 
892
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Allowed_Property_Values(): could not get property description.");
 
893
    return -1;
 
894
  }
 
895
 
 
896
  if (opd.FormFlag == PTP_OPFF_Enumeration) {
 
897
    int i = 0;
 
898
    
 
899
    allowed_vals->is_range = 0;
 
900
    allowed_vals->num_entries = opd.FORM.Enum.NumberOfValues;
 
901
 
 
902
    switch (opd.DataType)
 
903
    {
 
904
      case PTP_DTC_INT8:
 
905
        allowed_vals->i8vals = malloc(sizeof(int8_t) * opd.FORM.Enum.NumberOfValues);
 
906
        allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
 
907
        break;
 
908
      case PTP_DTC_UINT8:
 
909
        allowed_vals->u8vals = malloc(sizeof(uint8_t) * opd.FORM.Enum.NumberOfValues);
 
910
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
 
911
        break;
 
912
      case PTP_DTC_INT16:
 
913
        allowed_vals->i16vals = malloc(sizeof(int16_t) * opd.FORM.Enum.NumberOfValues);
 
914
        allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
 
915
        break;
 
916
      case PTP_DTC_UINT16:
 
917
        allowed_vals->u16vals = malloc(sizeof(uint16_t) * opd.FORM.Enum.NumberOfValues);
 
918
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
 
919
        break;
 
920
      case PTP_DTC_INT32:
 
921
        allowed_vals->i32vals = malloc(sizeof(int32_t) * opd.FORM.Enum.NumberOfValues);
 
922
        allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
 
923
        break;
 
924
      case PTP_DTC_UINT32:
 
925
        allowed_vals->u32vals = malloc(sizeof(uint32_t) * opd.FORM.Enum.NumberOfValues);
 
926
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
 
927
        break;
 
928
      case PTP_DTC_INT64:
 
929
        allowed_vals->i64vals = malloc(sizeof(int64_t) * opd.FORM.Enum.NumberOfValues);
 
930
        allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
 
931
        break;
 
932
      case PTP_DTC_UINT64:
 
933
        allowed_vals->u64vals = malloc(sizeof(uint64_t) * opd.FORM.Enum.NumberOfValues);
 
934
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
 
935
        break;
 
936
    }
 
937
    
 
938
    for (i = 0; i < opd.FORM.Enum.NumberOfValues; i++) {
 
939
      switch (opd.DataType)
 
940
      {
 
941
        case PTP_DTC_INT8:
 
942
          allowed_vals->i8vals[i] = opd.FORM.Enum.SupportedValue[i].i8;
 
943
          break;
 
944
        case PTP_DTC_UINT8:
 
945
          allowed_vals->u8vals[i] = opd.FORM.Enum.SupportedValue[i].u8;
 
946
          break;
 
947
        case PTP_DTC_INT16:
 
948
          allowed_vals->i16vals[i] = opd.FORM.Enum.SupportedValue[i].i16;
 
949
          break;
 
950
        case PTP_DTC_UINT16:
 
951
          allowed_vals->u16vals[i] = opd.FORM.Enum.SupportedValue[i].u16;
 
952
          break;
 
953
        case PTP_DTC_INT32:
 
954
          allowed_vals->i32vals[i] = opd.FORM.Enum.SupportedValue[i].i32;
 
955
          break;
 
956
        case PTP_DTC_UINT32:
 
957
          allowed_vals->u32vals[i] = opd.FORM.Enum.SupportedValue[i].u32;
 
958
          break;
 
959
        case PTP_DTC_INT64:
 
960
          allowed_vals->i64vals[i] = opd.FORM.Enum.SupportedValue[i].i64;
 
961
          break;
 
962
        case PTP_DTC_UINT64:
 
963
          allowed_vals->u64vals[i] = opd.FORM.Enum.SupportedValue[i].u64;
 
964
          break;
 
965
      }
 
966
    }
 
967
    ptp_free_objectpropdesc(&opd);
 
968
    return 0;
 
969
  } else if (opd.FormFlag == PTP_OPFF_Range) {
 
970
    allowed_vals->is_range = 1;
 
971
    
 
972
    switch (opd.DataType)
 
973
    {
 
974
      case PTP_DTC_INT8:
 
975
        allowed_vals->i8min = opd.FORM.Range.MinimumValue.i8;
 
976
        allowed_vals->i8max = opd.FORM.Range.MaximumValue.i8;
 
977
        allowed_vals->i8step = opd.FORM.Range.StepSize.i8;
 
978
        allowed_vals->datatype = LIBMTP_DATATYPE_INT8;
 
979
        break;
 
980
      case PTP_DTC_UINT8:
 
981
        allowed_vals->u8min = opd.FORM.Range.MinimumValue.u8;
 
982
        allowed_vals->u8max = opd.FORM.Range.MaximumValue.u8;
 
983
        allowed_vals->u8step = opd.FORM.Range.StepSize.u8;
 
984
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT8;
 
985
        break;
 
986
      case PTP_DTC_INT16:
 
987
        allowed_vals->i16min = opd.FORM.Range.MinimumValue.i16;
 
988
        allowed_vals->i16max = opd.FORM.Range.MaximumValue.i16;
 
989
        allowed_vals->i16step = opd.FORM.Range.StepSize.i16;
 
990
        allowed_vals->datatype = LIBMTP_DATATYPE_INT16;
 
991
        break;
 
992
      case PTP_DTC_UINT16:
 
993
        allowed_vals->u16min = opd.FORM.Range.MinimumValue.u16;
 
994
        allowed_vals->u16max = opd.FORM.Range.MaximumValue.u16;
 
995
        allowed_vals->u16step = opd.FORM.Range.StepSize.u16;
 
996
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT16;
 
997
        break;
 
998
      case PTP_DTC_INT32:
 
999
        allowed_vals->i32min = opd.FORM.Range.MinimumValue.i32;
 
1000
        allowed_vals->i32max = opd.FORM.Range.MaximumValue.i32;
 
1001
        allowed_vals->i32step = opd.FORM.Range.StepSize.i32;
 
1002
        allowed_vals->datatype = LIBMTP_DATATYPE_INT32;
 
1003
        break;
 
1004
      case PTP_DTC_UINT32:
 
1005
        allowed_vals->u32min = opd.FORM.Range.MinimumValue.u32;
 
1006
        allowed_vals->u32max = opd.FORM.Range.MaximumValue.u32;
 
1007
        allowed_vals->u32step = opd.FORM.Range.StepSize.u32;
 
1008
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT32;
 
1009
        break;
 
1010
      case PTP_DTC_INT64:
 
1011
        allowed_vals->i64min = opd.FORM.Range.MinimumValue.i64;
 
1012
        allowed_vals->i64max = opd.FORM.Range.MaximumValue.i64;
 
1013
        allowed_vals->i64step = opd.FORM.Range.StepSize.i64;
 
1014
        allowed_vals->datatype = LIBMTP_DATATYPE_INT64;
 
1015
        break;
 
1016
      case PTP_DTC_UINT64:
 
1017
        allowed_vals->u64min = opd.FORM.Range.MinimumValue.u64;
 
1018
        allowed_vals->u64max = opd.FORM.Range.MaximumValue.u64;
 
1019
        allowed_vals->u64step = opd.FORM.Range.StepSize.u64;
 
1020
        allowed_vals->datatype = LIBMTP_DATATYPE_UINT64;
 
1021
        break;
 
1022
    }
 
1023
    return 0; 
 
1024
  } else
 
1025
    return -1;
 
1026
}
 
1027
 
 
1028
/**
 
1029
 * Destroys a LIBMTP_allowed_values_t struct
 
1030
 * @param allowed_vals the struct to destroy
 
1031
 */
 
1032
void LIBMTP_destroy_allowed_values_t(LIBMTP_allowed_values_t *allowed_vals)
 
1033
{
 
1034
  if (!allowed_vals->is_range)
 
1035
  {
 
1036
    switch (allowed_vals->datatype)
 
1037
    {
 
1038
      case LIBMTP_DATATYPE_INT8:
 
1039
        if (allowed_vals->i8vals)
 
1040
          free(allowed_vals->i8vals);
 
1041
        break;
 
1042
      case LIBMTP_DATATYPE_UINT8:
 
1043
        if (allowed_vals->u8vals)
 
1044
          free(allowed_vals->u8vals);
 
1045
        break;
 
1046
      case LIBMTP_DATATYPE_INT16:
 
1047
        if (allowed_vals->i16vals)
 
1048
          free(allowed_vals->i16vals);
 
1049
        break;
 
1050
      case LIBMTP_DATATYPE_UINT16:
 
1051
        if (allowed_vals->u16vals)
 
1052
          free(allowed_vals->u16vals);
 
1053
        break;
 
1054
      case LIBMTP_DATATYPE_INT32:
 
1055
        if (allowed_vals->i32vals)
 
1056
          free(allowed_vals->i32vals);
 
1057
        break;
 
1058
      case LIBMTP_DATATYPE_UINT32:
 
1059
        if (allowed_vals->u32vals)
 
1060
          free(allowed_vals->u32vals);
 
1061
        break;
 
1062
      case LIBMTP_DATATYPE_INT64:
 
1063
        if (allowed_vals->i64vals)
 
1064
          free(allowed_vals->i64vals);
 
1065
        break;
 
1066
      case LIBMTP_DATATYPE_UINT64:
 
1067
        if (allowed_vals->u64vals)
 
1068
          free(allowed_vals->u64vals);
 
1069
        break;
 
1070
    }
 
1071
  }
 
1072
}
 
1073
 
 
1074
/**
 
1075
 * Determine if a property is supported for a given file type
 
1076
 * @param device a pointer to an MTP device
 
1077
 * @param property the property to query
 
1078
 * @param filetype the filetype of the object you want to set values for
 
1079
 * @return 0 if not supported, positive if supported, negative on error
 
1080
 */
 
1081
int LIBMTP_Is_Property_Supported(LIBMTP_mtpdevice_t *device, LIBMTP_property_t const property,
 
1082
            LIBMTP_filetype_t const filetype)
 
1083
{
 
1084
  uint16_t *props = NULL;
 
1085
  uint32_t propcnt = 0;
 
1086
  uint16_t ret = 0;
 
1087
  int i = 0;
 
1088
  int supported = 0;
 
1089
  uint16_t ptp_prop = map_libmtp_property_to_ptp_property(property);
 
1090
  
 
1091
  ret = ptp_mtp_getobjectpropssupported(device->params, map_libmtp_type_to_ptp_type(filetype), &propcnt, &props);
 
1092
  if (ret != PTP_RC_OK) {
 
1093
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Is_Property_Supported(): could not get properties supported.");
 
1094
    return -1;
 
1095
  }
 
1096
 
 
1097
        for (i = 0; i < propcnt; i++) {
 
1098
    if (props[i] == ptp_prop) {
 
1099
      supported = 1;
 
1100
      break;
 
1101
    }
 
1102
  }
 
1103
  
 
1104
  free(props);
 
1105
  
 
1106
  return supported;
 
1107
}
 
1108
 
 
1109
/**
 
1110
 * Retrieves a string from an object
 
1111
 *
 
1112
 * @param device a pointer to an MTP device.
 
1113
 * @param object_id Object reference
 
1114
 * @param attribute_id MTP attribute ID
 
1115
 * @return valid string or NULL on failure. The returned string
 
1116
 *         must bee <code>free()</code>:ed by the caller after
 
1117
 *         use.
 
1118
 */
 
1119
char *LIBMTP_Get_String_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1120
                                    LIBMTP_property_t const attribute_id)
 
1121
{
 
1122
  return get_string_from_object(device, object_id, attribute_id);
 
1123
}
 
1124
 
 
1125
/**
 
1126
* Retrieves an unsigned 64-bit integer from an object attribute
 
1127
 *
 
1128
 * @param device a pointer to an MTP device.
 
1129
 * @param object_id Object reference
 
1130
 * @param attribute_id MTP attribute ID
 
1131
 * @param value_default Default value to return on failure
 
1132
 * @return the value
 
1133
 */
 
1134
uint64_t LIBMTP_Get_u64_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
 
1135
                                    LIBMTP_property_t const attribute_id, uint64_t const value_default)
 
1136
{
 
1137
  return get_u64_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
 
1138
}
 
1139
 
 
1140
/**
 
1141
 * Retrieves an unsigned 32-bit integer from an object attribute
 
1142
 *
 
1143
 * @param device a pointer to an MTP device.
 
1144
 * @param object_id Object reference
 
1145
 * @param attribute_id MTP attribute ID
 
1146
 * @param value_default Default value to return on failure
 
1147
 * @return the value
 
1148
 */
 
1149
uint32_t LIBMTP_Get_u32_From_Object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,
 
1150
                                    LIBMTP_property_t const attribute_id, uint32_t const value_default)
 
1151
{
 
1152
  return get_u32_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
 
1153
}
 
1154
 
 
1155
/**
 
1156
 * Retrieves an unsigned 16-bit integer from an object attribute
 
1157
 *
 
1158
 * @param device a pointer to an MTP device.
 
1159
 * @param object_id Object reference
 
1160
 * @param attribute_id MTP attribute ID
 
1161
 * @param value_default Default value to return on failure
 
1162
 * @return a value
 
1163
 */
 
1164
uint16_t LIBMTP_Get_u16_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1165
                                    LIBMTP_property_t const attribute_id, uint16_t const value_default)
 
1166
{
 
1167
  return get_u16_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
 
1168
}
 
1169
 
 
1170
/**
 
1171
 * Retrieves an unsigned 8-bit integer from an object attribute
 
1172
 *
 
1173
 * @param device a pointer to an MTP device.
 
1174
 * @param object_id Object reference
 
1175
 * @param attribute_id MTP attribute ID
 
1176
 * @param value_default Default value to return on failure
 
1177
 * @return a value
 
1178
 */
 
1179
uint8_t LIBMTP_Get_u8_From_Object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1180
                                  LIBMTP_property_t const attribute_id, uint8_t const value_default)
 
1181
{
 
1182
  return get_u8_from_object(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value_default);
 
1183
}
 
1184
 
 
1185
/**
 
1186
 * Sets an object attribute from a string
 
1187
 *
 
1188
 * @param device a pointer to an MTP device.
 
1189
 * @param object_id Object reference
 
1190
 * @param attribute_id MTP attribute ID
 
1191
 * @param string string value to set
 
1192
 * @return 0 on success, any other value means failure
 
1193
 */
 
1194
int LIBMTP_Set_Object_String(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1195
                             LIBMTP_property_t const attribute_id, char const * const string)
 
1196
{
 
1197
  return set_object_string(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), string);
 
1198
}
 
1199
 
 
1200
 
 
1201
/**
 
1202
 * Sets an object attribute from an unsigned 32-bit integer
 
1203
 *
 
1204
 * @param device a pointer to an MTP device.
 
1205
 * @param object_id Object reference
 
1206
 * @param attribute_id MTP attribute ID
 
1207
 * @param value 32-bit unsigned integer to set
 
1208
 * @return 0 on success, any other value means failure
 
1209
 */
 
1210
int LIBMTP_Set_Object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1211
                          LIBMTP_property_t const attribute_id, uint32_t const value)
 
1212
{
 
1213
  return set_object_u32(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
 
1214
}
 
1215
 
 
1216
/**
 
1217
 * Sets an object attribute from an unsigned 16-bit integer
 
1218
 *
 
1219
 * @param device a pointer to an MTP device.
 
1220
 * @param object_id Object reference
 
1221
 * @param attribute_id MTP attribute ID
 
1222
 * @param value 16-bit unsigned integer to set
 
1223
 * @return 0 on success, any other value means failure
 
1224
 */
 
1225
int LIBMTP_Set_Object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1226
                          LIBMTP_property_t const attribute_id, uint16_t const value)
 
1227
{
 
1228
  return set_object_u16(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
 
1229
}
 
1230
 
 
1231
/**
 
1232
 * Sets an object attribute from an unsigned 8-bit integer
 
1233
 *
 
1234
 * @param device a pointer to an MTP device.
 
1235
 * @param object_id Object reference
 
1236
 * @param attribute_id MTP attribute ID
 
1237
 * @param value 8-bit unsigned integer to set
 
1238
 * @return 0 on success, any other value means failure
 
1239
 */
 
1240
int LIBMTP_Set_Object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,
 
1241
                         LIBMTP_property_t const attribute_id, uint8_t const value)
 
1242
{
 
1243
  return set_object_u8(device, object_id, map_libmtp_property_to_ptp_property(attribute_id), value);
 
1244
}
 
1245
 
 
1246
/**
502
1247
 * Retrieves a string from an object
503
1248
 *
504
1249
 * @param device a pointer to an MTP device.
515
1260
  char *retstring = NULL;
516
1261
  PTPParams *params = (PTPParams *) device->params;
517
1262
  uint16_t ret;
 
1263
  MTPProperties *prop;
518
1264
 
519
1265
  if ( device == NULL || object_id == 0) {
520
1266
    return NULL;
521
1267
  }
522
1268
  
523
 
  // This O(n) search should not be used so often, since code
524
 
  // using the cached properties don't usually call this function.
525
 
  if (params->props) {
526
 
    MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
527
 
    if (prop) {
528
 
        if (prop->propval.str != NULL)
529
 
          return strdup(prop->propval.str);
530
 
        else
531
 
          return NULL;
532
 
    }
 
1269
  prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
 
1270
  if (prop) {
 
1271
    if (prop->propval.str != NULL)
 
1272
      return strdup(prop->propval.str);
 
1273
    else
 
1274
      return NULL;
533
1275
  }
534
1276
 
535
1277
  ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
561
1303
  uint64_t retval = value_default;
562
1304
  PTPParams *params = (PTPParams *) device->params;
563
1305
  uint16_t ret;
 
1306
  MTPProperties *prop;
564
1307
  
565
1308
  if ( device == NULL ) {
566
1309
    return value_default;
567
1310
  }
568
1311
  
569
 
  // This O(n) search should not be used so often, since code
570
 
  // using the cached properties don't usually call this function.
571
 
  if (params->props) {
572
 
    MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
573
 
    if (prop)
574
 
      return prop->propval.u64;
575
 
  }
 
1312
  prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
 
1313
  if (prop)
 
1314
    return prop->propval.u64;
576
1315
 
577
1316
  ret = ptp_mtp_getobjectpropvalue(params, object_id,
578
1317
                                   attribute_id,
603
1342
  uint32_t retval = value_default;
604
1343
  PTPParams *params = (PTPParams *) device->params;
605
1344
  uint16_t ret;
 
1345
  MTPProperties *prop;
606
1346
 
607
1347
  if ( device == NULL ) {
608
1348
    return value_default;
609
1349
  }
610
1350
 
611
 
  // This O(n) search should not be used so often, since code
612
 
  // using the cached properties don't usually call this function.
613
 
  if (params->props) {
614
 
    MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
615
 
    if (prop)
616
 
      return prop->propval.u32;
617
 
  }
 
1351
  prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
 
1352
  if (prop)
 
1353
    return prop->propval.u32;
618
1354
 
619
1355
  ret = ptp_mtp_getobjectpropvalue(params, object_id,
620
1356
                                   attribute_id,
625
1361
  } else {
626
1362
    add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
627
1363
  }
628
 
 
629
1364
  return retval;
630
1365
}
631
1366
 
645
1380
  uint16_t retval = value_default;
646
1381
  PTPParams *params = (PTPParams *) device->params;
647
1382
  uint16_t ret;
 
1383
  MTPProperties *prop;
648
1384
 
649
1385
  if ( device == NULL ) {
650
1386
    return value_default;
652
1388
 
653
1389
  // This O(n) search should not be used so often, since code
654
1390
  // using the cached properties don't usually call this function.
655
 
  if (params->props) {
656
 
    MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
657
 
    if (prop)
658
 
      return prop->propval.u16;
659
 
  }
 
1391
  prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
 
1392
  if (prop)
 
1393
    return prop->propval.u16;
660
1394
 
661
1395
  ret = ptp_mtp_getobjectpropvalue(params, object_id,
662
1396
                                   attribute_id,
687
1421
  uint8_t retval = value_default;
688
1422
  PTPParams *params = (PTPParams *) device->params;
689
1423
  uint16_t ret;
 
1424
  MTPProperties *prop;
690
1425
 
691
1426
  if ( device == NULL ) {
692
1427
    return value_default;
694
1429
 
695
1430
  // This O(n) search should not be used so often, since code
696
1431
  // using the cached properties don't usually call this function.
697
 
  if (params->props) {
698
 
    MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
699
 
    if (prop)
700
 
      return prop->propval.u8;
701
 
  }
 
1432
  prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
 
1433
  if (prop)
 
1434
    return prop->propval.u8;
702
1435
 
703
1436
  ret = ptp_mtp_getobjectpropvalue(params, object_id,
704
1437
                                   attribute_id,
965
1698
    return NULL;
966
1699
  }
967
1700
  memset(current_params, 0, sizeof(PTPParams));
 
1701
  current_params->device_flags = rawdevice->device_entry.device_flags;
 
1702
  current_params->nrofobjects = 0;
 
1703
  current_params->objects = NULL;
 
1704
  current_params->response_packet_size = 0;
 
1705
  current_params->response_packet = NULL;
968
1706
  /* This will be a pointer to PTP_USB later */
969
1707
  current_params->data = NULL;
970
1708
  /* Set upp local debug and error functions */
971
1709
  current_params->debug_func = LIBMTP_ptp_debug;
972
1710
  current_params->error_func = LIBMTP_ptp_error;
973
 
  /* Clear all handlers */
974
 
  current_params->handles.Handler = NULL;
975
 
  current_params->objectinfo = NULL;
976
 
  current_params->props = NULL;
977
1711
  /* TODO: Will this always be little endian? */
978
1712
  current_params->byteorder = PTP_DL_LE;
979
1713
  current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
1435
2169
                            "inconsistent results.");
1436
2170
    return -1;
1437
2171
  }
1438
 
  params->props = props; /* cache it */
1439
 
  params->nrofprops = nrofprops; /* cache it */
1440
 
  
1441
2172
  /* 
1442
2173
   * We count the number of objects by counting the ObjectHandle
1443
2174
   * references, whenever it changes we get a new object, when it's
1452
2183
      prop++;
1453
2184
  }
1454
2185
  lasthandle = 0xffffffff;
1455
 
  params->objectinfo = malloc (sizeof (PTPObjectInfo) * cnt);
1456
 
  memset (params->objectinfo, 0, sizeof(PTPObjectInfo) * cnt);
1457
 
  params->handles.Handler = malloc (sizeof (uint32_t) * cnt);
1458
 
  params->handles.n = cnt;
1459
 
  
 
2186
  params->objects = calloc (sizeof(PTPObject),cnt);
1460
2187
  prop = props;
1461
2188
  i = -1;
1462
2189
  for (j=0;j<nrofprops;j++) {
1463
2190
    if (lasthandle != prop->ObjectHandle) {
1464
2191
      if (i >= 0) {
1465
 
        if (!params->objectinfo[i].Filename) {
 
2192
        params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
 
2193
        if (!params->objects[i].oi.Filename) {
1466
2194
          /* I have one such file on my Creative (Marcus) */
1467
 
          params->objectinfo[i].Filename = strdup("<null>");
 
2195
          params->objects[i].oi.Filename = strdup("<null>");
1468
2196
        }
1469
2197
      }
1470
2198
      i++;
1471
2199
      lasthandle = prop->ObjectHandle;
1472
 
      params->handles.Handler[i] = prop->ObjectHandle;
 
2200
      params->objects[i].oid = prop->ObjectHandle;
1473
2201
    }
1474
2202
    switch (prop->property) {
1475
2203
    case PTP_OPC_ParentObject:
1476
 
      params->objectinfo[i].ParentObject = prop->propval.u32;
 
2204
      params->objects[i].oi.ParentObject = prop->propval.u32;
 
2205
      params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
1477
2206
      break;
1478
2207
    case PTP_OPC_ObjectFormat:
1479
 
      params->objectinfo[i].ObjectFormat = prop->propval.u16;
 
2208
      params->objects[i].oi.ObjectFormat = prop->propval.u16;
1480
2209
      break;
1481
2210
    case PTP_OPC_ObjectSize:
1482
2211
      // We loose precision here, up to 32 bits! However the commands that
1483
2212
      // retrieve metadata for files and tracks will make sure that the
1484
2213
      // PTP_OPC_ObjectSize is read in and duplicated again.
1485
2214
      if (device->object_bitsize == 64) {
1486
 
        params->objectinfo[i].ObjectCompressedSize = (uint32_t) prop->propval.u64;
 
2215
        params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
1487
2216
      } else {
1488
 
        params->objectinfo[i].ObjectCompressedSize = prop->propval.u32;
 
2217
        params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
1489
2218
      }
1490
2219
      break;
1491
2220
    case PTP_OPC_StorageID:
1492
 
      params->objectinfo[i].StorageID = prop->propval.u32;
 
2221
      params->objects[i].oi.StorageID = prop->propval.u32;
 
2222
      params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
1493
2223
      break;
1494
2224
    case PTP_OPC_ObjectFileName:
1495
2225
      if (prop->propval.str != NULL)
1496
 
        params->objectinfo[i].Filename = strdup(prop->propval.str);
1497
 
      break;
1498
 
    default:
1499
 
      /*
1500
 
       * This was in libgphoto2 no idea what it tests for...
1501
 
       * if ((prop->property & 0xfff0) == 0xdc00)
1502
 
       * gp_log (GP_LOG_DEBUG, "ptp2/mtpfast", "case %x type %x unhandled.\n", prop->property, prop->datatype);
1503
 
       */
1504
 
      break;
1505
 
      // FIXME: the rest of the metadata is readily available right here!
 
2226
        params->objects[i].oi.Filename = strdup(prop->propval.str);
 
2227
      break;
 
2228
    default: {
 
2229
      MTPProperties *newprops;
 
2230
 
 
2231
      /* Copy all of the other MTP oprierties into the per-object proplist */
 
2232
      if (params->objects[i].nrofmtpprops) {
 
2233
        newprops = realloc(params->objects[i].mtpprops,(params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
 
2234
      } else {
 
2235
        newprops = calloc(sizeof(MTPProperties),1);
 
2236
      }
 
2237
      if (!newprops) return 0; /* FIXME: error handling? */
 
2238
      params->objects[i].mtpprops = newprops;
 
2239
      memcpy(&params->objects[i].mtpprops[params->objects[i].nrofmtpprops],&props[j],sizeof(props[j]));
 
2240
      params->objects[i].nrofmtpprops++;
 
2241
      params->objects[i].flags |= PTPOBJECT_MTPPROPLIST_LOADED;
 
2242
      break;
 
2243
    }
1506
2244
    }
1507
2245
    prop++;
1508
2246
  }
 
2247
  /* mark last entry also */
 
2248
  params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED;
 
2249
  params->nrofobjects = i+1;
 
2250
  /* The device might not give the list in linear ascending order */
 
2251
  ptp_objects_sort (params);
1509
2252
  return 0;
1510
2253
}
1511
2254
 
1518
2261
 */
1519
2262
static void get_handles_recursively(LIBMTP_mtpdevice_t *device, 
1520
2263
                                    PTPParams *params, 
1521
 
                                    PTPObjectHandles *handles, 
1522
2264
                                    uint32_t storageid,
1523
2265
                                    uint32_t parent)
1524
2266
{
1525
2267
  PTPObjectHandles currentHandles;
1526
2268
  int i = 0;
1527
 
  uint32_t old_handles;
1528
 
  
1529
2269
  uint16_t ret = ptp_getobjecthandles(params,
1530
2270
                                      storageid,
1531
2271
                                      PTP_GOH_ALL_FORMATS,
1540
2280
  if (currentHandles.Handler == NULL || currentHandles.n == 0)
1541
2281
    return;
1542
2282
 
1543
 
  old_handles = handles->n;
1544
 
  
1545
 
  // Realloc main space
1546
 
  handles->Handler = (uint32_t *) realloc(handles->Handler, 
1547
 
                                          (old_handles + currentHandles.n) * sizeof(uint32_t));
1548
 
  // Realloc object info cache
1549
 
  params->objectinfo = (PTPObjectInfo*) realloc(params->objectinfo, 
1550
 
                                          (old_handles + currentHandles.n) * sizeof(PTPObjectInfo));
1551
 
  memset(&params->objectinfo[old_handles], 0, currentHandles.n * sizeof(PTPObjectInfo));
1552
 
 
1553
 
  // Copy new handles
1554
 
  memmove(&(handles->Handler[old_handles]), currentHandles.Handler, currentHandles.n * sizeof(uint32_t));
1555
 
  handles->n = old_handles + currentHandles.n;
1556
 
  
1557
2283
  // Now descend into any subdirectories found
1558
2284
  for (i = 0; i < currentHandles.n; i++) {    
1559
 
    ret = ptp_getobjectinfo(params,
1560
 
                            currentHandles.Handler[i],
1561
 
                            &params->objectinfo[old_handles + i]);
1562
 
    
 
2285
    PTPObject *ob;
 
2286
    ret = ptp_object_want(params,currentHandles.Handler[i],PTPOBJECT_OBJECTINFO_LOADED, &ob);
1563
2287
    if (ret == PTP_RC_OK) {
1564
 
      PTPObjectInfo *oi;
1565
 
 
1566
 
      oi = &params->objectinfo[old_handles + i];
1567
 
      if (oi->ObjectFormat == PTP_OFC_Association) {
1568
 
        get_handles_recursively(device, params, handles, storageid, currentHandles.Handler[i]);
1569
 
      }
 
2288
      if (ob->oi.ObjectFormat == PTP_OFC_Association)
 
2289
        get_handles_recursively(device, params, storageid, currentHandles.Handler[i]);
1570
2290
    } else {
1571
2291
      add_error_to_errorstack(device,
1572
2292
                              LIBMTP_ERROR_CONNECTING,
1573
2293
                              "Found a bad handle, trying to ignore it.");
1574
2294
    }
1575
2295
  }
1576
 
   
1577
2296
  free(currentHandles.Handler);
1578
2297
}
1579
2298
 
1591
2310
  int ret;
1592
2311
  uint32_t i;
1593
2312
 
1594
 
  if (params->handles.Handler != NULL) {
1595
 
    free(params->handles.Handler);
1596
 
  }
1597
 
  if (params->objectinfo != NULL) {
1598
 
    for (i=0;i<params->handles.n;i++)
1599
 
      ptp_free_objectinfo (&params->objectinfo[i]);
1600
 
    free(params->objectinfo);
1601
 
  }
1602
 
  if (params->props != NULL) {
1603
 
    ptp_destroy_object_prop_list(params->props, params->nrofprops);
1604
 
  }
1605
 
  
1606
 
  params->handles.n = 0;
1607
 
  params->handles.Handler = NULL;
1608
 
  params->objectinfo = NULL;
1609
 
  params->props = NULL;
1610
 
  params->nrofprops = 0;
 
2313
  if (params->objects != NULL) {
 
2314
    for (i=0;i<params->nrofobjects;i++)
 
2315
      ptp_free_object (&params->objects[i]);
 
2316
    free(params->objects);
 
2317
    params->objects = NULL;
 
2318
    params->nrofobjects = 0;
 
2319
  }
1611
2320
 
1612
2321
  if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
1613
2322
      && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
1617
2326
  }
1618
2327
  // If the previous failed or returned no objects, use classic
1619
2328
  // methods instead.
1620
 
  if (params->props == NULL) {
 
2329
  if (params->nrofobjects == 0) {
1621
2330
    // Get all the handles using just standard commands.
1622
2331
    if (device->storage == NULL) {
1623
2332
      get_handles_recursively(device, params,
1624
 
                              &params->handles,
1625
2333
                              PTP_GOH_ALL_STORAGE,
1626
2334
                              PTP_GOH_ROOT_PARENT);
1627
2335
    } else {
1629
2337
      LIBMTP_devicestorage_t *storage = device->storage;
1630
2338
      while(storage != NULL) {
1631
2339
        get_handles_recursively(device, params,
1632
 
                                &params->handles,
1633
2340
                                storage->id,
1634
2341
                                PTP_GOH_ROOT_PARENT);
1635
2342
        storage = storage->next;
1642
2349
   * keywords, then attempt to locate some default folders
1643
2350
   * in the root directory of the primary storage.
1644
2351
   */
1645
 
  for(i = 0; i < params->handles.n; i++) {
1646
 
    PTPObjectInfo *oi;
1647
 
    
1648
 
    oi = &params->objectinfo[i];
1649
 
    if (oi->Filename == NULL) {
1650
 
      oi->Filename = strdup("<null>");
1651
 
    }
1652
 
    if (oi->Keywords == NULL) {
1653
 
      oi->Keywords = strdup("<null>");
1654
 
    }
1655
 
    
 
2352
  for(i = 0; i < params->nrofobjects; i++) {
 
2353
    PTPObject *ob, *xob;
 
2354
 
 
2355
    ob = &params->objects[i];
 
2356
    ret = ptp_object_want(params,params->objects[i].oid,PTPOBJECT_OBJECTINFO_LOADED, &xob);
 
2357
    if (ret != PTP_RC_OK) {
 
2358
        fprintf(stderr,"broken! %x not found\n", params->objects[i].oid);
 
2359
    }
 
2360
    if (ob->oi.Filename == NULL)
 
2361
      ob->oi.Filename = strdup("<null>");
 
2362
    if (ob->oi.Keywords == NULL)
 
2363
      ob->oi.Keywords = strdup("<null>");
 
2364
 
1656
2365
    /* Ignore handles that point to non-folders */
1657
 
    if(oi->ObjectFormat != PTP_OFC_Association)
 
2366
    if(ob->oi.ObjectFormat != PTP_OFC_Association)
1658
2367
      continue;
1659
2368
    /* Only look in the root folder */
1660
 
    if (oi->ParentObject != 0x00000000U)
 
2369
    if (ob->oi.ParentObject != 0x00000000U)
1661
2370
      continue;
1662
2371
    /* Only look in the primary storage */
1663
 
    if (device->storage != NULL && oi->StorageID != device->storage->id)
 
2372
    if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
1664
2373
      continue;
1665
2374
 
1666
2375
    
1667
2376
    /* Is this the Music Folder */
1668
 
    if (!strcasecmp(oi->Filename, "My Music") ||
1669
 
        !strcasecmp(oi->Filename, "Music")) {
1670
 
      device->default_music_folder = 
1671
 
        params->handles.Handler[i];
1672
 
    }
1673
 
    else if (!strcasecmp(oi->Filename, "My Playlists") ||
1674
 
             !strcasecmp(oi->Filename, "Playlists")) {
1675
 
      device->default_playlist_folder =
1676
 
        params->handles.Handler[i];
1677
 
    }
1678
 
    else if (!strcasecmp(oi->Filename, "My Pictures") ||
1679
 
             !strcasecmp(oi->Filename, "Pictures")) {
1680
 
      device->default_picture_folder = 
1681
 
        params->handles.Handler[i];
1682
 
    }
1683
 
    else if (!strcasecmp(oi->Filename, "My Video") ||
1684
 
             !strcasecmp(oi->Filename, "Video")) {
1685
 
        device->default_video_folder = 
1686
 
          params->handles.Handler[i];
1687
 
    }
1688
 
    else if (!strcasecmp(oi->Filename, "My Organizer")) {
1689
 
      device->default_organizer_folder =
1690
 
        params->handles.Handler[i];
1691
 
    }
1692
 
    else if (!strcasecmp(oi->Filename, "ZENcast") ||
1693
 
             !strcasecmp(oi->Filename, "Datacasts")) {
1694
 
      device->default_zencast_folder = 
1695
 
        params->handles.Handler[i];
1696
 
    }
1697
 
    else if (!strcasecmp(oi->Filename, "My Albums") ||
1698
 
             !strcasecmp(oi->Filename, "Albums")) {
1699
 
      device->default_album_folder = 
1700
 
        params->handles.Handler[i];
1701
 
    }
1702
 
    else if (!strcasecmp(oi->Filename, "Text") ||
1703
 
             !strcasecmp(oi->Filename, "Texts")) {
1704
 
      device->default_text_folder =
1705
 
        params->handles.Handler[i];
 
2377
    if (!strcasecmp(ob->oi.Filename, "My Music") ||
 
2378
        !strcasecmp(ob->oi.Filename, "Music")) {
 
2379
      device->default_music_folder = ob->oid;
 
2380
    }
 
2381
    else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
 
2382
             !strcasecmp(ob->oi.Filename, "Playlists")) {
 
2383
      device->default_playlist_folder = ob->oid;
 
2384
    }
 
2385
    else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
 
2386
             !strcasecmp(ob->oi.Filename, "Pictures")) {
 
2387
      device->default_picture_folder = ob->oid;
 
2388
    }
 
2389
    else if (!strcasecmp(ob->oi.Filename, "My Video") ||
 
2390
             !strcasecmp(ob->oi.Filename, "Video")) {
 
2391
        device->default_video_folder = ob->oid;
 
2392
    }
 
2393
    else if (!strcasecmp(ob->oi.Filename, "My Organizer")) {
 
2394
      device->default_organizer_folder = ob->oid;
 
2395
    }
 
2396
    else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
 
2397
             !strcasecmp(ob->oi.Filename, "Datacasts")) {
 
2398
      device->default_zencast_folder = ob->oid;
 
2399
    }
 
2400
    else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
 
2401
             !strcasecmp(ob->oi.Filename, "Albums")) {
 
2402
      device->default_album_folder = ob->oid;
 
2403
    }
 
2404
    else if (!strcasecmp(ob->oi.Filename, "Text") ||
 
2405
             !strcasecmp(ob->oi.Filename, "Texts")) {
 
2406
      device->default_text_folder = ob->oid;
1706
2407
    }
1707
2408
  }
1708
2409
}
1981
2682
          PTPObjectPropDesc opd;
1982
2683
          int k;
1983
2684
          
1984
 
          (void) ptp_render_mtp_propname(props[j],sizeof(txt),txt);
1985
 
          printf("      %04x: %s", props[j], txt);
 
2685
          printf("      %04x: %s", props[j], LIBMTP_Get_Property_Description(map_ptp_property_to_libmtp_property(props[j])));
1986
2686
          // Get a more verbose description
1987
2687
          ret = ptp_mtp_getobjectpropdesc(params, props[j], params->deviceinfo.ImageFormats[i], &opd);
1988
2688
          if (ret != PTP_RC_OK) {
2737
3437
    localtypes[localtypelen] = LIBMTP_FILETYPE_OGG;
2738
3438
    localtypelen++;
2739
3439
  }
 
3440
  // The forgotten FLAC support on Cowon iAudio S9 and others...
 
3441
  if (FLAG_FLAC_IS_UNKNOWN(ptp_usb)) {
 
3442
    localtypes = (uint16_t *) realloc(localtypes, (params->deviceinfo.ImageFormats_len+1) * sizeof(uint16_t));
 
3443
    localtypes[localtypelen] = LIBMTP_FILETYPE_FLAC;
 
3444
    localtypelen++;
 
3445
  }
2740
3446
 
2741
3447
  *filetypes = localtypes;
2742
3448
  *length = localtypelen;
2883
3589
  new->parent_id = 0;
2884
3590
  new->storage_id = 0;
2885
3591
  new->filesize = 0;
 
3592
  new->modificationdate = 0;
2886
3593
  new->filetype = LIBMTP_FILETYPE_UNKNOWN;
2887
3594
  new->next = NULL;
2888
3595
  return new;
2971
3678
  uint16_t ret;
2972
3679
 
2973
3680
  // Get all the handles if we haven't already done that
2974
 
  if (params->handles.Handler == NULL) {
 
3681
  if (params->nrofobjects == 0) {
2975
3682
    flush_handles(device);
2976
3683
  }
2977
3684
 
2978
 
  for (i = 0; i < params->handles.n; i++) {
 
3685
  for (i = 0; i < params->nrofobjects; i++) {
2979
3686
    LIBMTP_file_t *file;
2980
 
    PTPObjectInfo *oi;
 
3687
    PTPObject *ob, *xob;
2981
3688
 
2982
3689
    if (callback != NULL)
2983
 
      callback(i, params->handles.n, data);
2984
 
 
2985
 
    oi = &params->objectinfo[i];
2986
 
 
2987
 
    if (oi->ObjectFormat == PTP_OFC_Association) {
 
3690
      callback(i, params->nrofobjects, data);
 
3691
 
 
3692
    ob = &params->objects[i];
 
3693
 
 
3694
    if (ob->oi.ObjectFormat == PTP_OFC_Association) {
2988
3695
      // MTP use this object format for folders which means
2989
3696
      // these "files" will turn up on a folder listing instead.
2990
3697
      continue;
2993
3700
    // Allocate a new file type
2994
3701
    file = LIBMTP_new_file_t();
2995
3702
 
2996
 
    file->parent_id = oi->ParentObject;
2997
 
    file->storage_id = oi->StorageID;
 
3703
    file->parent_id = ob->oi.ParentObject;
 
3704
    file->storage_id = ob->oi.StorageID;
2998
3705
 
2999
3706
    // This is some sort of unique ID so we can keep track of the track.
3000
 
    file->item_id = params->handles.Handler[i];
 
3707
    file->item_id = ob->oid;
3001
3708
 
3002
3709
    // Set the filetype
3003
 
    file->filetype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
 
3710
    file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
 
3711
    
 
3712
    // Set the modification date
 
3713
    file->modificationdate = ob->oi.ModificationDate;
3004
3714
 
3005
3715
    // Original file-specific properties
3006
3716
    // We only have 32-bit file size here; if we find it, we use the 
3007
3717
    // PTP_OPC_ObjectSize property which has 64bit precision.
3008
 
    file->filesize = oi->ObjectCompressedSize;
3009
 
    if (oi->Filename != NULL) {
3010
 
      file->filename = strdup(oi->Filename);
 
3718
    file->filesize = ob->oi.ObjectCompressedSize;
 
3719
    if (ob->oi.Filename != NULL) {
 
3720
      file->filename = strdup(ob->oi.Filename);
3011
3721
    }
3012
3722
 
3013
3723
    /*
3014
 
     * A special quirk for iriver devices that doesn't quite
 
3724
     * A special quirk for devices that doesn't quite
3015
3725
     * remember that some files marked as "unknown" type are
3016
 
     * actually OGG files. We look at the filename extension
3017
 
     * and see if it happens that this was atleast named "ogg"
 
3726
     * actually OGG or FLAC files. We look at the filename extension
 
3727
     * and see if it happens that this was atleast named "ogg" or "flac"
3018
3728
     * and fall back on this heuristic approach in that case, 
3019
3729
     * for these bugged devices only.
3020
3730
     */
3021
 
    if (file->filetype == LIBMTP_FILETYPE_UNKNOWN &&
3022
 
        (FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
3023
 
         FLAG_OGG_IS_UNKNOWN(ptp_usb))) {
3024
 
      // Repair forgotten OGG filetype
3025
 
      if (has_ogg_extension(file->filename)) {
3026
 
        // Fix it.
3027
 
        file->filetype = LIBMTP_FILETYPE_OGG;
3028
 
      }
 
3731
    if (file->filetype == LIBMTP_FILETYPE_UNKNOWN) {
 
3732
      if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
 
3733
           FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
 
3734
          has_ogg_extension(file->filename))
 
3735
        file->filetype = LIBMTP_FILETYPE_OGG;
 
3736
      if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
 
3737
          has_flac_extension(file->filename))
 
3738
        file->filetype = LIBMTP_FILETYPE_FLAC;
3029
3739
    }
3030
3740
 
3031
3741
    /*
3032
3742
     * If we have a cached, large set of metadata, then use it!
3033
3743
     */
3034
 
    if (params->props) {
3035
 
      MTPProperties *prop = params->props;
 
3744
    ret = ptp_object_want (params, ob->oid, PTPOBJECT_MTPPROPLIST_LOADED, &xob);
 
3745
    if (ob->mtpprops) {
 
3746
      MTPProperties *prop = ob->mtpprops;
3036
3747
      int i;
3037
 
      
3038
 
      for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != file->item_id);i++,prop++)
3039
 
                /*empty*/;
3040
 
      for (;i<params->nrofprops;i++) {
3041
 
        if (prop->ObjectHandle != file->item_id)
3042
 
          break;
3043
3748
 
 
3749
      for (i=0;i<ob->nrofmtpprops;i++) {
3044
3750
        // Pick ObjectSize here...
3045
3751
        if (prop->property == PTP_OPC_ObjectSize) {
3046
3752
          if (device->object_bitsize == 64) {
3050
3756
          }
3051
3757
          break;
3052
3758
        }
3053
 
        prop ++;
3054
 
      }
3055
 
    } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
3056
 
               && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
3057
 
      MTPProperties *props = NULL;
3058
 
      MTPProperties *prop;
3059
 
      
3060
 
      int nrofprops;
3061
 
      
3062
 
      /*
3063
 
       * This should retrieve all properties for an object, but on devices
3064
 
       * which are inherently broken it will not, so these need the
3065
 
       * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
3066
 
       */
3067
 
      ret = ptp_mtp_getobjectproplist(params, file->item_id, &props, &nrofprops);
3068
 
      if (ret != PTP_RC_OK) {
3069
 
        add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): call to ptp_mtp_getobjectproplist() failed.");
3070
 
        // Silently fall through.
3071
 
      }
3072
 
      if (props == NULL && nrofprops != 0) {
3073
 
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3074
 
                                "LIBMTP_Get_Filelisting_With_Callback: "
3075
 
                                "call to ptp_mtp_getobjectproplist() returned "
3076
 
                                "inconsistent results.");
3077
 
        nrofprops = 0;
3078
 
      }
3079
 
      if (props != NULL) {
3080
 
        int i;
3081
 
        prop = props;
3082
 
        for (i=0;i<nrofprops;i++) {
3083
 
          if (prop->ObjectHandle != file->item_id)
3084
 
            break;
3085
 
          // Pick ObjectSize here...
3086
 
          if (prop->property == PTP_OPC_ObjectSize) {
3087
 
            if (device->object_bitsize == 64) {
3088
 
              file->filesize = prop->propval.u64;
3089
 
            } else {
3090
 
              file->filesize = prop->propval.u32;
3091
 
            }
3092
 
            break;
3093
 
          }
3094
 
          prop ++;
3095
 
        }
3096
 
        ptp_destroy_object_prop_list(props, nrofprops);
 
3759
        prop++;
3097
3760
      }
3098
3761
    } else {
3099
3762
      uint16_t *props = NULL;
3100
3763
      uint32_t propcnt = 0;
3101
3764
      
3102
3765
      // First see which properties can be retrieved for this object format
3103
 
      ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
 
3766
      ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
3104
3767
      if (ret != PTP_RC_OK) {
3105
3768
        add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): call to ptp_mtp_getobjectpropssupported() failed.");
3106
3769
        // Silently fall through.
3161
3824
{
3162
3825
  uint32_t i = 0;
3163
3826
  PTPParams *params = (PTPParams *) device->params;
3164
 
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3165
3827
  uint16_t ret;
 
3828
  PTPObject *ob;
 
3829
  LIBMTP_file_t *file;
3166
3830
 
3167
3831
  // Get all the handles if we haven't already done that
3168
 
  if (params->handles.Handler == NULL) {
 
3832
  if (params->nrofobjects == 0) {
3169
3833
    flush_handles(device);
3170
3834
  }
3171
3835
 
3172
 
  for (i = 0; i < params->handles.n; i++) {
3173
 
    LIBMTP_file_t *file;
3174
 
    PTPObjectInfo *oi;
3175
 
 
3176
 
    // Is this the file we're looking for?
3177
 
    if (params->handles.Handler[i] != fileid) {
3178
 
      continue;
3179
 
    }
3180
 
 
3181
 
    oi = &params->objectinfo[i];
3182
 
 
3183
 
    // Allocate a new file type
3184
 
    file = LIBMTP_new_file_t();
3185
 
    
3186
 
    file->parent_id = oi->ParentObject;
3187
 
    file->storage_id = oi->StorageID;
3188
 
 
3189
 
    // Set the filetype
3190
 
    file->filetype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
3191
 
 
3192
 
    // Original file-specific properties
3193
 
    
3194
 
    // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
3195
 
    file->filesize = oi->ObjectCompressedSize;
3196
 
    if (oi->Filename != NULL) {
3197
 
      file->filename = strdup(oi->Filename);
3198
 
    }
3199
 
 
3200
 
    // This is some sort of unique ID so we can keep track of the file.
3201
 
    file->item_id = params->handles.Handler[i];
3202
 
 
3203
 
    /*
3204
 
     * If we have a cached, large set of metadata, then use it!
3205
 
     */
3206
 
    if (params->props) {
3207
 
      MTPProperties *prop = params->props;
3208
 
      
3209
 
      for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != file->item_id);i++,prop++)
3210
 
                /*empty*/;
3211
 
      for (;(i<params->nrofprops) && (prop->ObjectHandle == file->item_id);i++,prop++) {
3212
 
        // Pick ObjectSize here...
3213
 
        if (prop->property == PTP_OPC_ObjectSize) {
3214
 
          // This may already be set, but this 64bit precision value 
3215
 
          // is better than the PTP 32bit value, so let it override.
3216
 
          if (device->object_bitsize == 64) {
3217
 
            file->filesize = prop->propval.u64;
3218
 
          } else {
3219
 
            file->filesize = prop->propval.u32;
3220
 
          }
3221
 
          break;
3222
 
        }
3223
 
      }
3224
 
    } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
3225
 
               && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
3226
 
      MTPProperties *props = NULL;
3227
 
      MTPProperties *prop;
3228
 
      int nrofprops;
3229
 
      
3230
 
      /*
3231
 
       * This should retrieve all properties for an object, but on devices
3232
 
       * which are inherently broken it will not, so these need the
3233
 
       * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
3234
 
       */
3235
 
      ret = ptp_mtp_getobjectproplist(params, file->item_id, &props, &nrofprops);
3236
 
      if (ret != PTP_RC_OK) {
3237
 
        add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): "
3238
 
                                    "call to ptp_mtp_getobjectproplist() failed.");
3239
 
        // Silently fall through.
3240
 
      }
3241
 
      if (props == NULL && nrofprops != 0) {
3242
 
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, 
3243
 
                                "LIBMTP_Get_Filelisting_With_Callback(): "
3244
 
                                "call to ptp_mtp_getobjectproplist() returned "
3245
 
                                "inconsistent results.");
3246
 
        return NULL;
3247
 
      }
3248
 
      prop = props;
3249
 
      for (i=0;i<nrofprops;i++) {
3250
 
        if ((prop->ObjectHandle == file->item_id) && (prop->property == PTP_OPC_ObjectSize)) {
3251
 
          // This may already be set, but this 64bit precision value 
3252
 
          // is better than the PTP 32bit value, so let it override.
3253
 
          if (device->object_bitsize == 64) {
3254
 
            file->filesize = prop->propval.u64;
3255
 
          } else {
3256
 
            file->filesize = prop->propval.u32;
3257
 
          }
3258
 
          break;
3259
 
        }
3260
 
        prop ++;
3261
 
      }
3262
 
      ptp_destroy_object_prop_list(props, nrofprops);
 
3836
  ret = ptp_object_want (params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
 
3837
  if (ret != PTP_RC_OK)
 
3838
    return NULL;
 
3839
 
 
3840
  // Allocate a new file type
 
3841
  file = LIBMTP_new_file_t();
 
3842
  
 
3843
  file->parent_id = ob->oi.ParentObject;
 
3844
  file->storage_id = ob->oi.StorageID;
 
3845
 
 
3846
  // Set the filetype
 
3847
  file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
 
3848
 
 
3849
  // Original file-specific properties
 
3850
  
 
3851
  // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
 
3852
  file->filesize = ob->oi.ObjectCompressedSize;
 
3853
  if (ob->oi.Filename != NULL) {
 
3854
    file->filename = strdup(ob->oi.Filename);
 
3855
  }
 
3856
 
 
3857
  // This is some sort of unique ID so we can keep track of the file.
 
3858
  file->item_id = fileid;
 
3859
 
 
3860
  /*
 
3861
   * If we have a cached, large set of metadata, then use it!
 
3862
   */
 
3863
  if (ob->mtpprops) {
 
3864
    MTPProperties *prop = ob->mtpprops;
 
3865
    
 
3866
    for (i=0;i<ob->nrofmtpprops;i++,prop++) {
 
3867
      // Pick ObjectSize here...
 
3868
      if (prop->property == PTP_OPC_ObjectSize) {
 
3869
        // This may already be set, but this 64bit precision value 
 
3870
        // is better than the PTP 32bit value, so let it override.
 
3871
        if (device->object_bitsize == 64) {
 
3872
          file->filesize = prop->propval.u64;
 
3873
        } else {
 
3874
          file->filesize = prop->propval.u32;
 
3875
        }
 
3876
        break;
 
3877
      }
 
3878
    }
 
3879
  } else {
 
3880
    uint16_t *props = NULL;
 
3881
    uint32_t propcnt = 0;
 
3882
    
 
3883
    // First see which properties can be retrieved for this object format
 
3884
    ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
 
3885
    if (ret != PTP_RC_OK) {
 
3886
      add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filemetadata(): call to ptp_mtp_getobjectpropssupported() failed.");
 
3887
      // Silently fall through.
3263
3888
    } else {
3264
 
      uint16_t *props = NULL;
3265
 
      uint32_t propcnt = 0;
3266
 
      
3267
 
      // First see which properties can be retrieved for this object format
3268
 
      ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
3269
 
      if (ret != PTP_RC_OK) {
3270
 
        add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filemetadata(): call to ptp_mtp_getobjectpropssupported() failed.");
3271
 
        // Silently fall through.
3272
 
      } else {
3273
 
        for (i=0;i<propcnt;i++) {
3274
 
          switch (props[i]) {
3275
 
          case PTP_OPC_ObjectSize:
3276
 
            if (device->object_bitsize == 64) {
3277
 
              file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
3278
 
            } else {
3279
 
              file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
3280
 
            }
3281
 
            break;
3282
 
          default:
3283
 
            break;
 
3889
      for (i=0;i<propcnt;i++) {
 
3890
        switch (props[i]) {
 
3891
        case PTP_OPC_ObjectSize:
 
3892
          if (device->object_bitsize == 64) {
 
3893
            file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
 
3894
          } else {
 
3895
            file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
3284
3896
          }
 
3897
          break;
 
3898
        default:
 
3899
          break;
3285
3900
        }
3286
 
        free(props);
3287
3901
      }
 
3902
      free(props);
3288
3903
    }
3289
 
    
3290
 
    return file;
3291
 
    
3292
3904
  }
3293
 
  return NULL;
 
3905
  
 
3906
  return file;
3294
3907
}
3295
3908
 
3296
3909
/**
3337
3950
  new->bitratetype = 0;
3338
3951
  new->rating = 0;
3339
3952
  new->usecount = 0;
 
3953
  new->modificationdate = 0;
3340
3954
  new->next = NULL;
3341
3955
  return new;
3342
3956
}
3466
4080
{
3467
4081
  uint16_t ret;
3468
4082
  PTPParams *params = (PTPParams *) device->params;
3469
 
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3470
4083
  uint32_t i;
 
4084
  MTPProperties *prop;
 
4085
  PTPObject *ob;
3471
4086
 
3472
4087
  /*
3473
4088
   * If we have a cached, large set of metadata, then use it!
3474
4089
   */
3475
 
  if (params->props) {
3476
 
    MTPProperties *prop = params->props;
3477
 
 
3478
 
    for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != track->item_id);i++,prop++)
3479
 
      /*empty*/;
3480
 
    for (i=0;(i<params->nrofprops) && (prop->ObjectHandle == track->item_id);i++,prop++) {
 
4090
  ret = ptp_object_want(params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
 
4091
  if (ob->mtpprops) {
 
4092
    prop = ob->mtpprops;
 
4093
    for (i=0;i<ob->nrofmtpprops;i++,prop++)
3481
4094
      pick_property_to_track_metadata(device, prop, track);
3482
 
    }
3483
 
  } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
3484
 
             && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
3485
 
    MTPProperties *props = NULL;
3486
 
    MTPProperties *prop;
3487
 
    int nrofprops;
3488
 
 
3489
 
    /*
3490
 
     * This should retrieve all properties for an object, but on devices
3491
 
     * which are inherently broken it will not, so these need the
3492
 
     * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
3493
 
     */
3494
 
    ret = ptp_mtp_getobjectproplist(params, track->item_id, &props, &nrofprops);
3495
 
    if (ret != PTP_RC_OK) {
3496
 
      add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectproplist() failed.");
3497
 
      return;
3498
 
    }
3499
 
    if (props == NULL && nrofprops != 0) {
3500
 
      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
3501
 
                              "get_track_metadata(): "
3502
 
                              "call to ptp_mtp_getobjectproplist() returned "
3503
 
                              "inconsistent results.");
3504
 
      return;
3505
 
    }
3506
 
    prop = props;
3507
 
    for (i=0;i<nrofprops;i++,prop++) {
3508
 
      if (prop->ObjectHandle == track->item_id)
3509
 
        pick_property_to_track_metadata(device, prop, track);
3510
 
    }
3511
 
    ptp_destroy_object_prop_list(props, nrofprops);
3512
4095
  } else {
3513
4096
    uint16_t *props = NULL;
3514
4097
    uint32_t propcnt = 0;
3646
4229
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
3647
4230
 
3648
4231
  // Get all the handles if we haven't already done that
3649
 
  if (params->handles.Handler == NULL) {
 
4232
  if (params->nrofobjects == 0) {
3650
4233
    flush_handles(device);
3651
4234
  }
3652
4235
 
3653
 
  for (i = 0; i < params->handles.n; i++) {
 
4236
  for (i = 0; i < params->nrofobjects; i++) {
3654
4237
    LIBMTP_track_t *track;
3655
 
    PTPObjectInfo *oi;
 
4238
    PTPObject *ob;
3656
4239
    LIBMTP_filetype_t mtptype;
3657
4240
 
3658
4241
    if (callback != NULL)
3659
 
      callback(i, params->handles.n, data);
 
4242
      callback(i, params->nrofobjects, data);
3660
4243
 
3661
 
    oi = &params->objectinfo[i];
3662
 
    mtptype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
 
4244
    ob = &params->objects[i];
 
4245
    mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
3663
4246
 
3664
4247
    // Ignore stuff we don't know how to handle...
3665
4248
    // TODO: get this list as an intersection of the sets
3667
4250
    // all known track files?
3668
4251
    if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
3669
4252
        // This row lets through undefined files for examination since they may be forgotten OGG files.
3670
 
        (oi->ObjectFormat != PTP_OFC_Undefined || 
 
4253
        (ob->oi.ObjectFormat != PTP_OFC_Undefined || 
3671
4254
         (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
3672
 
         !FLAG_OGG_IS_UNKNOWN(ptp_usb)))
 
4255
          !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
 
4256
          !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
3673
4257
        ) {
3674
4258
      //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
3675
4259
      continue;
3679
4263
    track = LIBMTP_new_track_t();
3680
4264
      
3681
4265
    // This is some sort of unique ID so we can keep track of the track.
3682
 
    track->item_id = params->handles.Handler[i];
3683
 
    track->parent_id = oi->ParentObject;
3684
 
    track->storage_id = oi->StorageID;
 
4266
    track->item_id = ob->oid;
 
4267
    track->parent_id = ob->oi.ParentObject;
 
4268
    track->storage_id = ob->oi.StorageID;
 
4269
    track->modificationdate = ob->oi.ModificationDate;
3685
4270
 
3686
4271
    track->filetype = mtptype;
3687
4272
 
3688
4273
    // Original file-specific properties
3689
 
    track->filesize = oi->ObjectCompressedSize;
3690
 
    if (oi->Filename != NULL) {
3691
 
      track->filename = strdup(oi->Filename);
 
4274
    track->filesize = ob->oi.ObjectCompressedSize;
 
4275
    if (ob->oi.Filename != NULL) {
 
4276
      track->filename = strdup(ob->oi.Filename);
3692
4277
    }
3693
4278
 
3694
 
    get_track_metadata(device, oi->ObjectFormat, track);
 
4279
    get_track_metadata(device, ob->oi.ObjectFormat, track);
3695
4280
 
3696
4281
    /*
3697
4282
     * A special quirk for iriver devices that doesn't quite
3698
4283
     * remember that some files marked as "unknown" type are
3699
 
     * actually OGG files. We look at the filename extension
3700
 
     * and see if it happens that this was atleast named "ogg"
3701
 
     * and fall back on this heuristic approach in that case, 
 
4284
     * actually OGG or FLAC files. We look at the filename extension
 
4285
     * and see if it happens that this was atleast named "ogg" or "flac"
 
4286
     * and fall back on this heuristic approach in that case,
3702
4287
     * for these bugged devices only.
3703
4288
     */
3704
4289
    if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
3705
 
        track->filename != NULL &&
3706
 
        (FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
3707
 
         FLAG_OGG_IS_UNKNOWN(ptp_usb))) {
3708
 
      // Repair forgotten OGG filetype
3709
 
      if (has_ogg_extension(track->filename)) {
 
4290
        track->filename != NULL) {
 
4291
      if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
 
4292
           FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
 
4293
          has_ogg_extension(track->filename))
3710
4294
        track->filetype = LIBMTP_FILETYPE_OGG;
3711
 
      } else {
3712
 
        // This was not an OGG file so discard it and continue
 
4295
      else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
 
4296
               has_flac_extension(track->filename))
 
4297
        track->filetype = LIBMTP_FILETYPE_FLAC;
 
4298
      else {
 
4299
        // This was not an OGG/FLAC file so discard it and continue
3713
4300
        LIBMTP_destroy_track_t(track);
3714
4301
        continue;
3715
4302
      }
3748
4335
 */
3749
4336
LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
3750
4337
{
3751
 
  uint32_t i = 0;
3752
4338
  PTPParams *params = (PTPParams *) device->params;
3753
4339
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
4340
  PTPObject *ob;
 
4341
  LIBMTP_track_t *track;
 
4342
  LIBMTP_filetype_t mtptype;
 
4343
  uint16_t ret;
3754
4344
 
3755
4345
  // Get all the handles if we haven't already done that
3756
 
  if (params->handles.Handler == NULL) {
 
4346
  if (params->nrofobjects == 0)
3757
4347
    flush_handles(device);
3758
 
  }
3759
 
 
3760
 
  for (i = 0; i < params->handles.n; i++) {
3761
 
    PTPObjectInfo *oi;
3762
 
    LIBMTP_track_t *track;
3763
 
    LIBMTP_filetype_t mtptype;
3764
 
 
3765
 
    // Skip if this is not the track we want.
3766
 
    if (params->handles.Handler[i] != trackid) {
3767
 
      continue;
3768
 
    }
3769
 
 
3770
 
    oi = &params->objectinfo[i];
3771
 
    mtptype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
3772
 
 
3773
 
    // Ignore stuff we don't know how to handle...
3774
 
    if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
3775
 
        // This row lets through undefined files for examination since they may be forgotten OGG files.
3776
 
        (oi->ObjectFormat != PTP_OFC_Undefined || 
3777
 
         (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
3778
 
         !FLAG_OGG_IS_UNKNOWN(ptp_usb)))
3779
 
        ) {
3780
 
      //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
 
4348
 
 
4349
  ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
4350
  if (ret != PTP_RC_OK)
 
4351
    return NULL;
 
4352
 
 
4353
  mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
 
4354
 
 
4355
  // Ignore stuff we don't know how to handle...
 
4356
  if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
 
4357
      /*
 
4358
       * This row lets through undefined files for examination
 
4359
       * since they may be forgotten OGG or FLAC files.
 
4360
       */
 
4361
      (ob->oi.ObjectFormat != PTP_OFC_Undefined || 
 
4362
       (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
 
4363
        !FLAG_OGG_IS_UNKNOWN(ptp_usb) &&
 
4364
        !FLAG_FLAC_IS_UNKNOWN(ptp_usb)))
 
4365
      ) {
 
4366
    //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
 
4367
    return NULL;
 
4368
  }
 
4369
 
 
4370
  // Allocate a new track type
 
4371
  track = LIBMTP_new_track_t();
 
4372
  
 
4373
  // This is some sort of unique ID so we can keep track of the track.
 
4374
  track->item_id = ob->oid;
 
4375
  track->parent_id = ob->oi.ParentObject;
 
4376
  track->storage_id = ob->oi.StorageID;
 
4377
  track->modificationdate = ob->oi.ModificationDate;
 
4378
 
 
4379
  track->filetype = mtptype;
 
4380
 
 
4381
  // Original file-specific properties
 
4382
  track->filesize = ob->oi.ObjectCompressedSize;
 
4383
  if (ob->oi.Filename != NULL) {
 
4384
    track->filename = strdup(ob->oi.Filename);
 
4385
  }
 
4386
 
 
4387
  /*
 
4388
   * A special quirk for devices that doesn't quite
 
4389
   * remember that some files marked as "unknown" type are
 
4390
   * actually OGG or FLAC files. We look at the filename extension
 
4391
   * and see if it happens that this was atleast named "ogg"
 
4392
   * and fall back on this heuristic approach in that case, 
 
4393
   * for these bugged devices only.
 
4394
   */
 
4395
  if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
 
4396
      track->filename != NULL) {
 
4397
    if ((FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
 
4398
         FLAG_OGG_IS_UNKNOWN(ptp_usb)) &&
 
4399
        has_ogg_extension(track->filename))
 
4400
      track->filetype = LIBMTP_FILETYPE_OGG;
 
4401
    else if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) &&
 
4402
             has_flac_extension(track->filename))
 
4403
      track->filetype = LIBMTP_FILETYPE_FLAC;
 
4404
    else {
 
4405
      // This was not an OGG/FLAC file so discard it
 
4406
      LIBMTP_destroy_track_t(track);
3781
4407
      return NULL;
3782
4408
    }
3783
 
 
3784
 
    // Allocate a new track type
3785
 
    track = LIBMTP_new_track_t();
3786
 
    
3787
 
    // This is some sort of unique ID so we can keep track of the track.
3788
 
    track->item_id = params->handles.Handler[i];
3789
 
    track->parent_id = oi->ParentObject;
3790
 
    track->storage_id = oi->StorageID;
3791
 
 
3792
 
    track->filetype = mtptype;
3793
 
 
3794
 
    // Original file-specific properties
3795
 
    track->filesize = oi->ObjectCompressedSize;
3796
 
    if (oi->Filename != NULL) {
3797
 
      track->filename = strdup(oi->Filename);
3798
 
    }
3799
 
 
3800
 
    /*
3801
 
     * A special quirk for iriver devices that doesn't quite
3802
 
     * remember that some files marked as "unknown" type are
3803
 
     * actually OGG files. We look at the filename extension
3804
 
     * and see if it happens that this was atleast named "ogg"
3805
 
     * and fall back on this heuristic approach in that case, 
3806
 
     * for these bugged devices only.
3807
 
     */
3808
 
    if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
3809
 
        (FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
3810
 
         FLAG_OGG_IS_UNKNOWN(ptp_usb))) {
3811
 
      if (has_ogg_extension(track->filename)) {
3812
 
        // Fix it.
3813
 
        track->filetype = LIBMTP_FILETYPE_OGG;
3814
 
      } else {
3815
 
        // This was not an OGG file so discard it
3816
 
        LIBMTP_destroy_track_t(track);
3817
 
        return NULL;
3818
 
      }
3819
 
    }
3820
 
 
3821
 
    get_track_metadata(device, oi->ObjectFormat, track);
3822
 
    
3823
 
    return track;
3824
 
    
3825
 
  }
3826
 
  return NULL;
3827
 
}
3828
 
 
 
4409
  }
 
4410
  get_track_metadata(device, ob->oi.ObjectFormat, track);
 
4411
  return track;
 
4412
}
 
4413
 
 
4414
/**
 
4415
 * This is a manual conversion from MTPDataGetFunc to PTPDataGetFunc
 
4416
 * to isolate the internal type.
 
4417
 */
 
4418
static uint16_t get_func_wrapper(PTPParams* params, void* priv, unsigned long wantlen, unsigned char *data, unsigned long *gotlen)
 
4419
{
 
4420
  MTPDataHandler *handler = (MTPDataHandler *)priv;
 
4421
  uint16_t ret;
 
4422
  uint32_t local_gotlen = 0;
 
4423
  ret = handler->getfunc(params, handler->priv, wantlen, data, &local_gotlen);
 
4424
  *gotlen = local_gotlen;
 
4425
  switch (ret)
 
4426
  {
 
4427
    case LIBMTP_HANDLER_RETURN_OK:
 
4428
      return PTP_RC_OK;
 
4429
    case LIBMTP_HANDLER_RETURN_ERROR:
 
4430
      return PTP_ERROR_IO;
 
4431
    case LIBMTP_HANDLER_RETURN_CANCEL:
 
4432
      return PTP_ERROR_CANCEL;
 
4433
    default:
 
4434
      return PTP_ERROR_IO;
 
4435
  }
 
4436
}
 
4437
 
 
4438
/**
 
4439
 * This is a manual conversion from MTPDataPutFunc to PTPDataPutFunc
 
4440
 * to isolate the internal type.
 
4441
 */
 
4442
static uint16_t put_func_wrapper(PTPParams* params, void* priv, unsigned long sendlen, unsigned char *data, unsigned long *putlen)
 
4443
{
 
4444
  MTPDataHandler *handler = (MTPDataHandler *)priv;
 
4445
  uint16_t ret;
 
4446
  uint32_t local_putlen = 0;
 
4447
  ret = handler->putfunc(params, handler->priv, sendlen, data, &local_putlen);
 
4448
  *putlen = local_putlen;
 
4449
  switch (ret)
 
4450
  {
 
4451
    case LIBMTP_HANDLER_RETURN_OK:
 
4452
      return PTP_RC_OK;
 
4453
    case LIBMTP_HANDLER_RETURN_ERROR:
 
4454
      return PTP_ERROR_IO;
 
4455
    case LIBMTP_HANDLER_RETURN_CANCEL:
 
4456
      return PTP_ERROR_CANCEL;
 
4457
    default:
 
4458
      return PTP_ERROR_IO;
 
4459
  }
 
4460
}
3829
4461
 
3830
4462
/**
3831
4463
 * This gets a file off the device to a local file identified
3863
4495
  if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IRWXU)) == -1 ) {
3864
4496
#endif
3865
4497
#else
3866
 
#ifdef __USE_LARGEFILE64
3867
 
  if ( (fd = open64(path, O_RDWR|O_CREAT|O_TRUNC|O_LARGEFILE,S_IRWXU|S_IRGRP)) == -1) {
3868
 
#else
3869
4498
  if ( (fd = open(path, O_RDWR|O_CREAT|O_TRUNC,S_IRWXU|S_IRGRP)) == -1) {
3870
4499
#endif
3871
 
#endif
3872
4500
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File(): Could not create file.");
3873
4501
    return -1;
3874
4502
  }
3912
4540
                                        LIBMTP_progressfunc_t const callback,
3913
4541
                                        void const * const data)
3914
4542
{
3915
 
  PTPObjectInfo *oi;
3916
 
  uint32_t i;
3917
4543
  uint16_t ret;
3918
4544
  PTPParams *params = (PTPParams *) device->params;
3919
4545
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
4546
  PTPObject *ob;
3920
4547
 
3921
 
  oi = NULL;
3922
 
  for (i = 0; i < params->handles.n; i++) {
3923
 
    if (params->handles.Handler[i] == id) {
3924
 
      oi = &params->objectinfo[i];
3925
 
      break;
3926
 
    }
3927
 
  }
3928
 
  if (oi == NULL) {
 
4548
  ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
4549
  if (ret != PTP_RC_OK) {
3929
4550
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
3930
4551
    return -1;
3931
4552
  }
3932
 
  if (oi->ObjectFormat == PTP_OFC_Association) {
 
4553
  if (ob->oi.ObjectFormat == PTP_OFC_Association) {
3933
4554
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
3934
4555
    return -1;
3935
4556
  }
3936
4557
 
3937
4558
  // Callbacks
3938
4559
  ptp_usb->callback_active = 1;
3939
 
  ptp_usb->current_transfer_total = oi->ObjectCompressedSize+
 
4560
  ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
3940
4561
    PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
3941
4562
  ptp_usb->current_transfer_complete = 0;
3942
4563
  ptp_usb->current_transfer_callback = callback;
3961
4582
}
3962
4583
 
3963
4584
/**
 
4585
 * This gets a file off the device and calls put_func
 
4586
 * with chunks of data
 
4587
 *
 
4588
 * @param device a pointer to the device to get the file from.
 
4589
 * @param id the file ID of the file to retrieve.
 
4590
 * @param put_func the function to call when we have data.
 
4591
 * @param priv the user-defined pointer that is passed to
 
4592
 *             <code>put_func</code>.
 
4593
 * @param callback a progress indicator function or NULL to ignore.
 
4594
 * @param data a user-defined pointer that is passed along to
 
4595
 *             the <code>progress</code> function in order to
 
4596
 *             pass along some user defined data to the progress
 
4597
 *             updates. If not used, set this to NULL.
 
4598
 * @return 0 if the transfer was successful, any other value means
 
4599
 *           failure.
 
4600
 */
 
4601
int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
 
4602
                                        uint32_t const id,
 
4603
                                        MTPDataPutFunc put_func,
 
4604
          void * priv,
 
4605
                                        LIBMTP_progressfunc_t const callback,
 
4606
                                        void const * const data)
 
4607
{
 
4608
  PTPObject *ob;
 
4609
  uint16_t ret;
 
4610
  PTPParams *params = (PTPParams *) device->params;
 
4611
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
4612
 
 
4613
  ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
4614
  if (ret != PTP_RC_OK) {
 
4615
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
 
4616
    return -1;
 
4617
  }
 
4618
  if (ob->oi.ObjectFormat == PTP_OFC_Association) {
 
4619
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
 
4620
    return -1;
 
4621
  }
 
4622
 
 
4623
  // Callbacks
 
4624
  ptp_usb->callback_active = 1;
 
4625
  ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
 
4626
    PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
 
4627
  ptp_usb->current_transfer_complete = 0;
 
4628
  ptp_usb->current_transfer_callback = callback;
 
4629
  ptp_usb->current_transfer_callback_data = data;
 
4630
 
 
4631
  MTPDataHandler mtp_handler;
 
4632
  mtp_handler.getfunc = NULL;
 
4633
  mtp_handler.putfunc = put_func;
 
4634
  mtp_handler.priv = priv;
 
4635
 
 
4636
  PTPDataHandler handler;
 
4637
  handler.getfunc = NULL;
 
4638
  handler.putfunc = put_func_wrapper;
 
4639
  handler.priv = &mtp_handler;
 
4640
 
 
4641
  ret = ptp_getobject_to_handler(params, id, &handler);
 
4642
 
 
4643
  ptp_usb->callback_active = 0;
 
4644
  ptp_usb->current_transfer_callback = NULL;
 
4645
  ptp_usb->current_transfer_callback_data = NULL;
 
4646
 
 
4647
  if (ret == PTP_ERROR_CANCEL) {
 
4648
    add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Get_File_From_File_Descriptor(): Cancelled transfer.");
 
4649
    return -1;
 
4650
  }
 
4651
  if (ret != PTP_RC_OK) {
 
4652
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_File_To_File_Descriptor(): Could not get file from device.");
 
4653
    return -1;
 
4654
  }
 
4655
 
 
4656
  return 0;
 
4657
}
 
4658
 
 
4659
 
 
4660
/**
3964
4661
 * This gets a track off the device to a file identified
3965
4662
 * by a filename. This is actually just a wrapper for the
3966
4663
 * \c LIBMTP_Get_Track_To_File() function.
4011
4708
}
4012
4709
 
4013
4710
/**
 
4711
 * This gets a track off the device to a handler function.
 
4712
 * This is actually just a wrapper for
 
4713
 * the \c LIBMTP_Get_File_To_Handler() function.
 
4714
 * @param device a pointer to the device to get the track from.
 
4715
 * @param id the track ID of the track to retrieve.
 
4716
 * @param put_func the function to call when we have data.
 
4717
 * @param priv the user-defined pointer that is passed to
 
4718
 *             <code>put_func</code>.
 
4719
 * @param callback a progress indicator function or NULL to ignore.
 
4720
 * @param data a user-defined pointer that is passed along to
 
4721
 *             the <code>progress</code> function in order to
 
4722
 *             pass along some user defined data to the progress
 
4723
 *             updates. If not used, set this to NULL.
 
4724
 * @return 0 if the transfer was successful, any other value means
 
4725
 *           failure.
 
4726
 */
 
4727
int LIBMTP_Get_Track_To_Handler(LIBMTP_mtpdevice_t *device,
 
4728
                                        uint32_t const id,
 
4729
                                        MTPDataPutFunc put_func,
 
4730
          void * priv,
 
4731
                                        LIBMTP_progressfunc_t const callback,
 
4732
                                        void const * const data)
 
4733
{
 
4734
  // This is just a wrapper
 
4735
  return LIBMTP_Get_File_To_Handler(device, id, put_func, priv, callback, data);
 
4736
}
 
4737
 
 
4738
/**
4014
4739
 * This function sends a track from a local file to an
4015
4740
 * MTP device. A filename and a set of metadata must be
4016
4741
 * given as input.
4069
4794
  if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
4070
4795
#endif
4071
4796
#else
4072
 
#ifdef __USE_LARGEFILE64
4073
 
  if ( (fd = open64(path, O_RDONLY|O_LARGEFILE)) == -1) {
4074
 
#else
4075
4797
  if ( (fd = open(path, O_RDONLY)) == -1) {
4076
4798
#endif
4077
 
#endif
4078
4799
    printf("LIBMTP_Send_Track_From_File(): Could not open source file \"%s\"\n", path);
4079
4800
    return -1;
4080
4801
  }
4091
4812
  return ret;
4092
4813
}
4093
4814
 
4094
 
 
4095
 
 
4096
4815
/**
4097
4816
 * This function sends a track from a file descriptor to an
4098
4817
 * MTP device. A filename and a set of metadata must be
4189
4908
}
4190
4909
 
4191
4910
/**
 
4911
 * This function sends a track from a handler function to an
 
4912
 * MTP device. A filename and a set of metadata must be
 
4913
 * given as input.
 
4914
 * @param device a pointer to the device to send the track to.
 
4915
 * @param get_func the function to call when we have data.
 
4916
 * @param priv the user-defined pointer that is passed to
 
4917
 *             <code>get_func</code>.
 
4918
 * @param metadata a track metadata set to be written along with the file.
 
4919
 *        After this call the field <code>metadata-&gt;item_id</code>
 
4920
 *        will contain the new track ID. Other fields such
 
4921
 *        as the <code>metadata-&gt;filename</code>, <code>metadata-&gt;parent_id</code>
 
4922
 *        or <code>metadata-&gt;storage_id</code> may also change during this 
 
4923
 *        operation due to device restrictions, so do not rely on the
 
4924
 *        contents of this struct to be preserved in any way.
 
4925
 *        <ul>
 
4926
 *        <li><code>metadata-&gt;parent_id</code> should be set to the parent 
 
4927
 *        (e.g. folder) to store this track in. Since some 
 
4928
 *        devices are a bit picky about where files
 
4929
 *        are placed, a default folder will be chosen if libmtp
 
4930
 *        has detected one for the current filetype and this
 
4931
 *        parameter is set to 0. If this is 0 and no default folder
 
4932
 *        can be found, the file will be stored in the root folder.
 
4933
 *        <li><code>metadata-&gt;storage_id</code> should be set to the
 
4934
 *        desired storage (e.g. memory card or whatever your device
 
4935
 *        presents) to store this track in. Setting this to 0 will store
 
4936
 *        the track on the primary storage.
 
4937
 *        </ul>
 
4938
 * @param callback a progress indicator function or NULL to ignore.
 
4939
 * @param data a user-defined pointer that is passed along to
 
4940
 *             the <code>progress</code> function in order to
 
4941
 *             pass along some user defined data to the progress
 
4942
 *             updates. If not used, set this to NULL.
 
4943
 * @return 0 if the transfer was successful, any other value means
 
4944
 *           failure.
 
4945
 * @see LIBMTP_Send_Track_From_File()
 
4946
 * @see LIBMTP_Delete_Object()
 
4947
 */
 
4948
int LIBMTP_Send_Track_From_Handler(LIBMTP_mtpdevice_t *device,
 
4949
                         MTPDataGetFunc get_func, void * priv, LIBMTP_track_t * const metadata,
 
4950
                         LIBMTP_progressfunc_t const callback,
 
4951
                         void const * const data)
 
4952
{
 
4953
  int subcall_ret;
 
4954
  LIBMTP_file_t filedata;
 
4955
 
 
4956
  // Sanity check, is this really a track?
 
4957
  if (!LIBMTP_FILETYPE_IS_TRACK(metadata->filetype)) {
 
4958
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, 
 
4959
                            "LIBMTP_Send_Track_From_Handler(): "
 
4960
                            "I don't think this is actually a track, strange filetype...");
 
4961
  }
 
4962
 
 
4963
  // Wrap around the file transfer function
 
4964
  filedata.item_id = metadata->item_id;
 
4965
  filedata.parent_id = metadata->parent_id;
 
4966
  filedata.storage_id = metadata->storage_id;
 
4967
  filedata.filename = metadata->filename;
 
4968
  filedata.filesize = metadata->filesize;
 
4969
  filedata.filetype = metadata->filetype;
 
4970
  filedata.next = NULL;
 
4971
 
 
4972
  subcall_ret = LIBMTP_Send_File_From_Handler(device,
 
4973
                                                      get_func,
 
4974
                  priv, 
 
4975
                                                      &filedata,
 
4976
                                                      callback,
 
4977
                                                      data);
 
4978
 
 
4979
  if (subcall_ret != 0) {
 
4980
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, 
 
4981
                            "LIBMTP_Send_Track_From_Handler(): "
 
4982
                            "subcall to LIBMTP_Send_File_From_Handler failed.");
 
4983
    // We used to delete the file here, but don't... It might be OK after all.
 
4984
    // (void) LIBMTP_Delete_Object(device, metadata->item_id);
 
4985
    return -1;
 
4986
  }
 
4987
 
 
4988
  // Pick up new item (and parent, storage) ID
 
4989
  metadata->item_id = filedata.item_id;
 
4990
  metadata->parent_id = filedata.parent_id;
 
4991
  metadata->storage_id = filedata.storage_id;
 
4992
 
 
4993
  // Set track metadata for the new fine track
 
4994
  subcall_ret = LIBMTP_Update_Track_Metadata(device, metadata);
 
4995
  if (subcall_ret != 0) {
 
4996
    // Subcall will add error to errorstack
 
4997
    // We used to delete the file here, but don't... It might be OK after all.
 
4998
    // (void) LIBMTP_Delete_Object(device, metadata->item_id);
 
4999
    return -1;
 
5000
  }
 
5001
 
 
5002
  // note we don't need to update the cache here because LIBMTP_Send_File_From_File_Descriptor
 
5003
  // has added the object handle and LIBMTP_Update_Track_Metadata has added the metadata.
 
5004
 
 
5005
  return 0;
 
5006
}
 
5007
 
 
5008
/**
4192
5009
 * This function sends a local file to an MTP device.
4193
5010
 * A filename and a set of metadata must be
4194
5011
 * given as input.
4198
5015
 *        After this call the field <code>filedata-&gt;item_id</code>
4199
5016
 *        will contain the new file ID. Other fields such
4200
5017
 *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
4201
 
 *        or <code>filedata-&gt;storage_id</code> may also change during this 
 
5018
 *        or <code>filedata-&gt;storage_id</code> may also change during this
4202
5019
 *        operation due to device restrictions, so do not rely on the
4203
5020
 *        contents of this struct to be preserved in any way.
4204
5021
 *        <ul>
4205
 
 *        <li><code>filedata-&gt;parent_id</code> should be set to the parent 
4206
 
 *        (e.g. folder) to store this file in. If this is 0, 
 
5022
 *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
 
5023
 *        (e.g. folder) to store this file in. If this is 0,
4207
5024
 *        the file will be stored in the root folder.
4208
5025
 *        <li><code>filedata-&gt;storage_id</code> should be set to the
4209
5026
 *        desired storage (e.g. memory card or whatever your device
4242
5059
  if ( (fd = open(path, O_RDONLY|O_BINARY) == -1) ) {
4243
5060
#endif
4244
5061
#else
4245
 
#ifdef __USE_LARGEFILE64
4246
 
  if ( (fd = open64(path, O_RDONLY|O_LARGEFILE)) == -1) {
4247
 
#else
4248
5062
  if ( (fd = open(path, O_RDONLY)) == -1) {
4249
5063
#endif
4250
 
#endif
4251
5064
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File(): Could not open source file.");
4252
5065
    return -1;
4253
5066
  }
4270
5083
 * given as input.
4271
5084
 *
4272
5085
 * This can potentially be used for sending in a stream of unknown
4273
 
 * length. Send music files with 
 
5086
 * length. Send music files with
4274
5087
 * <code>LIBMTP_Send_Track_From_File_Descriptor()</code>
4275
5088
 *
4276
5089
 * @param device a pointer to the device to send the file to.
4279
5092
 *        After this call the field <code>filedata-&gt;item_id</code>
4280
5093
 *        will contain the new file ID. Other fields such
4281
5094
 *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
4282
 
 *        or <code>filedata-&gt;storage_id</code> may also change during this 
 
5095
 *        or <code>filedata-&gt;storage_id</code> may also change during this
4283
5096
 *        operation due to device restrictions, so do not rely on the
4284
5097
 *        contents of this struct to be preserved in any way.
4285
5098
 *        <ul>
4286
 
 *        <li><code>filedata-&gt;parent_id</code> should be set to the parent 
4287
 
 *        (e.g. folder) to store this file in. If this is 0, 
 
5099
 *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
 
5100
 *        (e.g. folder) to store this file in. If this is 0,
4288
5101
 *        the file will be stored in the root folder.
4289
5102
 *        <li><code>filedata-&gt;storage_id</code> should be set to the
4290
5103
 *        desired storage (e.g. memory card or whatever your device
4308
5121
                         void const * const data)
4309
5122
{
4310
5123
  uint16_t ret;
 
5124
  PTPParams *params = (PTPParams *) device->params;
 
5125
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
5126
  LIBMTP_file_t *newfilemeta;
 
5127
 
 
5128
  if (send_file_object_info(device, filedata))
 
5129
  {
 
5130
    // no need to output an error since send_file_object_info will already have done so
 
5131
    return -1;
 
5132
  }
 
5133
 
 
5134
  // Callbacks
 
5135
  ptp_usb->callback_active = 1;
 
5136
  // The callback will deactivate itself after this amount of data has been sent
 
5137
  // One BULK header for the request, one for the data phase. No parameters to the request.
 
5138
  ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
 
5139
  ptp_usb->current_transfer_complete = 0;
 
5140
  ptp_usb->current_transfer_callback = callback;
 
5141
  ptp_usb->current_transfer_callback_data = data;
 
5142
 
 
5143
  ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
 
5144
 
 
5145
  ptp_usb->callback_active = 0;
 
5146
  ptp_usb->current_transfer_callback = NULL;
 
5147
  ptp_usb->current_transfer_callback_data = NULL;
 
5148
 
 
5149
  if (ret == PTP_ERROR_CANCEL) {
 
5150
    add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
 
5151
    return -1;
 
5152
  }
 
5153
  if (ret != PTP_RC_OK) {
 
5154
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
 
5155
                                "Could not send object.");
 
5156
    return -1;
 
5157
  }
 
5158
 
 
5159
  add_object_to_cache(device, filedata->item_id);
 
5160
 
 
5161
  /*
 
5162
   * Get the device-assined parent_id from the cache.
 
5163
   * The operation that adds it to the cache will
 
5164
   * look it up from the device, so we get the new
 
5165
   * parent_id from the cache.
 
5166
   */
 
5167
  newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
 
5168
  if (newfilemeta != NULL) {
 
5169
    filedata->parent_id = newfilemeta->parent_id;
 
5170
    filedata->storage_id = newfilemeta->storage_id;
 
5171
    LIBMTP_destroy_file_t(newfilemeta);
 
5172
  } else {
 
5173
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
 
5174
                            "LIBMTP_Send_File_From_File_Descriptor(): "
 
5175
                            "Could not retrieve updated metadata.");
 
5176
    return -1;
 
5177
  }
 
5178
 
 
5179
  return 0;
 
5180
}
 
5181
 
 
5182
/**
 
5183
 * This function sends a generic file from a handler function to an
 
5184
 * MTP device. A filename and a set of metadata must be
 
5185
 * given as input.
 
5186
 *
 
5187
 * This can potentially be used for sending in a stream of unknown
 
5188
 * length. Send music files with
 
5189
 * <code>LIBMTP_Send_Track_From_Handler()</code>
 
5190
 *
 
5191
 * @param device a pointer to the device to send the file to.
 
5192
 * @param get_func the function to call to get data to write
 
5193
 * @param priv a user-defined pointer that is passed along to
 
5194
 *        <code>get_func</code>. If not used, this is set to NULL.
 
5195
 * @param filedata a file metadata set to be written along with the file.
 
5196
 *        After this call the field <code>filedata-&gt;item_id</code>
 
5197
 *        will contain the new file ID. Other fields such
 
5198
 *        as the <code>filedata-&gt;filename</code>, <code>filedata-&gt;parent_id</code>
 
5199
 *        or <code>filedata-&gt;storage_id</code> may also change during this
 
5200
 *        operation due to device restrictions, so do not rely on the
 
5201
 *        contents of this struct to be preserved in any way.
 
5202
 *        <ul>
 
5203
 *        <li><code>filedata-&gt;parent_id</code> should be set to the parent
 
5204
 *        (e.g. folder) to store this file in. If this is 0,
 
5205
 *        the file will be stored in the root folder.
 
5206
 *        <li><code>filedata-&gt;storage_id</code> should be set to the
 
5207
 *        desired storage (e.g. memory card or whatever your device
 
5208
 *        presents) to store this file in. Setting this to 0 will store
 
5209
 *        the file on the primary storage.
 
5210
 *        </ul>
 
5211
 * @param callback a progress indicator function or NULL to ignore.
 
5212
 * @param data a user-defined pointer that is passed along to
 
5213
 *             the <code>progress</code> function in order to
 
5214
 *             pass along some user defined data to the progress
 
5215
 *             updates. If not used, set this to NULL.
 
5216
 * @return 0 if the transfer was successful, any other value means
 
5217
 *           failure.
 
5218
 * @see LIBMTP_Send_File_From_File()
 
5219
 * @see LIBMTP_Send_Track_From_File_Descriptor()
 
5220
 * @see LIBMTP_Delete_Object()
 
5221
 */
 
5222
int LIBMTP_Send_File_From_Handler(LIBMTP_mtpdevice_t *device,
 
5223
                         MTPDataGetFunc get_func, void * priv, LIBMTP_file_t * const filedata,
 
5224
       LIBMTP_progressfunc_t const callback, void const * const data)
 
5225
{
 
5226
  uint16_t ret;
 
5227
  PTPParams *params = (PTPParams *) device->params;
 
5228
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
5229
  LIBMTP_file_t *newfilemeta;
 
5230
 
 
5231
  if (send_file_object_info(device, filedata))
 
5232
  {
 
5233
    // no need to output an error since send_file_object_info will already have done so
 
5234
    return -1;
 
5235
  }
 
5236
 
 
5237
  // Callbacks
 
5238
  ptp_usb->callback_active = 1;
 
5239
  // The callback will deactivate itself after this amount of data has been sent
 
5240
  // One BULK header for the request, one for the data phase. No parameters to the request.
 
5241
  ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
 
5242
  ptp_usb->current_transfer_complete = 0;
 
5243
  ptp_usb->current_transfer_callback = callback;
 
5244
  ptp_usb->current_transfer_callback_data = data;
 
5245
 
 
5246
  MTPDataHandler mtp_handler;
 
5247
  mtp_handler.getfunc = get_func;
 
5248
  mtp_handler.putfunc = NULL;
 
5249
  mtp_handler.priv = priv;
 
5250
 
 
5251
  PTPDataHandler handler;
 
5252
  handler.getfunc = get_func_wrapper;
 
5253
  handler.putfunc = NULL;
 
5254
  handler.priv = &mtp_handler;
 
5255
 
 
5256
  ret = ptp_sendobject_from_handler(params, &handler, filedata->filesize);
 
5257
 
 
5258
  ptp_usb->callback_active = 0;
 
5259
  ptp_usb->current_transfer_callback = NULL;
 
5260
  ptp_usb->current_transfer_callback_data = NULL;
 
5261
 
 
5262
  if (ret == PTP_ERROR_CANCEL) {
 
5263
    add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_Handler(): Cancelled transfer.");
 
5264
    return -1;
 
5265
  }
 
5266
  if (ret != PTP_RC_OK) {
 
5267
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_Handler(): "
 
5268
                                "Could not send object.");
 
5269
    return -1;
 
5270
  }
 
5271
 
 
5272
  add_object_to_cache(device, filedata->item_id);
 
5273
 
 
5274
  /*
 
5275
   * Get the device-assined parent_id from the cache.
 
5276
   * The operation that adds it to the cache will
 
5277
   * look it up from the device, so we get the new
 
5278
   * parent_id from the cache.
 
5279
   */
 
5280
  newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
 
5281
  if (newfilemeta != NULL) {
 
5282
    filedata->parent_id = newfilemeta->parent_id;
 
5283
    filedata->storage_id = newfilemeta->storage_id;
 
5284
    LIBMTP_destroy_file_t(newfilemeta);
 
5285
  } else {
 
5286
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
 
5287
                            "LIBMTP_Send_File_From_Handler(): "
 
5288
                            "Could not retrieve updated metadata.");
 
5289
    return -1;
 
5290
  }
 
5291
 
 
5292
  return 0;
 
5293
}
 
5294
 
 
5295
/**
 
5296
 * This function sends the file object info, ready for sendobject
 
5297
 * @param device a pointer to the device to send the file to.
 
5298
 * @param filedata a file metadata set to be written along with the file.
 
5299
 * @return 0 if the transfer was successful, any other value means
 
5300
 *           failure.
 
5301
 */
 
5302
static int send_file_object_info(LIBMTP_mtpdevice_t *device, LIBMTP_file_t *filedata)
 
5303
{
 
5304
  PTPParams *params = (PTPParams *) device->params;
 
5305
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
4311
5306
  uint32_t store;
 
5307
  int use_primary_storage = 1;
 
5308
  uint16_t of = map_libmtp_type_to_ptp_type(filedata->filetype);
 
5309
  LIBMTP_devicestorage_t *storage;
4312
5310
  uint32_t localph = filedata->parent_id;
4313
 
  LIBMTP_devicestorage_t *storage;
4314
 
  PTPParams *params = (PTPParams *) device->params;
4315
 
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
 
5311
  uint16_t ret;
4316
5312
  int i;
4317
 
  uint16_t of =  map_libmtp_type_to_ptp_type(filedata->filetype);
4318
 
  LIBMTP_file_t *newfilemeta;
4319
 
  int use_primary_storage = 1;
4320
5313
 
4321
5314
  // Sanity check: no zerolength files.
4322
5315
  if (filedata->filesize == 0) {
4323
 
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_File_From_File_Descriptor(): "
 
5316
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "send_file_object_info(): "
4324
5317
                            "File of zero size.");
4325
5318
    return -1;
4326
5319
  }
4377
5370
  }
4378
5371
 
4379
5372
  // Here we wire the type to unknown on bugged, but
4380
 
  // Ogg-supportive devices.
 
5373
  // Ogg or FLAC-supportive devices.
4381
5374
  if (FLAG_OGG_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_OGG) {
4382
5375
    of = PTP_OFC_Undefined;
4383
5376
  }
 
5377
  if (FLAG_FLAC_IS_UNKNOWN(ptp_usb) && of == PTP_OFC_MTP_FLAC) {
 
5378
    of = PTP_OFC_Undefined;
 
5379
  }
4384
5380
 
4385
5381
  if (ptp_operation_issupported(params, PTP_OC_MTP_SendObjectPropList) &&
4386
5382
      !FLAG_BROKEN_SEND_OBJECT_PROPLIST(ptp_usb)) {
4448
5444
    MTPProperties *prop = NULL;
4449
5445
    uint16_t *properties = NULL;
4450
5446
    uint32_t propcnt = 0;
4451
 
    
 
5447
 
4452
5448
    // default parent handle
4453
5449
    if (localph == 0)
4454
5450
      localph = 0xFFFFFFFFU; // Set to -1
4460
5456
 
4461
5457
    for (i=0;i<propcnt;i++) {
4462
5458
      PTPObjectPropDesc opd;
4463
 
      
 
5459
 
4464
5460
      ret = ptp_mtp_getobjectpropdesc(params, properties[i], of, &opd);
4465
5461
      if (ret != PTP_RC_OK) {
4466
 
        add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
 
5462
        add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
4467
5463
                                "could not get property description.");
4468
5464
      } else if (opd.GetSet) {
4469
5465
        switch (properties[i]) {
4509
5505
            prop->property = PTP_OPC_DateModified;
4510
5506
            prop->datatype = PTP_DTC_STR;
4511
5507
            prop->propval.str = get_iso8601_stamp();
 
5508
            filedata->modificationdate = time(NULL);
4512
5509
          }
4513
5510
          break;
4514
5511
        }
4524
5521
    ptp_destroy_object_prop_list(props, nrofprops);
4525
5522
 
4526
5523
    if (ret != PTP_RC_OK) {
4527
 
      add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor():" 
 
5524
      add_ptp_error_to_errorstack(device, ret, "send_file_object_info():"
4528
5525
                                  "Could not send object property list.");
4529
5526
      if (ret == PTP_RC_AccessDenied) {
4530
5527
        add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
4535
5532
    PTPObjectInfo new_file;
4536
5533
 
4537
5534
    memset(&new_file, 0, sizeof(PTPObjectInfo));
4538
 
  
 
5535
 
4539
5536
    new_file.Filename = filedata->filename;
4540
5537
    if (FLAG_ONLY_7BIT_FILENAMES(ptp_usb)) {
4541
5538
      strip_7bit_from_utf8(new_file.Filename);
4542
5539
    }
4543
 
    // We loose precision here.
 
5540
    // We lose precision here.
4544
5541
    new_file.ObjectCompressedSize = (uint32_t) filedata->filesize;
4545
5542
    new_file.ObjectFormat = of;
4546
5543
    new_file.StorageID = store;
4547
5544
    new_file.ParentObject = localph;
 
5545
    new_file.ModificationDate = time(NULL);
4548
5546
 
4549
5547
    // Create the object
4550
5548
    ret = ptp_sendobjectinfo(params, &store, &localph, &filedata->item_id, &new_file);
4551
5549
 
4552
5550
    if (ret != PTP_RC_OK) {
4553
 
      add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
 
5551
      add_ptp_error_to_errorstack(device, ret, "send_file_object_info(): "
4554
5552
                                  "Could not send object info.");
4555
5553
      if (ret == PTP_RC_AccessDenied) {
4556
5554
        add_ptp_error_to_errorstack(device, ret, "ACCESS DENIED.");
4564
5562
  // Now there IS an object with this parent handle.
4565
5563
  filedata->parent_id = localph;
4566
5564
 
4567
 
  // Callbacks
4568
 
  ptp_usb->callback_active = 1;
4569
 
  // The callback will deactivate itself after this amount of data has been sent
4570
 
  // One BULK header for the request, one for the data phase. No parameters to the request.
4571
 
  ptp_usb->current_transfer_total = filedata->filesize+PTP_USB_BULK_HDR_LEN*2;
4572
 
  ptp_usb->current_transfer_complete = 0;
4573
 
  ptp_usb->current_transfer_callback = callback;
4574
 
  ptp_usb->current_transfer_callback_data = data;
4575
 
  
4576
 
  ret = ptp_sendobject_fromfd(params, fd, filedata->filesize);
4577
 
  
4578
 
  ptp_usb->callback_active = 0;
4579
 
  ptp_usb->current_transfer_callback = NULL;
4580
 
  ptp_usb->current_transfer_callback_data = NULL;
4581
 
 
4582
 
  if (ret == PTP_ERROR_CANCEL) {
4583
 
    add_error_to_errorstack(device, LIBMTP_ERROR_CANCELLED, "LIBMTP_Send_File_From_File_Descriptor(): Cancelled transfer.");
4584
 
    return -1;
4585
 
  }
4586
 
  if (ret != PTP_RC_OK) {
4587
 
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_File_From_File_Descriptor(): "
4588
 
                                "Could not send object.");
4589
 
    return -1;
4590
 
  }
4591
 
 
4592
 
  add_object_to_cache(device, filedata->item_id);
4593
 
  
4594
 
  /*
4595
 
   * Get the device-assined parent_id from the cache.
4596
 
   * The operation that adds it to the cache will
4597
 
   * look it up from the device, so we get the new
4598
 
   * parent_id from the cache.
4599
 
   */
4600
 
  newfilemeta = LIBMTP_Get_Filemetadata(device, filedata->item_id);
4601
 
  if (newfilemeta != NULL) {
4602
 
    filedata->parent_id = newfilemeta->parent_id;
4603
 
    filedata->storage_id = newfilemeta->storage_id;
4604
 
    LIBMTP_destroy_file_t(newfilemeta);
4605
 
  } else {
4606
 
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
4607
 
                            "LIBMTP_Send_File_From_File_Descriptor(): "
4608
 
                            "Could not retrieve updated metadata.");
4609
 
    return -1;
4610
 
  }
4611
 
 
4612
5565
  return 0;
4613
5566
}
4614
5567
 
4653
5606
    MTPProperties *props = NULL;
4654
5607
    MTPProperties *prop = NULL;
4655
5608
    int nrofprops = 0;
4656
 
    
 
5609
 
4657
5610
    for (i=0;i<propcnt;i++) {
4658
5611
      PTPObjectPropDesc opd;
4659
 
      
 
5612
 
4660
5613
      ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
4661
5614
      if (ret != PTP_RC_OK) {
4662
5615
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
4667
5620
          if (metadata->title == NULL)
4668
5621
            break;
4669
5622
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4670
 
          prop->ObjectHandle = metadata->item_id;      
 
5623
          prop->ObjectHandle = metadata->item_id;
4671
5624
          prop->property = PTP_OPC_Name;
4672
5625
          prop->datatype = PTP_DTC_STR;
4673
5626
          prop->propval.str = strdup(metadata->title);
4685
5638
          if (metadata->artist == NULL)
4686
5639
            break;
4687
5640
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4688
 
          prop->ObjectHandle = metadata->item_id;      
 
5641
          prop->ObjectHandle = metadata->item_id;
4689
5642
          prop->property = PTP_OPC_Artist;
4690
5643
          prop->datatype = PTP_DTC_STR;
4691
5644
          prop->propval.str = strdup(metadata->artist);
4703
5656
          if (metadata->genre == NULL)
4704
5657
            break;
4705
5658
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4706
 
          prop->ObjectHandle = metadata->item_id;      
 
5659
          prop->ObjectHandle = metadata->item_id;
4707
5660
          prop->property = PTP_OPC_Genre;
4708
5661
          prop->datatype = PTP_DTC_STR;
4709
5662
          prop->propval.str = strdup(metadata->genre);
4726
5679
          if (metadata->date == NULL)
4727
5680
            break;
4728
5681
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4729
 
          prop->ObjectHandle = metadata->item_id;      
 
5682
          prop->ObjectHandle = metadata->item_id;
4730
5683
          prop->property = PTP_OPC_OriginalReleaseDate;
4731
5684
          prop->datatype = PTP_DTC_STR;
4732
5685
          prop->propval.str = strdup(metadata->date);
4733
5686
          break;
4734
5687
        case PTP_OPC_SampleRate:
4735
5688
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4736
 
          prop->ObjectHandle = metadata->item_id;      
 
5689
          prop->ObjectHandle = metadata->item_id;
4737
5690
          prop->property = PTP_OPC_SampleRate;
4738
5691
          prop->datatype = PTP_DTC_UINT32;
4739
5692
          prop->propval.u32 = adjust_u32(metadata->samplerate, &opd);
4740
5693
          break;
4741
5694
        case PTP_OPC_NumberOfChannels:
4742
5695
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4743
 
          prop->ObjectHandle = metadata->item_id;      
 
5696
          prop->ObjectHandle = metadata->item_id;
4744
5697
          prop->property = PTP_OPC_NumberOfChannels;
4745
5698
          prop->datatype = PTP_DTC_UINT16;
4746
5699
          prop->propval.u16 = adjust_u16(metadata->nochannels, &opd);
4747
5700
          break;
4748
5701
        case PTP_OPC_AudioWAVECodec:
4749
5702
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4750
 
          prop->ObjectHandle = metadata->item_id;      
 
5703
          prop->ObjectHandle = metadata->item_id;
4751
5704
          prop->property = PTP_OPC_AudioWAVECodec;
4752
5705
          prop->datatype = PTP_DTC_UINT32;
4753
5706
          prop->propval.u32 = adjust_u32(metadata->wavecodec, &opd);
4754
5707
          break;
4755
5708
        case PTP_OPC_AudioBitRate:
4756
5709
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4757
 
          prop->ObjectHandle = metadata->item_id;      
 
5710
          prop->ObjectHandle = metadata->item_id;
4758
5711
          prop->property = PTP_OPC_AudioBitRate;
4759
5712
          prop->datatype = PTP_DTC_UINT32;
4760
5713
          prop->propval.u32 = adjust_u32(metadata->bitrate, &opd);
4761
5714
          break;
4762
5715
        case PTP_OPC_BitRateType:
4763
5716
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4764
 
          prop->ObjectHandle = metadata->item_id;      
 
5717
          prop->ObjectHandle = metadata->item_id;
4765
5718
          prop->property = PTP_OPC_BitRateType;
4766
5719
          prop->datatype = PTP_DTC_UINT16;
4767
5720
          prop->propval.u16 = adjust_u16(metadata->bitratetype, &opd);
4771
5724
          if (metadata->rating == 0)
4772
5725
            break;
4773
5726
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4774
 
          prop->ObjectHandle = metadata->item_id;      
 
5727
          prop->ObjectHandle = metadata->item_id;
4775
5728
          prop->property = PTP_OPC_Rating;
4776
5729
          prop->datatype = PTP_DTC_UINT16;
4777
5730
          prop->propval.u16 = adjust_u16(metadata->rating, &opd);
4778
5731
          break;
4779
5732
        case PTP_OPC_UseCount:
4780
5733
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
4781
 
          prop->ObjectHandle = metadata->item_id;      
 
5734
          prop->ObjectHandle = metadata->item_id;
4782
5735
          prop->property = PTP_OPC_UseCount;
4783
5736
          prop->datatype = PTP_DTC_UINT32;
4784
5737
          prop->propval.u32 = adjust_u32(metadata->usecount, &opd);
4802
5755
 
4803
5756
    // NOTE: File size is not updated, this should not change anyway.
4804
5757
    // neither will we change the filename.
4805
 
    
 
5758
 
4806
5759
    ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
4807
 
    
 
5760
 
4808
5761
    ptp_destroy_object_prop_list(props, nrofprops);
4809
 
    
 
5762
 
4810
5763
    if (ret != PTP_RC_OK) {
4811
5764
      // TODO: return error of which property we couldn't set
4812
5765
      add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
4814
5767
      free(properties);
4815
5768
      return -1;
4816
5769
    }
4817
 
    
 
5770
 
4818
5771
  } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
4819
5772
    for (i=0;i<propcnt;i++) {
4820
5773
      PTPObjectPropDesc opd;
4821
 
      
 
5774
 
4822
5775
      ret = ptp_mtp_getobjectpropdesc(params, properties[i], map_libmtp_type_to_ptp_type(metadata->filetype), &opd);
4823
5776
      if (ret != PTP_RC_OK) {
4824
5777
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Update_Track_Metadata(): "
4974
5927
            }
4975
5928
            free(tmpstamp);
4976
5929
          }
4977
 
          break;          
4978
 
          
 
5930
          break;
 
5931
 
4979
5932
          // NOTE: File size is not updated, this should not change anyway.
4980
5933
          // neither will we change the filename.
4981
5934
        default:
4990
5943
    free(properties);
4991
5944
    return -1;
4992
5945
  }
4993
 
  
 
5946
 
4994
5947
  // update cached object properties if metadata cache exists
4995
5948
  update_metadata_cache(device, metadata->item_id);
4996
5949
 
4997
5950
  free(properties);
4998
 
  
 
5951
 
4999
5952
  return 0;
5000
5953
}
5001
5954
 
5007
5960
 * really delete all the files that were in that folder, rather it is
5008
5961
 * expected that they will not be deleted, and will turn up in object
5009
5962
 * listings with parent set to a non-existant object ID. The safe way
5010
 
 * to do this is to recursively delete all files (and folders) contained 
 
5963
 * to do this is to recursively delete all files (and folders) contained
5011
5964
 * in the folder, then the folder itself.
5012
5965
 *
5013
5966
 * @param device a pointer to the device to delete the object from.
5072
6025
    int nrofprops = 0;
5073
6026
 
5074
6027
    prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
5075
 
    prop->ObjectHandle = object_id;  
 
6028
    prop->ObjectHandle = object_id;
5076
6029
    prop->property = PTP_OPC_ObjectFileName;
5077
6030
    prop->datatype = PTP_DTC_STR;
5078
6031
    prop->propval.str = newname;
5298
6251
                            "could not get file metadata for target object.");
5299
6252
    return -1;
5300
6253
  }
5301
 
  
 
6254
 
5302
6255
  ret = set_object_filename(device, object_id, map_libmtp_type_to_ptp_type(file->filetype), (const char **) &newname);
5303
 
  
 
6256
 
5304
6257
  free(file);
5305
6258
 
5306
6259
  return ret;
5316
6269
           uint32_t const id)
5317
6270
{
5318
6271
  PTPParams *params = (PTPParams *) device->params;
5319
 
  uint32_t i;
 
6272
  uint16_t ret;
 
6273
  PTPObject *ob;
5320
6274
 
5321
 
  for (i = 0; i < params->handles.n; i++) {
5322
 
    if (params->handles.Handler[i] == id) {
 
6275
  ret = ptp_object_want (params, id, 0, &ob);
 
6276
  if (ret == PTP_RC_OK)
5323
6277
      return -1;
5324
 
    }
5325
 
  }
5326
6278
  return 0;
5327
6279
}
5328
6280
 
5438
6390
    // Remove curr from the list.
5439
6391
    curr->child->sibling = curr->sibling;
5440
6392
    curr->sibling->child = curr->child;
5441
 
    
 
6393
 
5442
6394
    // Attach the children to curr.
5443
6395
    curr->child = children;
5444
 
      
 
6396
 
5445
6397
    // Put this folder into the list of siblings.
5446
6398
    curr->sibling = retfolders;
5447
6399
    retfolders = curr;
5464
6416
  int i;
5465
6417
 
5466
6418
  // Get all the handles if we haven't already done that
5467
 
  if (params->handles.Handler == NULL) {
 
6419
  if (params->nrofobjects == 0) {
5468
6420
    flush_handles(device);
5469
6421
  }
5470
6422
 
5482
6434
   */
5483
6435
  head.sibling = &head;
5484
6436
  head.child = &head;
5485
 
  for (i = 0; i < params->handles.n; i++) {
 
6437
  for (i = 0; i < params->nrofobjects; i++) {
5486
6438
    LIBMTP_folder_t *folder;
5487
 
    PTPObjectInfo *oi;
 
6439
    PTPObject *ob;
5488
6440
 
5489
 
    oi = &params->objectinfo[i];
5490
 
    if (oi->ObjectFormat != PTP_OFC_Association) {
 
6441
    ob = &params->objects[i];
 
6442
    if (ob->oi.ObjectFormat != PTP_OFC_Association) {
5491
6443
      continue;
5492
6444
    }
5493
6445
    /*
5494
6446
     * Do we know how to handle these? They are part
5495
6447
     * of the MTP 1.0 specification paragraph 3.6.4.
5496
 
     * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences() 
5497
 
     * should be called on these to get the contained objects, but 
 
6448
     * For AssociationDesc 0x00000001U ptp_mtp_getobjectreferences()
 
6449
     * should be called on these to get the contained objects, but
5498
6450
     * we basically don't care. Hopefully parent_id is maintained for all
5499
6451
     * children, because we rely on that instead.
5500
6452
     */
5501
 
    if (oi->AssociationDesc != 0x00000000U) {
5502
 
      printf("MTP extended association type 0x%08x encountered\n", oi->AssociationDesc);
 
6453
    if (ob->oi.AssociationDesc != 0x00000000U) {
 
6454
      printf("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
5503
6455
    }
5504
6456
 
5505
6457
    // Create a folder struct...
5508
6460
      // malloc failure or so.
5509
6461
      return NULL;
5510
6462
    }
5511
 
    folder->folder_id = params->handles.Handler[i];
5512
 
    folder->parent_id = oi->ParentObject;
5513
 
    folder->storage_id = oi->StorageID;
5514
 
    folder->name = (oi->Filename) ? (char *)strdup(oi->Filename) : NULL;
 
6463
    folder->folder_id = ob->oid;
 
6464
    folder->parent_id = ob->oi.ParentObject;
 
6465
    folder->storage_id = ob->oi.StorageID;
 
6466
    folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
5515
6467
 
5516
6468
    // pretend sibling says next, and child says prev.
5517
6469
    folder->sibling = head.sibling;
5548
6500
 * files and folders may refer to as its "parent".
5549
6501
 *
5550
6502
 * @param device a pointer to the device to create the folder on.
5551
 
 * @param name the name of the new folder.
 
6503
 * @param name the name of the new folder. Note this can be modified
 
6504
 *        if the device does not support all the characters in the
 
6505
 *        name.
5552
6506
 * @param parent_id id of parent folder to add the new folder to,
5553
6507
 *        or 0 to put it in the root directory.
5554
6508
 * @param storage_id id of the storage to add this new folder to.
5681
6635
  uint32_t i;
5682
6636
 
5683
6637
  // Get all the handles if we haven't already done that
5684
 
  if (params->handles.Handler == NULL) {
 
6638
  if (params->nrofobjects == 0) {
5685
6639
    flush_handles(device);
5686
6640
  }
5687
6641
 
5688
 
  for (i = 0; i < params->handles.n; i++) {
 
6642
  for (i = 0; i < params->nrofobjects; i++) {
5689
6643
    LIBMTP_playlist_t *pl;
5690
 
    PTPObjectInfo *oi;
 
6644
    PTPObject *ob;
5691
6645
    uint16_t ret;
5692
6646
 
5693
 
    oi = &params->objectinfo[i];
 
6647
    ob = &params->objects[i];
5694
6648
 
5695
6649
    // Ignore stuff that isn't playlists
5696
6650
 
5697
6651
    // For Samsung players we must look for the .spl extension explicitly since
5698
6652
    // playlists are not stored as playlist objects.
5699
 
    if ( REQ_SPL && is_spl_playlist(oi) ) {
 
6653
    if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
5700
6654
      // Allocate a new playlist type
5701
6655
      pl = LIBMTP_new_playlist_t();
5702
 
      spl_to_playlist_t(device, oi, params->handles.Handler[i], pl);
 
6656
      spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
5703
6657
    }
5704
 
    else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
 
6658
    else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
5705
6659
      continue;
5706
6660
    }
5707
6661
    else {
5709
6663
      pl = LIBMTP_new_playlist_t();
5710
6664
 
5711
6665
      // Try to look up proper name, else use the oi->Filename field.
5712
 
      pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
 
6666
      pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
5713
6667
      if (pl->name == NULL) {
5714
 
        pl->name = strdup(oi->Filename);
 
6668
        pl->name = strdup(ob->oi.Filename);
5715
6669
      }
5716
 
      pl->playlist_id = params->handles.Handler[i];
5717
 
      pl->parent_id = oi->ParentObject;
5718
 
      pl->storage_id = oi->StorageID;
 
6670
      pl->playlist_id = ob->oid;
 
6671
      pl->parent_id = ob->oi.ParentObject;
 
6672
      pl->storage_id = ob->oi.StorageID;
5719
6673
 
5720
6674
      // Then get the track listing for this playlist
5721
6675
      ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
5726
6680
        pl->no_tracks = 0;
5727
6681
      }
5728
6682
    }
5729
 
    
 
6683
 
5730
6684
    // Add playlist to a list that will be returned afterwards.
5731
6685
    if (retlists == NULL) {
5732
6686
      retlists = pl;
5735
6689
      curlist->next = pl;
5736
6690
      curlist = pl;
5737
6691
    }
5738
 
    
 
6692
 
5739
6693
    // Call callback here if we decide to add that possibility...
5740
6694
  }
5741
6695
  return retlists;
5754
6708
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5755
6709
  const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
5756
6710
  PTPParams *params = (PTPParams *) device->params;
5757
 
  uint32_t i;
 
6711
  PTPObject *ob;
 
6712
  LIBMTP_playlist_t *pl;
 
6713
  uint16_t ret;
5758
6714
 
5759
6715
  // Get all the handles if we haven't already done that
5760
 
  if (params->handles.Handler == NULL) {
 
6716
  if (params->nrofobjects == 0) {
5761
6717
    flush_handles(device);
5762
6718
  }
5763
6719
 
5764
 
  for (i = 0; i < params->handles.n; i++) {
5765
 
    LIBMTP_playlist_t *pl;
5766
 
    PTPObjectInfo *oi;
5767
 
    uint16_t ret;
5768
 
    
5769
 
    if (params->handles.Handler[i] != plid) {
5770
 
      continue;
5771
 
    }
5772
 
    
5773
 
    oi = &params->objectinfo[i];
5774
 
 
5775
 
    // For Samsung players we must look for the .spl extension explicitly since
5776
 
    // playlists are not stored as playlist objects.
5777
 
    if ( REQ_SPL && is_spl_playlist(oi) ) {
5778
 
      // Allocate a new playlist type
5779
 
      pl = LIBMTP_new_playlist_t();
5780
 
      spl_to_playlist_t(device, oi, params->handles.Handler[i], pl);
5781
 
      return pl;
5782
 
    }
5783
 
 
5784
 
    // Ignore stuff that isn't playlists
5785
 
    else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
5786
 
      return NULL;
5787
 
    }
5788
 
 
 
6720
  ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
6721
  if (ret != PTP_RC_OK)
 
6722
    return NULL;
 
6723
 
 
6724
  // For Samsung players we must look for the .spl extension explicitly since
 
6725
  // playlists are not stored as playlist objects.
 
6726
  if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
5789
6727
    // Allocate a new playlist type
5790
6728
    pl = LIBMTP_new_playlist_t();
5791
 
 
5792
 
    pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
5793
 
    if (pl->name == NULL) {
5794
 
      pl->name = strdup(oi->Filename);
5795
 
    }
5796
 
    pl->playlist_id = params->handles.Handler[i];
5797
 
    pl->parent_id = oi->ParentObject;
5798
 
    pl->storage_id = oi->StorageID;
5799
 
    
5800
 
    // Then get the track listing for this playlist
5801
 
    ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
5802
 
    if (ret != PTP_RC_OK) {
5803
 
      add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
5804
 
      pl->tracks = NULL;
5805
 
      pl->no_tracks = 0;
5806
 
    }
5807
 
 
 
6729
    spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
5808
6730
    return pl;
5809
6731
  }
5810
 
  return NULL;
 
6732
 
 
6733
  // Ignore stuff that isn't playlists
 
6734
  else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
 
6735
    return NULL;
 
6736
  }
 
6737
 
 
6738
  // Allocate a new playlist type
 
6739
  pl = LIBMTP_new_playlist_t();
 
6740
 
 
6741
  pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
 
6742
  if (pl->name == NULL) {
 
6743
    pl->name = strdup(ob->oi.Filename);
 
6744
  }
 
6745
  pl->playlist_id = ob->oid;
 
6746
  pl->parent_id = ob->oi.ParentObject;
 
6747
  pl->storage_id = ob->oi.StorageID;
 
6748
 
 
6749
  // Then get the track listing for this playlist
 
6750
  ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
 
6751
  if (ret != PTP_RC_OK) {
 
6752
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
 
6753
    pl->tracks = NULL;
 
6754
    pl->no_tracks = 0;
 
6755
  }
 
6756
 
 
6757
  return pl;
5811
6758
}
5812
6759
 
5813
6760
/**
5814
6761
 * This function creates a new abstract list such as a playlist
5815
6762
 * or an album.
5816
 
 * 
 
6763
 *
5817
6764
 * @param device a pointer to the device to create the new abstract list
5818
6765
 *        on.
5819
6766
 * @param name the name of the new abstract list.
5898
6845
    MTPProperties *props = NULL;
5899
6846
    MTPProperties *prop = NULL;
5900
6847
    int nrofprops = 0;
5901
 
    
 
6848
 
5902
6849
    *newid = 0x00000000U;
5903
6850
 
5904
6851
    ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
5905
6852
 
5906
6853
    for (i=0;i<propcnt;i++) {
5907
6854
      PTPObjectPropDesc opd;
5908
 
      
 
6855
 
5909
6856
      ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
5910
6857
      if (ret != PTP_RC_OK) {
5911
6858
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
5914
6861
        switch (properties[i]) {
5915
6862
        case PTP_OPC_ObjectFileName:
5916
6863
          prop = ptp_get_new_object_prop_entry(&props,&nrofprops);
5917
 
          prop->ObjectHandle = *newid;      
 
6864
          prop->ObjectHandle = *newid;
5918
6865
          prop->property = PTP_OPC_ObjectFileName;
5919
6866
          prop->datatype = PTP_DTC_STR;
5920
6867
          prop->propval.str = strdup(fname);
6010
6957
      }
6011
6958
      return -1;
6012
6959
    }
6013
 
    
 
6960
 
6014
6961
    // now send the blank object
6015
6962
    ret = ptp_sendobject(params, NULL, 0);
6016
6963
    if (ret != PTP_RC_OK) {
6039
6986
    }
6040
6987
    // NOTE: don't destroy new_object objectinfo afterwards - the strings it contains are
6041
6988
    // not copies.
6042
 
        
6043
6989
    /*
6044
6990
     * We have to send this one blank data byte.
6045
6991
     * If we don't, the handle will not be created and thus there is no playlist.
6051
6997
      add_ptp_error_to_errorstack(device, ret, "create_new_abstract_list(): Could not send blank object data.");
6052
6998
      return -1;
6053
6999
    }
6054
 
    
 
7000
 
6055
7001
    // set the properties one by one
6056
7002
    ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
6057
7003
 
6058
7004
    for (i=0;i<propcnt;i++) {
6059
7005
      PTPObjectPropDesc opd;
6060
 
      
 
7006
 
6061
7007
      ret = ptp_mtp_getobjectpropdesc(params, properties[i], objectformat, &opd);
6062
7008
      if (ret != PTP_RC_OK) {
6063
7009
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "create_new_abstract_list(): "
6140
7086
}
6141
7087
 
6142
7088
/**
6143
 
 * This updates the metadata and track listing 
 
7089
 * This updates the metadata and track listing
6144
7090
 * for an abstract list.
6145
7091
 * @param device a pointer to the device that the abstract list
6146
7092
 *        resides on.
6169
7115
  uint16_t *properties = NULL;
6170
7116
  uint32_t propcnt = 0;
6171
7117
  int i;
6172
 
  
 
7118
 
6173
7119
  // First see which properties can be set
6174
7120
  // i.e only try to update this metadata for object tags that exist on the current player.
6175
7121
  ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &properties);
6184
7130
    MTPProperties *props = NULL;
6185
7131
    MTPProperties *prop = NULL;
6186
7132
    int nrofprops = 0;
6187
 
    
 
7133
 
6188
7134
    for (i=0;i<propcnt;i++) {
6189
7135
      PTPObjectPropDesc opd;
6190
7136
 
6196
7142
        switch (properties[i]) {
6197
7143
        case PTP_OPC_Name:
6198
7144
          prop = ptp_get_new_object_prop_entry(&props, &nrofprops);
6199
 
          prop->ObjectHandle = objecthandle;      
 
7145
          prop->ObjectHandle = objecthandle;
6200
7146
          prop->property = PTP_OPC_Name;
6201
7147
          prop->datatype = PTP_DTC_STR;
6202
7148
          if (name != NULL)
6254
7200
      }
6255
7201
      ptp_free_objectpropdesc(&opd);
6256
7202
    }
6257
 
    
 
7203
 
6258
7204
    // proplist could be NULL if we can't write any properties
6259
7205
    if (props != NULL) {
6260
7206
      ret = ptp_mtp_setobjectproplist(params, props, nrofprops);
6261
7207
 
6262
7208
      ptp_destroy_object_prop_list(props, nrofprops);
6263
 
    
 
7209
 
6264
7210
      if (ret != PTP_RC_OK) {
6265
7211
        // TODO: return error of which property we couldn't set
6266
7212
        add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "update_abstract_list(): "
6269
7215
        return -1;
6270
7216
      }
6271
7217
    }
6272
 
      
 
7218
 
6273
7219
  } else if (ptp_operation_issupported(params,PTP_OC_MTP_SetObjectPropValue)) {
6274
7220
    for (i=0;i<propcnt;i++) {
6275
7221
      switch (properties[i]) {
6333
7279
    free(properties);
6334
7280
    return -1;
6335
7281
  }
6336
 
  
 
7282
 
6337
7283
  // Then the object references...
6338
7284
  ret = ptp_mtp_setobjectreferences (params, objecthandle, (uint32_t *) tracks, no_tracks);
6339
7285
  if (ret != PTP_RC_OK) {
6345
7291
  free(properties);
6346
7292
 
6347
7293
  update_metadata_cache(device, objecthandle);
6348
 
  
 
7294
 
6349
7295
  return 0;
6350
7296
}
6351
7297
 
6504
7450
}
6505
7451
 
6506
7452
/**
 
7453
 * This function maps and copies a property onto the album metadata if applicable.
 
7454
 */
 
7455
static void pick_property_to_album_metadata(LIBMTP_mtpdevice_t *device,
 
7456
                                            MTPProperties *prop, LIBMTP_album_t *alb)
 
7457
{
 
7458
  switch (prop->property) {
 
7459
  case PTP_OPC_Name:
 
7460
    if (prop->propval.str != NULL)
 
7461
      alb->name = strdup(prop->propval.str);
 
7462
    else
 
7463
      alb->name = NULL;
 
7464
    break;
 
7465
  case PTP_OPC_AlbumArtist:
 
7466
    if (prop->propval.str != NULL) {
 
7467
      // This should take precedence over plain "Artist"
 
7468
      if (alb->artist != NULL)
 
7469
        free(alb->artist);
 
7470
      alb->artist = strdup(prop->propval.str);
 
7471
    } else
 
7472
      alb->artist = NULL;
 
7473
    break;
 
7474
  case PTP_OPC_Artist:
 
7475
    if (prop->propval.str != NULL) {
 
7476
      // Only use of AlbumArtist is not set
 
7477
      if (alb->artist == NULL)
 
7478
        alb->artist = strdup(prop->propval.str);
 
7479
    } else
 
7480
      alb->artist = NULL;
 
7481
    break;
 
7482
  case PTP_OPC_Composer:
 
7483
    if (prop->propval.str != NULL)
 
7484
      alb->composer = strdup(prop->propval.str);
 
7485
    else
 
7486
      alb->composer = NULL;
 
7487
    break;
 
7488
  case PTP_OPC_Genre:
 
7489
    if (prop->propval.str != NULL)
 
7490
      alb->genre = strdup(prop->propval.str);
 
7491
    else
 
7492
      alb->genre = NULL;
 
7493
    break;
 
7494
  }
 
7495
}
 
7496
 
 
7497
/**
 
7498
 * This function retrieves the album metadata for an album
 
7499
 * given by a unique ID.
 
7500
 * @param device a pointer to the device to get the track metadata off.
 
7501
 * @param alb an album metadata metadata set to fill in.
 
7502
 */
 
7503
static void get_album_metadata(LIBMTP_mtpdevice_t *device,
 
7504
                               LIBMTP_album_t *alb)
 
7505
{
 
7506
  uint16_t ret;
 
7507
  PTPParams *params = (PTPParams *) device->params;
 
7508
  uint32_t i;
 
7509
  MTPProperties *prop;
 
7510
  PTPObject *ob;
 
7511
 
 
7512
  /*
 
7513
   * If we have a cached, large set of metadata, then use it!
 
7514
   */
 
7515
  ret = ptp_object_want(params, alb->album_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
 
7516
  if (ob->mtpprops) {
 
7517
    prop = ob->mtpprops;
 
7518
    for (i=0;i<ob->nrofmtpprops;i++,prop++)
 
7519
      pick_property_to_album_metadata(device, prop, alb);
 
7520
  } else {
 
7521
    uint16_t *props = NULL;
 
7522
    uint32_t propcnt = 0;
 
7523
 
 
7524
    // First see which properties can be retrieved for albums
 
7525
    ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
 
7526
    if (ret != PTP_RC_OK) {
 
7527
      add_ptp_error_to_errorstack(device, ret, "get_album_metadata(): call to ptp_mtp_getobjectpropssupported() failed.");
 
7528
      // Just bail out for now, nothing is ever set.
 
7529
      return;
 
7530
    } else {
 
7531
      for (i=0;i<propcnt;i++) {
 
7532
        switch (props[i]) {
 
7533
        case PTP_OPC_Name:
 
7534
          alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
 
7535
          break;
 
7536
        case PTP_OPC_AlbumArtist:
 
7537
          if (alb->artist != NULL)
 
7538
            free(alb->artist);
 
7539
          alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
 
7540
          break;
 
7541
        case PTP_OPC_Artist:
 
7542
          if (alb->artist == NULL)
 
7543
            alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
 
7544
          break;
 
7545
        case PTP_OPC_Composer:
 
7546
          alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
 
7547
          break;
 
7548
        case PTP_OPC_Genre:
 
7549
          alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
 
7550
          break;
 
7551
        default:
 
7552
          break;
 
7553
        }
 
7554
      }
 
7555
      free(props);
 
7556
    }
 
7557
  }
 
7558
}
 
7559
 
 
7560
/**
6507
7561
 * This function returns a list of the albums available on the
6508
7562
 * device.
6509
7563
 *
6520
7574
  uint32_t i;
6521
7575
 
6522
7576
  // Get all the handles if we haven't already done that
6523
 
  if (params->handles.Handler == NULL) {
 
7577
  if (params->nrofobjects == 0)
6524
7578
    flush_handles(device);
6525
 
  }
6526
7579
 
6527
 
  for (i = 0; i < params->handles.n; i++) {
 
7580
  for (i = 0; i < params->nrofobjects; i++) {
6528
7581
    LIBMTP_album_t *alb;
6529
 
    PTPObjectInfo *oi;
 
7582
    PTPObject *ob;
6530
7583
    uint16_t ret;
6531
7584
 
6532
 
    oi = &params->objectinfo[i];
 
7585
    ob = &params->objects[i];
6533
7586
 
6534
7587
    // Ignore stuff that isn't an album
6535
 
    if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
 
7588
    if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum )
6536
7589
      continue;
6537
 
    }
6538
7590
 
6539
7591
    // Allocate a new album type
6540
7592
    alb = LIBMTP_new_album_t();
6541
 
    alb->album_id = params->handles.Handler[i];
6542
 
    alb->parent_id = oi->ParentObject;
6543
 
    alb->storage_id = oi->StorageID;
6544
 
 
6545
 
    // Get metadata for it.
6546
 
    alb->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
6547
 
    alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_AlbumArtist);
6548
 
    if (alb->artist == NULL) {
6549
 
      alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Artist);
6550
 
    }
6551
 
    alb->composer = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Composer);
6552
 
    alb->genre = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Genre);
6553
 
    
 
7593
    alb->album_id = ob->oid;
 
7594
    alb->parent_id = ob->oi.ParentObject;
 
7595
    alb->storage_id = ob->oi.StorageID;
 
7596
 
 
7597
    // Fetch supported metadata
 
7598
    get_album_metadata(device, alb);
 
7599
 
6554
7600
    // Then get the track listing for this album
6555
7601
    ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
6556
7602
    if (ret != PTP_RC_OK) {
6558
7604
      alb->tracks = NULL;
6559
7605
      alb->no_tracks = 0;
6560
7606
    }
6561
 
    
 
7607
 
6562
7608
    // Add album to a list that will be returned afterwards.
6563
7609
    if (retalbums == NULL) {
6564
7610
      retalbums = alb;
6567
7613
      curalbum->next = alb;
6568
7614
      curalbum = alb;
6569
7615
    }
6570
 
    
 
7616
 
6571
7617
  }
6572
7618
  return retalbums;
6573
7619
}
6582
7628
LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
6583
7629
{
6584
7630
  PTPParams *params = (PTPParams *) device->params;
6585
 
  uint32_t i;
 
7631
  uint16_t ret;
 
7632
  PTPObject *ob;
 
7633
  LIBMTP_album_t *alb;
6586
7634
 
6587
7635
  // Get all the handles if we haven't already done that
6588
 
  if (params->handles.Handler == NULL) {
 
7636
  if (params->nrofobjects == 0)
6589
7637
    flush_handles(device);
6590
 
  }
6591
 
 
6592
 
  for (i = 0; i < params->handles.n; i++) {
6593
 
    LIBMTP_album_t *alb;
6594
 
    PTPObjectInfo *oi;
6595
 
    uint16_t ret;
6596
 
 
6597
 
    if (params->handles.Handler[i] != albid) {
6598
 
      continue;
6599
 
    }
6600
 
 
6601
 
    oi = &params->objectinfo[i];
6602
 
 
6603
 
    // Ignore stuff that isn't an album
6604
 
    if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
6605
 
      return NULL;
6606
 
    }
6607
 
 
6608
 
    // Allocate a new album type
6609
 
    alb = LIBMTP_new_album_t();
6610
 
    alb->album_id = params->handles.Handler[i];
6611
 
    alb->parent_id = oi->ParentObject;
6612
 
    alb->storage_id = oi->StorageID;
6613
 
 
6614
 
    // Get metadata for it.
6615
 
    alb->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
6616
 
    alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_AlbumArtist);
6617
 
    if (alb->artist == NULL) {
6618
 
      alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Artist);
6619
 
    }
6620
 
    alb->composer = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Composer);
6621
 
    alb->genre = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Genre);
6622
 
    ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
6623
 
    if (ret != PTP_RC_OK) {
6624
 
      add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
6625
 
      alb->tracks = NULL;
6626
 
      alb->no_tracks = 0;
6627
 
    }
6628
 
    
6629
 
    return alb;
6630
 
  }
6631
 
  return NULL;
 
7638
 
 
7639
  ret = ptp_object_want(params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
7640
  if (ret != PTP_RC_OK)
 
7641
    return NULL;
 
7642
 
 
7643
  // Ignore stuff that isn't an album
 
7644
  if (ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum)
 
7645
    return NULL;
 
7646
 
 
7647
  // Allocate a new album type
 
7648
  alb = LIBMTP_new_album_t();
 
7649
  alb->album_id = ob->oid;
 
7650
  alb->parent_id = ob->oi.ParentObject;
 
7651
  alb->storage_id = ob->oi.StorageID;
 
7652
 
 
7653
  // Fetch supported metadata
 
7654
  get_album_metadata(device, alb);
 
7655
 
 
7656
  // Then get the track listing for this album
 
7657
  ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
 
7658
  if (ret != PTP_RC_OK) {
 
7659
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
 
7660
    alb->tracks = NULL;
 
7661
    alb->no_tracks = 0;
 
7662
  }
 
7663
 
 
7664
  return alb;
6632
7665
}
6633
7666
 
6634
7667
/**
6641
7674
 *        exits with success, the <code>album_id</code> field of this
6642
7675
 *        struct will contain the new ID of the album.
6643
7676
 *        <ul>
6644
 
 *        <li><code>metadata-&gt;parent_id</code> should be set to the parent 
6645
 
 *        (e.g. folder) to store this track in. Since some 
 
7677
 *        <li><code>metadata-&gt;parent_id</code> should be set to the parent
 
7678
 *        (e.g. folder) to store this track in. Since some
6646
7679
 *        devices are a bit picky about where files
6647
7680
 *        are placed, a default folder will be chosen if libmtp
6648
7681
 *        has detected one for the current filetype and this
6763
7796
  int support_height = 0;
6764
7797
  int support_width = 0;
6765
7798
  int support_duration = 0;
 
7799
  int support_size = 0;
6766
7800
 
6767
7801
  PTPObjectPropDesc opd_height;
6768
7802
  PTPObjectPropDesc opd_width;
6769
7803
  PTPObjectPropDesc opd_format;
6770
7804
  PTPObjectPropDesc opd_duration;
 
7805
  PTPObjectPropDesc opd_size;
6771
7806
  
6772
7807
  // Default to no type supported.
6773
7808
  *sample = NULL;
6792
7827
      support_format = 1;
6793
7828
      break;
6794
7829
    case PTP_OPC_RepresentativeSampleSize:
 
7830
      support_size = 1;
6795
7831
      break;
6796
7832
    case PTP_OPC_RepresentativeSampleHeight:
6797
7833
      support_height = 1;
6807
7843
    }
6808
7844
  }
6809
7845
  free(props);
6810
 
  
 
7846
    
6811
7847
  if (support_data && support_format && support_height && support_width && !support_duration) {
6812
7848
    // Something that supports height and width and not duration is likely to be JPEG
6813
7849
    LIBMTP_filesampledata_t *retsam = LIBMTP_new_filesampledata_t();
6819
7855
     */
6820
7856
    ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);    
6821
7857
    retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
 
7858
    ptp_free_objectpropdesc(&opd_format);
6822
7859
    /* Populate the maximum image height */
6823
7860
    ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleWidth, map_libmtp_type_to_ptp_type(filetype), &opd_width);        
6824
7861
    retsam->width = opd_width.FORM.Range.MaximumValue.u32;
 
7862
    ptp_free_objectpropdesc(&opd_width);
6825
7863
    /* Populate the maximum image width */
6826
7864
    ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleHeight, map_libmtp_type_to_ptp_type(filetype), &opd_height);                                                 
6827
7865
    retsam->height = opd_height.FORM.Range.MaximumValue.u32;
 
7866
    ptp_free_objectpropdesc(&opd_height);
 
7867
    /* Populate the maximum size */
 
7868
    if (support_size) {
 
7869
      ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
 
7870
      retsam->size = opd_size.FORM.Range.MaximumValue.u32;
 
7871
      ptp_free_objectpropdesc(&opd_size);
 
7872
    }
6828
7873
    *sample = retsam;
6829
7874
  } else if (support_data && support_format && !support_height && !support_width && support_duration) {
6830
7875
    // Another qualified guess
6837
7882
     */
6838
7883
    ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleFormat, map_libmtp_type_to_ptp_type(filetype), &opd_format);    
6839
7884
    retsam->filetype = map_ptp_type_to_libmtp_type(opd_format.FORM.Enum.SupportedValue[0].u16);
6840
 
        /* Populate the maximum duration */
 
7885
    ptp_free_objectpropdesc(&opd_format);
 
7886
    /* Populate the maximum duration */
6841
7887
    ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleDuration, map_libmtp_type_to_ptp_type(filetype), &opd_duration);    
6842
7888
    retsam->duration = opd_duration.FORM.Range.MaximumValue.u32;
 
7889
    ptp_free_objectpropdesc(&opd_duration);
 
7890
    /* Populate the maximum size */
 
7891
    if (support_size) {
 
7892
      ptp_mtp_getobjectpropdesc (params, PTP_OPC_RepresentativeSampleSize, map_libmtp_type_to_ptp_type(filetype), &opd_size);
 
7893
      retsam->size = opd_size.FORM.Range.MaximumValue.u32;
 
7894
      ptp_free_objectpropdesc(&opd_size);
 
7895
    }
6843
7896
    *sample = retsam;
6844
7897
  }
6845
7898
  return 0;
6851
7904
 * if the device supports it. The data should be of a format acceptable
6852
7905
 * to the player (for iRiver and Creative, this seems to be JPEG) and
6853
7906
 * must not be too large. (for a Creative, max seems to be about 20KB.)
6854
 
 * TODO: there must be a way to find the max size for an ObjectPropertyValue.
 
7907
 * Check by calling LIBMTP_Get_Representative_Sample_Format() to get
 
7908
 * maximum size, dimensions, etc..
6855
7909
 * @param device a pointer to the device which the object is on.
6856
7910
 * @param id unique id of the object to set artwork for.
6857
7911
 * @param pointer to LIBMTP_filesampledata_t struct containing data
6868
7922
  PTPParams *params = (PTPParams *) device->params;
6869
7923
  PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
6870
7924
  PTPPropertyValue propval;
6871
 
  PTPObjectInfo *oi;
 
7925
  PTPObject *ob;
6872
7926
  uint32_t i;
6873
7927
  uint16_t *props = NULL;
6874
7928
  uint32_t propcnt = 0;
6875
7929
  int supported = 0;
6876
7930
 
6877
7931
  // get the file format for the object we're going to send representative data for
6878
 
  oi = NULL;
6879
 
  for (i = 0; i < params->handles.n; i++) {
6880
 
    if (params->handles.Handler[i] == id) {
6881
 
      oi = &params->objectinfo[i];
6882
 
      break;
6883
 
    }
6884
 
  }
6885
 
 
6886
 
  if (oi == NULL) {
 
7932
  ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
7933
  if (ret != PTP_RC_OK) {
6887
7934
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
6888
7935
    return -1;
6889
7936
  }
6890
7937
 
6891
7938
  // check that we can send representative sample data for this object format
6892
 
  ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
 
7939
  ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
6893
7940
  if (ret != PTP_RC_OK) {
6894
7941
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
6895
7942
    return -1;
6969
8016
  uint16_t ret;
6970
8017
  PTPParams *params = (PTPParams *) device->params;
6971
8018
  PTPPropertyValue propval;
6972
 
  PTPObjectInfo *oi;
 
8019
  PTPObject *ob;
6973
8020
  uint32_t i;
6974
8021
  uint16_t *props = NULL;
6975
8022
  uint32_t propcnt = 0;
6976
8023
  int supported = 0;
6977
8024
 
6978
8025
  // get the file format for the object we're going to send representative data for
6979
 
  oi = NULL;
6980
 
  for (i = 0; i < params->handles.n; i++) {
6981
 
    if (params->handles.Handler[i] == id) {
6982
 
      oi = &params->objectinfo[i];
6983
 
      break;
6984
 
    }
6985
 
  }
6986
 
 
6987
 
  if (oi == NULL) {
 
8026
  ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
 
8027
  if (ret != PTP_RC_OK) {
6988
8028
    add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
6989
8029
    return -1;
6990
8030
  }
6991
8031
 
6992
8032
  // check that we can store representative sample data for this object format
6993
 
  ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
 
8033
  ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
6994
8034
  if (ret != PTP_RC_OK) {
6995
8035
    add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
6996
8036
    return -1;