summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Walleij <triad@df.lth.se>2009-06-14 23:03:33 +0000
committerLinus Walleij <triad@df.lth.se>2009-06-14 23:03:33 +0000
commitd4637506d9551957a152cab2cfb80fdfed029424 (patch)
treedcc8a3847d8726eaaf4ee892f84ffcf086d9a536
parent21b2ddeb77b6c136210aa5631fc43f3bccc6168a (diff)
downloadlibmtp-d4637506d9551957a152cab2cfb80fdfed029424.tar.gz
Marcus' core updates.
-rw-r--r--ChangeLog85
-rw-r--r--INSTALL19
-rw-r--r--configure.ac5
-rw-r--r--src/device-flags.h34
-rw-r--r--src/libmtp.c994
-rw-r--r--src/ptp-pack.c102
-rw-r--r--src/ptp.c408
-rw-r--r--src/ptp.h45
8 files changed, 923 insertions, 769 deletions
diff --git a/ChangeLog b/ChangeLog
index 1d0bbd4..702ab72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,84 @@
+2009-06-15 Linus Walleij <triad@df.lth.se>
+
+ * configure.ac: some buildsystem updates.
+ * INSTALL: some doc updates.
+
+2009-06-15 Marcus Meissner <meissner@suse.de>
+
+ * src/libmtp.c: synced to new libgphoto2 code.
+ * src/device-flags.h: dito.
+ * src/ptp.h: sync to upstream.
+ * src/ptp.c: dito.
+ * src/ptp-pack.c: dito.
+
+ The handles, the PTPObjectInfo and the MTP proplists
+ are now consolidated into "PTPObject"s.
+
+ This and abstraction and the resulting helper functions
+ allow implementation of easier dynamic operations like
+ I need for libgphoto2.
+
+ Some corner stones:
+
+ - PTPParams now contains the device flags itself.
+ (from device-flags.h) This is needed due to
+ ptp_object_want() needing to decide whether it can call
+ GetObjPropList, and it makes it cleaner.
+
+ So the ptp-bugs and device-flags handling are unified.
+
+ - PTPObjects are sorted by object handle. This allows binary
+ search by handle.
+
+ - New generic helper functions.
+
+ * uint16_t ptp_object_find (PTPParams *params,
+ uint32_t handle, PTPObject **retob)
+ binary searches the handle in the object list and returns
+ a pointer to the object.
+
+ * uint16_t ptp_object_find_or_insert (PTPParams *params,
+ uint32_t handle, PTPObject **retob)
+ binary searches the handle in the object list, inserts it
+ if not there yet, and returns a pointer to the object.
+
+ * uint16_t ptp_object_want (PTPParams *params, uint32_t handle,
+ int want, PTPObject **retob)
+ The most magic function, which does the "on demand" loading
+ of objectinfos, mtp proplists (and more).
+ want is a flag mask of PTPOBJECT_*_LOADED
+ PTPOBJECT_OBJECTINFO_LOADED clear
+ PTPOBJECT_CANONFLAGS_LOADED (special canon flags)
+ PTPOBJECT_MTPPROPLIST_LOADED mtp properties for this object
+ loaded
+ PTPOBJECT_DIRECTORY_LOADED (only used by libgphoto2 currently)
+ PTPOBJECT_PARENTOBJECT_LOADED this and storageid are
+ interesting for directory based
+ lookups
+ PTPOBJECT_STORAGEID_LOADED and can be filled out by directory
+ loading
+
+ * void ptp_objects_sort (PTPParams *params);
+ Sort the objects list if you did any modification of your own
+ on it and the order of object handles might not be linear
+ anymore.
+
+ - Multiple object information loading strategies are possible.
+ libmtp uses getobjecthandles() /getobjectinfo() and
+ getobjectproplist() loading strategies for initial setup. This
+ stays of course, it will just fill out the PTPObject array.
+
+ libgphoto2 now uses a per-directory getobjecthandles() /
+ getobjectinfo() loading approach, and I will readd the
+ getobjectproplist() approach.
+
+ It is open what you chose to use here. For libmtp the "load all
+ handles at startup" is good, dynamic loading is better for
+ libgphoto2.
+
+ Only rule is: The objectlist must be in order of objecthandles!
+ (ptp_object_sort()).
+
2009-06-02 Linus Walleij <triad@df.lth.se>
* examples/hotplug.c: change the udev match rule from
@@ -5,7 +86,7 @@
Alan Jenkins, this should be faster.
* src/libusb-glue.c: include config.h (Marcus Meissner found
this is needed when you're not using iconv().)
-
+
2009-05-09 Linus Walleij <triad@df.lth.se>
* src/libmtp.c: include <config.h> for iconv() compatibility.
@@ -33,7 +114,7 @@
and for some unknown reason it loops forever when executing
"examples/hotplug > libmtp.usermap". But hopefully the
simple "make" completes without errors.
-
+
* configure.ac:
* iconv is now detected with autotools, this makes libmtp
linkable on cygwin too (previously it was not).
diff --git a/INSTALL b/INSTALL
index fc67dd8..86d8345 100644
--- a/INSTALL
+++ b/INSTALL
@@ -17,15 +17,24 @@ help you get used to using the libmtp API, as well as provide some
immediate gratification. Links to other programs using the libmtp
API may be found at the homepage: http://libmtp.sourceforge.net/
+
Install From Distribution
-------------------------
You should probably prefer to install libmtp from the distribution
source you're using. Last time we checked, libmtp was part of Ubuntu,
-Fedora, OpenSUSE, Debian testing, Gentoo, FreeBSD ports and OpenBSD
+Fedora, OpenSUSE, Debian testing, Gentoo, FreeBSD ports and OpenBSD
packages/ports.
+Dependencies
+------------
+
+To build libmtp you should only need development files for libusb.
+(Often named libusb-devel or similar.) For working with CVS versions
+you may need autoconf, automake, libtool, gettext(-devel).
+
+
Shared Library Support
----------------------
@@ -36,8 +45,8 @@ libmtp install directory to your shared library search path.
On Linux, you would add the line "/usr/local/lib" to your
"/etc/ld.so.conf" or as a oneliner in for example a
"/etc/ld.so.conf.d/local.conf" file and run the
-program "ldconfig" to scan in the shared libraries at
-the new path. This is a part of the Linux shared library
+program "ldconfig" to scan in the shared libraries at
+the new path. This is a part of the Linux shared library
loader actually.
To access the library from real odd locations you can use
@@ -57,8 +66,8 @@ here: http://www.visi.com/~barr/ldpath.html
The shared library comes with different interface version numbers,
for example libmtp.so.4, libmtp.so.5 and so forth. This is used so
that both old and new libmtp libraries shall be able to coexist on
-the same system. When you compile your programs they will typically
-bind to the latest version of the shared library. A link to the
+the same system. When you compile your programs they will typically
+bind to the latest version of the shared library. A link to the
latest version is always provided as $PREFIX/lib/libmtp.so.
libusb Support
diff --git a/configure.ac b/configure.ac
index 725b371..7c4d2f3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,7 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.52)
AC_INIT([libmtp], [0.3.7], [libmtp-discuss@lists.sourceforge.net])
+AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_SRCDIR([src/libmtp.c])
AM_CONFIG_HEADER(config.h)
@@ -17,8 +18,8 @@ AC_PROG_INSTALL
AC_PROG_LN_S
AC_LIBTOOL_WIN32_DLL
AC_PROG_LIBTOOL
-AM_ICONV
-
+AM_ICONV
+
# Check for doxygen
AC_CHECK_PROG(HAVE_DOXYGEN, doxygen, true, false)
AM_CONDITIONAL(HAVE_DOXYGEN,$HAVE_DOXYGEN)
diff --git a/src/device-flags.h b/src/device-flags.h
index b08d28d..5a71aa8 100644
--- a/src/device-flags.h
+++ b/src/device-flags.h
@@ -206,3 +206,37 @@
* level.
*/
#define DEVICE_FLAG_BROKEN_BATTERY_LEVEL 0x00010000
+
+/**
+ * Devices that send "ObjectDeleted" events after deletion
+ * of images. (libgphoto2)
+ */
+#define DEVICE_FLAG_DELETE_SENDS_EVENT 0x00020000
+
+/**
+ * Cameras that can capture images. (libgphoto2)
+ */
+#define DEVICE_FLAG_CAPTURE 0x00040000
+
+/**
+ * Cameras that can capture images. (libgphoto2)
+ */
+#define DEVICE_FLAG_CAPTURE_PREVIEW 0x00080000
+
+/**
+ * Nikon broken capture support without proper ObjectAdded events.
+ * (libgphoto2)
+ */
+#define DEVICE_FLAG_NIKON_BROKEN_CAPTURE 0x00100000
+
+/**
+ * Broken capture support where cameras do not send CaptureComplete events.
+ * (libgphoto2)
+ */
+#define DEVICE_FLAG_NO_CAPTURE_COMPLETE 0x00400000
+
+/**
+ * Direct PTP match required.
+ * (libgphoto2)
+ */
+#define DEVICE_FLAG_MATCH_PTP_INTERFACE 0x00800000
diff --git a/src/libmtp.c b/src/libmtp.c
index 03dc950..2eb217a 100644
--- a/src/libmtp.c
+++ b/src/libmtp.c
@@ -112,7 +112,6 @@ static void add_ptp_error_to_errorstack(LIBMTP_mtpdevice_t *device,
static void flush_handles(LIBMTP_mtpdevice_t *device);
static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
PTPParams *params,
- PTPObjectHandles *handles,
uint32_t storageid,
uint32_t parent);
static void free_storage_list(LIBMTP_mtpdevice_t *device);
@@ -1241,21 +1240,18 @@ static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const o
char *retstring = NULL;
PTPParams *params = (PTPParams *) device->params;
uint16_t ret;
+ MTPProperties *prop;
if ( device == NULL || object_id == 0) {
return NULL;
}
- // This O(n) search should not be used so often, since code
- // using the cached properties don't usually call this function.
- if (params->props) {
- MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
- if (prop) {
- if (prop->propval.str != NULL)
- return strdup(prop->propval.str);
- else
- return NULL;
- }
+ prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
+ if (prop) {
+ if (prop->propval.str != NULL)
+ return strdup(prop->propval.str);
+ else
+ return NULL;
}
ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);
@@ -1287,18 +1283,15 @@ static uint64_t get_u64_from_object(LIBMTP_mtpdevice_t *device,uint32_t const ob
uint64_t retval = value_default;
PTPParams *params = (PTPParams *) device->params;
uint16_t ret;
+ MTPProperties *prop;
if ( device == NULL ) {
return value_default;
}
- // This O(n) search should not be used so often, since code
- // using the cached properties don't usually call this function.
- if (params->props) {
- MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
- if (prop)
- return prop->propval.u64;
- }
+ prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
+ if (prop)
+ return prop->propval.u64;
ret = ptp_mtp_getobjectpropvalue(params, object_id,
attribute_id,
@@ -1329,18 +1322,15 @@ static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const ob
uint32_t retval = value_default;
PTPParams *params = (PTPParams *) device->params;
uint16_t ret;
+ MTPProperties *prop;
if ( device == NULL ) {
return value_default;
}
- // This O(n) search should not be used so often, since code
- // using the cached properties don't usually call this function.
- if (params->props) {
- MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
- if (prop)
- return prop->propval.u32;
- }
+ prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
+ if (prop)
+ return prop->propval.u32;
ret = ptp_mtp_getobjectpropvalue(params, object_id,
attribute_id,
@@ -1351,7 +1341,6 @@ static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const ob
} else {
add_ptp_error_to_errorstack(device, ret, "get_u32_from_object(): could not get unsigned 32bit integer from object.");
}
-
return retval;
}
@@ -1371,6 +1360,7 @@ static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const o
uint16_t retval = value_default;
PTPParams *params = (PTPParams *) device->params;
uint16_t ret;
+ MTPProperties *prop;
if ( device == NULL ) {
return value_default;
@@ -1378,11 +1368,9 @@ static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const o
// This O(n) search should not be used so often, since code
// using the cached properties don't usually call this function.
- if (params->props) {
- MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
- if (prop)
- return prop->propval.u16;
- }
+ prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
+ if (prop)
+ return prop->propval.u16;
ret = ptp_mtp_getobjectpropvalue(params, object_id,
attribute_id,
@@ -1413,6 +1401,7 @@ static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const obj
uint8_t retval = value_default;
PTPParams *params = (PTPParams *) device->params;
uint16_t ret;
+ MTPProperties *prop;
if ( device == NULL ) {
return value_default;
@@ -1420,11 +1409,9 @@ static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const obj
// This O(n) search should not be used so often, since code
// using the cached properties don't usually call this function.
- if (params->props) {
- MTPProperties *prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
- if (prop)
- return prop->propval.u8;
- }
+ prop = ptp_find_object_prop_in_cache(params, object_id, attribute_id);
+ if (prop)
+ return prop->propval.u8;
ret = ptp_mtp_getobjectpropvalue(params, object_id,
attribute_id,
@@ -1691,15 +1678,16 @@ LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device(LIBMTP_raw_device_t *rawdevice)
return NULL;
}
memset(current_params, 0, sizeof(PTPParams));
+ current_params->device_flags = rawdevice->device_entry.device_flags;
+ current_params->nrofobjects = 0;
+ current_params->objects = NULL;
+ current_params->response_packet_size = 0;
+ current_params->response_packet = NULL;
/* This will be a pointer to PTP_USB later */
current_params->data = NULL;
/* Set upp local debug and error functions */
current_params->debug_func = LIBMTP_ptp_debug;
current_params->error_func = LIBMTP_ptp_error;
- /* Clear all handlers */
- current_params->handles.Handler = NULL;
- current_params->objectinfo = NULL;
- current_params->props = NULL;
/* TODO: Will this always be little endian? */
current_params->byteorder = PTP_DL_LE;
current_params->cd_locale_to_ucs2 = iconv_open("UCS-2LE", "UTF-8");
@@ -2161,9 +2149,6 @@ static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device,
"inconsistent results.");
return -1;
}
- params->props = props; /* cache it */
- params->nrofprops = nrofprops; /* cache it */
-
/*
* We count the number of objects by counting the ObjectHandle
* references, whenever it changes we get a new object, when it's
@@ -2178,57 +2163,63 @@ static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device,
prop++;
}
lasthandle = 0xffffffff;
- params->objectinfo = malloc (sizeof (PTPObjectInfo) * cnt);
- memset (params->objectinfo, 0, sizeof(PTPObjectInfo) * cnt);
- params->handles.Handler = malloc (sizeof (uint32_t) * cnt);
- params->handles.n = cnt;
-
+ params->objects = calloc (sizeof(PTPObject),cnt);
prop = props;
i = -1;
for (j=0;j<nrofprops;j++) {
if (lasthandle != prop->ObjectHandle) {
if (i >= 0) {
- if (!params->objectinfo[i].Filename) {
+ params->objects[i].flags |= PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_OBJECTINFO_LOADED;
+ if (!params->objects[i].oi.Filename) {
/* I have one such file on my Creative (Marcus) */
- params->objectinfo[i].Filename = strdup("<null>");
+ params->objects[i].oi.Filename = strdup("<null>");
}
}
i++;
lasthandle = prop->ObjectHandle;
- params->handles.Handler[i] = prop->ObjectHandle;
+ params->objects[i].oid = prop->ObjectHandle;
}
switch (prop->property) {
case PTP_OPC_ParentObject:
- params->objectinfo[i].ParentObject = prop->propval.u32;
+ params->objects[i].oi.ParentObject = prop->propval.u32;
+ params->objects[i].flags |= PTPOBJECT_PARENTOBJECT_LOADED;
break;
case PTP_OPC_ObjectFormat:
- params->objectinfo[i].ObjectFormat = prop->propval.u16;
+ params->objects[i].oi.ObjectFormat = prop->propval.u16;
break;
case PTP_OPC_ObjectSize:
// We loose precision here, up to 32 bits! However the commands that
// retrieve metadata for files and tracks will make sure that the
// PTP_OPC_ObjectSize is read in and duplicated again.
if (device->object_bitsize == 64) {
- params->objectinfo[i].ObjectCompressedSize = (uint32_t) prop->propval.u64;
+ params->objects[i].oi.ObjectCompressedSize = (uint32_t) prop->propval.u64;
} else {
- params->objectinfo[i].ObjectCompressedSize = prop->propval.u32;
+ params->objects[i].oi.ObjectCompressedSize = prop->propval.u32;
}
break;
case PTP_OPC_StorageID:
- params->objectinfo[i].StorageID = prop->propval.u32;
+ params->objects[i].oi.StorageID = prop->propval.u32;
+ params->objects[i].flags |= PTPOBJECT_STORAGEID_LOADED;
break;
case PTP_OPC_ObjectFileName:
if (prop->propval.str != NULL)
- params->objectinfo[i].Filename = strdup(prop->propval.str);
+ params->objects[i].oi.Filename = strdup(prop->propval.str);
break;
- default:
- /*
- * This was in libgphoto2 no idea what it tests for...
- * if ((prop->property & 0xfff0) == 0xdc00)
- * gp_log (GP_LOG_DEBUG, "ptp2/mtpfast", "case %x type %x unhandled.\n", prop->property, prop->datatype);
- */
+ default: {
+ MTPProperties *newprops;
+
+ /* Copy all of the other MTP oprierties into the per-object proplist */
+ if (params->objects[i].nrofmtpprops) {
+ newprops = realloc(params->objects[i].mtpprops,(params->objects[i].nrofmtpprops+1)*sizeof(MTPProperties));
+ } else {
+ newprops = calloc(sizeof(MTPProperties),1);
+ }
+ if (!newprops) return 0; /* FIXME: error handling? */
+ params->objects[i].mtpprops = newprops;
+ memcpy(&params->objects[i].mtpprops[params->objects[i].nrofmtpprops],&props[j],sizeof(props[j]));
+ params->objects[i].nrofmtpprops++;
break;
- // FIXME: the rest of the metadata is readily available right here!
+ }
}
prop++;
}
@@ -2244,14 +2235,11 @@ static int get_all_metadata_fast(LIBMTP_mtpdevice_t *device,
*/
static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
PTPParams *params,
- PTPObjectHandles *handles,
uint32_t storageid,
uint32_t parent)
{
PTPObjectHandles currentHandles;
int i = 0;
- uint32_t old_handles;
-
uint16_t ret = ptp_getobjecthandles(params,
storageid,
PTP_GOH_ALL_FORMATS,
@@ -2266,40 +2254,19 @@ static void get_handles_recursively(LIBMTP_mtpdevice_t *device,
if (currentHandles.Handler == NULL || currentHandles.n == 0)
return;
- old_handles = handles->n;
-
- // Realloc main space
- handles->Handler = (uint32_t *) realloc(handles->Handler,
- (old_handles + currentHandles.n) * sizeof(uint32_t));
- // Realloc object info cache
- params->objectinfo = (PTPObjectInfo*) realloc(params->objectinfo,
- (old_handles + currentHandles.n) * sizeof(PTPObjectInfo));
- memset(&params->objectinfo[old_handles], 0, currentHandles.n * sizeof(PTPObjectInfo));
-
- // Copy new handles
- memmove(&(handles->Handler[old_handles]), currentHandles.Handler, currentHandles.n * sizeof(uint32_t));
- handles->n = old_handles + currentHandles.n;
-
// Now descend into any subdirectories found
for (i = 0; i < currentHandles.n; i++) {
- ret = ptp_getobjectinfo(params,
- currentHandles.Handler[i],
- &params->objectinfo[old_handles + i]);
-
+ PTPObject *ob;
+ ret = ptp_object_want(params,currentHandles.Handler[i],PTPOBJECT_OBJECTINFO_LOADED, &ob);
if (ret == PTP_RC_OK) {
- PTPObjectInfo *oi;
-
- oi = &params->objectinfo[old_handles + i];
- if (oi->ObjectFormat == PTP_OFC_Association) {
- get_handles_recursively(device, params, handles, storageid, currentHandles.Handler[i]);
- }
+ if (ob->oi.ObjectFormat == PTP_OFC_Association)
+ get_handles_recursively(device, params, storageid, currentHandles.Handler[i]);
} else {
add_error_to_errorstack(device,
LIBMTP_ERROR_CONNECTING,
"Found a bad handle, trying to ignore it.");
}
}
-
free(currentHandles.Handler);
}
@@ -2317,23 +2284,13 @@ static void flush_handles(LIBMTP_mtpdevice_t *device)
int ret;
uint32_t i;
- if (params->handles.Handler != NULL) {
- free(params->handles.Handler);
- }
- if (params->objectinfo != NULL) {
- for (i=0;i<params->handles.n;i++)
- ptp_free_objectinfo (&params->objectinfo[i]);
- free(params->objectinfo);
- }
- if (params->props != NULL) {
- ptp_destroy_object_prop_list(params->props, params->nrofprops);
+ if (params->objects != NULL) {
+ for (i=0;i<params->nrofobjects;i++)
+ ptp_free_object (&params->objects[i]);
+ free(params->objects);
+ params->objects = NULL;
+ params->nrofobjects = 0;
}
-
- params->handles.n = 0;
- params->handles.Handler = NULL;
- params->objectinfo = NULL;
- params->props = NULL;
- params->nrofprops = 0;
if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
&& !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)
@@ -2343,11 +2300,10 @@ static void flush_handles(LIBMTP_mtpdevice_t *device)
}
// If the previous failed or returned no objects, use classic
// methods instead.
- if (params->props == NULL) {
+ if (params->nrofobjects == 0) {
// Get all the handles using just standard commands.
if (device->storage == NULL) {
get_handles_recursively(device, params,
- &params->handles,
PTP_GOH_ALL_STORAGE,
PTP_GOH_ROOT_PARENT);
} else {
@@ -2355,7 +2311,6 @@ static void flush_handles(LIBMTP_mtpdevice_t *device)
LIBMTP_devicestorage_t *storage = device->storage;
while(storage != NULL) {
get_handles_recursively(device, params,
- &params->handles,
storage->id,
PTP_GOH_ROOT_PARENT);
storage = storage->next;
@@ -2368,67 +2323,61 @@ static void flush_handles(LIBMTP_mtpdevice_t *device)
* keywords, then attempt to locate some default folders
* in the root directory of the primary storage.
*/
- for(i = 0; i < params->handles.n; i++) {
- PTPObjectInfo *oi;
-
- oi = &params->objectinfo[i];
- if (oi->Filename == NULL) {
- oi->Filename = strdup("<null>");
- }
- if (oi->Keywords == NULL) {
- oi->Keywords = strdup("<null>");
+ for(i = 0; i < params->nrofobjects; i++) {
+ PTPObject *ob, *xob;
+
+ ob = &params->objects[i];
+ ret = ptp_object_want(params,params->objects[i].oid,PTPOBJECT_OBJECTINFO_LOADED, &xob);
+ if (ret != PTP_RC_OK) {
+ fprintf(stderr,"broken! %x not found\n", params->objects[i].oid);
}
-
+ if (ob->oi.Filename == NULL)
+ ob->oi.Filename = strdup("<null>");
+ if (ob->oi.Keywords == NULL)
+ ob->oi.Keywords = strdup("<null>");
+
/* Ignore handles that point to non-folders */
- if(oi->ObjectFormat != PTP_OFC_Association)
+ if(ob->oi.ObjectFormat != PTP_OFC_Association)
continue;
/* Only look in the root folder */
- if (oi->ParentObject != 0x00000000U)
+ if (ob->oi.ParentObject != 0x00000000U)
continue;
/* Only look in the primary storage */
- if (device->storage != NULL && oi->StorageID != device->storage->id)
+ if (device->storage != NULL && ob->oi.StorageID != device->storage->id)
continue;
/* Is this the Music Folder */
- if (!strcasecmp(oi->Filename, "My Music") ||
- !strcasecmp(oi->Filename, "Music")) {
- device->default_music_folder =
- params->handles.Handler[i];
+ if (!strcasecmp(ob->oi.Filename, "My Music") ||
+ !strcasecmp(ob->oi.Filename, "Music")) {
+ device->default_music_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "My Playlists") ||
- !strcasecmp(oi->Filename, "Playlists")) {
- device->default_playlist_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "My Playlists") ||
+ !strcasecmp(ob->oi.Filename, "Playlists")) {
+ device->default_playlist_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "My Pictures") ||
- !strcasecmp(oi->Filename, "Pictures")) {
- device->default_picture_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "My Pictures") ||
+ !strcasecmp(ob->oi.Filename, "Pictures")) {
+ device->default_picture_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "My Video") ||
- !strcasecmp(oi->Filename, "Video")) {
- device->default_video_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "My Video") ||
+ !strcasecmp(ob->oi.Filename, "Video")) {
+ device->default_video_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "My Organizer")) {
- device->default_organizer_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "My Organizer")) {
+ device->default_organizer_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "ZENcast") ||
- !strcasecmp(oi->Filename, "Datacasts")) {
- device->default_zencast_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "ZENcast") ||
+ !strcasecmp(ob->oi.Filename, "Datacasts")) {
+ device->default_zencast_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "My Albums") ||
- !strcasecmp(oi->Filename, "Albums")) {
- device->default_album_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "My Albums") ||
+ !strcasecmp(ob->oi.Filename, "Albums")) {
+ device->default_album_folder = ob->oid;
}
- else if (!strcasecmp(oi->Filename, "Text") ||
- !strcasecmp(oi->Filename, "Texts")) {
- device->default_text_folder =
- params->handles.Handler[i];
+ else if (!strcasecmp(ob->oi.Filename, "Text") ||
+ !strcasecmp(ob->oi.Filename, "Texts")) {
+ device->default_text_folder = ob->oid;
}
}
}
@@ -3697,20 +3646,20 @@ LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
uint16_t ret;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
+ for (i = 0; i < params->nrofobjects; i++) {
LIBMTP_file_t *file;
- PTPObjectInfo *oi;
+ PTPObject *ob, *xob;
if (callback != NULL)
- callback(i, params->handles.n, data);
+ callback(i, params->nrofobjects, data);
- oi = &params->objectinfo[i];
+ ob = &params->objects[i];
- if (oi->ObjectFormat == PTP_OFC_Association) {
+ if (ob->oi.ObjectFormat == PTP_OFC_Association) {
// MTP use this object format for folders which means
// these "files" will turn up on a folder listing instead.
continue;
@@ -3719,24 +3668,24 @@ LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
// Allocate a new file type
file = LIBMTP_new_file_t();
- file->parent_id = oi->ParentObject;
- file->storage_id = oi->StorageID;
+ file->parent_id = ob->oi.ParentObject;
+ file->storage_id = ob->oi.StorageID;
// This is some sort of unique ID so we can keep track of the track.
- file->item_id = params->handles.Handler[i];
+ file->item_id = ob->oid;
// Set the filetype
- file->filetype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
+ file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
// Set the modification date
- file->modificationdate = oi->ModificationDate;
+ file->modificationdate = ob->oi.ModificationDate;
// Original file-specific properties
// We only have 32-bit file size here; if we find it, we use the
// PTP_OPC_ObjectSize property which has 64bit precision.
- file->filesize = oi->ObjectCompressedSize;
- if (oi->Filename != NULL) {
- file->filename = strdup(oi->Filename);
+ file->filesize = ob->oi.ObjectCompressedSize;
+ if (ob->oi.Filename != NULL) {
+ file->filename = strdup(ob->oi.Filename);
}
/*
@@ -3760,16 +3709,12 @@ LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
/*
* If we have a cached, large set of metadata, then use it!
*/
- if (params->props) {
- MTPProperties *prop = params->props;
+ ret = ptp_object_want (params, ob->oid, PTPOBJECT_MTPPROPLIST_LOADED, &xob);
+ if (ob->mtpprops) {
+ MTPProperties *prop = ob->mtpprops;
int i;
-
- for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != file->item_id);i++,prop++)
- /*empty*/;
- for (;i<params->nrofprops;i++) {
- if (prop->ObjectHandle != file->item_id)
- break;
+ for (i=0;i<ob->nrofmtpprops;i++) {
// Pick ObjectSize here...
if (prop->property == PTP_OPC_ObjectSize) {
if (device->object_bitsize == 64) {
@@ -3779,57 +3724,14 @@ LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
}
break;
}
- prop ++;
- }
- } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
- && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
- MTPProperties *props = NULL;
- MTPProperties *prop;
-
- int nrofprops;
-
- /*
- * This should retrieve all properties for an object, but on devices
- * which are inherently broken it will not, so these need the
- * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
- */
- ret = ptp_mtp_getobjectproplist(params, file->item_id, &props, &nrofprops);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): call to ptp_mtp_getobjectproplist() failed.");
- // Silently fall through.
- }
- if (props == NULL && nrofprops != 0) {
- add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
- "LIBMTP_Get_Filelisting_With_Callback: "
- "call to ptp_mtp_getobjectproplist() returned "
- "inconsistent results.");
- nrofprops = 0;
- }
- if (props != NULL) {
- int i;
- prop = props;
- for (i=0;i<nrofprops;i++) {
- if (prop->ObjectHandle != file->item_id)
- break;
- // Pick ObjectSize here...
- if (prop->property == PTP_OPC_ObjectSize) {
- if (device->object_bitsize == 64) {
- file->filesize = prop->propval.u64;
- } else {
- file->filesize = prop->propval.u32;
- }
- break;
- }
- prop ++;
- }
- ptp_destroy_object_prop_list(props, nrofprops);
+ prop++;
}
} else {
uint16_t *props = NULL;
uint32_t propcnt = 0;
// First see which properties can be retrieved for this object format
- ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
+ ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
if (ret != PTP_RC_OK) {
add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): call to ptp_mtp_getobjectpropssupported() failed.");
// Silently fall through.
@@ -3890,136 +3792,86 @@ LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t cons
{
uint32_t i = 0;
PTPParams *params = (PTPParams *) device->params;
- PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
uint16_t ret;
+ PTPObject *ob;
+ LIBMTP_file_t *file;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
- LIBMTP_file_t *file;
- PTPObjectInfo *oi;
+ ret = ptp_object_want (params, fileid, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
+ if (ret != PTP_RC_OK)
+ return NULL;
- // Is this the file we're looking for?
- if (params->handles.Handler[i] != fileid) {
- continue;
- }
+ // Allocate a new file type
+ file = LIBMTP_new_file_t();
+
+ file->parent_id = ob->oi.ParentObject;
+ file->storage_id = ob->oi.StorageID;
- oi = &params->objectinfo[i];
+ // Set the filetype
+ file->filetype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
- // Allocate a new file type
- file = LIBMTP_new_file_t();
-
- file->parent_id = oi->ParentObject;
- file->storage_id = oi->StorageID;
+ // Original file-specific properties
+
+ // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
+ file->filesize = ob->oi.ObjectCompressedSize;
+ if (ob->oi.Filename != NULL) {
+ file->filename = strdup(ob->oi.Filename);
+ }
- // Set the filetype
- file->filetype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
+ // This is some sort of unique ID so we can keep track of the file.
+ file->item_id = fileid;
- // Original file-specific properties
+ /*
+ * If we have a cached, large set of metadata, then use it!
+ */
+ if (ob->mtpprops) {
+ MTPProperties *prop = ob->mtpprops;
- // We only have 32-bit file size here; later we use the PTP_OPC_ObjectSize property
- file->filesize = oi->ObjectCompressedSize;
- if (oi->Filename != NULL) {
- file->filename = strdup(oi->Filename);
- }
-
- // This is some sort of unique ID so we can keep track of the file.
- file->item_id = params->handles.Handler[i];
-
- /*
- * If we have a cached, large set of metadata, then use it!
- */
- if (params->props) {
- MTPProperties *prop = params->props;
-
- for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != file->item_id);i++,prop++)
- /*empty*/;
- for (;(i<params->nrofprops) && (prop->ObjectHandle == file->item_id);i++,prop++) {
- // Pick ObjectSize here...
- if (prop->property == PTP_OPC_ObjectSize) {
- // This may already be set, but this 64bit precision value
- // is better than the PTP 32bit value, so let it override.
- if (device->object_bitsize == 64) {
- file->filesize = prop->propval.u64;
- } else {
- file->filesize = prop->propval.u32;
- }
- break;
+ for (i=0;i<ob->nrofmtpprops;i++,prop++) {
+ // Pick ObjectSize here...
+ if (prop->property == PTP_OPC_ObjectSize) {
+ // This may already be set, but this 64bit precision value
+ // is better than the PTP 32bit value, so let it override.
+ if (device->object_bitsize == 64) {
+ file->filesize = prop->propval.u64;
+ } else {
+ file->filesize = prop->propval.u32;
}
+ break;
}
- } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
- && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
- MTPProperties *props = NULL;
- MTPProperties *prop;
- int nrofprops;
-
- /*
- * This should retrieve all properties for an object, but on devices
- * which are inherently broken it will not, so these need the
- * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
- */
- ret = ptp_mtp_getobjectproplist(params, file->item_id, &props, &nrofprops);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filelisting_With_Callback(): "
- "call to ptp_mtp_getobjectproplist() failed.");
- // Silently fall through.
- }
- if (props == NULL && nrofprops != 0) {
- add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
- "LIBMTP_Get_Filelisting_With_Callback(): "
- "call to ptp_mtp_getobjectproplist() returned "
- "inconsistent results.");
- return NULL;
- }
- prop = props;
- for (i=0;i<nrofprops;i++) {
- if ((prop->ObjectHandle == file->item_id) && (prop->property == PTP_OPC_ObjectSize)) {
- // This may already be set, but this 64bit precision value
- // is better than the PTP 32bit value, so let it override.
+ }
+ } else {
+ uint16_t *props = NULL;
+ uint32_t propcnt = 0;
+
+ // First see which properties can be retrieved for this object format
+ ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
+ if (ret != PTP_RC_OK) {
+ add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filemetadata(): call to ptp_mtp_getobjectpropssupported() failed.");
+ // Silently fall through.
+ } else {
+ for (i=0;i<propcnt;i++) {
+ switch (props[i]) {
+ case PTP_OPC_ObjectSize:
if (device->object_bitsize == 64) {
- file->filesize = prop->propval.u64;
+ file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
} else {
- file->filesize = prop->propval.u32;
+ file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
}
break;
+ default:
+ break;
}
- prop ++;
- }
- ptp_destroy_object_prop_list(props, nrofprops);
- } else {
- uint16_t *props = NULL;
- uint32_t propcnt = 0;
-
- // First see which properties can be retrieved for this object format
- ret = ptp_mtp_getobjectpropssupported(params, map_libmtp_type_to_ptp_type(file->filetype), &propcnt, &props);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Filemetadata(): call to ptp_mtp_getobjectpropssupported() failed.");
- // Silently fall through.
- } else {
- for (i=0;i<propcnt;i++) {
- switch (props[i]) {
- case PTP_OPC_ObjectSize:
- if (device->object_bitsize == 64) {
- file->filesize = get_u64_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
- } else {
- file->filesize = get_u32_from_object(device, file->item_id, PTP_OPC_ObjectSize, 0);
- }
- break;
- default:
- break;
- }
- }
- free(props);
}
+ free(props);
}
-
- return file;
-
}
- return NULL;
+
+ return file;
}
/**
@@ -4196,49 +4048,18 @@ static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat
{
uint16_t ret;
PTPParams *params = (PTPParams *) device->params;
- PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
uint32_t i;
+ MTPProperties *prop;
+ PTPObject *ob;
/*
* If we have a cached, large set of metadata, then use it!
*/
- if (params->props) {
- MTPProperties *prop = params->props;
-
- for (i=0;(i<params->nrofprops) && (prop->ObjectHandle != track->item_id);i++,prop++)
- /*empty*/;
- for (i=0;(i<params->nrofprops) && (prop->ObjectHandle == track->item_id);i++,prop++) {
+ ret = ptp_object_want (params, track->item_id, PTPOBJECT_MTPPROPLIST_LOADED, &ob);
+ if (ob->mtpprops) {
+ prop = ob->mtpprops;
+ for (i=0;i<ob->nrofmtpprops;i++,prop++)
pick_property_to_track_metadata(device, prop, track);
- }
- } else if (ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)
- && !FLAG_BROKEN_MTPGETOBJPROPLIST(ptp_usb)) {
- MTPProperties *props = NULL;
- MTPProperties *prop;
- int nrofprops;
-
- /*
- * This should retrieve all properties for an object, but on devices
- * which are inherently broken it will not, so these need the
- * special flag DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST.
- */
- ret = ptp_mtp_getobjectproplist(params, track->item_id, &props, &nrofprops);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "get_track_metadata(): call to ptp_mtp_getobjectproplist() failed.");
- return;
- }
- if (props == NULL && nrofprops != 0) {
- add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL,
- "get_track_metadata(): "
- "call to ptp_mtp_getobjectproplist() returned "
- "inconsistent results.");
- return;
- }
- prop = props;
- for (i=0;i<nrofprops;i++,prop++) {
- if (prop->ObjectHandle == track->item_id)
- pick_property_to_track_metadata(device, prop, track);
- }
- ptp_destroy_object_prop_list(props, nrofprops);
} else {
uint16_t *props = NULL;
uint32_t propcnt = 0;
@@ -4376,20 +4197,20 @@ LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
+ for (i = 0; i < params->nrofobjects; i++) {
LIBMTP_track_t *track;
- PTPObjectInfo *oi;
+ PTPObject *ob;
LIBMTP_filetype_t mtptype;
if (callback != NULL)
- callback(i, params->handles.n, data);
+ callback(i, params->nrofobjects, data);
- oi = &params->objectinfo[i];
- mtptype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
+ ob = &params->objects[i];
+ mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
// Ignore stuff we don't know how to handle...
// TODO: get this list as an intersection of the sets
@@ -4397,7 +4218,7 @@ LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device
// all known track files?
if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
// This row lets through undefined files for examination since they may be forgotten OGG files.
- (oi->ObjectFormat != PTP_OFC_Undefined ||
+ (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
(!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
!FLAG_OGG_IS_UNKNOWN(ptp_usb)))
) {
@@ -4409,20 +4230,20 @@ LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device
track = LIBMTP_new_track_t();
// This is some sort of unique ID so we can keep track of the track.
- track->item_id = params->handles.Handler[i];
- track->parent_id = oi->ParentObject;
- track->storage_id = oi->StorageID;
- track->modificationdate = oi->ModificationDate;
+ track->item_id = ob->oid;
+ track->parent_id = ob->oi.ParentObject;
+ track->storage_id = ob->oi.StorageID;
+ track->modificationdate = ob->oi.ModificationDate;
track->filetype = mtptype;
// Original file-specific properties
- track->filesize = oi->ObjectCompressedSize;
- if (oi->Filename != NULL) {
- track->filename = strdup(oi->Filename);
+ track->filesize = ob->oi.ObjectCompressedSize;
+ if (ob->oi.Filename != NULL) {
+ track->filename = strdup(ob->oi.Filename);
}
- get_track_metadata(device, oi->ObjectFormat, track);
+ get_track_metadata(device, ob->oi.ObjectFormat, track);
/*
* A special quirk for iriver devices that doesn't quite
@@ -4479,83 +4300,73 @@ LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device
*/
LIBMTP_track_t *LIBMTP_Get_Trackmetadata(LIBMTP_mtpdevice_t *device, uint32_t const trackid)
{
- uint32_t i = 0;
PTPParams *params = (PTPParams *) device->params;
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
+ PTPObject *ob;
+ LIBMTP_track_t *track;
+ LIBMTP_filetype_t mtptype;
+ uint16_t ret;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0)
flush_handles(device);
- }
-
- for (i = 0; i < params->handles.n; i++) {
- PTPObjectInfo *oi;
- LIBMTP_track_t *track;
- LIBMTP_filetype_t mtptype;
- // Skip if this is not the track we want.
- if (params->handles.Handler[i] != trackid) {
- continue;
- }
+ ret = ptp_object_want (params, trackid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK)
+ return NULL;
- oi = &params->objectinfo[i];
- mtptype = map_ptp_type_to_libmtp_type(oi->ObjectFormat);
+ mtptype = map_ptp_type_to_libmtp_type(ob->oi.ObjectFormat);
- // Ignore stuff we don't know how to handle...
- if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
- // This row lets through undefined files for examination since they may be forgotten OGG files.
- (oi->ObjectFormat != PTP_OFC_Undefined ||
- (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
- !FLAG_OGG_IS_UNKNOWN(ptp_usb)))
- ) {
- //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
- return NULL;
- }
+ // Ignore stuff we don't know how to handle...
+ if (!LIBMTP_FILETYPE_IS_TRACK(mtptype) &&
+ // This row lets through undefined files for examination since they may be forgotten OGG files.
+ (ob->oi.ObjectFormat != PTP_OFC_Undefined ||
+ (!FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) &&
+ !FLAG_OGG_IS_UNKNOWN(ptp_usb)))
+ ) {
+ //printf("Not a music track (name: %s format: %d), skipping...\n", oi->Filename, oi->ObjectFormat);
+ return NULL;
+ }
- // Allocate a new track type
- track = LIBMTP_new_track_t();
-
- // This is some sort of unique ID so we can keep track of the track.
- track->item_id = params->handles.Handler[i];
- track->parent_id = oi->ParentObject;
- track->storage_id = oi->StorageID;
- track->modificationdate = oi->ModificationDate;
+ // Allocate a new track type
+ track = LIBMTP_new_track_t();
+
+ // This is some sort of unique ID so we can keep track of the track.
+ track->item_id = ob->oid;
+ track->parent_id = ob->oi.ParentObject;
+ track->storage_id = ob->oi.StorageID;
+ track->modificationdate = ob->oi.ModificationDate;
- track->filetype = mtptype;
+ track->filetype = mtptype;
- // Original file-specific properties
- track->filesize = oi->ObjectCompressedSize;
- if (oi->Filename != NULL) {
- track->filename = strdup(oi->Filename);
- }
+ // Original file-specific properties
+ track->filesize = ob->oi.ObjectCompressedSize;
+ if (ob->oi.Filename != NULL) {
+ track->filename = strdup(ob->oi.Filename);
+ }
- /*
- * A special quirk for iriver devices that doesn't quite
- * remember that some files marked as "unknown" type are
- * actually OGG files. We look at the filename extension
- * and see if it happens that this was atleast named "ogg"
- * and fall back on this heuristic approach in that case,
- * for these bugged devices only.
- */
- if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
- (FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
- FLAG_OGG_IS_UNKNOWN(ptp_usb))) {
- if (has_ogg_extension(track->filename)) {
- // Fix it.
- track->filetype = LIBMTP_FILETYPE_OGG;
- } else {
- // This was not an OGG file so discard it
- LIBMTP_destroy_track_t(track);
- return NULL;
- }
+ /*
+ * A special quirk for iriver devices that doesn't quite
+ * remember that some files marked as "unknown" type are
+ * actually OGG files. We look at the filename extension
+ * and see if it happens that this was atleast named "ogg"
+ * and fall back on this heuristic approach in that case,
+ * for these bugged devices only.
+ */
+ if (track->filetype == LIBMTP_FILETYPE_UNKNOWN &&
+ (FLAG_IRIVER_OGG_ALZHEIMER(ptp_usb) ||
+ FLAG_OGG_IS_UNKNOWN(ptp_usb))) {
+ if (has_ogg_extension(track->filename)) {
+ // Fix it.
+ track->filetype = LIBMTP_FILETYPE_OGG;
+ } else {
+ // This was not an OGG file so discard it
+ LIBMTP_destroy_track_t(track);
+ return NULL;
}
-
- get_track_metadata(device, oi->ObjectFormat, track);
-
- return track;
-
}
- return NULL;
+ get_track_metadata(device, ob->oi.ObjectFormat, track);
+ return track;
}
/**
@@ -4691,31 +4502,24 @@ int LIBMTP_Get_File_To_File_Descriptor(LIBMTP_mtpdevice_t *device,
LIBMTP_progressfunc_t const callback,
void const * const data)
{
- PTPObjectInfo *oi;
- uint32_t i;
uint16_t ret;
PTPParams *params = (PTPParams *) device->params;
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
+ PTPObject *ob;
- oi = NULL;
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == id) {
- oi = &params->objectinfo[i];
- break;
- }
- }
- if (oi == NULL) {
+ ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
return -1;
}
- if (oi->ObjectFormat == PTP_OFC_Association) {
+ if (ob->oi.ObjectFormat == PTP_OFC_Association) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
return -1;
}
// Callbacks
ptp_usb->callback_active = 1;
- ptp_usb->current_transfer_total = oi->ObjectCompressedSize+
+ ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
ptp_usb->current_transfer_complete = 0;
ptp_usb->current_transfer_callback = callback;
@@ -4763,31 +4567,24 @@ int LIBMTP_Get_File_To_Handler(LIBMTP_mtpdevice_t *device,
LIBMTP_progressfunc_t const callback,
void const * const data)
{
- PTPObjectInfo *oi;
- uint32_t i;
+ PTPObject *ob;
uint16_t ret;
PTPParams *params = (PTPParams *) device->params;
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
- oi = NULL;
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == id) {
- oi = &params->objectinfo[i];
- break;
- }
- }
- if (oi == NULL) {
+ ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Could not get object info.");
return -1;
}
- if (oi->ObjectFormat == PTP_OFC_Association) {
+ if (ob->oi.ObjectFormat == PTP_OFC_Association) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_File_To_File_Descriptor(): Bad object format.");
return -1;
}
// Callbacks
ptp_usb->callback_active = 1;
- ptp_usb->current_transfer_total = oi->ObjectCompressedSize+
+ ptp_usb->current_transfer_total = ob->oi.ObjectCompressedSize+
PTP_USB_BULK_HDR_LEN+sizeof(uint32_t); // Request length, one parameter
ptp_usb->current_transfer_complete = 0;
ptp_usb->current_transfer_callback = callback;
@@ -6439,13 +6236,12 @@ int LIBMTP_Track_Exists(LIBMTP_mtpdevice_t *device,
uint32_t const id)
{
PTPParams *params = (PTPParams *) device->params;
- uint32_t i;
+ uint16_t ret;
+ PTPObject *ob;
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == id) {
+ ret = ptp_object_want (params, id, 0, &ob);
+ if (ret == PTP_RC_OK)
return -1;
- }
- }
return 0;
}
@@ -6587,7 +6383,7 @@ LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
int i;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
@@ -6605,12 +6401,12 @@ LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
*/
head.sibling = &head;
head.child = &head;
- for (i = 0; i < params->handles.n; i++) {
+ for (i = 0; i < params->nrofobjects; i++) {
LIBMTP_folder_t *folder;
- PTPObjectInfo *oi;
+ PTPObject *ob;
- oi = &params->objectinfo[i];
- if (oi->ObjectFormat != PTP_OFC_Association) {
+ ob = &params->objects[i];
+ if (ob->oi.ObjectFormat != PTP_OFC_Association) {
continue;
}
/*
@@ -6621,8 +6417,8 @@ LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
* we basically don't care. Hopefully parent_id is maintained for all
* children, because we rely on that instead.
*/
- if (oi->AssociationDesc != 0x00000000U) {
- printf("MTP extended association type 0x%08x encountered\n", oi->AssociationDesc);
+ if (ob->oi.AssociationDesc != 0x00000000U) {
+ printf("MTP extended association type 0x%08x encountered\n", ob->oi.AssociationDesc);
}
// Create a folder struct...
@@ -6631,10 +6427,10 @@ LIBMTP_folder_t *LIBMTP_Get_Folder_List(LIBMTP_mtpdevice_t *device)
// malloc failure or so.
return NULL;
}
- folder->folder_id = params->handles.Handler[i];
- folder->parent_id = oi->ParentObject;
- folder->storage_id = oi->StorageID;
- folder->name = (oi->Filename) ? (char *)strdup(oi->Filename) : NULL;
+ folder->folder_id = ob->oid;
+ folder->parent_id = ob->oi.ParentObject;
+ folder->storage_id = ob->oi.StorageID;
+ folder->name = (ob->oi.Filename) ? (char *)strdup(ob->oi.Filename) : NULL;
// pretend sibling says next, and child says prev.
folder->sibling = head.sibling;
@@ -6806,27 +6602,27 @@ LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
uint32_t i;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
+ for (i = 0; i < params->nrofobjects; i++) {
LIBMTP_playlist_t *pl;
- PTPObjectInfo *oi;
+ PTPObject *ob;
uint16_t ret;
- oi = &params->objectinfo[i];
+ ob = &params->objects[i];
// Ignore stuff that isn't playlists
// For Samsung players we must look for the .spl extension explicitly since
// playlists are not stored as playlist objects.
- if ( REQ_SPL && is_spl_playlist(oi) ) {
+ if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
// Allocate a new playlist type
pl = LIBMTP_new_playlist_t();
- spl_to_playlist_t(device, oi, params->handles.Handler[i], pl);
+ spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
}
- else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
+ else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
continue;
}
else {
@@ -6834,13 +6630,13 @@ LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
pl = LIBMTP_new_playlist_t();
// Try to look up proper name, else use the oi->Filename field.
- pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
+ pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
if (pl->name == NULL) {
- pl->name = strdup(oi->Filename);
+ pl->name = strdup(ob->oi.Filename);
}
- pl->playlist_id = params->handles.Handler[i];
- pl->parent_id = oi->ParentObject;
- pl->storage_id = oi->StorageID;
+ pl->playlist_id = ob->oid;
+ pl->parent_id = ob->oi.ParentObject;
+ pl->storage_id = ob->oi.StorageID;
// Then get the track listing for this playlist
ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
@@ -6879,60 +6675,53 @@ LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t cons
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
PTPParams *params = (PTPParams *) device->params;
- uint32_t i;
+ PTPObject *ob;
+ LIBMTP_playlist_t *pl;
+ uint16_t ret;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
- LIBMTP_playlist_t *pl;
- PTPObjectInfo *oi;
- uint16_t ret;
-
- if (params->handles.Handler[i] != plid) {
- continue;
- }
-
- oi = &params->objectinfo[i];
-
- // For Samsung players we must look for the .spl extension explicitly since
- // playlists are not stored as playlist objects.
- if ( REQ_SPL && is_spl_playlist(oi) ) {
- // Allocate a new playlist type
- pl = LIBMTP_new_playlist_t();
- spl_to_playlist_t(device, oi, params->handles.Handler[i], pl);
- return pl;
- }
-
- // Ignore stuff that isn't playlists
- else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
- return NULL;
- }
+ ret = ptp_object_want (params, plid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK)
+ return NULL;
+ // For Samsung players we must look for the .spl extension explicitly since
+ // playlists are not stored as playlist objects.
+ if ( REQ_SPL && is_spl_playlist(&ob->oi) ) {
// Allocate a new playlist type
pl = LIBMTP_new_playlist_t();
+ spl_to_playlist_t(device, &ob->oi, ob->oid, pl);
+ return pl;
+ }
- pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
- if (pl->name == NULL) {
- pl->name = strdup(oi->Filename);
- }
- pl->playlist_id = params->handles.Handler[i];
- pl->parent_id = oi->ParentObject;
- pl->storage_id = oi->StorageID;
-
- // Then get the track listing for this playlist
- ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
- pl->tracks = NULL;
- pl->no_tracks = 0;
- }
+ // Ignore stuff that isn't playlists
+ else if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
+ return NULL;
+ }
- return pl;
+ // Allocate a new playlist type
+ pl = LIBMTP_new_playlist_t();
+
+ pl->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
+ if (pl->name == NULL) {
+ pl->name = strdup(ob->oi.Filename);
+ }
+ pl->playlist_id = ob->oid;
+ pl->parent_id = ob->oi.ParentObject;
+ pl->storage_id = ob->oi.StorageID;
+
+ // Then get the track listing for this playlist
+ ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks);
+ if (ret != PTP_RC_OK) {
+ add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist(): Could not get object references.");
+ pl->tracks = NULL;
+ pl->no_tracks = 0;
}
- return NULL;
+
+ return pl;
}
/**
@@ -7645,36 +7434,36 @@ LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
uint32_t i;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
+ for (i = 0; i < params->nrofobjects; i++) {
LIBMTP_album_t *alb;
- PTPObjectInfo *oi;
+ PTPObject *ob;
uint16_t ret;
- oi = &params->objectinfo[i];
+ ob = &params->objects[i];
// Ignore stuff that isn't an album
- if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
+ if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
continue;
}
// Allocate a new album type
alb = LIBMTP_new_album_t();
- alb->album_id = params->handles.Handler[i];
- alb->parent_id = oi->ParentObject;
- alb->storage_id = oi->StorageID;
+ alb->album_id = ob->oid;
+ alb->parent_id = ob->oi.ParentObject;
+ alb->storage_id = ob->oi.StorageID;
// Get metadata for it.
- alb->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
- alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_AlbumArtist);
+ alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
+ alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
if (alb->artist == NULL) {
- alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Artist);
+ alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
}
- alb->composer = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Composer);
- alb->genre = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Genre);
+ alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
+ alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
// Then get the track listing for this album
ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
@@ -7707,53 +7496,46 @@ LIBMTP_album_t *LIBMTP_Get_Album_List(LIBMTP_mtpdevice_t *device)
LIBMTP_album_t *LIBMTP_Get_Album(LIBMTP_mtpdevice_t *device, uint32_t const albid)
{
PTPParams *params = (PTPParams *) device->params;
- uint32_t i;
+ uint16_t ret;
+ PTPObject *ob;
+ LIBMTP_album_t *alb;
// Get all the handles if we haven't already done that
- if (params->handles.Handler == NULL) {
+ if (params->nrofobjects == 0) {
flush_handles(device);
}
- for (i = 0; i < params->handles.n; i++) {
- LIBMTP_album_t *alb;
- PTPObjectInfo *oi;
- uint16_t ret;
-
- if (params->handles.Handler[i] != albid) {
- continue;
- }
-
- oi = &params->objectinfo[i];
+ ret = ptp_object_want (params, albid, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK)
+ return NULL;
- // Ignore stuff that isn't an album
- if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
- return NULL;
- }
+ // Ignore stuff that isn't an album
+ if ( ob->oi.ObjectFormat != PTP_OFC_MTP_AbstractAudioAlbum ) {
+ return NULL;
+ }
- // Allocate a new album type
- alb = LIBMTP_new_album_t();
- alb->album_id = params->handles.Handler[i];
- alb->parent_id = oi->ParentObject;
- alb->storage_id = oi->StorageID;
+ // Allocate a new album type
+ alb = LIBMTP_new_album_t();
+ alb->album_id = ob->oid;
+ alb->parent_id = ob->oi.ParentObject;
+ alb->storage_id = ob->oi.StorageID;
- // Get metadata for it.
- alb->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name);
- alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_AlbumArtist);
- if (alb->artist == NULL) {
- alb->artist = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Artist);
- }
- alb->composer = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Composer);
- alb->genre = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Genre);
- ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
- if (ret != PTP_RC_OK) {
- add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
- alb->tracks = NULL;
- alb->no_tracks = 0;
- }
-
- return alb;
+ // Get metadata for it.
+ alb->name = get_string_from_object(device, ob->oid, PTP_OPC_Name);
+ alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_AlbumArtist);
+ if (alb->artist == NULL) {
+ alb->artist = get_string_from_object(device, ob->oid, PTP_OPC_Artist);
}
- return NULL;
+ alb->composer = get_string_from_object(device, ob->oid, PTP_OPC_Composer);
+ alb->genre = get_string_from_object(device, ob->oid, PTP_OPC_Genre);
+ ret = ptp_mtp_getobjectreferences(params, alb->album_id, &alb->tracks, &alb->no_tracks);
+ if (ret != PTP_RC_OK) {
+ add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Album: Could not get object references.");
+ alb->tracks = NULL;
+ alb->no_tracks = 0;
+ }
+
+ return alb;
}
/**
@@ -8014,28 +7796,21 @@ int LIBMTP_Send_Representative_Sample(LIBMTP_mtpdevice_t *device,
PTPParams *params = (PTPParams *) device->params;
PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
PTPPropertyValue propval;
- PTPObjectInfo *oi;
+ PTPObject *ob;
uint32_t i;
uint16_t *props = NULL;
uint32_t propcnt = 0;
int supported = 0;
// get the file format for the object we're going to send representative data for
- oi = NULL;
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == id) {
- oi = &params->objectinfo[i];
- break;
- }
- }
-
- if (oi == NULL) {
+ ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Send_Representative_Sample(): could not get object info.");
return -1;
}
// check that we can send representative sample data for this object format
- ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
+ ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
if (ret != PTP_RC_OK) {
add_ptp_error_to_errorstack(device, ret, "LIBMTP_Send_Representative_Sample(): could not get object properties.");
return -1;
@@ -8115,28 +7890,21 @@ int LIBMTP_Get_Representative_Sample(LIBMTP_mtpdevice_t *device,
uint16_t ret;
PTPParams *params = (PTPParams *) device->params;
PTPPropertyValue propval;
- PTPObjectInfo *oi;
+ PTPObject *ob;
uint32_t i;
uint16_t *props = NULL;
uint32_t propcnt = 0;
int supported = 0;
// get the file format for the object we're going to send representative data for
- oi = NULL;
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == id) {
- oi = &params->objectinfo[i];
- break;
- }
- }
-
- if (oi == NULL) {
+ ret = ptp_object_want (params, id, PTPOBJECT_OBJECTINFO_LOADED, &ob);
+ if (ret != PTP_RC_OK) {
add_error_to_errorstack(device, LIBMTP_ERROR_GENERAL, "LIBMTP_Get_Representative_Sample(): could not get object info.");
return -1;
}
// check that we can store representative sample data for this object format
- ret = ptp_mtp_getobjectpropssupported(params, oi->ObjectFormat, &propcnt, &props);
+ ret = ptp_mtp_getobjectpropssupported(params, ob->oi.ObjectFormat, &propcnt, &props);
if (ret != PTP_RC_OK) {
add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Representative_Sample(): could not get object properties.");
return -1;
diff --git a/src/ptp-pack.c b/src/ptp-pack.c
index 14ab38d..2384120 100644
--- a/src/ptp-pack.c
+++ b/src/ptp-pack.c
@@ -285,6 +285,8 @@ ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsign
uint8_t len;
unsigned int totallen;
+ if (!data) return;
+ if (datalen < 12) return;
di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
di->VendorExtensionID =
dtoh32a(&data[PTP_di_VendorExtensionID]);
@@ -1164,10 +1166,19 @@ ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry
#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
-#define PTP_ece_OI_ObjectID 8 /* only for objectinfos */
-#define PTP_ece_OI_OFC 0x0c /* only for objectinfos */
-#define PTP_ece_OI_Size 0x14 /* only for objectinfos */
-#define PTP_ece_OI_Name 0x1c /* only for objectinfos */
+/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
+#define PTP_ece_OI_ObjectID 8
+#define PTP_ece_OI_OFC 0x0c
+#define PTP_ece_OI_Size 0x14
+#define PTP_ece_OI_Name 0x1c
+
+/* for PTP_EC_CANON_EOS_ObjectAddedEx */
+#define PTP_ece_OA_ObjectID 8
+#define PTP_ece_OA_StorageID 0x0c
+#define PTP_ece_OA_OFC 0x10
+#define PTP_ece_OA_Size 0x1c
+#define PTP_ece_OA_Parent 0x20
+#define PTP_ece_OA_Name 0x28
static inline int
ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
@@ -1194,15 +1205,28 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
+ (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
switch (type) {
- case PTP_EC_CANON_EOS_RequestObjectTransfer:
+ case PTP_EC_CANON_EOS_ObjectAddedEx:
(*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
+ (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
+ (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
+ (*ce)[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
+ (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
+ (*ce)[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
+ (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
+ ptp_debug (params, "event %d: objectinfo added oid %08lx, parent %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ParentObject, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
+ break;
+ case PTP_EC_CANON_EOS_RequestObjectTransfer:
+ (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
(*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
+ (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */
(*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
+ (*ce)[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
(*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
(*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
- ptp_debug (params, "event %d: objectinfo oid %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
+ ptp_debug (params, "event %d: request object transfer oid %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
break;
case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
@@ -1256,7 +1280,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
default: {
int k;
ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, fill in (val=%x).", i, dpd->DataType, proptype, dtoh32a(data));
- for (k=0;k<size-PTP_ece_Prop_Desc_Data;k++)
+ for (k=0;k<(size-PTP_ece_Prop_Desc_Data)/propxcnt;k++)
ptp_debug (params, " %d: %02x", k, data[k]);
break;
}
@@ -1302,6 +1326,19 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
switch (proptype) {
case PTP_DPC_CANON_EOS_CameraTime:
case PTP_DPC_CANON_EOS_EVFOutputDevice:
+ case PTP_DPC_CANON_EOS_AvailableShots:
+ case PTP_DPC_CANON_EOS_DriveMode:
+ case PTP_DPC_CANON_EOS_CaptureDestination:
+ case PTP_DPC_CANON_EOS_WhiteBalanceXA:
+ case PTP_DPC_CANON_EOS_WhiteBalanceXB:
+ case PTP_DPC_CANON_EOS_AEB:
+ case PTP_DPC_CANON_EOS_QuickReviewTime:
+ case PTP_DPC_CANON_EOS_CurrentStorage:
+ case PTP_DPC_CANON_EOS_CurrentFolder:
+ case PTP_DPC_CANON_EOS_ShutterCounter:
+ case PTP_DPC_CANON_EOS_ModelID:
+ case PTP_DPC_CANON_EOS_LensID:
+ case PTP_DPC_CANON_EOS_StroboFiring:
dpd->DataType = PTP_DTC_UINT32;
break;
case PTP_DPC_CANON_EOS_Aperture:
@@ -1311,6 +1348,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
case PTP_DPC_CANON_EOS_AutoExposureMode:
case PTP_DPC_CANON_EOS_ColorSpace:
case PTP_DPC_CANON_EOS_BatteryPower:
+ case PTP_DPC_CANON_EOS_PTPExtensionVersion:
dpd->DataType = PTP_DTC_UINT16;
break;
case PTP_DPC_CANON_EOS_PictureStyle:
@@ -1327,14 +1365,9 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
dpd->DataType = PTP_DTC_INT16;
break;
/* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
- case PTP_DPC_CANON_EOS_DriveMode:
- case PTP_DPC_CANON_EOS_WhiteBalanceXB:
case PTP_DPC_CANON_EOS_BatterySelect:
case 0xd114:
- case PTP_DPC_CANON_EOS_PTPExtensionVersion:
case PTP_DPC_CANON_EOS_DPOFVersion:
- case PTP_DPC_CANON_EOS_AvailableShots:
- case PTP_DPC_CANON_EOS_CaptureDestination:
case PTP_DPC_CANON_EOS_BracketMode:
case PTP_DPC_CANON_EOS_CustomFunc1:
case PTP_DPC_CANON_EOS_CustomFunc2:
@@ -1354,16 +1387,10 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
break;
/* yet unknown 32bit props */
case PTP_DPC_CANON_EOS_ColorTemperature:
- case PTP_DPC_CANON_EOS_WhiteBalanceXA:
- case PTP_DPC_CANON_EOS_ModelID:
- case PTP_DPC_CANON_EOS_CurrentStorage:
- case PTP_DPC_CANON_EOS_CurrentFolder:
case PTP_DPC_CANON_EOS_WftStatus:
case PTP_DPC_CANON_EOS_LensStatus:
- case PTP_DPC_CANON_EOS_QuickReviewTime:
case PTP_DPC_CANON_EOS_CardExtension:
case PTP_DPC_CANON_EOS_TempStatus:
- case PTP_DPC_CANON_EOS_ShutterCounter:
case PTP_DPC_CANON_EOS_PhotoStudioMode:
case PTP_DPC_CANON_EOS_EVFMode:
case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
@@ -1371,6 +1398,12 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
case PTP_DPC_CANON_EOS_EVFWBMode:
case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
case PTP_DPC_CANON_EOS_EVFColorTemp:
+ case PTP_DPC_CANON_EOS_EVFRecordStatus:
+ case PTP_DPC_CANON_EOS_ExposureSimMode:
+ case PTP_DPC_CANON_EOS_LvAfSystem:
+ case PTP_DPC_CANON_EOS_MovSize:
+ case PTP_DPC_CANON_EOS_DepthOfField:
+ case PTP_DPC_CANON_EOS_LvViewTypeSelect:
dpd->DataType = PTP_DTC_UINT32;
ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint32", i ,proptype, size-PTP_ece_Prop_Val_Data);
for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
@@ -1417,12 +1450,36 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
break;
default:
- ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
+ switch (type) {
+#define XX(x) case PTP_EC_CANON_EOS_##x: ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size);break;
+ XX(RequestGetEvent)
+ XX(ObjectRemoved)
+ XX(RequestGetObjectInfoEx)
+ XX(StorageStatusChanged)
+ XX(StorageInfoChanged)
+ XX(ObjectInfoChangedEx)
+ XX(ObjectContentChanged)
+ XX(CameraStatusChanged)
+ XX(WillSoonShutdown)
+ XX(ShutdownTimerUpdated)
+ XX(RequestCancelTransfer)
+ XX(RequestObjectTransferDT)
+ XX(RequestCancelTransferDT)
+ XX(StoreAdded)
+ XX(StoreRemoved)
+ XX(BulbExposureTime)
+ XX(RecordingTime)
+ XX(RequestObjectTransferTS)
+ XX(AfResult)
+#undef XX
+ default:
+ ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
+ break;
+ }
if (size >= 0x8) { /* event info */
int j;
- for (j=8;j<size;j++) {
- ptp_debug (params, " %d: %02x", j, data[j]);
- }
+ for (j=8;j<size;j++)
+ ptp_debug (params, " %d: %02x", j, curdata[j]);
}
(*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
break;
@@ -1643,4 +1700,3 @@ ptp_unpack_canon_directory (
#undef ISOBJECT
return PTP_RC_OK;
}
-
diff --git a/src/ptp.c b/src/ptp.c
index 6dafb3c..898c5de 100644
--- a/src/ptp.c
+++ b/src/ptp.c
@@ -22,7 +22,7 @@
*/
#define _BSD_SOURCE
-#include <config.h>
+#include "config.h"
#include "ptp.h"
#include <stdlib.h>
@@ -419,6 +419,7 @@ ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo)
len=0;
ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
ptp_exit_recv_memory_handler (&handler, &di, &len);
+ if (!di) ret = PTP_RC_GeneralError;
if (ret == PTP_RC_OK) ptp_unpack_DI(params, di, deviceinfo, len);
free(di);
return ret;
@@ -474,7 +475,6 @@ ptp_opensession (PTPParams* params, uint32_t session)
/* no split headers */
params->split_header_data = 0;
-
PTP_CNT_INIT(ptp);
ptp.Code=PTP_OC_OpenSession;
ptp.Param1=session;
@@ -524,20 +524,11 @@ void
ptp_free_params (PTPParams *params) {
int i;
- for (i=0;i<params->nrofprops;i++) {
- MTPProperties *xpl = &params->props[i];
-
- if ((xpl->datatype == PTP_DTC_STR) && (xpl->propval.str))
- free (xpl->propval.str);
- }
- if (params->props) free (params->props);
- if (params->canon_flags) free (params->canon_flags);
if (params->cameraname) free (params->cameraname);
if (params->wifi_profiles) free (params->wifi_profiles);
- free (params->handles.Handler);
- for (i=0;i<params->handles.n;i++)
- ptp_free_objectinfo (&params->objectinfo[i]);
- free (params->objectinfo);
+ for (i=0;i<params->nrofobjects;i++)
+ ptp_free_object (&params->objects[i]);
+ free (params->objects);
ptp_free_DI (&params->deviceinfo);
}
@@ -1868,6 +1859,27 @@ ptp_canon_keepdeviceon (PTPParams* params)
}
/**
+ * ptp_canon_eos_keepdeviceon:
+ *
+ * This operation sends a "ping" style message to the camera.
+ *
+ * params: PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+uint16_t
+ptp_canon_eos_keepdeviceon (PTPParams* params)
+{
+ PTPContainer ptp;
+
+ PTP_CNT_INIT(ptp);
+ ptp.Code=PTP_OC_CANON_EOS_KeepDeviceOn;
+ ptp.Nparam=0;
+ return ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
+}
+
+/**
* ptp_canon_initiatecaptureinmemory:
*
* This operation starts the image capture according to the current camera
@@ -3463,6 +3475,18 @@ ptp_free_objectinfo (PTPObjectInfo *oi)
free (oi->Keywords); oi->Keywords = NULL;
}
+void
+ptp_free_object (PTPObject *ob)
+{
+ int i;
+ if (!ob) return;
+
+ ptp_free_objectinfo (&ob->oi);
+ for (i=0;i<ob->nrofmtpprops;i++)
+ ptp_destroy_object_prop(&ob->mtpprops[i]);
+ ob->flags = 0;
+}
+
void
ptp_perror(PTPParams* params, uint16_t error) {
@@ -5074,16 +5098,19 @@ ptp_destroy_object_prop_list(MTPProperties *props, int nrofprops)
MTPProperties *
ptp_find_object_prop_in_cache(PTPParams *params, uint32_t const handle, uint32_t const attribute_id)
{
- int i;
- MTPProperties *prop = params->props;
-
- if (!prop)
+ int i;
+ MTPProperties *prop;
+ PTPObject *ob;
+ uint16_t ret;
+
+ ret = ptp_object_find (params, handle, &ob);
+ if (ret != PTP_RC_OK)
return NULL;
-
- for (i=0;i<params->nrofprops;i++) {
- if (handle == prop->ObjectHandle && attribute_id == prop->property)
+ prop = ob->mtpprops;
+ for (i=0;i<ob->nrofmtpprops;i++) {
+ if (attribute_id == prop->property)
return prop;
- prop ++;
+ prop++;
}
return NULL;
}
@@ -5092,108 +5119,263 @@ void
ptp_remove_object_from_cache(PTPParams *params, uint32_t handle)
{
int i;
+ PTPObject *ob;
+ uint16_t ret;
+ ret = ptp_object_find (params, handle, &ob);
+ if (ret != PTP_RC_OK)
+ return;
+ i = ob-params->objects;
/* remove object from object info cache */
- for (i = 0; i < params->handles.n; i++) {
- if (params->handles.Handler[i] == handle) {
- ptp_free_objectinfo(&params->objectinfo[i]);
-
- if (i < params->handles.n-1) {
- memmove(params->handles.Handler+i, params->handles.Handler+i+1,
- (params->handles.n-i-1)*sizeof(uint32_t));
- memmove(params->objectinfo+i, params->objectinfo+i+1,
- (params->handles.n-i-1)*sizeof(PTPObjectInfo));
- }
- params->handles.n--;
- /* We use less memory than before so this shouldn't fail */
- params->handles.Handler = realloc(params->handles.Handler, sizeof(uint32_t)*params->handles.n);
- params->objectinfo = realloc(params->objectinfo, sizeof(PTPObjectInfo)*params->handles.n);
- break;
- }
- }
+ ptp_free_object (ob);
+
+ if (i < params->nrofobjects-1)
+ memmove (ob,ob+1,(params->nrofobjects-1)*sizeof(PTPObject));
+ params->nrofobjects--;
+ /* We use less memory than before so this shouldn't fail */
+ params->objects = realloc(params->objects, sizeof(PTPObject)*params->nrofobjects);
+}
+
+static int _cmp_ob (const void *a, const void *b) {
+ PTPObject *oa = (PTPObject*)a;
+ PTPObject *ob = (PTPObject*)b;
+
+ return oa->oid - ob->oid;
+}
- /* delete cached object properties if metadata cache exists */
- if (params->props != NULL) {
- int nrofoldprops = 0;
- int firstoldprop = 0;
-
- for (i=0; i<params->nrofprops; i++) {
- MTPProperties *prop = &params->props[i];
- if (prop->ObjectHandle == handle)
- {
- nrofoldprops++;
- if (nrofoldprops == 1) {
- firstoldprop = i;
- }
- }
- }
- for (i=firstoldprop;i<(firstoldprop+nrofoldprops);i++) {
- ptp_destroy_object_prop(&params->props[i]);
+void
+ptp_objects_sort (PTPParams *params) {
+ qsort (params->objects, params->nrofobjects, sizeof(PTPObject), _cmp_ob);
+}
+
+/* Binary search in objects. Needs "objects" to be a sorted by objectid list! */
+uint16_t
+ptp_object_find (PTPParams *params, uint32_t handle, PTPObject **retob) {
+ PTPObject tmpob;
+
+ tmpob.oid = handle;
+ *retob = bsearch (&tmpob, params->objects, params->nrofobjects, sizeof(tmpob), _cmp_ob);
+ if (!*retob)
+ return PTP_RC_GeneralError;
+ return PTP_RC_OK;
+}
+
+/* Binary search in objects + insert of not found. Needs "objects" to be a sorted by objectid list! */
+uint16_t
+ptp_object_find_or_insert (PTPParams *params, uint32_t handle, PTPObject **retob) {
+ int begin, end, cursor;
+ int insertat;
+ PTPObject *newobs;
+
+ if (!handle) return PTP_RC_GeneralError;
+ *retob = NULL;
+ if (!params->nrofobjects) {
+ params->objects = calloc(1,sizeof(PTPObject));
+ params->nrofobjects = 1;
+ params->objects[0].oid = handle;
+ *retob = &params->objects[0];
+ return PTP_RC_OK;
+ }
+ begin = 0;
+ end = params->nrofobjects-1;
+ /*ptp_debug (params, "searching %08x, total=%d\n", handle, params->nrofobjects);*/
+ while (1) {
+ cursor = (end-begin)/2+begin;
+ /*ptp_debug (params, "ob %d: %08x [%d-%d]\n", cursor, params->objects[cursor].oid, begin, end);*/
+ if (params->objects[cursor].oid == handle) {
+ *retob = &params->objects[cursor];
+ return PTP_RC_OK;
}
- memmove(&params->props[firstoldprop],
- &params->props[firstoldprop+nrofoldprops],
- (params->nrofprops-firstoldprop-nrofoldprops)*sizeof(MTPProperties));
- /* We use less memory than before so this shouldn't fail */
- params->props = realloc(params->props,
- (params->nrofprops - nrofoldprops)*sizeof(MTPProperties));
- params->nrofprops -= nrofoldprops;
+ if (params->objects[cursor].oid < handle)
+ begin = cursor;
+ else
+ end = cursor;
+ if ((end - begin) <= 1)
+ break;
+ }
+ if (params->objects[begin].oid == handle) {
+ *retob = &params->objects[begin];
+ return PTP_RC_OK;
+ }
+ if (params->objects[end].oid == handle) {
+ *retob = &params->objects[end];
+ return PTP_RC_OK;
}
+ if ((begin == 0) && (handle < params->objects[0].oid))
+ insertat=begin;
+ else
+ insertat=begin+1;
+ /*ptp_debug (params, "inserting oid %x at [%x,%x]\n", handle, params->objects[begin].oid, params->objects[end].oid);*/
+ newobs = realloc (params->objects, sizeof(PTPObject)*(params->nrofobjects+1));
+ if (!newobs) return PTP_RC_GeneralError;
+ params->objects = newobs;
+ if (insertat<=params->nrofobjects)
+ memmove (&params->objects[insertat+1],&params->objects[insertat],(params->nrofobjects-insertat)*sizeof(PTPObject));
+ memset(&params->objects[insertat],0,sizeof(PTPObject));
+ params->objects[insertat].oid = handle;
+ *retob = &params->objects[insertat];
+ params->nrofobjects++;
+ return PTP_RC_OK;
}
uint16_t
-ptp_add_object_to_cache(PTPParams *params, uint32_t handle)
-{
- uint32_t n;
- uint32_t *xhandler;
- PTPObjectInfo *xoi;
-
- /* We have a new handle */
- params->handles.n++;
- n = params->handles.n;
-
- /* Insert the new handle */
- xhandler = (uint32_t*) realloc(params->handles.Handler,
- sizeof(uint32_t)*n);
- if (!xhandler) {
- /* Well, out of memory is no I/O error really... */
- return PTP_ERROR_IO;
- }
- params->handles.Handler = xhandler;
- params->handles.Handler[n-1] = handle;
-
- /* Insert a new object info struct and populate it */
- xoi = (PTPObjectInfo*)realloc(params->objectinfo,
- sizeof(PTPObjectInfo)*n);
- if (!xoi) {
- /* Well, out of memory is no I/O error really... */
- return PTP_ERROR_IO;
+ptp_object_want (PTPParams *params, uint32_t handle, int want, PTPObject **retob) {
+ uint16_t ret;
+ PTPObject *ob;
+ //Camera *camera = ((PTPData *)params->data)->camera;
+
+ *retob = NULL;
+ if (!handle) {
+ ptp_debug (params, "ptp_object_want: querying handle 0?\n");
+ return PTP_RC_GeneralError;
}
- params->objectinfo = xoi;
- memset(&params->objectinfo[n-1], 0, sizeof(PTPObjectInfo));
- ptp_getobjectinfo(params, handle, &params->objectinfo[n-1]);
-
- /* Update proplist if we use cached props */
- if (params->props != NULL) {
- MTPProperties *props = NULL;
- MTPProperties *xprops;
- int no_new_props = 0;
- uint16_t ret;
-
- ret = ptp_mtp_getobjectproplist(params, handle, &props, &no_new_props);
- if (ret != PTP_RC_OK) {
+ ret = ptp_object_find_or_insert (params, handle, &ob);
+ if (ret != PTP_RC_OK)
+ return PTP_RC_GeneralError;
+ *retob = ob;
+ /* Do we have all of it already? */
+ if ((ob->flags & want) == want)
+ return PTP_RC_OK;
+
+ if ( (want & PTPOBJECT_OBJECTINFO_LOADED) &&
+ (!(ob->flags & PTPOBJECT_OBJECTINFO_LOADED))
+ ) {
+ ret = ptp_getobjectinfo (params, handle, &ob->oi);
+ if (ret != PTP_RC_OK)
return ret;
+ //debug_objectinfo(params, handle, &params->objects[i].oi);
+ ob->flags |= PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_STORAGEID_LOADED|PTPOBJECT_PARENTOBJECT_LOADED;
+ }
+ if ( (want & PTPOBJECT_MTPPROPLIST_LOADED) &&
+ (!(ob->flags & PTPOBJECT_MTPPROPLIST_LOADED))
+ ) {
+ int nrofprops = 0;
+ MTPProperties *props = NULL;
+
+ if (params->device_flags & DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST) {
+ want &= ~PTPOBJECT_MTPPROPLIST_LOADED;
+ goto fallback;
+ }
+ /* Microsoft/MTP has fast directory retrieval. */
+ if (!ptp_operation_issupported(params,PTP_OC_MTP_GetObjPropList)) {
+ want &= ~PTPOBJECT_MTPPROPLIST_LOADED;
+ goto fallback;
}
- xprops = realloc(params->props, (params->nrofprops+no_new_props)*sizeof(MTPProperties));
- if (!xprops) {
- free(props);
- /* Well, out of memory is no I/O error really... */
- return PTP_ERROR_IO;
+
+ ptp_debug (params, "ptp2/mtpfast: reading mtp proplist of %08x", handle);
+ ret = ptp_mtp_getobjectproplist (params, handle, &props, &nrofprops);
+ if (ret != PTP_RC_OK)
+ goto fallback;
+ ob->mtpprops = props;
+ ob->nrofmtpprops = nrofprops;
+
+#if 0
+ MTPProperties *xpl;
+ int j;
+ PTPObjectInfo oinfo;
+
+ memset (&oinfo,0,sizeof(oinfo));
+ /* hmm, not necessary ... only if we would use it */
+ for (j=0;j<nrofprops;j++) {
+ xpl = &props[j];
+ switch (xpl->property) {
+ case PTP_OPC_ParentObject:
+ if (xpl->datatype != PTP_DTC_UINT32) {
+ ptp_debug (params, "ptp2/mtpfast: parentobject has type 0x%x???", xpl->datatype);
+ break;
+ }
+ oinfo.ParentObject = xpl->propval.u32;
+ ptp_debug (params, "ptp2/mtpfast: parent 0x%x", xpl->propval.u32);
+ break;
+ case PTP_OPC_ObjectFormat:
+ if (xpl->datatype != PTP_DTC_UINT16) {
+ ptp_debug (params, "ptp2/mtpfast: objectformat has type 0x%x???", xpl->datatype);
+ break;
+ }
+ oinfo.ObjectFormat = xpl->propval.u16;
+ ptp_debug (params, "ptp2/mtpfast: ofc 0x%x", xpl->propval.u16);
+ break;
+ case PTP_OPC_ObjectSize:
+ switch (xpl->datatype) {
+ case PTP_DTC_UINT32:
+ oinfo.ObjectCompressedSize = xpl->propval.u32;
+ break;
+ case PTP_DTC_UINT64:
+ oinfo.ObjectCompressedSize = xpl->propval.u64;
+ break;
+ default:
+ ptp_debug (params, "ptp2/mtpfast: objectsize has type 0x%x???", xpl->datatype);
+ break;
+ }
+ ptp_debug (params, "ptp2/mtpfast: objectsize %u", xpl->propval.u32);
+ break;
+ case PTP_OPC_StorageID:
+ if (xpl->datatype != PTP_DTC_UINT32) {
+ ptp_debug (params, "ptp2/mtpfast: storageid has type 0x%x???", xpl->datatype);
+ break;
+ }
+ oinfo.StorageID = xpl->propval.u32;
+ ptp_debug (params, "ptp2/mtpfast: storageid 0x%x", xpl->propval.u32);
+ break;
+ case PTP_OPC_ProtectionStatus:/*UINT16*/
+ if (xpl->datatype != PTP_DTC_UINT16) {
+ ptp_debug (params, "ptp2/mtpfast: protectionstatus has type 0x%x???", xpl->datatype);
+ break;
+ }
+ oinfo.ProtectionStatus = xpl->propval.u16;
+ ptp_debug (params, "ptp2/mtpfast: protection 0x%x", xpl->propval.u16);
+ break;
+ case PTP_OPC_ObjectFileName:
+ if (xpl->datatype != PTP_DTC_STR) {
+ ptp_debug (params, "ptp2/mtpfast: filename has type 0x%x???", xpl->datatype);
+ break;
+ }
+ if (xpl->propval.str) {
+ ptp_debug (params, "ptp2/mtpfast: filename %s", xpl->propval.str);
+ oinfo.Filename = strdup(xpl->propval.str);
+ } else {
+ oinfo.Filename = NULL;
+ }
+ break;
+ case PTP_OPC_DateCreated:
+ if (xpl->datatype != PTP_DTC_STR) {
+ ptp_debug (params, "ptp2/mtpfast: datecreated has type 0x%x???", xpl->datatype);
+ break;
+ }
+ ptp_debug (params, "ptp2/mtpfast: capturedate %s", xpl->propval.str);
+ oinfo.CaptureDate = ptp_unpack_PTPTIME (xpl->propval.str);
+ break;
+ case PTP_OPC_DateModified:
+ if (xpl->datatype != PTP_DTC_STR) {
+ ptp_debug (params, "ptp2/mtpfast: datemodified has type 0x%x???", xpl->datatype);
+ break;
+ }
+ ptp_debug (params, "ptp2/mtpfast: moddate %s", xpl->propval.str);
+ oinfo.ModificationDate = ptp_unpack_PTPTIME (xpl->propval.str);
+ break;
+ default:
+ if ((xpl->property & 0xfff0) == 0xdc00)
+ ptp_debug (params, "ptp2/mtpfast:case %x type %x unhandled", xpl->property, xpl->datatype);
+ break;
+ }
}
- params->props = xprops;
- memcpy(&params->props[params->nrofprops],&props[0],no_new_props*sizeof(MTPProperties));
- /* do not free the sub strings, we copied them above! Only free the array. */
- free(props);
- params->nrofprops += no_new_props;
+ if (!oinfo.Filename)
+ /* i have one such file on my Creative */
+ oinfo.Filename = strdup("<null>");
+#endif
+ ob->flags |= PTPOBJECT_MTPPROPLIST_LOADED;
+fallback: ;
}
- return PTP_RC_OK;
+ if ((ob->flags & want) == want)
+ return PTP_RC_OK;
+ ptp_debug (params, "ptp_object_want: oid 0x%08x, want flags %x, have only %x?", handle, want, ob->flags);
+ return PTP_RC_GeneralError;
+}
+
+
+uint16_t
+ptp_add_object_to_cache(PTPParams *params, uint32_t handle)
+{
+ PTPObject *ob;
+ return ptp_object_want (params, handle, PTPOBJECT_OBJECTINFO_LOADED|PTPOBJECT_MTPPROPLIST_LOADED, &ob);
}
diff --git a/src/ptp.h b/src/ptp.h
index 7923499..400ba17 100644
--- a/src/ptp.h
+++ b/src/ptp.h
@@ -29,6 +29,7 @@
#include <iconv.h>
#endif
#include "gphoto2-endian.h"
+#include "device-flags.h"
#ifdef __cplusplus
extern "C" {
@@ -785,6 +786,7 @@ typedef struct _PTPObjectInfo PTPObjectInfo;
/* Canon extension */
#define PTP_OFC_CANON_CRW 0xb101
#define PTP_OFC_CANON_CRW3 0xb103
+#define PTP_OFC_CANON_MOV 0xb104
/* MTP extensions */
#define PTP_OFC_MTP_MediaCard 0xb211
#define PTP_OFC_MTP_MediaCardGroup 0xb212
@@ -1044,8 +1046,9 @@ struct _PTPNIKONWifiProfile {
typedef struct _PTPNIKONWifiProfile PTPNIKONWifiProfile;
-#define PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN 0
-#define PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO 1
+#define PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN 0
+#define PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO 1
+#define PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER 2
struct _PTPCanon_New_Object {
uint32_t oid;
@@ -1818,7 +1821,27 @@ typedef void (* PTPDebugFunc) (void *data, const char *format, va_list args)
#endif
;
+struct _PTPObject {
+ uint32_t oid;
+ unsigned int flags;
+#define PTPOBJECT_OBJECTINFO_LOADED (1<<0)
+#define PTPOBJECT_CANONFLAGS_LOADED (1<<1)
+#define PTPOBJECT_MTPPROPLIST_LOADED (1<<2)
+#define PTPOBJECT_DIRECTORY_LOADED (1<<3)
+#define PTPOBJECT_PARENTOBJECT_LOADED (1<<4)
+#define PTPOBJECT_STORAGEID_LOADED (1<<5)
+
+ PTPObjectInfo oi;
+ uint32_t canon_flags;
+ MTPProperties *mtpprops;
+ int nrofmtpprops;
+};
+typedef struct _PTPObject PTPObject;
+
struct _PTPParams {
+ /* device flags */
+ uint32_t device_flags;
+
/* data layer byteorder */
uint8_t byteorder;
uint16_t maxpacketsize;
@@ -1847,13 +1870,10 @@ struct _PTPParams {
/* PTP IO: if we have MTP style split header/data transfers */
int split_header_data;
- /* PTP: MTP specific structure. */
- MTPProperties *props;
- int nrofprops;
-
/* PTP: internal structures used by ptp driver */
- PTPObjectHandles handles;
- PTPObjectInfo *objectinfo;
+ PTPObject *objects;
+ int nrofobjects;
+
PTPDeviceInfo deviceinfo;
/* PTP: the current event queue */
@@ -1861,7 +1881,6 @@ struct _PTPParams {
int nrofevents;
/* PTP: Canon specific flags list */
- uint32_t *canon_flags; /* size(handles.n) */
PTPCanon_Property *canon_props;
int nrofcanon_props;
@@ -2031,6 +2050,7 @@ uint16_t ptp_canon_checkevent (PTPParams* params,
uint16_t ptp_canon_focuslock (PTPParams* params);
uint16_t ptp_canon_focusunlock (PTPParams* params);
uint16_t ptp_canon_keepdeviceon (PTPParams* params);
+uint16_t ptp_canon_eos_keepdeviceon (PTPParams* params);
uint16_t ptp_canon_initiatecaptureinmemory (PTPParams* params);
uint16_t ptp_canon_eos_capture (PTPParams* params);
uint16_t ptp_canon_eos_getevent (PTPParams* params, PTPCanon_changes_entry **entries, int *nrofentries);
@@ -2104,7 +2124,7 @@ void ptp_free_devicepropvalue (uint16_t dt, PTPPropertyValue* dpd);
void ptp_free_objectpropdesc (PTPObjectPropDesc* dpd);
void ptp_free_params (PTPParams *params);
void ptp_free_objectinfo (PTPObjectInfo *oi);
-
+void ptp_free_object (PTPObject *oi);
void ptp_perror (PTPParams* params, uint16_t error);
@@ -2123,7 +2143,10 @@ void ptp_destroy_object_prop_list(MTPProperties *props, int nrofprops);
MTPProperties *ptp_find_object_prop_in_cache(PTPParams *params, uint32_t const handle, uint32_t const attribute_id);
void ptp_remove_object_from_cache(PTPParams *params, uint32_t handle);
uint16_t ptp_add_object_to_cache(PTPParams *params, uint32_t handle);
-
+uint16_t ptp_object_want (PTPParams *, uint32_t handle, int want, PTPObject**retob);
+void ptp_objects_sort (PTPParams *);
+uint16_t ptp_object_find (PTPParams *params, uint32_t handle, PTPObject **retob);
+uint16_t ptp_object_find_or_insert (PTPParams *params, uint32_t handle, PTPObject **retob);
/* ptpip.c */
void ptp_nikon_getptpipguid (unsigned char* guid);