Sophie

Sophie

distrib > Mageia > 5 > x86_64 > by-pkgid > 1e8e1c6a1925f1fd1367b863dfea0985 > files > 1

libmtp-1.1.8-4.1.mga5.src.rpm

--- libmtp-1.1.8/src/libmtp.c.orig	2017-07-08 15:24:05.362906649 -0400
+++ libmtp-1.1.8/src/libmtp.c	2017-07-08 15:25:19.804729041 -0400
@@ -1851,6 +1851,7 @@ LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Devi
   memset(current_params, 0, sizeof(PTPParams));
   current_params->device_flags = rawdevice->device_entry.device_flags;
   current_params->nrofobjects = 0;
+  current_params->cachetime = 2;
   current_params->objects = NULL;
   current_params->response_packet_size = 0;
   current_params->response_packet = NULL;
@@ -2420,6 +2421,8 @@ static void add_ptp_error_to_errorstack(
 					uint16_t ptp_error,
 					char const * const error_text)
 {
+  PTPParams      *params = (PTPParams *) device->params;
+
   if (device == NULL) {
     LIBMTP_ERROR("LIBMTP PANIC: Trying to add PTP error to a NULL device!\n");
     return;
@@ -2429,7 +2432,7 @@ static void add_ptp_error_to_errorstack(
     outstr[sizeof(outstr)-1] = '\0';
     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
 
-    snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error));
+    snprintf(outstr, sizeof(outstr), "Error %04x: %s", ptp_error, ptp_strerror(ptp_error, params->deviceinfo.VendorExtensionID));
     outstr[sizeof(outstr)-1] = '\0';
     add_error_to_errorstack(device, LIBMTP_ERROR_PTP_LAYER, outstr);
   }
@@ -3100,13 +3103,8 @@ void LIBMTP_Dump_Device_Info(LIBMTP_mtpd
     tmpext = tmpext->next;
   }
   printf("Supported operations:\n");
-  for (i=0;i<params->deviceinfo.OperationsSupported_len;i++) {
-    char txt[256];
-
-    (void) ptp_render_opcode(params, params->deviceinfo.OperationsSupported[i],
-			     sizeof(txt), txt);
-    printf("   %04x: %s\n", params->deviceinfo.OperationsSupported[i], txt);
-  }
+  for (i=0;i<params->deviceinfo.OperationsSupported_len;i++)
+    printf("   %04x: %s\n", params->deviceinfo.OperationsSupported[i], ptp_get_opcode_name(params, params->deviceinfo.OperationsSupported[i]));
   printf("Events supported:\n");
   if (params->deviceinfo.EventsSupported_len == 0) {
     printf("   None.\n");
--- libmtp-1.1.8/src/ptp-pack.c.orig	2014-06-02 15:44:03.000000000 -0400
+++ libmtp-1.1.8/src/ptp-pack.c	2017-07-08 14:39:13.812876741 -0400
@@ -1,7 +1,7 @@
 /* ptp-pack.c
  *
  * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
- * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
  * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
  * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
  * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
@@ -30,7 +30,7 @@
 #ifndef UINT_MAX
 # define UINT_MAX 0xFFFFFFFF
 #endif
-#ifdef HAVE_ICONV
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
 #include <iconv.h>
 #endif
 
@@ -127,7 +127,7 @@ dtoh64ap (PTPParams *params, const unsig
 
 
 static inline char*
-ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
+ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t total, uint8_t *len)
 {
 	uint8_t length;
 	uint16_t string[PTP_MAXSTRLEN+1];
@@ -136,10 +136,16 @@ ptp_unpack_string(PTPParams *params, uns
 	size_t nconv, srclen, destlen;
 	char *src, *dest;
 
+	if (offset + 1 >= total)
+		return NULL;
+
 	length = dtoh8a(&data[offset]);	/* PTP_MAXSTRLEN == 255, 8 bit len */
 	*len = length;
 	if (length == 0)		/* nothing to do? */
-		return(NULL);
+		return NULL;
+
+	if (offset + 1 + length*sizeof(string[0]) > total)
+		return NULL;
 
 	/* copy to string[] to ensure correct alignment for iconv(3) */
 	memcpy(string, &data[offset+1], length * sizeof(string[0]));
@@ -152,7 +158,7 @@ ptp_unpack_string(PTPParams *params, uns
 	dest = loclstr;
 	destlen = sizeof(loclstr)-1;
 	nconv = (size_t)-1;
-#ifdef HAVE_ICONV
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
 	if (params->cd_ucs2_to_locale != (iconv_t)-1)
 		nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, &dest, &destlen);
 #endif
@@ -193,7 +199,7 @@ ptp_pack_string(PTPParams *params, char
 
 	/* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
 	memset(ucs2strp, 0, sizeof(ucs2str));  /* XXX: necessary? */
-#ifdef HAVE_ICONV
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
 	if (params->cd_locale_to_ucs2 != (iconv_t)-1) {
 		size_t nconv;
 		size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
@@ -258,17 +264,34 @@ ptp_get_packed_stringcopy(PTPParams *par
 }
 
 static inline uint32_t
-ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
+ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint32_t **array)
 {
 	uint32_t n, i=0;
 
+	if (!data)
+		return 0;
+
+	if (offset >= datalen)
+		return 0;
+
+	if (offset + sizeof(uint32_t) > datalen)
+		return 0;
+
 	*array = NULL;
 	n=dtoh32a(&data[offset]);
 	if (n >= UINT_MAX/sizeof(uint32_t))
 		return 0;
 	if (!n)
 		return 0;
+
+	if (offset + sizeof(uint32_t)*(n+1) > datalen) {
+		ptp_debug (params ,"array runs over datalen bufferend (%d vs %d)", offset + sizeof(uint32_t)*(n+1) , datalen);
+		return 0;
+	}
+
 	*array = malloc (n*sizeof(uint32_t));
+	if (!*array)
+		return 0;
 	for (i=0;i<n;i++)
 		(*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
 	return n;
@@ -280,6 +303,8 @@ ptp_pack_uint32_t_array(PTPParams *param
 	uint32_t i=0;
 
 	*data = malloc ((arraylen+1)*sizeof(uint32_t));
+	if (!*data)
+		return 0;
 	htod32a(&(*data)[0],arraylen);
 	for (i=0;i<arraylen;i++)
 		htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
@@ -287,17 +312,27 @@ ptp_pack_uint32_t_array(PTPParams *param
 }
 
 static inline uint32_t
-ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
+ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint16_t **array)
 {
 	uint32_t n, i=0;
 
+	if (!data)
+		return 0;
 	*array = NULL;
 	n=dtoh32a(&data[offset]);
 	if (n >= UINT_MAX/sizeof(uint16_t))
 		return 0;
 	if (!n)
 		return 0;
+	if (offset + sizeof(uint32_t) > datalen)
+		return 0;
+	if (offset + sizeof(uint32_t)+sizeof(uint16_t)*n > datalen) {
+		ptp_debug (params ,"array runs over datalen bufferend (%d vs %d)", offset + sizeof(uint32_t)+n*sizeof(uint16_t) , datalen);
+		return 0;
+	}
 	*array = malloc (n*sizeof(uint16_t));
+	if (!*array)
+		return 0;
 	for (i=0;i<n;i++)
 		(*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
 	return n;
@@ -312,104 +347,130 @@ ptp_unpack_uint16_t_array(PTPParams *par
 #define PTP_di_FunctionalMode		 8
 #define PTP_di_OperationsSupported	10
 
-static inline void
+static inline int
 ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
 {
 	uint8_t len;
 	unsigned int totallen;
 
-	if (!data) return;
-	if (datalen < 12) return;
+	if (!data) return 0;
+	if (datalen < 12) return 0;
+	memset (di, 0, sizeof(*di));
 	di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
 	di->VendorExtensionID =
 		dtoh32a(&data[PTP_di_VendorExtensionID]);
 	di->VendorExtensionVersion =
 		dtoh16a(&data[PTP_di_VendorExtensionVersion]);
-	di->VendorExtensionDesc = 
+	di->VendorExtensionDesc =
 		ptp_unpack_string(params, data,
-		PTP_di_VendorExtensionDesc, &len); 
+		PTP_di_VendorExtensionDesc,
+		datalen,
+		&len);
 	totallen=len*2+1;
-	di->FunctionalMode = 
+	if (datalen <= totallen) return 0;
+	di->FunctionalMode =
 		dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
 	di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&di->OperationsSupported);
 	totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
 	di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&di->EventsSupported);
 	totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
 	di->DevicePropertiesSupported_len =
 		ptp_unpack_uint16_t_array(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&di->DevicePropertiesSupported);
 	totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
 	di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&di->CaptureFormats);
 	totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
 	di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&di->ImageFormats);
 	totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
 	di->Manufacturer = ptp_unpack_string(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&len);
 	totallen+=len*2+1;
+	/* be more relaxed ... as these are optional its ok if they are not here */
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
 	di->Model = ptp_unpack_string(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&len);
 	totallen+=len*2+1;
+	/* be more relaxed ... as these are optional its ok if they are not here */
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
 	di->DeviceVersion = ptp_unpack_string(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&len);
 	totallen+=len*2+1;
+	/* be more relaxed ... as these are optional its ok if they are not here */
+	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
 	di->SerialNumber = ptp_unpack_string(params, data,
 		PTP_di_OperationsSupported+totallen,
+		datalen,
 		&len);
+	return 1;
 }
 
 inline static void
 ptp_free_DI (PTPDeviceInfo *di) {
-	if (di->SerialNumber) free (di->SerialNumber);
-	if (di->DeviceVersion) free (di->DeviceVersion);
-	if (di->Model) free (di->Model);
-	if (di->Manufacturer) free (di->Manufacturer);
-	if (di->ImageFormats) free (di->ImageFormats);
-	if (di->CaptureFormats) free (di->CaptureFormats);
-	if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
-	if (di->OperationsSupported) free (di->OperationsSupported);
-	if (di->EventsSupported) free (di->EventsSupported);
-	if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
+	free (di->SerialNumber);
+	free (di->DeviceVersion);
+	free (di->Model);
+	free (di->Manufacturer);
+	free (di->ImageFormats);
+	free (di->CaptureFormats);
+	free (di->VendorExtensionDesc);
+	free (di->OperationsSupported);
+	free (di->EventsSupported);
+	free (di->DevicePropertiesSupported);
+	memset(di, 0, sizeof(*di));
 }
 
 /* EOS Device Info unpack */
-static inline void
+static inline int
 ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
 {
 	unsigned int totallen = 4;
 
 	memset (di,0, sizeof(*di));
-	if (datalen < 8) return;
+	if (datalen < 8) return 0;
 
 	/* uint32_t struct len - ignore */
 	di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
-		totallen, &di->EventsSupported);
-	if (!di->EventsSupported) return;
+		totallen, datalen, &di->EventsSupported);
+	if (!di->EventsSupported) return 0;
 	totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
-	if (totallen >= datalen) return;
+	if (totallen >= datalen) return 0;
 
 	di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
-		totallen, &di->DevicePropertiesSupported);
-	if (!di->DevicePropertiesSupported) return;
+		totallen, datalen, &di->DevicePropertiesSupported);
+	if (!di->DevicePropertiesSupported) return 0;
 	totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
-	if (totallen >= datalen) return;
+	if (totallen >= datalen) return 0;
 
 	di->unk_len = ptp_unpack_uint32_t_array(params, data,
-		totallen, &di->unk);
-	if (!di->unk) return;
+		totallen, datalen, &di->unk);
+	if (!di->unk) return 0;
 	totallen += di->unk_len*sizeof(uint32_t)+4;
-	return;
+	return 1;
 }
 
 static inline void
@@ -428,7 +489,7 @@ static inline void
 ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
 {
 	if (len) {
-		oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
+		oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, len, &oh->Handler);
 	} else {
 		oh->n = 0;
 		oh->Handler = NULL;
@@ -442,13 +503,13 @@ ptp_unpack_OH (PTPParams *params, unsign
 static inline void
 ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
 {
-	if (!data || !len) {
-		sids->n = 0;
-		sids->Storage = NULL;
+	sids->n = 0;
+	sids->Storage = NULL;
+
+	if (!data || !len)
 		return;
-        }
-	sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
-	&sids->Storage);
+
+	sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, len, &sids->Storage);
 }
 
 /* StorageInfo pack/unpack */
@@ -461,22 +522,29 @@ ptp_unpack_SIDs (PTPParams *params, unsi
 #define PTP_si_FreeSpaceInImages	22
 #define PTP_si_StorageDescription	26
 
-static inline void
+static inline int
 ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
 {
 	uint8_t storagedescriptionlen;
 
+	if (len < 26) return 0;
 	si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
 	si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
 	si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
 	si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
 	si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
 	si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
+
+	/* FIXME: check more lengths here */
 	si->StorageDescription=ptp_unpack_string(params, data,
-		PTP_si_StorageDescription, &storagedescriptionlen);
+		PTP_si_StorageDescription,
+		len,
+		&storagedescriptionlen);
 	si->VolumeLabel=ptp_unpack_string(params, data,
 		PTP_si_StorageDescription+storagedescriptionlen*2+1,
+		len,
 		&storagedescriptionlen);
+	return 1;
 }
 
 /* ObjectInfo pack/unpack */
@@ -617,6 +685,12 @@ ptp_unpack_OI (PTPParams *params, unsign
 	uint8_t capturedatelen;
 	char *capture_date;
 
+	if (len < PTP_oi_SequenceNumber)
+		return;
+
+	oi->Filename = oi->Keywords = NULL;
+
+	/* FIXME: also handle length with all the strings at the end */
 	oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
 	oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
 	oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
@@ -639,10 +713,10 @@ ptp_unpack_OI (PTPParams *params, unsign
 	oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
 	oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
 
-	oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
+	oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, len, &filenamelen);
 
 	capture_date = ptp_unpack_string(params, data,
-		PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
+		PTP_oi_filenamelen+filenamelen*2+1, len, &capturedatelen);
 	/* subset of ISO 8601, without '.s' tenths of second and 
 	 * time zone
 	 */
@@ -652,7 +726,7 @@ ptp_unpack_OI (PTPParams *params, unsign
 	/* now the modification date ... */
 	capture_date = ptp_unpack_string(params, data,
 		PTP_oi_filenamelen+filenamelen*2
-		+capturedatelen*2+2,&capturedatelen);
+		+capturedatelen*2+2, len, &capturedatelen);
 	oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
 	free(capture_date);
 }
