blob: fb4dc4e53919782b5e7252efa9db259e35fd1ea7 [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 Walleij3bc0d7f2008-11-01 23:06:24 +00005extern void
6ptp_debug (PTPParams *params, const char *format, ...);
7
Linus Walleijb02a0662006-04-25 08:05:09 +00008static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00009htod16p (PTPParams *params, uint16_t var)
10{
11 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
12}
13
Linus Walleijb02a0662006-04-25 08:05:09 +000014static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000015htod32p (PTPParams *params, uint32_t var)
16{
17 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
18}
19
Linus Walleijb02a0662006-04-25 08:05:09 +000020static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
22{
23 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000024 htole16a(a,val);
25 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000026 htobe16a(a,val);
27}
28
Linus Walleijb02a0662006-04-25 08:05:09 +000029static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000030htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
31{
32 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000033 htole32a(a,val);
34 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000035 htobe32a(a,val);
36}
37
Linus Walleijabf54752007-07-30 19:51:54 +000038static inline void
39htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
40{
41 if (params->byteorder==PTP_DL_LE)
42 htole64a(a,val);
43 else
44 htobe64a(a,val);
45}
46
Linus Walleijb02a0662006-04-25 08:05:09 +000047static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000048dtoh16p (PTPParams *params, uint16_t var)
49{
50 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
51}
52
Linus Walleijb02a0662006-04-25 08:05:09 +000053static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000054dtoh32p (PTPParams *params, uint32_t var)
55{
56 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
57}
58
Linus Walleijabf54752007-07-30 19:51:54 +000059static inline uint64_t
60dtoh64p (PTPParams *params, uint64_t var)
61{
62 return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
63}
64
Linus Walleijb02a0662006-04-25 08:05:09 +000065static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000066dtoh16ap (PTPParams *params, unsigned char *a)
67{
68 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
69}
70
Linus Walleijb02a0662006-04-25 08:05:09 +000071static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000072dtoh32ap (PTPParams *params, unsigned char *a)
73{
74 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
75}
76
Linus Walleijb02a0662006-04-25 08:05:09 +000077static inline uint64_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000078dtoh64ap (PTPParams *params, unsigned char *a)
79{
Linus Walleijabf54752007-07-30 19:51:54 +000080 return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000081}
82
Linus Walleijb02a0662006-04-25 08:05:09 +000083#define htod8a(a,x) *(uint8_t*)(a) = x
84#define htod16a(a,x) htod16ap(params,a,x)
85#define htod32a(a,x) htod32ap(params,a,x)
Linus Walleijabf54752007-07-30 19:51:54 +000086#define htod64a(a,x) htod64ap(params,a,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000087#define htod16(x) htod16p(params,x)
88#define htod32(x) htod32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000089#define htod64(x) htod64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000090
91#define dtoh8a(x) (*(uint8_t*)(x))
92#define dtoh16a(a) dtoh16ap(params,a)
93#define dtoh32a(a) dtoh32ap(params,a)
94#define dtoh64a(a) dtoh64ap(params,a)
95#define dtoh16(x) dtoh16p(params,x)
96#define dtoh32(x) dtoh32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000097#define dtoh64(x) dtoh64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000098
99
100static inline char*
101ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000102{
Linus Walleija8a19cc2007-02-02 22:13:17 +0000103 uint8_t length;
104 uint16_t string[PTP_MAXSTRLEN+1];
105 /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
106 char loclstr[PTP_MAXSTRLEN*3+1];
107 size_t nconv, srclen, destlen;
108 char *src, *dest;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000109
Linus Walleija8a19cc2007-02-02 22:13:17 +0000110 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
111 *len = length;
112 if (length == 0) /* nothing to do? */
113 return(NULL);
114
115 /* copy to string[] to ensure correct alignment for iconv(3) */
116 memcpy(string, &data[offset+1], length * sizeof(string[0]));
117 string[length] = 0x0000U; /* be paranoid! add a terminator. */
118 loclstr[0] = '\0';
119
120 /* convert from camera UCS-2 to our locale */
121 src = (char *)string;
122 srclen = length * sizeof(string[0]);
123 dest = loclstr;
124 destlen = sizeof(loclstr)-1;
125 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen,
126 &dest, &destlen);
127 if (nconv == (size_t) -1) { /* do it the hard way */
128 int i;
129 /* try the old way, in case iconv is broken */
130 for (i=0;i<length;i++) {
131 if (dtoh16a(&data[offset+1+2*i])>127)
132 loclstr[i] = '?';
133 else
134 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000135 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000136 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000137 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000138 *dest = '\0';
139 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
140 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000141}
142
Linus Walleija823a702006-08-27 21:27:46 +0000143static inline int
144ucs2strlen(uint16_t const * const unicstr)
145{
146 int length;
147
148 /* Unicode strings are terminated with 2 * 0x00 */
149 for(length = 0; unicstr[length] != 0x0000U; length ++);
150 return length;
151}
152
153
Linus Walleijb02a0662006-04-25 08:05:09 +0000154static inline void
155ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000156{
Linus Walleija823a702006-08-27 21:27:46 +0000157 int packedlen;
158 uint16_t ucs2str[PTP_MAXSTRLEN+1];
159 char *ucs2strp = (char *) ucs2str;
160 char *stringp = string;
161 size_t nconv;
162 size_t convlen = strlen(string);
163 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
164
165 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000166 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
167 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
168 &ucs2strp, &convmax);
Linus Walleij4f40d112006-09-21 07:44:53 +0000169 if (nconv == (size_t) -1)
Linus Walleija823a702006-08-27 21:27:46 +0000170 ucs2str[0] = 0x0000U;
Linus Walleija8a19cc2007-02-02 22:13:17 +0000171 /*
172 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
173 * why do we need ucs2strlen()?
174 */
Linus Walleija823a702006-08-27 21:27:46 +0000175 packedlen = ucs2strlen(ucs2str);
176 if (packedlen > PTP_MAXSTRLEN-1) {
177 *len=0;
178 return;
179 }
Linus Walleij958441f2006-08-29 15:30:11 +0000180
Linus Walleij7f234382006-12-09 19:41:00 +0000181 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000182 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000183 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
184 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000185
186 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000187 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000188}
189
190static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000191ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000192{
Richard Low8b42ca32006-11-15 08:52:17 +0000193 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000194 size_t plen;
195 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000196
197 if (string == NULL)
198 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
199 else
200 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
201
Linus Walleij958441f2006-08-29 15:30:11 +0000202 /* returned length is in characters, then one byte for string length */
203 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000204
Linus Walleija823a702006-08-27 21:27:46 +0000205 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000206 if (!retcopy) {
207 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000208 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000209 }
Linus Walleija823a702006-08-27 21:27:46 +0000210 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000211 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000212 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000213}
214
Linus Walleijb02a0662006-04-25 08:05:09 +0000215static inline uint32_t
216ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000217{
218 uint32_t n, i=0;
219
220 n=dtoh32a(&data[offset]);
221 *array = malloc (n*sizeof(uint32_t));
222 while (n>i) {
223 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
224 i++;
225 }
226 return n;
227}
228
Linus Walleijb02a0662006-04-25 08:05:09 +0000229static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000230ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
231{
232 uint32_t i=0;
233
234 *data = malloc ((arraylen+1)*sizeof(uint32_t));
235 htod32a(&(*data)[0],arraylen);
236 for (i=0;i<arraylen;i++)
237 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
238 return (arraylen+1)*sizeof(uint32_t);
239}
240
241static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000242ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000243{
244 uint32_t n, i=0;
245
246 n=dtoh32a(&data[offset]);
247 *array = malloc (n*sizeof(uint16_t));
248 while (n>i) {
249 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
250 i++;
251 }
252 return n;
253}
254
255/* DeviceInfo pack/unpack */
256
257#define PTP_di_StandardVersion 0
258#define PTP_di_VendorExtensionID 2
259#define PTP_di_VendorExtensionVersion 6
260#define PTP_di_VendorExtensionDesc 8
261#define PTP_di_FunctionalMode 8
262#define PTP_di_OperationsSupported 10
263
Linus Walleijb02a0662006-04-25 08:05:09 +0000264static inline void
265ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000266{
267 uint8_t len;
268 unsigned int totallen;
269
Linus Walleij7347d0f2006-10-23 07:23:39 +0000270 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000271 di->VendorExtensionID =
272 dtoh32a(&data[PTP_di_VendorExtensionID]);
273 di->VendorExtensionVersion =
274 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
275 di->VendorExtensionDesc =
276 ptp_unpack_string(params, data,
277 PTP_di_VendorExtensionDesc, &len);
278 totallen=len*2+1;
279 di->FunctionalMode =
280 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
281 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
282 PTP_di_OperationsSupported+totallen,
283 &di->OperationsSupported);
284 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
285 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
286 PTP_di_OperationsSupported+totallen,
287 &di->EventsSupported);
288 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
289 di->DevicePropertiesSupported_len =
290 ptp_unpack_uint16_t_array(params, data,
291 PTP_di_OperationsSupported+totallen,
292 &di->DevicePropertiesSupported);
293 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
294 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
295 PTP_di_OperationsSupported+totallen,
296 &di->CaptureFormats);
297 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
298 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
299 PTP_di_OperationsSupported+totallen,
300 &di->ImageFormats);
301 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
302 di->Manufacturer = ptp_unpack_string(params, data,
303 PTP_di_OperationsSupported+totallen,
304 &len);
305 totallen+=len*2+1;
306 di->Model = ptp_unpack_string(params, data,
307 PTP_di_OperationsSupported+totallen,
308 &len);
309 totallen+=len*2+1;
310 di->DeviceVersion = ptp_unpack_string(params, data,
311 PTP_di_OperationsSupported+totallen,
312 &len);
313 totallen+=len*2+1;
314 di->SerialNumber = ptp_unpack_string(params, data,
315 PTP_di_OperationsSupported+totallen,
316 &len);
317}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000318
319static void
320ptp_free_DI (PTPDeviceInfo *di) {
321 if (di->SerialNumber) free (di->SerialNumber);
322 if (di->DeviceVersion) free (di->DeviceVersion);
323 if (di->Model) free (di->Model);
324 if (di->Manufacturer) free (di->Manufacturer);
325 if (di->ImageFormats) free (di->ImageFormats);
326 if (di->CaptureFormats) free (di->CaptureFormats);
327 if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
328 if (di->OperationsSupported) free (di->OperationsSupported);
329 if (di->EventsSupported) free (di->EventsSupported);
330 if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
331}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000332
333/* ObjectHandles array pack/unpack */
334
335#define PTP_oh 0
336
Linus Walleijb02a0662006-04-25 08:05:09 +0000337static inline void
338ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000339{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000340 if (len) {
341 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
342 } else {
343 oh->n = 0;
344 oh->Handler = NULL;
345 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000346}
347
348/* StoreIDs array pack/unpack */
349
350#define PTP_sids 0
351
Linus Walleijb02a0662006-04-25 08:05:09 +0000352static inline void
353ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000354{
355 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
356 &sids->Storage);
357}
358
359/* StorageInfo pack/unpack */
360
361#define PTP_si_StorageType 0
362#define PTP_si_FilesystemType 2
363#define PTP_si_AccessCapability 4
364#define PTP_si_MaxCapability 6
365#define PTP_si_FreeSpaceInBytes 14
366#define PTP_si_FreeSpaceInImages 22
367#define PTP_si_StorageDescription 26
368
Linus Walleijb02a0662006-04-25 08:05:09 +0000369static inline void
370ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000371{
372 uint8_t storagedescriptionlen;
373
374 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
375 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
376 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000377 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
378 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
379 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
380 si->StorageDescription=ptp_unpack_string(params, data,
381 PTP_si_StorageDescription, &storagedescriptionlen);
382 si->VolumeLabel=ptp_unpack_string(params, data,
383 PTP_si_StorageDescription+storagedescriptionlen*2+1,
384 &storagedescriptionlen);
385}
386
387/* ObjectInfo pack/unpack */
388
389#define PTP_oi_StorageID 0
390#define PTP_oi_ObjectFormat 4
391#define PTP_oi_ProtectionStatus 6
392#define PTP_oi_ObjectCompressedSize 8
393#define PTP_oi_ThumbFormat 12
394#define PTP_oi_ThumbCompressedSize 14
395#define PTP_oi_ThumbPixWidth 18
396#define PTP_oi_ThumbPixHeight 22
397#define PTP_oi_ImagePixWidth 26
398#define PTP_oi_ImagePixHeight 30
399#define PTP_oi_ImageBitDepth 34
400#define PTP_oi_ParentObject 38
401#define PTP_oi_AssociationType 42
402#define PTP_oi_AssociationDesc 44
403#define PTP_oi_SequenceNumber 48
404#define PTP_oi_filenamelen 52
405#define PTP_oi_Filename 53
406
Linus Walleija0323272007-01-07 12:21:30 +0000407/* the max length assuming zero length dates. We have need 3 */
408/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000409#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
410
Linus Walleijb02a0662006-04-25 08:05:09 +0000411static inline uint32_t
412ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000413{
Linus Walleijb02a0662006-04-25 08:05:09 +0000414 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000415 uint8_t filenamelen;
416 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000417 /* let's allocate some memory first; correct assuming zero length dates */
418 oidata=malloc(PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000419 /* the caller should free it after use! */
420#if 0
421 char *capture_date="20020101T010101"; /* XXX Fake date */
422#endif
Richard Lowa679b1c2006-12-29 20:08:14 +0000423 memset (oidata, 0, PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000424 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
425 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
426 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
427 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
428 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
429 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
430 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
431 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
432 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
433 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
434 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
435 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
436 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
437 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
438 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
439
440 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
441/*
442 filenamelen=(uint8_t)strlen(oi->Filename);
443 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
444 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
445 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
446 }
447*/
448 /*
449 *XXX Fake date.
450 * for example Kodak sets Capture date on the basis of EXIF data.
451 * Spec says that this field is from perspective of Initiator.
452 */
453#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
454 capturedatelen=strlen(capture_date);
455 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
456 capturedatelen+1);
457 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
458 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
459 }
460 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
461 capturedatelen+1);
462 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
463 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
464 capture_date[i];
465 }
466#endif
467 /* XXX this function should return dataset length */
468
469 *oidataptr=oidata;
Richard Lowa679b1c2006-12-29 20:08:14 +0000470 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000471}
472
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000473static time_t
474ptp_unpack_PTPTIME (const char *str) {
475 char ptpdate[40];
476 char tmp[5];
477 int ptpdatelen;
478 struct tm tm;
479
480 if (!str)
481 return 0;
482 ptpdatelen = strlen(str);
483 if (ptpdatelen >= sizeof (ptpdate))
484 return 0;
485 strcpy (ptpdate, str);
486 if (ptpdatelen<=15)
487 return 0;
488
489 memset(&tm,0,sizeof(tm));
490 strncpy (tmp, ptpdate, 4);
491 tmp[4] = 0;
492 tm.tm_year=atoi (tmp) - 1900;
493 strncpy (tmp, ptpdate + 4, 2);
494 tmp[2] = 0;
495 tm.tm_mon = atoi (tmp) - 1;
496 strncpy (tmp, ptpdate + 6, 2);
497 tmp[2] = 0;
498 tm.tm_mday = atoi (tmp);
499 strncpy (tmp, ptpdate + 9, 2);
500 tmp[2] = 0;
501 tm.tm_hour = atoi (tmp);
502 strncpy (tmp, ptpdate + 11, 2);
503 tmp[2] = 0;
504 tm.tm_min = atoi (tmp);
505 strncpy (tmp, ptpdate + 13, 2);
506 tmp[2] = 0;
507 tm.tm_sec = atoi (tmp);
508 return mktime (&tm);
509}
510
Linus Walleijb02a0662006-04-25 08:05:09 +0000511static inline void
512ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000513{
514 uint8_t filenamelen;
515 uint8_t capturedatelen;
516 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000517
518 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
519 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
520 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
521 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
522 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
523 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
524 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
525 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
526 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
527 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
528 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
529 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
530 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
531 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
532 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
533 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
534
535 capture_date = ptp_unpack_string(params, data,
536 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
537 /* subset of ISO 8601, without '.s' tenths of second and
538 * time zone
539 */
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000540 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000541 free(capture_date);
542
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000543 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000544 capture_date = ptp_unpack_string(params, data,
545 PTP_oi_filenamelen+filenamelen*2
546 +capturedatelen*2+2,&capturedatelen);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000547 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000548 free(capture_date);
549}
550
551/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000552#define CTVAL(target,func) { \
553 if (total - *offset < sizeof(target)) \
554 return 0; \
555 target = func(&data[*offset]); \
556 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000557}
558
Linus Walleijb02a0662006-04-25 08:05:09 +0000559#define RARR(val,member,func) { \
560 int n,j; \
561 if (total - *offset < sizeof(uint32_t)) \
562 return 0; \
563 n = dtoh32a (&data[*offset]); \
564 *offset += sizeof(uint32_t); \
565 \
566 val->a.count = n; \
567 val->a.v = malloc(sizeof(val->a.v[0])*n); \
568 if (!val->a.v) return 0; \
569 for (j=0;j<n;j++) \
570 CTVAL(val->a.v[j].member, func); \
571}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000572
Linus Walleijb02a0662006-04-25 08:05:09 +0000573static inline int
574ptp_unpack_DPV (
575 PTPParams *params, unsigned char* data, int *offset, int total,
576 PTPPropertyValue* value, uint16_t datatype
577) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000578 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000579 case PTP_DTC_INT8:
580 CTVAL(value->i8,dtoh8a);
581 break;
582 case PTP_DTC_UINT8:
583 CTVAL(value->u8,dtoh8a);
584 break;
585 case PTP_DTC_INT16:
586 CTVAL(value->i16,dtoh16a);
587 break;
588 case PTP_DTC_UINT16:
589 CTVAL(value->u16,dtoh16a);
590 break;
591 case PTP_DTC_INT32:
592 CTVAL(value->i32,dtoh32a);
593 break;
594 case PTP_DTC_UINT32:
595 CTVAL(value->u32,dtoh32a);
596 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000597 case PTP_DTC_INT64:
598 CTVAL(value->i64,dtoh64a);
599 break;
600 case PTP_DTC_UINT64:
601 CTVAL(value->u64,dtoh64a);
602 break;
603
Linus Walleij037a1252006-12-16 20:36:52 +0000604 case PTP_DTC_UINT128:
605 *offset += 16;
606 /*fprintf(stderr,"unhandled unpack of uint128n");*/
607 break;
608 case PTP_DTC_INT128:
609 *offset += 16;
610 /*fprintf(stderr,"unhandled unpack of int128n");*/
611 break;
612
613
614
Linus Walleijb02a0662006-04-25 08:05:09 +0000615 case PTP_DTC_AINT8:
616 RARR(value,i8,dtoh8a);
617 break;
618 case PTP_DTC_AUINT8:
619 RARR(value,u8,dtoh8a);
620 break;
621 case PTP_DTC_AUINT16:
622 RARR(value,u16,dtoh16a);
623 break;
624 case PTP_DTC_AINT16:
625 RARR(value,i16,dtoh16a);
626 break;
627 case PTP_DTC_AUINT32:
628 RARR(value,u32,dtoh32a);
629 break;
630 case PTP_DTC_AINT32:
631 RARR(value,i32,dtoh32a);
632 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000633 case PTP_DTC_AUINT64:
634 RARR(value,u64,dtoh64a);
635 break;
636 case PTP_DTC_AINT64:
637 RARR(value,i64,dtoh64a);
638 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000639 /* XXX: other int types are unimplemented */
640 /* XXX: other int arrays are unimplemented also */
641 case PTP_DTC_STR: {
642 uint8_t len;
643 /* XXX: max size */
644 value->str = ptp_unpack_string(params,data,*offset,&len);
645 *offset += len*2+1;
646 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000647 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000648 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000649 }
Linus Walleij037a1252006-12-16 20:36:52 +0000650 default:
651 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000652 }
653 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000654}
655
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000656/* Device Property pack/unpack */
657
658#define PTP_dpd_DevicePropertyCode 0
659#define PTP_dpd_DataType 2
660#define PTP_dpd_GetSet 4
661#define PTP_dpd_FactoryDefaultValue 5
662
Linus Walleijb02a0662006-04-25 08:05:09 +0000663static inline int
664ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000665{
Linus Walleijb02a0662006-04-25 08:05:09 +0000666 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000667
Linus Walleijb02a0662006-04-25 08:05:09 +0000668 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000669 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
670 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
671 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000672 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000673
674 offset = PTP_dpd_FactoryDefaultValue;
675 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
676 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000677 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
678 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000679 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
680 if (!ret) goto outofmemory;
681
682 /* if offset==0 then Data Type format is not supported by this
683 code or the Data Type is a string (with two empty strings as
684 values). In both cases Form Flag should be set to 0x00 and FORM is
685 not present. */
686
Linus Walleijb02a0662006-04-25 08:05:09 +0000687 if (offset==PTP_dpd_FactoryDefaultValue)
688 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000689
Linus Walleijb02a0662006-04-25 08:05:09 +0000690 dpd->FormFlag=dtoh8a(&data[offset]);
691 offset+=sizeof(uint8_t);
692
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000693 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000694 case PTP_DPFF_Range:
695 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
696 if (!ret) goto outofmemory;
697 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
698 if (!ret) goto outofmemory;
699 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
700 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000701 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000702 case PTP_DPFF_Enumeration: {
703 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000704#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000705 N = dtoh16a(&data[offset]);
706 offset+=sizeof(uint16_t);
707 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
708 if (!dpd->FORM.Enum.SupportedValue)
709 goto outofmemory;
710
711 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
712 for (i=0;i<N;i++) {
713 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
714
715 /* Slightly different handling here. The HP PhotoSmart 120
716 * specifies an enumeration with N in wrong endian
717 * 00 01 instead of 01 00, so we count the enum just until the
718 * the end of the packet.
719 */
720 if (!ret) {
721 if (!i)
722 goto outofmemory;
723 dpd->FORM.Enum.NumberOfValues = i;
724 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000725 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000726 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000727 }
728 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000729#undef N
730 return 1;
731outofmemory:
732 ptp_free_devicepropdesc(dpd);
733 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000734}
735
Linus Walleijb02a0662006-04-25 08:05:09 +0000736/* (MTP) Object Property pack/unpack */
737#define PTP_opd_ObjectPropertyCode 0
738#define PTP_opd_DataType 2
739#define PTP_opd_GetSet 4
740#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000741
Linus Walleijb02a0662006-04-25 08:05:09 +0000742static inline int
743ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000744{
Linus Walleijb02a0662006-04-25 08:05:09 +0000745 int offset=0, ret;
746
747 memset (opd, 0, sizeof(*opd));
748 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
749 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
750 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
751
752 offset = PTP_opd_FactoryDefaultValue;
753 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
754 if (!ret) goto outofmemory;
755
756 opd->GroupCode=dtoh32a(&data[offset]);
757 offset+=sizeof(uint32_t);
758
759 opd->FormFlag=dtoh8a(&data[offset]);
760 offset+=sizeof(uint8_t);
761
762 switch (opd->FormFlag) {
763 case PTP_OPFF_Range:
764 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
765 if (!ret) goto outofmemory;
766 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
767 if (!ret) goto outofmemory;
768 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
769 if (!ret) goto outofmemory;
770 break;
771 case PTP_OPFF_Enumeration: {
772 int i;
773#define N opd->FORM.Enum.NumberOfValues
774 N = dtoh16a(&data[offset]);
775 offset+=sizeof(uint16_t);
776 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
777 if (!opd->FORM.Enum.SupportedValue)
778 goto outofmemory;
779
780 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
781 for (i=0;i<N;i++) {
782 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
783
784 /* Slightly different handling here. The HP PhotoSmart 120
785 * specifies an enumeration with N in wrong endian
786 * 00 01 instead of 01 00, so we count the enum just until the
787 * the end of the packet.
788 */
789 if (!ret) {
790 if (!i)
791 goto outofmemory;
792 opd->FORM.Enum.NumberOfValues = i;
793 break;
794 }
795 }
796#undef N
797 }
798 }
799 return 1;
800outofmemory:
801 ptp_free_objectpropdesc(opd);
802 return 0;
803}
804
805
806static inline uint32_t
807ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
808{
809 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000810 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000811 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000812
813 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000814 case PTP_DTC_INT8:
815 size=sizeof(int8_t);
816 dpv=malloc(size);
817 htod8a(dpv,value->i8);
818 break;
819 case PTP_DTC_UINT8:
820 size=sizeof(uint8_t);
821 dpv=malloc(size);
822 htod8a(dpv,value->u8);
823 break;
824 case PTP_DTC_INT16:
825 size=sizeof(int16_t);
826 dpv=malloc(size);
827 htod16a(dpv,value->i16);
828 break;
829 case PTP_DTC_UINT16:
830 size=sizeof(uint16_t);
831 dpv=malloc(size);
832 htod16a(dpv,value->u16);
833 break;
834 case PTP_DTC_INT32:
835 size=sizeof(int32_t);
836 dpv=malloc(size);
837 htod32a(dpv,value->i32);
838 break;
839 case PTP_DTC_UINT32:
840 size=sizeof(uint32_t);
841 dpv=malloc(size);
842 htod32a(dpv,value->u32);
843 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000844 case PTP_DTC_INT64:
845 size=sizeof(int64_t);
846 dpv=malloc(size);
847 htod64a(dpv,value->i64);
848 break;
849 case PTP_DTC_UINT64:
850 size=sizeof(uint64_t);
851 dpv=malloc(size);
852 htod64a(dpv,value->u64);
853 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000854 case PTP_DTC_AUINT8:
855 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
856 dpv=malloc(size);
857 htod32a(dpv,value->a.count);
858 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000859 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000860 break;
861 case PTP_DTC_AINT8:
862 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
863 dpv=malloc(size);
864 htod32a(dpv,value->a.count);
865 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000866 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000867 break;
868 case PTP_DTC_AUINT16:
869 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
870 dpv=malloc(size);
871 htod32a(dpv,value->a.count);
872 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000873 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000874 break;
875 case PTP_DTC_AINT16:
876 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
877 dpv=malloc(size);
878 htod32a(dpv,value->a.count);
879 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000880 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000881 break;
882 case PTP_DTC_AUINT32:
883 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
884 dpv=malloc(size);
885 htod32a(dpv,value->a.count);
886 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000887 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000888 break;
889 case PTP_DTC_AINT32:
890 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
891 dpv=malloc(size);
892 htod32a(dpv,value->a.count);
893 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000894 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000895 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000896 case PTP_DTC_AUINT64:
897 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
898 dpv=malloc(size);
899 htod32a(dpv,value->a.count);
900 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000901 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +0000902 break;
903 case PTP_DTC_AINT64:
904 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
905 dpv=malloc(size);
906 htod32a(dpv,value->a.count);
907 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000908 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +0000909 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000910 /* XXX: other int types are unimplemented */
911 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000912 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000913 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000914 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000915 }
916 *dpvptr=dpv;
917 return size;
918}
919
Linus Walleij99310d42006-11-01 08:29:39 +0000920#define MAX_MTP_PROPS 127
921static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +0000922ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +0000923{
924 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000925 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +0000926 unsigned char *packedprops[MAX_MTP_PROPS];
927 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +0000928 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +0000929 uint16_t packedpropsids[MAX_MTP_PROPS];
930 uint16_t packedpropstypes[MAX_MTP_PROPS];
931 uint32_t totalsize = 0;
932 uint32_t bufp = 0;
933 uint32_t noitems = 0;
934 uint32_t i;
935
936 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +0000937 propitr = props;
938 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +0000939 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +0000940 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +0000941 totalsize += sizeof(uint32_t); /* Object ID */
942 /* Metadata type */
943 packedpropsids[noitems]=propitr->property;
944 totalsize += sizeof(uint16_t);
945 /* Data type */
946 packedpropstypes[noitems]= propitr->datatype;
947 totalsize += sizeof(uint16_t);
948 /* Add each property to be sent. */
949 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
950 totalsize += packedpropslens[noitems];
951 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000952 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +0000953 }
954
955 /* Allocate memory for the packed property list */
956 opldata = malloc(totalsize);
957
958 htod32a(&opldata[bufp],noitems);
959 bufp += 4;
960
961 /* Copy into a nice packed list */
962 for (i = 0; i < noitems; i++) {
963 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +0000964 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +0000965 bufp += sizeof(uint32_t);
966 htod16a(&opldata[bufp],packedpropsids[i]);
967 bufp += sizeof(uint16_t);
968 htod16a(&opldata[bufp],packedpropstypes[i]);
969 bufp += sizeof(uint16_t);
970 /* The copy the actual property */
971 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
972 bufp += packedpropslens[i];
973 free(packedprops[i]);
974 }
975 *opldataptr = opldata;
976 return totalsize;
977}
978
Linus Walleij1e9a0332007-09-12 19:35:56 +0000979static int
980_compare_func(const void* x, const void *y) {
981 const MTPProperties *px = x;
982 const MTPProperties *py = y;
983
984 return px->ObjectHandle - py->ObjectHandle;
985}
986
Richard Low8d82d2f2006-11-16 20:37:43 +0000987static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +0000988ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +0000989{
Linus Walleij277cd532006-11-20 14:57:46 +0000990 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +0000991 MTPProperties *props = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +0000992 int offset = 0, i;
993
994 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +0000995 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +0000996 return 0;
997 }
Linus Walleijd49955b2008-11-09 17:20:00 +0000998 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +0000999 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001000 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001001 props = malloc(prop_count * sizeof(MTPProperties));
1002 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001003 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001004 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001005 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001006 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1007 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001008 qsort (props, i, sizeof(MTPProperties),_compare_func);
1009 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001010 return i;
1011 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001012 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001013 data += sizeof(uint32_t);
1014 len -= sizeof(uint32_t);
1015
Linus Walleij1e9a0332007-09-12 19:35:56 +00001016 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001017 data += sizeof(uint16_t);
1018 len -= sizeof(uint16_t);
1019
Linus Walleij1e9a0332007-09-12 19:35:56 +00001020 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001021 data += sizeof(uint16_t);
1022 len -= sizeof(uint16_t);
1023
1024 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001025 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001026 data += offset;
1027 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001028 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001029 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1030 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001031 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001032}
1033
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001034/*
1035 PTP USB Event container unpack
1036 Copyright (c) 2003 Nikolai Kopanygin
1037*/
1038
1039#define PTP_ec_Length 0
1040#define PTP_ec_Type 4
1041#define PTP_ec_Code 6
1042#define PTP_ec_TransId 8
1043#define PTP_ec_Param1 12
1044#define PTP_ec_Param2 16
1045#define PTP_ec_Param3 20
1046
Linus Walleijb02a0662006-04-25 08:05:09 +00001047static inline void
1048ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPUSBEventContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001049{
1050 if (data==NULL)
1051 return;
1052 ec->length=dtoh32a(&data[PTP_ec_Length]);
1053 ec->type=dtoh16a(&data[PTP_ec_Type]);
1054 ec->code=dtoh16a(&data[PTP_ec_Code]);
1055 ec->trans_id=dtoh32a(&data[PTP_ec_TransId]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001056
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001057 if (ec->length>=(PTP_ec_Param1+4))
1058 ec->param1=dtoh32a(&data[PTP_ec_Param1]);
1059 else
1060 ec->param1=0;
1061 if (ec->length>=(PTP_ec_Param2+4))
1062 ec->param2=dtoh32a(&data[PTP_ec_Param2]);
1063 else
1064 ec->param2=0;
1065 if (ec->length>=(PTP_ec_Param3+4))
1066 ec->param3=dtoh32a(&data[PTP_ec_Param3]);
1067 else
1068 ec->param3=0;
1069}
1070
1071/*
1072 PTP Canon Folder Entry unpack
1073 Copyright (c) 2003 Nikolai Kopanygin
1074*/
1075#define PTP_cfe_ObjectHandle 0
1076#define PTP_cfe_ObjectFormatCode 4
1077#define PTP_cfe_Flags 6
1078#define PTP_cfe_ObjectSize 7
1079#define PTP_cfe_Time 11
1080#define PTP_cfe_Filename 15
1081
Linus Walleijb02a0662006-04-25 08:05:09 +00001082static inline void
1083ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001084{
1085 int i;
1086 if (data==NULL)
1087 return;
1088 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1089 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1090 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001091 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001092 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1093 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001094 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1095}
1096
1097/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001098 PTP EOS Changes Entry unpack
1099*/
1100#define PTP_ece_Size 0
1101#define PTP_ece_Type 4
1102
1103#define PTP_ece_Prop_Subtype 8 /* only for properties */
1104#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1105#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1106#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1107#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1108
1109#define PTP_ece_OI_ObjectID 8 /* only for objectinfos */
1110#define PTP_ece_OI_OFC 0x0c /* only for objectinfos */
1111#define PTP_ece_OI_Size 0x14 /* only for objectinfos */
1112#define PTP_ece_OI_Name 0x1c /* only for objectinfos */
1113
1114static inline int
1115ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
1116{
1117 int i = 0, entries = 0;
1118 unsigned char *curdata = data;
1119
1120 if (data==NULL)
1121 return 0;
1122 while (curdata - data < datasize) {
1123 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1124 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1125
1126 curdata += size;
1127 if ((size == 8) && (type == 0))
1128 break;
1129 entries++;
1130 }
Linus Walleij9d22ce02008-05-28 20:39:29 +00001131 *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001132 if (!*ce) return 0;
1133
1134 curdata = data;
1135 while (curdata - data < datasize) {
1136 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1137 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1138
1139 switch (type) {
1140 case 0xc186: { /* objectinfo from capture */
1141 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1142 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
1143 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
1144 (*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1145 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001146
1147 ptp_debug (params, "event %d: objectinfo oid %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001148 break;
1149 }
1150 case 0xc18a: { /* property desc */
1151 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1152 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1153 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
1154 unsigned char *data = &curdata[PTP_ece_Prop_Desc_Data];
1155 int j;
1156 PTPDevicePropDesc *dpd;
1157
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001158 ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d", i, proptype, size-PTP_ece_Prop_Desc_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001159 for (j=0;j<params->nrofcanon_props;j++)
1160 if (params->canon_props[j].proptype == proptype)
1161 break;
1162 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001163 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001164 break;
1165 }
1166 dpd = &params->canon_props[j].dpd;
1167 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001168 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1169 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
1170 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001171 break;
1172 }
1173 if (propxcnt) {
1174 dpd->FormFlag = PTP_DPFF_Enumeration;
1175 dpd->FORM.Enum.NumberOfValues = propxcnt;
1176 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1177 for (j=0;j<propxcnt;j++) {
1178 switch (dpd->DataType) {
1179 case PTP_DTC_UINT16:
1180 dpd->FORM.Enum.SupportedValue[j].u16 = dtoh16a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001181 ptp_debug (params, "event %d: suppval[%d] of %x is %x.", i, j, proptype, dtoh16a(data));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001182 break;
1183 case PTP_DTC_UINT8:
1184 dpd->FORM.Enum.SupportedValue[j].u8 = dtoh8a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001185 ptp_debug (params,"event %d: suppvalue[%d] of %x is %x", i, j, proptype, dtoh8a(data));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001186 break;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001187 default: {
1188 int k;
1189 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, fill in (val=%x).", i, dpd->DataType, proptype, dtoh32a(data));
1190 for (k=0;k<size-PTP_ece_Prop_Desc_Data;k++)
1191 ptp_debug (params, " %d: %02x", k, data[k]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001192 break;
1193 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001194 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001195 data += 4; /* might only be for propxtype 3 */
1196 }
1197 }
1198 break;
1199 }
1200 case 0xc189: /* property value */
1201 if (size >= 0xc) { /* property info */
1202 int j;
1203 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1204 unsigned char *data = &curdata[PTP_ece_Prop_Val_Data];
1205 PTPDevicePropDesc *dpd;
1206
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001207 ptp_debug (params, "event %d: EOS prop %04x info record, datasize %d", i, proptype, size-4);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001208 for (j=0;j<params->nrofcanon_props;j++)
1209 if (params->canon_props[j].proptype == proptype)
1210 break;
1211 if (j<params->nrofcanon_props) {
1212 if ( (params->canon_props[j].size != size) ||
1213 (memcmp(params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data))) {
1214 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
1215 memcpy (params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data);
1216 }
1217 } else {
1218 if (j)
1219 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1220 else
1221 params->canon_props = malloc(sizeof(params->canon_props[0]));
1222 params->canon_props[j].type = type;
1223 params->canon_props[j].proptype = proptype;
1224 params->canon_props[j].size = size;
1225 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
1226 memcpy(params->canon_props[j].data, data, size-PTP_ece_Prop_Val_Data);
1227 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1228 params->canon_props[j].dpd.GetSet = 1;
1229 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1230 params->nrofcanon_props = j+1;
1231 }
1232 dpd = &params->canon_props[j].dpd;
1233 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001234 case PTP_DPC_CANON_EOS_CameraTime:
1235 dpd->DataType = PTP_DTC_UINT32;
1236 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001237 case PTP_DPC_CANON_EOS_Aperture:
1238 case PTP_DPC_CANON_EOS_ShutterSpeed:
1239 case PTP_DPC_CANON_EOS_ISOSpeed:
1240 dpd->DataType = PTP_DTC_UINT16;
1241 break;
1242 case PTP_DPC_CANON_EOS_PictureStyle:
1243 case PTP_DPC_CANON_EOS_WhiteBalance:
1244 case PTP_DPC_CANON_EOS_MeteringMode:
1245 case PTP_DPC_CANON_EOS_ExpCompensation:
1246 dpd->DataType = PTP_DTC_UINT8;
1247 break;
1248 case PTP_DPC_CANON_EOS_Owner:
1249 dpd->DataType = PTP_DTC_STR;
1250 break;
1251 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001252 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1253 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1254 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001255 break;
1256 }
1257 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001258 case PTP_DTC_UINT32:
1259 dpd->FactoryDefaultValue.u32 = dtoh32a(data);
1260 dpd->CurrentValue.u32 = dtoh32a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001261 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001262 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001263 case PTP_DTC_UINT16:
1264 dpd->FactoryDefaultValue.u16 = dtoh16a(data);
1265 dpd->CurrentValue.u16 = dtoh16a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001266 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001267 break;
1268 case PTP_DTC_UINT8:
1269 dpd->FactoryDefaultValue.u8 = dtoh8a(data);
1270 dpd->CurrentValue.u8 = dtoh8a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001271 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001272 break;
1273 case PTP_DTC_STR: {
1274 uint8_t len = 0;
1275 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1276 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001277 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001278 break;
1279 }
1280 default:
1281 /* debug is printed in switch above this one */
1282 break;
1283 }
1284 break;
1285 }
1286 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001287 ptp_debug (params, "event %d: unknown EOS property type %04x", i, type);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001288 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1289 break;
1290 }
1291 curdata += size;
1292 i++;
Linus Walleij9d22ce02008-05-28 20:39:29 +00001293 if ((size == 8) && (type == 0))
1294 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001295 }
1296
1297 return entries;
1298}
1299
1300/*
Linus Walleijb02a0662006-04-25 08:05:09 +00001301 PTP USB Event container unpack for Nikon events.
1302*/
1303#define PTP_nikon_ec_Length 0
1304#define PTP_nikon_ec_Code 2
1305#define PTP_nikon_ec_Param1 4
1306#define PTP_nikon_ec_Size 6
1307static inline void
1308ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPUSBEventContainer **ec, int *cnt)
1309{
1310 int i;
1311
1312 *ec = NULL;
1313 if (data == NULL)
1314 return;
1315 if (len < PTP_nikon_ec_Code)
1316 return;
1317 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
1318 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
1319 return;
1320 *ec = malloc(sizeof(PTPUSBEventContainer)*(*cnt));
1321
1322 for (i=0;i<*cnt;i++) {
1323 memset(&(*ec)[i],0,sizeof(PTPUSBEventContainer));
1324 (*ec)[i].code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
1325 (*ec)[i].param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
1326 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001327}
1328
1329
Linus Walleijb02a0662006-04-25 08:05:09 +00001330static inline uint32_t
1331ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
1332 int i, len = 0;
1333 uint8_t retlen;
1334 unsigned char *curdata;
1335
1336 len = 2*(strlen(text->title)+1)+1+
1337 2*(strlen(text->line[0])+1)+1+
1338 2*(strlen(text->line[1])+1)+1+
1339 2*(strlen(text->line[2])+1)+1+
1340 2*(strlen(text->line[3])+1)+1+
1341 2*(strlen(text->line[4])+1)+1+
1342 4*2+2*4+2+4+2+5*4*2;
1343 *data = malloc(len);
1344 if (!*data) return 0;
1345
1346 curdata = *data;
1347 htod16a(curdata,100);curdata+=2;
1348 htod16a(curdata,1);curdata+=2;
1349 htod16a(curdata,0);curdata+=2;
1350 htod16a(curdata,1000);curdata+=2;
1351
1352 htod32a(curdata,0);curdata+=4;
1353 htod32a(curdata,0);curdata+=4;
1354
1355 htod16a(curdata,6);curdata+=2;
1356 htod32a(curdata,0);curdata+=4;
1357
1358 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1359 htod16a(curdata,0x10);curdata+=2;
1360
1361 for (i=0;i<5;i++) {
1362 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1363 htod16a(curdata,0x10);curdata+=2;
1364 htod16a(curdata,0x01);curdata+=2;
1365 htod16a(curdata,0x02);curdata+=2;
1366 htod16a(curdata,0x06);curdata+=2;
1367 }
1368 return len;
1369}
Linus Walleij7347d0f2006-10-23 07:23:39 +00001370
1371#define ptp_canon_dir_version 0x00
1372#define ptp_canon_dir_ofc 0x02
1373#define ptp_canon_dir_unk1 0x04
1374#define ptp_canon_dir_objectid 0x08
1375#define ptp_canon_dir_parentid 0x0c
1376#define ptp_canon_dir_previd 0x10 /* in same dir */
1377#define ptp_canon_dir_nextid 0x14 /* in same dir */
1378#define ptp_canon_dir_nextchild 0x18 /* down one dir */
1379#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
1380#define ptp_canon_dir_name 0x20
1381#define ptp_canon_dir_flags 0x2c
1382#define ptp_canon_dir_size 0x30
1383#define ptp_canon_dir_unixtime 0x34
1384#define ptp_canon_dir_year 0x38
1385#define ptp_canon_dir_month 0x39
1386#define ptp_canon_dir_mday 0x3a
1387#define ptp_canon_dir_hour 0x3b
1388#define ptp_canon_dir_minute 0x3c
1389#define ptp_canon_dir_second 0x3d
1390#define ptp_canon_dir_unk2 0x3e
1391#define ptp_canon_dir_thumbsize 0x40
1392#define ptp_canon_dir_width 0x44
1393#define ptp_canon_dir_height 0x48
1394
1395static inline uint16_t
1396ptp_unpack_canon_directory (
1397 PTPParams *params,
1398 unsigned char *dir,
1399 uint32_t cnt,
1400 PTPObjectHandles *handles,
1401 PTPObjectInfo **oinfos, /* size(handles->n) */
1402 uint32_t **flags /* size(handles->n) */
1403) {
1404 unsigned int i, j, nrofobs = 0, curob = 0;
1405
1406#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
1407 for (i=0;i<cnt;i++)
1408 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
1409 handles->n = nrofobs;
1410 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
1411 if (!handles->Handler) return PTP_RC_GeneralError;
1412 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
1413 if (!*oinfos) return PTP_RC_GeneralError;
1414 *flags = calloc(sizeof((*flags)[0]),nrofobs);
1415 if (!*flags) return PTP_RC_GeneralError;
1416
1417 /* Migrate data into objects ids, handles into
1418 * the object handler array.
1419 */
1420 curob = 0;
1421 for (i=0;i<cnt;i++) {
1422 unsigned char *cur = dir+i*0x4c;
1423 PTPObjectInfo *oi = (*oinfos)+curob;
1424
1425 if (!ISOBJECT(cur))
1426 continue;
1427
1428 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
1429 oi->StorageID = 0xffffffff;
1430 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
1431 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
1432 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
1433 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
1434 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
1435 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
1436 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
1437 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
1438 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
1439 curob++;
1440 }
1441 /* Walk over Storage ID entries and distribute the IDs to
1442 * the parent objects. */
1443 for (i=0;i<cnt;i++) {
1444 unsigned char *cur = dir+i*0x4c;
1445 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1446
1447 if (ISOBJECT(cur))
1448 continue;
1449 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1450 if (j == handles->n) continue;
1451 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
1452 }
1453 /* Walk over all objects and distribute the storage ids */
1454 while (1) {
1455 int changed = 0;
1456 for (i=0;i<cnt;i++) {
1457 unsigned char *cur = dir+i*0x4c;
1458 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
1459 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
1460 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1461 uint32_t storageid;
1462
1463 if (!ISOBJECT(cur))
1464 continue;
1465 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
1466 if (j == handles->n) {
1467 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
1468 continue;
1469 }
1470 storageid = (*oinfos)[j].StorageID;
1471 if (storageid == 0xffffffff) continue;
1472 if (nextoid != 0xffffffff) {
1473 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
1474 if (j == handles->n) {
1475 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
1476 continue;
1477 }
1478 if ((*oinfos)[j].StorageID == 0xffffffff) {
1479 (*oinfos)[j].StorageID = storageid;
1480 changed++;
1481 }
1482 }
1483 if (nextchild != 0xffffffff) {
1484 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1485 if (j == handles->n) {
1486 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
1487 continue;
1488 }
1489 if ((*oinfos)[j].StorageID == 0xffffffff) {
1490 (*oinfos)[j].StorageID = storageid;
1491 changed++;
1492 }
1493 }
1494 }
1495 /* Check if we:
1496 * - changed no entry (nothing more to do)
1497 * - changed all of them at once (usually happens)
1498 * break if we do.
1499 */
1500 if (!changed || (changed==nrofobs-1))
1501 break;
1502 }
1503#undef ISOBJECT
1504 return PTP_RC_OK;
1505}
1506