Logo Search packages:      
Sourcecode: libgphoto2 version File versions  Download package

ptp-pack.c

/* currently this file is included into ptp.c */

#include <iconv.h>

static inline uint16_t
htod16p (PTPParams *params, uint16_t var)
{
      return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
}

static inline uint32_t
htod32p (PTPParams *params, uint32_t var)
{
      return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
}

static inline void
htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
{
      if (params->byteorder==PTP_DL_LE)
            htole16a(a,val);
      else 
            htobe16a(a,val);
}

static inline void
htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
{
      if (params->byteorder==PTP_DL_LE)
            htole32a(a,val);
      else 
            htobe32a(a,val);
}

static inline uint16_t
dtoh16p (PTPParams *params, uint16_t var)
{
      return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
}

static inline uint32_t
dtoh32p (PTPParams *params, uint32_t var)
{
      return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
}

static inline uint16_t
dtoh16ap (PTPParams *params, unsigned char *a)
{
      return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
}

static inline uint32_t
dtoh32ap (PTPParams *params, unsigned char *a)
{
      return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
}

static inline uint64_t
dtoh64ap (PTPParams *params, unsigned char *a)
{
      uint64_t tmp = 0;
      int i;

      if (params->byteorder==PTP_DL_LE) {
            for (i=0;i<8;i++)
                  tmp |= (((uint64_t)a[i]) << (8*i));
      } else {
            for (i=0;i<8;i++)
                  tmp |= (((uint64_t)a[i]) << (8*(7-i)));
      }
      return tmp;
}

#define htod8a(a,x)     *(uint8_t*)(a) = x
#define htod16a(a,x)    htod16ap(params,a,x)
#define htod32a(a,x)    htod32ap(params,a,x)
#define htod16(x) htod16p(params,x)
#define htod32(x) htod32p(params,x)

#define dtoh8a(x) (*(uint8_t*)(x))
#define dtoh16a(a)      dtoh16ap(params,a)
#define dtoh32a(a)      dtoh32ap(params,a)
#define dtoh64a(a)      dtoh64ap(params,a)
#define dtoh16(x) dtoh16p(params,x)
#define dtoh32(x) dtoh32p(params,x)


static inline char*
ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
{
      uint8_t length;
      uint16_t string[PTP_MAXSTRLEN+1];
      /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
      char loclstr[PTP_MAXSTRLEN*3+1]; 
      size_t nconv, srclen, destlen;
      char *src, *dest;

      length = dtoh8a(&data[offset]);     /* PTP_MAXSTRLEN == 255, 8 bit len */
      *len = length;
      if (length == 0)        /* nothing to do? */
            return(NULL);

      /* 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. */
      loclstr[0] = '\0';
    
      /* convert from camera UCS-2 to our locale */
      src = (char *)string;
      srclen = length * sizeof(string[0]);
      dest = loclstr;
      destlen = sizeof(loclstr)-1;
      nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, 
                  &dest, &destlen);
      if (nconv == (size_t) -1) { /* do it the hard way */
            int i;
            /* try the old way, in case iconv is broken */
            for (i=0;i<length;i++) {
                  if (dtoh16a(&data[offset+1+2*i])>127)
                        loclstr[i] = '?';
                  else
                        loclstr[i] = dtoh16a(&data[offset+1+2*i]);
            }
            dest = loclstr+length;
      }
      *dest = '\0';
      loclstr[sizeof(loclstr)-1] = '\0';   /* be safe? */
      return(strdup(loclstr));
}

static inline int
ucs2strlen(uint16_t const * const unicstr)
{
      int length;
      
      /* Unicode strings are terminated with 2 * 0x00 */
      for(length = 0; unicstr[length] != 0x0000U; length ++);
      return length;
}


static inline void
ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
{
      int packedlen;
      uint16_t ucs2str[PTP_MAXSTRLEN+1];
      char *ucs2strp = (char *) ucs2str;
      char *stringp = string;
      size_t nconv;
      size_t convlen = strlen(string);
      size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */

      /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
      memset(ucs2strp, 0, sizeof(ucs2str));  /* XXX: necessary? */
      nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
            &ucs2strp, &convmax);
      if (nconv == (size_t) -1)
            ucs2str[0] = 0x0000U;
      /*
       * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
       *      why do we need ucs2strlen()?
       */
      packedlen = ucs2strlen(ucs2str);
      if (packedlen > PTP_MAXSTRLEN-1) {
            *len=0;
            return;
      }
      
      /* number of characters including terminating 0 (PTP standard confirmed) */
      htod8a(&data[offset],packedlen+1);
      memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
      htod16a(&data[offset+packedlen*2+1], 0x0000);  /* terminate 0 */

      /* The returned length is in number of characters */
      *len = (uint8_t) packedlen+1;
}

