Some refactoring
diff --git a/src/libmtp.c b/src/libmtp.c
index daef1cd..6475f13 100644
--- a/src/libmtp.c
+++ b/src/libmtp.c
@@ -3854,69 +3854,81 @@
}
/*
- * TODO: Refactor LIBMTP_Create_New_Playlist() and
- * LIBMTP_Create_New_Album() to use a common
- * static create_new_abstract_entity() function.
- */
-
-/**
- * This routine creates a new playlist based on the metadata
- * supplied. If the <code>tracks</code> field of the metadata
- * contains a track listing, these tracks will be added to the
- * playlist.
- * @param device a pointer to the device to create the new playlist on.
- * @param metadata the metadata for the new playlist. If the function
- * exits with success, the <code>playlist_id</code> field of this
- * struct will contain the new playlist ID of the playlist.
- * @param parenthandle the parent (e.g. folder) to store this playlist
- * in. Pass in 0 to put the playlist in the root directory.
+ * This function creates a new abstract list such as a playlist
+ * or an album.
+ *
+ * @param device a pointer to the device to create the new abstract list
+ * on.
+ * @param name the name of the new abstract list.
+ * @param parenthandle the handle of the parent or 0 for no parent
+ * i.e. the root folder.
+ * @param objectformat the abstract list type to create.
+ * @param suffix the ".foo" (4 characters) suffix to use for the virtual
+ * "file" created by this operation.
+ * @param newid a pointer to a variable that will hold the new object
+ * ID if this call is successful.
+ * @param tracks an array of tracks to associate with this list.
+ * @param no_tracks the number of tracks in the list.
* @return 0 on success, any other value means failure.
- * @see LIBMTP_Update_Playlist()
- * @see LIBMTP_Delete_Object()
*/
-int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
- LIBMTP_playlist_t * const metadata,
- uint32_t const parenthandle)
+static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,
+ char const * const name,
+ uint32_t const parenthandle,
+ uint16_t const objectformat,
+ char const * const suffix,
+ uint32_t * const newid,
+ uint32_t const * const tracks,
+ uint32_t const no_tracks)
+
{
+ int i;
+ int supported = 0;
uint16_t ret;
uint32_t store = 0;
uint16_t *props = NULL;
uint32_t propcnt = 0;
- uint8_t nonconsumable = 0x00U; /* By default it is consumable */
- int i;
- PTPParams *params = (PTPParams *) device->params;
uint32_t localph = parenthandle;
+ uint8_t nonconsumable = 0x00U; /* By default it is consumable */
+ PTPParams *params = (PTPParams *) device->params;
char fname[256];
uint8_t data[2];
- PTPObjectInfo new_pl;
+ PTPObjectInfo new_object;
- // Use a default folder if none given
- if (localph == 0) {
- localph = device->default_playlist_folder;
- }
-
- // .zpl is the "abstract audio/video playlist "file" suffix
- new_pl.Filename = NULL;
- if (strlen(metadata->name) > 4) {
- char *suff = &metadata->name[strlen(metadata->name)-4];
- if (!strcmp(suff, ".zpl")) {
- // Home free.
- new_pl.Filename = metadata->name;
+ // Check if we can create an object of this type
+ for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
+ if (params->deviceinfo.ImageFormats[i] == objectformat) {
+ supported = 1;
+ break;
}
}
- // If it didn't end with ".zpl" then add that here.
- if (new_pl.Filename == NULL) {
- strncpy(fname, metadata->name, sizeof(fname)-5);
- strcat(fname, ".zpl");
+ if (!supported) {
+ printf("create_new_abstract_list(): player does not support this abstract type (0x%04x)\n", objectformat);
+ return -1;
+ }
+
+
+ // add the new suffix if it isn's there
+ new_object.Filename = NULL;
+ if (strlen(name) > strlen(suffix)) {
+ char const * const suff = &name[strlen(name)-strlen(suffix)];
+ if (!strcmp(suff, suffix)) {
+ // Home free.
+ new_object.Filename = (char *) name;
+ }
+ }
+ // If it didn't end with "<suffix>" then add that here.
+ if (new_object.Filename == NULL) {
+ strncpy(fname, name, sizeof(fname)-strlen(suffix)-1);
+ strcat(fname, suffix);
fname[sizeof(fname)-1] = '\0';
- new_pl.Filename = fname;
+ new_object.Filename = fname;
}
// Playlists created on device have size (uint32_t) -1 = 0xFFFFFFFFU, but setting:
- // new_pl.ObjectCompressedSize = 0; <- DOES NOT WORK! (return PTP_RC_GeneralError)
- // new_pl.ObjectCompressedSize = (uint32_t) -1; <- DOES NOT WORK! (return PTP_RC_MTP_Object_Too_Large)
- new_pl.ObjectCompressedSize = 1;
- new_pl.ObjectFormat = PTP_OFC_MTP_AbstractAudioVideoPlaylist;
+ // new_object.ObjectCompressedSize = 0; <- DOES NOT WORK! (return PTP_RC_GeneralError)
+ // new_object.ObjectCompressedSize = (uint32_t) -1; <- DOES NOT WORK! (return PTP_RC_MTP_Object_Too_Large)
+ new_object.ObjectCompressedSize = 1;
+ new_object.ObjectFormat = objectformat;
#ifdef ENABLE_MTP_ENHANCED
if (ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
@@ -3925,7 +3937,7 @@
MTPPropList *prop = NULL;
MTPPropList *previous = NULL;
- ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioVideoPlaylist, &propcnt, &props);
+ ret = ptp_mtp_getobjectpropssupported(params, objectformat, &propcnt, &props);
for (i=0;i<propcnt;i++) {
switch (props[i]) {
@@ -3933,7 +3945,7 @@
prop = New_MTP_Prop_Entry();
prop->property = PTP_OPC_ObjectFileName;
prop->datatype = PTP_DTC_STR;
- prop->propval.str = strdup(new_pl.Filename);
+ prop->propval.str = strdup(new_object.Filename);
if (previous != NULL)
previous->next = prop;
@@ -3972,7 +3984,7 @@
prop = New_MTP_Prop_Entry();
prop->property = PTP_OPC_Name;
prop->datatype = PTP_DTC_STR;
- prop->propval.str = strdup(metadata->name);
+ prop->propval.str = strdup(name);
if (previous != NULL)
previous->next = prop;
@@ -3985,13 +3997,12 @@
}
free(props);
- metadata->playlist_id = 0x00000000U;
+ *newid = 0x00000000U;
// TODO: try setting size to 0xFFFFFFFFU instead of 1 here, and move
// the 1-byte sending function below.
- ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->playlist_id,
- PTP_OFC_MTP_AbstractAudioVideoPlaylist,
- 1, proplist);
+ ret = ptp_mtp_sendobjectproplist(params, &store, &localph, newid,
+ objectformat, 1, proplist);
/* Free property list */
prop = proplist;
@@ -4003,7 +4014,7 @@
if (ret != PTP_RC_OK) {
ptp_perror(params, ret);
- printf("LIBMTP_Create_New_Playlist(): Could not send object property list.\n");
+ printf("create_new_abstract_list(): Could not send object property list.\n");
if (ret == PTP_RC_AccessDenied) {
printf("ACCESS DENIED.\n");
} else {
@@ -4016,10 +4027,10 @@
{
#endif // ENABLE_MTP_ENHANCED
// Create the object
- ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->playlist_id, &new_pl);
+ ret = ptp_sendobjectinfo(params, &store, &localph, newid, &new_object);
if (ret != PTP_RC_OK) {
ptp_perror(params, ret);
- printf("LIBMTP_New_Playlist(): Could not send object info (the playlist itself)\n");
+ printf("create_new_abstract_list(): Could not send object info (the playlist itself)\n");
if (ret == PTP_RC_AccessDenied) {
printf("ACCESS DENIED.\n");
} else {
@@ -4032,29 +4043,31 @@
/*
* We have to send this one blank data byte.
* If we don't, the handle will not be created and thus there is no playlist.
+ * TODO: see if this can be avoided with enhanced commands!
*/
data[0] = '\0';
data[1] = '\0';
ret = ptp_sendobject(params, data, 1);
if (ret != PTP_RC_OK) {
ptp_perror(params, ret);
- printf("LIBMTP_New_Playlist(): Could not send blank object data\n");
+ printf("create_new_abstract_list(): Could not send blank object data\n");
printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
return -1;
}
// Update title
- ret = LIBMTP_Set_Object_String(device, metadata->playlist_id, PTP_OPC_Name, metadata->name);
+ // TODO: should not be needed for enhanced commands!
+ ret = LIBMTP_Set_Object_String(device, *newid, PTP_OPC_Name, name);
if (ret != 0) {
- printf("LIBMTP_New_Playlist(): could not set playlist name\n");
+ printf("create_new_abstract_list(): could not set entity name\n");
return -1;
}
- if (metadata->no_tracks > 0) {
+ if (no_tracks > 0) {
// Add tracks to the new playlist as object references.
- ret = ptp_mtp_setobjectreferences (params, metadata->playlist_id, metadata->tracks, metadata->no_tracks);
+ ret = ptp_mtp_setobjectreferences (params, *newid, (uint32_t *) tracks, no_tracks);
if (ret != PTP_RC_OK) {
- printf("LIBMTP_New_Playlist(): could not add tracks as object references\n");
+ printf("create_new_abstract_list(): could not add tracks as object references\n");
printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
return -1;
}
@@ -4066,6 +4079,44 @@
return 0;
}
+
+/**
+ * This routine creates a new playlist based on the metadata
+ * supplied. If the <code>tracks</code> field of the metadata
+ * contains a track listing, these tracks will be added to the
+ * playlist.
+ * @param device a pointer to the device to create the new playlist on.
+ * @param metadata the metadata for the new playlist. If the function
+ * exits with success, the <code>playlist_id</code> field of this
+ * struct will contain the new playlist ID of the playlist.
+ * @param parenthandle the parent (e.g. folder) to store this playlist
+ * in. Pass in 0 to put the playlist in the root directory.
+ * @return 0 on success, any other value means failure.
+ * @see LIBMTP_Update_Playlist()
+ * @see LIBMTP_Delete_Object()
+ */
+int LIBMTP_Create_New_Playlist(LIBMTP_mtpdevice_t *device,
+ LIBMTP_playlist_t * const metadata,
+ uint32_t const parenthandle)
+{
+ uint32_t localph = parenthandle;
+
+ // Use a default folder if none given
+ if (localph == 0) {
+ localph = device->default_playlist_folder;
+ }
+
+ // Just create a new abstract audio/video playlist...
+ return create_new_abstract_list(device,
+ metadata->name,
+ localph,
+ PTP_OFC_MTP_AbstractAudioVideoPlaylist,
+ ".zpl",
+ &metadata->playlist_id,
+ metadata->tracks,
+ metadata->no_tracks);
+}
+
/**
* This routine updates a playlist based on the metadata
* supplied. If the <code>tracks</code> field of the metadata
@@ -4282,191 +4333,22 @@
LIBMTP_album_t * const metadata,
uint32_t const parenthandle)
{
- uint16_t ret;
- uint32_t store = 0;
- PTPObjectInfo new_alb;
- PTPParams *params = (PTPParams *) device->params;
uint32_t localph = parenthandle;
- char fname[256];
- uint8_t data[2];
- uint16_t *props = NULL;
- uint32_t propcnt = 0;
- uint8_t nonconsumable = 0x00U; /* By default it is consumable */
-
- // Check if we can create an object of type PTP_OFC_MTP_AbstractAudioAlbum
- int i;
- int supported = 0;
- for ( i=0; i < params->deviceinfo.ImageFormats_len; i++ ) {
- if (params->deviceinfo.ImageFormats[i] == PTP_OFC_MTP_AbstractAudioAlbum) {
- supported = 1;
- break;
- }
- }
- if (!supported) {
- printf("LIBMTP_Create_New_Album(): Player does not support the AbstractAudioAlbum type\n");
- return -1;
- }
// Use a default folder if none given
if (localph == 0) {
localph = device->default_album_folder;
}
- new_alb.Filename = NULL;
- if (strlen(metadata->name) > 4) {
- char *suff = &metadata->name[strlen(metadata->name)-4];
- if (!strcmp(suff, ".alb")) {
- new_alb.Filename = metadata->name;
- }
- }
- // If it didn't end with ".alb" then add that here.
- if (new_alb.Filename == NULL) {
- strncpy(fname, metadata->name, sizeof(fname)-5);
- strcat(fname, ".alb");
- fname[sizeof(fname)-1] = '\0';
- new_alb.Filename = fname;
- }
-
- new_alb.ObjectCompressedSize = 1;
- new_alb.ObjectFormat = PTP_OFC_MTP_AbstractAudioAlbum;
-
-#ifdef ENABLE_MTP_ENHANCED
- if (ptp_operation_issupported(params,PTP_OC_MTP_SendObjectPropList)) {
-
- MTPPropList *proplist = NULL;
- MTPPropList *prop = NULL;
- MTPPropList *previous = NULL;
-
- ret = ptp_mtp_getobjectpropssupported(params, PTP_OFC_MTP_AbstractAudioAlbum, &propcnt, &props);
-
- for (i=0;i<propcnt;i++) {
- switch (props[i]) {
- case PTP_OPC_ObjectFileName:
- prop = New_MTP_Prop_Entry();
- prop->property = PTP_OPC_ObjectFileName;
- prop->datatype = PTP_DTC_STR;
- prop->propval.str = strdup(new_alb.Filename);
-
- if (previous != NULL)
- previous->next = prop;
- else
- proplist = prop;
- previous = prop;
- prop->next = NULL;
- break;
- case PTP_OPC_ProtectionStatus:
- prop = New_MTP_Prop_Entry();
- prop->property = PTP_OPC_ProtectionStatus;
- prop->datatype = PTP_DTC_UINT16;
- prop->propval.u16 = 0x0000U; /* Not protected */
-
- if (previous != NULL)
- previous->next = prop;
- else
- proplist = prop;
- previous = prop;
- prop->next = NULL;
- break;
- case PTP_OPC_NonConsumable:
- prop = New_MTP_Prop_Entry();
- prop->property = PTP_OPC_NonConsumable;
- prop->datatype = PTP_DTC_UINT8;
- prop->propval.u8 = nonconsumable;
-
- if (previous != NULL)
- previous->next = prop;
- else
- proplist = prop;
- previous = prop;
- prop->next = NULL;
- break;
- case PTP_OPC_Name:
- prop = New_MTP_Prop_Entry();
- prop->property = PTP_OPC_Name;
- prop->datatype = PTP_DTC_STR;
- prop->propval.str = strdup(metadata->name);
-
- if (previous != NULL)
- previous->next = prop;
- else
- proplist = prop;
- previous = prop;
- prop->next = NULL;
- break;
- }
- }
- free(props);
-
- metadata->album_id = 0x00000000U;
-
- // TODO: try setting size to 0xFFFFFFFFU instead of 1 here, and move
- // the 1-byte sending function below.
- ret = ptp_mtp_sendobjectproplist(params, &store, &localph, &metadata->album_id,
- PTP_OFC_MTP_AbstractAudioAlbum,
- 1, proplist);
-
- /* Free property list */
- prop = proplist;
- while (prop != NULL) {
- previous = prop;
- prop = prop->next;
- Destroy_MTP_Prop_Entry(previous);
- }
-
- if (ret != PTP_RC_OK) {
- ptp_perror(params, ret);
- printf("LIBMTP_New_Album(): Could not send object property list.\n");
- if (ret == PTP_RC_AccessDenied) {
- printf("ACCESS DENIED.\n");
- } else {
- printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
- }
- return -1;
- }
- } else if (ptp_operation_issupported(params,PTP_OC_SendObjectInfo)) {
-#else // !ENABLE_MTP_ENHANCED
- {
-#endif // ENABLE_MTP_ENHANCED
- // Create the object
- ret = ptp_sendobjectinfo(params, &store, &localph, &metadata->album_id, &new_alb);
- if (ret != PTP_RC_OK) {
- ptp_perror(params, ret);
- printf("LIBMTP_New_Album(): Could not send object info (the album itself)\n");
- printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
- return -1;
- }
- }
- data[0] = '\0';
- data[1] = '\0';
- ret = ptp_sendobject(params, data, 1);
- if (ret != PTP_RC_OK) {
- ptp_perror(params, ret);
- printf("LIBMTP_New_Album(): Could not send blank object data\n");
- printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
- return -1;
- }
-
- // Update title
- ret = LIBMTP_Set_Object_String(device, metadata->album_id, PTP_OPC_Name, metadata->name);
- if (ret != 0) {
- printf("LIBMTP_New_Album(): could not set album name\n");
- return -1;
- }
-
- if (metadata->no_tracks > 0) {
- // Add tracks to the new album as object references.
- ret = ptp_mtp_setobjectreferences (params, metadata->album_id, metadata->tracks, metadata->no_tracks);
- if (ret != PTP_RC_OK) {
- printf("LIBMTP_New_Album(): could not add tracks as object references\n");
- printf("Return code: 0x%04x (look this up in ptp.h for an explanation).\n", ret);
- return -1;
- }
- }
-
- // Created new item, so flush handles
- flush_handles(device);
-
- return 0;
+ // Just create a new abstract album...
+ return create_new_abstract_list(device,
+ metadata->name,
+ localph,
+ PTP_OFC_MTP_AbstractAudioAlbum,
+ ".alb",
+ &metadata->album_id,
+ metadata->tracks,
+ metadata->no_tracks);
}
/**