* ptp-pack.c: fixed a bug in ptp_unpack_DI(), totallen could be bigger than uint8_t git-svn-id: https://svn.code.sf.net/p/gphoto/code/trunk/libgphoto2@6032 67ed7778-7388-44ab-90cf-0a291f65f57c
400 lines
12 KiB
C
400 lines
12 KiB
C
// curently this file is included into ptp.c
|
|
|
|
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));
|
|
}
|
|
|
|
#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 dtoh16(x) dtoh16p(params,x)
|
|
#define dtoh32(x) dtoh32p(params,x)
|
|
|
|
|
|
static inline char*
|
|
ptp_unpack_string(PTPParams *params, PTPReq *req, uint16_t offset, uint8_t *len)
|
|
{
|
|
int i;
|
|
char *string=NULL;
|
|
|
|
*len=dtoh8a(&req->data[offset]);
|
|
if (*len) {
|
|
string=malloc(*len);
|
|
memset(string, 0, *len);
|
|
for (i=0;i<*len && i< MAXFILENAMELEN; i++) {
|
|
string[i]=(char)dtoh16a(&req->data[offset+i*2+1]);
|
|
}
|
|
// be paranoid! :(
|
|
string[*len-1]=0;
|
|
}
|
|
return (string);
|
|
}
|
|
|
|
static inline void
|
|
ptp_pack_string(PTPParams *params, char *string, PTPReq *req, uint16_t offset, uint8_t *len)
|
|
{
|
|
int i;
|
|
*len = (uint8_t)strlen(string);
|
|
|
|
htod8a(&req->data[offset],*len+1);
|
|
for (i=0;i<*len && i< MAXFILENAMELEN; i++) {
|
|
htod16a(&req->data[offset+i*2+1],(uint16_t)string[i]);
|
|
}
|
|
}
|
|
|
|
static inline uint32_t
|
|
ptp_unpack_uint32_t_array(PTPParams *params, PTPReq *req, uint16_t offset, uint32_t *array)
|
|
{
|
|
uint32_t n, i=0;
|
|
|
|
n=dtoh32a(&req->data[offset]);
|
|
while (n>i) {
|
|
array[i]=dtoh32a(&req->data[offset+(sizeof(uint32_t)*(i+1))]);
|
|
i++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
static inline uint32_t
|
|
ptp_unpack_uint16_t_array(PTPParams *params, PTPReq *req, uint16_t offset, uint16_t **array)
|
|
{
|
|
uint32_t n, i=0;
|
|
|
|
n=dtoh32a(&req->data[offset]);
|
|
*array = malloc (n*sizeof(uint16_t));
|
|
while (n>i) {
|
|
(*array)[i]=dtoh16a(&req->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, PTPReq *req, PTPDeviceInfo *di)
|
|
{
|
|
uint8_t len;
|
|
unsigned int totallen;
|
|
|
|
di->StaqndardVersion = dtoh16a(&req->data[PTP_di_StandardVersion]);
|
|
di->VendorExtensionID =
|
|
dtoh32a(&req->data[PTP_di_VendorExtensionID]);
|
|
di->VendorExtensionVersion =
|
|
dtoh16a(&req->data[PTP_di_VendorExtensionVersion]);
|
|
di->VendorExtensionDesc =
|
|
ptp_unpack_string(params, req,
|
|
PTP_di_VendorExtensionDesc, &len);
|
|
totallen=len*2+1;
|
|
di->FunctionalMode =
|
|
dtoh16a(&req->data[PTP_di_FunctionalMode+totallen]);
|
|
di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, req,
|
|
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, req,
|
|
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, req,
|
|
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, req,
|
|
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, req,
|
|
PTP_di_OperationsSupported+totallen,
|
|
&di->ImageFormats);
|
|
totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
|
|
di->Manufacturer = ptp_unpack_string(params, req,
|
|
PTP_di_OperationsSupported+totallen,
|
|
&len);
|
|
totallen+=len*2+1;
|
|
di->Model = ptp_unpack_string(params, req,
|
|
PTP_di_OperationsSupported+totallen,
|
|
&len);
|
|
totallen+=len*2+1;
|
|
di->DeviceVersion = ptp_unpack_string(params, req,
|
|
PTP_di_OperationsSupported+totallen,
|
|
&len);
|
|
totallen+=len*2+1;
|
|
di->SerialNumber = ptp_unpack_string(params, req,
|
|
PTP_di_OperationsSupported+totallen,
|
|
&len);
|
|
|
|
}
|
|
|
|
// ObjectHandles array pack/unpack
|
|
|
|
#define PTP_oh 0
|
|
|
|
static inline void
|
|
ptp_unpack_OH (PTPParams *params, PTPReq *req, PTPObjectHandles *oh)
|
|
{
|
|
oh->n = ptp_unpack_uint32_t_array(params, req, PTP_oh, oh->handler);
|
|
}
|
|
|
|
// StoreIDs array pack/unpack
|
|
|
|
#define PTP_sids 0
|
|
|
|
static inline void
|
|
ptp_unpack_SIDs (PTPParams *params, PTPReq *req, PTPStorageIDs *sids)
|
|
{
|
|
sids->n = ptp_unpack_uint32_t_array(params, req, 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, PTPReq *req, PTPStorageInfo *si)
|
|
{
|
|
uint8_t storagedescriptionlen;
|
|
|
|
si->StorageType=dtoh16a(&req->data[PTP_si_StorageType]);
|
|
si->FilesystemType=dtoh16a(&req->data[PTP_si_FilesystemType]);
|
|
si->AccessCapability=dtoh16a(&req->data[PTP_si_AccessCapability]);
|
|
// XXX no dtoh64a !!! skiping next two
|
|
si->FreeSpaceInImages=dtoh32a(&req->data[PTP_si_FreeSpaceInImages]);
|
|
si->StorageDescription=ptp_unpack_string(params, req,
|
|
PTP_si_StorageDescription, &storagedescriptionlen);
|
|
si->VolumeLabel=ptp_unpack_string(params, req,
|
|
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
|
|
|
|
static inline int
|
|
ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, PTPReq *req)
|
|
{
|
|
uint8_t filenamelen;
|
|
uint8_t capturedatelen=0;
|
|
#if 0
|
|
char *capture_date="20020101T010101"; // XXX Fake date
|
|
#endif
|
|
memset (req, 0, sizeof(PTPReq));
|
|
htod32a(&req->data[PTP_oi_StorageID],oi->StorageID);
|
|
htod16a(&req->data[PTP_oi_ObjectFormat],oi->ObjectFormat);
|
|
htod16a(&req->data[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
|
|
htod32a(&req->data[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
|
|
htod16a(&req->data[PTP_oi_ThumbFormat],oi->ThumbFormat);
|
|
htod32a(&req->data[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
|
|
htod32a(&req->data[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
|
|
htod32a(&req->data[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
|
|
htod32a(&req->data[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
|
|
htod32a(&req->data[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
|
|
htod32a(&req->data[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
|
|
htod32a(&req->data[PTP_oi_ParentObject],oi->ParentObject);
|
|
htod16a(&req->data[PTP_oi_AssociationType],oi->AssociationType);
|
|
htod32a(&req->data[PTP_oi_AssociationDesc],oi->AssociationDesc);
|
|
htod32a(&req->data[PTP_oi_SequenceNumber],oi->SequenceNumber);
|
|
|
|
ptp_pack_string(params, oi->Filename, req, PTP_oi_filenamelen, &filenamelen);
|
|
/*
|
|
filenamelen=(uint8_t)strlen(oi->Filename);
|
|
htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
|
|
for (i=0;i<filenamelen && i< MAXFILENAMELEN; 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(&req->data[PTP_oi_Filename+(filenamelen+1)*2],
|
|
capturedatelen+1);
|
|
for (i=0;i<capturedatelen && i< MAXFILENAMELEN; i++) {
|
|
req->data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
|
|
}
|
|
htod8a(&req->data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
|
|
capturedatelen+1);
|
|
for (i=0;i<capturedatelen && i< MAXFILENAMELEN; i++) {
|
|
req->data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
|
|
capture_date[i];
|
|
}
|
|
#endif
|
|
// XXX this function should return dataset length
|
|
|
|
return (PTP_oi_Filename+(filenamelen+1)*2+(capturedatelen+1)*4);
|
|
}
|
|
|
|
static inline void
|
|
ptp_unpack_OI (PTPParams *params, PTPReq *req, 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(&req->data[PTP_oi_StorageID]);
|
|
oi->ObjectFormat=dtoh16a(&req->data[PTP_oi_ObjectFormat]);
|
|
oi->ProtectionStatus=dtoh16a(&req->data[PTP_oi_ProtectionStatus]);
|
|
oi->ObjectCompressedSize=dtoh32a(&req->data[PTP_oi_ObjectCompressedSize]);
|
|
oi->ThumbFormat=dtoh16a(&req->data[PTP_oi_ThumbFormat]);
|
|
oi->ThumbCompressedSize=dtoh32a(&req->data[PTP_oi_ThumbCompressedSize]);
|
|
oi->ThumbPixWidth=dtoh32a(&req->data[PTP_oi_ThumbPixWidth]);
|
|
oi->ThumbPixHeight=dtoh32a(&req->data[PTP_oi_ThumbPixHeight]);
|
|
oi->ImagePixWidth=dtoh32a(&req->data[PTP_oi_ImagePixWidth]);
|
|
oi->ImagePixHeight=dtoh32a(&req->data[PTP_oi_ImagePixHeight]);
|
|
oi->ImageBitDepth=dtoh32a(&req->data[PTP_oi_ImageBitDepth]);
|
|
oi->ParentObject=dtoh32a(&req->data[PTP_oi_ParentObject]);
|
|
oi->AssociationType=dtoh16a(&req->data[PTP_oi_AssociationType]);
|
|
oi->AssociationDesc=dtoh32a(&req->data[PTP_oi_AssociationDesc]);
|
|
oi->SequenceNumber=dtoh32a(&req->data[PTP_oi_SequenceNumber]);
|
|
oi->Filename= ptp_unpack_string(params, req, PTP_oi_filenamelen, &filenamelen);
|
|
|
|
capture_date = ptp_unpack_string(params, req,
|
|
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, req,
|
|
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);
|
|
}
|