static inline unsigned char *
ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
{
      uint8_t packed[PTP_MAXSTRLEN*2+3], len;
      size_t plen;
      unsigned char *retcopy = NULL;

      ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
      /* returned length is in characters, then one byte for string length */
      plen = len*2 + 1;
      
      retcopy = malloc(plen);
      if (!retcopy) {
            *packed_size = 0;
            return NULL;
      }
      memcpy(retcopy, packed, plen);
      *packed_size = plen;
      return (retcopy);
}

static inline uint32_t
ptp_unpack_uint32_t_array(PTPParams *params, unsigned 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;
}

static inline uint32_t
ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
{
      uint32_t i=0;

      *data = malloc ((arraylen+1)*sizeof(uint32_t));
      htod32a(&(*data)[0],arraylen);
      for (i=0;i<arraylen;i++)
            htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
      return (arraylen+1)*sizeof(uint32_t);
}

static inline uint32_t
ptp_unpack_uint16_t_array(PTPParams *params, unsigned 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

static inline void
ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
{
      uint8_t len;
      unsigned int totallen;
      
      di->StandardVersion = 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);
}

static void
ptp_free_DI (PTPDeviceInfo *di) {
      if (di->SerialNumber) free (di->SerialNumber);
      if (di->DeviceVersion) free (di->DeviceVersion);
      if (di->Model) free (di->Model);
      if (di->Manufacturer) free (di->Manufacturer);
      if (di->ImageFormats) free (di->ImageFormats);
      if (di->CaptureFormats) free (di->CaptureFormats);
      if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
      if (di->OperationsSupported) free (di->OperationsSupported);
      if (di->EventsSupported) free (di->EventsSupported);
      if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
}
      
/* ObjectHandles array pack/unpack */

#define PTP_oh                       0

static inline void
ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
{
      if (len) {
            oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
      } else {
            oh->n = 0;
            oh->Handler = NULL;
      } 
}

/* StoreIDs array pack/unpack */

#define PTP_sids               0