@@ -674,6 +748,8 @@ ptp_unpack_OI (PTPParams *params, unsign
 							\
 	if (n >= UINT_MAX/sizeof(val->a.v[0]))		\
 		return 0;				\
+	if (n > (total - (*offset))/sizeof(val->a.v[0]))\
+		return 0;				\
 	val->a.count = n;				\
 	val->a.v = malloc(sizeof(val->a.v[0])*n);	\
 	if (!val->a.v) return 0;			\
@@ -683,9 +759,12 @@ ptp_unpack_OI (PTPParams *params, unsign
 
 static inline unsigned int
 ptp_unpack_DPV (
-	PTPParams *params, unsigned char* data, unsigned int *offset, int total,
+	PTPParams *params, unsigned char* data, unsigned int *offset, unsigned int total,
 	PTPPropertyValue* value, uint16_t datatype
 ) {
+	if (*offset >= total)	/* we are at the end or over the end of the buffer */
+		return 0;
+
 	switch (datatype) {
 	case PTP_DTC_INT8:
 		CTVAL(value->i8,dtoh8a);
@@ -752,7 +831,11 @@ ptp_unpack_DPV (
 	case PTP_DTC_STR: {
 		uint8_t len;
 		/* XXX: max size */
-		value->str = ptp_unpack_string(params,data,*offset,&len);
+
+		if (*offset >= total+1)
+			return 0;
+
+		value->str = ptp_unpack_string(params,data,*offset,total,&len);
 		*offset += len*2+1;
 		if (!value->str)
 			return 1;
@@ -776,6 +859,8 @@ ptp_unpack_DPD (PTPParams *params, unsig
 	unsigned int offset = 0, ret;
 
 	memset (dpd, 0, sizeof(*dpd));
+	if (dpdlen <= 5)
+		return 0;
 	dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
 	dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
 	dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
@@ -854,13 +939,19 @@ static inline int
 ptp_unpack_Sony_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen, unsigned int *poffset)
 {
 	unsigned int ret;
+#if 0
+	unsigned int unk1, unk2;
+#endif
 
 	memset (dpd, 0, sizeof(*dpd));
 	dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_Sony_DevicePropertyCode]);
 	dpd->DataType=dtoh16a(&data[PTP_dpd_Sony_DataType]);
 
 #if 0
-	dpd->GetSet=dtoh8a(&data[PTP_dpd_Sony_GetSet]);
+	/* get set ? */
+	unk1 = dtoh8a(&data[PTP_dpd_Sony_GetSet]);
+	unk2 = dtoh8a(&data[PTP_dpd_Sony_Unknown]);
+	ptp_debug (params, "prop 0x%04x, datatype 0x%04x, unk1 %d unk2 %d", dpd->DevicePropertyCode, dpd->DataType, unk1, unk2);
 #endif
 	dpd->GetSet=1;
 
@@ -1251,8 +1342,11 @@ ptp_unpack_OPL (PTPParams *params, unsig
 	MTPProperties *props = NULL;
 	unsigned int offset = 0, i;
 
-	if (prop_count == 0) {
-		*pprops = NULL;
+	*pprops = NULL;
+	if (prop_count == 0)
+		return 0;
+	if (prop_count >= INT_MAX/sizeof(MTPProperties)) {
+		ptp_debug (params ,"prop_count %d is too large", prop_count);
 		return 0;
 	}
 	ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
@@ -1263,7 +1357,7 @@ ptp_unpack_OPL (PTPParams *params, unsig
 	for (i = 0; i < prop_count; i++) {
 		if (len <= 0) {
 			ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
-			ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
+			ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL");
 			ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
 			qsort (props, i, sizeof(MTPProperties),_compare_func);
 			*pprops = props;
@@ -1282,7 +1376,12 @@ ptp_unpack_OPL (PTPParams *params, unsig
 		len -= sizeof(uint16_t);
 
 		offset = 0;
-		ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
+		if (!ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype)) {
+			ptp_debug (params ,"unpacking DPV of property %d encountered insufficient buffer. attack?", i);
+			qsort (props, i, sizeof(MTPProperties),_compare_func);
+			*pprops = props;
+			return i;
+		}
 		data += offset;
 		len -= offset;
 	}
@@ -1409,7 +1508,8 @@ ObjectInfo for 'IMG_0199.JPG':
 0014  72 0c 74 92  OID
 0018  01 00 02 00  StorageID
 001c  01 38 00 00  OFC
-0020  00 00 00 00 00 00 00 00  ? 
+0020  00 00 00 00 ??
+0024  21 00 00 00  flags (4 bytes? 1 byte?)
 0028  19 d5 21 00  Size
 002c  00 00 74 92  ?
 0030  70 0c 74 92  OID
@@ -1422,7 +1522,7 @@ ObjectInfo for 'IMG_0199.JPG':
 #define PTP_cefe_ObjectHandle		0
 #define PTP_cefe_StorageID		4
 #define PTP_cefe_ObjectFormatCode	8
-#define PTP_cefe_Flags			12
+#define PTP_cefe_Flags			16
 #define PTP_cefe_ObjectSize		20
 #define PTP_cefe_Filename		32
 #define PTP_cefe_Time			48
@@ -1541,19 +1641,125 @@ ptp_pack_EOS_ImageFormat (PTPParams* par
 	return s;
 }
 
+/* 00: 32 bit size
+ * 04: 16 bit subsize
+ * 08: 16 bit version (?)
+ * 0c: 16 bit focus_points_in_struct
+ * 10: 16 bit focus_points_in_use
+ * 14: variable arrays:
+ * 	16 bit sizex, 16 bit sizey
+ * 	16 bit othersizex, 16 bit othersizey
+ * 	16 bit array height[focus_points_in_struct]
+ * 	16 bit array width[focus_points_in_struct]
+ * 	16 bit array offsetheight[focus_points_in_struct] middle is 0
+ * 	16 bit array offsetwidth[focus_points_in_struct] middle is ?
+ * bitfield of selected focus points, starting with 0 [size focus_points_in_struct in bits]
+ * unknown stuff , likely which are active
+ * 16 bit 0xffff
+ *
+ * size=NxN,size2=NxN,points={NxNxNxN,NxNxNxN,...},selected={0,1,2}
+ */
+static inline char*
+ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data, uint32_t datasize )
+{
+	uint32_t size 			= dtoh32a( *data );
+	uint32_t halfsize		= dtoh16a( (*data) + 4);
+	uint32_t version		= dtoh16a( (*data) + 6);
+	uint32_t focus_points_in_struct	= dtoh16a( (*data) + 8);
+	uint32_t focus_points_in_use	= dtoh16a( (*data) + 10);
+	uint32_t sizeX			= dtoh16a( (*data) + 12);
+	uint32_t sizeY			= dtoh16a( (*data) + 14);
+	uint32_t size2X			= dtoh16a( (*data) + 16);
+	uint32_t size2Y			= dtoh16a( (*data) + 18);
+	uint32_t i;
+	uint32_t maxlen;
+	char	*str, *p;
+
+	if ((size >= datasize) || (size < 20))
+		return strdup("bad size 1");
+	/* every focuspoint gets 4 (16 bit number possible "-" sign and a x) and a ,*/
+	/* inital things around lets say 100 chars at most. 
+	 * FIXME: check selected when we decode it
+	 */
+	if (size < focus_points_in_struct*8) {
+		ptp_error(params, "focus_points_in_struct %d is too large vs size %d", focus_points_in_struct, size);
+		return strdup("bad size 2");
+	}
+	if (focus_points_in_use > focus_points_in_struct) {
+		ptp_error(params, "focus_points_in_use %d is larger than focus_points_in_struct %d", focus_points_in_use, focus_points_in_struct);
+		return strdup("bad size 3");
+	}
+
+	maxlen = focus_points_in_use*32 + 100 + (size - focus_points_in_struct*8)*2;
+	if (halfsize != size-4) {
+		ptp_error(params, "halfsize %d is not expected %d", halfsize, size-4);
+		return strdup("bad size 4");
+	}
+	if (20 + focus_points_in_struct*8 + (focus_points_in_struct+7)/8 > size) {
+		ptp_error(params, "size %d is too large for fp in struct %d", focus_points_in_struct*8 + 20 + (focus_points_in_struct+7)/8, size);
+		return strdup("bad size 5");
+	}
+#if 0
+	ptp_debug(params,"d1d3 content:");
+	for (i=0;i<size;i+=2)
+		ptp_debug(params,"%d: %02x %02x", i, (*data)[i], (*data)[i+1]);
+#endif
+	ptp_debug(params,"d1d3 version %d", version);
+	ptp_debug(params,"d1d3 size %d", size);
+	ptp_debug(params,"d1d3 focus points in struct %d, in use %d", focus_points_in_struct, focus_points_in_use);
+
+	str = (char*)malloc( maxlen );
+	if (!str)
+		return NULL;
+	p = str;
+
+	p += sprintf(p,"eosversion=%d,size=%dx%d,size2=%dx%d,points={", version, sizeX, sizeY, size2X, size2Y);
+	for (i=0;i<focus_points_in_use;i++) {
+		int16_t x = dtoh16a((*data) + focus_points_in_struct*4 + 20 + 2*i);
+		int16_t y = dtoh16a((*data) + focus_points_in_struct*6 + 20 + 2*i);
+		int16_t w = dtoh16a((*data) + focus_points_in_struct*2 + 20 + 2*i);
+		int16_t h = dtoh16a((*data) + focus_points_in_struct*0 + 20 + 2*i);
+
+		p += sprintf(p,"{%d,%d,%d,%d}",x,y,w,h);
+
+		if (i<focus_points_in_use-1)
+			p += sprintf(p,",");
+	}
+	p += sprintf(p,"},select={");
+	for (i=0;i<focus_points_in_use;i++) {
+		if ((1<<(i%8)) & ((*data)[focus_points_in_struct*8+20+i/8]))
+			p+=sprintf(p,"%d,", i);
+	}
+
+	p += sprintf(p,"},unknown={");
+	for (i=focus_points_in_struct*8+(focus_points_in_struct+7)/8+20;i<size;i++) {
+		if ((p-str) > maxlen - 4)
+			break;
+		p+=sprintf(p,"%02x", (*data)[i]);
+	}
+	p += sprintf(p,"}");
+	return str;
+}
+
+
 static inline char*
 ptp_unpack_EOS_CustomFuncEx (PTPParams* params, unsigned char** data )
 {
 	uint32_t s = dtoh32a( *data );
 	uint32_t n = s/4, i;
-	char* str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/
+	char	*str, *p;
+
+	if (s > 1024) {
+		ptp_debug (params, "customfuncex data is larger than 1k / %d... unexpected?", s);
+		return strdup("bad length");
+	}
+	str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/
 	if (!str)
-		return str;
-	char* p = str;
+		return strdup("malloc failed");
 
+	p = str;
 	for (i=0; i < n; ++i)
 		p += sprintf(p, "%x,", dtoh32a( *data + 4*i ));
-
 	return str;
 }
 
@@ -1602,6 +1808,44 @@ ptp_pack_EOS_CustomFuncEx (PTPParams* pa
 #define PTP_ece_OA_Parent	0x20
 #define PTP_ece_OA_Name		0x28
 
+#define PTP_ece2_OA_ObjectID	8	/* OK */
+#define PTP_ece2_OA_StorageID	0x0c	/* OK */
+#define PTP_ece2_OA_OFC		0x10	/* OK */
+#define PTP_ece2_OA_Size	0x1c	/* OK, might be 64 bit now? */
+#define PTP_ece2_OA_Parent	0x24
+#define PTP_ece2_OA_2ndOID	0x28
+#define PTP_ece2_OA_Name	0x2c	/* OK */
+
+/* for PTP_EC_CANON_EOS_ObjectAddedNew */
+#define PTP_ece_OAN_OFC		0x0c
+#define PTP_ece_OAN_Size	0x14
+
+static PTPDevicePropDesc*
+_lookup_or_allocate_canon_prop(PTPParams *params, uint16_t proptype)
+{
+	unsigned int j;
+
+	for (j=0;j<params->nrofcanon_props;j++)
+		if (params->canon_props[j].proptype == proptype)
+			break;
+	if (j<params->nrofcanon_props)
+		return &params->canon_props[j].dpd;
+
+	if (j)
+		params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
+	else
+		params->canon_props = malloc(sizeof(params->canon_props[0]));
+	params->canon_props[j].proptype = proptype;
+	params->canon_props[j].size = 0;
+	params->canon_props[j].data = NULL;
+	memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
+	params->canon_props[j].dpd.GetSet = 1;
+	params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
+	params->nrofcanon_props = j+1;
+	return &params->canon_props[j].dpd;
+}
+
+
 static inline int
 ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **pce)
 {
@@ -1611,18 +1855,33 @@ ptp_unpack_CANON_changes (PTPParams *par
 
 	if (data==NULL)
 		return 0;
-	while (curdata - data < datasize) {
+	while (curdata - data + 8 < datasize) {
 		uint32_t	size = dtoh32a(&curdata[PTP_ece_Size]);
 		uint32_t	type = dtoh32a(&curdata[PTP_ece_Type]);
 
+		if (size > datasize) {
+			ptp_debug (params, "size %d is larger than datasize %d", size, datasize);
+			break;
+		}
+		if (size < 8) {
+			ptp_debug (params, "size %d is smaller than 8.", size);
+			break;
+		}
 		if ((size == 8) && (type == 0))
 			break;
+		if ((curdata - data) + size >= datasize) {
+			ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries");
+			break;
+		}
 		if (type == PTP_EC_CANON_EOS_OLCInfoChanged) {
 			unsigned int j;
 
-			for (j=0;j<31;j++)
-				if (dtoh32a(curdata+12) & (1<<j))
-					entries++;
+			entries++;
+			if (size >= 12+2) {
+				for (j=0;j<31;j++)
+					if (dtoh16a(curdata+12) & (1<<j))
+						entries++;
+			}
 		}
 		curdata += size;
 		entries++;
@@ -1631,35 +1890,75 @@ ptp_unpack_CANON_changes (PTPParams *par
 	if (!ce) return 0;
 
 	curdata = data;
-	while (curdata - data < datasize) {
+	while (curdata - data  + 8 < datasize) {
 		uint32_t	size = dtoh32a(&curdata[PTP_ece_Size]);
 		uint32_t	type = dtoh32a(&curdata[PTP_ece_Type]);
 
+		if (size > datasize) {
+			ptp_debug (params, "size %d is larger than datasize %d", size, datasize);
+			break;
+		}
+		if (size < 8) {
+			ptp_debug (params, "size %d is smaller than 8", size);
+			break;
+		}
+
+		if ((size == 8) && (type == 0))
+			break;
+
+		if ((curdata - data) + size >= datasize) {
+			ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries");
+			break;
+		}
+
 		ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
 		ce[i].u.info = NULL;
 		switch (type) {
-		case  PTP_EC_CANON_EOS_ObjectAddedEx:
+		case PTP_EC_CANON_EOS_ObjectAddedEx:
+			if (size < PTP_ece_OA_Name+1) {
+				ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OA_Name+1);
+				break;
+			}
 			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.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]));
+			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_ObjectAddedUnknown:	/* FIXME: review if the data used is correct */
+			if (size < PTP_ece2_OA_Name+1) {
+				ptp_debug (params, "size %d is smaller than %d", size, PTP_ece2_OA_Name+1);
+				break;
+			}
+			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
+			ce[i].u.object.oid    		= dtoh32a(&curdata[PTP_ece2_OA_ObjectID]);
+			ce[i].u.object.oi.StorageID	= dtoh32a(&curdata[PTP_ece2_OA_StorageID]);
+			ce[i].u.object.oi.ParentObject	= dtoh32a(&curdata[PTP_ece2_OA_Parent]);
+			ce[i].u.object.oi.ObjectFormat 	= dtoh16a(&curdata[PTP_ece2_OA_OFC]);
+			ce[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece2_OA_Size]);	/* FIXME: might be 64bit now */
+			ce[i].u.object.oi.Filename 	= strdup(((char*)&curdata[PTP_ece2_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:
+		case PTP_EC_CANON_EOS_RequestObjectTransfer:
+		case PTP_EC_CANON_EOS_RequestObjectTransferNew: /* FIXME: confirm */
+			if (size < PTP_ece_OI_Name+1) {
+				ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OI_Name+1);
+				break;
+			}
 			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.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]));
+			ce[i].u.object.oi.Filename 	= strdup(((char*)&curdata[PTP_ece_OI_Name]));
 
 			ptp_debug (params, "event %d: request object transfer oid %08lx, ofc %04x, size %d, filename %p", 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 */
+		case PTP_EC_CANON_EOS_AvailListChanged: {	/* property desc */
 			uint32_t	proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
 			uint32_t	propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
 			uint32_t	propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
@@ -1667,6 +1966,11 @@ ptp_unpack_CANON_changes (PTPParams *par
 			unsigned int	j;
 			PTPDevicePropDesc	*dpd;
 
+			if (size < PTP_ece_Prop_Desc_Data) {
+				ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Desc_Data);
+				break;
+			}
+
 			ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d, propxtype %d", i, proptype, size-PTP_ece_Prop_Desc_Data, propxtype);
 			for (j=0;j<params->nrofcanon_props;j++)
 				if (params->canon_props[j].proptype == proptype)
@@ -1681,7 +1985,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 			 * 7 - string?
 			 */
 			if (propxtype != 3) {
-				ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
+				ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled, size %d", i, propxtype, proptype, size);
 				for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
 					ptp_debug (params, "    %d: %02x", j, xdata[j]);
 				break;
@@ -1695,7 +1999,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 				   i, propxtype, proptype, dpd->DataType, propxcnt);
 			dpd->FormFlag = PTP_DPFF_Enumeration;
 			dpd->FORM.Enum.NumberOfValues = propxcnt;
-			if (dpd->FORM.Enum.SupportedValue) free (dpd->FORM.Enum.SupportedValue);
+			free (dpd->FORM.Enum.SupportedValue);
 			dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
 
 			switch (proptype) {
@@ -1714,8 +2018,12 @@ ptp_unpack_CANON_changes (PTPParams *par
 				/* 'normal' enumerated types */
 				switch (dpd->DataType) {
 #define XX( TYPE, CONV )\
-					for (j=0;j<propxcnt;j++) { \
-						dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \
+					if (sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data > size) {	\
+						ptp_debug (params, "size %d does not match needed %d", sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data, size);	\
+						break;							\
+					}								\
+					for (j=0;j<propxcnt;j++) { 					\
+						dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); 	\
 						ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \
 						xdata += 4; /* might only be for propxtype 3 */ \
 					} \
@@ -1727,7 +2035,10 @@ ptp_unpack_CANON_changes (PTPParams *par
 				case PTP_DTC_UINT8:	XX( u8,  dtoh8a );
 #undef XX
 				default:
-					ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata));
+					free (dpd->FORM.Enum.SupportedValue);
+					dpd->FORM.Enum.SupportedValue = NULL;
+					dpd->FORM.Enum.NumberOfValues = 0;
+					ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, size %d, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata), size);
 					for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */
 						ptp_debug (params, "    %3d: 0x%8x", j, dtoh32a(xdata));
 					break;
@@ -1742,6 +2053,10 @@ ptp_unpack_CANON_changes (PTPParams *par
 				unsigned char	*xdata = &curdata[PTP_ece_Prop_Val_Data];
 				PTPDevicePropDesc	*dpd;
 
+				if (size < PTP_ece_Prop_Val_Data) {
+					ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Val_Data);
+					break;
+				}
 				ptp_debug (params, "event %d: EOS prop %04x info record, datasize is %d", i, proptype, size-PTP_ece_Prop_Val_Data);
 				for (j=0;j<params->nrofcanon_props;j++)
 					if (params->canon_props[j].proptype == proptype)
@@ -1750,6 +2065,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 					if (	(params->canon_props[j].size != size) ||
 						(memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
 						params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
+						params->canon_props[j].size = size;
 						memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
 					}
 				} else {
@@ -1757,7 +2073,6 @@ ptp_unpack_CANON_changes (PTPParams *par
 						params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
 					else
 						params->canon_props = malloc(sizeof(params->canon_props[0]));
-					params->canon_props[j].type = type;
 					params->canon_props[j].proptype = proptype;
 					params->canon_props[j].size = size;
 					params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
@@ -1823,6 +2138,9 @@ ptp_unpack_CANON_changes (PTPParams *par
 				case PTP_DPC_CANON_EOS_ModelID:
 				case PTP_DPC_CANON_EOS_LensID:
 				case PTP_DPC_CANON_EOS_StroboFiring:
+				case PTP_DPC_CANON_EOS_AFSelectFocusArea:
+				case PTP_DPC_CANON_EOS_ContinousAFMode:
+				case PTP_DPC_CANON_EOS_MirrorUpSetting:
 					dpd->DataType = PTP_DTC_UINT32;
 					break;
 				/* enumeration for AEM is never provided, but is available to set */
@@ -1846,12 +2164,13 @@ ptp_unpack_CANON_changes (PTPParams *par
 				case PTP_DPC_CANON_EOS_EVFMode:
 				case PTP_DPC_CANON_EOS_EVFOutputDevice:
 				case PTP_DPC_CANON_EOS_AutoPowerOff:
+				case PTP_DPC_CANON_EOS_EVFRecordStatus:
 					dpd->DataType = PTP_DTC_UINT16;
 					break;
 				case PTP_DPC_CANON_EOS_PictureStyle:
 				case PTP_DPC_CANON_EOS_WhiteBalance:
 				case PTP_DPC_CANON_EOS_MeteringMode:
-				case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
+				case PTP_DPC_CANON_EOS_ExpCompensation:
 					dpd->DataType = PTP_DTC_UINT8;
 					break;
 				case PTP_DPC_CANON_EOS_Owner:
@@ -1902,7 +2221,6 @@ ptp_unpack_CANON_changes (PTPParams *par
 				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:
@@ -1915,7 +2233,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 					if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
 						ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
 					for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
-						ptp_debug (params, "    %d: 0x%8x", j, ((uint32_t*)xdata)[j]);
+						ptp_debug (params, "    %d: 0x%8x", j, dtoh32a(xdata+j*4));
 					break;
 				/* ImageFormat properties have to be ignored here, see special handling below */
 				case PTP_DPC_CANON_EOS_ImageFormat:
@@ -1923,6 +2241,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 				case PTP_DPC_CANON_EOS_ImageFormatSD:
 				case PTP_DPC_CANON_EOS_ImageFormatExtHD:
 				case PTP_DPC_CANON_EOS_CustomFuncEx:
+				case PTP_DPC_CANON_EOS_FocusInfoEx:
 					break;
 				default:
 					ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
@@ -1951,16 +2270,21 @@ ptp_unpack_CANON_changes (PTPParams *par
 					dpd->CurrentValue.u8		= dtoh8a(xdata);
 					ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
 					break;
+				case PTP_DTC_INT8:
+					dpd->FactoryDefaultValue.i8	= dtoh8a(xdata);
+					dpd->CurrentValue.i8		= dtoh8a(xdata);
+					ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.i8);
+					break;
 				case PTP_DTC_STR: {
 #if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
 					uint8_t len = 0;
 					dpd->FactoryDefaultValue.str	= ptp_unpack_string(params, data, 0, &len);
 					dpd->CurrentValue.str		= ptp_unpack_string(params, data, 0, &len);
 #else
-					if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
+					free (dpd->FactoryDefaultValue.str);
 					dpd->FactoryDefaultValue.str	= strdup( (char*)xdata );
 
-					if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
+					free (dpd->CurrentValue.str);
 					dpd->CurrentValue.str		= strdup( (char*)xdata );
 #endif
 					ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
@@ -1984,12 +2308,20 @@ ptp_unpack_CANON_changes (PTPParams *par
 					break;
 				case PTP_DPC_CANON_EOS_CustomFuncEx:
 					dpd->DataType = PTP_DTC_STR;
-					if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
-					if (dpd->CurrentValue.str)	  free (dpd->CurrentValue.str);
-					dpd->FactoryDefaultValue.str	= ptp_unpack_EOS_CustomFuncEx( params, &data );
+					free (dpd->FactoryDefaultValue.str);
+					free (dpd->CurrentValue.str);
+					dpd->FactoryDefaultValue.str	= ptp_unpack_EOS_CustomFuncEx( params, &xdata );
 					dpd->CurrentValue.str		= strdup( (char*)dpd->FactoryDefaultValue.str );
 					ptp_debug (params,"event %d: decoded custom function, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
 					break;
+				case PTP_DPC_CANON_EOS_FocusInfoEx:
+					dpd->DataType = PTP_DTC_STR;
+					free (dpd->FactoryDefaultValue.str);
+					free (dpd->CurrentValue.str);
+					dpd->FactoryDefaultValue.str	= ptp_unpack_EOS_FocusInfoEx( params, &xdata, size );
+					dpd->CurrentValue.str		= strdup( (char*)dpd->FactoryDefaultValue.str );
+					ptp_debug (params,"event %d: decoded focus info, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
+					break;
 				}
 
 				break;
@@ -1998,23 +2330,29 @@ ptp_unpack_CANON_changes (PTPParams *par
 		case PTP_EC_CANON_EOS_OLCInfoChanged: {
 			uint32_t		len, curoff;
 			uint16_t		mask,proptype;
-			unsigned int		j;
 			PTPDevicePropDesc	*dpd;
 
 			/* unclear what OLC stands for */
 			ptp_debug (params, "event %d: EOS event OLCInfoChanged (size %d)", i, size);
 			if (size >= 0x8) {	/* event info */
-				unsigned int j;
-				for (j=8;j<size;j++)
-					ptp_debug (params, "    %d: %02x", j-8, curdata[j]);
+				unsigned int k;
+				for (k=8;k<size;k++)
+					ptp_debug (params, "    %d: %02x", k-8, curdata[k]);
 			}
 			len = dtoh32a(curdata+8);
-			if (len != size-8) {
+			if ((len != size-8) && (len != size-4)) {
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
-				ptp_debug (params, "event %d: size %d, len %d", i, size, len);
+				ce[i].u.info = strdup("OLC size unexpected");
+				ptp_debug (params, "event %d: OLC unexpected size %d for blob len %d (not -4 nor -8)", i, size, len);
 				break;
 			}
 			mask = dtoh16a(curdata+8+4);
+			if (size < 14) {
+				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
+				ce[i].u.info = strdup("OLC size too small");
+				ptp_debug (params, "event %d: OLC unexpected size %d", i, size);
+				break;
+			}
 			curoff = 8+4+4;
 			if (mask & CANON_EOS_OLC_BUTTON) {
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
@@ -2028,13 +2366,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 				/* 6 bytes: 01 01 98 10 00 60 */
 				/* this seesm to be the shutter speed record */
 				proptype = PTP_DPC_CANON_EOS_ShutterSpeed;
-				for (j=0;j<params->nrofcanon_props;j++)
-					if (params->canon_props[j].proptype == proptype)
-						break;
-				if (j == params->nrofcanon_props)
-					ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
-
-				dpd = &params->canon_props[j].dpd;
+				dpd = _lookup_or_allocate_canon_prop(params, proptype);
 				dpd->CurrentValue.u16 = curdata[curoff+5]; /* just use last byte */
 
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
@@ -2046,13 +2378,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 				/* 5 bytes: 01 01 5b 30 30 */
 				/* this seesm to be the aperture record */
 				proptype = PTP_DPC_CANON_EOS_Aperture;
-				for (j=0;j<params->nrofcanon_props;j++)
-					if (params->canon_props[j].proptype == proptype)
-						break;
-				if (j == params->nrofcanon_props)
-					ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
-
-				dpd = &params->canon_props[j].dpd;
+				dpd = _lookup_or_allocate_canon_prop(params, proptype);
 				dpd->CurrentValue.u16 = curdata[curoff+4]; /* just use last byte */
 
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
@@ -2064,13 +2390,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 				/* 5 bytes: 01 01 00 78 */
 				/* this seesm to be the aperture record */
 				proptype = PTP_DPC_CANON_EOS_ISOSpeed;
-				for (j=0;j<params->nrofcanon_props;j++)
-					if (params->canon_props[j].proptype == proptype)
-						break;
-				if (j == params->nrofcanon_props)
-					ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
-
-				dpd = &params->canon_props[j].dpd;
+				dpd = _lookup_or_allocate_canon_prop(params, proptype);
 				dpd->CurrentValue.u16 = curdata[curoff+3]; /* just use last byte */
 
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
@@ -2107,13 +2427,15 @@ ptp_unpack_CANON_changes (PTPParams *par
 				i++;
 			}
 			if (mask & 0x0040) {
+				int	value = (signed char)curdata[curoff+2];
 				/* mask 0x0040: 7 bytes, 01 01 00 00 00 00 00 observed */
+				/* exposure indicator */
 				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
-				ce[i].u.info = malloc(strlen("OLCInfo event 0x0040 content 0123456789abcd")+1); 
-				sprintf(ce[i].u.info,"OLCInfo event 0x0040 content %02x%02x%02x%02x%02x%02x%02x",
+				ce[i].u.info = malloc(strlen("OLCInfo exposure indicator 012345678901234567890123456789abcd")+1); 
+				sprintf(ce[i].u.info,"OLCInfo exposure indicator %d,%d,%d.%d (%02x%02x%02x%02x)",
 					curdata[curoff],
 					curdata[curoff+1],
-					curdata[curoff+2],
+					value/10,abs(value)%10,
 					curdata[curoff+3],
 					curdata[curoff+4],
 					curdata[curoff+5],
@@ -2137,9 +2459,9 @@ ptp_unpack_CANON_changes (PTPParams *par
 			}
 			if (mask & 0x0100) {
 				/* mask 0x0100: 6 bytes, 00 00 00 00 00 00 (before focus) and 00 00 00 00 01 00 (on focus) observed */
-				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
-				ce[i].u.info = malloc(strlen("OLCInfo event 0x0100 content 0123456789ab")+1); 
-				sprintf(ce[i].u.info,"OLCInfo event 0x0100 content %02x%02x%02x%02x%02x%02x",
+				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_FOCUSINFO;
+				ce[i].u.info = malloc(strlen("0123456789ab")+1); 
+				sprintf(ce[i].u.info,"%02x%02x%02x%02x%02x%02x",
 					curdata[curoff],
 					curdata[curoff+1],
 					curdata[curoff+2],
@@ -2152,9 +2474,9 @@ ptp_unpack_CANON_changes (PTPParams *par
 			}
 			if (mask & 0x0200) {
 				/* mask 0x0200: 7 bytes, 00 00 00 00 00 00 00 observed */
-				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
-				ce[i].u.info = malloc(strlen("OLCInfo event 0x0200 content 0123456789abcd")+1); 
-				sprintf(ce[i].u.info,"OLCInfo event 0x0200 content %02x%02x%02x%02x%02x%02x%02x",
+				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_FOCUSMASK;
+				ce[i].u.info = malloc(strlen("0123456789abcd0123456789abcdef")+1); 
+				sprintf(ce[i].u.info,"%02x%02x%02x%02x%02x%02x%02x",
 					curdata[curoff],
 					curdata[curoff+1],
 					curdata[curoff+2],
@@ -2229,9 +2551,13 @@ ptp_unpack_CANON_changes (PTPParams *par
 			break;
 		case PTP_EC_CANON_EOS_BulbExposureTime:
 			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
-			ce[i].u.info = malloc(strlen("BulbExposureTime 123456789"));
+			ce[i].u.info = malloc(strlen("BulbExposureTime 123456789012345678"));
 			sprintf (ce[i].u.info, "BulbExposureTime %d",  dtoh32a(curdata+8));
 			break;
+		case PTP_EC_CANON_EOS_ObjectRemoved:
+			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTREMOVED;
+			ce[i].u.object.oid = dtoh32a(curdata+8);
+			break;
 		default:
 			switch (type) {
 #define XX(x)		case PTP_EC_CANON_EOS_##x: 								\
@@ -2240,7 +2566,6 @@ ptp_unpack_CANON_changes (PTPParams *par
 				sprintf (ce[i].u.info, "unhandled EOS event "#x" (size %d)",  size);		\
 				break;
 			XX(RequestGetEvent)
-			XX(ObjectRemoved)
 			XX(RequestGetObjectInfoEx)
 			XX(StorageStatusChanged)
 			XX(StorageInfoChanged)
@@ -2264,6 +2589,7 @@ ptp_unpack_CANON_changes (PTPParams *par
 			}
 			if (size >= 0x8) {	/* event info */
 				unsigned int j;
+				/*ptp_debug (params, "data=%p, curdata=%p, datsize=%d, size=%d", data, curdata, datasize, size);*/
 				for (j=8;j<size;j++)
 					ptp_debug (params, "    %d: %02x", j, curdata[j]);
 			}
@@ -2271,9 +2597,10 @@ ptp_unpack_CANON_changes (PTPParams *par
 			break;
 		}
 		curdata += size;
-		if ((size == 8) && (type == 0))
-			break;
 		i++;
+		if (i >= entries) {
+			ptp_debug (params, "BAD: i %d, entries %d", i, entries);
+		}
 	}
 	if (!i) {
 		free (ce);
@@ -2301,8 +2628,10 @@ ptp_unpack_Nikon_EC (PTPParams *params,
 	if (len < PTP_nikon_ec_Code)
 		return;
 	*cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
-	if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
+	if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) { /* broken cnt? */
+		*cnt = 0;
 		return;
+	}
 	if (!*cnt)
 		return;
 
@@ -2397,11 +2726,11 @@ ptp_unpack_canon_directory (
 	for (i=0;i<cnt;i++)
 		if (ISOBJECT(dir+i*0x4c)) nrofobs++;
 	handles->n = nrofobs;
-	handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
+	handles->Handler = calloc(nrofobs,sizeof(handles->Handler[0]));
 	if (!handles->Handler) return PTP_RC_GeneralError;
-	*oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
+	*oinfos = calloc(nrofobs,sizeof((*oinfos)[0]));
 	if (!*oinfos) return PTP_RC_GeneralError;
-	*flags  = calloc(sizeof((*flags)[0]),nrofobs);
+	*flags  = calloc(nrofobs,sizeof((*flags)[0]));
 	if (!*flags) return PTP_RC_GeneralError;
 
 	/* Migrate data into objects ids, handles into
--- libmtp-1.1.8/src/ptp.c.orig	2014-06-02 15:44:03.000000000 -0400
+++ libmtp-1.1.8/src/ptp.c	2017-07-08 14:39:19.240864345 -0400
@@ -1,7 +1,7 @@
 /* ptp.c
  *
  * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
- * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
  * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
  * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
  * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
@@ -22,7 +22,7 @@
  * Boston, MA  02110-1301  USA
  */
 
-#define _BSD_SOURCE
+#define _DEFAULT_SOURCE
 #include "config.h"
 #include "ptp.h"
 
@@ -34,7 +34,9 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
 
 #ifdef ENABLE_NLS
 #  include <libintl.h>
@@ -55,9 +57,29 @@
 #  define N_(String) (String)
 #endif
 
-#define CHECK_PTP_RC(result)	{uint16_t r=(result); if (r!=PTP_RC_OK) return r;}
+#define CHECK_PTP_RC(RESULT) do { uint16_t r = (RESULT); if (r != PTP_RC_OK) return r; } while(0)
+
+static inline void
+ptp_init_container(PTPContainer* ptp, uint16_t code, int n_param, ...)
+{
+	va_list	args;
+	int	i;
+
+	memset(ptp, 0, sizeof(*ptp));
+	ptp->Code = code;
+	ptp->Nparam = n_param;
+
+	va_start(args, n_param);
+	for (i=0; i<n_param; ++i)
+		(&ptp->Param1)[i] = va_arg(args, uint32_t);
+	va_end(args);
+}
+
+#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
+#define NARGS(...) NARGS_SEQ(-1, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0)
 
-#define PTP_CNT_INIT(cnt) {memset(&cnt,0,sizeof(cnt));}
+#define PTP_CNT_INIT(PTP, CODE, ...) \
+	ptp_init_container(&PTP, CODE, NARGS(__VA_ARGS__), ##__VA_ARGS__)
 
 static uint16_t ptp_exit_recv_memory_handler (PTPDataHandler*,unsigned char**,unsigned long*);
 static uint16_t ptp_init_recv_memory_handler(PTPDataHandler*);
@@ -104,12 +126,6 @@ ptp_error (PTPParams *params, const char
 
 /* major PTP functions */
 
-/* Transaction data phase description */
-#define PTP_DP_NODATA		0x0000	/* no data phase */
-#define PTP_DP_SENDDATA		0x0001	/* sending data */
-#define PTP_DP_GETDATA		0x0002	/* receiving data */
-#define PTP_DP_DATA_MASK	0x00ff	/* data phase mask */
-
 /**
  * ptp_transaction:
  * params:	PTPParams*
@@ -153,36 +169,23 @@ ptp_transaction_new (PTPParams* params,
 	ptp->Transaction_ID=params->transaction_id++;
 	ptp->SessionID=params->session_id;
 	/* send request */
-	CHECK_PTP_RC(params->sendreq_func (params, ptp));
+	CHECK_PTP_RC(params->sendreq_func (params, ptp, flags));
 	/* is there a dataphase? */
 	switch (flags&PTP_DP_DATA_MASK) {
 	case PTP_DP_SENDDATA:
 		{
-			uint16_t ret;
-			ret = params->senddata_func(params, ptp,
-						    sendlen, handler);
-			if (ret == PTP_ERROR_CANCEL) {
-				ret = params->cancelreq_func(params, 
-							     params->transaction_id-1);
-				if (ret == PTP_RC_OK)
-					ret = PTP_ERROR_CANCEL;
-			}
-			if (ret != PTP_RC_OK)
-				return ret;
+			uint16_t ret = params->senddata_func(params, ptp, sendlen, handler);
+			if (ret == PTP_ERROR_CANCEL)
+				CHECK_PTP_RC(params->cancelreq_func(params, params->transaction_id-1));
+			CHECK_PTP_RC(ret);
 		}
 		break;
 	case PTP_DP_GETDATA:
 		{
-			uint16_t ret;
-			ret = params->getdata_func(params, ptp, handler);
-			if (ret == PTP_ERROR_CANCEL) {
-				ret = params->cancelreq_func(params, 
-							     params->transaction_id-1);
-				if (ret == PTP_RC_OK)
-					ret = PTP_ERROR_CANCEL;
-			}
-			if (ret != PTP_RC_OK)
-				return ret;
+			uint16_t ret = params->getdata_func(params, ptp, handler);
+			if (ret == PTP_ERROR_CANCEL)
+				CHECK_PTP_RC(params->cancelreq_func(params, params->transaction_id-1));
+			CHECK_PTP_RC(ret);
 		}
 		break;
 	case PTP_DP_NODATA:
@@ -200,10 +203,12 @@ ptp_transaction_new (PTPParams* params,
 			tries++;
 			continue;
 		}
-		if (ret != PTP_RC_OK)
-			return ret;
-		
+		CHECK_PTP_RC(ret);
+
 		if (ptp->Transaction_ID < params->transaction_id-1) {
+			/* The Leica uses Transaction ID 0 on result from CloseSession. */
+			if (cmd == PTP_OC_CloseSession)
+				break;
 			tries++;
 			ptp_debug (params,
 				"PTP: Sequence number mismatch %d vs expected %d, suspecting old reply.",
@@ -219,7 +224,9 @@ ptp_transaction_new (PTPParams* params,
 				"PTP: Sequence number mismatch %d vs expected %d.",
 				ptp->Transaction_ID, params->transaction_id-1
 			);
+#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 			return PTP_ERROR_BADPARAM;
+#endif
 		}
 		break;
 	}
@@ -305,7 +311,8 @@ ptp_init_send_memory_handler(PTPDataHand
 
 /* free private struct + data */
 static uint16_t
-ptp_exit_send_memory_handler (PTPDataHandler *handler) {
+ptp_exit_send_memory_handler (PTPDataHandler *handler)
+{
 	PTPMemHandlerPrivate* priv = (PTPMemHandlerPrivate*)handler->priv;
 	/* data is owned by caller */
 	free (priv);
@@ -350,7 +357,7 @@ fd_putfunc(PTPParams* params, void* private,
 	       unsigned long sendlen, unsigned char *data,
 	       unsigned long *putlen
 ) {
-	int		written;
+	ssize_t		written;
 	PTPFDHandlerPrivate* priv = (PTPFDHandlerPrivate*)private;
 
 	written = write (priv->fd, data, sendlen);
@@ -357,7 +364,7 @@ fd_putfunc(PTPParams* params, void* private,
 	if (written != -1)
 		*putlen = written;
 	else
-		return PTP_RC_GeneralError;
+		return PTP_ERROR_IO;
 	return PTP_RC_OK;
 }
 
@@ -375,13 +380,22 @@ ptp_init_fd_handler(PTPDataHandler *hand
 }
 
 static uint16_t
-ptp_exit_fd_handler (PTPDataHandler *handler) {
+ptp_exit_fd_handler (PTPDataHandler *handler)
+{
 	PTPFDHandlerPrivate* priv = (PTPFDHandlerPrivate*)handler->priv;
 	free (priv);
 	return PTP_RC_OK;
 }
 
 /* Old style transaction, based on memory */
+/* A note on memory management:
+ * If called with the flag PTP_DP_GETDATA, this function will internally
+ * allocate memory as much as necessary. The caller has to free the memory
+ * returned in *data. If the function returns an error, it will free any
+ * memory it might have allocated. The recvlen may be NULL. After the
+ * function returns, *data will be initialized (valid memory pointer or NULL),
+ * i.e. it is not necessary to initialize *data or *recvlen beforehand.
+ */
 uint16_t
 ptp_transaction (PTPParams* params, PTPContainer* ptp, 
 		uint16_t flags, uint64_t sendlen,
@@ -392,12 +406,17 @@ ptp_transaction (PTPParams* params, PTPC
 
 	switch (flags & PTP_DP_DATA_MASK) {
 	case PTP_DP_SENDDATA:
-		ret = ptp_init_send_memory_handler (&handler, *data, sendlen);
-		if (ret != PTP_RC_OK) return ret;
+		if (!data)
+			return PTP_ERROR_BADPARAM;
+		CHECK_PTP_RC(ptp_init_send_memory_handler (&handler, *data, sendlen));
 		break;
 	case PTP_DP_GETDATA:
-		ret = ptp_init_recv_memory_handler (&handler);
-		if (ret != PTP_RC_OK) return ret;
+		if (!data)
+			return PTP_ERROR_BADPARAM;
+		*data = NULL;
+		if (recvlen)
+			*recvlen = 0;
+		CHECK_PTP_RC(ptp_init_recv_memory_handler (&handler));
 		break;
 	default:break;
 	}
@@ -409,6 +428,11 @@ ptp_transaction (PTPParams* params, PTPC
 	case PTP_DP_GETDATA: {
 		unsigned long len;
 		ptp_exit_recv_memory_handler (&handler, data, &len);
+		if (ret != PTP_RC_OK) {
+			len = 0;
+			free(*data);
+			*data = NULL;
+		}
 		if (recvlen)
 			*recvlen = len;
 		break;
@@ -438,53 +462,46 @@ ptp_transaction (PTPParams* params, PTPC
 uint16_t
 ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo)
 {
-	uint16_t 	ret;
-	unsigned long	len;
 	PTPContainer	ptp;
-	unsigned char*	di=NULL;
-	PTPDataHandler	handler;
+	unsigned char	*data;
+	unsigned int	size;
+	int		ret;
 
-	ptp_init_recv_memory_handler (&handler);
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetDeviceInfo;
-	ptp.Nparam=0;
-	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;
+	PTP_CNT_INIT(ptp, PTP_OC_GetDeviceInfo);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ret = ptp_unpack_DI(params, data, deviceinfo, size);
+	free(data);
+	if (ret)
+		return PTP_RC_OK;
+	else
+		return PTP_ERROR_IO;
 }
 
 uint16_t
 ptp_canon_eos_getdeviceinfo (PTPParams* params, PTPCanonEOSDeviceInfo*di)
 {
-	uint16_t 	ret;
 	PTPContainer	ptp;
-	PTPDataHandler	handler;
-	unsigned long	len;
 	unsigned char	*data;
+	unsigned int	size;
+	int		ret;
 
-	ptp_init_recv_memory_handler (&handler);
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_EOS_GetDeviceInfoEx;
-	ptp.Nparam=0;
-	len=0;
-	data=NULL;
-	ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
-	ptp_exit_recv_memory_handler (&handler, &data, &len);
-	if (ret == PTP_RC_OK) ptp_unpack_EOS_DI(params, data, di, len);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetDeviceInfoEx);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ret = ptp_unpack_EOS_DI(params, data, di, size);
 	free (data);
-	return ret;
+	if (ret)
+		return PTP_RC_OK;
+	else
+		return PTP_ERROR_IO;
 }
 
 #ifdef HAVE_LIBXML2
 static int
-traverse_tree (PTPParams *params, int depth, xmlNodePtr node) {
+traverse_tree (PTPParams *params, int depth, xmlNodePtr node)
+{
 	xmlNodePtr	next;
 	xmlChar		*xchar;
-	int n;
+	int		n;
 	char 		*xx;
 
 
@@ -508,9 +525,10 @@ traverse_tree (PTPParams *params, int de
 }
 
 static int
-parse_9301_cmd_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di) {
-	xmlNodePtr next;
-	int	cnt;
+parse_9301_cmd_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di)
+{
+	xmlNodePtr	next;
+	int		cnt;
 
 	cnt = 0;
 	next = xmlFirstElementChild (node);
@@ -534,7 +552,8 @@ parse_9301_cmd_tree (PTPParams *params,
 }
 
 static int
-parse_9301_value (PTPParams *params, const char *str, uint16_t type, PTPPropertyValue *propval) {
+parse_9301_value (PTPParams *params, const char *str, uint16_t type, PTPPropertyValue *propval)
+{
 	switch (type) {
 	case 6: { /*UINT32*/
 		unsigned int x;
@@ -632,7 +651,8 @@ parse_9301_value (PTPParams *params, con
 }
 
 static int
-parse_9301_propdesc (PTPParams *params, xmlNodePtr next, PTPDevicePropDesc *dpd) {
+parse_9301_propdesc (PTPParams *params, xmlNodePtr next, PTPDevicePropDesc *dpd)
+{
 	int type = -1;
 
 	if (!next)
@@ -720,7 +740,8 @@ parse_9301_propdesc (PTPParams *params,
 }
 
 static int
-parse_9301_prop_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di) {
+parse_9301_prop_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di)
+{
 	xmlNodePtr	next;
 	int		cnt;
 	unsigned int	i;
@@ -751,10 +772,7 @@ parse_9301_prop_tree (PTPParams *params,
 			if (params->deviceproperties[i].desc.DevicePropertyCode == p)
 				break;
 		if (i == params->nrofdeviceproperties) {
-			if (!i)
-				params->deviceproperties = malloc(sizeof(params->deviceproperties[0]));
-			else
-				params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
+			params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
 			memset(&params->deviceproperties[i],0,sizeof(params->deviceproperties[0]));
 			params->nrofdeviceproperties++;
 		} else {
@@ -771,9 +789,10 @@ parse_9301_prop_tree (PTPParams *params,
 }
 
 static int
-parse_9301_event_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di) {
-	xmlNodePtr next;
-	int	cnt;
+parse_9301_event_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di)
+{
+	xmlNodePtr	next;
+	int		cnt;
 
 	cnt = 0;
 	next = xmlFirstElementChild (node);
@@ -797,7 +816,8 @@ parse_9301_event_tree (PTPParams *params
 }
 
 static int
-parse_9301_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di) {
+parse_9301_tree (PTPParams *params, xmlNodePtr node, PTPDeviceInfo *di)
+{
 	xmlNodePtr	next;
 
 	next = xmlFirstElementChild (node);
@@ -825,7 +845,8 @@ parse_9301_tree (PTPParams *params, xmlN
 }
 
 static uint16_t
-ptp_olympus_parse_output_xml(PTPParams* params, char*data, int len, xmlNodePtr *code) {
+ptp_olympus_parse_output_xml(PTPParams* params, char*data, int len, xmlNodePtr *code)
+{
         xmlDocPtr       docin;
         xmlNodePtr      docroot, output, next;
 	int 		result, xcode;
@@ -893,26 +914,19 @@ uint16_t
 ptp_olympus_getdeviceinfo (PTPParams* params, PTPDeviceInfo *di)
 {
 #ifdef HAVE_LIBXML2
-	uint16_t 	ret;
 	PTPContainer	ptp;
-	PTPDataHandler	handler;
+	uint16_t 	ret;
 	unsigned char	*data;
-	unsigned long	len;
+	unsigned int	size;
 	xmlNodePtr	code;
 
 	memset (di, 0, sizeof(PTPDeviceInfo));
-	ptp_init_recv_memory_handler (&handler);
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_OLYMPUS_GetDeviceInfo;
-	ptp.Nparam = 0;
-	len	   = 0;
-	data       = NULL;
-	ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
 
-	ptp_exit_recv_memory_handler (&handler, &data, &len);
-
-	ret = ptp_olympus_parse_output_xml(params,(char*)data,len,&code);
+	PTP_CNT_INIT(ptp, PTP_OC_OLYMPUS_GetDeviceInfo);
+	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
+	/* TODO: check for error, only parse_output_xml if ret == PTP_RC_OK?
+	 * where is 'data' going to be deallocated? */
+	ret = ptp_olympus_parse_output_xml(params,(char*)data,size,&code);
 	if (ret != PTP_RC_OK)
 		return ret;
 
@@ -926,39 +940,21 @@ ptp_olympus_getdeviceinfo (PTPParams* pa
 }
 
 uint16_t
-ptp_olympus_opensession (PTPParams* params, unsigned char**data, unsigned long *len)
+ptp_olympus_opensession (PTPParams* params, unsigned char**data, unsigned int *len)
 {
-	uint16_t 	ret;
 	PTPContainer	ptp;
-	PTPDataHandler	handler;
 
-	ptp_init_recv_memory_handler (&handler);
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_OLYMPUS_OpenSession;
-	ptp.Nparam = 0;
-	*len	   = 0;
-	*data      = NULL;
-	ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
-	ptp_exit_recv_memory_handler (&handler, data, len);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_OLYMPUS_OpenSession);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, len);
 }
 
 uint16_t
-ptp_olympus_getcameraid (PTPParams* params, unsigned char**data, unsigned long *len)
+ptp_olympus_getcameraid (PTPParams* params, unsigned char**data, unsigned int *len)
 {
-	uint16_t 	ret;
 	PTPContainer	ptp;
-	PTPDataHandler	handler;
 
-	ptp_init_recv_memory_handler (&handler);
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_OLYMPUS_GetCameraID;
-	ptp.Nparam = 0;
-	*len	   = 0;
-	*data       = NULL;
-	ret=ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
-	ptp_exit_recv_memory_handler (&handler, data, len);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_OLYMPUS_GetCameraID);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, len);
 }
 
 /**
@@ -975,14 +971,14 @@ ptp_olympus_getcameraid (PTPParams* para
 uint16_t
 ptp_generic_no_data (PTPParams* params, uint16_t code, unsigned int n_param, ...)
 {
-	PTPContainer ptp;
-	va_list args;
-	unsigned int i;
+	PTPContainer	ptp;
+	va_list		args;
+	unsigned int	i;
 
 	if( n_param > 5 )
-		return PTP_RC_InvalidParameter;
+		return PTP_ERROR_BADPARAM;
 
-	PTP_CNT_INIT(ptp);
+	memset(&ptp, 0, sizeof(ptp));
 	ptp.Code=code;
 	ptp.Nparam=n_param;
 
@@ -1006,8 +1002,8 @@ ptp_generic_no_data (PTPParams* params,
 uint16_t
 ptp_opensession (PTPParams* params, uint32_t session)
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
+	uint16_t	ret;
 
 	ptp_debug(params,"PTP: Opening session");
 
@@ -1022,18 +1018,17 @@ ptp_opensession (PTPParams* params, uint
 	/* no split headers */
 	params->split_header_data = 0;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_OpenSession;
-	ptp.Param1=session;
-	ptp.Nparam=1;
+	PTP_CNT_INIT(ptp, PTP_OC_OpenSession, session);
 	ret=ptp_transaction_new(params, &ptp, PTP_DP_NODATA, 0, NULL);
+	/* TODO: check for error */
 	/* now set the global session id to current session number */
 	params->session_id=session;
 	return ret;
 }
 
 void
-ptp_free_devicepropvalue(uint16_t dt, PTPPropertyValue* dpd) {
+ptp_free_devicepropvalue(uint16_t dt, PTPPropertyValue* dpd)
+{
 	switch (dt) {
 	case PTP_DTC_INT8:	case PTP_DTC_UINT8:
 	case PTP_DTC_UINT16:	case PTP_DTC_INT16:
@@ -1047,12 +1042,10 @@ ptp_free_devicepropvalue(uint16_t dt, PT
 	case PTP_DTC_AUINT32:	case PTP_DTC_AINT32:
 	case PTP_DTC_AUINT64:	case PTP_DTC_AINT64:
 	case PTP_DTC_AUINT128:	case PTP_DTC_AINT128:
-		if (dpd->a.v)
-			free(dpd->a.v);
+		free(dpd->a.v);
 		break;
 	case PTP_DTC_STR:
-		if (dpd->str)
-			free(dpd->str);
+		free(dpd->str);
 		break;
 	}
 }
@@ -1126,14 +1119,16 @@ ptp_free_objectpropdesc(PTPObjectPropDes
  * Return values: Some PTP_RC_* code.
  **/
 void
-ptp_free_params (PTPParams *params) {
+ptp_free_params (PTPParams *params)
+{
 	unsigned int i;
 
-	if (params->cameraname) free (params->cameraname);
-	if (params->wifi_profiles) free (params->wifi_profiles);
+	free (params->cameraname);
+	free (params->wifi_profiles);
 	for (i=0;i<params->nrofobjects;i++)
 		ptp_free_object (&params->objects[i]);
 	free (params->objects);
+	free (params->storageids.Storage);
 	free (params->events);
 	for (i=0;i<params->nrofcanon_props;i++) {
 		free (params->canon_props[i].data);
@@ -1160,19 +1155,15 @@ ptp_free_params (PTPParams *params) {
 uint16_t
 ptp_getstorageids (PTPParams* params, PTPStorageIDs* storageids)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned int len;
-	unsigned char* sids=NULL;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetStorageIDs;
-	ptp.Nparam=0;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &sids, &len);
-	if (ret == PTP_RC_OK) ptp_unpack_SIDs(params, sids, storageids, len);
-	free(sids);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_GetStorageIDs);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ptp_unpack_SIDs(params, data, storageids, size);
+	free(data);
+	return PTP_RC_OK;
 }
 
 /**
@@ -1189,20 +1180,21 @@ uint16_t
 ptp_getstorageinfo (PTPParams* params, uint32_t storageid,
 			PTPStorageInfo* storageinfo)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* si=NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetStorageInfo;
-	ptp.Param1=storageid;
-	ptp.Nparam=1;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &si, &len);
-	if (ret == PTP_RC_OK) ptp_unpack_SI(params, si, storageinfo, len);
-	free(si);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_GetStorageInfo, storageid);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	if (!data || !size)
+		return PTP_RC_GeneralError;
+	memset(storageinfo, 0, sizeof(*storageinfo));
+	if (!ptp_unpack_SI(params, data, storageinfo, size)) {
+		free(data);
+		return PTP_RC_GeneralError;
+	}
+	free(data);
+	return PTP_RC_OK;
 }
 
 /**
@@ -1224,21 +1216,18 @@ ptp_getobjecthandles (PTPParams* params,
 			uint32_t objectformatcode, uint32_t associationOH,
 			PTPObjectHandles* objecthandles)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* oh=NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetObjectHandles;
-	ptp.Param1=storage;
-	ptp.Param2=objectformatcode;
-	ptp.Param3=associationOH;
-	ptp.Nparam=3;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oh, &len);
+	objecthandles->Handler = NULL;
+	objecthandles->n = 0;
+
+	PTP_CNT_INIT(ptp, PTP_OC_GetObjectHandles, storage, objectformatcode, associationOH);
+	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
 	if (ret == PTP_RC_OK) {
-		ptp_unpack_OH(params, oh, objecthandles, len);
+		ptp_unpack_OH(params, data, objecthandles, size);
 	} else {
 		if (	(storage == 0xffffffff) &&
 			(objectformatcode == 0) &&
@@ -1252,7 +1241,7 @@ ptp_getobjecthandles (PTPParams* params,
 			ret = PTP_RC_OK;
 		}
 	}
-	free(oh);
+	free(data);
 	return ret;
 }
 
@@ -1261,19 +1250,10 @@ ptp_getfilesystemmanifest (PTPParams* pa
 			uint32_t objectformatcode, uint32_t associationOH,
 			unsigned char** data)
 {
-	uint16_t ret;
 	PTPContainer ptp;
-	unsigned int len;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetFilesystemManifest;
-	ptp.Param1=storage;
-	ptp.Param2=objectformatcode;
-	ptp.Param3=associationOH;
-	ptp.Nparam=3;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, &len);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_GetFilesystemManifest, storage, objectformatcode, associationOH);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, NULL);
 }
 
 /**
@@ -1295,23 +1275,15 @@ ptp_getnumobjects (PTPParams* params, ui
 			uint32_t objectformatcode, uint32_t associationOH,
 			uint32_t* numobs)
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetNumObjects;
-	ptp.Param1=storage;
-	ptp.Param2=objectformatcode;
-	ptp.Param3=associationOH;
-	ptp.Nparam=3;
-	ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if (ret == PTP_RC_OK) {
-		if (ptp.Nparam >= 1)
-			*numobs = ptp.Param1;
-		else
-			ret = PTP_RC_GeneralError;
-	}
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_GetNumObjects, storage, objectformatcode, associationOH);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
+	if (ptp.Nparam >= 1)
+		*numobs = ptp.Param1;
+	else
+		return PTP_RC_GeneralError;
+	return PTP_RC_OK;
 }
 
 /**
@@ -1325,16 +1297,13 @@ ptp_getnumobjects (PTPParams* params, ui
 uint16_t
 ptp_canon_eos_bulbstart (PTPParams* params)
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_EOS_BulbStart;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ((ret == PTP_RC_OK) && (ptp.Nparam >= 1) && ((ptp.Param1 & 0x7000) == 0x2000))
-		ret = ptp.Param1;
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_BulbStart);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
+	if ((ptp.Nparam >= 1) && ((ptp.Param1 & 0x7000) == 0x2000))
+		return ptp.Param1;
+	return PTP_RC_OK;
 }
 
 /**
@@ -1351,17 +1320,14 @@ ptp_canon_eos_bulbstart (PTPParams* para
 uint16_t
 ptp_canon_eos_capture (PTPParams* params, uint32_t *result)
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_EOS_RemoteRelease;
-	ptp.Nparam = 0;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_RemoteRelease);
 	*result = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ((ret == PTP_RC_OK) && (ptp.Nparam >= 1))
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
+	if (ptp.Nparam >= 1)
 		*result = ptp.Param1;
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -1375,16 +1341,13 @@ ptp_canon_eos_capture (PTPParams* params
 uint16_t
 ptp_canon_eos_bulbend (PTPParams* params)
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_EOS_BulbEnd;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ((ret == PTP_RC_OK) && (ptp.Nparam >= 1) && ((ptp.Param1 & 0x7000) == 0x2000))
-		ret = ptp.Param1;
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_BulbEnd);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
+	if ((ptp.Nparam >= 1) && ((ptp.Param1 & 0x7000) == 0x2000))
+		return ptp.Param1;
+	return PTP_RC_OK;
 }
 
 /**
@@ -1401,20 +1364,15 @@ uint16_t
 ptp_getobjectinfo (PTPParams* params, uint32_t handle,
 			PTPObjectInfo* objectinfo)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* oi=NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetObjectInfo;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &oi, &len);
-	if (ret == PTP_RC_OK) ptp_unpack_OI(params, oi, objectinfo, len);
-	free(oi);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_GetObjectInfo, handle);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ptp_unpack_OI(params, data, objectinfo, size);
+	free(data);
+	return PTP_RC_OK;
 }
 
 /**
@@ -1432,14 +1390,30 @@ uint16_t
 ptp_getobject (PTPParams* params, uint32_t handle, unsigned char** object)
 {
 	PTPContainer ptp;
-	unsigned int len;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetObject;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
-	len=0;
-	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, &len);
+	PTP_CNT_INIT(ptp, PTP_OC_GetObject, handle);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, NULL);
+}
+
+/**
+ * ptp_getobject_with_size:
+ * params:	PTPParams*
+ *		handle			- Object handle
+ *		object			- pointer to data area
+ *		size			- pointer to uint, returns size of object
+ *
+ * Get object 'handle' from device and store the data in newly
+ * allocated 'object'.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getobject_with_size (PTPParams* params, uint32_t handle, unsigned char** object, unsigned int *size)
+{
+	PTPContainer ptp;
+
+	PTP_CNT_INIT(ptp, PTP_OC_GetObject, handle);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, size);
 }
 
 /**
@@ -1458,10 +1432,7 @@ ptp_getobject_to_handler (PTPParams* par
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetObject;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
+	PTP_CNT_INIT(ptp, PTP_OC_GetObject, handle);
 	return ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, handler);
 }
 
@@ -1483,11 +1454,8 @@ ptp_getobject_tofd (PTPParams* params, u
 	PTPDataHandler	handler;
 	uint16_t	ret;
 
+	PTP_CNT_INIT(ptp, PTP_OC_GetObject, handle);
 	ptp_init_fd_handler (&handler, fd);
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetObject;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
 	ret = ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, &handler);
 	ptp_exit_fd_handler (&handler);
 	return ret;
@@ -1514,17 +1482,34 @@ ptp_getpartialobject (PTPParams* params,
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetPartialObject;
-	ptp.Param1=handle;
-	ptp.Param2=offset;
-	ptp.Param3=maxbytes;
-	ptp.Nparam=3;
-	*len=0;
+	PTP_CNT_INIT(ptp, PTP_OC_GetPartialObject, handle, offset, maxbytes);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, len);
 }
 
 /**
+ * ptp_getpartialobject_to_handler:
+ * params:	PTPParams*
+ *		handle			- Object handle
+ *		offset			- Offset into object
+ *		maxbytes		- Maximum of bytes to read
+ *		handler			- a ptp data handler
+ *
+ * Get object 'handle' from device and send the data to the
+ * data handler. Start from offset and read at most maxbytes.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+uint16_t
+ptp_getpartialobject_to_handler (PTPParams* params, uint32_t handle, uint32_t offset,
+			uint32_t maxbytes, PTPDataHandler *handler)
+{
+	PTPContainer ptp;
+
+	PTP_CNT_INIT(ptp, PTP_OC_GetPartialObject, handle, offset, maxbytes);
+	return ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, handler);
+}
+
+/**
  * ptp_getthumb:
  * params:	PTPParams*
  *		handle			- Object handle
@@ -1540,11 +1525,7 @@ ptp_getthumb (PTPParams* params, uint32_
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetThumb;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
-	*len = 0;
+	PTP_CNT_INIT(ptp, PTP_OC_GetThumb, handle);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, len);
 }
 
@@ -1562,17 +1543,9 @@ uint16_t
 ptp_deleteobject (PTPParams* params, uint32_t handle, uint32_t ofc)
 {
 	PTPContainer ptp;
-	uint16_t ret;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_DeleteObject;
-	ptp.Param1=handle;
-	ptp.Param2=ofc;
-	ptp.Nparam=2;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if (ret != PTP_RC_OK) {
-		return ret;
-	}
+	PTP_CNT_INIT(ptp, PTP_OC_DeleteObject, handle, ofc);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	/* If the object is cached and could be removed, cleanse cache. */
 	ptp_remove_object_from_cache(params, handle);
 	return PTP_RC_OK;
@@ -1601,20 +1574,15 @@ ptp_sendobjectinfo (PTPParams* params, u
 			uint32_t* parenthandle, uint32_t* handle,
 			PTPObjectInfo* objectinfo)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* oidata=NULL;
-	uint32_t size;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_SendObjectInfo;
-	ptp.Param1=*store;
-	ptp.Param2=*parenthandle;
-	ptp.Nparam=2;
-	
-	size=ptp_pack_OI(params, objectinfo, &oidata);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata, NULL); 
-	free(oidata);
+	PTP_CNT_INIT(ptp, PTP_OC_SendObjectInfo, *store, *parenthandle);
+	size = ptp_pack_OI(params, objectinfo, &data);
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	*store=ptp.Param1;
 	*parenthandle=ptp.Param2;
 	*handle=ptp.Param3; 
@@ -1637,10 +1605,7 @@ ptp_sendobject (PTPParams* params, unsig
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_SendObject;
-	ptp.Nparam=0;
-
+	PTP_CNT_INIT(ptp, PTP_OC_SendObject);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object, NULL);
 }
 
@@ -1658,11 +1623,9 @@ ptp_sendobject (PTPParams* params, unsig
 uint16_t
 ptp_sendobject_from_handler (PTPParams* params, PTPDataHandler *handler, uint64_t size)
 {
-	PTPContainer	ptp;
+	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_SendObject;
-	ptp.Nparam=0;
+	PTP_CNT_INIT(ptp, PTP_OC_SendObject);
 	return ptp_transaction_new(params, &ptp, PTP_DP_SENDDATA, size, handler);
 }
 
@@ -1685,10 +1648,8 @@ ptp_sendobject_fromfd (PTPParams* params
 	PTPDataHandler	handler;
 	uint16_t	ret;
 
+	PTP_CNT_INIT(ptp, PTP_OC_SendObject);
 	ptp_init_fd_handler (&handler, fd);
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_SendObject;
-	ptp.Nparam=0;
 	ret = ptp_transaction_new(params, &ptp, PTP_DP_SENDDATA, size, &handler);
 	ptp_exit_fd_handler (&handler);
 	return ret;
@@ -1700,49 +1661,47 @@ uint16_t
 ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode, 
 			PTPDevicePropDesc* devicepropertydesc)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	unsigned int len;
-	unsigned char* dpd=NULL;
+	PTPContainer	ptp;
+	uint16_t	ret = PTP_RC_OK;
+	unsigned char	*data;
+	unsigned int	size;
 
+	PTP_CNT_INIT(ptp, PTP_OC_GetDevicePropDesc, propcode);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_GetDevicePropDesc;
-	ptp.Param1 = propcode;
-	ptp.Nparam = 1;
-	len        = 0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpd, &len);
+	if (!data) {
+		ptp_debug (params, "no data received for getdevicepropdesc");
+		return PTP_RC_InvalidDevicePropFormat;
+	}
 
-	if (ret == PTP_RC_OK) {
-		if (params->device_flags & DEVICE_FLAG_OLYMPUS_XML_WRAPPED) {
+	if (params->device_flags & DEVICE_FLAG_OLYMPUS_XML_WRAPPED) {
 #ifdef HAVE_LIBXML2
-			xmlNodePtr	code;
+		xmlNodePtr	code;
 
-			ret = ptp_olympus_parse_output_xml (params,(char*)dpd,len,&code);
-			if (ret == PTP_RC_OK) {
-				int x;
+		ret = ptp_olympus_parse_output_xml (params,(char*)data,size,&code);
+		if (ret == PTP_RC_OK) {
+			int x;
 
-				if (	(xmlChildElementCount(code) == 1) &&
+			if (	(xmlChildElementCount(code) == 1) &&
 					(!strcmp((char*)code->name,"c1014"))
-				) {
-					code = xmlFirstElementChild (code);
+					) {
+				code = xmlFirstElementChild (code);
 
-					if (	(sscanf((char*)code->name,"p%x", &x)) &&
+				if (	(sscanf((char*)code->name,"p%x", &x)) &&
 						(x == propcode)
-					) {
-						ret = parse_9301_propdesc (params, xmlFirstElementChild (code), devicepropertydesc);
-						xmlFreeDoc(code->doc);
-					}
+						) {
+					ret = parse_9301_propdesc (params, xmlFirstElementChild (code), devicepropertydesc);
+					xmlFreeDoc(code->doc);
 				}
-			} else {
-				ptp_debug(params,"failed to parse output xml, ret %x?", ret);
 			}
-#endif
 		} else {
-			ptp_unpack_DPD(params, dpd, devicepropertydesc, len);
+			ptp_debug(params,"failed to parse output xml, ret %x?", ret);
 		}
+#endif
+	} else {
+		ptp_unpack_DPD(params, data, devicepropertydesc, size);
 	}
-	free(dpd);
+	free(data);
 	return ret;
 }
 
@@ -1751,26 +1710,17 @@ uint16_t
 ptp_getdevicepropvalue (PTPParams* params, uint16_t propcode,
 			PTPPropertyValue* value, uint16_t datatype)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	unsigned int len, offset;
-	unsigned char* dpv=NULL;
-
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size, offset = 0;
+	uint16_t	ret;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_GetDevicePropValue;
-	ptp.Param1=propcode;
-	ptp.Nparam=1;
-	len=offset=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv, &len);
-	if (ret == PTP_RC_OK) {
-		int ret2 = ptp_unpack_DPV(params, dpv, &offset, len, value, datatype);
-		if (!ret2) {
-			ptp_debug (params, "ptp_getdevicepropvalue: unpacking DPV failed");
-			ret = PTP_RC_GeneralError;
-		}
-	}
-	free(dpv);
+	PTP_CNT_INIT(ptp, PTP_OC_GetDevicePropValue, propcode);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ret = ptp_unpack_DPV(params, data, &offset, size, value, datatype) ? PTP_RC_OK : PTP_RC_GeneralError;
+	if (ret != PTP_RC_OK)
+		ptp_debug (params, "ptp_getdevicepropvalue: unpacking DPV failed");
+	free(data);
 	return ret;
 }
 
@@ -1778,18 +1728,15 @@ uint16_t
 ptp_setdevicepropvalue (PTPParams* params, uint16_t propcode,
 			PTPPropertyValue *value, uint16_t datatype)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	uint32_t size;
-	unsigned char* dpv=NULL;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_SetDevicePropValue;
-	ptp.Param1=propcode;
-	ptp.Nparam=1;
-	size=ptp_pack_DPV(params, value, &dpv, datatype);
-	ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv, NULL);
-	free(dpv);
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_SetDevicePropValue, propcode);
+	size=ptp_pack_DPV(params, value, &data, datatype);
+	ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	return ret;
 }
 
@@ -1816,20 +1763,15 @@ ptp_ek_sendfileobjectinfo (PTPParams* pa
 			uint32_t* parenthandle, uint32_t* handle,
 			PTPObjectInfo* objectinfo)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* oidata=NULL;
-	uint32_t size;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_EK_SendFileObjectInfo;
-	ptp.Param1=*store;
-	ptp.Param2=*parenthandle;
-	ptp.Nparam=2;
-	
-	size=ptp_pack_OI(params, objectinfo, &oidata);
-	ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &oidata, NULL); 
-	free(oidata);
+	PTP_CNT_INIT(ptp, PTP_OC_EK_SendFileObjectInfo, *store, *parenthandle);
+	size=ptp_pack_OI(params, objectinfo, &data);
+	ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	*store=ptp.Param1;
 	*parenthandle=ptp.Param2;
 	*handle=ptp.Param3; 
@@ -1852,9 +1794,7 @@ ptp_ek_getserial (PTPParams* params, uns
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_EK_GetSerial;
-	ptp.Nparam = 0;
+	PTP_CNT_INIT(ptp, PTP_OC_EK_GetSerial);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 }
 
@@ -1874,9 +1814,7 @@ ptp_ek_setserial (PTPParams* params, uns
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_EK_SetSerial;
-	ptp.Nparam = 0;
+	PTP_CNT_INIT(ptp, PTP_OC_EK_SetSerial);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL); 
 }
 
@@ -1886,9 +1824,7 @@ ptp_ek_9007 (PTPParams* params, unsigned
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = 0x9007;
-	ptp.Nparam = 0;
+	PTP_CNT_INIT(ptp, 0x9007);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 }
 
@@ -1897,15 +1833,13 @@ uint16_t
 ptp_ek_9009 (PTPParams* params, uint32_t *p1, uint32_t *p2)
 {
 	PTPContainer	ptp;
-	uint16_t	ret;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = 0x9009;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL); 
+	PTP_CNT_INIT(ptp, 0x9009);
+	*p1 = *p2 = 0;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*p1 = ptp.Param1;
 	*p2 = ptp.Param2;
-	return ret;
+	return PTP_RC_OK;
 }
 
 /* unclear yet, but I guess it returns the info from 9008 */
@@ -1914,9 +1848,7 @@ ptp_ek_900c (PTPParams* params, unsigned
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = 0x900c;
-	ptp.Nparam = 0;
+	PTP_CNT_INIT(ptp, 0x900c);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 	/* returned data is 16bit,16bit,32bit,32bit */
 }
@@ -1934,17 +1866,15 @@ ptp_ek_900c (PTPParams* params, unsigned
 uint16_t
 ptp_ek_settext (PTPParams* params, PTPEKTextParams *text)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	unsigned int size;
-	unsigned char *data;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_EK_SetText;
-	ptp.Nparam = 0;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = 0;
+	uint32_t	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_EK_SetText);
 	if (0 == (size = ptp_pack_EK_text(params, text, &data)))
 		return PTP_ERROR_BADPARAM;
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL); 
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
 	free(data);
 	return ret;
 }
@@ -1965,10 +1895,7 @@ ptp_ek_sendfileobject (PTPParams* params
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_EK_SendFileObject;
-	ptp.Nparam=0;
-
+	PTP_CNT_INIT(ptp, PTP_OC_EK_SendFileObject);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &object, NULL);
 }
 
@@ -1988,9 +1915,7 @@ ptp_ek_sendfileobject_from_handler (PTPP
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_EK_SendFileObject;
-	ptp.Nparam=0;
+	PTP_CNT_INIT(ptp, PTP_OC_EK_SendFileObject);
 	return ptp_transaction_new(params, &ptp, PTP_DP_SENDDATA, size, handler);
 }
 
@@ -2024,18 +1949,14 @@ uint16_t
 ptp_canon_getpartialobjectinfo (PTPParams* params, uint32_t handle, uint32_t p2, 
 			uint32_t* size, uint32_t* rp2) 
 {
-	uint16_t ret;
-	PTPContainer ptp;
+	PTPContainer	ptp;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetPartialObjectInfo;
-	ptp.Param1=handle;
-	ptp.Param2=p2;
-	ptp.Nparam=2;
-	ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetPartialObjectInfo, handle, p2);
+	*size = *rp2 = 0;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*size=ptp.Param1;
 	*rp2=ptp.Param2;
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -2052,13 +1973,9 @@ uint16_t
 ptp_canon_get_mac_address (PTPParams* params, unsigned char **mac)
 {
 	PTPContainer ptp;
-	unsigned int size = 0;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetMACAddress;
-	ptp.Nparam=0;
-	*mac = NULL;
-	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, mac, &size);
+        PTP_CNT_INIT(ptp, PTP_OC_CANON_GetMACAddress);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, mac, NULL);
 }
 
 /**
@@ -2080,18 +1997,13 @@ ptp_canon_get_directory (PTPParams* para
 	uint32_t		**flags		/* size(handles->n) */
 ) {
 	PTPContainer	ptp;
-	unsigned char	*dir = NULL;
-	unsigned int	size = 0;
+	unsigned char	*data;
 	uint16_t	ret;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetDirectory;
-	ptp.Nparam=0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dir, &size);
-	if (ret != PTP_RC_OK)
-		return ret;
-	ret = ptp_unpack_canon_directory(params, dir, ptp.Param1, handles, oinfos, flags);
-	free (dir);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetDirectory);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL));
+	ret = ptp_unpack_canon_directory(params, data, ptp.Param1, handles, oinfos, flags);
+	free (data);
 	return ret;
 }
 
@@ -2110,17 +2022,13 @@ ptp_canon_get_directory (PTPParams* para
 uint16_t
 ptp_canon_gettreeinfo (PTPParams* params, uint32_t *out)
 {
-	PTPContainer ptp;
-	uint16_t ret;
+	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_GetTreeInfo;
-	ptp.Nparam = 1;
-	ptp.Param1 = 0xf;
-	ret = ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ((ret == PTP_RC_OK) && (ptp.Nparam>0))
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetTreeInfo, 0xf);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
+	if (ptp.Nparam > 0)
 		*out = ptp.Param1;
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -2137,18 +2045,9 @@ uint16_t
 ptp_canon_getpairinginfo (PTPParams* params, uint32_t nr, unsigned char **data, unsigned int *size)
 {
 	PTPContainer ptp;
-	uint16_t ret;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_GetPairingInfo;
-	ptp.Nparam = 1;
-	ptp.Param1 = nr;
-	*data = NULL;
-	*size = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
-	if (ret != PTP_RC_OK)
-		return ret;
-	return PTP_RC_OK;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetPairingInfo, nr);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
 }
 
 /**
@@ -2167,32 +2066,29 @@ uint16_t
 ptp_canon_gettreesize (PTPParams* params,
 	PTPCanon_directtransfer_entry **entries, unsigned int *cnt)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *out = NULL, *cur;
-	unsigned int i, size;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_CANON_GetTreeSize;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &out, &size);
-	if (ret != PTP_RC_OK)
-		return ret;
-	*cnt = dtoh32a(out);
+	PTPContainer	ptp;
+	uint16_t	ret = PTP_RC_OK;
+	unsigned char	*data, *cur;
+	unsigned int	size, i;
+
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetTreeSize);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	*cnt = dtoh32a(data);
 	*entries = malloc(sizeof(PTPCanon_directtransfer_entry)*(*cnt));
 	if (!*entries) {
-		free (out);
-		return PTP_RC_GeneralError;
+		ret = PTP_RC_GeneralError;
+		goto exit;
 	}
-	cur = out+4;
+	cur = data+4;
 	for (i=0;i<*cnt;i++) {
 		unsigned char len;
 		(*entries)[i].oid = dtoh32a(cur);
-		(*entries)[i].str = ptp_unpack_string(params, cur, 4, &len);
+		(*entries)[i].str = ptp_unpack_string(params, cur, 4, size-(cur-data-4), &len);
 		cur += 4+(cur[4]*2+1);
 	}
-	free (out);
-	return PTP_RC_OK;
+exit:
+	free (data);
+	return ret;
 }
 
 /**
@@ -2217,63 +2113,124 @@ ptp_canon_gettreesize (PTPParams* params
 uint16_t
 ptp_canon_checkevent (PTPParams* params, PTPContainer* event, int* isevent)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char *evdata = NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 	
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_CheckEvent);
 	*isevent=0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_CheckEvent;
-	ptp.Nparam=0;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &evdata, &len);
-	if (evdata!=NULL) {
-		if (ret == PTP_RC_OK) {
-        		ptp_unpack_EC(params, evdata, event, len);
-    			*isevent=1;
-        	}
-		free(evdata);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	if (data && size) { /* check if we had a successfull call with data */
+		ptp_unpack_EC(params, data, event, size);
+		*isevent=1;
+		free(data);
 	}
-	return ret;
+	return PTP_RC_OK;
 }
 
 uint16_t
-ptp_add_event (PTPParams *params, PTPContainer *evt) {
-	if (params->nrofevents)
-		params->events = realloc(params->events, sizeof(PTPContainer)*(params->nrofevents+1));
-	else
-		params->events = malloc(sizeof(PTPContainer)*1);
+ptp_add_event (PTPParams *params, PTPContainer *evt)
+{
+	params->events = realloc(params->events, sizeof(PTPContainer)*(params->nrofevents+1));
 	memcpy (&params->events[params->nrofevents],evt,1*sizeof(PTPContainer));
 	params->nrofevents += 1;
 	return PTP_RC_OK;
 }
 
+static void
+handle_event_internal (PTPParams *params, PTPContainer *event)
+{
+	/* handle some PTP stack internal events */
+	switch (event->Code) {
+	case PTP_EC_DevicePropChanged: {
+		unsigned int i;
+
+		/* mark the property for a forced refresh on the next query */
+		for (i=0;i<params->nrofdeviceproperties;i++)
+			if (params->deviceproperties[i].desc.DevicePropertyCode == event->Param1) {
+				params->deviceproperties[i].timestamp = 0;
+				break;
+			}
+		break;
+	}
+	case PTP_EC_StoreAdded:
+	case PTP_EC_StoreRemoved: {
+		int i;
+
+		/* refetch storage IDs and also invalidate whole object tree */
+		free (params->storageids.Storage);
+		params->storageids.Storage	= NULL;
+		params->storageids.n 		= 0;
+		ptp_getstorageids (params, &params->storageids);
+
+		/* free object storage as it might be associated with the storage ids */
+		/* FIXME: enhance and just delete the ones from the storage */
+		for (i=0;i<params->nrofobjects;i++)
+			ptp_free_object (&params->objects[i]);
+		free (params->objects);
+		params->objects 		= NULL;
+		params->nrofobjects 		= 0;
+
+		params->storagechanged		= 1;
+		break;
+	}
+	default: /* check if we should handle it internally too */
+		break;
+	}
+}
+
 uint16_t
-ptp_check_event (PTPParams *params) {
-	PTPContainer		event;
-	uint16_t		ret;
+ptp_check_event_queue (PTPParams *params)
+{
+	PTPContainer	event;
+	uint16_t	ret;
+
+	/* We try to do a event check without I/O */
+	/* Basically this means just looking at the meanwhile queued events */
+
+	ret = params->event_check_queue(params,&event);
+
+	if (ret == PTP_RC_OK) {
+		ptp_debug (params, "event: nparams=0x%X, code=0x%X, trans_id=0x%X, p1=0x%X, p2=0x%X, p3=0x%X", event.Nparam,event.Code,event.Transaction_ID, event.Param1, event.Param2, event.Param3);
+		ptp_add_event (params, &event);
+		handle_event_internal (params, &event);
+	}
+	if (ret == PTP_ERROR_TIMEOUT) /* ok, just new events */
+		ret = PTP_RC_OK;
+	return ret;
+}
 
+uint16_t
+ptp_check_event (PTPParams *params)
+{
+	PTPContainer	event;
+	uint16_t	ret;
+
+	/* Method offered by Nikon DSLR, Nikon 1, and some older Nikon Coolpix P*
+	 * The Nikon Coolpix P2 however does not return anything. So if we never get
+	 * events from here, use the ptp "interrupt" method */
 	if (	(params->deviceinfo.VendorExtensionID == PTP_VENDOR_NIKON) &&
 		ptp_operation_issupported(params, PTP_OC_NIKON_CheckEvent)
 	) {
-		unsigned int evtcnt;
-		PTPContainer	*xevent = NULL;
+		unsigned int evtcnt = 0, i;
+		PTPContainer *xevent = NULL;
 
 		ret = ptp_nikon_check_event(params, &xevent, &evtcnt);
-		if (ret != PTP_RC_OK)
-			return ret;
+		if (ret != PTP_RC_OperationNotSupported)
+			CHECK_PTP_RC(ret);
 
 		if (evtcnt) {
-			if (params->nrofevents)
-				params->events = realloc(params->events, sizeof(PTPContainer)*(evtcnt+params->nrofevents));
-			else
-				params->events = malloc(sizeof(PTPContainer)*evtcnt);
+			for (i = 0; i < evtcnt; i++)
+				handle_event_internal (params, &xevent[i]);
+			params->events = realloc(params->events, sizeof(PTPContainer)*(evtcnt+params->nrofevents));
 			memcpy (&params->events[params->nrofevents],xevent,evtcnt*sizeof(PTPContainer));
 			params->nrofevents += evtcnt;
 			free (xevent);
+			params->event90c7works = 1;
 		}
-		return PTP_RC_OK;
+		if (params->event90c7works)
+			return PTP_RC_OK;
+		/* fall through to generic event handling */
 	}
 	/* should not get here ... EOS has no normal PTP events and another queue handling. */
 	if (	(params->deviceinfo.VendorExtensionID == PTP_VENDOR_CANON) &&
@@ -2287,14 +2244,15 @@ ptp_check_event (PTPParams *params) {
 	) {
 		int isevent;
 
-		ret = ptp_canon_checkevent (params,&event,&isevent);
-		if (ret!=PTP_RC_OK)
-			return ret;
-		if (isevent)
+		CHECK_PTP_RC(ptp_canon_checkevent (params,&event,&isevent));
+
+		if (isevent) {
+			ret = PTP_RC_OK;
 			goto store_event;
+		}
 		/* Event Emulate Mode 0 (unset) and 1-5 get interrupt events. 6-7 does not. */
 		if (params->canon_event_mode > 5)
-			return ret;
+			return PTP_RC_OK;
 
 		/* FIXME: fallthrough or return? */
 #ifdef __APPLE__
@@ -2302,7 +2260,7 @@ ptp_check_event (PTPParams *params) {
 		 * for interrupts, they have no timeout for it. 2010/08/23
 		 * Check back in 2011 or so. -Marcus
 		 */
-		return ret;
+		return PTP_RC_OK;
 #endif
 	}
 	ret = params->event_check(params,&event);
@@ -2311,14 +2269,38 @@ store_event:
 	if (ret == PTP_RC_OK) {
 		ptp_debug (params, "event: nparams=0x%X, code=0x%X, trans_id=0x%X, p1=0x%X, p2=0x%X, p3=0x%X", event.Nparam,event.Code,event.Transaction_ID, event.Param1, event.Param2, event.Param3);
 		ptp_add_event (params, &event);
+
+		handle_event_internal (params, &event);
+
+	
+	}
+	if (ret == PTP_ERROR_TIMEOUT) /* ok, just new events */
+		ret = PTP_RC_OK;
+	return ret;
+}
+
+uint16_t
+ptp_wait_event (PTPParams *params)
+{
+	PTPContainer	event;
+	uint16_t	ret;
+
+	ret = params->event_wait(params,&event);
+	if (ret == PTP_RC_OK) {
+		ptp_debug (params, "event: nparams=0x%X, code=0x%X, trans_id=0x%X, p1=0x%X, p2=0x%X, p3=0x%X", event.Nparam,event.Code,event.Transaction_ID, event.Param1, event.Param2, event.Param3);
+		ptp_add_event (params, &event);
+
+		handle_event_internal (params, &event);
 	}
 	if (ret == PTP_ERROR_TIMEOUT) /* ok, just new events */
 		ret = PTP_RC_OK;
 	return ret;
 }
 
+
 int
-ptp_get_one_event(PTPParams *params, PTPContainer *event) {
+ptp_get_one_event(PTPParams *params, PTPContainer *event)
+{
 	if (!params->nrofevents)
 		return 0;
 	memcpy (event, params->events, sizeof(PTPContainer));
@@ -2347,33 +2329,27 @@ ptp_get_one_event(PTPParams *params, PTP
 uint16_t
 ptp_canon_eos_getevent (PTPParams* params, PTPCanon_changes_entry **entries, int *nrofentries)
 {
-	PTPContainer ptp;
-	uint16_t	ret;
-	unsigned int 	size = 0;
-	unsigned char	*data = NULL;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int 	size;
 
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetEvent);
 	*nrofentries = 0;
 	*entries = NULL;
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_CANON_EOS_GetEvent;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret != PTP_RC_OK) return ret;
-        *nrofentries = ptp_unpack_CANON_changes(params,data,size,entries);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	*nrofentries = ptp_unpack_CANON_changes(params,data,size,entries);
 	free (data);
 	return PTP_RC_OK;
 }
 
 uint16_t
-ptp_check_eos_events (PTPParams *params) {
-	uint16_t		ret;
+ptp_check_eos_events (PTPParams *params)
+{
 	PTPCanon_changes_entry	*entries = NULL, *nentries;
 	int			nrofentries = 0;
 
 	while (1) { /* call it repeatedly until the camera does not report any */
-		ret = ptp_canon_eos_getevent (params, &entries, &nrofentries);
-		if (ret != PTP_RC_OK)
-			return ret;
+		CHECK_PTP_RC(ptp_canon_eos_getevent (params, &entries, &nrofentries));
 		if (!nrofentries)
 			return PTP_RC_OK;
 
@@ -2394,7 +2370,8 @@ ptp_check_eos_events (PTPParams *params)
 }
 
 int
-ptp_get_one_eos_event (PTPParams *params, PTPCanon_changes_entry *entry) {
+ptp_get_one_eos_event (PTPParams *params, PTPCanon_changes_entry *entry)
+{
 	if (!params->nrofbacklogentries)
 		return 0;
 	memcpy (entry, params->backlogentries, sizeof(*entry));
@@ -2443,34 +2420,24 @@ uint16_t
 ptp_canon_eos_getstorageids (PTPParams* params, PTPStorageIDs* storageids)
 {
 	PTPContainer	ptp;
-	unsigned int	len = 0;
-	uint16_t	ret;
-	unsigned char*	sids=NULL;
-	
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_GetStorageIDs;
-	ptp.Nparam	= 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &sids, &len);
-	if (ret == PTP_RC_OK) ptp_unpack_SIDs(params, sids, storageids, len);
-	free(sids);
-	return ret;
+	unsigned char	*data;
+	unsigned int	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetStorageIDs);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ptp_unpack_SIDs(params, data, storageids, size);
+	free(data);
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_canon_eos_getstorageinfo (PTPParams* params, uint32_t p1, unsigned char **data, unsigned int *size)
 {
-	PTPContainer ptp;
-	uint16_t	ret;
+	PTPContainer	ptp;
 	
-	*size = 0;
-	*data = NULL;
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_GetStorageInfo;
-	ptp.Nparam	= 1;
-	ptp.Param1	= p1;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetStorageInfo, p1);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
 	/* FIXME: do stuff with data */
-	return ret;
 }
 
 uint16_t
@@ -2479,40 +2446,50 @@ ptp_canon_eos_getobjectinfoex (
 	PTPCANONFolderEntry **entries, unsigned int *nrofentries
 ) {
 	PTPContainer	ptp;
-	unsigned int	i, size = 0;
+	uint16_t	ret = PTP_RC_OK;
 	unsigned char	*data, *xdata;
-	uint16_t	ret;
-
-	data = NULL;
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_GetObjectInfoEx;
-	ptp.Nparam	= 3;
-	ptp.Param1	= storageid;
-	ptp.Param2	= oid;
-	ptp.Param3	= unk;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret != PTP_RC_OK)
-		return ret;
+	unsigned int	size, i;
 
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetObjectInfoEx, storageid, oid, unk);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
 	if (!data) {
 		*nrofentries = 0;
 		return PTP_RC_OK;
 	}
 
+	if (size < 4) {
+		ret = PTP_RC_GeneralError;
+		goto exit;
+	}
+	/* check for integer overflow */
+	if (dtoh32a(data) >= INT_MAX/sizeof(PTPCANONFolderEntry))  {
+		ret = PTP_RC_GeneralError;
+		goto exit;
+	}
+
 	*nrofentries = dtoh32a(data);
 	*entries = malloc(*nrofentries * sizeof(PTPCANONFolderEntry));
 	if (!*entries) {
-		free (data);
-		return PTP_RC_GeneralError;
+		ret = PTP_RC_GeneralError;
+		goto exit;
 	}
 
 	xdata = data+sizeof(uint32_t);
 	for (i=0;i<*nrofentries;i++) {
+		if ((dtoh32a(xdata) + (xdata-data)) > size) {
+			ptp_debug (params, "reading canon FEs run over read data size?\n");
+			free (*entries);
+			*entries = NULL;
+			*nrofentries = 0;
+			ret = PTP_RC_GeneralError;
+			goto exit;
+		}
 		ptp_unpack_Canon_EOS_FE (params, &xdata[4], &((*entries)[i]));
 		xdata += dtoh32a(xdata);
 	}
+exit:
 	free (data);
-	return PTP_RC_OK;
+	return ret;
 }
 
 /**
@@ -2535,16 +2512,9 @@ uint16_t
 ptp_canon_eos_getpartialobject (PTPParams* params, uint32_t oid, uint32_t offset, uint32_t xsize, unsigned char**data)
 {
 	PTPContainer	ptp;
-	unsigned int	size = 0;
 
-	*data = NULL;
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_GetPartialObject;
-	ptp.Nparam	= 3;
-	ptp.Param1	= oid;
-	ptp.Param2	= offset;
-	ptp.Param3	= xsize;
-	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, &size);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetPartialObject, oid, offset, xsize);
+	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, NULL);
 }
 
 uint16_t
@@ -2552,9 +2522,7 @@ ptp_canon_eos_setdevicepropvalueex (PTPP
 {
 	PTPContainer	ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_SetDevicePropValueEx;
-	ptp.Nparam	= 0;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_SetDevicePropValueEx);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
 }
 
@@ -2564,12 +2532,11 @@ ptp_canon_eos_setdevicepropvalue (PTPPar
 ) {
 	PTPContainer	ptp;
 	uint16_t	ret;
+	unsigned char	*data = NULL;
 	unsigned int	i, size;
-	unsigned char	*data;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code 	= PTP_OC_CANON_EOS_SetDevicePropValueEx;
-	ptp.Nparam	= 0;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_SetDevicePropValueEx);
+
 	for (i=0;i<params->nrofcanon_props;i++)
 		if (params->canon_props[i].proptype == propcode)
 			break;
@@ -2599,12 +2566,12 @@ ptp_canon_eos_setdevicepropvalue (PTPPar
 		break;
 	default:
 		if (datatype != PTP_DTC_STR) {
-			data = calloc(sizeof(uint32_t),3);
+			data = calloc(3,sizeof(uint32_t));
 			if (!data) return PTP_RC_GeneralError;
 			size = sizeof(uint32_t)*3;
 		} else {
 			size = strlen(value->str) + 1 + 8;
-			data = calloc(sizeof(char),size);
+			data = calloc(size,sizeof(char));
 			if (!data) return PTP_RC_GeneralError;
 		}
 		switch (datatype) {
@@ -2666,24 +2633,17 @@ ptp_canon_getpartialobject (PTPParams* p
 				uint32_t pos, unsigned char** block, 
 				uint32_t* readnum)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char *data=NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetPartialObjectEx;
-	ptp.Param1=handle;
-	ptp.Param2=offset;
-	ptp.Param3=size;
-	ptp.Param4=pos;
-	ptp.Nparam=4;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetPartialObjectEx, handle, offset, size, pos);
+	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL);
 	if (ret==PTP_RC_OK) {
 		*block=data;
 		*readnum=ptp.Param1;
 	}
+	free (data);
 	return ret;
 }
 
@@ -2706,15 +2666,13 @@ ptp_canon_getpartialobject (PTPParams* p
 uint16_t
 ptp_canon_getviewfinderimage (PTPParams* params, unsigned char** image, uint32_t* size)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned int len;
+	PTPContainer	ptp;
+	uint16_t	ret;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetViewfinderImage;
-	ptp.Nparam=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, image, &len);
-	if (ret==PTP_RC_OK) *size=ptp.Param1;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetViewfinderImage);
+	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, image, NULL);
+	if (ret==PTP_RC_OK)
+		*size=ptp.Param1;
 	return ret;
 }
 
@@ -2738,20 +2696,15 @@ ptp_canon_getviewfinderimage (PTPParams*
 uint16_t
 ptp_canon_getchanges (PTPParams* params, uint16_t** props, uint32_t* propnum)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* data=NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetChanges;
-	ptp.Nparam=0;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len);
-	if (ret == PTP_RC_OK)
-        	*propnum=ptp_unpack_uint16_t_array(params,data,0,props);
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetChanges);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	*propnum=ptp_unpack_uint16_t_array(params,data,0,size,props);
 	free(data);
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -2782,34 +2735,42 @@ ptp_canon_getobjectinfo (PTPParams* para
 			    uint32_t parent, uint32_t handle, 
 			    PTPCANONFolderEntry** entries, uint32_t* entnum)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char *data = NULL;
-	unsigned int len;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	unsigned int	i, size;
 	
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CANON_GetObjectInfoEx;
-	ptp.Param1=store;
-	ptp.Param2=p2;
-	ptp.Param3=parent;
-	ptp.Param4=handle;
-	ptp.Nparam=4;
-	len=0;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &len);
-	if (ret == PTP_RC_OK) {
-		unsigned int i;
-		*entnum=ptp.Param1;
-		*entries=calloc(*entnum, sizeof(PTPCANONFolderEntry));
-		if (*entries!=NULL) {
-			for(i=0; i<(*entnum); i++)
-				ptp_unpack_Canon_FE(params,
-					data+i*PTP_CANON_FolderEntryLen,
-					&((*entries)[i]) );
-		} else {
-			ret=PTP_ERROR_IO; /* Cannot allocate memory */
-		}
+	*entnum = 0;
+	*entries = NULL;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetObjectInfoEx, store, p2, parent, handle);
+	data = NULL;
+	size = 0;
+	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL);
+	if (ret != PTP_RC_OK)
+		goto exit;
+	if (!data)
+		return ret;
+	if (ptp.Param1 > size/PTP_CANON_FolderEntryLen) {
+		ptp_debug (params, "param1 is %d, size is only %d", ptp.Param1, size);
+		ret = PTP_RC_GeneralError;
+		goto exit;
+	}
+
+	*entnum = ptp.Param1;
+	*entries= calloc(*entnum, sizeof(PTPCANONFolderEntry));
+	if (*entries == NULL) {
+		ret = PTP_RC_GeneralError;
+		goto exit;
+	}
+	for(i=0; i<(*entnum); i++) {
+		if (size < i*PTP_CANON_FolderEntryLen) break;
+		ptp_unpack_Canon_FE(params,
+				    data+i*PTP_CANON_FolderEntryLen,
+				    &((*entries)[i]) );
 	}
-	free(data);
+
+exit:
+	free (data);
 	return ret;
 }
 
@@ -2833,16 +2794,14 @@ ptp_canon_getobjectinfo (PTPParams* para
 uint16_t
 ptp_canon_get_objecthandle_by_name (PTPParams* params, char* name, uint32_t* objectid)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char *data = NULL;
-	uint8_t len;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	uint8_t		len = 0;
 
-	PTP_CNT_INIT (ptp);
-	ptp.Code=PTP_OC_CANON_GetObjectHandleByName;
-	ptp.Nparam=0;
-	len=0;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetObjectHandleByName);
 	data = malloc (2*(strlen(name)+1)+2);
+	if (!data) return PTP_RC_GeneralError;
 	memset (data, 0, 2*(strlen(name)+1)+2);
 	ptp_pack_string (params, name, data, 0, &len);
 	ret=ptp_transaction (params, &ptp, PTP_DP_SENDDATA, (len+1)*2+1, &data, NULL);
@@ -2871,24 +2830,17 @@ ptp_canon_get_customize_data (PTPParams*
 {
 	PTPContainer ptp;
 
-	*data = NULL;
-	*size = 0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_CANON_GetCustomizeData;
-	ptp.Param1	= themenr;
-	ptp.Nparam	= 1;
+	PTP_CNT_INIT(ptp, PTP_OC_CANON_GetCustomizeData, themenr);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 }
 
 
 uint16_t
-ptp_nikon_curve_download (PTPParams* params, unsigned char **data, unsigned int *size) {
+ptp_nikon_curve_download (PTPParams* params, unsigned char **data, unsigned int *size)
+{
 	PTPContainer ptp;
-	*data = NULL;
-	*size = 0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_NIKON_CurveDownload;
-	ptp.Nparam	= 0;
+
+	PTP_CNT_INIT(ptp, PTP_OC_NIKON_CurveDownload);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 }
 
@@ -2903,21 +2855,15 @@ ptp_nikon_curve_download (PTPParams* par
  *
  **/
 uint16_t
-ptp_sony_sdioconnect (PTPParams* params, uint32_t p1, uint32_t p2, uint32_t p3) {
+ptp_sony_sdioconnect (PTPParams* params, uint32_t p1, uint32_t p2, uint32_t p3)
+{
 	PTPContainer	ptp;
-	uint16_t	ret;
-	unsigned char	*xdata = NULL;
-	unsigned int 	xsize;
+	unsigned char	*data;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_SONY_SDIOConnect;
-	ptp.Nparam	= 3;
-	ptp.Param1	= p1;
-	ptp.Param2	= p2;
-	ptp.Param3	= p3;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &xdata, &xsize); 
-	free (xdata);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_SDIOConnect, p1, p2, p3);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL));
+	free (data);
+	return PTP_RC_OK;
 }
 /**
  * ptp_sony_get_vendorpropcodes:
@@ -2932,42 +2878,58 @@ ptp_sony_sdioconnect (PTPParams* params,
  *
  **/
 uint16_t
-ptp_sony_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int *size) {
+ptp_sony_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int *size)
+{
 	PTPContainer	ptp;
-	uint16_t	ret;
 	unsigned char	*xdata = NULL;
-	unsigned int 	xsize;
+	unsigned int 	xsize, psize1 = 0, psize2 = 0;
+	uint16_t	*props1 = NULL,*props2 = NULL;
 
 	*props = NULL;
 	*size = 0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_SONY_GetSDIOGetExtDeviceInfo;
-	ptp.Nparam	= 1;
-	ptp.Param1	= 0xc8; /* unclear */
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &xdata, &xsize); 
-	/* first 16 bit is 0xc8 0x00, then an array of 16 bit PTP ids */
-	if (ret == PTP_RC_OK)
-        	*size = ptp_unpack_uint16_t_array(params,xdata+2,0,props);
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_GetSDIOGetExtDeviceInfo, 0xc8 /* unclear */);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &xdata, &xsize));
+	if (xsize == 0) {
+		ptp_debug (params, "No special operations sent?");
+		return PTP_RC_OK;
+	}
+
+	psize1 = ptp_unpack_uint16_t_array (params, xdata+2, 0, xsize, &props1);
+	ptp_debug (params, "xsize %d, got size %d\n", xsize, psize1*2 + 2 + 4);
+	if (psize1*2 + 2 + 4 < xsize) {
+		psize2 = ptp_unpack_uint16_t_array(params,xdata+2+psize1*2+4, 0, xsize, &props2);
+	}
+	*props = calloc(psize1+psize2, sizeof(uint16_t));
+	if (!*props) {
+		ptp_debug (params, "oom during malloc?");
+		free (props1);
+		free (props2);
+		free (xdata);
+		return PTP_RC_OK;
+	}
+	*size = psize1+psize2;
+	memcpy (*props, props1, psize1*sizeof(uint16_t));
+	memcpy ((*props)+psize1, props2, psize2*sizeof(uint16_t));
+	free (props1);
+	free (props2);
 	free (xdata);
-	return ret;
+	return PTP_RC_OK;
 }
 
 uint16_t
-ptp_sony_getdevicepropdesc (PTPParams* params, uint16_t propcode, PTPDevicePropDesc *dpd) {
+ptp_sony_getdevicepropdesc (PTPParams* params, uint16_t propcode, PTPDevicePropDesc *dpd)
+{
 	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int 	size, len = 0;
 	uint16_t	ret;
-	unsigned char	*xdata = NULL;
-	unsigned int 	xsize,len = 0;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_SONY_GetDevicePropdesc;
-	ptp.Nparam	= 1;
-	ptp.Param1	= propcode;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &xdata, &xsize); 
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_GetDevicePropdesc, propcode);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	if (!data) return PTP_RC_GeneralError;
 	/* first 16 bit is 0xc8 0x00, then an array of 16 bit PTP ids */
-	if (ret == PTP_RC_OK)
-        	ret = ptp_unpack_Sony_DPD(params,xdata,dpd,xsize,&len)?PTP_RC_OK:PTP_RC_GeneralError;
-	free (xdata);
+	ret = ptp_unpack_Sony_DPD(params,data,dpd,size,&len) ? PTP_RC_OK : PTP_RC_GeneralError;
+	free (data);
 	return ret;
 }
 
@@ -2975,17 +2937,18 @@ uint16_t
 ptp_sony_getalldevicepropdesc (PTPParams* params)
 {
 	PTPContainer		ptp;
-	uint16_t		ret;
-	unsigned char		*data = NULL , *dpddata;
-	uint32_t		size = 0, readlen;
+	unsigned char		*data, *dpddata;
+	unsigned int		size, readlen;
 	PTPDevicePropDesc	dpd;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_SONY_GetAllDevicePropData;
-	ptp.Nparam = 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret != PTP_RC_OK)
-		return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_GetAllDevicePropData);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	if (!data)
+		return PTP_RC_GeneralError;
+	if (size <= 8) {
+		free (data);
+		return PTP_RC_GeneralError;
+	}
 	dpddata = data+8; /* nr of entries 32bit, 0 32bit */
 	size -= 8;
 	while (size>0) {
@@ -3001,11 +2964,37 @@ ptp_sony_getalldevicepropdesc (PTPParams
 			if (params->deviceproperties[i].desc.DevicePropertyCode == propcode)
 				break;
 
+		/* debug output to see what changes */
+		if (i != params->nrofdeviceproperties) {
+			switch (dpd.DataType) {
+			case PTP_DTC_INT8:
+#define CHECK_CHANGED(type) \
+				if (params->deviceproperties[i].desc.CurrentValue.type != dpd.CurrentValue.type) \
+					ptp_debug (params, "ptp_sony_getalldevicepropdesc: %04x: value %d -> %d", propcode, params->deviceproperties[i].desc.CurrentValue.type, dpd.CurrentValue.type);
+				CHECK_CHANGED(i8);
+				break;
+			case PTP_DTC_UINT8:
+				CHECK_CHANGED(u8);
+				break;
+			case PTP_DTC_UINT16:
+				CHECK_CHANGED(u16);
+				break;
+			case PTP_DTC_INT16:
+				CHECK_CHANGED(i16);
+				break;
+			case PTP_DTC_INT32:
+				CHECK_CHANGED(i32);
+				break;
+			case PTP_DTC_UINT32:
+				CHECK_CHANGED(u32);
+				break;
+			default:
+				break;
+			}
+		}
+
 		if (i == params->nrofdeviceproperties) {
-			if (!i)
-				params->deviceproperties = malloc(sizeof(params->deviceproperties[0]));
-			else
-				params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
+			params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
 			memset(&params->deviceproperties[i],0,sizeof(params->deviceproperties[0]));
 			params->nrofdeviceproperties++;
 		} else {
@@ -3042,25 +3031,22 @@ ptp_sony_getalldevicepropdesc (PTPParams
 		size -= readlen;
 	}
 	free(data);
-	return ret;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_sony_setdevicecontrolvaluea (PTPParams* params, uint16_t propcode,
 			PTPPropertyValue *value, uint16_t datatype)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	uint32_t size;
-	unsigned char* dpv=NULL;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_SONY_SetControlDeviceA;
-	ptp.Param1 = propcode;
-	ptp.Nparam = 1;
-	size = ptp_pack_DPV(params, value, &dpv, datatype);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv, NULL);
-	free(dpv);
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	uint32_t	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_SetControlDeviceA, propcode);
+	size = ptp_pack_DPV(params, value, &data, datatype);
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	return ret;
 }
 
@@ -3068,18 +3054,53 @@ uint16_t
 ptp_sony_setdevicecontrolvalueb (PTPParams* params, uint16_t propcode,
 			PTPPropertyValue *value, uint16_t datatype)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	uint32_t size;
-	unsigned char* dpv=NULL;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_SONY_SetControlDeviceB;
-	ptp.Param1 = propcode;
-	ptp.Nparam = 1;
-	size = ptp_pack_DPV(params, value, &dpv, datatype);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &dpv, NULL);
-	free(dpv);
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	uint32_t	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_SONY_SetControlDeviceB, propcode);
+	size = ptp_pack_DPV(params, value, &data , datatype);
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
+	return ret;
+}
+
+uint16_t
+ptp_sony_9280 (PTPParams* params, uint32_t param1,
+	uint32_t additional, uint32_t data2, uint32_t data3, uint32_t data4, uint8_t x, uint8_t y)
+{
+	PTPContainer	ptp;
+	unsigned char 	buf[18];
+	unsigned char	*buffer;
+
+	PTP_CNT_INIT(ptp, 0x9280, param1);
+
+	if ((additional != 0) && (additional != 2))
+		return PTP_RC_GeneralError;
+
+	htod32a(&buf[0], additional);
+	htod32a(&buf[4], data2);
+	htod32a(&buf[8], data3);
+	htod32a(&buf[12], data4);
+
+	/* only sent in the case where additional is 2 */
+	buf[16]= x; buf[17]= y;
+
+	buffer=buf;
+	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, 16+additional, &buffer, NULL);
+}
+
+uint16_t
+ptp_sony_9281 (PTPParams* params, uint32_t param1) {
+	PTPContainer	ptp;
+	unsigned int	size = 0;
+	unsigned char	*buffer = NULL;
+	uint16_t	ret;
+
+	PTP_CNT_INIT(ptp, 0x9281, param1);
+	ret =  ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buffer, &size);
+	free (buffer);
 	return ret;
 }
 
@@ -3098,30 +3119,25 @@ ptp_sony_setdevicecontrolvalueb (PTPPara
  *
  **/
 /* Cache time in seconds. Should perhaps be more granular... */
-#define CACHETIME 2
 
 uint16_t
 ptp_generic_getdevicepropdesc (PTPParams *params, uint16_t propcode, PTPDevicePropDesc *dpd)
 {
 	unsigned int	i;
-	uint16_t	ret;
 	time_t		now;
 
 	for (i=0;i<params->nrofdeviceproperties;i++)
 		if (params->deviceproperties[i].desc.DevicePropertyCode == propcode)
 			break;
 	if (i == params->nrofdeviceproperties) {
-		if (!i)
-			params->deviceproperties = malloc(sizeof(params->deviceproperties[0]));
-		else
-			params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
+		params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
 		memset(&params->deviceproperties[i],0,sizeof(params->deviceproperties[0]));
 		params->nrofdeviceproperties++;
 	}
 
 	if (params->deviceproperties[i].desc.DataType != PTP_DTC_UNDEF) {
 		time(&now);
-		if ((now - params->deviceproperties[i].timestamp) <= CACHETIME) {
+		if (params->deviceproperties[i].timestamp + params->cachetime > now) {
 			duplicate_DevicePropDesc(&params->deviceproperties[i].desc, dpd);
 			return PTP_RC_OK;
 		}
@@ -3132,13 +3148,15 @@ ptp_generic_getdevicepropdesc (PTPParams
 	if (	(params->deviceinfo.VendorExtensionID == PTP_VENDOR_SONY) &&
 		ptp_operation_issupported(params, PTP_OC_SONY_GetAllDevicePropData)
 	) {
-		ret = ptp_sony_getalldevicepropdesc (params);
-		if (ret != PTP_RC_OK)
-			return ret;
+		CHECK_PTP_RC(ptp_sony_getalldevicepropdesc (params));
 
 		for (i=0;i<params->nrofdeviceproperties;i++)
 			if (params->deviceproperties[i].desc.DevicePropertyCode == propcode)
 				break;
+		if (i == params->nrofdeviceproperties) {
+			ptp_debug (params, "property 0x%04x not found?\n", propcode);
+			return PTP_RC_GeneralError;
+		}
 		time(&now);
 		params->deviceproperties[i].timestamp = now;
 		duplicate_DevicePropDesc(&params->deviceproperties[i].desc, dpd);
@@ -3147,9 +3165,7 @@ ptp_generic_getdevicepropdesc (PTPParams
 	if (	(params->deviceinfo.VendorExtensionID == PTP_VENDOR_SONY) &&
 		ptp_operation_issupported(params, PTP_OC_SONY_GetDevicePropdesc)
 	) {
-		ret = ptp_sony_getdevicepropdesc (params, propcode, &params->deviceproperties[i].desc);
-		if (ret != PTP_RC_OK)
-			return ret;
+		CHECK_PTP_RC(ptp_sony_getdevicepropdesc (params, propcode, &params->deviceproperties[i].desc));
 
 		time(&now);
 		params->deviceproperties[i].timestamp = now;
@@ -3159,9 +3175,7 @@ ptp_generic_getdevicepropdesc (PTPParams
 
 
 	if (ptp_operation_issupported(params, PTP_OC_GetDevicePropDesc)) {
-		ret = ptp_getdevicepropdesc (params, propcode, &params->deviceproperties[i].desc);
-		if (ret != PTP_RC_OK)
-			return ret;
+		CHECK_PTP_RC(ptp_getdevicepropdesc (params, propcode, &params->deviceproperties[i].desc));
 
 		time(&now);
 		params->deviceproperties[i].timestamp = now;
@@ -3189,9 +3203,19 @@ uint16_t
 ptp_generic_setdevicepropvalue (PTPParams* params, uint16_t propcode,
 	PTPPropertyValue *value, uint16_t datatype)
 {
+	unsigned int i;
+
+	/* reset the cache entry */
+	for (i=0;i<params->nrofdeviceproperties;i++)
+		if (params->deviceproperties[i].desc.DevicePropertyCode == propcode)
+			break;
+	if (i != params->nrofdeviceproperties)
+		params->deviceproperties[i].timestamp = 0;
+
 	/* FIXME: change the cache? hmm */
+	/* this works for some methods, but not for all */
 	if (	(params->deviceinfo.VendorExtensionID == PTP_VENDOR_SONY) &&
-		ptp_operation_issupported(params, PTP_OC_SONY_SetControlDeviceB)
+		ptp_operation_issupported(params, PTP_OC_SONY_SetControlDeviceA)
 	)
 		return ptp_sony_setdevicecontrolvaluea (params, propcode, value, datatype);
 	return ptp_setdevicepropvalue (params, propcode, value, datatype);
@@ -3210,22 +3234,19 @@ ptp_generic_setdevicepropvalue (PTPParam
  *
  **/
 uint16_t
-ptp_nikon_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int *size) {
+ptp_nikon_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int *size)
+{
 	PTPContainer	ptp;
-	uint16_t	ret;
-	unsigned char	*xdata = NULL;
-	unsigned int 	xsize;
+	unsigned char	*data = NULL;
+	unsigned int	xsize = 0;
 
 	*props = NULL;
 	*size = 0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_NIKON_GetVendorPropCodes;
-	ptp.Nparam	= 0;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &xdata, &xsize); 
-	if (ret == PTP_RC_OK)
-        	*size = ptp_unpack_uint16_t_array(params,xdata,0,props);
-	free (xdata);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetVendorPropCodes);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &xsize));
+	*size = ptp_unpack_uint16_t_array(params,data,0,xsize,props);
+	free (data);
+	return PTP_RC_OK;
 }
 
 uint16_t
@@ -3234,14 +3255,8 @@ ptp_nikon_getfileinfoinblock ( PTPParams
 	unsigned char **data, unsigned int *size
 ) {
 	PTPContainer ptp;
-	*data = NULL;
-	*size = 0;
-	PTP_CNT_INIT(ptp);
-	ptp.Code	= PTP_OC_NIKON_GetFileInfoInBlock;
-	ptp.Nparam	= 3;
-	ptp.Param1	= p1;
-	ptp.Param2	= p2;
-	ptp.Param3	= p3;
+
+	PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetFileInfoInBlock, p1, p2, p3);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size); 
 }
 
@@ -3260,9 +3275,7 @@ ptp_nikon_get_liveview_image (PTPParams*
 {
         PTPContainer ptp;
         
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_NIKON_GetLiveViewImg;
-        ptp.Nparam=0;
+        PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetLiveViewImg);
         return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
 }
 
@@ -3280,22 +3293,18 @@ uint16_t
 ptp_nikon_get_preview_image (PTPParams* params, unsigned char **xdata, unsigned int *xsize,
 	uint32_t *handle)
 {
-        PTPContainer	ptp;
-	uint16_t	ret;
-        
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_NIKON_GetPreviewImg;
-        ptp.Nparam=0;
+	PTPContainer	ptp;
+
+        PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetPreviewImg);
+
 	/* FIXME:
 	 * pdslrdashboard passes 3 parameters:
 	 * objectid, minimum size, maximum size
 	 */
-        ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, xdata, xsize);
-	if (ret == PTP_RC_OK) {
-		if (ptp.Nparam > 0)
-			*handle = ptp.Param1;
-	}
-	return ret;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, xdata, xsize));
+	if (ptp.Nparam > 0)
+		*handle = ptp.Param1;
+	return PTP_RC_OK;
 }
 
 /**
@@ -3313,10 +3322,7 @@ ptp_canon_eos_get_viewfinder_image (PTPP
 {
         PTPContainer ptp;
         
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_CANON_EOS_GetViewFinderData;
-        ptp.Nparam=1;
-        ptp.Param1=0x00100000; /* from trace */
+        PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetViewFinderData, 0x00100000 /* from trace */);
         return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
 }
 
@@ -3325,10 +3331,7 @@ ptp_canon_eos_get_viewfinder_image_handl
 {
         PTPContainer ptp;
         
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_CANON_EOS_GetViewFinderData;
-        ptp.Nparam=1;
-        ptp.Param1=0x00100000; /* from trace */
+        PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetViewFinderData, 0x00100000 /* from trace */);
         return ptp_transaction_new(params, &ptp, PTP_DP_GETDATA, 0, handler);
 }
 
@@ -3347,21 +3350,16 @@ ptp_canon_eos_get_viewfinder_image_handl
 uint16_t
 ptp_nikon_check_event (PTPParams* params, PTPContainer** event, unsigned int* evtcnt)
 {
-        PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *data = NULL;
-	unsigned int size = 0;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_NIKON_CheckEvent;
-	ptp.Nparam=0;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_NIKON_CheckEvent);
 	*evtcnt = 0;
-	ret = ptp_transaction (params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret == PTP_RC_OK) {
-		ptp_unpack_Nikon_EC (params, data, size, event, evtcnt);
-		free (data);
-	}
-	return ret;
+	CHECK_PTP_RC(ptp_transaction (params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ptp_unpack_Nikon_EC (params, data, size, event, evtcnt);
+	free (data);
+	return PTP_RC_OK;
 }
 
 /**
@@ -3381,9 +3379,7 @@ ptp_nikon_getptpipinfo (PTPParams* param
 {
         PTPContainer ptp;
         
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_NIKON_GetDevicePTPIPInfo;
-        ptp.Nparam=0;
+        PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetDevicePTPIPInfo);
         return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, size);
 }
 
@@ -3400,28 +3396,24 @@ ptp_nikon_getptpipinfo (PTPParams* param
 uint16_t
 ptp_nikon_getwifiprofilelist (PTPParams* params)
 {
-        PTPContainer ptp;
-	unsigned char* data;
-	unsigned int size;
-	unsigned int pos;
-	unsigned int profn;
-	unsigned int n;
-	char* buffer;
-	uint8_t len;
-	
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_NIKON_GetProfileAllData;
-        ptp.Nparam=0;
-	size = 0;
-	data = NULL;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data;
+	unsigned int	size, pos, profn, n;
+	char		*buffer;
+	uint8_t		len;
+
+        PTP_CNT_INIT(ptp, PTP_OC_NIKON_GetProfileAllData);
 	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
 
-	if (size < 2) return PTP_RC_Undefined; /* FIXME: Add more precise error code */
+	ret = PTP_RC_Undefined; /* FIXME: Add more precise error code */
+
+	if (size < 2)
+		goto exit;
 
 	params->wifi_profiles_version = data[0];
 	params->wifi_profiles_number = data[1];
-	if (params->wifi_profiles)
-		free(params->wifi_profiles);
+	free(params->wifi_profiles);
 	
 	params->wifi_profiles = malloc(params->wifi_profiles_number*sizeof(PTPNIKONWifiProfile));
 	memset(params->wifi_profiles, 0, params->wifi_profiles_number*sizeof(PTPNIKONWifiProfile));
@@ -3429,13 +3421,15 @@ ptp_nikon_getwifiprofilelist (PTPParams*
 	pos = 2;
 	profn = 0;
 	while (profn < params->wifi_profiles_number && pos < size) {
-		if (pos+6 >= size) return PTP_RC_Undefined;
+		if (pos+6 >= size)
+			goto exit;
 		params->wifi_profiles[profn].id = data[pos++];
 		params->wifi_profiles[profn].valid = data[pos++];
 
 		n = dtoh32a(&data[pos]);
 		pos += 4;
-		if (pos+n+4 >= size) return PTP_RC_Undefined;
+		if (pos+n+4 >= size)
+			goto exit;
 		strncpy(params->wifi_profiles[profn].profile_name, (char*)&data[pos], n);
 		params->wifi_profiles[profn].profile_name[16] = '\0';
 		pos += n;
@@ -3444,21 +3438,24 @@ ptp_nikon_getwifiprofilelist (PTPParams*
 		params->wifi_profiles[profn].device_type = data[pos++];
 		params->wifi_profiles[profn].icon_type = data[pos++];
 
-		buffer = ptp_unpack_string(params, data, pos, &len);
+		buffer = ptp_unpack_string(params, data, pos, size, &len);
 		strncpy(params->wifi_profiles[profn].creation_date, buffer, sizeof(params->wifi_profiles[profn].creation_date));
 		free (buffer);
 		pos += (len*2+1);
-		if (pos+1 >= size) return PTP_RC_Undefined;
+		if (pos+1 >= size)
+			goto exit;
 		/* FIXME: check if it is really last usage date */
-		buffer = ptp_unpack_string(params, data, pos, &len);
+		buffer = ptp_unpack_string(params, data, pos, size, &len);
 		strncpy(params->wifi_profiles[profn].lastusage_date, buffer, sizeof(params->wifi_profiles[profn].lastusage_date));
 		free (buffer);
 		pos += (len*2+1);
-		if (pos+5 >= size) return PTP_RC_Undefined;
+		if (pos+5 >= size)
+			goto exit;
 		
 		n = dtoh32a(&data[pos]);
 		pos += 4;
-		if (pos+n >= size) return PTP_RC_Undefined;
+		if (pos+n >= size)
+			goto exit;
 		strncpy(params->wifi_profiles[profn].essid, (char*)&data[pos], n);
 		params->wifi_profiles[profn].essid[32] = '\0';
 		pos += n;
@@ -3480,8 +3477,11 @@ ptp_nikon_getwifiprofilelist (PTPParams*
 
 	ptp_nikon_writewifiprofile(params, &test);
 #endif
-
-	return PTP_RC_OK;
+	/* everything went Ok */
+	ret = PTP_RC_OK;
+exit:
+	free (data);
+	return ret;
 }
 
 /**
@@ -3500,8 +3500,6 @@ ptp_nikon_getwifiprofilelist (PTPParams*
 uint16_t
 ptp_nikon_writewifiprofile (PTPParams* params, PTPNIKONWifiProfile* profile)
 {
-	unsigned char guid[16];
-	
 	PTPContainer ptp;
 	unsigned char buffer[1024];
 	unsigned char* data = buffer;
@@ -3509,7 +3507,8 @@ ptp_nikon_writewifiprofile (PTPParams* p
 	int i;
 	uint8_t len;
 	int profilenr = -1;
-	
+	unsigned char guid[16];
+
 	ptp_nikon_getptpipguid(guid);
 
 	if (!params->wifi_profiles)
@@ -3580,10 +3579,7 @@ ptp_nikon_writewifiprofile (PTPParams* p
 	}
 	size = 0xC4;
 	       
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_NIKON_SendProfileData;
-	ptp.Nparam=1;
-	ptp.Param1=profilenr;
+	PTP_CNT_INIT(ptp, PTP_OC_NIKON_SendProfileData, profilenr);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
 }
 
@@ -3604,20 +3600,16 @@ uint16_t
 ptp_mtp_getobjectpropssupported (PTPParams* params, uint16_t ofc,
 		 uint32_t *propnum, uint16_t **props
 ) {
-        PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *data = NULL;
-	unsigned int size = 0;
-        
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_MTP_GetObjectPropsSupported;
-        ptp.Nparam = 1;
-        ptp.Param1 = ofc;
-        ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret == PTP_RC_OK)
-        	*propnum=ptp_unpack_uint16_t_array(params,data,0,props);
+	PTPContainer	ptp;
+	unsigned char	*data = NULL;
+	unsigned int	xsize = 0;
+
+        PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjectPropsSupported, ofc);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &xsize));
+	if (!data) return PTP_RC_GeneralError;
+	*propnum=ptp_unpack_uint16_t_array (params, data, 0, xsize, props);
 	free(data);
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -3636,21 +3628,15 @@ uint16_t
 ptp_mtp_getobjectpropdesc (
 	PTPParams* params, uint16_t opc, uint16_t ofc, PTPObjectPropDesc *opd
 ) {
-        PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *data = NULL;
-	unsigned int size = 0;
-        
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_MTP_GetObjectPropDesc;
-        ptp.Nparam = 2;
-        ptp.Param1 = opc;
-        ptp.Param2 = ofc;
-        ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret == PTP_RC_OK)
-		ptp_unpack_OPD (params, data, opd, size);
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
+
+        PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjectPropDesc, opc, ofc);
+        CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	ptp_unpack_OPD (params, data, opd, size);
 	free(data);
-	return ret;
+	return PTP_RC_OK;
 }
 
 /**
@@ -3670,25 +3656,17 @@ ptp_mtp_getobjectpropvalue (
 	PTPParams* params, uint32_t oid, uint16_t opc,
 	PTPPropertyValue *value, uint16_t datatype
 ) {
-        PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *data = NULL;
-	unsigned int size = 0;
-	unsigned int offset = 0;
+	PTPContainer	ptp;
+	uint16_t	ret = PTP_RC_OK;
+	unsigned char	*data;
+	unsigned int	size, offset = 0;
         
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_MTP_GetObjectPropValue;
-        ptp.Nparam = 2;
-        ptp.Param1 = oid;
-        ptp.Param2 = opc;
-        ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size);
-	if (ret == PTP_RC_OK) {
-		int ret2 = ptp_unpack_DPV(params, data, &offset, size, value, datatype);
-		if (!ret2) {
-			ptp_debug (params, "ptp_mtp_getobjectpropvalue: unpacking DPV failed");
-			ret = PTP_RC_GeneralError;
-		}
-	}
+        PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjectPropValue, oid, opc);
+        CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+        if (!ptp_unpack_DPV(params, data, &offset, size, value, datatype)) {
+                ptp_debug (params, "ptp_mtp_getobjectpropvalue: unpacking DPV failed");
+                ret = PTP_RC_GeneralError;
+        }
 	free(data);
 	return ret;
 }
@@ -3710,16 +3688,12 @@ ptp_mtp_setobjectpropvalue (
 	PTPParams* params, uint32_t oid, uint16_t opc,
 	PTPPropertyValue *value, uint16_t datatype
 ) {
-        PTPContainer ptp;
-	uint16_t ret;
-	unsigned char *data = NULL;
-	unsigned int size ;
-        
-        PTP_CNT_INIT(ptp);
-        ptp.Code=PTP_OC_MTP_SetObjectPropValue;
-        ptp.Nparam = 2;
-        ptp.Param1 = oid;
-        ptp.Param2 = opc;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
+
+        PTP_CNT_INIT(ptp, PTP_OC_MTP_SetObjectPropValue, oid, opc);
 	size = ptp_pack_DPV(params, value, &data, datatype);
         ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
 	free(data);
@@ -3729,116 +3703,94 @@ ptp_mtp_setobjectpropvalue (
 uint16_t
 ptp_mtp_getobjectreferences (PTPParams* params, uint32_t handle, uint32_t** ohArray, uint32_t* arraylen)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	unsigned char* dpv=NULL;
-	unsigned int dpvlen = 0;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_MTP_GetObjectReferences;
-	ptp.Param1=handle;
-	ptp.Nparam=1;
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &dpv, &dpvlen);
-	if (ret == PTP_RC_OK) {
-		/* Sandisk Sansa skips the DATA phase, but returns OK as response.
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjectReferences, handle);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data , &size));
+	/* Sandisk Sansa skips the DATA phase, but returns OK as response.
 		 * this will gives us a NULL here. Handle it. -Marcus */
-		if ((dpv == NULL) || (dpvlen == 0)) {
-			*arraylen = 0;
-			*ohArray = NULL;
-		} else {
-			*arraylen = ptp_unpack_uint32_t_array(params, dpv, 0, ohArray);
-		}
+	if ((data == NULL) || (size == 0)) {
+		*arraylen = 0;
+		*ohArray = NULL;
+	} else {
+		*arraylen = ptp_unpack_uint32_t_array(params, data , 0, size, ohArray);
 	}
-	free(dpv);
-	return ret;
+	free(data);
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_mtp_setobjectreferences (PTPParams* params, uint32_t handle, uint32_t* ohArray, uint32_t arraylen)
 {
-	PTPContainer ptp;
-	uint16_t ret;
-	uint32_t size;
-	unsigned char* dpv=NULL;
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code   = PTP_OC_MTP_SetObjectReferences;
-	ptp.Param1 = handle;
-	ptp.Nparam = 1;
-	size = ptp_pack_uint32_t_array(params, ohArray, arraylen, &dpv);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, (unsigned char **)&dpv, NULL);
-	free(dpv);
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
+
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_SetObjectReferences, handle);
+	size = ptp_pack_uint32_t_array(params, ohArray, arraylen, &data);
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	return ret;
 }
 
 uint16_t
 ptp_mtp_getobjectproplist (PTPParams* params, uint32_t handle, MTPProperties **props, int *nrofprops)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* opldata = NULL;
-	unsigned int oplsize;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_MTP_GetObjPropList;
-	ptp.Param1 = handle;
-	ptp.Param2 = 0x00000000U;  /* 0x00000000U should be "all formats" */
-	ptp.Param3 = 0xFFFFFFFFU;  /* 0xFFFFFFFFU should be "all properties" */
-	ptp.Param4 = 0x00000000U;
-	ptp.Param5 = 0xFFFFFFFFU;  /* means - return full tree below the Param1 handle */
-	ptp.Nparam = 5;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &opldata, &oplsize);  
-	if (ret == PTP_RC_OK) *nrofprops = ptp_unpack_OPL(params, opldata, props, oplsize);
-	if (opldata != NULL)
-		free(opldata);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjPropList, handle,
+		     0x00000000U,  /* 0x00000000U should be "all formats" */
+		     0xFFFFFFFFU,  /* 0xFFFFFFFFU should be "all properties" */
+		     0x00000000U,
+		     0xFFFFFFFFU  /* means - return full tree below the Param1 handle */
+	);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	*nrofprops = ptp_unpack_OPL(params, data, props, size);
+	free(data);
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_mtp_getobjectproplist_single (PTPParams* params, uint32_t handle, MTPProperties **props, int *nrofprops)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* opldata = NULL;
-	unsigned int oplsize;
+	PTPContainer	ptp;
+	unsigned char	*data;
+	unsigned int	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_MTP_GetObjPropList;
-	ptp.Param1 = handle;
-	ptp.Param2 = 0x00000000U;  /* 0x00000000U should be "all formats" */
-	ptp.Param3 = 0xFFFFFFFFU;  /* 0xFFFFFFFFU should be "all properties" */
-	ptp.Param4 = 0x00000000U;
-	ptp.Param5 = 0x00000000U;  /* means - return single tree below the Param1 handle */
-	ptp.Nparam = 5;
-	ret = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &opldata, &oplsize);  
-	if (ret == PTP_RC_OK) *nrofprops = ptp_unpack_OPL(params, opldata, props, oplsize);
-	if (opldata != NULL)
-		free(opldata);
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_GetObjPropList, handle,
+		     0x00000000U,  /* 0x00000000U should be "all formats" */
+		     0xFFFFFFFFU,  /* 0xFFFFFFFFU should be "all properties" */
+		     0x00000000U,
+		     0x00000000U  /* means - return single tree below the Param1 handle */
+	);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+	*nrofprops = ptp_unpack_OPL(params, data, props, size);
+	free(data);
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_mtp_sendobjectproplist (PTPParams* params, uint32_t* store, uint32_t* parenthandle, uint32_t* handle,
 			    uint16_t objecttype, uint64_t objectsize, MTPProperties *props, int nrofprops)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* opldata=NULL;
-	uint32_t oplsize;
+	PTPContainer	ptp;
+	uint16_t	ret;
+	unsigned char	*data = NULL;
+	uint32_t	size;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_MTP_SendObjectPropList;
-	ptp.Param1 = *store;
-	ptp.Param2 = *parenthandle;
-	ptp.Param3 = (uint32_t) objecttype;
-	ptp.Param4 = (uint32_t) (objectsize >> 32);
-	ptp.Param5 = (uint32_t) (objectsize & 0xffffffffU);
-	ptp.Nparam = 5;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_SendObjectPropList, *store, *parenthandle, (uint32_t) objecttype,
+		     (uint32_t) (objectsize >> 32), (uint32_t) (objectsize & 0xffffffffU)
+	);
 
 	/* Set object handle to 0 for a new object */
-	oplsize = ptp_pack_OPL(params,props,nrofprops,&opldata);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, oplsize, &opldata, NULL); 
-	free(opldata);
+	size = ptp_pack_OPL(params,props,nrofprops,&data);
+	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL);
+	free(data);
 	*store = ptp.Param1;
 	*parenthandle = ptp.Param2;
 	*handle = ptp.Param3; 
@@ -3849,20 +3801,15 @@ ptp_mtp_sendobjectproplist (PTPParams* p
 uint16_t
 ptp_mtp_setobjectproplist (PTPParams* params, MTPProperties *props, int nrofprops)
 {
-	uint16_t ret;
-	PTPContainer ptp;
-	unsigned char* opldata=NULL;
-	uint32_t oplsize;
-  
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_MTP_SetObjPropList;
-	ptp.Nparam = 0;
-  
-	oplsize = ptp_pack_OPL(params,props,nrofprops,&opldata);
-	ret = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, oplsize, &opldata, NULL); 
-	free(opldata);
+	PTPContainer	ptp;
+	unsigned char	*data = NULL;
+	uint32_t	size;
 
-	return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_SetObjPropList);
+	size = ptp_pack_OPL(params,props,nrofprops,&data);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, &data, NULL));
+	free(data);
+	return PTP_RC_OK;
 }
 
 uint16_t
@@ -3870,8 +3817,7 @@ ptp_mtpz_sendwmdrmpdapprequest (PTPParam
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_WMDRMPD_SendWMDRMPDAppRequest);
 	return ptp_transaction (params, &ptp, PTP_DP_SENDDATA, size, &appcertmsg, NULL);
 }
 
@@ -3880,8 +3826,7 @@ ptp_mtpz_getwmdrmpdappresponse (PTPParam
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code = PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse;
+	PTP_CNT_INIT(ptp, PTP_OC_MTP_WMDRMPD_GetWMDRMPDAppResponse);
 	*size = 0;
 	*response = NULL;
 	return ptp_transaction (params, &ptp, PTP_DP_GETDATA, 0, response, size);
@@ -3894,12 +3839,7 @@ ptp_chdk_get_memory(PTPParams* params, i
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=3;
-	ptp.Param1=PTP_CHDK_GetMemory;
-	ptp.Param2=start;
-	ptp.Param3=num;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_GetMemory, start, num);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, buf, NULL);
 }
 
@@ -3909,15 +3849,22 @@ ptp_chdk_set_memory_long(PTPParams* para
 	PTPContainer ptp;
 	unsigned char *buf = (unsigned char *) &val; /* FIXME ... endianness? */
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=3;
-	ptp.Param1=PTP_CHDK_SetMemory;
-	ptp.Param2=addr;
-	ptp.Param3=4;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_SetMemory, addr, 4);
 	return ptp_transaction(params, &ptp, PTP_DP_SENDDATA, 4, &buf, NULL);
 }
 
+uint16_t
+ptp_chdk_download(PTPParams* params, char *remote_fn, PTPDataHandler *handler)
+{
+	PTPContainer ptp;
+
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_TempData, 0);
+	CHECK_PTP_RC (ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(remote_fn), (unsigned char**)&remote_fn, NULL));
+
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_DownloadFile);
+	return ptp_transaction_new (params, &ptp, PTP_DP_GETDATA, 0, handler);
+}
+
 #if 0
 int ptp_chdk_upload(PTPParams* params, char *local_fn, char *remote_fn)
 {
@@ -3927,10 +3874,7 @@ int ptp_chdk_upload(PTPParams* params, c
   FILE *f;
   unsigned file_len,data_len,file_name_len;
 
-  PTP_CNT_INIT(ptp);
-  ptp.Code=PTP_OC_CHDK;
-  ptp.Nparam=1;
-  ptp.Param1=PTP_CHDK_UploadFile;
+  PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_UploadFile);
 
   f = fopen(local_fn,"rb");
   if ( f == NULL )
@@ -3964,62 +3908,6 @@ int ptp_chdk_upload(PTPParams* params, c
   return 1;
 }
 
-static uint16_t gd_to_file(PTPParams* params, PTPGetdataParams *gdparams, unsigned len, unsigned char *bytes) {
-	FILE *f = (FILE *)gdparams->handler_data;
-	size_t count=fwrite(bytes,1,len,f);
-	if(count != len) {
-		return PTP_ERROR_IO;
-	}
-	return PTP_RC_OK;
-}
-
-int ptp_chdk_download(PTPParams* params, char *remote_fn, char *local_fn)
-{
-  uint16_t ret;
-  PTPContainer ptp;
-  PTPGetdataParams gdparams;
-  FILE *f;
-
-  f = fopen(local_fn,"wb");
-  if ( f == NULL )
-  {
-    ptp_error(params,"could not open file \'%s\'",local_fn);
-    return 0;
-  }
-
-  PTP_CNT_INIT(ptp);
-  ptp.Code=PTP_OC_CHDK;
-  ptp.Nparam=2;
-  ptp.Param1=PTP_CHDK_TempData;
-  ptp.Param2=0;
-  ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(remote_fn), &remote_fn, NULL);
-  if ( ret != PTP_RC_OK )
-  {
-    ptp_error(params,"unexpected return code 0x%x",ret);
-	fclose(f);
-    return 0;
-  }
-
-  PTP_CNT_INIT(ptp);
-  ptp.Code=PTP_OC_CHDK;
-  ptp.Nparam=1;
-  ptp.Param1=PTP_CHDK_DownloadFile;
-
-  PTP_CNT_INIT(gdparams);
-
-  gdparams.handler = gd_to_file;
-  gdparams.block_size = 0; // default
-  gdparams.handler_data = f;
-  ret=ptp_getdata_transaction(params, &ptp, &gdparams);
-  fclose(f);
-  if ( ret != PTP_RC_OK )
-  {
-    ptp_error(params,"unexpected return code 0x%x",ret);
-    return 0;
-  }
-  
-  return 1;
-}
 #endif
 
 /*
@@ -4032,173 +3920,115 @@ int ptp_chdk_download(PTPParams* params,
 uint16_t
 ptp_chdk_rcisready(PTPParams* params, int *isready, int *imgnum)
 {
-	uint16_t ret;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_RemoteCaptureIsReady;
-
-	ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ( ret != PTP_RC_OK )
-		return ret;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_RemoteCaptureIsReady);
+	*isready = *imgnum = 0;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*isready=ptp.Param1;
 	*imgnum=ptp.Param2;
-	return ret;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_rcgetchunk(PTPParams* params, int fmt, ptp_chdk_rc_chunk *chunk)
 {
-	uint16_t ret;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=2;
-	ptp.Param1=PTP_CHDK_RemoteCaptureGetData;
-	ptp.Param2=fmt; //get chunk
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_RemoteCaptureGetData, fmt); //get chunk
 
 	chunk->data = NULL;
 	chunk->size = 0;
 	chunk->offset = 0;
 	chunk->last = 0;
-
 	// TODO should allow ptp_getdata_transaction to send chunks directly to file, or to mem
-	ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &chunk->data, NULL);
-	if ( ret != PTP_RC_OK )
-	  return ret;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &chunk->data, NULL));
 	chunk->size = ptp.Param1;
 	chunk->last = (ptp.Param2 == 0);
   	chunk->offset = ptp.Param3; //-1 for none
-	return ret;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_exec_lua(PTPParams* params, char *script, int flags, int *script_id, int *status)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=2;
-	ptp.Param1=PTP_CHDK_ExecuteScript;
-	ptp.Param2=PTP_CHDK_SL_LUA | flags;
-
-	r = ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(script)+1, (unsigned char**)&script, NULL);
-
-	if ( r != PTP_RC_OK ) {
-		*script_id = 0;
-		*status = 0;
-		return r;
-	} else {
-		*script_id = ptp.Param1;
-		*status = ptp.Param2;
-		//return (*status == PTP_CHDK_S_ERRTYPE_NONE);
-		if (*status == PTP_CHDK_S_ERRTYPE_NONE)
-			return PTP_RC_OK;
-		else
-			return r;
-	}
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_ExecuteScript, PTP_CHDK_SL_LUA | flags);
+	*script_id = 0;
+	*status = 0;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(script)+1, (unsigned char**)&script, NULL));
+	*script_id = ptp.Param1;
+	*status = ptp.Param2;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_get_version(PTPParams* params, int *major, int *minor)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_Version;
-	r=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ( r != PTP_RC_OK )
-		return r;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_Version);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*major = ptp.Param1;
 	*minor = ptp.Param2;
-	return r;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_get_script_status(PTPParams* params, unsigned *status)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_ScriptStatus;
-	r=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ( r != PTP_RC_OK )
-		return r;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_ScriptStatus);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*status = ptp.Param1;
-	return r;
+	return PTP_RC_OK;
 }
 uint16_t
 ptp_chdk_get_script_support(PTPParams* params, unsigned *status)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_ScriptSupport;
-	r=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL);
-	if ( r != PTP_RC_OK )
-		return r;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_ScriptSupport);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL, NULL));
 	*status = ptp.Param1;
-	return r;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_write_script_msg(PTPParams* params, char *data, unsigned size, int target_script_id, int *status)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
 	// a zero length data phase appears to do bad things, camera stops responding to PTP
 	if(!size) {
 		ptp_error(params,"zero length message not allowed");
 		*status = 0;
-		return 0;
-	}
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=2;
-	ptp.Param1=PTP_CHDK_WriteScriptMsg;
-	ptp.Param2=target_script_id;
-
-	r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, (unsigned char**)&data, NULL);
-	if ( r != PTP_RC_OK ) {
-		*status = 0;
-		return r;
+		return PTP_ERROR_BADPARAM;
 	}
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_WriteScriptMsg, target_script_id);
+	*status = 0;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size, (unsigned char**)&data, NULL));
 	*status = ptp.Param1;
-	return r;
+	return PTP_RC_OK;
 }
 uint16_t
 ptp_chdk_read_script_msg(PTPParams* params, ptp_chdk_script_msg **msg)
 {
-	uint16_t r;
-	PTPContainer ptp;
-	unsigned char *data = NULL;
+	PTPContainer	ptp;
+	unsigned char	*data;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_ReadScriptMsg;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_ReadScriptMsg);
 
 	*msg = NULL;
 
 	/* camera will always send data, otherwise getdata will cause problems */
-	r=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL);
-	if ( r != PTP_RC_OK )
-		return r;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, NULL));
+	if (!data) {
+		ptp_error(params,"no data received");
+		return PTP_ERROR_BADPARAM;
+	}
 
 	/* for convenience, always allocate an extra byte and null it*/
 	*msg = malloc(sizeof(ptp_chdk_script_msg) + ptp.Param4 + 1);
@@ -4209,48 +4039,31 @@ ptp_chdk_read_script_msg(PTPParams* para
 	memcpy((*msg)->data,data,(*msg)->size);
 	(*msg)->data[(*msg)->size] = 0;
 	free(data);
-	return r;
+	return PTP_RC_OK;
 }
 
 uint16_t
-ptp_chdk_get_live_data(PTPParams* params, unsigned flags, unsigned char **data, unsigned int *data_size) {
-	uint16_t r;
+ptp_chdk_get_live_data(PTPParams* params, unsigned flags, unsigned char **data, unsigned int *data_size)
+{
 	PTPContainer ptp;
-	unsigned int real_size = 0;
-
-
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=2;
-	ptp.Param1=PTP_CHDK_GetDisplayData;
-	ptp.Param2=flags;
 
-	*data = NULL;
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_GetDisplayData, flags);
 	*data_size = 0;
-
-	r = ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, &real_size);
-	if ( r != PTP_RC_OK )
-		return r;
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, data, NULL));
 	*data_size = ptp.Param1;
-	return r;
+	return PTP_RC_OK;
 }
 
 uint16_t
 ptp_chdk_call_function(PTPParams* params, int *args, int size, int *ret)
 {
-	uint16_t r;
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_CHDK;
-	ptp.Nparam=1;
-	ptp.Param1=PTP_CHDK_CallFunction;
-	r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size*sizeof(int), (unsigned char **) &args, NULL);
-	if ( r != PTP_RC_OK )
-		return r;
-	if ( ret )
+	PTP_CNT_INIT(ptp, PTP_OC_CHDK, PTP_CHDK_CallFunction);
+	CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size*sizeof(int), (unsigned char **) &args, NULL));
+	if (ret)
 		*ret = ptp.Param1;
-	return r;
+	return PTP_RC_OK;
 }
 
 
@@ -4283,14 +4096,7 @@ ptp_android_getpartialobject64 (PTPParam
 {
 	PTPContainer ptp;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_ANDROID_GetPartialObject64;
-	ptp.Param1=handle;
-	ptp.Param2=offset & 0xFFFFFFFF;
-	ptp.Param3=offset >> 32;
-	ptp.Param4=maxbytes;
-	ptp.Nparam=4;
-	*len=0;
+	PTP_CNT_INIT(ptp, PTP_OC_ANDROID_GetPartialObject64, handle, offset & 0xFFFFFFFF, offset >> 32, maxbytes);
 	return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, object, len);
 }
 
@@ -4298,16 +4104,10 @@ uint16_t
 ptp_android_sendpartialobject (PTPParams* params, uint32_t handle, uint64_t offset,
 				unsigned char* object,	uint32_t len)
 {
-	uint32_t err;
-	PTPContainer ptp;
+	PTPContainer	ptp;
+	uint16_t	ret;
 
-	PTP_CNT_INIT(ptp);
-	ptp.Code=PTP_OC_ANDROID_SendPartialObject;
-	ptp.Param1=handle;
-	ptp.Param2=offset & 0xFFFFFFFF;
-	ptp.Param3=offset >> 32;
-	ptp.Param4=len;
-	ptp.Nparam=4;
+	PTP_CNT_INIT(ptp, PTP_OC_ANDROID_SendPartialObject, handle, offset & 0xFFFFFFFF, offset >> 32, len);
 
 	/*
 	 * MtpServer.cpp is buggy: it uses write() without offset
@@ -4315,10 +4115,10 @@ ptp_android_sendpartialobject (PTPParams
 	 * the header packet
 	 */
 	params->split_header_data = 1;
-	err=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, len, &object, NULL);
+	ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, len, &object, NULL);
 	params->split_header_data = 0;
 
-	return err;
+	return ret;
 }
 
 
@@ -4369,75 +4169,91 @@ ptp_free_object (PTPObject *ob)
 	ob->flags = 0;
 }
 
-const char *
-ptp_strerror(uint16_t error) {
+/* PTP error descriptions */
+static struct {
+	uint16_t rc;
+	uint16_t vendor;
+	const char *txt;
+} ptp_errors[] = {
+	{PTP_RC_Undefined,		0, N_("PTP Undefined Error")},
+	{PTP_RC_OK,			0, N_("PTP OK!")},
+	{PTP_RC_GeneralError,		0, N_("PTP General Error")},
+	{PTP_RC_SessionNotOpen,		0, N_("PTP Session Not Open")},
+	{PTP_RC_InvalidTransactionID,	0, N_("PTP Invalid Transaction ID")},
+	{PTP_RC_OperationNotSupported,	0, N_("PTP Operation Not Supported")},
+	{PTP_RC_ParameterNotSupported,	0, N_("PTP Parameter Not Supported")},
+	{PTP_RC_IncompleteTransfer,	0, N_("PTP Incomplete Transfer")},
+	{PTP_RC_InvalidStorageId,	0, N_("PTP Invalid Storage ID")},
+	{PTP_RC_InvalidObjectHandle,	0, N_("PTP Invalid Object Handle")},
+	{PTP_RC_DevicePropNotSupported,	0, N_("PTP Device Prop Not Supported")},
+	{PTP_RC_InvalidObjectFormatCode,0, N_("PTP Invalid Object Format Code")},
+	{PTP_RC_StoreFull,		0, N_("PTP Store Full")},
+	{PTP_RC_ObjectWriteProtected,	0, N_("PTP Object Write Protected")},
+	{PTP_RC_StoreReadOnly,		0, N_("PTP Store Read Only")},
+	{PTP_RC_AccessDenied,		0, N_("PTP Access Denied")},
+	{PTP_RC_NoThumbnailPresent,	0, N_("PTP No Thumbnail Present")},
+	{PTP_RC_SelfTestFailed,		0, N_("PTP Self Test Failed")},
+	{PTP_RC_PartialDeletion,	0, N_("PTP Partial Deletion")},
+	{PTP_RC_StoreNotAvailable,	0, N_("PTP Store Not Available")},
+	{PTP_RC_SpecificationByFormatUnsupported, 0, N_("PTP Specification By Format Unsupported")},
+	{PTP_RC_NoValidObjectInfo,	0, N_("PTP No Valid Object Info")},
+	{PTP_RC_InvalidCodeFormat,	0, N_("PTP Invalid Code Format")},
+	{PTP_RC_UnknownVendorCode,	0, N_("PTP Unknown Vendor Code")},
+	{PTP_RC_CaptureAlreadyTerminated, 0, N_("PTP Capture Already Terminated")},
+	{PTP_RC_DeviceBusy,		0, N_("PTP Device Busy")},
+	{PTP_RC_InvalidParentObject,	0, N_("PTP Invalid Parent Object")},
+	{PTP_RC_InvalidDevicePropFormat,0, N_("PTP Invalid Device Prop Format")},
+	{PTP_RC_InvalidDevicePropValue,	0, N_("PTP Invalid Device Prop Value")},
+	{PTP_RC_InvalidParameter,	0, N_("PTP Invalid Parameter")},
+	{PTP_RC_SessionAlreadyOpened,	0, N_("PTP Session Already Opened")},
+	{PTP_RC_TransactionCanceled,	0, N_("PTP Transaction Canceled")},
+	{PTP_RC_SpecificationOfDestinationUnsupported, 0, N_("PTP Specification Of Destination Unsupported")},
+
+	{PTP_RC_EK_FilenameRequired,	PTP_VENDOR_EASTMAN_KODAK, N_("Filename Required")},
+	{PTP_RC_EK_FilenameConflicts,	PTP_VENDOR_EASTMAN_KODAK, N_("Filename Conflicts")},
+	{PTP_RC_EK_FilenameInvalid,	PTP_VENDOR_EASTMAN_KODAK, N_("Filename Invalid")},
+
+	{PTP_RC_NIKON_HardwareError,		PTP_VENDOR_NIKON, N_("Hardware Error")},
+	{PTP_RC_NIKON_OutOfFocus,		PTP_VENDOR_NIKON, N_("Out of Focus")},
+	{PTP_RC_NIKON_ChangeCameraModeFailed,	PTP_VENDOR_NIKON, N_("Change Camera Mode Failed")},
+	{PTP_RC_NIKON_InvalidStatus,		PTP_VENDOR_NIKON, N_("Invalid Status")},
+	{PTP_RC_NIKON_SetPropertyNotSupported,	PTP_VENDOR_NIKON, N_("Set Property Not Supported")},
+	{PTP_RC_NIKON_WbResetError,		PTP_VENDOR_NIKON, N_("Whitebalance Reset Error")},
+	{PTP_RC_NIKON_DustReferenceError,	PTP_VENDOR_NIKON, N_("Dust Reference Error")},
+	{PTP_RC_NIKON_ShutterSpeedBulb,		PTP_VENDOR_NIKON, N_("Shutter Speed Bulb")},
+	{PTP_RC_NIKON_MirrorUpSequence,		PTP_VENDOR_NIKON, N_("Mirror Up Sequence")},
+	{PTP_RC_NIKON_CameraModeNotAdjustFNumber, PTP_VENDOR_NIKON, N_("Camera Mode Not Adjust FNumber")},
+	{PTP_RC_NIKON_NotLiveView,		PTP_VENDOR_NIKON, N_("Not in Liveview")},
+	{PTP_RC_NIKON_MfDriveStepEnd,		PTP_VENDOR_NIKON, N_("Mf Drive Step End")},
+	{PTP_RC_NIKON_MfDriveStepInsufficiency,	PTP_VENDOR_NIKON, N_("Mf Drive Step Insufficiency")},
+	{PTP_RC_NIKON_AdvancedTransferCancel,	PTP_VENDOR_NIKON, N_("Advanced Transfer Cancel")},
+
+	{PTP_RC_CANON_UNKNOWN_COMMAND,	PTP_VENDOR_CANON, N_("Unknown Command")},
+	{PTP_RC_CANON_OPERATION_REFUSED,PTP_VENDOR_CANON, N_("Operation Refused")},
+	{PTP_RC_CANON_LENS_COVER,	PTP_VENDOR_CANON, N_("Lens Cover Present")},
+	{PTP_RC_CANON_BATTERY_LOW,	PTP_VENDOR_CANON, N_("Battery Low")},
+	{PTP_RC_CANON_NOT_READY,	PTP_VENDOR_CANON, N_("Camera Not Ready")},
+
+	{PTP_ERROR_TIMEOUT,		0, N_("PTP Timeout")},
+	{PTP_ERROR_CANCEL,		0, N_("PTP Cancel Request")},
+	{PTP_ERROR_BADPARAM,		0, N_("PTP Invalid Parameter")},
+	{PTP_ERROR_RESP_EXPECTED,	0, N_("PTP Response Expected")},
+	{PTP_ERROR_DATA_EXPECTED,	0, N_("PTP Data Expected")},
+	{PTP_ERROR_IO,			0, N_("PTP I/O Error")},
+	{0, 0, NULL}
+};
 
+const char *
+ptp_strerror(uint16_t ret, uint16_t vendor)
+{
 	int i;
-	/* PTP error descriptions */
-	static struct {
-		short n;
-		const char *txt;
-	} ptp_errors[] = {
-	{PTP_RC_Undefined, 		N_("PTP: Undefined Error")},
-	{PTP_RC_OK, 			N_("PTP: OK!")},
-	{PTP_RC_GeneralError, 		N_("PTP: General Error")},
-	{PTP_RC_SessionNotOpen, 	N_("PTP: Session Not Open")},
-	{PTP_RC_InvalidTransactionID, 	N_("PTP: Invalid Transaction ID")},
-	{PTP_RC_OperationNotSupported, 	N_("PTP: Operation Not Supported")},
-	{PTP_RC_ParameterNotSupported, 	N_("PTP: Parameter Not Supported")},
-	{PTP_RC_IncompleteTransfer, 	N_("PTP: Incomplete Transfer")},
-	{PTP_RC_InvalidStorageId, 	N_("PTP: Invalid Storage ID")},
-	{PTP_RC_InvalidObjectHandle, 	N_("PTP: Invalid Object Handle")},
-	{PTP_RC_DevicePropNotSupported, N_("PTP: Device Prop Not Supported")},
-	{PTP_RC_InvalidObjectFormatCode, N_("PTP: Invalid Object Format Code")},
-	{PTP_RC_StoreFull, 		N_("PTP: Store Full")},
-	{PTP_RC_ObjectWriteProtected, 	N_("PTP: Object Write Protected")},
-	{PTP_RC_StoreReadOnly, 		N_("PTP: Store Read Only")},
-	{PTP_RC_AccessDenied,		N_("PTP: Access Denied")},
-	{PTP_RC_NoThumbnailPresent, 	N_("PTP: No Thumbnail Present")},
-	{PTP_RC_SelfTestFailed, 	N_("PTP: Self Test Failed")},
-	{PTP_RC_PartialDeletion, 	N_("PTP: Partial Deletion")},
-	{PTP_RC_StoreNotAvailable, 	N_("PTP: Store Not Available")},
-	{PTP_RC_SpecificationByFormatUnsupported,
-				N_("PTP: Specification By Format Unsupported")},
-	{PTP_RC_NoValidObjectInfo, 	N_("PTP: No Valid Object Info")},
-	{PTP_RC_InvalidCodeFormat, 	N_("PTP: Invalid Code Format")},
-	{PTP_RC_UnknownVendorCode, 	N_("PTP: Unknown Vendor Code")},
-	{PTP_RC_CaptureAlreadyTerminated,
-					N_("PTP: Capture Already Terminated")},
-	{PTP_RC_DeviceBusy, 		N_("PTP: Device Busy")},
-	{PTP_RC_InvalidParentObject, 	N_("PTP: Invalid Parent Object")},
-	{PTP_RC_InvalidDevicePropFormat, N_("PTP: Invalid Device Prop Format")},
-	{PTP_RC_InvalidDevicePropValue, N_("PTP: Invalid Device Prop Value")},
-	{PTP_RC_InvalidParameter, 	N_("PTP: Invalid Parameter")},
-	{PTP_RC_SessionAlreadyOpened, 	N_("PTP: Session Already Opened")},
-	{PTP_RC_TransactionCanceled, 	N_("PTP: Transaction Canceled")},
-	{PTP_RC_SpecificationOfDestinationUnsupported,
-			N_("PTP: Specification Of Destination Unsupported")},
-	{PTP_RC_EK_FilenameRequired,	N_("PTP: EK Filename Required")},
-	{PTP_RC_EK_FilenameConflicts,	N_("PTP: EK Filename Conflicts")},
-	{PTP_RC_EK_FilenameInvalid,	N_("PTP: EK Filename Invalid")},
-
-	{PTP_ERROR_IO,		  N_("PTP: I/O error")},
-	{PTP_ERROR_BADPARAM,	  N_("PTP: Error: bad parameter")},
-	{PTP_ERROR_DATA_EXPECTED, N_("PTP: Protocol error, data expected")},
-	{PTP_ERROR_RESP_EXPECTED, N_("PTP: Protocol error, response expected")},
-	{0, NULL}
-};
 
-	for (i=0; ptp_errors[i].txt!=NULL; i++)
-		if (ptp_errors[i].n == error)
+	for (i=0; ptp_errors[i].txt != NULL; i++)
+		if ((ptp_errors[i].rc == ret) && ((ptp_errors[i].vendor == 0) || (ptp_errors[i].vendor == vendor)))
 			return ptp_errors[i].txt;
 	return NULL;
 }
 
-void
-ptp_perror(PTPParams* params, uint16_t error) {
-	const char *txt = ptp_strerror(error);
-	if (txt != NULL)
-		ptp_error(params, txt);
-}
-
 const char*
 ptp_get_property_description(PTPParams* params, uint16_t dpc)
 {
@@ -4481,6 +4297,19 @@ ptp_get_property_description(PTPParams*
 		{PTP_DPC_UploadURL,		N_("Upload URL")},
 		{PTP_DPC_Artist,		N_("Artist")},
 		{PTP_DPC_CopyrightInfo,		N_("Copyright Info")},
+		{PTP_DPC_SupportedStreams,	N_("Supported Streams")},
+		{PTP_DPC_EnabledStreams,	N_("Enabled Streams")},
+		{PTP_DPC_VideoFormat,		N_("Video Format")},
+		{PTP_DPC_VideoResolution,	N_("Video Resolution")},
+		{PTP_DPC_VideoQuality,		N_("Video Quality")},
+		{PTP_DPC_VideoFrameRate,	N_("Video Framerate")},
+		{PTP_DPC_VideoContrast,		N_("Video Contrast")},
+		{PTP_DPC_VideoBrightness,	N_("Video Brightness")},
+		{PTP_DPC_AudioFormat,		N_("Audio Format")},
+		{PTP_DPC_AudioBitrate,		N_("Audio Bitrate")},
+		{PTP_DPC_AudioSamplingRate,	N_("Audio Samplingrate")},
+		{PTP_DPC_AudioBitPerSample,	N_("Audio Bits per sample")},
+		{PTP_DPC_AudioVolume,		N_("Audio Volume")},
 		{0,NULL}
 	};
 	struct {
@@ -4825,6 +4654,8 @@ ptp_get_property_description(PTPParams*
 		 N_("Movie Card Slot")},
 		{PTP_DPC_NIKON_ManualMovieSetting,		/* 0xD0A6 */
 		 N_("Manual Movie Setting")},
+		{PTP_DPC_NIKON_MovQuality,			/* 0xD0A7 */
+		 N_("Movie Quality")},
 		{PTP_DPC_NIKON_MonitorOffDelay,			/* 0xD0B3 */
 		 N_("Monitor Off Delay")},
 		{PTP_DPC_NIKON_Bracketing,			/* 0xD0C0 */
@@ -5066,6 +4897,23 @@ ptp_get_property_description(PTPParams*
 		 N_("Active Pic Ctrl Item")},
 		{PTP_DPC_NIKON_ChangePicCtrlItem,		/* 0xD201 */
 		 N_("Change Pic Ctrl Item")},
+		/* nikon 1 stuff */
+		{PTP_DPC_NIKON_1_ISO,				/* 0xf002 */
+		 N_("ISO")},
+		{PTP_DPC_NIKON_1_ImageSize,			/* 0xf00a */
+		 N_("Image Size")},
+		{PTP_DPC_NIKON_1_LongExposureNoiseReduction,    /* 0xF00D */
+		 N_("Long Exposure Noise Reduction")},
+		{PTP_DPC_NIKON_1_MovQuality,                    /* 0xF01C */
+		 N_("Movie Quality")},
+		{PTP_DPC_NIKON_1_HiISONoiseReduction,           /* 0xF00E */
+		 N_("High ISO Noise Reduction")},
+		{PTP_DPC_NIKON_1_WhiteBalance,           	/* 0xF00C */
+		 N_("White Balance")},
+		{PTP_DPC_NIKON_1_ImageCompression,           	/* 0xF009 */
+		 N_("Image Compression")},
+		{PTP_DPC_NIKON_1_ActiveDLighting,           	/* 0xF00F */
+		 N_("Active D-Lighting")},
 		{0,NULL}
 	};
         struct {
@@ -5105,6 +4953,60 @@ ptp_get_property_description(PTPParams*
 		{0,NULL}
         };
 
+        struct {
+		uint16_t dpc;
+		const char *txt;
+        } ptp_device_properties_SONY[] = {
+		{PTP_DPC_SONY_DPCCompensation, ("DOC Compensation")},	/* 0xD200 */
+		{PTP_DPC_SONY_DRangeOptimize, ("DRangeOptimize")},	/* 0xD201 */
+		{PTP_DPC_SONY_ImageSize, N_("Image size")},		/* 0xD203 */
+		{PTP_DPC_SONY_ShutterSpeed, N_("Shutter speed")},	/* 0xD20D */
+		{PTP_DPC_SONY_ColorTemp, N_("Color temperature")},	/* 0xD20F */
+		{PTP_DPC_SONY_CCFilter, ("CC Filter")},			/* 0xD210 */
+		{PTP_DPC_SONY_AspectRatio, N_("Aspect Ratio")}, 	/* 0xD211 */
+		{PTP_DPC_SONY_FocusFound, N_("Focus status")},		/* 0xD213 */
+		{PTP_DPC_SONY_ObjectInMemory, N_("Objects in memory")},	/* 0xD215 */
+		{PTP_DPC_SONY_ExposeIndex, N_("Expose Index")},		/* 0xD216 */
+		{PTP_DPC_SONY_BatteryLevel, N_("Battery Level")},	/* 0xD218 */
+		{PTP_DPC_SONY_PictureEffect, N_("Picture Effect")},	/* 0xD21B */
+		{PTP_DPC_SONY_ABFilter, N_("AB Filter")},		/* 0xD21C */
+		{PTP_DPC_SONY_ISO, N_("ISO")},				/* 0xD21E */
+		{PTP_DPC_SONY_Movie, N_("Movie")},			/* 0xD2C8 */
+		{PTP_DPC_SONY_StillImage, N_("Still Image")},		/* 0xD2C7 */
+		{0,NULL}
+        };
+
+        struct {
+		uint16_t dpc;
+		const char *txt;
+        } ptp_device_properties_PARROT[] = {
+		{PTP_DPC_PARROT_PhotoSensorEnableMask,		"PhotoSensorEnableMask"}, /* 0xD201 */
+		{PTP_DPC_PARROT_PhotoSensorsKeepOn,		"PhotoSensorsKeepOn"}, /* 0xD202 */
+		{PTP_DPC_PARROT_MultispectralImageSize,		"MultispectralImageSize"}, /* 0xD203 */
+		{PTP_DPC_PARROT_MainBitDepth,			"MainBitDepth"}, /* 0xD204 */
+		{PTP_DPC_PARROT_MultispectralBitDepth,		"MultispectralBitDepth"}, /* 0xD205 */
+		{PTP_DPC_PARROT_HeatingEnable,			"HeatingEnable"}, /* 0xD206 */
+		{PTP_DPC_PARROT_WifiStatus,			"WifiStatus"}, /* 0xD207 */
+		{PTP_DPC_PARROT_WifiSSID,			"WifiSSID"}, /* 0xD208 */
+		{PTP_DPC_PARROT_WifiEncryptionType,		"WifiEncryptionType"}, /* 0xD209 */
+		{PTP_DPC_PARROT_WifiPassphrase,			"WifiPassphrase"}, /* 0xD20A */
+		{PTP_DPC_PARROT_WifiChannel,			"WifiChannel"}, /* 0xD20B */
+		{PTP_DPC_PARROT_Localization,			"Localization"}, /* 0xD20C */
+		{PTP_DPC_PARROT_WifiMode,			"WifiMode"}, /* 0xD20D */
+		{PTP_DPC_PARROT_AntiFlickeringFrequency,	"AntiFlickeringFrequency"}, /* 0xD210 */
+		{PTP_DPC_PARROT_DisplayOverlayMask,		"DisplayOverlayMask"}, /* 0xD211 */
+		{PTP_DPC_PARROT_GPSInterval,			"GPSInterval"}, /* 0xD212 */
+		{PTP_DPC_PARROT_MultisensorsExposureMeteringMode,"MultisensorsExposureMeteringMode"}, /* 0xD213 */
+		{PTP_DPC_PARROT_MultisensorsExposureTime,	"MultisensorsExposureTime"}, /* 0xD214 */
+		{PTP_DPC_PARROT_MultisensorsExposureProgramMode,"MultisensorsExposureProgramMode"}, /* 0xD215 */
+		{PTP_DPC_PARROT_MultisensorsExposureIndex,	"MultisensorsExposureIndex"}, /* 0xD216 */
+		{PTP_DPC_PARROT_MultisensorsIrradianceGain,	"MultisensorsIrradianceGain"}, /* 0xD217 */
+		{PTP_DPC_PARROT_MultisensorsIrradianceIntegrationTime,"MultisensorsIrradianceIntegrationTime"}, /* 0xD218 */
+		{PTP_DPC_PARROT_OverlapRate,			"OverlapRate"}, /* 0xD219 */
+		{0,NULL}
+        };
+
+
 	for (i=0; ptp_device_properties[i].txt!=NULL; i++)
 		if (ptp_device_properties[i].dpc==dpc)
 			return (ptp_device_properties[i].txt);
@@ -5135,6 +5037,16 @@ ptp_get_property_description(PTPParams*
 			if (ptp_device_properties_FUJI[i].dpc==dpc)
 				return (ptp_device_properties_FUJI[i].txt);
 
+	if (params->deviceinfo.VendorExtensionID==PTP_VENDOR_SONY)
+		for (i=0; ptp_device_properties_SONY[i].txt!=NULL; i++)
+			if (ptp_device_properties_SONY[i].dpc==dpc)
+				return (ptp_device_properties_SONY[i].txt);
+	if (params->deviceinfo.VendorExtensionID==PTP_VENDOR_PARROT)
+		for (i=0; ptp_device_properties_PARROT[i].txt!=NULL; i++)
+			if (ptp_device_properties_PARROT[i].dpc==dpc)
+				return (ptp_device_properties_PARROT[i].txt);
+
+
 	return NULL;
 }
 
@@ -5822,9 +5734,14 @@ ptp_render_property_value(PTPParams* par
 		switch (dpc) {
 		case PTP_DPC_MTP_SynchronizationPartner:
 		case PTP_DPC_MTP_DeviceFriendlyName:
-			return snprintf(out, length, "%s", dpd->CurrentValue.str);
+			if (dpd->DataType == PTP_DTC_STR)
+				return snprintf(out, length, "%s", dpd->CurrentValue.str);
+			else
+				return snprintf(out, length, "invalid type, expected STR");
 		case PTP_DPC_MTP_SecureTime:
 		case PTP_DPC_MTP_DeviceCertificate: {
+			if (dpd->DataType != PTP_DTC_AUINT16)
+				return snprintf(out, length, "invalid type, expected AUINT16");
 			/* FIXME: Convert to use unicode demux functions */
 			for (i=0;(i<dpd->CurrentValue.a.count) && (i<length);i++)
 				out[i] = dpd->CurrentValue.a.v[i].u16;
@@ -5971,6 +5888,14 @@ ptp_render_ofc(PTPParams* params, uint16
 				break;
 			}
 			break;
+		case PTP_VENDOR_SONY:
+			switch (ofc) {
+			case PTP_OFC_SONY_RAW:
+				return snprintf (txt, spaceleft,"ARW");
+			default:
+				break;
+			}
+			break;
 		case PTP_VENDOR_MICROSOFT:
 		case PTP_VENDOR_MTP:		  
 			for (i=0;i<sizeof(ptp_ofc_mtp_trans)/sizeof(ptp_ofc_mtp_trans[0]);i++)
@@ -5983,12 +5908,14 @@ ptp_render_ofc(PTPParams* params, uint16
 	return snprintf (txt, spaceleft,_("Unknown(%04x)"), ofc);
 }
 
-struct {
+typedef struct {
 	uint16_t opcode;
 	const char *name;
-} ptp_opcode_trans[] = {
+} ptp_opcode_trans_t;
+
+ptp_opcode_trans_t ptp_opcode_trans[] = {
 	{PTP_OC_Undefined,N_("Undefined")},
-	{PTP_OC_GetDeviceInfo,N_("get device info")},
+	{PTP_OC_GetDeviceInfo,N_("Get device info")},
 	{PTP_OC_OpenSession,N_("Open session")},
 	{PTP_OC_CloseSession,N_("Close session")},
 	{PTP_OC_GetStorageIDs,N_("Get storage IDs")},
@@ -6015,13 +5942,20 @@ struct {
 	{PTP_OC_MoveObject,N_("Move object")},
 	{PTP_OC_CopyObject,N_("Copy object")},
 	{PTP_OC_GetPartialObject,N_("Get partial object")},
-	{PTP_OC_InitiateOpenCapture,N_("Initiate open capture")}
+	{PTP_OC_InitiateOpenCapture,N_("Initiate open capture")},
+	/* PTP v1.1 operation codes */
+	{PTP_OC_StartEnumHandles,N_("Start Enumerate Handles")},
+	{PTP_OC_EnumHandles,N_("Enumerate Handles")},
+	{PTP_OC_StopEnumHandles,N_("Stop Enumerate Handles")},
+	{PTP_OC_GetVendorExtensionMaps,N_("Get Vendor Extension Maps")},
+	{PTP_OC_GetVendorDeviceInfo,N_("Get Vendor Device Info")},
+	{PTP_OC_GetResizedImageObject,N_("Get Resized Image Object")},
+	{PTP_OC_GetFilesystemManifest,N_("Get Filesystem Manifest")},
+	{PTP_OC_GetStreamInfo,N_("Get Stream Info")},
+	{PTP_OC_GetStream,N_("Get Stream")},
 };
 
-struct {
-	uint16_t opcode;
-	const char *name;
-} ptp_opcode_mtp_trans[] = {
+ptp_opcode_trans_t ptp_opcode_mtp_trans[] = {
 	{PTP_OC_MTP_GetObjectPropsSupported,N_("Get object properties supported")},
 	{PTP_OC_MTP_GetObjectPropDesc,N_("Get object property description")},
 	{PTP_OC_MTP_GetObjectPropValue,N_("Get object property value")},
@@ -6085,27 +6019,248 @@ struct {
 	{PTP_OC_ANDROID_EndEditObject,N_("End Edit Object")},
 };
 
-int
-ptp_render_opcode(PTPParams* params, uint16_t opcode, int spaceleft, char *txt)
-{
-	unsigned int i;
+ptp_opcode_trans_t ptp_opcode_nikon_trans[] = {
+	{PTP_OC_NIKON_GetProfileAllData,"PTP_OC_NIKON_GetProfileAllData"},
+	{PTP_OC_NIKON_SendProfileData,"PTP_OC_NIKON_SendProfileData"},
+	{PTP_OC_NIKON_DeleteProfile,"PTP_OC_NIKON_DeleteProfile"},
+	{PTP_OC_NIKON_SetProfileData,"PTP_OC_NIKON_SetProfileData"},
+	{PTP_OC_NIKON_AdvancedTransfer,"PTP_OC_NIKON_AdvancedTransfer"},
+	{PTP_OC_NIKON_GetFileInfoInBlock,"PTP_OC_NIKON_GetFileInfoInBlock"},
+	{PTP_OC_NIKON_Capture,"PTP_OC_NIKON_Capture"},
+	{PTP_OC_NIKON_AfDrive,"PTP_OC_NIKON_AfDrive"},
+	{PTP_OC_NIKON_SetControlMode,"PTP_OC_NIKON_SetControlMode"},
+	{PTP_OC_NIKON_DelImageSDRAM,"PTP_OC_NIKON_DelImageSDRAM"},
+	{PTP_OC_NIKON_GetLargeThumb,"PTP_OC_NIKON_GetLargeThumb"},
+	{PTP_OC_NIKON_CurveDownload,"PTP_OC_NIKON_CurveDownload"},
+	{PTP_OC_NIKON_CurveUpload,"PTP_OC_NIKON_CurveUpload"},
+	{PTP_OC_NIKON_CheckEvent,"PTP_OC_NIKON_CheckEvent"},
+	{PTP_OC_NIKON_DeviceReady,"PTP_OC_NIKON_DeviceReady"},
+	{PTP_OC_NIKON_SetPreWBData,"PTP_OC_NIKON_SetPreWBData"},
+	{PTP_OC_NIKON_GetVendorPropCodes,"PTP_OC_NIKON_GetVendorPropCodes"},
+	{PTP_OC_NIKON_AfCaptureSDRAM,"PTP_OC_NIKON_AfCaptureSDRAM"},
+	{PTP_OC_NIKON_GetPictCtrlData,"PTP_OC_NIKON_GetPictCtrlData"},
+	{PTP_OC_NIKON_SetPictCtrlData,"PTP_OC_NIKON_SetPictCtrlData"},
+	{PTP_OC_NIKON_DelCstPicCtrl,"PTP_OC_NIKON_DelCstPicCtrl"},
+	{PTP_OC_NIKON_GetPicCtrlCapability,"PTP_OC_NIKON_GetPicCtrlCapability"},
+	{PTP_OC_NIKON_GetPreviewImg,"PTP_OC_NIKON_GetPreviewImg"},
+	{PTP_OC_NIKON_StartLiveView,"PTP_OC_NIKON_StartLiveView"},
+	{PTP_OC_NIKON_EndLiveView,"PTP_OC_NIKON_EndLiveView"},
+	{PTP_OC_NIKON_GetLiveViewImg,"PTP_OC_NIKON_GetLiveViewImg"},
+	{PTP_OC_NIKON_MfDrive,"PTP_OC_NIKON_MfDrive"},
+	{PTP_OC_NIKON_ChangeAfArea,"PTP_OC_NIKON_ChangeAfArea"},
+	{PTP_OC_NIKON_AfDriveCancel,"PTP_OC_NIKON_AfDriveCancel"},
+	{PTP_OC_NIKON_InitiateCaptureRecInMedia,"PTP_OC_NIKON_InitiateCaptureRecInMedia"},
+	{PTP_OC_NIKON_GetVendorStorageIDs,"PTP_OC_NIKON_GetVendorStorageIDs"},
+	{PTP_OC_NIKON_StartMovieRecInCard,"PTP_OC_NIKON_StartMovieRecInCard"},
+	{PTP_OC_NIKON_EndMovieRec,"PTP_OC_NIKON_EndMovieRec"},
+	{PTP_OC_NIKON_TerminateCapture,"PTP_OC_NIKON_TerminateCapture"},
+	{PTP_OC_NIKON_GetDevicePTPIPInfo,"PTP_OC_NIKON_GetDevicePTPIPInfo"},
+	{PTP_OC_NIKON_GetPartialObjectHiSpeed,"PTP_OC_NIKON_GetPartialObjectHiSpeed"},
+	{PTP_OC_NIKON_GetDevicePropEx,"PTP_OC_NIKON_GetDevicePropEx"},
+};
 
-	if (!(opcode & 0x8000)) {
-		for (i=0;i<sizeof(ptp_opcode_trans)/sizeof(ptp_opcode_trans[0]);i++)
-			if (opcode == ptp_opcode_trans[i].opcode)
-				return snprintf(txt, spaceleft, "%s", _(ptp_opcode_trans[i].name));
-	} else {
-		switch (params->deviceinfo.VendorExtensionID) {
-		case PTP_VENDOR_MICROSOFT:
-		case PTP_VENDOR_MTP:
-			for (i=0;i<sizeof(ptp_opcode_mtp_trans)/sizeof(ptp_opcode_mtp_trans[0]);i++)
-				if (opcode == ptp_opcode_mtp_trans[i].opcode)
-					return snprintf(txt, spaceleft, "%s", _(ptp_opcode_mtp_trans[i].name));
-			break;
-		default:break;
-		}
+ptp_opcode_trans_t ptp_opcode_canon_trans[] = {
+	{PTP_OC_CANON_GetPartialObjectInfo,"PTP_OC_CANON_GetPartialObjectInfo"},
+	{PTP_OC_CANON_SetObjectArchive,"PTP_OC_CANON_SetObjectArchive"},
+	{PTP_OC_CANON_KeepDeviceOn,"PTP_OC_CANON_KeepDeviceOn"},
+	{PTP_OC_CANON_LockDeviceUI,"PTP_OC_CANON_LockDeviceUI"},
+	{PTP_OC_CANON_UnlockDeviceUI,"PTP_OC_CANON_UnlockDeviceUI"},
+	{PTP_OC_CANON_GetObjectHandleByName,"PTP_OC_CANON_GetObjectHandleByName"},
+	{PTP_OC_CANON_InitiateReleaseControl,"PTP_OC_CANON_InitiateReleaseControl"},
+	{PTP_OC_CANON_TerminateReleaseControl,"PTP_OC_CANON_TerminateReleaseControl"},
+	{PTP_OC_CANON_TerminatePlaybackMode,"PTP_OC_CANON_TerminatePlaybackMode"},
+	{PTP_OC_CANON_ViewfinderOn,"PTP_OC_CANON_ViewfinderOn"},
+	{PTP_OC_CANON_ViewfinderOff,"PTP_OC_CANON_ViewfinderOff"},
+	{PTP_OC_CANON_DoAeAfAwb,"PTP_OC_CANON_DoAeAfAwb"},
+	{PTP_OC_CANON_GetCustomizeSpec,"PTP_OC_CANON_GetCustomizeSpec"},
+	{PTP_OC_CANON_GetCustomizeItemInfo,"PTP_OC_CANON_GetCustomizeItemInfo"},
+	{PTP_OC_CANON_GetCustomizeData,"PTP_OC_CANON_GetCustomizeData"},
+	{PTP_OC_CANON_SetCustomizeData,"PTP_OC_CANON_SetCustomizeData"},
+	{PTP_OC_CANON_GetCaptureStatus,"PTP_OC_CANON_GetCaptureStatus"},
+	{PTP_OC_CANON_CheckEvent,"PTP_OC_CANON_CheckEvent"},
+	{PTP_OC_CANON_FocusLock,"PTP_OC_CANON_FocusLock"},
+	{PTP_OC_CANON_FocusUnlock,"PTP_OC_CANON_FocusUnlock"},
+	{PTP_OC_CANON_GetLocalReleaseParam,"PTP_OC_CANON_GetLocalReleaseParam"},
+	{PTP_OC_CANON_SetLocalReleaseParam,"PTP_OC_CANON_SetLocalReleaseParam"},
+	{PTP_OC_CANON_AskAboutPcEvf,"PTP_OC_CANON_AskAboutPcEvf"},
+	{PTP_OC_CANON_SendPartialObject,"PTP_OC_CANON_SendPartialObject"},
+	{PTP_OC_CANON_InitiateCaptureInMemory,"PTP_OC_CANON_InitiateCaptureInMemory"},
+	{PTP_OC_CANON_GetPartialObjectEx,"PTP_OC_CANON_GetPartialObjectEx"},
+	{PTP_OC_CANON_SetObjectTime,"PTP_OC_CANON_SetObjectTime"},
+	{PTP_OC_CANON_GetViewfinderImage,"PTP_OC_CANON_GetViewfinderImage"},
+	{PTP_OC_CANON_GetObjectAttributes,"PTP_OC_CANON_GetObjectAttributes"},
+	{PTP_OC_CANON_ChangeUSBProtocol,"PTP_OC_CANON_ChangeUSBProtocol"},
+	{PTP_OC_CANON_GetChanges,"PTP_OC_CANON_GetChanges"},
+	{PTP_OC_CANON_GetObjectInfoEx,"PTP_OC_CANON_GetObjectInfoEx"},
+	{PTP_OC_CANON_InitiateDirectTransfer,"PTP_OC_CANON_InitiateDirectTransfer"},
+	{PTP_OC_CANON_TerminateDirectTransfer ,"PTP_OC_CANON_TerminateDirectTransfer "},
+	{PTP_OC_CANON_SendObjectInfoByPath ,"PTP_OC_CANON_SendObjectInfoByPath "},
+	{PTP_OC_CANON_SendObjectByPath ,"PTP_OC_CANON_SendObjectByPath "},
+	{PTP_OC_CANON_InitiateDirectTansferEx,"PTP_OC_CANON_InitiateDirectTansferEx"},
+	{PTP_OC_CANON_GetAncillaryObjectHandles,"PTP_OC_CANON_GetAncillaryObjectHandles"},
+	{PTP_OC_CANON_GetTreeInfo ,"PTP_OC_CANON_GetTreeInfo "},
+	{PTP_OC_CANON_GetTreeSize ,"PTP_OC_CANON_GetTreeSize "},
+	{PTP_OC_CANON_NotifyProgress ,"PTP_OC_CANON_NotifyProgress "},
+	{PTP_OC_CANON_NotifyCancelAccepted,"PTP_OC_CANON_NotifyCancelAccepted"},
+	{PTP_OC_CANON_902C,"PTP_OC_CANON_902C"},
+	{PTP_OC_CANON_GetDirectory,"PTP_OC_CANON_GetDirectory"},
+	{PTP_OC_CANON_SetPairingInfo,"PTP_OC_CANON_SetPairingInfo"},
+	{PTP_OC_CANON_GetPairingInfo,"PTP_OC_CANON_GetPairingInfo"},
+	{PTP_OC_CANON_DeletePairingInfo,"PTP_OC_CANON_DeletePairingInfo"},
+	{PTP_OC_CANON_GetMACAddress,"PTP_OC_CANON_GetMACAddress"},
+	{PTP_OC_CANON_SetDisplayMonitor,"PTP_OC_CANON_SetDisplayMonitor"},
+	{PTP_OC_CANON_PairingComplete,"PTP_OC_CANON_PairingComplete"},
+	{PTP_OC_CANON_GetWirelessMAXChannel,"PTP_OC_CANON_GetWirelessMAXChannel"},
+	{PTP_OC_CANON_GetWebServiceSpec,"PTP_OC_CANON_GetWebServiceSpec"},
+	{PTP_OC_CANON_GetWebServiceData,"PTP_OC_CANON_GetWebServiceData"},
+	{PTP_OC_CANON_SetWebServiceData,"PTP_OC_CANON_SetWebServiceData"},
+	{PTP_OC_CANON_GetRootCertificateSpec,"PTP_OC_CANON_GetRootCertificateSpec"},
+	{PTP_OC_CANON_GetRootCertificateData,"PTP_OC_CANON_GetRootCertificateData"},
+	{PTP_OC_CANON_SetRootCertificateData,"PTP_OC_CANON_SetRootCertificateData"},
+	{PTP_OC_CANON_EOS_GetStorageIDs,"PTP_OC_CANON_EOS_GetStorageIDs"},
+	{PTP_OC_CANON_EOS_GetStorageInfo,"PTP_OC_CANON_EOS_GetStorageInfo"},
+	{PTP_OC_CANON_EOS_GetObjectInfo,"PTP_OC_CANON_EOS_GetObjectInfo"},
+	{PTP_OC_CANON_EOS_GetObject,"PTP_OC_CANON_EOS_GetObject"},
+	{PTP_OC_CANON_EOS_DeleteObject,"PTP_OC_CANON_EOS_DeleteObject"},
+	{PTP_OC_CANON_EOS_FormatStore,"PTP_OC_CANON_EOS_FormatStore"},
+	{PTP_OC_CANON_EOS_GetPartialObject,"PTP_OC_CANON_EOS_GetPartialObject"},
+	{PTP_OC_CANON_EOS_GetDeviceInfoEx,"PTP_OC_CANON_EOS_GetDeviceInfoEx"},
+	{PTP_OC_CANON_EOS_GetObjectInfoEx,"PTP_OC_CANON_EOS_GetObjectInfoEx"},
+	{PTP_OC_CANON_EOS_GetThumbEx,"PTP_OC_CANON_EOS_GetThumbEx"},
+	{PTP_OC_CANON_EOS_SendPartialObject,"PTP_OC_CANON_EOS_SendPartialObject"},
+	{PTP_OC_CANON_EOS_SetObjectAttributes,"PTP_OC_CANON_EOS_SetObjectAttributes"},
+	{PTP_OC_CANON_EOS_GetObjectTime,"PTP_OC_CANON_EOS_GetObjectTime"},
+	{PTP_OC_CANON_EOS_SetObjectTime,"PTP_OC_CANON_EOS_SetObjectTime"},
+	{PTP_OC_CANON_EOS_RemoteRelease,"PTP_OC_CANON_EOS_RemoteRelease"},
+	{PTP_OC_CANON_EOS_SetDevicePropValueEx,"PTP_OC_CANON_EOS_SetDevicePropValueEx"},
+	{PTP_OC_CANON_EOS_GetRemoteMode,"PTP_OC_CANON_EOS_GetRemoteMode"},
+	{PTP_OC_CANON_EOS_SetRemoteMode,"PTP_OC_CANON_EOS_SetRemoteMode"},
+	{PTP_OC_CANON_EOS_SetEventMode,"PTP_OC_CANON_EOS_SetEventMode"},
+	{PTP_OC_CANON_EOS_GetEvent,"PTP_OC_CANON_EOS_GetEvent"},
+	{PTP_OC_CANON_EOS_TransferComplete,"PTP_OC_CANON_EOS_TransferComplete"},
+	{PTP_OC_CANON_EOS_CancelTransfer,"PTP_OC_CANON_EOS_CancelTransfer"},
+	{PTP_OC_CANON_EOS_ResetTransfer,"PTP_OC_CANON_EOS_ResetTransfer"},
+	{PTP_OC_CANON_EOS_PCHDDCapacity,"PTP_OC_CANON_EOS_PCHDDCapacity"},
+	{PTP_OC_CANON_EOS_SetUILock,"PTP_OC_CANON_EOS_SetUILock"},
+	{PTP_OC_CANON_EOS_ResetUILock,"PTP_OC_CANON_EOS_ResetUILock"},
+	{PTP_OC_CANON_EOS_KeepDeviceOn,"PTP_OC_CANON_EOS_KeepDeviceOn"},
+	{PTP_OC_CANON_EOS_SetNullPacketMode,"PTP_OC_CANON_EOS_SetNullPacketMode"},
+	{PTP_OC_CANON_EOS_UpdateFirmware,"PTP_OC_CANON_EOS_UpdateFirmware"},
+	{PTP_OC_CANON_EOS_TransferCompleteDT,"PTP_OC_CANON_EOS_TransferCompleteDT"},
+	{PTP_OC_CANON_EOS_CancelTransferDT,"PTP_OC_CANON_EOS_CancelTransferDT"},
+	{PTP_OC_CANON_EOS_SetWftProfile,"PTP_OC_CANON_EOS_SetWftProfile"},
+	{PTP_OC_CANON_EOS_GetWftProfile,"PTP_OC_CANON_EOS_GetWftProfile"},
+	{PTP_OC_CANON_EOS_SetProfileToWft,"PTP_OC_CANON_EOS_SetProfileToWft"},
+	{PTP_OC_CANON_EOS_BulbStart,"PTP_OC_CANON_EOS_BulbStart"},
+	{PTP_OC_CANON_EOS_BulbEnd,"PTP_OC_CANON_EOS_BulbEnd"},
+	{PTP_OC_CANON_EOS_RequestDevicePropValue,"PTP_OC_CANON_EOS_RequestDevicePropValue"},
+	{PTP_OC_CANON_EOS_RemoteReleaseOn,"PTP_OC_CANON_EOS_RemoteReleaseOn"},
+	{PTP_OC_CANON_EOS_RemoteReleaseOff,"PTP_OC_CANON_EOS_RemoteReleaseOff"},
+	{PTP_OC_CANON_EOS_RegistBackgroundImage,"PTP_OC_CANON_EOS_RegistBackgroundImage"},
+	{PTP_OC_CANON_EOS_ChangePhotoStudioMode,"PTP_OC_CANON_EOS_ChangePhotoStudioMode"},
+	{PTP_OC_CANON_EOS_GetPartialObjectEx,"PTP_OC_CANON_EOS_GetPartialObjectEx"},
+	{PTP_OC_CANON_EOS_ResetMirrorLockupState,"PTP_OC_CANON_EOS_ResetMirrorLockupState"},
+	{PTP_OC_CANON_EOS_PopupBuiltinFlash,"PTP_OC_CANON_EOS_PopupBuiltinFlash"},
+	{PTP_OC_CANON_EOS_EndGetPartialObjectEx,"PTP_OC_CANON_EOS_EndGetPartialObjectEx"},
+	{PTP_OC_CANON_EOS_MovieSelectSWOn,"PTP_OC_CANON_EOS_MovieSelectSWOn"},
+	{PTP_OC_CANON_EOS_MovieSelectSWOff,"PTP_OC_CANON_EOS_MovieSelectSWOff"},
+	{PTP_OC_CANON_EOS_GetCTGInfo,"PTP_OC_CANON_EOS_GetCTGInfo"},
+	{PTP_OC_CANON_EOS_GetLensAdjust,"PTP_OC_CANON_EOS_GetLensAdjust"},
+	{PTP_OC_CANON_EOS_SetLensAdjust,"PTP_OC_CANON_EOS_SetLensAdjust"},
+	{PTP_OC_CANON_EOS_GetMusicInfo,"PTP_OC_CANON_EOS_GetMusicInfo"},
+	{PTP_OC_CANON_EOS_CreateHandle,"PTP_OC_CANON_EOS_CreateHandle"},
+	{PTP_OC_CANON_EOS_SendPartialObjectEx,"PTP_OC_CANON_EOS_SendPartialObjectEx"},
+	{PTP_OC_CANON_EOS_EndSendPartialObjectEx,"PTP_OC_CANON_EOS_EndSendPartialObjectEx"},
+	{PTP_OC_CANON_EOS_SetCTGInfo,"PTP_OC_CANON_EOS_SetCTGInfo"},
+	{PTP_OC_CANON_EOS_SetRequestOLCInfoGroup,"PTP_OC_CANON_EOS_SetRequestOLCInfoGroup"},
+	{PTP_OC_CANON_EOS_SetRequestRollingPitchingLevel,"PTP_OC_CANON_EOS_SetRequestRollingPitchingLevel"},
+	{PTP_OC_CANON_EOS_GetCameraSupport,"PTP_OC_CANON_EOS_GetCameraSupport"},
+	{PTP_OC_CANON_EOS_SetRating,"PTP_OC_CANON_EOS_SetRating"},
+	{PTP_OC_CANON_EOS_RequestInnerDevelopStart,"PTP_OC_CANON_EOS_RequestInnerDevelopStart"},
+	{PTP_OC_CANON_EOS_RequestInnerDevelopParamChange,"PTP_OC_CANON_EOS_RequestInnerDevelopParamChange"},
+	{PTP_OC_CANON_EOS_RequestInnerDevelopEnd,"PTP_OC_CANON_EOS_RequestInnerDevelopEnd"},
+	{PTP_OC_CANON_EOS_GpsLoggingDataMode,"PTP_OC_CANON_EOS_GpsLoggingDataMode"},
+	{PTP_OC_CANON_EOS_GetGpsLogCurrentHandle,"PTP_OC_CANON_EOS_GetGpsLogCurrentHandle"},
+	{PTP_OC_CANON_EOS_InitiateViewfinder,"PTP_OC_CANON_EOS_InitiateViewfinder"},
+	{PTP_OC_CANON_EOS_TerminateViewfinder,"PTP_OC_CANON_EOS_TerminateViewfinder"},
+	{PTP_OC_CANON_EOS_GetViewFinderData,"PTP_OC_CANON_EOS_GetViewFinderData"},
+	{PTP_OC_CANON_EOS_DoAf,"PTP_OC_CANON_EOS_DoAf"},
+	{PTP_OC_CANON_EOS_DriveLens,"PTP_OC_CANON_EOS_DriveLens"},
+	{PTP_OC_CANON_EOS_DepthOfFieldPreview,"PTP_OC_CANON_EOS_DepthOfFieldPreview"},
+	{PTP_OC_CANON_EOS_ClickWB,"PTP_OC_CANON_EOS_ClickWB"},
+	{PTP_OC_CANON_EOS_Zoom,"PTP_OC_CANON_EOS_Zoom"},
+	{PTP_OC_CANON_EOS_ZoomPosition,"PTP_OC_CANON_EOS_ZoomPosition"},
+	{PTP_OC_CANON_EOS_SetLiveAfFrame,"PTP_OC_CANON_EOS_SetLiveAfFrame"},
+	{PTP_OC_CANON_EOS_TouchAfPosition,"PTP_OC_CANON_EOS_TouchAfPosition"},
+	{PTP_OC_CANON_EOS_SetLvPcFlavoreditMode,"PTP_OC_CANON_EOS_SetLvPcFlavoreditMode"},
+	{PTP_OC_CANON_EOS_SetLvPcFlavoreditParam,"PTP_OC_CANON_EOS_SetLvPcFlavoreditParam"},
+	{PTP_OC_CANON_EOS_AfCancel,"PTP_OC_CANON_EOS_AfCancel"},
+	{PTP_OC_CANON_EOS_SetDefaultCameraSetting,"PTP_OC_CANON_EOS_SetDefaultCameraSetting"},
+	{PTP_OC_CANON_EOS_GetAEData,"PTP_OC_CANON_EOS_GetAEData"},
+	{PTP_OC_CANON_EOS_NotifyNetworkError,"PTP_OC_CANON_EOS_NotifyNetworkError"},
+	{PTP_OC_CANON_EOS_AdapterTransferProgress,"PTP_OC_CANON_EOS_AdapterTransferProgress"},
+	{PTP_OC_CANON_EOS_TransferComplete2,"PTP_OC_CANON_EOS_TransferComplete2"},
+	{PTP_OC_CANON_EOS_CancelTransfer2,"PTP_OC_CANON_EOS_CancelTransfer2"},
+	{PTP_OC_CANON_EOS_FAPIMessageTX,"PTP_OC_CANON_EOS_FAPIMessageTX"},
+	{PTP_OC_CANON_EOS_FAPIMessageRX,"PTP_OC_CANON_EOS_FAPIMessageRX"},
+};
+
+ptp_opcode_trans_t ptp_opcode_sony_trans[] = {
+	{PTP_OC_SONY_SDIOConnect,"PTP_OC_SONY_SDIOConnect"},
+	{PTP_OC_SONY_GetSDIOGetExtDeviceInfo,"PTP_OC_SONY_GetSDIOGetExtDeviceInfo"},
+	{PTP_OC_SONY_GetDevicePropdesc,"PTP_OC_SONY_GetDevicePropdesc"},
+	{PTP_OC_SONY_GetDevicePropertyValue,"PTP_OC_SONY_GetDevicePropertyValue"},
+	{PTP_OC_SONY_SetControlDeviceA,"PTP_OC_SONY_SetControlDeviceA"},
+	{PTP_OC_SONY_GetControlDeviceDesc,"PTP_OC_SONY_GetControlDeviceDesc"},
+	{PTP_OC_SONY_SetControlDeviceB,"PTP_OC_SONY_SetControlDeviceB"},
+	{PTP_OC_SONY_GetAllDevicePropData,"PTP_OC_SONY_GetAllDevicePropData"},
+};
+
+ptp_opcode_trans_t ptp_opcode_parrot_trans[] = {
+	{PTP_OC_PARROT_GetSunshineValues,"PTP_OC_PARROT_GetSunshineValues"},
+	{PTP_OC_PARROT_GetTemperatureValues,"PTP_OC_PARROT_GetTemperatureValues"},
+	{PTP_OC_PARROT_GetAngleValues,"PTP_OC_PARROT_GetAngleValues"},
+	{PTP_OC_PARROT_GetGpsValues,"PTP_OC_PARROT_GetGpsValues"},
+	{PTP_OC_PARROT_GetGyroscopeValues,"PTP_OC_PARROT_GetGyroscopeValues"},
+	{PTP_OC_PARROT_GetAccelerometerValues,"PTP_OC_PARROT_GetAccelerometerValues"},
+	{PTP_OC_PARROT_GetMagnetometerValues,"PTP_OC_PARROT_GetMagnetometerValues"},
+	{PTP_OC_PARROT_GetImuValues,"PTP_OC_PARROT_GetImuValues"},
+	{PTP_OC_PARROT_GetStatusMask,"PTP_OC_PARROT_GetStatusMask"},
+	{PTP_OC_PARROT_EjectStorage,"PTP_OC_PARROT_EjectStorage"},
+	{PTP_OC_PARROT_StartMagnetoCalib,"PTP_OC_PARROT_StartMagnetoCalib"},
+	{PTP_OC_PARROT_StopMagnetoCalib,"PTP_OC_PARROT_StopMagnetoCalib"},
+	{PTP_OC_PARROT_MagnetoCalibStatus,"PTP_OC_PARROT_MagnetoCalibStatus"},
+	{PTP_OC_PARROT_SendFirmwareUpdate,"PTP_OC_PARROT_SendFirmwareUpdate"},
+};
+
+const char*
+ptp_get_opcode_name(PTPParams* params, uint16_t opcode)
+{
+#define RETURN_NAME_FROM_TABLE(TABLE, OPCODE) \
+{ \
+	unsigned int i; \
+	for (i=0; i<sizeof(TABLE)/sizeof(TABLE[0]); i++) \
+		if (OPCODE == TABLE[i].opcode) \
+			return _(TABLE[i].name); \
+	return _("Unknown PTP_OC"); \
+}
+
+	if (!(opcode & 0x8000))
+		RETURN_NAME_FROM_TABLE(ptp_opcode_trans, opcode);
+
+	switch (params->deviceinfo.VendorExtensionID) {
+	case PTP_VENDOR_MICROSOFT:
+	case PTP_VENDOR_MTP:	RETURN_NAME_FROM_TABLE(ptp_opcode_mtp_trans, opcode);
+	case PTP_VENDOR_NIKON:	RETURN_NAME_FROM_TABLE(ptp_opcode_nikon_trans, opcode);
+	case PTP_VENDOR_CANON:	RETURN_NAME_FROM_TABLE(ptp_opcode_canon_trans, opcode);
+	case PTP_VENDOR_SONY:	RETURN_NAME_FROM_TABLE(ptp_opcode_sony_trans, opcode);
+	case PTP_VENDOR_PARROT:	RETURN_NAME_FROM_TABLE(ptp_opcode_parrot_trans, opcode);
+	default:
+		break;
 	}
-	return snprintf (txt, spaceleft,_("Unknown (%04x)"), opcode);
+#undef RETURN_NAME_FROM_TABLE
+
+	return _("Unknown VendorExtensionID");
 }
 
 
@@ -6284,7 +6439,8 @@ struct {
 };
 
 int
-ptp_render_mtp_propname(uint16_t propid, int spaceleft, char *txt) {
+ptp_render_mtp_propname(uint16_t propid, int spaceleft, char *txt)
+{
 	unsigned int i;
 	for (i=0;i<sizeof(ptp_opc_trans)/sizeof(ptp_opc_trans[0]);i++)
 		if (propid == ptp_opc_trans[i].id)
@@ -6296,15 +6452,12 @@ ptp_render_mtp_propname(uint16_t propid,
  * Allocate and default-initialize a few object properties.
  */
 MTPProperties *
-ptp_get_new_object_prop_entry(MTPProperties **props, int *nrofprops) {
+ptp_get_new_object_prop_entry(MTPProperties **props, int *nrofprops)
+{
 	MTPProperties *newprops;
 	MTPProperties *prop;
 
-	if (*props == NULL) {
-		newprops = malloc(sizeof(MTPProperties)*(*nrofprops+1));
-	} else {
-		newprops = realloc(*props,sizeof(MTPProperties)*(*nrofprops+1));
-	}
+	newprops = realloc(*props,sizeof(MTPProperties)*(*nrofprops+1));
 	if (newprops == NULL)
 		return NULL;
 	prop = &newprops[*nrofprops];
@@ -6369,16 +6522,13 @@ ptp_find_object_prop_in_cache(PTPParams
 	return NULL;
 }
 
-void
+uint16_t
 ptp_remove_object_from_cache(PTPParams *params, uint32_t handle)
 {
 	unsigned int i;
 	PTPObject	*ob;
-	uint16_t	ret;
 
-	ret = ptp_object_find (params, handle, &ob);
-	if (ret != PTP_RC_OK)
-		return;
+	CHECK_PTP_RC(ptp_object_find (params, handle, &ob));
 	i = ob-params->objects;
 	/* remove object from object info cache */
 	ptp_free_object (ob);
@@ -6388,23 +6538,32 @@ ptp_remove_object_from_cache(PTPParams *
 	params->nrofobjects--;
 	/* We use less memory than before so this shouldn't fail */
 	params->objects = realloc(params->objects, sizeof(PTPObject)*params->nrofobjects);
+	return PTP_RC_OK;
 }
 
-static int _cmp_ob (const void *a, const void *b) {
+static int _cmp_ob (const void *a, const void *b)
+{
 	PTPObject *oa = (PTPObject*)a;
 	PTPObject *ob = (PTPObject*)b;
 
-	return oa->oid - ob->oid;
+	/* Do not subtract the oids and return ...
+	 * the unsigned int -> int conversion will overflow in cases
+	 * like 0xfffc0000 vs 0x0004000. */
+	if (oa->oid > ob->oid) return 1;
+	if (oa->oid < ob->oid) return -1;
+	return 0;
 }
 	
 void
-ptp_objects_sort (PTPParams *params) {
+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) {
+ptp_object_find (PTPParams *params, uint32_t handle, PTPObject **retob)
+{
 	PTPObject	tmpob;
 
 	tmpob.oid = handle;
@@ -6416,7 +6575,8 @@ ptp_object_find (PTPParams *params, uint
 
 /* 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) {
+ptp_object_find_or_insert (PTPParams *params, uint32_t handle, PTPObject **retob)
+{
 	unsigned int 	begin, end, cursor;
 	unsigned int	insertat;
 	PTPObject	*newobs;
@@ -6477,7 +6637,8 @@ ptp_object_find_or_insert (PTPParams *pa
 }
 
 uint16_t
-ptp_object_want (PTPParams *params, uint32_t handle, unsigned int want, PTPObject **retob) {
+ptp_object_want (PTPParams *params, uint32_t handle, unsigned int want, PTPObject **retob)
+{
 	uint16_t	ret;
 	PTPObject	*ob;
 	/*Camera 		*camera = ((PTPData *)params->data)->camera;*/
@@ -6491,9 +6652,7 @@ ptp_object_want (PTPParams *params, uint
 		ptp_debug (params, "ptp_object_want: querying handle 0?\n");
 		return PTP_RC_GeneralError;
 	}
-	ret = ptp_object_find_or_insert (params, handle, &ob);
-	if (ret != PTP_RC_OK)
-		return PTP_RC_GeneralError;
+	CHECK_PTP_RC(ptp_object_find_or_insert (params, handle, &ob));
 	*retob = ob;
 	/* Do we have all of it already? */
 	if ((ob->flags & want) == want)
--- libmtp-1.1.8/src/ptp.h.orig	2014-06-02 15:44:03.000000000 -0400
+++ libmtp-1.1.8/src/ptp.h	2017-07-08 14:39:24.512852305 -0400
@@ -1,7 +1,7 @@
 /* ptp.h
  *
  * Copyright (C) 2001 Mariusz Woloszyn <emsi@ipartners.pl>
- * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
+ * Copyright (C) 2003-2014 Marcus Meissner <marcus@jet.franken.de>
  * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
  *
  * This library is free software; you can redistribute it and/or
@@ -25,7 +25,7 @@
 
 #include <stdarg.h>
 #include <time.h>
-#ifdef HAVE_ICONV
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
 #include <iconv.h>
 #endif
 #include "gphoto2-endian.h"
@@ -172,9 +172,13 @@ typedef struct _PTPIPHeader PTPIPHeader;
 /* not from standards papers, but from traces: */
 #define PTP_VENDOR_SONY			0x00000011 /* observed in the A900 */
 #define PTP_VENDOR_SAMSUNG		0x0000001a /* observed in the Samsung NX1000 */
+#define PTP_VENDOR_PARROT		0x0000001b /* observed in the Parrot Sequoia */
 /* Vendor extension ID used for MTP (occasionaly, usualy 6 is used) */
 #define PTP_VENDOR_MTP			0xffffffff  
 
+/* gphoto overrides */
+#define PTP_VENDOR_GP_OLYMPUS		0xfffffffe
+
 /* Operation Codes */
 
 /* PTP v1.0 operation codes */
@@ -275,6 +279,8 @@ typedef struct _PTPIPHeader PTPIPHeader;
 /* 902c: no parms, read 3 uint32 in data, no response parms */
 #define PTP_OC_CANON_902C			0x902C
 #define PTP_OC_CANON_GetDirectory		0x902D
+#define PTP_OC_CANON_902E			0x902E
+#define PTP_OC_CANON_902F			0x902F	/* used during camera init */
 
 #define PTP_OC_CANON_SetPairingInfo		0x9030
 #define PTP_OC_CANON_GetPairingInfo		0x9031
@@ -396,12 +402,14 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_OC_CANON_EOS_GetLensAdjust		0x9136
 #define PTP_OC_CANON_EOS_SetLensAdjust		0x9137
 #define PTP_OC_CANON_EOS_GetMusicInfo		0x9138
+/* 3 paramaeters, no data, OFC, size, unknown */
 #define PTP_OC_CANON_EOS_CreateHandle		0x9139
 #define PTP_OC_CANON_EOS_SendPartialObjectEx	0x913A
 #define PTP_OC_CANON_EOS_EndSendPartialObjectEx	0x913B
 #define PTP_OC_CANON_EOS_SetCTGInfo		0x913C
 #define PTP_OC_CANON_EOS_SetRequestOLCInfoGroup	0x913D
 #define PTP_OC_CANON_EOS_SetRequestRollingPitchingLevel	0x913E
+/* 3 args, 0x21201020, 0x110, 0x1000000 (potentially reverse order) */
 #define PTP_OC_CANON_EOS_GetCameraSupport	0x913F
 #define PTP_OC_CANON_EOS_SetRating		0x9140 /* 2 args */
 #define PTP_OC_CANON_EOS_RequestInnerDevelopStart	0x9141 /* 2 args: 1 type, 1 object? */
@@ -412,6 +420,7 @@ typedef struct _PTPIPHeader PTPIPHeader;
 
 #define PTP_OC_CANON_EOS_InitiateViewfinder	0x9151
 #define PTP_OC_CANON_EOS_TerminateViewfinder	0x9152
+/* EOS M2 wlan: 2 params, 0x00200000 0x01000000 */
 #define PTP_OC_CANON_EOS_GetViewFinderData	0x9153
 #define PTP_OC_CANON_EOS_DoAf			0x9154
 #define PTP_OC_CANON_EOS_DriveLens		0x9155
@@ -433,6 +442,8 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_OC_CANON_EOS_FAPIMessageTX		0x91FE
 #define PTP_OC_CANON_EOS_FAPIMessageRX		0x91FF
 
+/* A1E8 ... also seen? is an error code? */
+
 /* Nikon extension Operation Codes */
 #define PTP_OC_NIKON_GetProfileAllData	0x9006
 #define PTP_OC_NIKON_SendProfileData	0x9007
@@ -645,6 +656,40 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_OC_ANDROID_BeginEditObject			0x95C4
 #define PTP_OC_ANDROID_EndEditObject			0x95C5
 
+/* Leica opcodes, from Lightroom tether plugin */
+#define PTP_OC_LEICA_SetCameraSettings			0x9001
+#define PTP_OC_LEICA_GetCameraSettings			0x9002
+#define PTP_OC_LEICA_GetLensParameter			0x9003
+/* probably 2 arguments.
+ * generic: releaseStage, stepSize
+ * Release(releasestage) = (releasestage,0)
+ * Release() = (0,0)
+ * AEStart() = (1,0)
+ * Autofocusrelease() = (2,0)
+ * AutofocusPush() = (1,0) ... same as AEStart?
+ * KeepCameraActive() = (0xe,0)
+ */
+#define PTP_OC_LEICA_Release				0x9004
+#define PTP_OC_LEICA_OpenLESession			0x9005
+#define PTP_OC_LEICA_CloseLESession			0x9006
+#define PTP_OC_LEICA_RequestObjectTransferReady		0x9007
+
+#define PTP_OC_PARROT_GetSunshineValues		0x9201
+#define PTP_OC_PARROT_GetTemperatureValues	0x9202
+#define PTP_OC_PARROT_GetAngleValues		0x9203
+#define PTP_OC_PARROT_GetGpsValues		0x9204
+#define PTP_OC_PARROT_GetGyroscopeValues	0x9205
+#define PTP_OC_PARROT_GetAccelerometerValues	0x9206
+#define PTP_OC_PARROT_GetMagnetometerValues	0x9207
+#define PTP_OC_PARROT_GetImuValues		0x9208
+#define PTP_OC_PARROT_GetStatusMask		0x9209
+#define PTP_OC_PARROT_EjectStorage		0x920A
+#define PTP_OC_PARROT_StartMagnetoCalib		0x9210
+#define PTP_OC_PARROT_StopMagnetoCalib		0x9211
+#define PTP_OC_PARROT_MagnetoCalibStatus	0x9212
+#define PTP_OC_PARROT_SendFirmwareUpdate	0x9213
+
+
 /* Proprietary vendor extension operations mask */
 #define PTP_OC_EXTENSION_MASK           0xF000
 #define PTP_OC_EXTENSION                0x9000
@@ -720,6 +765,15 @@ typedef struct _PTPIPHeader PTPIPHeader;
 
 #define PTP_RC_CANON_A009			0xA009
 
+#define PTP_RC_CANON_EOS_UnknownCommand		0xA001
+#define PTP_RC_CANON_EOS_OperationRefused	0xA005
+#define PTP_RC_CANON_EOS_LensCoverClosed	0xA006
+#define PTP_RC_CANON_EOS_LowBattery		0xA101
+#define PTP_RC_CANON_EOS_ObjectNotReady		0xA102
+#define PTP_RC_CANON_EOS_CannotMakeObject	0xA104
+#define PTP_RC_CANON_EOS_MemoryStatusNotReady	0xA106
+
+
 /* Microsoft/MTP specific codes */
 #define PTP_RC_MTP_Undefined			0xA800
 #define PTP_RC_MTP_Invalid_ObjectPropCode	0xA801
@@ -743,12 +797,12 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_RC_MTP_WFC_Version_Not_Supported	0xA122
 
 /* libptp2 extended ERROR codes */
-#define PTP_ERROR_IO			0x02FF
-#define PTP_ERROR_DATA_EXPECTED		0x02FE
-#define PTP_ERROR_RESP_EXPECTED		0x02FD
-#define PTP_ERROR_BADPARAM		0x02FC
-#define PTP_ERROR_CANCEL		0x02FB
 #define PTP_ERROR_TIMEOUT		0x02FA
+#define PTP_ERROR_CANCEL		0x02FB
+#define PTP_ERROR_BADPARAM		0x02FC
+#define PTP_ERROR_RESP_EXPECTED		0x02FD
+#define PTP_ERROR_DATA_EXPECTED		0x02FE
+#define PTP_ERROR_IO			0x02FF
 
 /* PTP Event Codes */
 
@@ -801,10 +855,12 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_EC_CANON_EOS_StoreRemoved			0xc193
 #define PTP_EC_CANON_EOS_BulbExposureTime		0xc194
 #define PTP_EC_CANON_EOS_RecordingTime			0xc195
-#define PTP_EC_CANON_EOS_RequestObjectTransferTS	0xC1a2
+#define PTP_EC_CANON_EOS_RequestObjectTransferTS	0xc1a2
 #define PTP_EC_CANON_EOS_AfResult			0xc1a3
 #define PTP_EC_CANON_EOS_CTGInfoCheckComplete		0xc1a4
 #define PTP_EC_CANON_EOS_OLCInfoChanged			0xc1a5
+#define PTP_EC_CANON_EOS_ObjectAddedUnknown		0xc1a7
+#define PTP_EC_CANON_EOS_RequestObjectTransferNew	0xc1a9
 #define PTP_EC_CANON_EOS_RequestObjectTransferFTP	0xc1f1
 
 /* Nikon extension Event Codes */
@@ -822,7 +878,7 @@ typedef struct _PTPIPHeader PTPIPHeader;
 
 /* Sony */
 #define PTP_EC_Sony_ObjectAdded			0xC201
-/* c202 ... unclear. also called with object id? */
+#define PTP_EC_Sony_ObjectRemoved		0xC202
 #define PTP_EC_Sony_PropertyChanged		0xC203
 
 /* MTP Event codes */
@@ -830,6 +886,10 @@ typedef struct _PTPIPHeader PTPIPHeader;
 #define PTP_EC_MTP_ObjectPropDescChanged	0xC802
 #define PTP_EC_MTP_ObjectReferencesChanged	0xC803
 
+#define PTP_EC_PARROT_Status			0xC201
+#define PTP_EC_PARROT_MagnetoCalibrationStatus	0xC202
+
+
 /* constants for GetObjectHandles */
 #define PTP_GOH_ALL_STORAGE 0xffffffff
 #define PTP_GOH_ALL_FORMATS 0x00000000
@@ -1237,11 +1297,16 @@ 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_OBJECTTRANSFER	2
-#define PTP_CANON_EOS_CHANGES_TYPE_PROPERTY		3
-#define PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS		4
+enum _PTPCanon_changes_types {
+	PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN,
+	PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO,
+	PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER,
+	PTP_CANON_EOS_CHANGES_TYPE_PROPERTY,
+	PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS,
+	PTP_CANON_EOS_CHANGES_TYPE_FOCUSINFO,
+	PTP_CANON_EOS_CHANGES_TYPE_FOCUSMASK,
+	PTP_CANON_EOS_CHANGES_TYPE_OBJECTREMOVED
+};
 
 struct _PTPCanon_New_Object {
 	uint32_t	oid;
@@ -1249,7 +1314,7 @@ struct _PTPCanon_New_Object {
 };
 
 struct _PTPCanon_changes_entry {
-	int	type;
+	enum _PTPCanon_changes_types	type;
 	union {
 		struct _PTPCanon_New_Object	object;	/* TYPE_OBJECTINFO */
 		char				*info;
@@ -1261,7 +1326,6 @@ typedef struct _PTPCanon_changes_entry P
 
 typedef struct _PTPCanon_Property {
 	uint32_t		size;
-	uint32_t		type;
 	uint32_t		proptype;
 	unsigned char		*data;
 
@@ -1666,6 +1730,7 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_NIKON_RemoteMode			0xD035
 #define PTP_DPC_NIKON_VideoMode				0xD036
 #define PTP_DPC_NIKON_EffectMode			0xD037
+#define PTP_DPC_NIKON_1_Mode				0xD038
 #define PTP_DPC_NIKON_CSMMenuBankSelect			0xD040
 #define PTP_DPC_NIKON_MenuBankNameA			0xD041
 #define PTP_DPC_NIKON_MenuBankNameB			0xD042
@@ -1750,6 +1815,7 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_NIKON_MovFileSlot			0xD0A3
 #define PTP_DPC_NIKON_MovRecProhibitCondition		0xD0A4
 #define PTP_DPC_NIKON_ManualMovieSetting		0xD0A6
+#define PTP_DPC_NIKON_MovQuality			0xD0A7
 #define PTP_DPC_NIKON_LiveViewScreenDisplaySetting	0xD0B2
 #define PTP_DPC_NIKON_MonitorOffDelay			0xD0B3
 #define PTP_DPC_NIKON_Bracketing			0xD0C0
@@ -1861,6 +1927,10 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_NIKON_LiveViewStatus			0xD1A2
 #define PTP_DPC_NIKON_LiveViewImageZoomRatio		0xD1A3
 #define PTP_DPC_NIKON_LiveViewProhibitCondition		0xD1A4
+#define PTP_DPC_NIKON_MovieShutterSpeed			0xD1A8
+#define PTP_DPC_NIKON_MovieFNumber			0xD1A9
+#define PTP_DPC_NIKON_MovieISO				0xD1AA
+#define PTP_DPC_NIKON_LiveViewMovieMode			0xD1AC /* ? */
 #define PTP_DPC_NIKON_ExposureDisplayStatus		0xD1B0
 #define PTP_DPC_NIKON_ExposureIndicateStatus		0xD1B1
 #define PTP_DPC_NIKON_InfoDispErrStatus			0xD1B2
@@ -1884,6 +1954,8 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_NIKON_ActiveSlot			0xD1F2
 #define PTP_DPC_NIKON_ActivePicCtrlItem			0xD200
 #define PTP_DPC_NIKON_ChangePicCtrlItem			0xD201
+#define PTP_DPC_NIKON_MovieNrHighISO			0xD236
+
 
 /* Nikon V1 (or WU adapter?) Trace */
 /* d241 - gets string "Nikon_WU2_0090B5123C61" */
@@ -1892,11 +1964,22 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_NIKON_D244				0xD244
 /* d247 - gets 3 bytes 0x01 0x00 0x00 */
 #define PTP_DPC_NIKON_D247				0xD247
+/* S9700 */
+#define PTP_DPC_NIKON_GUID				0xD24F
 /* d250 - gets a string "0000123C61" */
 #define PTP_DPC_NIKON_D250				0xD250
 /* d251 - gets a 0x0100000d */
 #define PTP_DPC_NIKON_D251				0xD251
 
+/* this is irregular, as it should be -0x5000 or 0xD000 based */
+#define PTP_DPC_NIKON_1_ISO				0xF002
+#define PTP_DPC_NIKON_1_ImageCompression		0xF009
+#define PTP_DPC_NIKON_1_ImageSize			0xF00A
+#define PTP_DPC_NIKON_1_WhiteBalance			0xF00C
+#define PTP_DPC_NIKON_1_LongExposureNoiseReduction	0xF00D
+#define PTP_DPC_NIKON_1_HiISONoiseReduction		0xF00E
+#define PTP_DPC_NIKON_1_ActiveDLighting			0xF00F
+#define PTP_DPC_NIKON_1_MovQuality			0xF01C
 
 /* Fuji specific */
 #define PTP_DPC_FUJI_ColorTemperature			0xD017
@@ -2019,10 +2102,15 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_SONY_ColorTemp				0xD20F
 #define PTP_DPC_SONY_CCFilter				0xD210
 #define PTP_DPC_SONY_AspectRatio			0xD211
+#define PTP_DPC_SONY_FocusFound     			0xD213 /* seems to be signaled (1->2) when focus is achieved */
+#define PTP_DPC_SONY_ObjectInMemory     		0xD215 /* used to signal when to retrieve new object */
 #define PTP_DPC_SONY_ExposeIndex			0xD216
+#define PTP_DPC_SONY_BatteryLevel			0xD218
 #define PTP_DPC_SONY_PictureEffect			0xD21B
 #define PTP_DPC_SONY_ABFilter				0xD21C
 #define PTP_DPC_SONY_ISO				0xD21E /* ? */
+#define PTP_DPC_SONY_AutoFocus				0xD2C1 /* ? half-press */
+#define PTP_DPC_SONY_Capture				0xD2C2 /* ? full-press */
 /* also seen: D2C3 D2C4 */
 /* semi control opcodes */
 #define PTP_DPC_SONY_Movie				0xD2C8 /* ? */
@@ -2059,6 +2147,34 @@ typedef struct _PTPCanonEOSDeviceInfo {
 #define PTP_DPC_CASIO_UNKNOWN_17	0xD030
 #define PTP_DPC_CASIO_UNKNOWN_18	0xD080
 
+#define PTP_DPC_RICOH_ShutterSpeed	0xD00F
+
+/* https://github.com/Parrot-Developers/sequoia-ptpy */
+#define PTP_DPC_PARROT_PhotoSensorEnableMask			0xD201
+#define PTP_DPC_PARROT_PhotoSensorsKeepOn			0xD202
+#define PTP_DPC_PARROT_MultispectralImageSize			0xD203
+#define PTP_DPC_PARROT_MainBitDepth				0xD204
+#define PTP_DPC_PARROT_MultispectralBitDepth			0xD205
+#define PTP_DPC_PARROT_HeatingEnable				0xD206
+#define PTP_DPC_PARROT_WifiStatus				0xD207
+#define PTP_DPC_PARROT_WifiSSID					0xD208
+#define PTP_DPC_PARROT_WifiEncryptionType			0xD209
+#define PTP_DPC_PARROT_WifiPassphrase				0xD20A
+#define PTP_DPC_PARROT_WifiChannel				0xD20B
+#define PTP_DPC_PARROT_Localization				0xD20C
+#define PTP_DPC_PARROT_WifiMode					0xD20D
+#define PTP_DPC_PARROT_AntiFlickeringFrequency			0xD210
+#define PTP_DPC_PARROT_DisplayOverlayMask			0xD211
+#define PTP_DPC_PARROT_GPSInterval				0xD212
+#define PTP_DPC_PARROT_MultisensorsExposureMeteringMode		0xD213
+#define PTP_DPC_PARROT_MultisensorsExposureTime			0xD214
+#define PTP_DPC_PARROT_MultisensorsExposureProgramMode		0xD215
+#define PTP_DPC_PARROT_MultisensorsExposureIndex		0xD216
+#define PTP_DPC_PARROT_MultisensorsIrradianceGain		0xD217
+#define PTP_DPC_PARROT_MultisensorsIrradianceIntegrationTime	0xD218
+#define PTP_DPC_PARROT_OverlapRate				0xD219
+
+
 /* MTP specific Object Properties */
 #define PTP_OPC_StorageID				0xDC01
 #define PTP_OPC_ObjectFormat				0xDC02
@@ -2273,7 +2389,7 @@ typedef struct _PTPDataHandler {
  * This functions take PTP oriented arguments and send them over an
  * appropriate data layer doing byteorder conversion accordingly.
  */
-typedef uint16_t (* PTPIOSendReq)	(PTPParams* params, PTPContainer* req);
+typedef uint16_t (* PTPIOSendReq)	(PTPParams* params, PTPContainer* req, int dataphase);
 typedef uint16_t (* PTPIOSendData)	(PTPParams* params, PTPContainer* ptp,
 					 uint64_t size, PTPDataHandler*getter);
 
@@ -2319,6 +2435,12 @@ struct _PTPDeviceProperty {
 };
 typedef struct _PTPDeviceProperty PTPDeviceProperty;
 
+/* Transaction data phase description, internal flags to sendreq / transaction driver. */
+#define PTP_DP_NODATA           0x0000  /* no data phase */
+#define PTP_DP_SENDDATA         0x0001  /* sending data */
+#define PTP_DP_GETDATA          0x0002  /* receiving data */
+#define PTP_DP_DATA_MASK        0x00ff  /* data phase mask */
+
 struct _PTPParams {
 	/* device flags */
 	uint32_t	device_flags;
@@ -2333,6 +2455,7 @@ struct _PTPParams {
 	PTPIOGetResp	getresp_func;
 	PTPIOGetData	getdata_func;
 	PTPIOGetResp	event_check;
+	PTPIOGetResp	event_check_queue;
 	PTPIOGetResp	event_wait;
 	PTPIOCancelReq	cancelreq_func;
 
@@ -2348,6 +2471,9 @@ struct _PTPParams {
 	/* ptp session ID */
 	uint32_t	session_id;
 
+	/* used for open capture */
+	uint32_t	opencapture_transid;
+
 	/* PTP IO: if we have MTP style split header/data transfers */
 	int		split_header_data;
 	int		ocs64; /* 64bit objectsize */
@@ -2365,6 +2491,13 @@ struct _PTPParams {
 	/* live view enabled */
 	int			inliveview;
 
+	/* PTP: caching time for properties, default 2 */
+	int			cachetime;
+
+	/* PTP: Storage Caching */
+	PTPStorageIDs		storageids;
+	int			storagechanged;
+
 	/* PTP: Device Property Caching */
 	PTPDeviceProperty	*deviceproperties;
 	unsigned int		nrofdeviceproperties;
@@ -2383,6 +2516,8 @@ struct _PTPParams {
 
 	/* PTP: Nikon specifics */
 	int			controlmode;
+	int			event90c7works;
+	int			deletesdramfails;
 
 	/* PTP: Wifi profiles */
 	uint8_t 	wifi_profiles_version;
@@ -2401,7 +2536,7 @@ struct _PTPParams {
 	char		*olympus_reply;
 	struct _PTPParams *outer_params;
 
-#ifdef HAVE_ICONV
+#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
 	/* PTP: iconv converters */
 	iconv_t	cd_locale_to_ucs2;
 	iconv_t cd_ucs2_to_locale;
@@ -2414,15 +2549,20 @@ struct _PTPParams {
 	uint16_t	response_packet_size;
 };
 
+/* Asynchronous event callback */
+typedef void (*PTPEventCbFn)(PTPParams *params, uint16_t code, PTPContainer *event, void *user_data);
+
 /* last, but not least - ptp functions */
 uint16_t ptp_usb_sendreq	(PTPParams* params, PTPContainer* req);
 uint16_t ptp_usb_senddata	(PTPParams* params, PTPContainer* ptp,
 				 uint64_t size, PTPDataHandler *handler);
 uint16_t ptp_usb_getresp	(PTPParams* params, PTPContainer* resp);
 uint16_t ptp_usb_getdata	(PTPParams* params, PTPContainer* ptp, 
 	                         PTPDataHandler *handler);
-uint16_t ptp_usb_event_check	(PTPParams* params, PTPContainer* event);
+uint16_t ptp_usb_event_async	(PTPParams *params, PTPEventCbFn cb, void *user_data);
 uint16_t ptp_usb_event_wait	(PTPParams* params, PTPContainer* event);
+uint16_t ptp_usb_event_check	(PTPParams* params, PTPContainer* event);
+uint16_t ptp_usb_event_check_queue	(PTPParams* params, PTPContainer* event);
 
 uint16_t ptp_usb_control_get_extended_event_data (PTPParams *params, char *buffer, int *size);
 uint16_t ptp_usb_control_device_reset_request (PTPParams *params);
@@ -2431,7 +2571,7 @@ uint16_t ptp_usb_control_cancel_request
 
 
 int      ptp_ptpip_connect	(PTPParams* params, const char *port);
-uint16_t ptp_ptpip_sendreq	(PTPParams* params, PTPContainer* req);
+uint16_t ptp_ptpip_sendreq	(PTPParams* params, PTPContainer* req, int dataphase);
 uint16_t ptp_ptpip_senddata	(PTPParams* params, PTPContainer* ptp,
 				uint64_t size, PTPDataHandler *handler);
 uint16_t ptp_ptpip_getresp	(PTPParams* params, PTPContainer* resp);
@@ -2439,6 +2579,7 @@ uint16_t ptp_ptpip_getdata	(PTPParams* p
 	                         PTPDataHandler *handler);
 uint16_t ptp_ptpip_event_wait	(PTPParams* params, PTPContainer* event);
 uint16_t ptp_ptpip_event_check	(PTPParams* params, PTPContainer* event);
+uint16_t ptp_ptpip_event_check_queue	(PTPParams* params, PTPContainer* event);
 
 uint16_t ptp_getdeviceinfo	(PTPParams* params, PTPDeviceInfo* deviceinfo);
 
@@ -2464,6 +2605,16 @@ uint16_t ptp_transaction (PTPParams* par
  * Return values: Some PTP_RC_* code.
  **/
 #define ptp_closesession(params) ptp_generic_no_data(params,PTP_OC_CloseSession,0)
+
+/**
+ * ptp_powerdown:
+ * params:      PTPParams*
+ *
+ * Powers down device.
+ *
+ * Return values: Some PTP_RC_* code.
+ **/
+#define ptp_powerdown(params) ptp_generic_no_data(params,PTP_OC_PowerDown,0)
 /**
  * ptp_resetdevice:
  * params:      PTPParams*
@@ -2505,11 +2656,16 @@ uint16_t ptp_getobjectinfo	(PTPParams *p
 
 uint16_t ptp_getobject		(PTPParams *params, uint32_t handle,
 				unsigned char** object);
+uint16_t ptp_getobject_with_size	(PTPParams *params, uint32_t handle,
+				unsigned char** object, unsigned int *size);
 uint16_t ptp_getobject_tofd     (PTPParams* params, uint32_t handle, int fd);
 uint16_t ptp_getobject_to_handler (PTPParams* params, uint32_t handle, PTPDataHandler*);
 uint16_t ptp_getpartialobject	(PTPParams* params, uint32_t handle, uint32_t offset,
 				uint32_t maxbytes, unsigned char** object,
 				uint32_t *len);
+uint16_t ptp_getpartialobject_to_handler (PTPParams* params, uint32_t handle, uint32_t offset,
+                        	uint32_t maxbytes, PTPDataHandler *handler);
+
 uint16_t ptp_getthumb		(PTPParams *params, uint32_t handle,
 				unsigned char** object, unsigned int *len);
 
@@ -2550,6 +2706,9 @@ uint16_t ptp_sendobject_from_handler  (P
  **/
 #define ptp_initiatecapture(params,storageid,ofc) ptp_generic_no_data(params,PTP_OC_InitiateCapture,2,storageid,ofc)
 
+#define ptp_initiateopencapture(params,storageid,ofc)	ptp_generic_no_data(params,PTP_OC_InitiateOpenCapture,2,storageid,ofc)
+#define ptp_terminateopencapture(params,transid)	ptp_generic_no_data(params,PTP_OC_TerminateOpenCapture,1,transid)
+
 uint16_t ptp_getdevicepropdesc	(PTPParams* params, uint16_t propcode,
 				PTPDevicePropDesc *devicepropertydesc);
 uint16_t ptp_generic_getdevicepropdesc (PTPParams *params, uint16_t propcode,
@@ -2567,6 +2726,8 @@ uint16_t ptp_getfilesystemmanifest (PTPP
 
 
 uint16_t ptp_check_event (PTPParams *params);
+uint16_t ptp_check_event_queue (PTPParams *params);
+uint16_t ptp_wait_event (PTPParams *params);
 uint16_t ptp_add_event (PTPParams *params, PTPContainer *evt);
 int ptp_get_one_event (PTPParams *params, PTPContainer *evt);
 uint16_t ptp_check_eos_events (PTPParams *params);
@@ -2847,6 +3008,7 @@ uint16_t ptp_canon_get_directory (PTPPar
  *
  **/
 #define ptp_canon_setobjectarchive(params,oid,flags) ptp_generic_no_data(params,PTP_OC_CANON_SetObjectArchive,2,oid,flags)
+#define ptp_canon_eos_setobjectattributes(params,oid,flags) ptp_generic_no_data(params,PTP_OC_CANON_EOS_SetObjectAttributes,2,oid,flags)
 uint16_t ptp_canon_get_customize_data (PTPParams* params, uint32_t themenr,
 				unsigned char **data, unsigned int *size);
 uint16_t ptp_canon_getpairinginfo (PTPParams* params, uint32_t nr, unsigned char**, unsigned int*);
@@ -2895,6 +3057,8 @@ uint16_t ptp_sony_setdevicecontrolvaluea
                         	PTPPropertyValue* value, uint16_t datatype);
 uint16_t ptp_sony_setdevicecontrolvalueb (PTPParams* params, uint16_t propcode,
                         	PTPPropertyValue* value, uint16_t datatype);
+uint16_t ptp_sony_9280 (PTPParams* params, uint32_t additional, uint32_t data1, uint32_t data2, uint32_t data3, uint32_t data4, uint8_t x, uint8_t y);
+uint16_t ptp_sony_9281 (PTPParams* params, uint32_t param1);
 /**
  * ptp_nikon_deletewifiprofile:
  *
@@ -2990,6 +3154,17 @@ uint16_t ptp_sony_setdevicecontrolvalueb
  **/
 #define ptp_canon_eos_afdrive(params) ptp_generic_no_data(params,PTP_OC_CANON_EOS_DoAf,0)
 /**
+ * ptp_canon_eos_afcancel:
+ *
+ * This command cancels the lens autofocus.
+ *  
+ * params:      PTPParams*
+ *
+ * Return values: Some PTP_RC_* code.
+ *
+ **/
+#define ptp_canon_eos_afcancel(params) ptp_generic_no_data(params,PTP_OC_CANON_EOS_AfCancel,0)
+/**
  * ptp_canon_eos_zoom:
  *
  * This command runs (drives) the lens autofocus.
@@ -3128,17 +3303,17 @@ uint16_t ptp_mtp_getobjectpropssupported
 uint16_t ptp_android_getpartialobject64	(PTPParams* params, uint32_t handle, uint64_t offset,
 					uint32_t maxbytes, unsigned char** object,
 					uint32_t *len);
-#define ptp_android_begineditobject(params,handle) ptp_generic_no_data (params, PTP_OC_ANDROID_BeginEditObject, 1, handle);
-#define ptp_android_truncate(params,handle,offset) ptp_generic_no_data (params, PTP_OC_ANDROID_TruncateObject, 3, handle, (offset & 0xFFFFFFFF), (offset >> 32));
+#define ptp_android_begineditobject(params,handle) ptp_generic_no_data (params, PTP_OC_ANDROID_BeginEditObject, 1, handle)
+#define ptp_android_truncate(params,handle,offset) ptp_generic_no_data (params, PTP_OC_ANDROID_TruncateObject, 3, handle, (offset & 0xFFFFFFFF), (offset >> 32))
 uint16_t ptp_android_sendpartialobject (PTPParams *params, uint32_t handle,
 					uint64_t offset, unsigned char *object, uint32_t len);
-#define ptp_android_endeditobject(params,handle) ptp_generic_no_data (params, PTP_OC_ANDROID_EndEditObject, 1, handle);
+#define ptp_android_endeditobject(params,handle) ptp_generic_no_data (params, PTP_OC_ANDROID_EndEditObject, 1, handle)
 
 uint16_t ptp_olympus_getdeviceinfo (PTPParams*, PTPDeviceInfo*);
-#define ptp_olympus_setcameracontrolmode(params,p1) ptp_generic_no_data (params, PTP_OC_OLYMPUS_SetCameraControlMode, 1, p1);
-uint16_t ptp_olympus_opensession (PTPParams*, unsigned char**, unsigned long *);
-#define ptp_olympus_capture(params,p1) ptp_generic_no_data (params, PTP_OC_OLYMPUS_Capture, 1, p1);
-uint16_t ptp_olympus_getcameraid (PTPParams*, unsigned char**, unsigned long *);
+#define ptp_olympus_setcameracontrolmode(params,p1) ptp_generic_no_data (params, PTP_OC_OLYMPUS_SetCameraControlMode, 1, p1)
+uint16_t ptp_olympus_opensession (PTPParams*, unsigned char**, unsigned int *);
+#define ptp_olympus_capture(params,p1) ptp_generic_no_data (params, PTP_OC_OLYMPUS_Capture, 1, p1)
+uint16_t ptp_olympus_getcameraid (PTPParams*, unsigned char**, unsigned int *);
 
 /* Non PTP protocol functions */
 static inline int
@@ -3163,26 +3338,25 @@ void ptp_free_devicepropvalue	(uint16_t,
 void ptp_free_objectinfo	(PTPObjectInfo *oi);
 void ptp_free_object		(PTPObject *oi);
 
-const char *ptp_strerror(uint16_t error);
-void ptp_perror			(PTPParams* params, uint16_t error);
+const char *ptp_strerror	(uint16_t ret, uint16_t vendor);
 void ptp_debug			(PTPParams *params, const char *format, ...);
 void ptp_error			(PTPParams *params, const char *format, ...);
 
 
-const char*
-ptp_get_property_description(PTPParams* params, uint16_t dpc);
+const char* ptp_get_property_description(PTPParams* params, uint16_t dpc);
+
+const char* ptp_get_opcode_name(PTPParams* params, uint16_t opcode);
 
 int
 ptp_render_property_value(PTPParams* params, uint16_t dpc,
                           PTPDevicePropDesc *dpd, unsigned int length, char *out);
 int ptp_render_ofc(PTPParams* params, uint16_t ofc, int spaceleft, char *txt);
-int ptp_render_opcode(PTPParams* params, uint16_t opcode, int spaceleft, char *txt);
 int ptp_render_mtp_propname(uint16_t propid, int spaceleft, char *txt);
 MTPProperties *ptp_get_new_object_prop_entry(MTPProperties **props, int *nrofprops);
 void ptp_destroy_object_prop(MTPProperties *prop);
 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_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, unsigned int want, PTPObject**retob);
 void ptp_objects_sort (PTPParams *);
@@ -3236,7 +3410,7 @@ typedef struct {
 uint16_t ptp_chdk_get_memory(PTPParams* params, int start, int num, unsigned char **);
 uint16_t ptp_chdk_set_memory_long(PTPParams* params, int addr, int val);
 int ptp_chdk_upload(PTPParams* params, char *local_fn, char *remote_fn);
-int ptp_chdk_download(PTPParams* params, char *remote_fn, char *local_fn);
+uint16_t ptp_chdk_download(PTPParams* params, char *remote_fn, PTPDataHandler *handler);
 
 /* remote capture */
 uint16_t ptp_chdk_rcisready(PTPParams* params, int *isready,int *imgnum);