Initial revision
diff --git a/src/ptp-pack.c b/src/ptp-pack.c
new file mode 100644
index 0000000..ce158a4
--- /dev/null
+++ b/src/ptp-pack.c
@@ -0,0 +1,926 @@
+/*
+ * ptp-pack.c
+ *
+ */
+
+#include "ptp.h"
+#include "ptp-pack.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+inline uint16_t
+htod16p (PTPParams *params, uint16_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
+}
+
+inline uint32_t
+htod32p (PTPParams *params, uint32_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
+}
+
+inline void
+htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
+{
+ if (params->byteorder==PTP_DL_LE)
+ htole16a(a,val); else
+ htobe16a(a,val);
+}
+
+inline void
+htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
+{
+ if (params->byteorder==PTP_DL_LE)
+ htole32a(a,val); else
+ htobe32a(a,val);
+}
+
+inline uint16_t
+dtoh16p (PTPParams *params, uint16_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
+}
+
+inline uint32_t
+dtoh32p (PTPParams *params, uint32_t var)
+{
+ return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
+}
+
+inline uint16_t
+dtoh16ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
+}
+
+inline uint32_t
+dtoh32ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
+}
+
+inline uint64_t
+dtoh64ap (PTPParams *params, unsigned char *a)
+{
+ return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
+}
+
+inline char*
+ptp_unpack_string(PTPParams *params, char* data, uint16_t offset, uint8_t *len)
+{
+ int i;
+ char *string=NULL;
+
+ *len=dtoh8a(&data[offset]);
+ if (*len) {
+ string=malloc(*len);
+ memset(string, 0, *len);
+ for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
+ string[i]=(char)dtoh16a(&data[offset+i*2+1]);
+ }
+ /* be paranoid! :( */
+ string[*len-1]=0;
+ }
+ return (string);
+}
+
+inline void
+ptp_pack_string(PTPParams *params, char *string, char* data, uint16_t offset, uint8_t *len)
+{
+ int i;
+ *len = (uint8_t)strlen(string);
+
+ /* XXX: check strlen! */
+ htod8a(&data[offset],*len+1);
+ for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
+ htod16a(&data[offset+i*2+1],(uint16_t)string[i]);
+ }
+}
+
+inline uint32_t
+ptp_unpack_uint32_t_array(PTPParams *params, char* data, uint16_t offset, uint32_t **array)
+{
+ uint32_t n, i=0;
+
+ n=dtoh32a(&data[offset]);
+ *array = malloc (n*sizeof(uint32_t));
+ while (n>i) {
+ (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
+ i++;
+ }
+ return n;
+}
+
+inline uint32_t
+ptp_unpack_uint16_t_array(PTPParams *params, char* data, uint16_t offset, uint16_t **array)
+{
+ uint32_t n, i=0;
+
+ n=dtoh32a(&data[offset]);
+ *array = malloc (n*sizeof(uint16_t));
+ while (n>i) {
+ (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
+ i++;
+ }
+ return n;
+}
+
+/* DeviceInfo pack/unpack */
+
+#define PTP_di_StandardVersion 0
+#define PTP_di_VendorExtensionID 2
+#define PTP_di_VendorExtensionVersion 6
+#define PTP_di_VendorExtensionDesc 8
+#define PTP_di_FunctionalMode 8
+#define PTP_di_OperationsSupported 10
+
+inline void
+ptp_unpack_DI (PTPParams *params, char* data, PTPDeviceInfo *di)
+{
+ uint8_t len;
+ unsigned int totallen;
+
+ di->StaqndardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
+ di->VendorExtensionID =
+ dtoh32a(&data[PTP_di_VendorExtensionID]);
+ di->VendorExtensionVersion =
+ dtoh16a(&data[PTP_di_VendorExtensionVersion]);
+ di->VendorExtensionDesc =
+ ptp_unpack_string(params, data,
+ PTP_di_VendorExtensionDesc, &len);
+ totallen=len*2+1;
+ di->FunctionalMode =
+ dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
+ di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->OperationsSupported);
+ totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->EventsSupported);
+ totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->DevicePropertiesSupported_len =
+ ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->DevicePropertiesSupported);
+ totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->CaptureFormats);
+ totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &di->ImageFormats);
+ totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
+ di->Manufacturer = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->Model = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->DeviceVersion = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+ totallen+=len*2+1;
+ di->SerialNumber = ptp_unpack_string(params, data,
+ PTP_di_OperationsSupported+totallen,
+ &len);
+}
+
+/* ObjectHandles array pack/unpack */
+
+#define PTP_oh 0
+
+inline void
+ptp_unpack_OH (PTPParams *params, char* data, PTPObjectHandles *oh)
+{
+ oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
+}
+
+/* StoreIDs array pack/unpack */
+
+#define PTP_sids 0
+
+inline void
+ptp_unpack_SIDs (PTPParams *params, char* data, PTPStorageIDs *sids)
+{
+ sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
+ &sids->Storage);
+}
+
+/* StorageInfo pack/unpack */
+
+#define PTP_si_StorageType 0
+#define PTP_si_FilesystemType 2
+#define PTP_si_AccessCapability 4
+#define PTP_si_MaxCapability 6
+#define PTP_si_FreeSpaceInBytes 14
+#define PTP_si_FreeSpaceInImages 22
+#define PTP_si_StorageDescription 26
+
+inline void
+ptp_unpack_SI (PTPParams *params, char* data, PTPStorageInfo *si)
+{
+ uint8_t storagedescriptionlen;
+
+ si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
+ si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
+ si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
+ /* next two added by RAL 2005-12-23 */
+ si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
+ si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
+ si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
+ si->StorageDescription=ptp_unpack_string(params, data,
+ PTP_si_StorageDescription, &storagedescriptionlen);
+ si->VolumeLabel=ptp_unpack_string(params, data,
+ PTP_si_StorageDescription+storagedescriptionlen*2+1,
+ &storagedescriptionlen);
+}
+
+/* ObjectInfo pack/unpack */
+
+#define PTP_oi_StorageID 0
+#define PTP_oi_ObjectFormat 4
+#define PTP_oi_ProtectionStatus 6
+#define PTP_oi_ObjectCompressedSize 8
+#define PTP_oi_ThumbFormat 12
+#define PTP_oi_ThumbCompressedSize 14
+#define PTP_oi_ThumbPixWidth 18
+#define PTP_oi_ThumbPixHeight 22
+#define PTP_oi_ImagePixWidth 26
+#define PTP_oi_ImagePixHeight 30
+#define PTP_oi_ImageBitDepth 34
+#define PTP_oi_ParentObject 38
+#define PTP_oi_AssociationType 42
+#define PTP_oi_AssociationDesc 44
+#define PTP_oi_SequenceNumber 48
+#define PTP_oi_filenamelen 52
+#define PTP_oi_Filename 53
+
+inline uint32_t
+ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, char** oidataptr)
+{
+ char* oidata;
+ uint8_t filenamelen;
+ uint8_t capturedatelen=0;
+ /* let's allocate some memory first; XXX i'm sure it's wrong */
+ oidata=malloc(PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4);
+ /* the caller should free it after use! */
+#if 0
+ char *capture_date="20020101T010101"; /* XXX Fake date */
+#endif
+ memset (oidata, 0, (PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4));
+ htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
+ htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
+ htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
+ htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
+ htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
+ htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
+ htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
+ htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
+ htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
+ htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
+ htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
+ htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
+ htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
+ htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
+ htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
+
+ ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
+/*
+ filenamelen=(uint8_t)strlen(oi->Filename);
+ htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
+ for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
+ req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
+ }
+*/
+ /*
+ *XXX Fake date.
+ * for example Kodak sets Capture date on the basis of EXIF data.
+ * Spec says that this field is from perspective of Initiator.
+ */
+#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
+ capturedatelen=strlen(capture_date);
+ htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
+ capturedatelen+1);
+ for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
+ data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
+ }
+ htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
+ capturedatelen+1);
+ for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
+ data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
+ capture_date[i];
+ }
+#endif
+ /* XXX this function should return dataset length */
+
+ *oidataptr=oidata;
+ return (PTP_oi_Filename+(filenamelen+1)*2+(capturedatelen+1)*4);
+}
+
+inline void
+ptp_unpack_OI (PTPParams *params, char* data, PTPObjectInfo *oi)
+{
+ uint8_t filenamelen;
+ uint8_t capturedatelen;
+ char *capture_date;
+ char tmp[16];
+ struct tm tm;
+
+ memset(&tm,0,sizeof(tm));
+
+ oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
+ oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
+ oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
+ oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
+ oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
+ oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
+ oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
+ oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
+ oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
+ oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
+ oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
+ oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
+ oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
+ 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);
+
+ capture_date = ptp_unpack_string(params, data,
+ PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
+ /* subset of ISO 8601, without '.s' tenths of second and
+ * time zone
+ */
+ if (capturedatelen>15)
+ {
+ strncpy (tmp, capture_date, 4);
+ tmp[4] = 0;
+ tm.tm_year=atoi (tmp) - 1900;
+ strncpy (tmp, capture_date + 4, 2);
+ tmp[2] = 0;
+ tm.tm_mon = atoi (tmp) - 1;
+ strncpy (tmp, capture_date + 6, 2);
+ tmp[2] = 0;
+ tm.tm_mday = atoi (tmp);
+ strncpy (tmp, capture_date + 9, 2);
+ tmp[2] = 0;
+ tm.tm_hour = atoi (tmp);
+ strncpy (tmp, capture_date + 11, 2);
+ tmp[2] = 0;
+ tm.tm_min = atoi (tmp);
+ strncpy (tmp, capture_date + 13, 2);
+ tmp[2] = 0;
+ tm.tm_sec = atoi (tmp);
+ oi->CaptureDate=mktime (&tm);
+ }
+ free(capture_date);
+
+ /* now it's modification date ;) */
+ capture_date = ptp_unpack_string(params, data,
+ PTP_oi_filenamelen+filenamelen*2
+ +capturedatelen*2+2,&capturedatelen);
+ if (capturedatelen>15)
+ {
+ strncpy (tmp, capture_date, 4);
+ tmp[4] = 0;
+ tm.tm_year=atoi (tmp) - 1900;
+ strncpy (tmp, capture_date + 4, 2);
+ tmp[2] = 0;
+ tm.tm_mon = atoi (tmp) - 1;
+ strncpy (tmp, capture_date + 6, 2);
+ tmp[2] = 0;
+ tm.tm_mday = atoi (tmp);
+ strncpy (tmp, capture_date + 9, 2);
+ tmp[2] = 0;
+ tm.tm_hour = atoi (tmp);
+ strncpy (tmp, capture_date + 11, 2);
+ tmp[2] = 0;
+ tm.tm_min = atoi (tmp);
+ strncpy (tmp, capture_date + 13, 2);
+ tmp[2] = 0;
+ tm.tm_sec = atoi (tmp);
+ oi->ModificationDate=mktime (&tm);
+ }
+ free(capture_date);
+}
+
+/* Custom Type Value Assignement (without Length) macro frequently used below */
+#define CTVAL(type,func,target) { \
+ *target = malloc(sizeof(type)); \
+ **(type **)target = \
+ func(data);\
+}
+
+/* modified by RAL 2005-12-26 to return value size */
+uint32_t
+ptp_unpack_DPV (PTPParams *params, char* data, void** value, uint16_t datatype)
+{
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_INT8:
+ CTVAL(int8_t,dtoh8a,value);
+ return sizeof(int8_t);
+ break;
+ case PTP_DTC_UINT8:
+ CTVAL(uint8_t,dtoh8a,value);
+ return sizeof(uint8_t);
+ break;
+ case PTP_DTC_INT16:
+ CTVAL(int16_t,dtoh16a,value);
+ return sizeof(int16_t);
+ break;
+ case PTP_DTC_UINT16:
+ CTVAL(uint16_t,dtoh16a,value);
+ return sizeof(uint16_t);
+ break;
+ case PTP_DTC_INT32:
+ CTVAL(int32_t,dtoh32a,value);
+ return sizeof(int32_t);
+ break;
+ case PTP_DTC_UINT32:
+ CTVAL(uint32_t,dtoh32a,value);
+ return sizeof(uint32_t);
+ break;
+ case PTP_DTC_UINT64:
+ CTVAL(uint64_t,dtoh64a,value);
+ return sizeof(uint64_t);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ case PTP_DTC_STR:
+ {
+ uint8_t len;
+ (char *)(*value)=ptp_unpack_string(params,data,0,&len);
+ return 2*len+1;
+ break;
+ }
+ case PTP_DTC_UNISTR:
+ {
+ /* this length includes the null character */
+ uint8_t len=dtoh8a(&data[0]);
+ if (len==0)
+ {
+ *value=malloc(2);
+ ((uint16_t *)*value)[0]=0;
+ }
+ else
+ {
+ *value=malloc(len*2);
+ for (i=0;i<len;i++)
+ {
+ ((uint16_t *)*value)[i]=dtoh16a(&data[i*2+1]);
+ }
+ /* just to be sure... */
+ ((uint16_t *)*value)[len-1]=0;
+ }
+
+ return 2*len+1;
+
+ break;
+ }
+ default:
+ printf("data type 0x%.04x not supported by ptp_unpack_DPV\n", datatype);
+ return 0;
+ }
+}
+
+
+/* Device Property pack/unpack */
+
+#define PTP_dpd_DevicePropertyCode 0
+#define PTP_dpd_DataType 2
+#define PTP_dpd_GetSet 4
+#define PTP_dpd_FactoryDefaultValue 5
+
+/* Custom Type Value Assignement macro frequently used below */
+#define CTVA(type,func,target) { \
+ target = malloc(sizeof(type)); \
+ *(type *)target = \
+ func(&data[PTP_dpd_FactoryDefaultValue+totallen]);\
+ totallen+=sizeof(type); \
+}
+
+/* Many Custom Types Vale Assignement macro frequently used below */
+
+#define MCTVA(type,func,target,n) { \
+ uint16_t i; \
+ for (i=0;i<n;i++) { \
+ target[i] = malloc(sizeof(type)); \
+ *(type *)target[i] = \
+ func(&data[PTP_dpd_FactoryDefaultValue+totallen]);\
+ totallen+=sizeof(type); \
+ } \
+}
+
+inline void
+ptp_unpack_DPD (PTPParams *params, char* data, PTPDevicePropDesc *dpd)
+{
+ uint8_t len;
+ int totallen=0;
+
+ dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
+ dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
+ dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
+ dpd->FactoryDefaultValue = NULL;
+ dpd->CurrentValue = NULL;
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ CTVA(int8_t,dtoh8a,dpd->FactoryDefaultValue);
+ CTVA(int8_t,dtoh8a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT8:
+ CTVA(uint8_t,dtoh8a,dpd->FactoryDefaultValue);
+ CTVA(uint8_t,dtoh8a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_INT16:
+ CTVA(int16_t,dtoh16a,dpd->FactoryDefaultValue);
+ CTVA(int16_t,dtoh16a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT16:
+ CTVA(uint16_t,dtoh16a,dpd->FactoryDefaultValue);
+ CTVA(uint16_t,dtoh16a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_INT32:
+ CTVA(int32_t,dtoh32a,dpd->FactoryDefaultValue);
+ CTVA(int32_t,dtoh32a,dpd->CurrentValue);
+ break;
+ case PTP_DTC_UINT32:
+ CTVA(uint32_t,dtoh32a,dpd->FactoryDefaultValue);
+ CTVA(uint32_t,dtoh32a,dpd->CurrentValue);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ case PTP_DTC_STR:
+ (char *)dpd->FactoryDefaultValue = ptp_unpack_string
+ (params,data,PTP_dpd_FactoryDefaultValue,&len);
+ totallen=len*2+1;
+ (char *)dpd->CurrentValue = ptp_unpack_string
+ (params, data, PTP_dpd_FactoryDefaultValue +
+ totallen, &len);
+ totallen+=len*2+1;
+ break;
+ }
+ /* if totallen==0 then Data Type format is not supported by this
+ code or the Data Type is a string (with two empty strings as
+ values). In both cases Form Flag should be set to 0x00 and FORM is
+ not present. */
+ dpd->FormFlag=PTP_DPFF_None;
+ if (totallen==0) return;
+
+ dpd->FormFlag=dtoh8a(&data[PTP_dpd_FactoryDefaultValue+totallen]);
+ totallen+=sizeof(uint8_t);
+ switch (dpd->FormFlag) {
+ case PTP_DPFF_Range:
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.MinimumValue);
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.MaximumValue);
+ CTVA(int8_t,dtoh8a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT8:
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint8_t,dtoh8a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_INT16:
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.MinimumValue);
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.MaximumValue);
+ CTVA(int16_t,dtoh16a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT16:
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint16_t,dtoh16a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_INT32:
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.MinimumValue);
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.MaximumValue);
+ CTVA(int32_t,dtoh32a,dpd->FORM.Range.StepSize);
+ break;
+ case PTP_DTC_UINT32:
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MinimumValue);
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.MaximumValue);
+ CTVA(uint32_t,dtoh32a,dpd->FORM.Range.StepSize);
+ break;
+ /* XXX: other int types are unimplemented */
+ /* XXX: int arrays are unimplemented also */
+ /* XXX: does it make any sense: "a range of strings"? */
+ }
+ break;
+ case PTP_DPFF_Enumeration:
+#define N dpd->FORM.Enum.NumberOfValues
+ N = dtoh16a(&data[PTP_dpd_FactoryDefaultValue+totallen]);
+ totallen+=sizeof(uint16_t);
+ dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(void *));
+ switch (dpd->DataType) {
+ case PTP_DTC_INT8:
+ MCTVA(int8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT8:
+ MCTVA(uint8_t,dtoh8a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_INT16:
+ MCTVA(int16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT16:
+ MCTVA(uint16_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_INT32:
+ MCTVA(int32_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_UINT32:
+ MCTVA(uint32_t,dtoh16a,dpd->FORM.Enum.SupportedValue,N);
+ break;
+ case PTP_DTC_STR:
+ {
+ int i;
+ for(i=0;i<N;i++)
+ {
+ (char *)dpd->FORM.Enum.SupportedValue[i]=
+ ptp_unpack_string
+ (params,data,PTP_dpd_FactoryDefaultValue
+ +totallen,&len);
+ totallen+=len*2+1;
+ }
+ }
+ break;
+ }
+ }
+}
+
+#define PACK_ARRAY(type,func) { \
+ size=sizeof(uint32_t)+sizeof(type)*arraylen; \
+ dpv=malloc(size); \
+ htod32a(dpv,arraylen); \
+ for (i=0; i<arraylen; i++) \
+ func(&(dpv[sizeof(uint32_t)+i*sizeof(type)]),((type*)value)[i]); \
+ }
+
+inline uint32_t
+ptp_pack_array (PTPParams *params, void* value, char** dpvptr, uint16_t datatype, uint32_t arraylen)
+{
+ char* dpv=NULL;
+ uint32_t size=0;
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_AINT8:
+ PACK_ARRAY(int8_t,htod8a);
+ break;
+ case PTP_DTC_AUINT8:
+ PACK_ARRAY(uint8_t,htod8a);
+ break;
+ case PTP_DTC_AINT16:
+ PACK_ARRAY(int16_t,htod16a);
+ break;
+ case PTP_DTC_AUINT16:
+ PACK_ARRAY(uint16_t,htod16a);
+ break;
+ case PTP_DTC_AINT32:
+ PACK_ARRAY(int32_t,htod32a);
+ break;
+ case PTP_DTC_AUINT32:
+ PACK_ARRAY(uint32_t,htod32a);
+ break;
+ /*case PTP_DTC_AINT64:
+ PACK_ARRAY(int64_t,htod64a);
+ break;
+ case PTP_DTC_AUINT64:
+ PACK_ARRAY(uint64_t,htod64a);
+ break;
+ case PTP_DTC_AINT128:
+ PACK_ARRAY(int128_t,htod128a);
+ break;
+ case PTP_DTC_AUINT128:
+ PACK_ARRAY(uint128_t,htod128a);
+ break;*/
+ default:
+ printf("data type 0x%.04x not supported by ptp_pack_array\n", datatype);
+ return 0;
+ }
+ *dpvptr=dpv;
+ return size;
+}
+
+#define UNPACK_ARRAY(type,func) { \
+ int i=0; \
+ *arraylen=dtoh32a(&data[0]); \
+ *value=malloc(sizeof(type)*(*arraylen)); \
+ for (i=0; i<*arraylen; i++) \
+ ((type*)(*value))[i]=func(&data[sizeof(uint32_t)+i*sizeof(type)]); \
+ return *arraylen*sizeof(type); \
+ }
+
+inline uint32_t
+ptp_unpack_array (PTPParams *params, char* data, void** value, uint16_t datatype, uint32_t* arraylen)
+{
+ switch (datatype) {
+ case PTP_DTC_AINT8:
+ UNPACK_ARRAY(int8_t,dtoh8a);
+ break;
+ case PTP_DTC_AUINT8:
+ UNPACK_ARRAY(uint8_t,dtoh8a);
+ break;
+ case PTP_DTC_AINT16:
+ UNPACK_ARRAY(int16_t,dtoh16a);
+ break;
+ case PTP_DTC_AUINT16:
+ UNPACK_ARRAY(uint16_t,dtoh16a);
+ break;
+ case PTP_DTC_AINT32:
+ UNPACK_ARRAY(int32_t,dtoh32a);
+ break;
+ case PTP_DTC_AUINT32:
+ UNPACK_ARRAY(uint32_t,dtoh32a);
+ break;
+ case PTP_DTC_AINT64:
+ UNPACK_ARRAY(int64_t,dtoh64a);
+ break;
+ case PTP_DTC_AUINT64:
+ UNPACK_ARRAY(uint64_t,dtoh64a);
+ break;
+ /*case PTP_DTC_AINT128:
+ UNPACK_ARRAY(int128_t,dtoh128a);
+ break;
+ case PTP_DTC_AUINT128:
+ UNPACK_ARRAY(uint128_t,dtoh128a);
+ break;*/
+ default:
+ printf("data type 0x%.04x not supported by ptp_unpack_array\n", datatype);
+ return 0;
+ }
+}
+
+inline uint32_t
+ptp_pack_DPV (PTPParams *params, void* value, char** dpvptr, uint16_t datatype)
+{
+ char* dpv=NULL;
+ uint32_t size=0;
+ int i=0;
+
+ switch (datatype) {
+ case PTP_DTC_INT8:
+ size=sizeof(int8_t);
+ dpv=malloc(size);
+ htod8a(dpv,*(int8_t*)value);
+ break;
+ case PTP_DTC_UINT8:
+ size=sizeof(uint8_t);
+ dpv=malloc(size);
+ htod8a(dpv,*(uint8_t*)value);
+ break;
+ case PTP_DTC_INT16:
+ size=sizeof(int16_t);
+ dpv=malloc(size);
+ htod16a(dpv,*(int16_t*)value);
+ break;
+ case PTP_DTC_UINT16:
+ size=sizeof(uint16_t);
+ dpv=malloc(size);
+ htod16a(dpv,*(uint16_t*)value);
+ break;
+ case PTP_DTC_INT32:
+ size=sizeof(int32_t);
+ dpv=malloc(size);
+ htod32a(dpv,*(int32_t*)value);
+ break;
+ case PTP_DTC_UINT32:
+ size=sizeof(uint32_t);
+ dpv=malloc(size);
+ htod32a(dpv,*(uint32_t*)value);
+ break;
+ /*case PTP_DTC_INT64:
+ size=sizeof(int64_t);
+ dpv=malloc(size);
+ htod64a(dpv,*(int64_t*)value);
+ break;
+ case PTP_DTC_UINT64:
+ size=sizeof(uint64_t);
+ dpv=malloc(size);
+ htod64a(dpv,*(uint64_t*)value);
+ break;
+ case PTP_DTC_INT128:
+ size=sizeof(int128_t);
+ dpv=malloc(size);
+ htod128a(dpv,*(int128_t*)value);
+ break;
+ case PTP_DTC_UINT128:
+ size=sizeof(uint128_t);
+ dpv=malloc(size);
+ htod128a(dpv,*(uint128_t*)value);
+ break;*/
+ case PTP_DTC_STR:
+ {
+ uint8_t len;
+ size=strlen((char*)value)*2+3;
+ dpv=malloc(size);
+ memset(dpv,0,size);
+ ptp_pack_string(params, (char *)value, dpv, 0, &len);
+ }
+ break;
+ case PTP_DTC_UNISTR:
+ {
+ uint8_t len = 0;
+ /* note PTP_MAXSTRLEN includes the null terminator */
+ while (((uint16_t *)value)[len] != 0 && len != PTP_MAXSTRLEN-1)
+ len++;
+ if (len==0)
+ {
+ size=1;
+ dpv=malloc(size);
+ *dpv=0;
+ }
+ else
+ {
+ /* 2 extra bytes for the terminator, 1 for the length at the beginning */
+ size=len*2+3;
+ dpv=malloc(size);
+ memset(dpv,0,size);
+ htod8a(&dpv[0],len+1);
+ for (i = 0; i < len; i++)
+ htod16a(&dpv[i*2+1],((uint16_t *)value)[i]);
+ /* terminator is done by memset above */
+ /*for (i = 0; i < size; i++)
+ printf("dpv[%d] = %d, ", i, dpv[i]);
+ printf("\n");*/
+ }
+ break;
+ }
+ default:
+ printf("data type 0x%.04x not supported by ptp_pack_DPV\n", datatype);
+ return 0;
+ }
+ *dpvptr=dpv;
+ return size;
+}
+
+
+/*
+ PTP USB Event container unpack
+ Copyright (c) 2003 Nikolai Kopanygin
+*/
+
+#define PTP_ec_Length 0
+#define PTP_ec_Type 4
+#define PTP_ec_Code 6
+#define PTP_ec_TransId 8
+#define PTP_ec_Param1 12
+#define PTP_ec_Param2 16
+#define PTP_ec_Param3 20
+
+inline void
+ptp_unpack_EC (PTPParams *params, char* data, PTPUSBEventContainer *ec)
+{
+ if (data==NULL)
+ return;
+ ec->length=dtoh32a(&data[PTP_ec_Length]);
+ ec->type=dtoh16a(&data[PTP_ec_Type]);
+ ec->code=dtoh16a(&data[PTP_ec_Code]);
+ ec->trans_id=dtoh32a(&data[PTP_ec_TransId]);
+ if (ec->length>=(PTP_ec_Param1+4))
+ ec->param1=dtoh32a(&data[PTP_ec_Param1]);
+ else
+ ec->param1=0;
+ if (ec->length>=(PTP_ec_Param2+4))
+ ec->param2=dtoh32a(&data[PTP_ec_Param2]);
+ else
+ ec->param2=0;
+ if (ec->length>=(PTP_ec_Param3+4))
+ ec->param3=dtoh32a(&data[PTP_ec_Param3]);
+ else
+ ec->param3=0;
+}
+
+/*
+ PTP Canon Folder Entry unpack
+ Copyright (c) 2003 Nikolai Kopanygin
+*/
+#define PTP_cfe_ObjectHandle 0
+#define PTP_cfe_ObjectFormatCode 4
+#define PTP_cfe_Flags 6
+#define PTP_cfe_ObjectSize 7
+#define PTP_cfe_Time 11
+#define PTP_cfe_Filename 15
+
+inline void
+ptp_unpack_Canon_FE (PTPParams *params, char* data, PTPCANONFolderEntry *fe)
+{
+ int i;
+ if (data==NULL)
+ return;
+ fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
+ fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
+ fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
+ fe->ObjectSize=dtoh32a(&data[PTP_cfe_ObjectSize]);
+ fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
+ for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
+ fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
+}
+
+