static inline void
ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
{
      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

static inline void
ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
{
      uint8_t storagedescriptionlen;

      si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
      si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
      si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
      si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
      si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
      si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
      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

/* the max length assuming zero length dates. We have need 3 */
/* bytes for these. */
#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3

static inline uint32_t
ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
{
      unsigned char* oidata;
      uint8_t filenamelen;
      uint8_t capturedatelen=0;
      /* let's allocate some memory first; correct assuming zero length dates */
      oidata=malloc(PTP_oi_MaxLen);
      /* the caller should free it after use! */
#if 0
      char *capture_date="20020101T010101"; /* XXX Fake date */
#endif
      memset (oidata, 0, PTP_oi_MaxLen);
      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*2+(capturedatelen+1)*3);
}

static inline void
ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
{
      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(target,func) {              \
      if (total - *offset < sizeof(target))     \
            return 0;               \
      target = func(&data[*offset]);            \
      *offset += sizeof(target);          \
}

#define RARR(val,member,func) {                 \
      int n,j;                            \
      if (total - *offset < sizeof(uint32_t))         \
            return 0;                     \
      n = dtoh32a (&data[*offset]);             \
      *offset += sizeof(uint32_t);              \
                                          \
      val->a.count = n;                   \
      val->a.v = malloc(sizeof(val->a.v[0])*n); \
      if (!val->a.v) return 0;                  \
      for (j=0;j<n;j++)                   \
            CTVAL(val->a.v[j].member, func);    \
}

static inline int
ptp_unpack_DPV (
      PTPParams *params, unsigned char* data, int *offset, int total,
      PTPPropertyValue* value, uint16_t datatype
) {
      switch (datatype) {
      case PTP_DTC_INT8:
            CTVAL(value->i8,dtoh8a);
            break;
      case PTP_DTC_UINT8:
            CTVAL(value->u8,dtoh8a);
            break;
      case PTP_DTC_INT16:
            CTVAL(value->i16,dtoh16a);
            break;
      case PTP_DTC_UINT16:
            CTVAL(value->u16,dtoh16a);
            break;
      case PTP_DTC_INT32:
            CTVAL(value->i32,dtoh32a);
            break;
      case PTP_DTC_UINT32:
            CTVAL(value->u32,dtoh32a);
            break;



      case PTP_DTC_UINT64:
            *offset += 8;
            /*fprintf(stderr,"unhandled unpack of uint64\n");*/
            break;
      case PTP_DTC_INT64:
            *offset += 8;
            /*fprintf(stderr,"unhandled unpack of int64\n");*/
            break;
      case PTP_DTC_UINT128:
            *offset += 16;
            /*fprintf(stderr,"unhandled unpack of uint128n");*/
            break;
      case PTP_DTC_INT128:
            *offset += 16;
            /*fprintf(stderr,"unhandled unpack of int128n");*/
            break;



      case PTP_DTC_AINT8:
            RARR(value,i8,dtoh8a);
            break;
      case PTP_DTC_AUINT8:
            RARR(value,u8,dtoh8a);
            break;
      case PTP_DTC_AUINT16:
            RARR(value,u16,dtoh16a);
            break;
      case PTP_DTC_AINT16:
            RARR(value,i16,dtoh16a);
            break;
      case PTP_DTC_AUINT32:
            RARR(value,u32,dtoh32a);
            break;
      case PTP_DTC_AINT32:
            RARR(value,i32,dtoh32a);
            break;
      /* XXX: other int types are unimplemented */
      /* XXX: other int arrays are unimplemented also */
      case PTP_DTC_STR: {
            uint8_t len;
            /* XXX: max size */
            value->str = ptp_unpack_string(params,data,*offset,&len);
            *offset += len*2+1;
            if (!value->str)
                  return 0;
            break;
      }
      default:
            return 0;
      }
      return 1;
}

/* Device Property pack/unpack */

#define PTP_dpd_DevicePropertyCode  0
#define PTP_dpd_DataType            2
#define PTP_dpd_GetSet              4
#define PTP_dpd_FactoryDefaultValue 5

static inline int
ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
{
      int offset=0, ret;

      memset (dpd, 0, sizeof(*dpd));
      dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
      dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
      dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);

      offset = PTP_dpd_FactoryDefaultValue;
      ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
      if (!ret) goto outofmemory;
      ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
      if (!ret) goto outofmemory;

      /* if offset==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 (offset==PTP_dpd_FactoryDefaultValue)
            return 1;

      dpd->FormFlag=dtoh8a(&data[offset]);
      offset+=sizeof(uint8_t);

      switch (dpd->FormFlag) {
      case PTP_DPFF_Range:
            ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
            if (!ret) goto outofmemory;
            ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
            if (!ret) goto outofmemory;
            ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
            if (!ret) goto outofmemory;
            break;
      case PTP_DPFF_Enumeration: {
            int i;
#define N   dpd->FORM.Enum.NumberOfValues
            N = dtoh16a(&data[offset]);
            offset+=sizeof(uint16_t);
            dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
            if (!dpd->FORM.Enum.SupportedValue)
                  goto outofmemory;

            memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
            for (i=0;i<N;i++) {
                  ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);

                  /* Slightly different handling here. The HP PhotoSmart 120
                   * specifies an enumeration with N in wrong endian
                   * 00 01 instead of 01 00, so we count the enum just until the
                   * the end of the packet.
                   */
                  if (!ret) {
                        if (!i)
                              goto outofmemory;
                        dpd->FORM.Enum.NumberOfValues = i;
                        break;
                  }
            }
            }
      }
#undef N
      return 1;
outofmemory:
      ptp_free_devicepropdesc(dpd);
      return 0;
}

/* (MTP) Object Property pack/unpack */
#define PTP_opd_ObjectPropertyCode  0
#define PTP_opd_DataType            2
#define PTP_opd_GetSet              4
#define PTP_opd_FactoryDefaultValue 5

