diff options
Diffstat (limited to 'src/ptp-pack.c')
-rw-r--r-- | src/ptp-pack.c | 280 |
1 files changed, 250 insertions, 30 deletions
diff --git a/src/ptp-pack.c b/src/ptp-pack.c index 22b9ae7..5319525 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-2016 Marcus Meissner <marcus@jet.franken.de> + * Copyright (C) 2003-2017 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> @@ -136,17 +136,22 @@ ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint3 size_t nconv, srclen, destlen; char *src, *dest; + *len = 0; + if (offset + 1 >= total) return NULL; length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */ - *len = length; - if (length == 0) /* nothing to do? */ + if (length == 0) { /* nothing to do? */ + *len = 0; return NULL; + } if (offset + 1 + length*sizeof(string[0]) > total) return NULL; + *len = length; + /* copy to string[] to ensure correct alignment for iconv(3) */ memcpy(string, &data[offset+1], length * sizeof(string[0])); string[length] = 0x0000U; /* be paranoid! add a terminator. */ @@ -319,7 +324,11 @@ ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int o if (!data) return 0; *array = NULL; + + if (datalen - offset < sizeof(uint32_t)) + return 0; n=dtoh32a(&data[offset]); + if (n >= UINT_MAX/sizeof(uint16_t)) return 0; if (!n) @@ -367,7 +376,10 @@ ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsign datalen, &len); totallen=len*2+1; - if (datalen <= totallen) return 0; + if (datalen <= totallen + PTP_di_FunctionalMode + sizeof(uint16_t)) { + ptp_debug (params, "datalen %d <= totallen + PTP_di_FunctionalMode + sizeof(uint16_t) %d", datalen, totallen + PTP_di_FunctionalMode + sizeof(uint16_t)); + return 0; + } di->FunctionalMode = dtoh16a(&data[PTP_di_FunctionalMode+totallen]); di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data, @@ -375,53 +387,77 @@ ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsign datalen, &di->OperationsSupported); totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t); - if (datalen <= totallen+PTP_di_OperationsSupported) return 0; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 1", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 2", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 3", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 4", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 5", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 6", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 7", 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; + if (datalen <= totallen+PTP_di_OperationsSupported) { + ptp_debug (params, "datalen %d <= totallen+PTP_di_OperationsSupported %d 8", datalen, totallen+PTP_di_OperationsSupported); + return 1; + } di->SerialNumber = ptp_unpack_string(params, data, PTP_di_OperationsSupported+totallen, datalen, @@ -698,8 +734,10 @@ ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsign /* Stupid Samsung Galaxy developers emit a 64bit objectcompressedsize */ if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0)) { + ptp_debug (params, "objectsize 64bit detected!"); params->ocs64 = 1; data += 4; + len -= 4; } oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]); oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]); @@ -836,9 +874,9 @@ ptp_unpack_DPV ( return 0; value->str = ptp_unpack_string(params,data,*offset,total,&len); - *offset += len*2+1; if (!value->str) - return 1; + return 0; + *offset += len*2+1; break; } default: @@ -879,7 +917,7 @@ ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, values). In both cases Form Flag should be set to 0x00 and FORM is not present. */ - if (offset==PTP_dpd_FactoryDefaultValue) + if (offset + sizeof(uint8_t) > dpdlen) return 1; dpd->FormFlag=dtoh8a(&data[offset]); @@ -897,6 +935,9 @@ ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, case PTP_DPFF_Enumeration: { int i; #define N dpd->FORM.Enum.NumberOfValues + + if (offset + sizeof(uint16_t) > dpdlen) goto outofmemory; + N = dtoh16a(&data[offset]); offset+=sizeof(uint16_t); dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0])); @@ -1096,6 +1137,10 @@ ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int offset=0, ret; memset (opd, 0, sizeof(*opd)); + + if (opdlen < 5) + return 0; + opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]); opd->DataType=dtoh16a(&data[PTP_opd_DataType]); opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]); @@ -1104,9 +1149,11 @@ ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType); if (!ret) goto outofmemory; + if (offset + sizeof(uint32_t) > opdlen) goto outofmemory; opd->GroupCode=dtoh32a(&data[offset]); offset+=sizeof(uint32_t); + if (offset + sizeof(uint8_t) > opdlen) goto outofmemory; opd->FormFlag=dtoh8a(&data[offset]); offset+=sizeof(uint8_t); @@ -1122,8 +1169,11 @@ ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, case PTP_OPFF_Enumeration: { unsigned int i; #define N opd->FORM.Enum.NumberOfValues + + if (offset + sizeof(uint16_t) > opdlen) goto outofmemory; N = dtoh16a(&data[offset]); offset+=sizeof(uint16_t); + opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0])); if (!opd->FORM.Enum.SupportedValue) goto outofmemory; @@ -1338,24 +1388,32 @@ _compare_func(const void* x, const void *y) { static inline int ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len) { - uint32_t prop_count = dtoh32a(data); + uint32_t prop_count; MTPProperties *props = NULL; unsigned int offset = 0, i; + if (len < sizeof(uint32_t)) { + ptp_debug (params ,"must have at least 4 bytes data, not %d", len); + return 0; + } + + prop_count = dtoh32a(data); *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); + data += sizeof(uint32_t); len -= sizeof(uint32_t); props = malloc(prop_count * sizeof(MTPProperties)); if (!props) return 0; for (i = 0; i < prop_count; i++) { - if (len <= 0) { + if (len <= (sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t))) { 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"); ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i); @@ -1363,6 +1421,8 @@ ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, *pprops = props; return i; } + + props[i].ObjectHandle = dtoh32a(data); data += sizeof(uint32_t); len -= sizeof(uint32_t); @@ -1528,10 +1588,12 @@ ObjectInfo for 'IMG_0199.JPG': #define PTP_cefe_Time 48 static inline void -ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe) +ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, unsigned int size, PTPCANONFolderEntry *fe) { int i; + if (size < PTP_cefe_Time + 4) return; + fe->ObjectHandle=dtoh32a(&data[PTP_cefe_ObjectHandle]); fe->ObjectFormatCode=dtoh16a(&data[PTP_cefe_ObjectFormatCode]); fe->Flags=dtoh8a(&data[PTP_cefe_Flags]); @@ -1539,6 +1601,7 @@ ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderE fe->Time=(time_t)dtoh32a(&data[PTP_cefe_Time]); for (i=0; i<PTP_CANON_FilenameBufferLen; i++) fe->Filename[i]=(char)data[PTP_cefe_Filename+i]; + fe->Filename[PTP_CANON_FilenameBufferLen-1] = 0; } @@ -1677,6 +1740,13 @@ ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data, uint32_t da if ((size >= datasize) || (size < 20)) return strdup("bad size 1"); + /* If data is zero-filled, then it is just a placeholder, so nothing + useful, but also not an error */ + if (!focus_points_in_struct || !focus_points_in_use) { + ptp_debug(params, "skipped FocusInfoEx data (zero filled)"); + return strdup("no focus points returned by camera"); + } + /* 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 @@ -1914,21 +1984,34 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; ce[i].u.info = NULL; switch (type) { + case PTP_EC_CANON_EOS_ObjectContentChanged: + if (size < PTP_ece_OA_ObjectID+1) { + ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OA_ObjectID+1); + break; + } + ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTCONTENT_CHANGE; + ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]); + break; + case PTP_EC_CANON_EOS_ObjectInfoChangedEx: 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].type = ((type == PTP_EC_CANON_EOS_ObjectAddedEx) ? PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO : PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO_CHANGE); ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]); ce[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]); ce[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]); ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]); ce[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]); ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name])); - ptp_debug (params, "event %d: objectinfo added oid %08lx, parent %08lx, ofc %04x, size %d, filename %s", i, ce[i].u.object.oid, ce[i].u.object.oi.ParentObject, ce[i].u.object.oi.ObjectFormat, ce[i].u.object.oi.ObjectCompressedSize, ce[i].u.object.oi.Filename); + if (type == PTP_EC_CANON_EOS_ObjectAddedEx) { + 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); + } else { + ptp_debug (params, "event %d: objectinfo changed 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 */ + case PTP_EC_CANON_EOS_ObjectAddedEx64: /* 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; @@ -1943,7 +2026,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, 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_RequestObjectTransferNew: /* FIXME: confirm */ + case PTP_EC_CANON_EOS_RequestObjectTransfer64: if (size < PTP_ece_OI_Name+1) { ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OI_Name+1); break; @@ -2030,9 +2113,11 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, break; case PTP_DTC_INT16: XX( i16, dtoh16a ); - case PTP_DTC_UINT32: XX( u32, dtoh32a ); case PTP_DTC_UINT16: XX( u16, dtoh16a ); + case PTP_DTC_UINT32: XX( u32, dtoh32a ); + case PTP_DTC_INT32: XX( i32, dtoh32a ); case PTP_DTC_UINT8: XX( u8, dtoh8a ); + case PTP_DTC_INT8: XX( i8, dtoh8a ); #undef XX default: free (dpd->FORM.Enum.SupportedValue); @@ -2141,6 +2226,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, case PTP_DPC_CANON_EOS_AFSelectFocusArea: case PTP_DPC_CANON_EOS_ContinousAFMode: case PTP_DPC_CANON_EOS_MirrorUpSetting: + case PTP_DPC_CANON_EOS_OLCInfoVersion: dpd->DataType = PTP_DTC_UINT32; break; /* enumeration for AEM is never provided, but is available to set */ @@ -2165,6 +2251,8 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, case PTP_DPC_CANON_EOS_EVFOutputDevice: case PTP_DPC_CANON_EOS_AutoPowerOff: case PTP_DPC_CANON_EOS_EVFRecordStatus: + case PTP_DPC_CANON_EOS_HighISOSettingNoiseReduction: + case PTP_DPC_CANON_EOS_MultiAspect: /* actually a 32bit value, but lets try it for easyness */ dpd->DataType = PTP_DTC_UINT16; break; case PTP_DPC_CANON_EOS_PictureStyle: @@ -2182,7 +2270,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, break; case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA: case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB: - dpd->DataType = PTP_DTC_INT16; + dpd->DataType = PTP_DTC_INT32; break; /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */ case PTP_DPC_CANON_EOS_DPOFVersion: @@ -2327,10 +2415,27 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, break; } /* one more information record handed to us */ + /* Versions seen: (d199) + * 100D: 7 (original reference) + * 5d Mark 3: 7 + * 650D: 7 + * 6D: 7 + * M10: 8 + * 70D: 8 + * 5Dsr: b + * 200D: f + */ case PTP_EC_CANON_EOS_OLCInfoChanged: { uint32_t len, curoff; uint16_t mask,proptype; PTPDevicePropDesc *dpd; + int olcver = 0; + + dpd = _lookup_or_allocate_canon_prop(params, PTP_DPC_CANON_EOS_OLCInfoVersion); + if (dpd) { + ptp_debug (params, "olcinfoversion is %d", dpd->CurrentValue.u32); + olcver = dpd->CurrentValue.u32; + } /* unclear what OLC stands for */ ptp_debug (params, "event %d: EOS event OLCInfoChanged (size %d)", i, size); @@ -2359,35 +2464,58 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, ce[i].u.info = malloc(strlen("Button 1234567")); sprintf(ce[i].u.info, "Button %d", dtoh16a(curdata+curoff)); i++; - curoff += 2; + curoff += 2; /* 7, 8 , f */ } if (mask & CANON_EOS_OLC_SHUTTERSPEED) { /* 6 bytes: 01 01 98 10 00 60 */ /* this seesm to be the shutter speed record */ + /* EOS 200D seems to have 7 bytes here, sample: + * 7 bytes: 01 03 98 10 00 70 00 + */ proptype = PTP_DPC_CANON_EOS_ShutterSpeed; dpd = _lookup_or_allocate_canon_prop(params, proptype); dpd->CurrentValue.u16 = curdata[curoff+5]; /* just use last byte */ ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY; ce[i].u.propid = proptype; - curoff += 6; + /* hack to differ between older EOS and EOS 200D newer */ + switch (olcver) { + case 0x8: + case 0xf: + curoff += 7; /* f (200D), 8 (M10) */ + break; + case 0x7: + case 0xb: + curoff += 6; /* 7 , b (5ds) */ + break; + default: + curoff += 6; + break; + } i++; } if (mask & CANON_EOS_OLC_APERTURE) { /* 5 bytes: 01 01 5b 30 30 */ /* this seesm to be the aperture record */ + /* EOS 200D seems to have 6 bytes here? + * 6 bytes: 01 01 50 20 20 00 * + */ proptype = PTP_DPC_CANON_EOS_Aperture; dpd = _lookup_or_allocate_canon_prop(params, proptype); dpd->CurrentValue.u16 = curdata[curoff+4]; /* just use last byte */ ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY; ce[i].u.propid = proptype; - curoff += 5; + if (olcver >= 0xf) { + curoff += 6; /* f */ + } else { + curoff += 5; /* 7, 8, b */ + } i++; } if (mask & CANON_EOS_OLC_ISO) { - /* 5 bytes: 01 01 00 78 */ + /* 4 bytes: 01 01 00 78 */ /* this seesm to be the aperture record */ proptype = PTP_DPC_CANON_EOS_ISOSpeed; dpd = _lookup_or_allocate_canon_prop(params, proptype); @@ -2395,7 +2523,7 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY; ce[i].u.propid = proptype; - curoff += 4; + curoff += 4; /* 7, 8, b, f*/ i++; } if (mask & 0x0010) { @@ -2412,7 +2540,10 @@ ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, i++; } if (mask & 0x0020) { - /* mask 0x0020: 6 bytes, 00 00 00 00 00 00 observed */ + /* mask 0x0020: 6 bytes, 00 00 00 00 00 00 observed. + * This seems to be the self-timer record: when active, + * has the form of 00 00 01 00 XX XX, where the last two bytes + * stand for the number of seconds remaining until the shot */ ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN; ce[i].u.info = malloc(strlen("OLCInfo event 0x0020 content 0123456789ab")+1); sprintf(ce[i].u.info,"OLCInfo event 0x0020 content %02x%02x%02x%02x%02x%02x", @@ -2822,3 +2953,92 @@ ptp_unpack_canon_directory ( #undef ISOBJECT return PTP_RC_OK; } + +static inline int +ptp_unpack_ptp11_manifest ( + PTPParams *params, + unsigned char *data, + unsigned int datalen, + uint64_t *numoifs, + PTPObjectFilesystemInfo **oifs +) { + uint64_t numberoifs, i; + unsigned int curoffset; + PTPObjectFilesystemInfo *xoifs; + + if (datalen < 8) + return 0; + numberoifs = dtoh64ap(params,data); + curoffset = 8; + xoifs = calloc(sizeof(PTPObjectFilesystemInfo),numberoifs); + if (!xoifs) + return 0; + + for (i = 0; i < numberoifs; i++) { + uint8_t len,dlen; + char *modify_date; + PTPObjectFilesystemInfo *oif = xoifs+i; + + if (curoffset + 34 + 2 > datalen) + goto tooshort; + + oif->ObjectHandle = dtoh32ap(params,data+curoffset); + oif->StorageID = dtoh32ap(params,data+curoffset+4); + oif->ObjectFormat = dtoh16ap(params,data+curoffset+8); + oif->ProtectionStatus = dtoh16ap(params,data+curoffset+10); + oif->ObjectCompressedSize64 = dtoh64ap(params,data+curoffset+12); + oif->ParentObject = dtoh32ap(params,data+curoffset+20); + oif->AssociationType = dtoh16ap(params,data+curoffset+24); + oif->AssociationDesc = dtoh32ap(params,data+curoffset+26); + oif->SequenceNumber = dtoh32ap(params,data+curoffset+30); + oif->Filename = ptp_unpack_string(params, data, curoffset+34, datalen, &len); + if (curoffset+34+len*2+1 > datalen) + goto tooshort; + modify_date = ptp_unpack_string(params, data, curoffset+len*2+1+34, datalen, &dlen); + oif->ModificationDate = ptp_unpack_PTPTIME(modify_date); + free(modify_date); + curoffset += 34+len*2+dlen*2+2; + } + *numoifs = numberoifs; + *oifs = xoifs; + return 1; +tooshort: + for (i = 0; i < numberoifs; i++) + if (xoifs[i].Filename) free (xoifs[i].Filename); + free (xoifs); + return 0; +} + +static inline void +ptp_unpack_chdk_lv_data_header (PTPParams *params, unsigned char* data, lv_data_header *header) +{ + int off = 0; + if (data==NULL) + return; + header->version_major = dtoh32a(&data[off]); + header->version_minor = dtoh32a(&data[off+=4]); + header->lcd_aspect_ratio = dtoh32a(&data[off+=4]); + header->palette_type = dtoh32a(&data[off+=4]); + header->palette_data_start = dtoh32a(&data[off+=4]); + header->vp_desc_start = dtoh32a(&data[off+=4]); + header->bm_desc_start = dtoh32a(&data[off+=4]); + if (header->version_minor > 1) + header->bmo_desc_start = dtoh32a(&data[off+=4]); +} + +static inline void +ptp_unpack_chdk_lv_framebuffer_desc (PTPParams *params, unsigned char* data, lv_framebuffer_desc *fd) +{ + int off = 0; + if (data==NULL) + return; + fd->fb_type = dtoh32a(&data[off]); + fd->data_start = dtoh32a(&data[off+=4]); + fd->buffer_width = dtoh32a(&data[off+=4]); + fd->visible_width = dtoh32a(&data[off+=4]); + fd->visible_height = dtoh32a(&data[off+=4]); + fd->margin_left = dtoh32a(&data[off+=4]); + fd->margin_top = dtoh32a(&data[off+=4]); + fd->margin_right = dtoh32a(&data[off+=4]); + fd->margin_bot = dtoh32a(&data[off+=4]); +} |