blob: a1aa5ecb51c41d8d73057e93d9476111ceb13ef7 [file] [log] [blame]
Linus Walleijb02a0662006-04-25 08:05:09 +00001/* currently this file is included into ptp.c */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00002
Linus Walleijb02a0662006-04-25 08:05:09 +00003static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00004htod16p (PTPParams *params, uint16_t var)
5{
6 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
7}
8
Linus Walleijb02a0662006-04-25 08:05:09 +00009static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000010htod32p (PTPParams *params, uint32_t var)
11{
12 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
13}
14
Linus Walleijb02a0662006-04-25 08:05:09 +000015static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000016htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
17{
18 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000019 htole16a(a,val);
20 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021 htobe16a(a,val);
22}
23
Linus Walleijb02a0662006-04-25 08:05:09 +000024static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000025htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
26{
27 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000028 htole32a(a,val);
29 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000030 htobe32a(a,val);
31}
32
Linus Walleijb02a0662006-04-25 08:05:09 +000033static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000034dtoh16p (PTPParams *params, uint16_t var)
35{
36 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
37}
38
Linus Walleijb02a0662006-04-25 08:05:09 +000039static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000040dtoh32p (PTPParams *params, uint32_t var)
41{
42 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
43}
44
Linus Walleijb02a0662006-04-25 08:05:09 +000045static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000046dtoh16ap (PTPParams *params, unsigned char *a)
47{
48 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
49}
50
Linus Walleijb02a0662006-04-25 08:05:09 +000051static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000052dtoh32ap (PTPParams *params, unsigned char *a)
53{
54 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
55}
56
Linus Walleijb02a0662006-04-25 08:05:09 +000057static inline uint64_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000058dtoh64ap (PTPParams *params, unsigned char *a)
59{
Linus Walleijb02a0662006-04-25 08:05:09 +000060 uint64_t tmp = 0;
61 int i;
62
63 if (params->byteorder==PTP_DL_LE) {
64 for (i=0;i<8;i++)
65 tmp |= (((uint64_t)a[i]) << (8*i));
66 } else {
67 for (i=0;i<8;i++)
68 tmp |= (((uint64_t)a[i]) << (8*(7-i)));
69 }
70 return tmp;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000071}
72
Linus Walleijb02a0662006-04-25 08:05:09 +000073#define htod8a(a,x) *(uint8_t*)(a) = x
74#define htod16a(a,x) htod16ap(params,a,x)
75#define htod32a(a,x) htod32ap(params,a,x)
76#define htod16(x) htod16p(params,x)
77#define htod32(x) htod32p(params,x)
78
79#define dtoh8a(x) (*(uint8_t*)(x))
80#define dtoh16a(a) dtoh16ap(params,a)
81#define dtoh32a(a) dtoh32ap(params,a)
82#define dtoh64a(a) dtoh64ap(params,a)
83#define dtoh16(x) dtoh16p(params,x)
84#define dtoh32(x) dtoh32p(params,x)
85
86
87static inline char*
88ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000089{
90 int i;
91 char *string=NULL;
92
93 *len=dtoh8a(&data[offset]);
94 if (*len) {
95 string=malloc(*len);
96 memset(string, 0, *len);
97 for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
98 string[i]=(char)dtoh16a(&data[offset+i*2+1]);
99 }
100 /* be paranoid! :( */
101 string[*len-1]=0;
102 }
103 return (string);
104}
105
Linus Walleijb02a0662006-04-25 08:05:09 +0000106static inline void
107ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000108{
109 int i;
110 *len = (uint8_t)strlen(string);
111
112 /* XXX: check strlen! */
113 htod8a(&data[offset],*len+1);
114 for (i=0;i<*len && i< PTP_MAXSTRLEN; i++) {
115 htod16a(&data[offset+i*2+1],(uint16_t)string[i]);
116 }
117}
118
Linus Walleijb02a0662006-04-25 08:05:09 +0000119static inline uint32_t
120ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000121{
122 uint32_t n, i=0;
123
124 n=dtoh32a(&data[offset]);
125 *array = malloc (n*sizeof(uint32_t));
126 while (n>i) {
127 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
128 i++;
129 }
130 return n;
131}
132
Linus Walleijb02a0662006-04-25 08:05:09 +0000133static inline uint32_t
134ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000135{
136 uint32_t n, i=0;
137
138 n=dtoh32a(&data[offset]);
139 *array = malloc (n*sizeof(uint16_t));
140 while (n>i) {
141 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
142 i++;
143 }
144 return n;
145}
146
147/* DeviceInfo pack/unpack */
148
149#define PTP_di_StandardVersion 0
150#define PTP_di_VendorExtensionID 2
151#define PTP_di_VendorExtensionVersion 6
152#define PTP_di_VendorExtensionDesc 8
153#define PTP_di_FunctionalMode 8
154#define PTP_di_OperationsSupported 10
155
Linus Walleijb02a0662006-04-25 08:05:09 +0000156static inline void
157ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000158{
159 uint8_t len;
160 unsigned int totallen;
161
162 di->StaqndardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
163 di->VendorExtensionID =
164 dtoh32a(&data[PTP_di_VendorExtensionID]);
165 di->VendorExtensionVersion =
166 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
167 di->VendorExtensionDesc =
168 ptp_unpack_string(params, data,
169 PTP_di_VendorExtensionDesc, &len);
170 totallen=len*2+1;
171 di->FunctionalMode =
172 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
173 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
174 PTP_di_OperationsSupported+totallen,
175 &di->OperationsSupported);
176 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
177 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
178 PTP_di_OperationsSupported+totallen,
179 &di->EventsSupported);
180 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
181 di->DevicePropertiesSupported_len =
182 ptp_unpack_uint16_t_array(params, data,
183 PTP_di_OperationsSupported+totallen,
184 &di->DevicePropertiesSupported);
185 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
186 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
187 PTP_di_OperationsSupported+totallen,
188 &di->CaptureFormats);
189 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
190 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
191 PTP_di_OperationsSupported+totallen,
192 &di->ImageFormats);
193 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
194 di->Manufacturer = ptp_unpack_string(params, data,
195 PTP_di_OperationsSupported+totallen,
196 &len);
197 totallen+=len*2+1;
198 di->Model = ptp_unpack_string(params, data,
199 PTP_di_OperationsSupported+totallen,
200 &len);
201 totallen+=len*2+1;
202 di->DeviceVersion = ptp_unpack_string(params, data,
203 PTP_di_OperationsSupported+totallen,
204 &len);
205 totallen+=len*2+1;
206 di->SerialNumber = ptp_unpack_string(params, data,
207 PTP_di_OperationsSupported+totallen,
208 &len);
209}
210
211/* ObjectHandles array pack/unpack */
212
213#define PTP_oh 0
214
Linus Walleijb02a0662006-04-25 08:05:09 +0000215static inline void
216ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000217{
218 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
219}
220
221/* StoreIDs array pack/unpack */
222
223#define PTP_sids 0
224
Linus Walleijb02a0662006-04-25 08:05:09 +0000225static inline void
226ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000227{
228 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
229 &sids->Storage);
230}
231
232/* StorageInfo pack/unpack */
233
234#define PTP_si_StorageType 0
235#define PTP_si_FilesystemType 2
236#define PTP_si_AccessCapability 4
237#define PTP_si_MaxCapability 6
238#define PTP_si_FreeSpaceInBytes 14
239#define PTP_si_FreeSpaceInImages 22
240#define PTP_si_StorageDescription 26
241
Linus Walleijb02a0662006-04-25 08:05:09 +0000242static inline void
243ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000244{
245 uint8_t storagedescriptionlen;
246
247 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
248 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
249 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000250 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
251 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
252 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
253 si->StorageDescription=ptp_unpack_string(params, data,
254 PTP_si_StorageDescription, &storagedescriptionlen);
255 si->VolumeLabel=ptp_unpack_string(params, data,
256 PTP_si_StorageDescription+storagedescriptionlen*2+1,
257 &storagedescriptionlen);
258}
259
260/* ObjectInfo pack/unpack */
261
262#define PTP_oi_StorageID 0
263#define PTP_oi_ObjectFormat 4
264#define PTP_oi_ProtectionStatus 6
265#define PTP_oi_ObjectCompressedSize 8
266#define PTP_oi_ThumbFormat 12
267#define PTP_oi_ThumbCompressedSize 14
268#define PTP_oi_ThumbPixWidth 18
269#define PTP_oi_ThumbPixHeight 22
270#define PTP_oi_ImagePixWidth 26
271#define PTP_oi_ImagePixHeight 30
272#define PTP_oi_ImageBitDepth 34
273#define PTP_oi_ParentObject 38
274#define PTP_oi_AssociationType 42
275#define PTP_oi_AssociationDesc 44
276#define PTP_oi_SequenceNumber 48
277#define PTP_oi_filenamelen 52
278#define PTP_oi_Filename 53
279
Linus Walleijb02a0662006-04-25 08:05:09 +0000280static inline uint32_t
281ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000282{
Linus Walleijb02a0662006-04-25 08:05:09 +0000283 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000284 uint8_t filenamelen;
285 uint8_t capturedatelen=0;
286 /* let's allocate some memory first; XXX i'm sure it's wrong */
287 oidata=malloc(PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4);
288 /* the caller should free it after use! */
289#if 0
290 char *capture_date="20020101T010101"; /* XXX Fake date */
291#endif
292 memset (oidata, 0, (PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4));
293 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
294 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
295 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
296 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
297 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
298 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
299 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
300 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
301 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
302 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
303 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
304 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
305 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
306 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
307 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
308
309 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
310/*
311 filenamelen=(uint8_t)strlen(oi->Filename);
312 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
313 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
314 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
315 }
316*/
317 /*
318 *XXX Fake date.
319 * for example Kodak sets Capture date on the basis of EXIF data.
320 * Spec says that this field is from perspective of Initiator.
321 */
322#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
323 capturedatelen=strlen(capture_date);
324 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
325 capturedatelen+1);
326 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
327 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
328 }
329 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
330 capturedatelen+1);
331 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
332 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
333 capture_date[i];
334 }
335#endif
336 /* XXX this function should return dataset length */
337
338 *oidataptr=oidata;
339 return (PTP_oi_Filename+(filenamelen+1)*2+(capturedatelen+1)*4);
340}
341
Linus Walleijb02a0662006-04-25 08:05:09 +0000342static inline void
343ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000344{
345 uint8_t filenamelen;
346 uint8_t capturedatelen;
347 char *capture_date;
348 char tmp[16];
349 struct tm tm;
350
351 memset(&tm,0,sizeof(tm));
352
353 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
354 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
355 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
356 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
357 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
358 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
359 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
360 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
361 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
362 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
363 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
364 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
365 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
366 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
367 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
368 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
369
370 capture_date = ptp_unpack_string(params, data,
371 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
372 /* subset of ISO 8601, without '.s' tenths of second and
373 * time zone
374 */
375 if (capturedatelen>15)
376 {
377 strncpy (tmp, capture_date, 4);
378 tmp[4] = 0;
379 tm.tm_year=atoi (tmp) - 1900;
380 strncpy (tmp, capture_date + 4, 2);
381 tmp[2] = 0;
382 tm.tm_mon = atoi (tmp) - 1;
383 strncpy (tmp, capture_date + 6, 2);
384 tmp[2] = 0;
385 tm.tm_mday = atoi (tmp);
386 strncpy (tmp, capture_date + 9, 2);
387 tmp[2] = 0;
388 tm.tm_hour = atoi (tmp);
389 strncpy (tmp, capture_date + 11, 2);
390 tmp[2] = 0;
391 tm.tm_min = atoi (tmp);
392 strncpy (tmp, capture_date + 13, 2);
393 tmp[2] = 0;
394 tm.tm_sec = atoi (tmp);
395 oi->CaptureDate=mktime (&tm);
396 }
397 free(capture_date);
398
399 /* now it's modification date ;) */
400 capture_date = ptp_unpack_string(params, data,
401 PTP_oi_filenamelen+filenamelen*2
402 +capturedatelen*2+2,&capturedatelen);
403 if (capturedatelen>15)
404 {
405 strncpy (tmp, capture_date, 4);
406 tmp[4] = 0;
407 tm.tm_year=atoi (tmp) - 1900;
408 strncpy (tmp, capture_date + 4, 2);
409 tmp[2] = 0;
410 tm.tm_mon = atoi (tmp) - 1;
411 strncpy (tmp, capture_date + 6, 2);
412 tmp[2] = 0;
413 tm.tm_mday = atoi (tmp);
414 strncpy (tmp, capture_date + 9, 2);
415 tmp[2] = 0;
416 tm.tm_hour = atoi (tmp);
417 strncpy (tmp, capture_date + 11, 2);
418 tmp[2] = 0;
419 tm.tm_min = atoi (tmp);
420 strncpy (tmp, capture_date + 13, 2);
421 tmp[2] = 0;
422 tm.tm_sec = atoi (tmp);
423 oi->ModificationDate=mktime (&tm);
424 }
425 free(capture_date);
426}
427
428/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000429#define CTVAL(target,func) { \
430 if (total - *offset < sizeof(target)) \
431 return 0; \
432 target = func(&data[*offset]); \
433 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000434}
435
Linus Walleijb02a0662006-04-25 08:05:09 +0000436#define RARR(val,member,func) { \
437 int n,j; \
438 if (total - *offset < sizeof(uint32_t)) \
439 return 0; \
440 n = dtoh32a (&data[*offset]); \
441 *offset += sizeof(uint32_t); \
442 \
443 val->a.count = n; \
444 val->a.v = malloc(sizeof(val->a.v[0])*n); \
445 if (!val->a.v) return 0; \
446 for (j=0;j<n;j++) \
447 CTVAL(val->a.v[j].member, func); \
448}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000449
Linus Walleijb02a0662006-04-25 08:05:09 +0000450static inline int
451ptp_unpack_DPV (
452 PTPParams *params, unsigned char* data, int *offset, int total,
453 PTPPropertyValue* value, uint16_t datatype
454) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000455 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000456 case PTP_DTC_INT8:
457 CTVAL(value->i8,dtoh8a);
458 break;
459 case PTP_DTC_UINT8:
460 CTVAL(value->u8,dtoh8a);
461 break;
462 case PTP_DTC_INT16:
463 CTVAL(value->i16,dtoh16a);
464 break;
465 case PTP_DTC_UINT16:
466 CTVAL(value->u16,dtoh16a);
467 break;
468 case PTP_DTC_INT32:
469 CTVAL(value->i32,dtoh32a);
470 break;
471 case PTP_DTC_UINT32:
472 CTVAL(value->u32,dtoh32a);
473 break;
474 case PTP_DTC_AINT8:
475 RARR(value,i8,dtoh8a);
476 break;
477 case PTP_DTC_AUINT8:
478 RARR(value,u8,dtoh8a);
479 break;
480 case PTP_DTC_AUINT16:
481 RARR(value,u16,dtoh16a);
482 break;
483 case PTP_DTC_AINT16:
484 RARR(value,i16,dtoh16a);
485 break;
486 case PTP_DTC_AUINT32:
487 RARR(value,u32,dtoh32a);
488 break;
489 case PTP_DTC_AINT32:
490 RARR(value,i32,dtoh32a);
491 break;
492 /* XXX: other int types are unimplemented */
493 /* XXX: other int arrays are unimplemented also */
494 case PTP_DTC_STR: {
495 uint8_t len;
496 /* XXX: max size */
497 value->str = ptp_unpack_string(params,data,*offset,&len);
498 *offset += len*2+1;
499 if (!value->str)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000500 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000501 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000502 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000503 case PTP_DTC_UNISTR: {
504 /* this length includes the null character */
505 const int unicsize = sizeof(uint16_t);
506 uint8_t len=dtoh8a(&data[0]);
507 if (len==0) {
508 value->unistr = malloc(unicsize);
509 value->unistr[0]=0;
510 } else {
511 int i;
512 value->unistr = malloc(len*unicsize);
513 for (i=0;i<len;i++) {
514 value->unistr[i]=dtoh16a(&data[i*unicsize+1]);
515 }
516 /* just to be sure... */
517 value->unistr[len-1]=0;
518 }
519 return 2*len+1;
520 break;
521 }
522 }
523 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000524}
525
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000526/* Device Property pack/unpack */
527
528#define PTP_dpd_DevicePropertyCode 0
529#define PTP_dpd_DataType 2
530#define PTP_dpd_GetSet 4
531#define PTP_dpd_FactoryDefaultValue 5
532
Linus Walleijb02a0662006-04-25 08:05:09 +0000533static inline int
534ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000535{
Linus Walleijb02a0662006-04-25 08:05:09 +0000536 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000537
Linus Walleijb02a0662006-04-25 08:05:09 +0000538 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000539 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
540 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
541 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000542
543 offset = PTP_dpd_FactoryDefaultValue;
544 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
545 if (!ret) goto outofmemory;
546 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
547 if (!ret) goto outofmemory;
548
549 /* if offset==0 then Data Type format is not supported by this
550 code or the Data Type is a string (with two empty strings as
551 values). In both cases Form Flag should be set to 0x00 and FORM is
552 not present. */
553
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000554 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000555 if (offset==PTP_dpd_FactoryDefaultValue)
556 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000557
Linus Walleijb02a0662006-04-25 08:05:09 +0000558 dpd->FormFlag=dtoh8a(&data[offset]);
559 offset+=sizeof(uint8_t);
560
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000561 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000562 case PTP_DPFF_Range:
563 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
564 if (!ret) goto outofmemory;
565 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
566 if (!ret) goto outofmemory;
567 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
568 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000569 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000570 case PTP_DPFF_Enumeration: {
571 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000572#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000573 N = dtoh16a(&data[offset]);
574 offset+=sizeof(uint16_t);
575 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
576 if (!dpd->FORM.Enum.SupportedValue)
577 goto outofmemory;
578
579 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
580 for (i=0;i<N;i++) {
581 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
582
583 /* Slightly different handling here. The HP PhotoSmart 120
584 * specifies an enumeration with N in wrong endian
585 * 00 01 instead of 01 00, so we count the enum just until the
586 * the end of the packet.
587 */
588 if (!ret) {
589 if (!i)
590 goto outofmemory;
591 dpd->FORM.Enum.NumberOfValues = i;
592 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000593 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000594 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000595 }
596 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000597#undef N
598 return 1;
599outofmemory:
600 ptp_free_devicepropdesc(dpd);
601 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000602}
603
Linus Walleijb02a0662006-04-25 08:05:09 +0000604/* (MTP) Object Property pack/unpack */
605#define PTP_opd_ObjectPropertyCode 0
606#define PTP_opd_DataType 2
607#define PTP_opd_GetSet 4
608#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000609
Linus Walleijb02a0662006-04-25 08:05:09 +0000610static inline int
611ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000612{
Linus Walleijb02a0662006-04-25 08:05:09 +0000613 int offset=0, ret;
614
615 memset (opd, 0, sizeof(*opd));
616 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
617 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
618 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
619
620 offset = PTP_opd_FactoryDefaultValue;
621 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
622 if (!ret) goto outofmemory;
623
624 opd->GroupCode=dtoh32a(&data[offset]);
625 offset+=sizeof(uint32_t);
626
627 opd->FormFlag=dtoh8a(&data[offset]);
628 offset+=sizeof(uint8_t);
629
630 switch (opd->FormFlag) {
631 case PTP_OPFF_Range:
632 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
633 if (!ret) goto outofmemory;
634 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
635 if (!ret) goto outofmemory;
636 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
637 if (!ret) goto outofmemory;
638 break;
639 case PTP_OPFF_Enumeration: {
640 int i;
641#define N opd->FORM.Enum.NumberOfValues
642 N = dtoh16a(&data[offset]);
643 offset+=sizeof(uint16_t);
644 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
645 if (!opd->FORM.Enum.SupportedValue)
646 goto outofmemory;
647
648 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
649 for (i=0;i<N;i++) {
650 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
651
652 /* Slightly different handling here. The HP PhotoSmart 120
653 * specifies an enumeration with N in wrong endian
654 * 00 01 instead of 01 00, so we count the enum just until the
655 * the end of the packet.
656 */
657 if (!ret) {
658 if (!i)
659 goto outofmemory;
660 opd->FORM.Enum.NumberOfValues = i;
661 break;
662 }
663 }
664#undef N
665 }
666 }
667 return 1;
668outofmemory:
669 ptp_free_objectpropdesc(opd);
670 return 0;
671}
672
673
674static inline uint32_t
675ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
676{
677 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000678 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000679 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000680
681 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000682 case PTP_DTC_INT8:
683 size=sizeof(int8_t);
684 dpv=malloc(size);
685 htod8a(dpv,value->i8);
686 break;
687 case PTP_DTC_UINT8:
688 size=sizeof(uint8_t);
689 dpv=malloc(size);
690 htod8a(dpv,value->u8);
691 break;
692 case PTP_DTC_INT16:
693 size=sizeof(int16_t);
694 dpv=malloc(size);
695 htod16a(dpv,value->i16);
696 break;
697 case PTP_DTC_UINT16:
698 size=sizeof(uint16_t);
699 dpv=malloc(size);
700 htod16a(dpv,value->u16);
701 break;
702 case PTP_DTC_INT32:
703 size=sizeof(int32_t);
704 dpv=malloc(size);
705 htod32a(dpv,value->i32);
706 break;
707 case PTP_DTC_UINT32:
708 size=sizeof(uint32_t);
709 dpv=malloc(size);
710 htod32a(dpv,value->u32);
711 break;
712 case PTP_DTC_AUINT8:
713 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
714 dpv=malloc(size);
715 htod32a(dpv,value->a.count);
716 for (i=0;i<value->a.count;i++)
717 htod8a(&dpv[4+i],value->a.v[i].u8);
718 break;
719 case PTP_DTC_AINT8:
720 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
721 dpv=malloc(size);
722 htod32a(dpv,value->a.count);
723 for (i=0;i<value->a.count;i++)
724 htod8a(&dpv[4+i],value->a.v[i].i8);
725 break;
726 case PTP_DTC_AUINT16:
727 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
728 dpv=malloc(size);
729 htod32a(dpv,value->a.count);
730 for (i=0;i<value->a.count;i++)
731 htod16a(&dpv[4+i],value->a.v[i].u16);
732 break;
733 case PTP_DTC_AINT16:
734 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
735 dpv=malloc(size);
736 htod32a(dpv,value->a.count);
737 for (i=0;i<value->a.count;i++)
738 htod16a(&dpv[4+i],value->a.v[i].i16);
739 break;
740 case PTP_DTC_AUINT32:
741 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
742 dpv=malloc(size);
743 htod32a(dpv,value->a.count);
744 for (i=0;i<value->a.count;i++)
745 htod32a(&dpv[4+i],value->a.v[i].u32);
746 break;
747 case PTP_DTC_AINT32:
748 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
749 dpv=malloc(size);
750 htod32a(dpv,value->a.count);
751 for (i=0;i<value->a.count;i++)
752 htod32a(&dpv[4+i],value->a.v[i].i32);
753 break;
754 /* XXX: other int types are unimplemented */
755 case PTP_DTC_STR: {
756 uint8_t len;
757
758 size=strlen(value->str)*2+3;
759 dpv=malloc(size);
760 memset(dpv,0,size);
761 ptp_pack_string(params, value->str, dpv, 0, &len);
762 break;
763 }
764 case PTP_DTC_UNISTR: {
765 uint8_t len = 0;
766 /* note PTP_MAXSTRLEN includes the null terminator */
767 while (((uint16_t *)value)[len] != 0 && len != PTP_MAXSTRLEN-1)
768 len++;
769 if (len==0) {
770 size=1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000771 dpv=malloc(size);
Linus Walleijb02a0662006-04-25 08:05:09 +0000772 *dpv=0;
773 } else {
774 /* 2 extra bytes for the terminator, 1 for the length at the beginning */
775 size=len*2+3;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000776 dpv=malloc(size);
777 memset(dpv,0,size);
Linus Walleijb02a0662006-04-25 08:05:09 +0000778 htod8a(&dpv[0],len+1);
779 for (i = 0; i < len; i++)
780 htod16a(&dpv[i*2+1],((uint16_t *)value)[i]);
781 /* terminator is done by memset above */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000782 }
783 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000784 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000785 }
786 *dpvptr=dpv;
787 return size;
788}
789
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000790/*
791 PTP USB Event container unpack
792 Copyright (c) 2003 Nikolai Kopanygin
793*/
794
795#define PTP_ec_Length 0
796#define PTP_ec_Type 4
797#define PTP_ec_Code 6
798#define PTP_ec_TransId 8
799#define PTP_ec_Param1 12
800#define PTP_ec_Param2 16
801#define PTP_ec_Param3 20
802
Linus Walleijb02a0662006-04-25 08:05:09 +0000803static inline void
804ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPUSBEventContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000805{
806 if (data==NULL)
807 return;
808 ec->length=dtoh32a(&data[PTP_ec_Length]);
809 ec->type=dtoh16a(&data[PTP_ec_Type]);
810 ec->code=dtoh16a(&data[PTP_ec_Code]);
811 ec->trans_id=dtoh32a(&data[PTP_ec_TransId]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000812
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000813 if (ec->length>=(PTP_ec_Param1+4))
814 ec->param1=dtoh32a(&data[PTP_ec_Param1]);
815 else
816 ec->param1=0;
817 if (ec->length>=(PTP_ec_Param2+4))
818 ec->param2=dtoh32a(&data[PTP_ec_Param2]);
819 else
820 ec->param2=0;
821 if (ec->length>=(PTP_ec_Param3+4))
822 ec->param3=dtoh32a(&data[PTP_ec_Param3]);
823 else
824 ec->param3=0;
825}
826
827/*
828 PTP Canon Folder Entry unpack
829 Copyright (c) 2003 Nikolai Kopanygin
830*/
831#define PTP_cfe_ObjectHandle 0
832#define PTP_cfe_ObjectFormatCode 4
833#define PTP_cfe_Flags 6
834#define PTP_cfe_ObjectSize 7
835#define PTP_cfe_Time 11
836#define PTP_cfe_Filename 15
837
Linus Walleijb02a0662006-04-25 08:05:09 +0000838static inline void
839ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000840{
841 int i;
842 if (data==NULL)
843 return;
844 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
845 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
846 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000847 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000848 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
849 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +0000850 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
851}
852
853/*
854 PTP USB Event container unpack for Nikon events.
855*/
856#define PTP_nikon_ec_Length 0
857#define PTP_nikon_ec_Code 2
858#define PTP_nikon_ec_Param1 4
859#define PTP_nikon_ec_Size 6
860static inline void
861ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPUSBEventContainer **ec, int *cnt)
862{
863 int i;
864
865 *ec = NULL;
866 if (data == NULL)
867 return;
868 if (len < PTP_nikon_ec_Code)
869 return;
870 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
871 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
872 return;
873 *ec = malloc(sizeof(PTPUSBEventContainer)*(*cnt));
874
875 for (i=0;i<*cnt;i++) {
876 memset(&(*ec)[i],0,sizeof(PTPUSBEventContainer));
877 (*ec)[i].code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
878 (*ec)[i].param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
879 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000880}
881
882
Linus Walleijb02a0662006-04-25 08:05:09 +0000883static inline uint32_t
884ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
885 int i, len = 0;
886 uint8_t retlen;
887 unsigned char *curdata;
888
889 len = 2*(strlen(text->title)+1)+1+
890 2*(strlen(text->line[0])+1)+1+
891 2*(strlen(text->line[1])+1)+1+
892 2*(strlen(text->line[2])+1)+1+
893 2*(strlen(text->line[3])+1)+1+
894 2*(strlen(text->line[4])+1)+1+
895 4*2+2*4+2+4+2+5*4*2;
896 *data = malloc(len);
897 if (!*data) return 0;
898
899 curdata = *data;
900 htod16a(curdata,100);curdata+=2;
901 htod16a(curdata,1);curdata+=2;
902 htod16a(curdata,0);curdata+=2;
903 htod16a(curdata,1000);curdata+=2;
904
905 htod32a(curdata,0);curdata+=4;
906 htod32a(curdata,0);curdata+=4;
907
908 htod16a(curdata,6);curdata+=2;
909 htod32a(curdata,0);curdata+=4;
910
911 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
912 htod16a(curdata,0x10);curdata+=2;
913
914 for (i=0;i<5;i++) {
915 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
916 htod16a(curdata,0x10);curdata+=2;
917 htod16a(curdata,0x01);curdata+=2;
918 htod16a(curdata,0x02);curdata+=2;
919 htod16a(curdata,0x06);curdata+=2;
920 }
921 return len;
922}