static inline int
ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
{
      int offset=0, ret;

      memset (opd, 0, sizeof(*opd));
      opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
      opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
      opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);

      offset = PTP_opd_FactoryDefaultValue;
      ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
      if (!ret) goto outofmemory;

      opd->GroupCode=dtoh32a(&data[offset]);
      offset+=sizeof(uint32_t);

      opd->FormFlag=dtoh8a(&data[offset]);
      offset+=sizeof(uint8_t);

      switch (opd->FormFlag) {
      case PTP_OPFF_Range:
            ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
            if (!ret) goto outofmemory;
            ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
            if (!ret) goto outofmemory;
            ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
            if (!ret) goto outofmemory;
            break;
      case PTP_OPFF_Enumeration: {
            int i;
#define N   opd->FORM.Enum.NumberOfValues
            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;

            memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
            for (i=0;i<N;i++) {
                  ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);

                  /* Slightly different handling here. The HP PhotoSmart 120
                   * specifies an enumeration with N in wrong endian
                   * 00 01 instead of 01 00, so we count the enum just until the
                   * the end of the packet.
                   */
                  if (!ret) {
                        if (!i)
                              goto outofmemory;
                        opd->FORM.Enum.NumberOfValues = i;
                        break;
                  }
            }
#undef N
            }
      }
      return 1;
outofmemory:
      ptp_free_objectpropdesc(opd);
      return 0;
}


static inline uint32_t
ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
{
      unsigned char* dpv=NULL;
      uint32_t size=0;
      int   i;

      switch (datatype) {
      case PTP_DTC_INT8:
            size=sizeof(int8_t);
            dpv=malloc(size);
            htod8a(dpv,value->i8);
            break;
      case PTP_DTC_UINT8:
            size=sizeof(uint8_t);
            dpv=malloc(size);
            htod8a(dpv,value->u8);
            break;
      case PTP_DTC_INT16:
            size=sizeof(int16_t);
            dpv=malloc(size);
            htod16a(dpv,value->i16);
            break;
      case PTP_DTC_UINT16:
            size=sizeof(uint16_t);
            dpv=malloc(size);
            htod16a(dpv,value->u16);
            break;
      case PTP_DTC_INT32:
            size=sizeof(int32_t);
            dpv=malloc(size);
            htod32a(dpv,value->i32);
            break;
      case PTP_DTC_UINT32:
            size=sizeof(uint32_t);
            dpv=malloc(size);
            htod32a(dpv,value->u32);
            break;
      case PTP_DTC_AUINT8:
            size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod8a(&dpv[4+i],value->a.v[i].u8);
            break;
      case PTP_DTC_AINT8:
            size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod8a(&dpv[4+i],value->a.v[i].i8);
            break;
      case PTP_DTC_AUINT16:
            size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod16a(&dpv[4+i],value->a.v[i].u16);
            break;
      case PTP_DTC_AINT16:
            size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod16a(&dpv[4+i],value->a.v[i].i16);
            break;
      case PTP_DTC_AUINT32:
            size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod32a(&dpv[4+i],value->a.v[i].u32);
            break;
      case PTP_DTC_AINT32:
            size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
            dpv=malloc(size);
            htod32a(dpv,value->a.count);
            for (i=0;i<value->a.count;i++)
                  htod32a(&dpv[4+i],value->a.v[i].i32);
            break;
      /* XXX: other int types are unimplemented */
      case PTP_DTC_STR: {
            dpv=ptp_get_packed_stringcopy(params, value->str, &size);
            break;
      }
      }
      *dpvptr=dpv;
      return size;
}

