blob: df2f4cb25d02d1de24fbbb9326c6942890ef6393 [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 Walleija823a702006-08-27 21:27:46 +00003#include <iconv.h>
4
Linus Walleijb02a0662006-04-25 08:05:09 +00005static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00006htod16p (PTPParams *params, uint16_t var)
7{
8 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
9}
10
Linus Walleijb02a0662006-04-25 08:05:09 +000011static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000012htod32p (PTPParams *params, uint32_t var)
13{
14 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
15}
16
Linus Walleijb02a0662006-04-25 08:05:09 +000017static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000018htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
19{
20 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000021 htole16a(a,val);
22 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000023 htobe16a(a,val);
24}
25
Linus Walleijb02a0662006-04-25 08:05:09 +000026static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000027htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
28{
29 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000030 htole32a(a,val);
31 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000032 htobe32a(a,val);
33}
34
Linus Walleijb02a0662006-04-25 08:05:09 +000035static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000036dtoh16p (PTPParams *params, uint16_t var)
37{
38 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
39}
40
Linus Walleijb02a0662006-04-25 08:05:09 +000041static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000042dtoh32p (PTPParams *params, uint32_t var)
43{
44 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
45}
46
Linus Walleijb02a0662006-04-25 08:05:09 +000047static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000048dtoh16ap (PTPParams *params, unsigned char *a)
49{
50 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
51}
52
Linus Walleijb02a0662006-04-25 08:05:09 +000053static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000054dtoh32ap (PTPParams *params, unsigned char *a)
55{
56 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
57}
58
Linus Walleijb02a0662006-04-25 08:05:09 +000059static inline uint64_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000060dtoh64ap (PTPParams *params, unsigned char *a)
61{
Linus Walleijb02a0662006-04-25 08:05:09 +000062 uint64_t tmp = 0;
63 int i;
64
65 if (params->byteorder==PTP_DL_LE) {
66 for (i=0;i<8;i++)
67 tmp |= (((uint64_t)a[i]) << (8*i));
68 } else {
69 for (i=0;i<8;i++)
70 tmp |= (((uint64_t)a[i]) << (8*(7-i)));
71 }
72 return tmp;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000073}
74
Linus Walleijb02a0662006-04-25 08:05:09 +000075#define htod8a(a,x) *(uint8_t*)(a) = x
76#define htod16a(a,x) htod16ap(params,a,x)
77#define htod32a(a,x) htod32ap(params,a,x)
78#define htod16(x) htod16p(params,x)
79#define htod32(x) htod32p(params,x)
80
81#define dtoh8a(x) (*(uint8_t*)(x))
82#define dtoh16a(a) dtoh16ap(params,a)
83#define dtoh32a(a) dtoh32ap(params,a)
84#define dtoh64a(a) dtoh64ap(params,a)
85#define dtoh16(x) dtoh16p(params,x)
86#define dtoh32(x) dtoh32p(params,x)
87
88
89static inline char*
90ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000091{
92 int i;
Linus Walleija823a702006-08-27 21:27:46 +000093 uint8_t loclen;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000094
Linus Walleija823a702006-08-27 21:27:46 +000095 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
96 loclen = dtoh8a(&data[offset]);
97 /* This len is used to advance the buffer pointer */
98 *len = loclen;
99 if (loclen) {
100 uint16_t string[PTP_MAXSTRLEN+1];
101 char *stringp = (char *) string;
102 char loclstr[PTP_MAXSTRLEN*3+1]; /* UTF-8 encoding is max 3 bytes per UCS2 char. */
103 char *locp = loclstr;
104 size_t nconv;
105 size_t convlen = loclen * 2; /* UCS-2 is 16 bit wide */
106 size_t convmax = PTP_MAXSTRLEN*3;
107
108 for (i=0;i<loclen;i++) {
109 string[i]=dtoh16a(&data[offset+i*2+1]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000110 }
Linus Walleija823a702006-08-27 21:27:46 +0000111 /* be paranoid! Add a terminator. :( */
112 string[loclen]=0x0000U;
113 loclstr[0]='\0';
114 /* loclstr=ucs2_to_utf8(string); */
115 /* Do the conversion. */
116 nconv = iconv (params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax);
117 /* FIXME: handle size errors */
118 loclstr[PTP_MAXSTRLEN*3] = '\0';
119 if (nconv == (size_t) -1)
120 return NULL;
121 return strdup(loclstr);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000122 }
Linus Walleija823a702006-08-27 21:27:46 +0000123 return NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000124}
125
Linus Walleija823a702006-08-27 21:27:46 +0000126
127static inline int
128ucs2strlen(uint16_t const * const unicstr)
129{
130 int length;
131
132 /* Unicode strings are terminated with 2 * 0x00 */
133 for(length = 0; unicstr[length] != 0x0000U; length ++);
134 return length;
135}
136
137
Linus Walleijb02a0662006-04-25 08:05:09 +0000138static inline void
139ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000140{
141 int i;
Linus Walleija823a702006-08-27 21:27:46 +0000142 int packedlen;
143 uint16_t ucs2str[PTP_MAXSTRLEN+1];
144 char *ucs2strp = (char *) ucs2str;
145 char *stringp = string;
146 size_t nconv;
147 size_t convlen = strlen(string);
148 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
149
150 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
151 ucs2str[0] = 0x0000U;
152 memset(ucs2strp, 0, PTP_MAXSTRLEN*2+2);
153 nconv = iconv (params->cd_locale_to_ucs2, &stringp, &convlen, &ucs2strp, &convmax);
154 if (nconv == (size_t) -1) {
155 ucs2str[0] = 0x0000U;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000156 }
Linus Walleija823a702006-08-27 21:27:46 +0000157 packedlen = ucs2strlen(ucs2str);
158 if (packedlen > PTP_MAXSTRLEN-1) {
159 *len=0;
160 return;
161 }
Linus Walleij958441f2006-08-29 15:30:11 +0000162
Linus Walleija823a702006-08-27 21:27:46 +0000163 /* +1 for the length byte, no zero 0x0000 terminator */
164 htod8a(&data[offset],packedlen+1);
165 for (i=0;i<packedlen && i< PTP_MAXSTRLEN; i++) {
166 htod16a(&data[offset+i*2+1],ucs2str[i]);
167 }
Linus Walleij958441f2006-08-29 15:30:11 +0000168
169 /* The returned length is in number of characters */
170 *len = (uint8_t) packedlen;
Linus Walleija823a702006-08-27 21:27:46 +0000171}
172
173static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000174ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000175{
Linus Walleij958441f2006-08-29 15:30:11 +0000176uint8_t packed[PTP_MAXSTRLEN+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000177 size_t plen;
178 unsigned char *retcopy = NULL;
179
180 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
Linus Walleij958441f2006-08-29 15:30:11 +0000181 /* returned length is in characters, then one byte for string length */
182 plen = len*2 + 1;
183 /* Assure proper termination, two zero bytes */
Linus Walleija823a702006-08-27 21:27:46 +0000184 packed[plen] = 0x00;
185 packed[plen+1] = 0x00;
186 /* Include terminator */
187 plen += 2;
188 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000189 if (!retcopy) {
190 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000191 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000192 }
Linus Walleija823a702006-08-27 21:27:46 +0000193 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000194 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000195 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000196}
197
Linus Walleijb02a0662006-04-25 08:05:09 +0000198static inline uint32_t
199ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000200{
201 uint32_t n, i=0;
202
203 n=dtoh32a(&data[offset]);
204 *array = malloc (n*sizeof(uint32_t));
205 while (n>i) {
206 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
207 i++;
208 }
209 return n;
210}
211
Linus Walleijb02a0662006-04-25 08:05:09 +0000212static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000213ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
214{
215 uint32_t i=0;
216
217 *data = malloc ((arraylen+1)*sizeof(uint32_t));
218 htod32a(&(*data)[0],arraylen);
219 for (i=0;i<arraylen;i++)
220 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
221 return (arraylen+1)*sizeof(uint32_t);
222}
223
224static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000225ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000226{
227 uint32_t n, i=0;
228
229 n=dtoh32a(&data[offset]);
230 *array = malloc (n*sizeof(uint16_t));
231 while (n>i) {
232 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
233 i++;
234 }
235 return n;
236}
237
238/* DeviceInfo pack/unpack */
239
240#define PTP_di_StandardVersion 0
241#define PTP_di_VendorExtensionID 2
242#define PTP_di_VendorExtensionVersion 6
243#define PTP_di_VendorExtensionDesc 8
244#define PTP_di_FunctionalMode 8
245#define PTP_di_OperationsSupported 10
246
Linus Walleijb02a0662006-04-25 08:05:09 +0000247static inline void
248ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000249{
250 uint8_t len;
251 unsigned int totallen;
252
253 di->StaqndardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
254 di->VendorExtensionID =
255 dtoh32a(&data[PTP_di_VendorExtensionID]);
256 di->VendorExtensionVersion =
257 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
258 di->VendorExtensionDesc =
259 ptp_unpack_string(params, data,
260 PTP_di_VendorExtensionDesc, &len);
261 totallen=len*2+1;
262 di->FunctionalMode =
263 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
264 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
265 PTP_di_OperationsSupported+totallen,
266 &di->OperationsSupported);
267 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
268 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
269 PTP_di_OperationsSupported+totallen,
270 &di->EventsSupported);
271 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
272 di->DevicePropertiesSupported_len =
273 ptp_unpack_uint16_t_array(params, data,
274 PTP_di_OperationsSupported+totallen,
275 &di->DevicePropertiesSupported);
276 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
277 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
278 PTP_di_OperationsSupported+totallen,
279 &di->CaptureFormats);
280 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
281 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
282 PTP_di_OperationsSupported+totallen,
283 &di->ImageFormats);
284 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
285 di->Manufacturer = ptp_unpack_string(params, data,
286 PTP_di_OperationsSupported+totallen,
287 &len);
288 totallen+=len*2+1;
289 di->Model = ptp_unpack_string(params, data,
290 PTP_di_OperationsSupported+totallen,
291 &len);
292 totallen+=len*2+1;
293 di->DeviceVersion = ptp_unpack_string(params, data,
294 PTP_di_OperationsSupported+totallen,
295 &len);
296 totallen+=len*2+1;
297 di->SerialNumber = ptp_unpack_string(params, data,
298 PTP_di_OperationsSupported+totallen,
299 &len);
300}
301
302/* ObjectHandles array pack/unpack */
303
304#define PTP_oh 0
305
Linus Walleijb02a0662006-04-25 08:05:09 +0000306static inline void
307ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000308{
309 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
310}
311
312/* StoreIDs array pack/unpack */
313
314#define PTP_sids 0
315
Linus Walleijb02a0662006-04-25 08:05:09 +0000316static inline void
317ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000318{
319 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
320 &sids->Storage);
321}
322
323/* StorageInfo pack/unpack */
324
325#define PTP_si_StorageType 0
326#define PTP_si_FilesystemType 2
327#define PTP_si_AccessCapability 4
328#define PTP_si_MaxCapability 6
329#define PTP_si_FreeSpaceInBytes 14
330#define PTP_si_FreeSpaceInImages 22
331#define PTP_si_StorageDescription 26
332
Linus Walleijb02a0662006-04-25 08:05:09 +0000333static inline void
334ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000335{
336 uint8_t storagedescriptionlen;
337
338 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
339 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
340 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000341 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
342 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
343 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
344 si->StorageDescription=ptp_unpack_string(params, data,
345 PTP_si_StorageDescription, &storagedescriptionlen);
346 si->VolumeLabel=ptp_unpack_string(params, data,
347 PTP_si_StorageDescription+storagedescriptionlen*2+1,
348 &storagedescriptionlen);
349}
350
351/* ObjectInfo pack/unpack */
352
353#define PTP_oi_StorageID 0
354#define PTP_oi_ObjectFormat 4
355#define PTP_oi_ProtectionStatus 6
356#define PTP_oi_ObjectCompressedSize 8
357#define PTP_oi_ThumbFormat 12
358#define PTP_oi_ThumbCompressedSize 14
359#define PTP_oi_ThumbPixWidth 18
360#define PTP_oi_ThumbPixHeight 22
361#define PTP_oi_ImagePixWidth 26
362#define PTP_oi_ImagePixHeight 30
363#define PTP_oi_ImageBitDepth 34
364#define PTP_oi_ParentObject 38
365#define PTP_oi_AssociationType 42
366#define PTP_oi_AssociationDesc 44
367#define PTP_oi_SequenceNumber 48
368#define PTP_oi_filenamelen 52
369#define PTP_oi_Filename 53
370
Linus Walleijb02a0662006-04-25 08:05:09 +0000371static inline uint32_t
372ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000373{
Linus Walleijb02a0662006-04-25 08:05:09 +0000374 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000375 uint8_t filenamelen;
376 uint8_t capturedatelen=0;
377 /* let's allocate some memory first; XXX i'm sure it's wrong */
378 oidata=malloc(PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4);
379 /* the caller should free it after use! */
380#if 0
381 char *capture_date="20020101T010101"; /* XXX Fake date */
382#endif
383 memset (oidata, 0, (PTP_oi_Filename+(strlen(oi->Filename)+1)*2+4));
384 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
385 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
386 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
387 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
388 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
389 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
390 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
391 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
392 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
393 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
394 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
395 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
396 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
397 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
398 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
399
400 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
401/*
402 filenamelen=(uint8_t)strlen(oi->Filename);
403 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
404 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
405 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
406 }
407*/
408 /*
409 *XXX Fake date.
410 * for example Kodak sets Capture date on the basis of EXIF data.
411 * Spec says that this field is from perspective of Initiator.
412 */
413#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
414 capturedatelen=strlen(capture_date);
415 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
416 capturedatelen+1);
417 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
418 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
419 }
420 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
421 capturedatelen+1);
422 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
423 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
424 capture_date[i];
425 }
426#endif
427 /* XXX this function should return dataset length */
428
429 *oidataptr=oidata;
430 return (PTP_oi_Filename+(filenamelen+1)*2+(capturedatelen+1)*4);
431}
432
Linus Walleijb02a0662006-04-25 08:05:09 +0000433static inline void
434ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000435{
436 uint8_t filenamelen;
437 uint8_t capturedatelen;
438 char *capture_date;
439 char tmp[16];
440 struct tm tm;
441
442 memset(&tm,0,sizeof(tm));
443
444 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
445 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
446 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
447 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
448 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
449 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
450 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
451 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
452 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
453 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
454 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
455 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
456 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
457 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
458 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
459 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
460
461 capture_date = ptp_unpack_string(params, data,
462 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
463 /* subset of ISO 8601, without '.s' tenths of second and
464 * time zone
465 */
466 if (capturedatelen>15)
467 {
468 strncpy (tmp, capture_date, 4);
469 tmp[4] = 0;
470 tm.tm_year=atoi (tmp) - 1900;
471 strncpy (tmp, capture_date + 4, 2);
472 tmp[2] = 0;
473 tm.tm_mon = atoi (tmp) - 1;
474 strncpy (tmp, capture_date + 6, 2);
475 tmp[2] = 0;
476 tm.tm_mday = atoi (tmp);
477 strncpy (tmp, capture_date + 9, 2);
478 tmp[2] = 0;
479 tm.tm_hour = atoi (tmp);
480 strncpy (tmp, capture_date + 11, 2);
481 tmp[2] = 0;
482 tm.tm_min = atoi (tmp);
483 strncpy (tmp, capture_date + 13, 2);
484 tmp[2] = 0;
485 tm.tm_sec = atoi (tmp);
486 oi->CaptureDate=mktime (&tm);
487 }
488 free(capture_date);
489
490 /* now it's modification date ;) */
491 capture_date = ptp_unpack_string(params, data,
492 PTP_oi_filenamelen+filenamelen*2
493 +capturedatelen*2+2,&capturedatelen);
494 if (capturedatelen>15)
495 {
496 strncpy (tmp, capture_date, 4);
497 tmp[4] = 0;
498 tm.tm_year=atoi (tmp) - 1900;
499 strncpy (tmp, capture_date + 4, 2);
500 tmp[2] = 0;
501 tm.tm_mon = atoi (tmp) - 1;
502 strncpy (tmp, capture_date + 6, 2);
503 tmp[2] = 0;
504 tm.tm_mday = atoi (tmp);
505 strncpy (tmp, capture_date + 9, 2);
506 tmp[2] = 0;
507 tm.tm_hour = atoi (tmp);
508 strncpy (tmp, capture_date + 11, 2);
509 tmp[2] = 0;
510 tm.tm_min = atoi (tmp);
511 strncpy (tmp, capture_date + 13, 2);
512 tmp[2] = 0;
513 tm.tm_sec = atoi (tmp);
514 oi->ModificationDate=mktime (&tm);
515 }
516 free(capture_date);
517}
518
519/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000520#define CTVAL(target,func) { \
521 if (total - *offset < sizeof(target)) \
522 return 0; \
523 target = func(&data[*offset]); \
524 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000525}
526
Linus Walleijb02a0662006-04-25 08:05:09 +0000527#define RARR(val,member,func) { \
528 int n,j; \
529 if (total - *offset < sizeof(uint32_t)) \
530 return 0; \
531 n = dtoh32a (&data[*offset]); \
532 *offset += sizeof(uint32_t); \
533 \
534 val->a.count = n; \
535 val->a.v = malloc(sizeof(val->a.v[0])*n); \
536 if (!val->a.v) return 0; \
537 for (j=0;j<n;j++) \
538 CTVAL(val->a.v[j].member, func); \
539}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000540
Linus Walleijb02a0662006-04-25 08:05:09 +0000541static inline int
542ptp_unpack_DPV (
543 PTPParams *params, unsigned char* data, int *offset, int total,
544 PTPPropertyValue* value, uint16_t datatype
545) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000546 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000547 case PTP_DTC_INT8:
548 CTVAL(value->i8,dtoh8a);
549 break;
550 case PTP_DTC_UINT8:
551 CTVAL(value->u8,dtoh8a);
552 break;
553 case PTP_DTC_INT16:
554 CTVAL(value->i16,dtoh16a);
555 break;
556 case PTP_DTC_UINT16:
557 CTVAL(value->u16,dtoh16a);
558 break;
559 case PTP_DTC_INT32:
560 CTVAL(value->i32,dtoh32a);
561 break;
562 case PTP_DTC_UINT32:
563 CTVAL(value->u32,dtoh32a);
564 break;
565 case PTP_DTC_AINT8:
566 RARR(value,i8,dtoh8a);
567 break;
568 case PTP_DTC_AUINT8:
569 RARR(value,u8,dtoh8a);
570 break;
571 case PTP_DTC_AUINT16:
572 RARR(value,u16,dtoh16a);
573 break;
574 case PTP_DTC_AINT16:
575 RARR(value,i16,dtoh16a);
576 break;
577 case PTP_DTC_AUINT32:
578 RARR(value,u32,dtoh32a);
579 break;
580 case PTP_DTC_AINT32:
581 RARR(value,i32,dtoh32a);
582 break;
583 /* XXX: other int types are unimplemented */
584 /* XXX: other int arrays are unimplemented also */
585 case PTP_DTC_STR: {
586 uint8_t len;
587 /* XXX: max size */
588 value->str = ptp_unpack_string(params,data,*offset,&len);
589 *offset += len*2+1;
590 if (!value->str)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000591 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000592 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000593 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000594 }
595 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000596}
597
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000598/* Device Property pack/unpack */
599
600#define PTP_dpd_DevicePropertyCode 0
601#define PTP_dpd_DataType 2
602#define PTP_dpd_GetSet 4
603#define PTP_dpd_FactoryDefaultValue 5
604
Linus Walleijb02a0662006-04-25 08:05:09 +0000605static inline int
606ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000607{
Linus Walleijb02a0662006-04-25 08:05:09 +0000608 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000609
Linus Walleijb02a0662006-04-25 08:05:09 +0000610 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000611 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
612 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
613 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000614
615 offset = PTP_dpd_FactoryDefaultValue;
616 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
617 if (!ret) goto outofmemory;
618 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
619 if (!ret) goto outofmemory;
620
621 /* if offset==0 then Data Type format is not supported by this
622 code or the Data Type is a string (with two empty strings as
623 values). In both cases Form Flag should be set to 0x00 and FORM is
624 not present. */
625
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000626 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000627 if (offset==PTP_dpd_FactoryDefaultValue)
628 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000629
Linus Walleijb02a0662006-04-25 08:05:09 +0000630 dpd->FormFlag=dtoh8a(&data[offset]);
631 offset+=sizeof(uint8_t);
632
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000633 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000634 case PTP_DPFF_Range:
635 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
636 if (!ret) goto outofmemory;
637 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
638 if (!ret) goto outofmemory;
639 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
640 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000641 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000642 case PTP_DPFF_Enumeration: {
643 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000644#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000645 N = dtoh16a(&data[offset]);
646 offset+=sizeof(uint16_t);
647 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
648 if (!dpd->FORM.Enum.SupportedValue)
649 goto outofmemory;
650
651 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
652 for (i=0;i<N;i++) {
653 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
654
655 /* Slightly different handling here. The HP PhotoSmart 120
656 * specifies an enumeration with N in wrong endian
657 * 00 01 instead of 01 00, so we count the enum just until the
658 * the end of the packet.
659 */
660 if (!ret) {
661 if (!i)
662 goto outofmemory;
663 dpd->FORM.Enum.NumberOfValues = i;
664 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000665 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000666 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000667 }
668 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000669#undef N
670 return 1;
671outofmemory:
672 ptp_free_devicepropdesc(dpd);
673 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000674}
675
Linus Walleijb02a0662006-04-25 08:05:09 +0000676/* (MTP) Object Property pack/unpack */
677#define PTP_opd_ObjectPropertyCode 0
678#define PTP_opd_DataType 2
679#define PTP_opd_GetSet 4
680#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000681
Linus Walleijb02a0662006-04-25 08:05:09 +0000682static inline int
683ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000684{
Linus Walleijb02a0662006-04-25 08:05:09 +0000685 int offset=0, ret;
686
687 memset (opd, 0, sizeof(*opd));
688 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
689 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
690 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
691
692 offset = PTP_opd_FactoryDefaultValue;
693 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
694 if (!ret) goto outofmemory;
695
696 opd->GroupCode=dtoh32a(&data[offset]);
697 offset+=sizeof(uint32_t);
698
699 opd->FormFlag=dtoh8a(&data[offset]);
700 offset+=sizeof(uint8_t);
701
702 switch (opd->FormFlag) {
703 case PTP_OPFF_Range:
704 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
705 if (!ret) goto outofmemory;
706 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
707 if (!ret) goto outofmemory;
708 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
709 if (!ret) goto outofmemory;
710 break;
711 case PTP_OPFF_Enumeration: {
712 int i;
713#define N opd->FORM.Enum.NumberOfValues
714 N = dtoh16a(&data[offset]);
715 offset+=sizeof(uint16_t);
716 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
717 if (!opd->FORM.Enum.SupportedValue)
718 goto outofmemory;
719
720 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
721 for (i=0;i<N;i++) {
722 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
723
724 /* Slightly different handling here. The HP PhotoSmart 120
725 * specifies an enumeration with N in wrong endian
726 * 00 01 instead of 01 00, so we count the enum just until the
727 * the end of the packet.
728 */
729 if (!ret) {
730 if (!i)
731 goto outofmemory;
732 opd->FORM.Enum.NumberOfValues = i;
733 break;
734 }
735 }
736#undef N
737 }
738 }
739 return 1;
740outofmemory:
741 ptp_free_objectpropdesc(opd);
742 return 0;
743}
744
745
746static inline uint32_t
747ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
748{
749 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000750 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000751 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000752
753 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000754 case PTP_DTC_INT8:
755 size=sizeof(int8_t);
756 dpv=malloc(size);
757 htod8a(dpv,value->i8);
758 break;
759 case PTP_DTC_UINT8:
760 size=sizeof(uint8_t);
761 dpv=malloc(size);
762 htod8a(dpv,value->u8);
763 break;
764 case PTP_DTC_INT16:
765 size=sizeof(int16_t);
766 dpv=malloc(size);
767 htod16a(dpv,value->i16);
768 break;
769 case PTP_DTC_UINT16:
770 size=sizeof(uint16_t);
771 dpv=malloc(size);
772 htod16a(dpv,value->u16);
773 break;
774 case PTP_DTC_INT32:
775 size=sizeof(int32_t);
776 dpv=malloc(size);
777 htod32a(dpv,value->i32);
778 break;
779 case PTP_DTC_UINT32:
780 size=sizeof(uint32_t);
781 dpv=malloc(size);
782 htod32a(dpv,value->u32);
783 break;
784 case PTP_DTC_AUINT8:
785 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
786 dpv=malloc(size);
787 htod32a(dpv,value->a.count);
788 for (i=0;i<value->a.count;i++)
789 htod8a(&dpv[4+i],value->a.v[i].u8);
790 break;
791 case PTP_DTC_AINT8:
792 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
793 dpv=malloc(size);
794 htod32a(dpv,value->a.count);
795 for (i=0;i<value->a.count;i++)
796 htod8a(&dpv[4+i],value->a.v[i].i8);
797 break;
798 case PTP_DTC_AUINT16:
799 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
800 dpv=malloc(size);
801 htod32a(dpv,value->a.count);
802 for (i=0;i<value->a.count;i++)
803 htod16a(&dpv[4+i],value->a.v[i].u16);
804 break;
805 case PTP_DTC_AINT16:
806 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
807 dpv=malloc(size);
808 htod32a(dpv,value->a.count);
809 for (i=0;i<value->a.count;i++)
810 htod16a(&dpv[4+i],value->a.v[i].i16);
811 break;
812 case PTP_DTC_AUINT32:
813 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
814 dpv=malloc(size);
815 htod32a(dpv,value->a.count);
816 for (i=0;i<value->a.count;i++)
817 htod32a(&dpv[4+i],value->a.v[i].u32);
818 break;
819 case PTP_DTC_AINT32:
820 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
821 dpv=malloc(size);
822 htod32a(dpv,value->a.count);
823 for (i=0;i<value->a.count;i++)
824 htod32a(&dpv[4+i],value->a.v[i].i32);
825 break;
826 /* XXX: other int types are unimplemented */
827 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000828 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000829 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000830 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000831 }
832 *dpvptr=dpv;
833 return size;
834}
835
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000836/*
837 PTP USB Event container unpack
838 Copyright (c) 2003 Nikolai Kopanygin
839*/
840
841#define PTP_ec_Length 0
842#define PTP_ec_Type 4
843#define PTP_ec_Code 6
844#define PTP_ec_TransId 8
845#define PTP_ec_Param1 12
846#define PTP_ec_Param2 16
847#define PTP_ec_Param3 20
848
Linus Walleijb02a0662006-04-25 08:05:09 +0000849static inline void
850ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPUSBEventContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000851{
852 if (data==NULL)
853 return;
854 ec->length=dtoh32a(&data[PTP_ec_Length]);
855 ec->type=dtoh16a(&data[PTP_ec_Type]);
856 ec->code=dtoh16a(&data[PTP_ec_Code]);
857 ec->trans_id=dtoh32a(&data[PTP_ec_TransId]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000858
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000859 if (ec->length>=(PTP_ec_Param1+4))
860 ec->param1=dtoh32a(&data[PTP_ec_Param1]);
861 else
862 ec->param1=0;
863 if (ec->length>=(PTP_ec_Param2+4))
864 ec->param2=dtoh32a(&data[PTP_ec_Param2]);
865 else
866 ec->param2=0;
867 if (ec->length>=(PTP_ec_Param3+4))
868 ec->param3=dtoh32a(&data[PTP_ec_Param3]);
869 else
870 ec->param3=0;
871}
872
873/*
874 PTP Canon Folder Entry unpack
875 Copyright (c) 2003 Nikolai Kopanygin
876*/
877#define PTP_cfe_ObjectHandle 0
878#define PTP_cfe_ObjectFormatCode 4
879#define PTP_cfe_Flags 6
880#define PTP_cfe_ObjectSize 7
881#define PTP_cfe_Time 11
882#define PTP_cfe_Filename 15
883
Linus Walleijb02a0662006-04-25 08:05:09 +0000884static inline void
885ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000886{
887 int i;
888 if (data==NULL)
889 return;
890 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
891 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
892 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +0000893 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000894 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
895 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +0000896 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
897}
898
899/*
900 PTP USB Event container unpack for Nikon events.
901*/
902#define PTP_nikon_ec_Length 0
903#define PTP_nikon_ec_Code 2
904#define PTP_nikon_ec_Param1 4
905#define PTP_nikon_ec_Size 6
906static inline void
907ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPUSBEventContainer **ec, int *cnt)
908{
909 int i;
910
911 *ec = NULL;
912 if (data == NULL)
913 return;
914 if (len < PTP_nikon_ec_Code)
915 return;
916 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
917 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
918 return;
919 *ec = malloc(sizeof(PTPUSBEventContainer)*(*cnt));
920
921 for (i=0;i<*cnt;i++) {
922 memset(&(*ec)[i],0,sizeof(PTPUSBEventContainer));
923 (*ec)[i].code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
924 (*ec)[i].param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
925 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000926}
927
928
Linus Walleijb02a0662006-04-25 08:05:09 +0000929static inline uint32_t
930ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
931 int i, len = 0;
932 uint8_t retlen;
933 unsigned char *curdata;
934
935 len = 2*(strlen(text->title)+1)+1+
936 2*(strlen(text->line[0])+1)+1+
937 2*(strlen(text->line[1])+1)+1+
938 2*(strlen(text->line[2])+1)+1+
939 2*(strlen(text->line[3])+1)+1+
940 2*(strlen(text->line[4])+1)+1+
941 4*2+2*4+2+4+2+5*4*2;
942 *data = malloc(len);
943 if (!*data) return 0;
944
945 curdata = *data;
946 htod16a(curdata,100);curdata+=2;
947 htod16a(curdata,1);curdata+=2;
948 htod16a(curdata,0);curdata+=2;
949 htod16a(curdata,1000);curdata+=2;
950
951 htod32a(curdata,0);curdata+=4;
952 htod32a(curdata,0);curdata+=4;
953
954 htod16a(curdata,6);curdata+=2;
955 htod32a(curdata,0);curdata+=4;
956
957 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
958 htod16a(curdata,0x10);curdata+=2;
959
960 for (i=0;i<5;i++) {
961 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
962 htod16a(curdata,0x10);curdata+=2;
963 htod16a(curdata,0x01);curdata+=2;
964 htod16a(curdata,0x02);curdata+=2;
965 htod16a(curdata,0x06);curdata+=2;
966 }
967 return len;
968}