diff options
author | Marcus Meissner <marcus@jet.franken.de> | 2017-03-16 15:59:48 +0100 |
---|---|---|
committer | Marcus Meissner <marcus@jet.franken.de> | 2017-03-16 15:59:48 +0100 |
commit | aa7d91a789873a9d86969028e57f888a1241c085 (patch) | |
tree | 57d3c17fd2e9243cca15724c0ba229309eeaafea /src | |
parent | e2bfba8fd746780c80d8729898bb686d03b5ed20 (diff) | |
download | libmtp-aa7d91a789873a9d86969028e57f888a1241c085.tar.gz |
imported ptp* from libgphoto2
lots of buffer overread checks
Diffstat (limited to 'src')
-rw-r--r-- | src/libmtp.c | 1 | ||||
-rw-r--r-- | src/ptp-pack.c | 312 | ||||
-rw-r--r-- | src/ptp.c | 340 | ||||
-rw-r--r-- | src/ptp.h | 89 |
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; @@ -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 (¶ms->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, ¶ms->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 (¶ms->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 (¶ms->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(¶ms->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(¶ms->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 @@ -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*); |