#define MAX_MTP_PROPS 127
static inline uint32_t
ptp_pack_OPL (PTPParams *params, MTPPropList *proplist, unsigned char** opldataptr)
{
      unsigned char* opldata;
      MTPPropList *propitr;
      unsigned char *packedprops[MAX_MTP_PROPS];
      uint32_t packedpropslens[MAX_MTP_PROPS];
      uint32_t packedobjecthandles[MAX_MTP_PROPS];
      uint16_t packedpropsids[MAX_MTP_PROPS];
      uint16_t packedpropstypes[MAX_MTP_PROPS];
      uint32_t totalsize = 0;
      uint32_t bufp = 0;
      uint32_t noitems = 0;
      uint32_t i;

      totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
      propitr = proplist;
      while (propitr != NULL && noitems < MAX_MTP_PROPS) {
            /* Object Handle */
            packedobjecthandles[noitems]=propitr->ObjectHandle;
            totalsize += sizeof(uint32_t); /* Object ID */
            /* Metadata type */
            packedpropsids[noitems]=propitr->property;
            totalsize += sizeof(uint16_t);
            /* Data type */
            packedpropstypes[noitems]= propitr->datatype;
            totalsize += sizeof(uint16_t);
            /* Add each property to be sent. */
              packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
            totalsize += packedpropslens[noitems];
            noitems ++;
            propitr = propitr->next;
      }

      /* Allocate memory for the packed property list */
      opldata = malloc(totalsize);

      htod32a(&opldata[bufp],noitems);
      bufp += 4;

      /* Copy into a nice packed list */
      for (i = 0; i < noitems; i++) {
            /* Object ID */
            htod32a(&opldata[bufp],packedobjecthandles[i]);
            bufp += sizeof(uint32_t);
            htod16a(&opldata[bufp],packedpropsids[i]);
            bufp += sizeof(uint16_t);
            htod16a(&opldata[bufp],packedpropstypes[i]);
            bufp += sizeof(uint16_t);
            /* The copy the actual property */
            memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
            bufp += packedpropslens[i];
            free(packedprops[i]);
      }
      *opldataptr = opldata;
      return totalsize;
}

static inline int
ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPPropList **proplist, unsigned int len)
{ 
      uint32_t prop_count = dtoh32a(data);
      MTPPropList *prop = NULL;
      int offset = 0, i;

      if (prop_count == 0) {
            *proplist = NULL;
            return 0;
      }
      data += sizeof(uint32_t);
      *proplist = malloc(sizeof(MTPPropList));
      prop = *proplist;
      for (i = 0; i < prop_count; i++) {
            prop->ObjectHandle = dtoh32a(data);
            data += sizeof(uint32_t);
            len -= sizeof(uint32_t);

            prop->property = dtoh16a(data);
            data += sizeof(uint16_t);
            len -= sizeof(uint16_t);

            prop->datatype = dtoh16a(data);
            data += sizeof(uint16_t);
            len -= sizeof(uint16_t);

            offset = 0;
            ptp_unpack_DPV(params, data, &offset, len, &prop->propval, prop->datatype);
            data += offset;
            len -= offset;

            if (i != prop_count - 1) {
                  prop->next = malloc(sizeof(MTPPropList));
                  prop = prop->next;
            } else
                  prop->next = NULL;
      }
      return prop_count;
}

/*
    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

static inline void
ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPUSBEventContainer *ec, unsigned int len)
{
      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

static inline void
ptp_unpack_Canon_FE (PTPParams *params, unsigned 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((unsigned char*)&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]);
}

/*
    PTP EOS Changes Entry unpack
*/
#define PTP_ece_Size          0
#define PTP_ece_Type          4

#define PTP_ece_Prop_Subtype  8     /* only for properties */
#define PTP_ece_Prop_Val_Data 0xc   /* only for properties */
#define PTP_ece_Prop_Desc_Type      0xc   /* only for property descs */
#define PTP_ece_Prop_Desc_Count     0x10  /* only for property descs */
#define PTP_ece_Prop_Desc_Data      0x14  /* only for property descs */

#define PTP_ece_OI_ObjectID   8     /* only for objectinfos */
#define PTP_ece_OI_OFC        0x0c  /* only for objectinfos */
#define PTP_ece_OI_Size       0x14  /* only for objectinfos */
#define PTP_ece_OI_Name       0x1c  /* only for objectinfos */

