aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarcus Meissner <marcus@jet.franken.de>2017-03-16 15:59:48 +0100
committerMarcus Meissner <marcus@jet.franken.de>2017-03-16 15:59:48 +0100
commitaa7d91a789873a9d86969028e57f888a1241c085 (patch)
tree57d3c17fd2e9243cca15724c0ba229309eeaafea /src
parente2bfba8fd746780c80d8729898bb686d03b5ed20 (diff)
downloadlibmtp-aa7d91a789873a9d86969028e57f888a1241c085.tar.gz
imported ptp* from libgphoto2
lots of buffer overread checks
Diffstat (limited to 'src')
-rw-r--r--src/libmtp.c1
-rw-r--r--src/ptp-pack.c312
-rw-r--r--src/ptp.c340
-rw-r--r--src/ptp.h89
4 files changed, 618 insertions, 124 deletions
diff --git a/src/libmtp.c b/src/libmtp.c
index 7bb5a7e..dfd77b7 100644
--- a/src/libmtp.c
+++ b/src/libmtp.c
@@ -1863,6 +1863,7 @@ LIBMTP_mtpdevice_t *LIBMTP_Open_Raw_Device_Uncached(LIBMTP_raw_device_t *rawdevi
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;
diff --git a/src/ptp-pack.c b/src/ptp-pack.c
index ea6bfc9..22b9ae7 100644
--- a/src/ptp-pack.c
+++ b/src/ptp-pack.c
@@ -1,7 +1,7 @@
/* ptp-pack.c
*
* Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
- * Copyright (C) 2003-2014 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>
@@ -127,7 +127,7 @@ dtoh64ap (PTPParams *params, const unsigned char *a)
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, unsigned char* data, uint16_t offset, uint8
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]));
@@ -262,6 +268,9 @@ ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, unsigned int o
{
uint32_t n, i=0;
+ if (!data)
+ return 0;
+
if (offset >= datalen)
return 0;
@@ -281,6 +290,8 @@ ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, unsigned int o
}
*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;
@@ -292,6 +303,8 @@ ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, u
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]);
@@ -303,6 +316,8 @@ ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int o
{
uint32_t n, i=0;
+ if (!data)
+ return 0;
*array = NULL;
n=dtoh32a(&data[offset]);
if (n >= UINT_MAX/sizeof(uint16_t))
@@ -316,6 +331,8 @@ ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int o
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;
@@ -330,66 +347,86 @@ ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int o
#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
@@ -404,35 +441,36 @@ ptp_free_DI (PTPDeviceInfo *di) {
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, datalen, &di->EventsSupported);
- if (!di->EventsSupported) return;
+ 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, datalen, &di->DevicePropertiesSupported);
- if (!di->DevicePropertiesSupported) return;
+ 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, datalen, &di->unk);
- if (!di->unk) return;
+ if (!di->unk) return 0;
totallen += di->unk_len*sizeof(uint32_t)+4;
- return;
+ return 1;
}
static inline void
@@ -465,11 +503,12 @@ ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, uns
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, len, &sids->Storage);
}
@@ -483,12 +522,12 @@ ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, un
#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;
+ 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]);
@@ -498,10 +537,14 @@ ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsig
/* 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 */
@@ -670,10 +713,10 @@ ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, 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
*/
@@ -683,7 +726,7 @@ ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, 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);
}
@@ -705,6 +748,8 @@ ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, 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; \
@@ -717,6 +762,9 @@ ptp_unpack_DPV (
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);
@@ -783,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;
@@ -807,6 +859,8 @@ ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd,
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]);
@@ -1288,8 +1342,11 @@ ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops,
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);
@@ -1300,7 +1357,7 @@ ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops,
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;
@@ -1319,7 +1376,12 @@ ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops,
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;
}
@@ -1598,7 +1660,7 @@ ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value
* size=NxN,size2=NxN,points={NxNxNxN,NxNxNxN,...},selected={0,1,2}
*/
static inline char*
-ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data )
+ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data, uint32_t datasize )
{
uint32_t size = dtoh32a( *data );
uint32_t halfsize = dtoh16a( (*data) + 4);
@@ -1613,24 +1675,37 @@ ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data )
uint32_t maxlen;
char *str, *p;
- /* every focuspoint gets 4 (16 bit number and a x) and a ,*/
+ 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 */
- maxlen = focus_points_in_use*6*4 + focus_points_in_use + 100;
+ * 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 "bad size";
+ 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 "bad size 2";
+ 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", version);
+ 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 );
@@ -1652,12 +1727,14 @@ ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data )
}
p += sprintf(p,"},select={");
for (i=0;i<focus_points_in_use;i++) {
- if ((1<<(i%7)) & ((*data)[focus_points_in_struct*8+20+i/8]))
+ 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,"}");
@@ -1670,14 +1747,19 @@ 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;
}
@@ -1726,6 +1808,18 @@ ptp_pack_EOS_CustomFuncEx (PTPParams* params, unsigned char* data, char* str)
#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)
{
@@ -1761,18 +1855,33 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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++;
@@ -1781,35 +1890,75 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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]);
@@ -1817,6 +1966,11 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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)
@@ -1831,7 +1985,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
* 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;
@@ -1864,8 +2018,12 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
/* '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 */ \
} \
@@ -1877,7 +2035,10 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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;
@@ -1892,6 +2053,10 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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)
@@ -1900,6 +2065,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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 {
@@ -1974,6 +2140,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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 */
@@ -2151,7 +2318,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
dpd->DataType = PTP_DTC_STR;
free (dpd->FactoryDefaultValue.str);
free (dpd->CurrentValue.str);
- dpd->FactoryDefaultValue.str = ptp_unpack_EOS_FocusInfoEx( params, &xdata );
+ 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;
@@ -2173,12 +2340,19 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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;
@@ -2377,7 +2551,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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:
@@ -2415,6 +2589,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
}
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]);
}
@@ -2422,9 +2597,10 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize,
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);
@@ -2452,8 +2628,10 @@ ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, P
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;
diff --git a/src/ptp.c b/src/ptp.c
index 68158c1..48eb005 100644
--- a/src/ptp.c
+++ b/src/ptp.c
@@ -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>
@@ -224,7 +224,9 @@ ptp_transaction_new (PTPParams* params, PTPContainer* ptp,
"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;
}
@@ -463,12 +465,16 @@ ptp_getdeviceinfo (PTPParams* params, PTPDeviceInfo* deviceinfo)
PTPContainer ptp;
unsigned char *data;
unsigned int size;
+ int ret;
PTP_CNT_INIT(ptp, PTP_OC_GetDeviceInfo);
CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
- ptp_unpack_DI(params, data, deviceinfo, size);
+ ret = ptp_unpack_DI(params, data, deviceinfo, size);
free(data);
- return PTP_RC_OK;
+ if (ret)
+ return PTP_RC_OK;
+ else
+ return PTP_ERROR_IO;
}
uint16_t
@@ -477,12 +483,16 @@ ptp_canon_eos_getdeviceinfo (PTPParams* params, PTPCanonEOSDeviceInfo*di)
PTPContainer ptp;
unsigned char *data;
unsigned int size;
+ int ret;
PTP_CNT_INIT(ptp, PTP_OC_CANON_EOS_GetDeviceInfoEx);
CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
- ptp_unpack_EOS_DI(params, data, di, size);
+ ret = ptp_unpack_EOS_DI(params, data, di, size);
free (data);
- return PTP_RC_OK;
+ if (ret)
+ return PTP_RC_OK;
+ else
+ return PTP_ERROR_IO;
}
#ifdef HAVE_LIBXML2
@@ -1118,6 +1128,7 @@ ptp_free_params (PTPParams *params)
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);
@@ -1175,7 +1186,13 @@ ptp_getstorageinfo (PTPParams* params, uint32_t storageid,
PTP_CNT_INIT(ptp, PTP_OC_GetStorageInfo, storageid);
CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
- ptp_unpack_SI(params, data, storageinfo, 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;
}
@@ -1204,6 +1221,9 @@ ptp_getobjecthandles (PTPParams* params, uint32_t storage,
unsigned char *data;
unsigned int size;
+ 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) {
@@ -1376,6 +1396,27 @@ ptp_getobject (PTPParams* params, uint32_t handle, unsigned char** object)
}
/**
+ * 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);
+}
+
+/**
* ptp_getobject_to_handler:
* params: PTPParams*
* handle - Object handle
@@ -1628,6 +1669,11 @@ ptp_getdevicepropdesc (PTPParams* params, uint16_t propcode,
PTP_CNT_INIT(ptp, PTP_OC_GetDevicePropDesc, propcode);
CHECK_PTP_RC(ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &data, &size));
+ if (!data) {
+ ptp_debug (params, "no data received for getdevicepropdesc");
+ return PTP_RC_InvalidDevicePropFormat;
+ }
+
if (params->device_flags & DEVICE_FLAG_OLYMPUS_XML_WRAPPED) {
#ifdef HAVE_LIBXML2
xmlNodePtr code;
@@ -2037,7 +2083,7 @@ ptp_canon_gettreesize (PTPParams* params,
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);
}
exit:
@@ -2091,6 +2137,69 @@ ptp_add_event (PTPParams *params, PTPContainer *evt)
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_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)
{
@@ -2103,7 +2212,7 @@ ptp_check_event (PTPParams *params)
if ( (params->deviceinfo.VendorExtensionID == PTP_VENDOR_NIKON) &&
ptp_operation_issupported(params, PTP_OC_NIKON_CheckEvent)
) {
- unsigned int evtcnt = 0;
+ unsigned int evtcnt = 0, i;
PTPContainer *xevent = NULL;
ret = ptp_nikon_check_event(params, &xevent, &evtcnt);
@@ -2111,6 +2220,8 @@ ptp_check_event (PTPParams *params)
CHECK_PTP_RC(ret);
if (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;
@@ -2159,22 +2270,8 @@ store_event:
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 some PTP stack internal events */
- switch (event.Code) {
- case PTP_EC_DevicePropChanged: {
- unsigned int i;
+ handle_event_internal (params, &event);
- /* 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;
- }
- default: /* check if we should handle it internally too */
- break;
- }
}
if (ret == PTP_ERROR_TIMEOUT) /* ok, just new events */
@@ -2193,22 +2290,7 @@ ptp_wait_event (PTPParams *params)
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 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;
- }
- default: /* check if we should handle it internally too */
- break;
- }
+ handle_event_internal (params, &event);
}
if (ret == PTP_ERROR_TIMEOUT) /* ok, just new events */
ret = PTP_RC_OK;
@@ -2375,6 +2457,16 @@ ptp_canon_eos_getobjectinfoex (
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) {
@@ -2384,6 +2476,14 @@ ptp_canon_eos_getobjectinfoex (
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);
}
@@ -2638,23 +2738,36 @@ ptp_canon_getobjectinfo (PTPParams* params, uint32_t store, uint32_t p2,
PTPContainer ptp;
uint16_t ret;
unsigned char *data;
- unsigned int i;
+ unsigned int i, size;
+ *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;
+ *entnum = ptp.Param1;
+ *entries= calloc(*entnum, sizeof(PTPCANONFolderEntry));
+ if (*entries == NULL) {
+ ret = PTP_RC_GeneralError;
goto exit;
}
- for(i=0; i<(*entnum); i++)
+ 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]) );
+ }
exit:
free (data);
@@ -2768,7 +2881,7 @@ uint16_t
ptp_sony_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int *size)
{
PTPContainer ptp;
- unsigned char *xdata;
+ unsigned char *xdata = NULL;
unsigned int xsize, psize1 = 0, psize2 = 0;
uint16_t *props1 = NULL,*props2 = NULL;
@@ -2786,8 +2899,15 @@ ptp_sony_get_vendorpropcodes (PTPParams* params, uint16_t **props, unsigned int
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;
- *props = malloc((psize1+psize2)*sizeof(uint16_t));
memcpy (*props, props1, psize1*sizeof(uint16_t));
memcpy ((*props)+psize1, props2, psize2*sizeof(uint16_t));
free (props1);
@@ -2806,6 +2926,7 @@ ptp_sony_getdevicepropdesc (PTPParams* params, uint16_t propcode, PTPDevicePropD
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 */
ret = ptp_unpack_Sony_DPD(params,data,dpd,size,&len) ? PTP_RC_OK : PTP_RC_GeneralError;
free (data);
@@ -2822,6 +2943,12 @@ ptp_sony_getalldevicepropdesc (PTPParams* params)
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) {
@@ -2837,6 +2964,35 @@ ptp_sony_getalldevicepropdesc (PTPParams* params)
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) {
params->deviceproperties = realloc(params->deviceproperties,(i+1)*sizeof(params->deviceproperties[0]));
memset(&params->deviceproperties[i],0,sizeof(params->deviceproperties[0]));
@@ -2963,7 +3119,6 @@ ptp_sony_9281 (PTPParams* params, uint32_t param1) {
*
**/
/* Cache time in seconds. Should perhaps be more granular... */
-#define CACHETIME 2
uint16_t
ptp_generic_getdevicepropdesc (PTPParams *params, uint16_t propcode, PTPDevicePropDesc *dpd)
@@ -2982,7 +3137,7 @@ ptp_generic_getdevicepropdesc (PTPParams *params, uint16_t propcode, PTPDevicePr
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;
}
@@ -3283,14 +3438,14 @@ ptp_nikon_getwifiprofilelist (PTPParams* params)
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)
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);
@@ -3451,6 +3606,7 @@ ptp_mtp_getobjectpropssupported (PTPParams* params, uint16_t ofc,
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 PTP_RC_OK;
@@ -3869,6 +4025,10 @@ ptp_chdk_read_script_msg(PTPParams* params, ptp_chdk_script_msg **msg)
/* camera will always send data, otherwise getdata will cause problems */
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);
@@ -4804,7 +4964,10 @@ ptp_get_property_description(PTPParams* params, uint16_t dpc)
{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 */
@@ -4813,6 +4976,36 @@ ptp_get_property_description(PTPParams* params, uint16_t dpc)
{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)
@@ -4848,6 +5041,11 @@ ptp_get_property_description(PTPParams* params, uint16_t dpc)
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;
}
@@ -5536,9 +5734,14 @@ ptp_render_property_value(PTPParams* params, uint16_t dpc,
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;
@@ -5685,6 +5888,14 @@ ptp_render_ofc(PTPParams* params, uint16_t ofc, int spaceleft, char *txt)
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++)
@@ -6005,6 +6216,23 @@ ptp_opcode_trans_t ptp_opcode_sony_trans[] = {
{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)
{
@@ -6026,6 +6254,7 @@ ptp_get_opcode_name(PTPParams* params, uint16_t 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;
}
@@ -6317,7 +6546,12 @@ 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
diff --git a/src/ptp.h b/src/ptp.h
index 62938b4..eda3e1b 100644
--- a/src/ptp.h
+++ b/src/ptp.h
@@ -172,6 +172,7 @@ 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
@@ -279,6 +280,7 @@ typedef struct _PTPIPHeader PTPIPHeader;
#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
@@ -407,6 +409,7 @@ typedef struct _PTPIPHeader PTPIPHeader;
#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? */
@@ -439,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
@@ -669,6 +674,22 @@ typedef struct _PTPIPHeader PTPIPHeader;
#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
@@ -744,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
@@ -825,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 */
@@ -854,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
@@ -2066,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 /* ? */
@@ -2108,6 +2149,32 @@ typedef struct _PTPCanonEOSDeviceInfo {
#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
@@ -2388,6 +2455,7 @@ struct _PTPParams {
PTPIOGetResp getresp_func;
PTPIOGetData getdata_func;
PTPIOGetResp event_check;
+ PTPIOGetResp event_check_queue;
PTPIOGetResp event_wait;
PTPIOCancelReq cancelreq_func;
@@ -2423,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;
@@ -2475,7 +2550,7 @@ struct _PTPParams {
};
/* Asynchronous event callback */
-typedef void(* PTPEventCbFn) (PTPParams *params, uint16_t code, PTPContainer *event, void *user_data);
+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, int dataphase);
@@ -2484,9 +2559,10 @@ uint16_t ptp_usb_senddata (PTPParams* params, PTPContainer* ptp,
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_wait (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);
@@ -2503,6 +2579,7 @@ uint16_t ptp_ptpip_getdata (PTPParams* params, PTPContainer* ptp,
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);
@@ -2579,6 +2656,8 @@ uint16_t ptp_getobjectinfo (PTPParams *params, uint32_t handle,
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,
@@ -2647,6 +2726,7 @@ uint16_t ptp_getfilesystemmanifest (PTPParams* params, uint32_t storage,
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);
@@ -2928,6 +3008,7 @@ uint16_t ptp_canon_get_directory (PTPParams* params, PTPObjectHandles *handles,
*
**/
#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*);