static inline int
ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
{
      int   i = 0, entries = 0;
      unsigned char     *curdata = data;

      if (data==NULL)
            return 0;
      while (curdata - data < datasize) {
            uint32_t    size = dtoh32a(&curdata[PTP_ece_Size]);
            uint32_t    type = dtoh32a(&curdata[PTP_ece_Type]);

            curdata += size;
            if ((size == 8) && (type == 0))
                  break;
            entries++;
      }
      *ce = malloc (sizeof(PTPCanon_changes_entry)*entries);
      if (!*ce) return 0;

      curdata = data;
      while (curdata - data < datasize) {
            uint32_t    size = dtoh32a(&curdata[PTP_ece_Size]);
            uint32_t    type = dtoh32a(&curdata[PTP_ece_Type]);

            switch (type) {
            case  0xc186: {   /* objectinfo from capture */
                  (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
                  (*ce)[i].u.object.oid               = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
                  (*ce)[i].u.object.oi.ObjectFormat   = dtoh16a(&curdata[PTP_ece_OI_OFC]);
                  (*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]));
                  break;
            }
            case  0xc18a: {   /* 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]);
                  unsigned char     *data = &curdata[PTP_ece_Prop_Desc_Data];
                  int         j;
                  PTPDevicePropDesc *dpd;

                  /*fprintf (stderr, "Adding EOS property %04x desc record, datasize is %d\n", proptype, size-PTP_ece_Prop_Desc_Data);*/
                  for (j=0;j<params->nrofcanon_props;j++)
                        if (params->canon_props[j].proptype == proptype)
                              break;
                  if (j==params->nrofcanon_props) {
                        /*fprintf (stderr, "should have received default value for %x first!\n", proptype);*/
                        break;
                  }
                  dpd = &params->canon_props[j].dpd;
                  if (propxtype != 3) {
                        /*fprintf (stderr, "propxtype is %x for %x, unhandled.\n", propxtype, proptype);*/
                        break;
                  }
                  if (propxcnt) {
                        dpd->FormFlag = PTP_DPFF_Enumeration;
                        dpd->FORM.Enum.NumberOfValues = propxcnt;
                        dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
                        for (j=0;j<propxcnt;j++) {
                              switch (dpd->DataType) {
                              case PTP_DTC_UINT16:
                                    dpd->FORM.Enum.SupportedValue[j].u16      = dtoh16a(data);
                                    /*fprintf (stderr,"suppvalue[%d] of %x is %x\n", j, proptype, dtoh16a(data));*/
                                    break;
                              case PTP_DTC_UINT8:
                                    dpd->FORM.Enum.SupportedValue[j].u8 = dtoh8a(data);
                                    /*fprintf (stderr,"suppvalue[%d] of %x is %x\n", j, proptype, dtoh8a(data));*/
                                    break;
                              default:
                                    /*fprintf(stderr,"data type 0x%04x of %x unhandled, fill in (val=%x).\n", dpd->DataType, proptype, dtoh32a(data));*/
                                    break;
                              }
                              data += 4; /* might only be for propxtype 3 */
                        }
                  }
                  break;
            }
            case  0xc189:     /* property value */
                  if (size >= 0xc) {      /* property info */
                        int j;
                        uint32_t    proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
                        unsigned char     *data = &curdata[PTP_ece_Prop_Val_Data];
                        PTPDevicePropDesc *dpd;

                        for (j=0;j<params->nrofcanon_props;j++)
                              if (params->canon_props[j].proptype == proptype)
                                    break;
                        if (j<params->nrofcanon_props) {
                              if (  (params->canon_props[j].size != size) ||
                                    (memcmp(params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data))) {
                                    params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
                                    memcpy (params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data);
                              }
                        } else {
                              if (j)
                                    params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
                              else
                                    params->canon_props = malloc(sizeof(params->canon_props[0]));
                              params->canon_props[j].type = type;
                              params->canon_props[j].proptype = proptype;
                              params->canon_props[j].size = size;
                              params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
                              memcpy(params->canon_props[j].data, data, size-PTP_ece_Prop_Val_Data);
                              memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
                              params->canon_props[j].dpd.GetSet = 1;
                              params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
                              params->nrofcanon_props = j+1;
                        }
                        dpd = &params->canon_props[j].dpd;
                        switch (proptype) {
                        case PTP_DPC_CANON_EOS_CameraTime:
                              dpd->DataType = PTP_DTC_UINT32;
                              break;
                        case PTP_DPC_CANON_EOS_Aperture:
                        case PTP_DPC_CANON_EOS_ShutterSpeed:
                        case PTP_DPC_CANON_EOS_ISOSpeed:
                              dpd->DataType = PTP_DTC_UINT16;
                              break;
                        case PTP_DPC_CANON_EOS_PictureStyle:
                        case PTP_DPC_CANON_EOS_WhiteBalance:
                        case PTP_DPC_CANON_EOS_MeteringMode:
                        case PTP_DPC_CANON_EOS_ExpCompensation:
                              dpd->DataType = PTP_DTC_UINT8;
                              break;
                        case PTP_DPC_CANON_EOS_Owner:
                              dpd->DataType = PTP_DTC_STR;
                              break;
                        default:
                              /*fprintf (stderr, "Unknown EOS property %04x, datasize is %d\n", proptype, size-PTP_ece_Prop_Val_Data);*/
                              break;
                        }
                        switch (dpd->DataType) {
                        case PTP_DTC_UINT32:
                              dpd->FactoryDefaultValue.u32  = dtoh32a(data);
                              dpd->CurrentValue.u32         = dtoh32a(data);
                              /*fprintf (stderr,"currentvalue of %x is %x\n", proptype, dpd->CurrentValue.u16);*/
                              break;
                        case PTP_DTC_UINT16:
                              dpd->FactoryDefaultValue.u16  = dtoh16a(data);
                              dpd->CurrentValue.u16         = dtoh16a(data);
                              /*fprintf (stderr,"currentvalue of %x is %x\n", proptype, dpd->CurrentValue.u16);*/
                              break;
                        case PTP_DTC_UINT8:
                              dpd->FactoryDefaultValue.u8   = dtoh8a(data);
                              dpd->CurrentValue.u8          = dtoh8a(data);
                              /*fprintf (stderr,"currentvalue of %x is %x\n", proptype, dpd->CurrentValue.u8);*/
                              break;
                        case PTP_DTC_STR: {
                              uint8_t len = 0;
                              dpd->FactoryDefaultValue.str  = ptp_unpack_string(params, data, 0, &len);
                              dpd->CurrentValue.str         = ptp_unpack_string(params, data, 0, &len);
                              break;
                        }
                        default:
                              /* debug is printed in switch above this one */
                              break;
                        }
                        break;
            }
            default:
                  /* fprintf (stderr, "unknown EOS property type %04x\n", type); */
                  (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
                  break;
            }
            curdata += size;
            i++;
      }

      return entries;
}

/*
    PTP USB Event container unpack for Nikon events.
*/
#define PTP_nikon_ec_Length         0
#define PTP_nikon_ec_Code           2
#define PTP_nikon_ec_Param1         4
#define PTP_nikon_ec_Size           6
static inline void
ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPUSBEventContainer **ec, int *cnt)
{
      int i;

      *ec = NULL;
      if (data == NULL)
            return;
      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? */
            return;
      *ec = malloc(sizeof(PTPUSBEventContainer)*(*cnt));
      
      for (i=0;i<*cnt;i++) {
            memset(&(*ec)[i],0,sizeof(PTPUSBEventContainer));
            (*ec)[i].code     = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
            (*ec)[i].param1   = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
      }
}


static inline uint32_t
ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
      int i, len = 0;
      uint8_t     retlen;
      unsigned char *curdata;

      len = 2*(strlen(text->title)+1)+1+
            2*(strlen(text->line[0])+1)+1+
            2*(strlen(text->line[1])+1)+1+
            2*(strlen(text->line[2])+1)+1+
            2*(strlen(text->line[3])+1)+1+
            2*(strlen(text->line[4])+1)+1+
            4*2+2*4+2+4+2+5*4*2;
      *data = malloc(len);
      if (!*data) return 0;

      curdata = *data;
      htod16a(curdata,100);curdata+=2;
      htod16a(curdata,1);curdata+=2;
      htod16a(curdata,0);curdata+=2;
      htod16a(curdata,1000);curdata+=2;

      htod32a(curdata,0);curdata+=4;
      htod32a(curdata,0);curdata+=4;

      htod16a(curdata,6);curdata+=2;
      htod32a(curdata,0);curdata+=4;

      ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
      htod16a(curdata,0x10);curdata+=2;
      
      for (i=0;i<5;i++) {
            ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
            htod16a(curdata,0x10);curdata+=2;
            htod16a(curdata,0x01);curdata+=2;
            htod16a(curdata,0x02);curdata+=2;
            htod16a(curdata,0x06);curdata+=2;
      }
      return len;
}

#define ptp_canon_dir_version 0x00
#define ptp_canon_dir_ofc     0x02
#define ptp_canon_dir_unk1    0x04
#define ptp_canon_dir_objectid      0x08
#define ptp_canon_dir_parentid      0x0c
#define ptp_canon_dir_previd  0x10  /* in same dir */
#define ptp_canon_dir_nextid  0x14  /* in same dir */
#define ptp_canon_dir_nextchild     0x18  /* down one dir */
#define ptp_canon_dir_storageid     0x1c  /* only in storage entry */
#define ptp_canon_dir_name    0x20
#define ptp_canon_dir_flags   0x2c
#define ptp_canon_dir_size    0x30
#define ptp_canon_dir_unixtime      0x34
#define ptp_canon_dir_year    0x38
#define ptp_canon_dir_month   0x39
#define ptp_canon_dir_mday    0x3a
#define ptp_canon_dir_hour    0x3b
#define ptp_canon_dir_minute  0x3c
#define ptp_canon_dir_second  0x3d
#define ptp_canon_dir_unk2    0x3e
#define ptp_canon_dir_thumbsize     0x40
#define ptp_canon_dir_width   0x44
#define ptp_canon_dir_height  0x48

static inline uint16_t
ptp_unpack_canon_directory (
      PTPParams         *params,
      unsigned char           *dir,
      uint32_t          cnt,
      PTPObjectHandles  *handles,
      PTPObjectInfo           **oinfos,   /* size(handles->n) */
      uint32_t          **flags           /* size(handles->n) */
) {
      unsigned int      i, j, nrofobs = 0, curob = 0;

#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
      for (i=0;i<cnt;i++)
            if (ISOBJECT(dir+i*0x4c)) nrofobs++;
      handles->n = nrofobs;
      handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
      if (!handles->Handler) return PTP_RC_GeneralError;
      *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
      if (!*oinfos) return PTP_RC_GeneralError;
      *flags  = calloc(sizeof((*flags)[0]),nrofobs);
      if (!*flags) return PTP_RC_GeneralError;

      /* Migrate data into objects ids, handles into
       * the object handler array.
       */
      curob = 0;
      for (i=0;i<cnt;i++) {
            unsigned char     *cur = dir+i*0x4c;
            PTPObjectInfo     *oi = (*oinfos)+curob;

            if (!ISOBJECT(cur))
                  continue;

            handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
            oi->StorageID           = 0xffffffff;
            oi->ObjectFormat  = dtoh16a(cur + ptp_canon_dir_ofc);
            oi->ParentObject  = dtoh32a(cur + ptp_canon_dir_parentid);
            oi->Filename            = strdup((char*)(cur + ptp_canon_dir_name));
            oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
            oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
            oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
            oi->ImagePixHeight      = dtoh32a(cur + ptp_canon_dir_height);
            oi->CaptureDate         = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
            (*flags)[curob]         = dtoh32a(cur + ptp_canon_dir_flags);
            curob++;
      }
      /* Walk over Storage ID entries and distribute the IDs to
       * the parent objects. */
      for (i=0;i<cnt;i++) {
            unsigned char     *cur = dir+i*0x4c;
            uint32_t    nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);

            if (ISOBJECT(cur))
                  continue;
            for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
            if (j == handles->n) continue;
            (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
      }
      /* Walk over all objects and distribute the storage ids */
      while (1) {
            int changed = 0;
            for (i=0;i<cnt;i++) {
                  unsigned char     *cur = dir+i*0x4c;
                  uint32_t    oid = dtoh32a(cur + ptp_canon_dir_objectid);
                  uint32_t    nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
                  uint32_t    nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
                  uint32_t    storageid;

                  if (!ISOBJECT(cur))
                        continue;
                  for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
                  if (j == handles->n) {
                        /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
                        continue;
                  }
                  storageid = (*oinfos)[j].StorageID;
                  if (storageid == 0xffffffff) continue;
                  if (nextoid != 0xffffffff) {
                        for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
                        if (j == handles->n) {
                              /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
                              continue;
                        }
                        if ((*oinfos)[j].StorageID == 0xffffffff) {
                              (*oinfos)[j].StorageID = storageid;
                              changed++;
                        }
                  }
                  if (nextchild != 0xffffffff) {
                        for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
                        if (j == handles->n) {
                              /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
                              continue;
                        }
                        if ((*oinfos)[j].StorageID == 0xffffffff) {
                              (*oinfos)[j].StorageID = storageid;
                              changed++;
                        }
                  }
            }
            /* Check if we:
             * - changed no entry (nothing more to do)
             * - changed all of them at once (usually happens)
             * break if we do.
             */
            if (!changed || (changed==nrofobs-1))
                  break;
      }
#undef ISOBJECT
      return PTP_RC_OK;
}


Generated by  Doxygen 1.6.0   Back to index