blob: bfe7fe212c015b9c97bc4cf0395e05c7a4e08077 [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 Walleij6db174f2009-05-09 13:15:26 +00003#ifdef HAVE_ICONV
Linus Walleija823a702006-08-27 21:27:46 +00004#include <iconv.h>
Linus Walleij6db174f2009-05-09 13:15:26 +00005#endif
Linus Walleija823a702006-08-27 21:27:46 +00006
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00007extern void
8ptp_debug (PTPParams *params, const char *format, ...);
9
Linus Walleijb02a0662006-04-25 08:05:09 +000010static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000011htod16p (PTPParams *params, uint16_t var)
12{
13 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
14}
15
Linus Walleijb02a0662006-04-25 08:05:09 +000016static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000017htod32p (PTPParams *params, uint32_t var)
18{
19 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
20}
21
Linus Walleijb02a0662006-04-25 08:05:09 +000022static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000023htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
24{
25 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000026 htole16a(a,val);
27 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000028 htobe16a(a,val);
29}
30
Linus Walleijb02a0662006-04-25 08:05:09 +000031static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000032htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
33{
34 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000035 htole32a(a,val);
36 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000037 htobe32a(a,val);
38}
39
Linus Walleijabf54752007-07-30 19:51:54 +000040static inline void
41htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
42{
43 if (params->byteorder==PTP_DL_LE)
44 htole64a(a,val);
45 else
46 htobe64a(a,val);
47}
48
Linus Walleijb02a0662006-04-25 08:05:09 +000049static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000050dtoh16p (PTPParams *params, uint16_t var)
51{
52 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
53}
54
Linus Walleijb02a0662006-04-25 08:05:09 +000055static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000056dtoh32p (PTPParams *params, uint32_t var)
57{
58 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
59}
60
Linus Walleijabf54752007-07-30 19:51:54 +000061static inline uint64_t
62dtoh64p (PTPParams *params, uint64_t var)
63{
64 return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
65}
66
Linus Walleijb02a0662006-04-25 08:05:09 +000067static inline uint16_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000068dtoh16ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000069{
70 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
71}
72
Linus Walleijb02a0662006-04-25 08:05:09 +000073static inline uint32_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000074dtoh32ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000075{
76 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
77}
78
Linus Walleijb02a0662006-04-25 08:05:09 +000079static inline uint64_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000080dtoh64ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000081{
Linus Walleijabf54752007-07-30 19:51:54 +000082 return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000083}
84
Linus Walleijb02a0662006-04-25 08:05:09 +000085#define htod8a(a,x) *(uint8_t*)(a) = x
86#define htod16a(a,x) htod16ap(params,a,x)
87#define htod32a(a,x) htod32ap(params,a,x)
Linus Walleijabf54752007-07-30 19:51:54 +000088#define htod64a(a,x) htod64ap(params,a,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000089#define htod16(x) htod16p(params,x)
90#define htod32(x) htod32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000091#define htod64(x) htod64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000092
93#define dtoh8a(x) (*(uint8_t*)(x))
94#define dtoh16a(a) dtoh16ap(params,a)
95#define dtoh32a(a) dtoh32ap(params,a)
96#define dtoh64a(a) dtoh64ap(params,a)
97#define dtoh16(x) dtoh16p(params,x)
98#define dtoh32(x) dtoh32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000099#define dtoh64(x) dtoh64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +0000100
101
102static inline char*
103ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000104{
Linus Walleija8a19cc2007-02-02 22:13:17 +0000105 uint8_t length;
106 uint16_t string[PTP_MAXSTRLEN+1];
107 /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
108 char loclstr[PTP_MAXSTRLEN*3+1];
109 size_t nconv, srclen, destlen;
110 char *src, *dest;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000111
Linus Walleija8a19cc2007-02-02 22:13:17 +0000112 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
113 *len = length;
114 if (length == 0) /* nothing to do? */
115 return(NULL);
116
117 /* copy to string[] to ensure correct alignment for iconv(3) */
118 memcpy(string, &data[offset+1], length * sizeof(string[0]));
119 string[length] = 0x0000U; /* be paranoid! add a terminator. */
120 loclstr[0] = '\0';
121
122 /* convert from camera UCS-2 to our locale */
123 src = (char *)string;
124 srclen = length * sizeof(string[0]);
125 dest = loclstr;
126 destlen = sizeof(loclstr)-1;
Linus Walleij6db174f2009-05-09 13:15:26 +0000127 nconv = (size_t)-1;
128#ifdef HAVE_ICONV
Linus Walleija8a19cc2007-02-02 22:13:17 +0000129 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen,
130 &dest, &destlen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000131#endif
Linus Walleija8a19cc2007-02-02 22:13:17 +0000132 if (nconv == (size_t) -1) { /* do it the hard way */
133 int i;
134 /* try the old way, in case iconv is broken */
135 for (i=0;i<length;i++) {
136 if (dtoh16a(&data[offset+1+2*i])>127)
137 loclstr[i] = '?';
138 else
139 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000140 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000141 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000142 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000143 *dest = '\0';
144 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
145 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000146}
147
Linus Walleija823a702006-08-27 21:27:46 +0000148static inline int
149ucs2strlen(uint16_t const * const unicstr)
150{
151 int length;
152
153 /* Unicode strings are terminated with 2 * 0x00 */
154 for(length = 0; unicstr[length] != 0x0000U; length ++);
155 return length;
156}
157
158
Linus Walleijb02a0662006-04-25 08:05:09 +0000159static inline void
160ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000161{
Linus Walleija823a702006-08-27 21:27:46 +0000162 int packedlen;
163 uint16_t ucs2str[PTP_MAXSTRLEN+1];
164 char *ucs2strp = (char *) ucs2str;
Linus Walleija823a702006-08-27 21:27:46 +0000165 size_t convlen = strlen(string);
Linus Walleija823a702006-08-27 21:27:46 +0000166
167 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000168 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
Linus Walleij6db174f2009-05-09 13:15:26 +0000169#ifdef HAVE_ICONV
170 {
171 size_t nconv;
172 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
173 char *stringp = string;
174
175 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
176 &ucs2strp, &convmax);
177 if (nconv == (size_t) -1)
178 ucs2str[0] = 0x0000U;
179 }
180#else
181 {
182 int i;
183 for (i=0;i<convlen;i++) {
184 ucs2str[i] = string[i];
185 }
186 ucs2str[convlen] = 0;
187 }
188#endif
Linus Walleija8a19cc2007-02-02 22:13:17 +0000189 /*
190 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
191 * why do we need ucs2strlen()?
192 */
Linus Walleija823a702006-08-27 21:27:46 +0000193 packedlen = ucs2strlen(ucs2str);
194 if (packedlen > PTP_MAXSTRLEN-1) {
195 *len=0;
196 return;
197 }
Linus Walleij958441f2006-08-29 15:30:11 +0000198
Linus Walleij7f234382006-12-09 19:41:00 +0000199 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000200 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000201 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
202 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000203
204 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000205 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000206}
207
208static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000209ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000210{
Richard Low8b42ca32006-11-15 08:52:17 +0000211 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000212 size_t plen;
213 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000214
215 if (string == NULL)
216 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
217 else
218 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
219
Linus Walleij958441f2006-08-29 15:30:11 +0000220 /* returned length is in characters, then one byte for string length */
221 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000222
Linus Walleija823a702006-08-27 21:27:46 +0000223 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000224 if (!retcopy) {
225 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000226 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000227 }
Linus Walleija823a702006-08-27 21:27:46 +0000228 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000229 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000230 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000231}
232
Linus Walleijb02a0662006-04-25 08:05:09 +0000233static inline uint32_t
234ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000235{
236 uint32_t n, i=0;
237
238 n=dtoh32a(&data[offset]);
239 *array = malloc (n*sizeof(uint32_t));
240 while (n>i) {
241 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
242 i++;
243 }
244 return n;
245}
246
Linus Walleijb02a0662006-04-25 08:05:09 +0000247static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000248ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
249{
250 uint32_t i=0;
251
252 *data = malloc ((arraylen+1)*sizeof(uint32_t));
253 htod32a(&(*data)[0],arraylen);
254 for (i=0;i<arraylen;i++)
255 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
256 return (arraylen+1)*sizeof(uint32_t);
257}
258
259static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000260ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000261{
262 uint32_t n, i=0;
263
264 n=dtoh32a(&data[offset]);
265 *array = malloc (n*sizeof(uint16_t));
266 while (n>i) {
267 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
268 i++;
269 }
270 return n;
271}
272
273/* DeviceInfo pack/unpack */
274
275#define PTP_di_StandardVersion 0
276#define PTP_di_VendorExtensionID 2
277#define PTP_di_VendorExtensionVersion 6
278#define PTP_di_VendorExtensionDesc 8
279#define PTP_di_FunctionalMode 8
280#define PTP_di_OperationsSupported 10
281
Linus Walleijb02a0662006-04-25 08:05:09 +0000282static inline void
283ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000284{
285 uint8_t len;
286 unsigned int totallen;
Linus Walleij7e756532009-05-06 21:25:09 +0000287
Linus Walleijd4637502009-06-14 23:03:33 +0000288 if (!data) return;
289 if (datalen < 12) return;
Linus Walleij7347d0f2006-10-23 07:23:39 +0000290 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000291 di->VendorExtensionID =
292 dtoh32a(&data[PTP_di_VendorExtensionID]);
293 di->VendorExtensionVersion =
294 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
295 di->VendorExtensionDesc =
296 ptp_unpack_string(params, data,
297 PTP_di_VendorExtensionDesc, &len);
298 totallen=len*2+1;
299 di->FunctionalMode =
300 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
301 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
302 PTP_di_OperationsSupported+totallen,
303 &di->OperationsSupported);
304 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
305 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
306 PTP_di_OperationsSupported+totallen,
307 &di->EventsSupported);
308 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
309 di->DevicePropertiesSupported_len =
310 ptp_unpack_uint16_t_array(params, data,
311 PTP_di_OperationsSupported+totallen,
312 &di->DevicePropertiesSupported);
313 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
314 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
315 PTP_di_OperationsSupported+totallen,
316 &di->CaptureFormats);
317 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
318 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
319 PTP_di_OperationsSupported+totallen,
320 &di->ImageFormats);
321 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
322 di->Manufacturer = ptp_unpack_string(params, data,
323 PTP_di_OperationsSupported+totallen,
324 &len);
325 totallen+=len*2+1;
326 di->Model = ptp_unpack_string(params, data,
327 PTP_di_OperationsSupported+totallen,
328 &len);
329 totallen+=len*2+1;
330 di->DeviceVersion = ptp_unpack_string(params, data,
331 PTP_di_OperationsSupported+totallen,
332 &len);
333 totallen+=len*2+1;
334 di->SerialNumber = ptp_unpack_string(params, data,
335 PTP_di_OperationsSupported+totallen,
336 &len);
337}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000338
339static void
340ptp_free_DI (PTPDeviceInfo *di) {
341 if (di->SerialNumber) free (di->SerialNumber);
342 if (di->DeviceVersion) free (di->DeviceVersion);
343 if (di->Model) free (di->Model);
344 if (di->Manufacturer) free (di->Manufacturer);
345 if (di->ImageFormats) free (di->ImageFormats);
346 if (di->CaptureFormats) free (di->CaptureFormats);
347 if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
348 if (di->OperationsSupported) free (di->OperationsSupported);
349 if (di->EventsSupported) free (di->EventsSupported);
350 if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
351}
Linus Walleij7e756532009-05-06 21:25:09 +0000352
353/* EOS Device Info unpack */
354static inline void
355ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
356{
357 int totallen = 4;
358 if (datalen < 8) return;
359
360 /* uint32_t struct len - ignore */
361 di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
362 totallen, &di->EventsSupported);
363 if (!di->EventsSupported) return;
364 totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
365 if (totallen >= datalen) return;
366
367 di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
368 totallen, &di->DevicePropertiesSupported);
369 if (!di->DevicePropertiesSupported) return;
370 totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
371 if (totallen >= datalen) return;
372
373 di->unk_len = ptp_unpack_uint32_t_array(params, data,
374 totallen, &di->unk);
375 if (!di->unk) return;
376 totallen += di->unk_len*sizeof(uint32_t)+4;
377 return;
378}
Linus Walleij0d762cc2010-04-04 23:34:27 +0000379
380static inline void
381ptp_free_EOS_DI (PTPCanonEOSDeviceInfo *di)
382{
383 free (di->EventsSupported);
384 free (di->DevicePropertiesSupported);
385 free (di->unk);
386}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000387
388/* ObjectHandles array pack/unpack */
389
390#define PTP_oh 0
391
Linus Walleijb02a0662006-04-25 08:05:09 +0000392static inline void
393ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000394{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000395 if (len) {
396 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
397 } else {
398 oh->n = 0;
399 oh->Handler = NULL;
400 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000401}
402
403/* StoreIDs array pack/unpack */
404
405#define PTP_sids 0
406
Linus Walleijb02a0662006-04-25 08:05:09 +0000407static inline void
408ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000409{
410 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
411 &sids->Storage);
412}
413
414/* StorageInfo pack/unpack */
415
416#define PTP_si_StorageType 0
417#define PTP_si_FilesystemType 2
418#define PTP_si_AccessCapability 4
419#define PTP_si_MaxCapability 6
420#define PTP_si_FreeSpaceInBytes 14
421#define PTP_si_FreeSpaceInImages 22
422#define PTP_si_StorageDescription 26
423
Linus Walleijb02a0662006-04-25 08:05:09 +0000424static inline void
425ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000426{
427 uint8_t storagedescriptionlen;
428
429 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
430 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
431 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000432 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
433 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
434 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
435 si->StorageDescription=ptp_unpack_string(params, data,
436 PTP_si_StorageDescription, &storagedescriptionlen);
437 si->VolumeLabel=ptp_unpack_string(params, data,
438 PTP_si_StorageDescription+storagedescriptionlen*2+1,
439 &storagedescriptionlen);
440}
441
442/* ObjectInfo pack/unpack */
443
444#define PTP_oi_StorageID 0
445#define PTP_oi_ObjectFormat 4
446#define PTP_oi_ProtectionStatus 6
447#define PTP_oi_ObjectCompressedSize 8
448#define PTP_oi_ThumbFormat 12
449#define PTP_oi_ThumbCompressedSize 14
450#define PTP_oi_ThumbPixWidth 18
451#define PTP_oi_ThumbPixHeight 22
452#define PTP_oi_ImagePixWidth 26
453#define PTP_oi_ImagePixHeight 30
454#define PTP_oi_ImageBitDepth 34
455#define PTP_oi_ParentObject 38
456#define PTP_oi_AssociationType 42
457#define PTP_oi_AssociationDesc 44
458#define PTP_oi_SequenceNumber 48
459#define PTP_oi_filenamelen 52
460#define PTP_oi_Filename 53
461
Linus Walleija0323272007-01-07 12:21:30 +0000462/* the max length assuming zero length dates. We have need 3 */
463/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000464#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
465
Linus Walleijb02a0662006-04-25 08:05:09 +0000466static inline uint32_t
467ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000468{
Linus Walleijb02a0662006-04-25 08:05:09 +0000469 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000470 uint8_t filenamelen;
471 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000472 /* let's allocate some memory first; correct assuming zero length dates */
473 oidata=malloc(PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000474 /* the caller should free it after use! */
475#if 0
476 char *capture_date="20020101T010101"; /* XXX Fake date */
477#endif
Richard Lowa679b1c2006-12-29 20:08:14 +0000478 memset (oidata, 0, PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000479 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
480 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
481 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
482 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
483 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
484 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
485 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
486 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
487 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
488 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
489 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
490 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
491 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
492 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
493 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
494
495 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
496/*
497 filenamelen=(uint8_t)strlen(oi->Filename);
498 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
499 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
500 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
501 }
502*/
503 /*
504 *XXX Fake date.
505 * for example Kodak sets Capture date on the basis of EXIF data.
506 * Spec says that this field is from perspective of Initiator.
507 */
508#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
509 capturedatelen=strlen(capture_date);
510 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
511 capturedatelen+1);
512 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
513 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
514 }
515 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
516 capturedatelen+1);
517 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
518 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
519 capture_date[i];
520 }
521#endif
522 /* XXX this function should return dataset length */
523
524 *oidataptr=oidata;
Richard Lowa679b1c2006-12-29 20:08:14 +0000525 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000526}
527
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000528static time_t
Linus Walleij6db174f2009-05-09 13:15:26 +0000529ptp_unpack_PTPTIME (const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000530 char ptpdate[40];
531 char tmp[5];
532 int ptpdatelen;
533 struct tm tm;
534
535 if (!str)
536 return 0;
537 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000538 if (ptpdatelen >= sizeof (ptpdate)) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000539 /*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000540 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000541 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000542 strcpy (ptpdate, str);
Linus Walleij7e756532009-05-06 21:25:09 +0000543 if (ptpdatelen<15) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000544 /*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000545 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000546 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000547
548 memset(&tm,0,sizeof(tm));
549 strncpy (tmp, ptpdate, 4);
550 tmp[4] = 0;
551 tm.tm_year=atoi (tmp) - 1900;
552 strncpy (tmp, ptpdate + 4, 2);
553 tmp[2] = 0;
554 tm.tm_mon = atoi (tmp) - 1;
555 strncpy (tmp, ptpdate + 6, 2);
556 tmp[2] = 0;
557 tm.tm_mday = atoi (tmp);
558 strncpy (tmp, ptpdate + 9, 2);
559 tmp[2] = 0;
560 tm.tm_hour = atoi (tmp);
561 strncpy (tmp, ptpdate + 11, 2);
562 tmp[2] = 0;
563 tm.tm_min = atoi (tmp);
564 strncpy (tmp, ptpdate + 13, 2);
565 tmp[2] = 0;
566 tm.tm_sec = atoi (tmp);
567 return mktime (&tm);
568}
569
Linus Walleijb02a0662006-04-25 08:05:09 +0000570static inline void
571ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000572{
573 uint8_t filenamelen;
574 uint8_t capturedatelen;
575 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000576
577 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
578 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
579 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
580 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
581 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
582 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
583 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
584 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
585 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
586 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
587 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
588 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
589 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
590 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
591 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
592 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
593
594 capture_date = ptp_unpack_string(params, data,
595 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
596 /* subset of ISO 8601, without '.s' tenths of second and
597 * time zone
598 */
Linus Walleij6db174f2009-05-09 13:15:26 +0000599 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000600 free(capture_date);
601
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000602 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000603 capture_date = ptp_unpack_string(params, data,
604 PTP_oi_filenamelen+filenamelen*2
605 +capturedatelen*2+2,&capturedatelen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000606 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000607 free(capture_date);
608}
609
610/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000611#define CTVAL(target,func) { \
612 if (total - *offset < sizeof(target)) \
613 return 0; \
614 target = func(&data[*offset]); \
615 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000616}
617
Linus Walleijb02a0662006-04-25 08:05:09 +0000618#define RARR(val,member,func) { \
619 int n,j; \
620 if (total - *offset < sizeof(uint32_t)) \
621 return 0; \
622 n = dtoh32a (&data[*offset]); \
623 *offset += sizeof(uint32_t); \
624 \
625 val->a.count = n; \
626 val->a.v = malloc(sizeof(val->a.v[0])*n); \
627 if (!val->a.v) return 0; \
628 for (j=0;j<n;j++) \
629 CTVAL(val->a.v[j].member, func); \
630}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000631
Linus Walleijb02a0662006-04-25 08:05:09 +0000632static inline int
633ptp_unpack_DPV (
634 PTPParams *params, unsigned char* data, int *offset, int total,
635 PTPPropertyValue* value, uint16_t datatype
636) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000637 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000638 case PTP_DTC_INT8:
639 CTVAL(value->i8,dtoh8a);
640 break;
641 case PTP_DTC_UINT8:
642 CTVAL(value->u8,dtoh8a);
643 break;
644 case PTP_DTC_INT16:
645 CTVAL(value->i16,dtoh16a);
646 break;
647 case PTP_DTC_UINT16:
648 CTVAL(value->u16,dtoh16a);
649 break;
650 case PTP_DTC_INT32:
651 CTVAL(value->i32,dtoh32a);
652 break;
653 case PTP_DTC_UINT32:
654 CTVAL(value->u32,dtoh32a);
655 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000656 case PTP_DTC_INT64:
657 CTVAL(value->i64,dtoh64a);
658 break;
659 case PTP_DTC_UINT64:
660 CTVAL(value->u64,dtoh64a);
661 break;
662
Linus Walleij037a1252006-12-16 20:36:52 +0000663 case PTP_DTC_UINT128:
664 *offset += 16;
665 /*fprintf(stderr,"unhandled unpack of uint128n");*/
666 break;
667 case PTP_DTC_INT128:
668 *offset += 16;
669 /*fprintf(stderr,"unhandled unpack of int128n");*/
670 break;
671
672
673
Linus Walleijb02a0662006-04-25 08:05:09 +0000674 case PTP_DTC_AINT8:
675 RARR(value,i8,dtoh8a);
676 break;
677 case PTP_DTC_AUINT8:
678 RARR(value,u8,dtoh8a);
679 break;
680 case PTP_DTC_AUINT16:
681 RARR(value,u16,dtoh16a);
682 break;
683 case PTP_DTC_AINT16:
684 RARR(value,i16,dtoh16a);
685 break;
686 case PTP_DTC_AUINT32:
687 RARR(value,u32,dtoh32a);
688 break;
689 case PTP_DTC_AINT32:
690 RARR(value,i32,dtoh32a);
691 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000692 case PTP_DTC_AUINT64:
693 RARR(value,u64,dtoh64a);
694 break;
695 case PTP_DTC_AINT64:
696 RARR(value,i64,dtoh64a);
697 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000698 /* XXX: other int types are unimplemented */
699 /* XXX: other int arrays are unimplemented also */
700 case PTP_DTC_STR: {
701 uint8_t len;
702 /* XXX: max size */
703 value->str = ptp_unpack_string(params,data,*offset,&len);
704 *offset += len*2+1;
705 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000706 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000707 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000708 }
Linus Walleij037a1252006-12-16 20:36:52 +0000709 default:
710 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000711 }
712 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000713}
714
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000715/* Device Property pack/unpack */
716
717#define PTP_dpd_DevicePropertyCode 0
718#define PTP_dpd_DataType 2
719#define PTP_dpd_GetSet 4
720#define PTP_dpd_FactoryDefaultValue 5
721
Linus Walleijb02a0662006-04-25 08:05:09 +0000722static inline int
723ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000724{
Linus Walleijb02a0662006-04-25 08:05:09 +0000725 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000726
Linus Walleijb02a0662006-04-25 08:05:09 +0000727 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000728 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
729 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
730 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000731 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000732
733 offset = PTP_dpd_FactoryDefaultValue;
734 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
735 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000736 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
737 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000738 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
739 if (!ret) goto outofmemory;
740
741 /* if offset==0 then Data Type format is not supported by this
742 code or the Data Type is a string (with two empty strings as
743 values). In both cases Form Flag should be set to 0x00 and FORM is
744 not present. */
745
Linus Walleijb02a0662006-04-25 08:05:09 +0000746 if (offset==PTP_dpd_FactoryDefaultValue)
747 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000748
Linus Walleijb02a0662006-04-25 08:05:09 +0000749 dpd->FormFlag=dtoh8a(&data[offset]);
750 offset+=sizeof(uint8_t);
751
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000752 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000753 case PTP_DPFF_Range:
754 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
755 if (!ret) goto outofmemory;
756 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
757 if (!ret) goto outofmemory;
758 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
759 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000760 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000761 case PTP_DPFF_Enumeration: {
762 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000763#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000764 N = dtoh16a(&data[offset]);
765 offset+=sizeof(uint16_t);
766 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
767 if (!dpd->FORM.Enum.SupportedValue)
768 goto outofmemory;
769
770 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
771 for (i=0;i<N;i++) {
772 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
773
774 /* Slightly different handling here. The HP PhotoSmart 120
775 * specifies an enumeration with N in wrong endian
776 * 00 01 instead of 01 00, so we count the enum just until the
777 * the end of the packet.
778 */
779 if (!ret) {
780 if (!i)
781 goto outofmemory;
782 dpd->FORM.Enum.NumberOfValues = i;
783 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000784 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000785 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000786 }
787 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000788#undef N
789 return 1;
790outofmemory:
791 ptp_free_devicepropdesc(dpd);
792 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000793}
794
Linus Walleijb02a0662006-04-25 08:05:09 +0000795/* (MTP) Object Property pack/unpack */
796#define PTP_opd_ObjectPropertyCode 0
797#define PTP_opd_DataType 2
798#define PTP_opd_GetSet 4
799#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000800
Linus Walleijb02a0662006-04-25 08:05:09 +0000801static inline int
802ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000803{
Linus Walleijb02a0662006-04-25 08:05:09 +0000804 int offset=0, ret;
805
806 memset (opd, 0, sizeof(*opd));
807 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
808 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
809 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
810
811 offset = PTP_opd_FactoryDefaultValue;
812 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
813 if (!ret) goto outofmemory;
814
815 opd->GroupCode=dtoh32a(&data[offset]);
816 offset+=sizeof(uint32_t);
817
818 opd->FormFlag=dtoh8a(&data[offset]);
819 offset+=sizeof(uint8_t);
820
821 switch (opd->FormFlag) {
822 case PTP_OPFF_Range:
823 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
824 if (!ret) goto outofmemory;
825 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
826 if (!ret) goto outofmemory;
827 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
828 if (!ret) goto outofmemory;
829 break;
830 case PTP_OPFF_Enumeration: {
831 int i;
832#define N opd->FORM.Enum.NumberOfValues
833 N = dtoh16a(&data[offset]);
834 offset+=sizeof(uint16_t);
835 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
836 if (!opd->FORM.Enum.SupportedValue)
837 goto outofmemory;
838
839 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
840 for (i=0;i<N;i++) {
841 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
842
843 /* Slightly different handling here. The HP PhotoSmart 120
844 * specifies an enumeration with N in wrong endian
845 * 00 01 instead of 01 00, so we count the enum just until the
846 * the end of the packet.
847 */
848 if (!ret) {
849 if (!i)
850 goto outofmemory;
851 opd->FORM.Enum.NumberOfValues = i;
852 break;
853 }
854 }
855#undef N
856 }
857 }
858 return 1;
859outofmemory:
860 ptp_free_objectpropdesc(opd);
861 return 0;
862}
863
864
865static inline uint32_t
866ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
867{
868 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000869 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000870 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000871
872 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000873 case PTP_DTC_INT8:
874 size=sizeof(int8_t);
875 dpv=malloc(size);
876 htod8a(dpv,value->i8);
877 break;
878 case PTP_DTC_UINT8:
879 size=sizeof(uint8_t);
880 dpv=malloc(size);
881 htod8a(dpv,value->u8);
882 break;
883 case PTP_DTC_INT16:
884 size=sizeof(int16_t);
885 dpv=malloc(size);
886 htod16a(dpv,value->i16);
887 break;
888 case PTP_DTC_UINT16:
889 size=sizeof(uint16_t);
890 dpv=malloc(size);
891 htod16a(dpv,value->u16);
892 break;
893 case PTP_DTC_INT32:
894 size=sizeof(int32_t);
895 dpv=malloc(size);
896 htod32a(dpv,value->i32);
897 break;
898 case PTP_DTC_UINT32:
899 size=sizeof(uint32_t);
900 dpv=malloc(size);
901 htod32a(dpv,value->u32);
902 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000903 case PTP_DTC_INT64:
904 size=sizeof(int64_t);
905 dpv=malloc(size);
906 htod64a(dpv,value->i64);
907 break;
908 case PTP_DTC_UINT64:
909 size=sizeof(uint64_t);
910 dpv=malloc(size);
911 htod64a(dpv,value->u64);
912 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000913 case PTP_DTC_AUINT8:
914 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
915 dpv=malloc(size);
916 htod32a(dpv,value->a.count);
917 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000918 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000919 break;
920 case PTP_DTC_AINT8:
921 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
922 dpv=malloc(size);
923 htod32a(dpv,value->a.count);
924 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000925 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000926 break;
927 case PTP_DTC_AUINT16:
928 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
929 dpv=malloc(size);
930 htod32a(dpv,value->a.count);
931 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000932 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000933 break;
934 case PTP_DTC_AINT16:
935 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
936 dpv=malloc(size);
937 htod32a(dpv,value->a.count);
938 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000939 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000940 break;
941 case PTP_DTC_AUINT32:
942 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
943 dpv=malloc(size);
944 htod32a(dpv,value->a.count);
945 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000946 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000947 break;
948 case PTP_DTC_AINT32:
949 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
950 dpv=malloc(size);
951 htod32a(dpv,value->a.count);
952 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000953 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000954 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000955 case PTP_DTC_AUINT64:
956 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
957 dpv=malloc(size);
958 htod32a(dpv,value->a.count);
959 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000960 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +0000961 break;
962 case PTP_DTC_AINT64:
963 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
964 dpv=malloc(size);
965 htod32a(dpv,value->a.count);
966 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000967 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +0000968 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000969 /* XXX: other int types are unimplemented */
970 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000971 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000972 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000973 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000974 }
975 *dpvptr=dpv;
976 return size;
977}
978
Linus Walleij99310d42006-11-01 08:29:39 +0000979#define MAX_MTP_PROPS 127
980static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +0000981ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +0000982{
983 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000984 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +0000985 unsigned char *packedprops[MAX_MTP_PROPS];
986 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +0000987 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +0000988 uint16_t packedpropsids[MAX_MTP_PROPS];
989 uint16_t packedpropstypes[MAX_MTP_PROPS];
990 uint32_t totalsize = 0;
991 uint32_t bufp = 0;
992 uint32_t noitems = 0;
993 uint32_t i;
994
995 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +0000996 propitr = props;
997 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +0000998 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +0000999 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +00001000 totalsize += sizeof(uint32_t); /* Object ID */
1001 /* Metadata type */
1002 packedpropsids[noitems]=propitr->property;
1003 totalsize += sizeof(uint16_t);
1004 /* Data type */
1005 packedpropstypes[noitems]= propitr->datatype;
1006 totalsize += sizeof(uint16_t);
1007 /* Add each property to be sent. */
1008 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
1009 totalsize += packedpropslens[noitems];
1010 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001011 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +00001012 }
1013
1014 /* Allocate memory for the packed property list */
1015 opldata = malloc(totalsize);
1016
1017 htod32a(&opldata[bufp],noitems);
1018 bufp += 4;
1019
1020 /* Copy into a nice packed list */
1021 for (i = 0; i < noitems; i++) {
1022 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +00001023 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +00001024 bufp += sizeof(uint32_t);
1025 htod16a(&opldata[bufp],packedpropsids[i]);
1026 bufp += sizeof(uint16_t);
1027 htod16a(&opldata[bufp],packedpropstypes[i]);
1028 bufp += sizeof(uint16_t);
1029 /* The copy the actual property */
1030 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1031 bufp += packedpropslens[i];
1032 free(packedprops[i]);
1033 }
1034 *opldataptr = opldata;
1035 return totalsize;
1036}
1037
Linus Walleij1e9a0332007-09-12 19:35:56 +00001038static int
1039_compare_func(const void* x, const void *y) {
1040 const MTPProperties *px = x;
1041 const MTPProperties *py = y;
1042
1043 return px->ObjectHandle - py->ObjectHandle;
1044}
1045
Richard Low8d82d2f2006-11-16 20:37:43 +00001046static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001047ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001048{
Linus Walleij277cd532006-11-20 14:57:46 +00001049 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001050 MTPProperties *props = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001051 int offset = 0, i;
1052
1053 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +00001054 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001055 return 0;
1056 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001057 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001058 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001059 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001060 props = malloc(prop_count * sizeof(MTPProperties));
1061 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001062 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001063 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001064 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001065 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1066 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001067 qsort (props, i, sizeof(MTPProperties),_compare_func);
1068 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001069 return i;
1070 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001071 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001072 data += sizeof(uint32_t);
1073 len -= sizeof(uint32_t);
1074
Linus Walleij1e9a0332007-09-12 19:35:56 +00001075 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001076 data += sizeof(uint16_t);
1077 len -= sizeof(uint16_t);
1078
Linus Walleij1e9a0332007-09-12 19:35:56 +00001079 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001080 data += sizeof(uint16_t);
1081 len -= sizeof(uint16_t);
1082
1083 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001084 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001085 data += offset;
1086 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001087 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001088 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1089 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001090 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001091}
1092
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001093/*
1094 PTP USB Event container unpack
1095 Copyright (c) 2003 Nikolai Kopanygin
1096*/
1097
1098#define PTP_ec_Length 0
1099#define PTP_ec_Type 4
1100#define PTP_ec_Code 6
1101#define PTP_ec_TransId 8
1102#define PTP_ec_Param1 12
1103#define PTP_ec_Param2 16
1104#define PTP_ec_Param3 20
1105
Linus Walleijb02a0662006-04-25 08:05:09 +00001106static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001107ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001108{
Linus Walleij7e756532009-05-06 21:25:09 +00001109 int length;
1110 int type;
1111
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001112 if (data==NULL)
1113 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001114 memset(ec,0,sizeof(*ec));
1115 length=dtoh32a(&data[PTP_ec_Length]);
1116 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001117
Linus Walleij7e756532009-05-06 21:25:09 +00001118 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1119 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1120
1121 if (type!=PTP_USB_CONTAINER_EVENT) {
1122 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1123 return;
1124 }
1125 if (length>=(PTP_ec_Param1+4)) {
1126 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1127 ec->Nparam=1;
1128 }
1129 if (length>=(PTP_ec_Param2+4)) {
1130 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1131 ec->Nparam=2;
1132 }
1133 if (length>=(PTP_ec_Param3+4)) {
1134 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1135 ec->Nparam=3;
1136 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001137}
1138
1139/*
1140 PTP Canon Folder Entry unpack
1141 Copyright (c) 2003 Nikolai Kopanygin
1142*/
1143#define PTP_cfe_ObjectHandle 0
1144#define PTP_cfe_ObjectFormatCode 4
1145#define PTP_cfe_Flags 6
1146#define PTP_cfe_ObjectSize 7
1147#define PTP_cfe_Time 11
1148#define PTP_cfe_Filename 15
1149
Linus Walleijb02a0662006-04-25 08:05:09 +00001150static inline void
1151ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001152{
1153 int i;
1154 if (data==NULL)
1155 return;
1156 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1157 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1158 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001159 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001160 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1161 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001162 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1163}
1164
Linus Walleij1a0c3012009-07-23 23:06:58 +00001165static inline uint16_t
1166ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1167{
1168 /*
1169 EOS ImageFormat entries (of at least the 5DMII and the 400D ) look like this:
1170 uint32: number of entries / generated files (1 or 2)
1171 uint32: size of this entry in bytes (most likely allways 0x10)
1172 uint32: image type (1 == JPG, 6 == RAW)
1173 uint32: image size (0 == Large, 1 == Medium, 2 == Small)
1174 uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
1175 If number of entries is 2 the last uint32 repeat.
1176
1177 example:
1178 0: 0x 1
1179 1: 0x 10
1180 2: 0x 6
1181 3: 0x 1
1182 4: 0x 4
1183
1184 The idea is to simply 'condense' these values to just one uint16 to be able to conveniontly
1185 use the available enumeration facilities (look-up table). The image size and compression
1186 values fully describe the image format. Hence we generate a uint16 with the four nibles set
1187 as follows: entry 1 size | entry 1 compression | entry 2 size | entry 2 compression.
1188 The above example would result in the value 0x1400.
1189 */
1190
1191 const unsigned char* d = *data;
1192 uint32_t n = dtoh32a( d );
1193 uint32_t l, s1, c1, s2 = 0, c2 = 0;
1194
1195 if (n != 1 && n !=2) {
1196 ptp_debug (params, "parsing EOS ImageFormat property failed (n != 1 && n != 2: %d)", n);
1197 return 0;
1198 }
1199
1200 l = dtoh32a( d+=4 );
1201 if (l != 0x10) {
1202 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1203 return 0;
1204 }
1205
1206 d+=4; /* skip type */
1207 s1 = dtoh32a( d+=4 );
1208 c1 = dtoh32a( d+=4 );
1209
1210 if (n == 2) {
1211 l = dtoh32a( d+=4 );
1212 if (l != 0x10) {
1213 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1214 return 0;
1215 }
1216 d+=4; /* skip type */
1217 s2 = dtoh32a( d+=4 );
1218 c2 = dtoh32a( d+=4 );
1219 }
1220
1221 *data = (unsigned char*) d+4;
1222
1223 return ((s1 & 0xF) << 12) | ((c1 & 0xF) << 8) | ((s2 & 0xF) << 4) | ((c2 & 0xF) << 0);
1224}
1225
1226static inline uint32_t
1227ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value)
1228{
1229 uint32_t n = (value & 0xFF) ? 2 : 1;
1230 uint32_t s = 4 + 0x10 * n;
1231
1232 if( !data )
1233 return s;
1234
1235 htod32a(data+=0, n);
1236 htod32a(data+=4, 0x10);
1237 htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
1238 htod32a(data+=4, (value >> 12) & 0xF);
1239 htod32a(data+=4, (value >> 8) & 0xF);
1240
1241 if (n==2) {
1242 htod32a(data+=4, 0x10);
1243 htod32a(data+=4, ((value >> 0) & 0xF) == 4 ? 6 : 1);
1244 htod32a(data+=4, (value >> 4) & 0xF);
1245 htod32a(data+=4, (value >> 0) & 0xF);
1246 }
1247
1248 return s;
1249}
1250
Linus Walleijb02a0662006-04-25 08:05:09 +00001251/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001252 PTP EOS Changes Entry unpack
1253*/
1254#define PTP_ece_Size 0
1255#define PTP_ece_Type 4
1256
1257#define PTP_ece_Prop_Subtype 8 /* only for properties */
1258#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1259#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1260#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1261#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1262
Linus Walleijd4637502009-06-14 23:03:33 +00001263/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
1264#define PTP_ece_OI_ObjectID 8
1265#define PTP_ece_OI_OFC 0x0c
1266#define PTP_ece_OI_Size 0x14
1267#define PTP_ece_OI_Name 0x1c
1268
1269/* for PTP_EC_CANON_EOS_ObjectAddedEx */
1270#define PTP_ece_OA_ObjectID 8
1271#define PTP_ece_OA_StorageID 0x0c
1272#define PTP_ece_OA_OFC 0x10
1273#define PTP_ece_OA_Size 0x1c
1274#define PTP_ece_OA_Parent 0x20
1275#define PTP_ece_OA_Name 0x28
Linus Walleijf0bf4372007-07-01 21:47:38 +00001276
1277static inline int
1278ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
1279{
1280 int i = 0, entries = 0;
1281 unsigned char *curdata = data;
1282
1283 if (data==NULL)
1284 return 0;
1285 while (curdata - data < datasize) {
1286 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1287 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1288
1289 curdata += size;
1290 if ((size == 8) && (type == 0))
1291 break;
1292 entries++;
1293 }
Linus Walleij9d22ce02008-05-28 20:39:29 +00001294 *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001295 if (!*ce) return 0;
1296
1297 curdata = data;
1298 while (curdata - data < datasize) {
1299 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1300 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1301
Linus Walleijd4637502009-06-14 23:03:33 +00001302 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Linus Walleijd7072c32010-12-07 20:43:00 +00001303 (*ce)[i].u.info = NULL;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001304 switch (type) {
Linus Walleijd4637502009-06-14 23:03:33 +00001305 case PTP_EC_CANON_EOS_ObjectAddedEx:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001306 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
Linus Walleijd4637502009-06-14 23:03:33 +00001307 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
1308 (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
1309 (*ce)[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
1310 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
1311 (*ce)[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
1312 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
1313 ptp_debug (params, "event %d: objectinfo added oid %08lx, parent %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ParentObject, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
1314 break;
1315 case PTP_EC_CANON_EOS_RequestObjectTransfer:
1316 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001317 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
Linus Walleijd4637502009-06-14 23:03:33 +00001318 (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001319 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
Linus Walleijd4637502009-06-14 23:03:33 +00001320 (*ce)[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001321 (*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1322 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001323
Linus Walleijd4637502009-06-14 23:03:33 +00001324 ptp_debug (params, "event %d: request object transfer 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 +00001325 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001326 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001327 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1328 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1329 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
1330 unsigned char *data = &curdata[PTP_ece_Prop_Desc_Data];
1331 int j;
1332 PTPDevicePropDesc *dpd;
1333
Linus Walleij7e756532009-05-06 21:25:09 +00001334 ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d, propxtype %d", i, proptype, size-PTP_ece_Prop_Desc_Data, propxtype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001335 for (j=0;j<params->nrofcanon_props;j++)
1336 if (params->canon_props[j].proptype == proptype)
1337 break;
1338 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001339 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001340 break;
1341 }
1342 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001343 /* 1 - uint16 ?
1344 * 3 - uint16
1345 * 7 - string?
1346 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001347 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001348 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1349 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
1350 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001351 break;
1352 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001353 if (! propxcnt)
1354 break;
1355
1356 ptp_debug (params, "event %d: propxtype is %x, prop is 0x%04x, data type is 0x%04x, propxcnt is %d.",
1357 i, propxtype, proptype, dpd->DataType, propxcnt);
1358 dpd->FormFlag = PTP_DPFF_Enumeration;
1359 dpd->FORM.Enum.NumberOfValues = propxcnt;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001360 if (dpd->FORM.Enum.SupportedValue) free (dpd->FORM.Enum.SupportedValue);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001361 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1362
1363 switch (proptype) {
1364 case PTP_DPC_CANON_EOS_ImageFormat:
1365 case PTP_DPC_CANON_EOS_ImageFormatCF:
1366 case PTP_DPC_CANON_EOS_ImageFormatSD:
1367 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1368 /* special handling of ImageFormat properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001369 for (j=0;j<propxcnt;j++) {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001370 dpd->FORM.Enum.SupportedValue[j].u16 =
1371 dtoh16( ptp_unpack_EOS_ImageFormat( params, &data ) );
1372 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, dpd->FORM.Enum.SupportedValue[j].u16);
1373 }
1374 break;
1375 default:
1376 /* 'normal' enumerated types */
1377 switch (dpd->DataType) {
1378#define XX( TYPE, CONV )\
1379 for (j=0;j<propxcnt;j++) { \
1380 dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(data); \
1381 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(data)); \
1382 data += 4; /* might only be for propxtype 3 */ \
1383 } \
1384 break;
1385
1386 case PTP_DTC_INT16: XX( i16, dtoh16a );
1387 case PTP_DTC_UINT32: XX( u32, dtoh32a );
1388 case PTP_DTC_UINT16: XX( u16, dtoh16a );
1389 case PTP_DTC_UINT8: XX( u8, dtoh8a );
1390#undef XX
1391 default:
1392 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(data));
1393 for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, data+=4) /* 4 is good for propxtype 3 */
1394 ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(data));
1395 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001396 }
1397 }
1398 break;
1399 }
Linus Walleij7e756532009-05-06 21:25:09 +00001400 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001401 if (size >= 0xc) { /* property info */
1402 int j;
1403 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1404 unsigned char *data = &curdata[PTP_ece_Prop_Val_Data];
1405 PTPDevicePropDesc *dpd;
1406
Linus Walleij1a0c3012009-07-23 23:06:58 +00001407 ptp_debug (params, "event %d: EOS prop %04x info record, datasize is %d", i, proptype, size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001408 for (j=0;j<params->nrofcanon_props;j++)
1409 if (params->canon_props[j].proptype == proptype)
1410 break;
1411 if (j<params->nrofcanon_props) {
1412 if ( (params->canon_props[j].size != size) ||
1413 (memcmp(params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data))) {
1414 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
1415 memcpy (params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data);
1416 }
1417 } else {
1418 if (j)
1419 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1420 else
1421 params->canon_props = malloc(sizeof(params->canon_props[0]));
1422 params->canon_props[j].type = type;
1423 params->canon_props[j].proptype = proptype;
1424 params->canon_props[j].size = size;
1425 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
1426 memcpy(params->canon_props[j].data, data, size-PTP_ece_Prop_Val_Data);
1427 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1428 params->canon_props[j].dpd.GetSet = 1;
1429 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1430 params->nrofcanon_props = j+1;
1431 }
1432 dpd = &params->canon_props[j].dpd;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001433
Linus Walleijd7072c32010-12-07 20:43:00 +00001434 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
1435 (*ce)[i].u.propid = proptype;
1436
Linus Walleij1a0c3012009-07-23 23:06:58 +00001437 /* fix GetSet value */
1438 switch (proptype) {
1439#define XX(x) case PTP_DPC_CANON_##x:
1440 XX(EOS_FocusMode)
1441 XX(EOS_BatteryPower)
1442 XX(EOS_BatterySelect)
1443 XX(EOS_ModelID)
1444 XX(EOS_PTPExtensionVersion)
1445 XX(EOS_DPOFVersion)
1446 XX(EOS_AvailableShots)
1447 XX(EOS_CurrentStorage)
1448 XX(EOS_CurrentFolder)
1449 XX(EOS_MyMenu)
1450 XX(EOS_MyMenuList)
1451 XX(EOS_HDDirectoryStructure)
1452 XX(EOS_BatteryInfo)
1453 XX(EOS_AdapterInfo)
1454 XX(EOS_LensStatus)
1455 XX(EOS_CardExtension)
1456 XX(EOS_TempStatus)
1457 XX(EOS_ShutterCounter)
1458 XX(EOS_SerialNumber)
1459 XX(EOS_DepthOfFieldPreview)
1460 XX(EOS_EVFRecordStatus)
1461 XX(EOS_LvAfSystem)
1462 XX(EOS_FocusInfoEx)
1463 XX(EOS_DepthOfField)
1464 XX(EOS_Brightness)
1465 XX(EOS_EFComp)
1466 XX(EOS_LensName)
1467 XX(EOS_LensID)
1468#undef XX
1469 dpd->GetSet = PTP_DPGS_Get;
1470 break;
1471 }
1472
1473 /* set DataType */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001474 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001475 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleijd4637502009-06-14 23:03:33 +00001476 case PTP_DPC_CANON_EOS_AvailableShots:
Linus Walleijd4637502009-06-14 23:03:33 +00001477 case PTP_DPC_CANON_EOS_CaptureDestination:
1478 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
1479 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
Linus Walleijd4637502009-06-14 23:03:33 +00001480 case PTP_DPC_CANON_EOS_CurrentStorage:
1481 case PTP_DPC_CANON_EOS_CurrentFolder:
1482 case PTP_DPC_CANON_EOS_ShutterCounter:
1483 case PTP_DPC_CANON_EOS_ModelID:
1484 case PTP_DPC_CANON_EOS_LensID:
1485 case PTP_DPC_CANON_EOS_StroboFiring:
Linus Walleijac052c12007-07-18 18:37:10 +00001486 dpd->DataType = PTP_DTC_UINT32;
1487 break;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001488 /* enumeration for AEM is never provided, but is available to set */
1489 case PTP_DPC_CANON_EOS_AutoExposureMode:
1490 dpd->DataType = PTP_DTC_UINT16;
1491 dpd->FormFlag = PTP_DPFF_Enumeration;
1492 dpd->FORM.Enum.NumberOfValues = 0;
1493 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001494 case PTP_DPC_CANON_EOS_Aperture:
1495 case PTP_DPC_CANON_EOS_ShutterSpeed:
1496 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00001497 case PTP_DPC_CANON_EOS_FocusMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001498 case PTP_DPC_CANON_EOS_ColorSpace:
1499 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleije29ca682010-01-30 08:15:25 +00001500 case PTP_DPC_CANON_EOS_BatterySelect:
Linus Walleijd4637502009-06-14 23:03:33 +00001501 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001502 case PTP_DPC_CANON_EOS_DriveMode:
1503 case PTP_DPC_CANON_EOS_AEB:
Linus Walleije29ca682010-01-30 08:15:25 +00001504 case PTP_DPC_CANON_EOS_BracketMode:
1505 case PTP_DPC_CANON_EOS_QuickReviewTime:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001506 case PTP_DPC_CANON_EOS_EVFMode:
1507 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001508 dpd->DataType = PTP_DTC_UINT16;
1509 break;
1510 case PTP_DPC_CANON_EOS_PictureStyle:
1511 case PTP_DPC_CANON_EOS_WhiteBalance:
1512 case PTP_DPC_CANON_EOS_MeteringMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001513 case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001514 dpd->DataType = PTP_DTC_UINT8;
1515 break;
1516 case PTP_DPC_CANON_EOS_Owner:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001517 case PTP_DPC_CANON_EOS_Artist:
1518 case PTP_DPC_CANON_EOS_Copyright:
1519 case PTP_DPC_CANON_EOS_SerialNumber:
1520 case PTP_DPC_CANON_EOS_LensName:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001521 dpd->DataType = PTP_DTC_STR;
1522 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001523 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
1524 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
1525 dpd->DataType = PTP_DTC_INT16;
1526 break;
1527 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
Linus Walleij7e756532009-05-06 21:25:09 +00001528 case 0xd114:
Linus Walleij7e756532009-05-06 21:25:09 +00001529 case PTP_DPC_CANON_EOS_DPOFVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001530 dpd->DataType = PTP_DTC_UINT16;
1531 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
1532 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1533 ptp_debug (params, " %d: %02x", j, data[j]);
1534 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001535 case PTP_DPC_CANON_EOS_CustomFunc1:
1536 case PTP_DPC_CANON_EOS_CustomFunc2:
1537 case PTP_DPC_CANON_EOS_CustomFunc3:
1538 case PTP_DPC_CANON_EOS_CustomFunc4:
1539 case PTP_DPC_CANON_EOS_CustomFunc5:
1540 case PTP_DPC_CANON_EOS_CustomFunc6:
1541 case PTP_DPC_CANON_EOS_CustomFunc7:
1542 case PTP_DPC_CANON_EOS_CustomFunc8:
1543 case PTP_DPC_CANON_EOS_CustomFunc9:
1544 case PTP_DPC_CANON_EOS_CustomFunc10:
1545 case PTP_DPC_CANON_EOS_CustomFunc11:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001546 dpd->DataType = PTP_DTC_UINT8;
1547 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint8", i ,proptype, size-PTP_ece_Prop_Val_Data);
Linus Walleij7e756532009-05-06 21:25:09 +00001548 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1549 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001550 /* custom func entries look like this on the 400D: '5 0 0 0 ?' = 4 bytes size + 1 byte data */
1551 data += 4;
Linus Walleij7e756532009-05-06 21:25:09 +00001552 break;
1553 /* yet unknown 32bit props */
1554 case PTP_DPC_CANON_EOS_ColorTemperature:
Linus Walleij7e756532009-05-06 21:25:09 +00001555 case PTP_DPC_CANON_EOS_WftStatus:
1556 case PTP_DPC_CANON_EOS_LensStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001557 case PTP_DPC_CANON_EOS_CardExtension:
1558 case PTP_DPC_CANON_EOS_TempStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001559 case PTP_DPC_CANON_EOS_PhotoStudioMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001560 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
1561 case PTP_DPC_CANON_EOS_EVFSharpness:
1562 case PTP_DPC_CANON_EOS_EVFWBMode:
1563 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
1564 case PTP_DPC_CANON_EOS_EVFColorTemp:
Linus Walleijd4637502009-06-14 23:03:33 +00001565 case PTP_DPC_CANON_EOS_EVFRecordStatus:
1566 case PTP_DPC_CANON_EOS_ExposureSimMode:
1567 case PTP_DPC_CANON_EOS_LvAfSystem:
1568 case PTP_DPC_CANON_EOS_MovSize:
1569 case PTP_DPC_CANON_EOS_DepthOfField:
1570 case PTP_DPC_CANON_EOS_LvViewTypeSelect:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001571 case PTP_DPC_CANON_EOS_CustomFuncEx:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001572 dpd->DataType = PTP_DTC_UINT32;
Linus Walleij7e756532009-05-06 21:25:09 +00001573 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint32", i ,proptype, size-PTP_ece_Prop_Val_Data);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001574 if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
1575 ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
1576 for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
1577 ptp_debug (params, " %d: 0x%8x", j, ((uint32_t*)data)[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001578 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001579 /* ImageFormat properties have to be ignored here, see special handling below */
1580 case PTP_DPC_CANON_EOS_ImageFormat:
1581 case PTP_DPC_CANON_EOS_ImageFormatCF:
1582 case PTP_DPC_CANON_EOS_ImageFormatSD:
1583 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1584 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001585 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001586 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1587 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1588 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001589 break;
1590 }
1591 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001592 case PTP_DTC_UINT32:
1593 dpd->FactoryDefaultValue.u32 = dtoh32a(data);
1594 dpd->CurrentValue.u32 = dtoh32a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001595 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001596 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001597 case PTP_DTC_UINT16:
1598 dpd->FactoryDefaultValue.u16 = dtoh16a(data);
1599 dpd->CurrentValue.u16 = dtoh16a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001600 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001601 break;
1602 case PTP_DTC_UINT8:
1603 dpd->FactoryDefaultValue.u8 = dtoh8a(data);
1604 dpd->CurrentValue.u8 = dtoh8a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001605 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001606 break;
1607 case PTP_DTC_STR: {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001608#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001609 uint8_t len = 0;
1610 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1611 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001612#else
Linus Walleij0d762cc2010-04-04 23:34:27 +00001613 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001614 dpd->FactoryDefaultValue.str = strdup( (char*)data );
Linus Walleij0d762cc2010-04-04 23:34:27 +00001615
1616 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001617 dpd->CurrentValue.str = strdup( (char*)data );
1618#endif
Linus Walleij7e756532009-05-06 21:25:09 +00001619 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001620 break;
1621 }
1622 default:
1623 /* debug is printed in switch above this one */
1624 break;
1625 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001626
Linus Walleijd7072c32010-12-07 20:43:00 +00001627 /* ImageFormat special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
1628 switch (proptype) {
1629 case PTP_DPC_CANON_EOS_ImageFormat:
1630 case PTP_DPC_CANON_EOS_ImageFormatCF:
1631 case PTP_DPC_CANON_EOS_ImageFormatSD:
1632 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1633 dpd->DataType = PTP_DTC_UINT16;
1634 dpd->FactoryDefaultValue.u16 = ptp_unpack_EOS_ImageFormat( params, &data );
1635 dpd->CurrentValue.u16 = dpd->FactoryDefaultValue.u16;
1636 ptp_debug (params,"event %d: decoded imageformat, currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
1637 break;
1638 }
1639
Linus Walleijf0bf4372007-07-01 21:47:38 +00001640 break;
1641 }
Linus Walleijd7072c32010-12-07 20:43:00 +00001642 case PTP_EC_CANON_EOS_CameraStatusChanged:
1643 ptp_debug (params, "event %d: EOS event CameraStatusChanged (size %d)", i, size);
1644 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS;
1645 (*ce)[i].u.status = dtoh32a(curdata+8);
1646 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001647 case 0: /* end marker */
1648 if (size == 8) /* no output */
1649 break;
1650 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
1651 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001652 default:
Linus Walleijd4637502009-06-14 23:03:33 +00001653 switch (type) {
Linus Walleijd7072c32010-12-07 20:43:00 +00001654#define XX(x) case PTP_EC_CANON_EOS_##x: \
1655 ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); \
1656 (*ce)[i].u.info = malloc(strlen("unhandled EOS event "#x" (size 123456789)")); \
1657 sprintf ((*ce)[i].u.info, "unhandled EOS event "#x" (size %d)", size); \
1658 break;
Linus Walleijd4637502009-06-14 23:03:33 +00001659 XX(RequestGetEvent)
1660 XX(ObjectRemoved)
1661 XX(RequestGetObjectInfoEx)
1662 XX(StorageStatusChanged)
1663 XX(StorageInfoChanged)
1664 XX(ObjectInfoChangedEx)
1665 XX(ObjectContentChanged)
Linus Walleijd4637502009-06-14 23:03:33 +00001666 XX(WillSoonShutdown)
1667 XX(ShutdownTimerUpdated)
1668 XX(RequestCancelTransfer)
1669 XX(RequestObjectTransferDT)
1670 XX(RequestCancelTransferDT)
1671 XX(StoreAdded)
1672 XX(StoreRemoved)
1673 XX(BulbExposureTime)
1674 XX(RecordingTime)
1675 XX(RequestObjectTransferTS)
1676 XX(AfResult)
1677#undef XX
1678 default:
1679 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
1680 break;
1681 }
Linus Walleij7e756532009-05-06 21:25:09 +00001682 if (size >= 0x8) { /* event info */
1683 int j;
Linus Walleijd4637502009-06-14 23:03:33 +00001684 for (j=8;j<size;j++)
1685 ptp_debug (params, " %d: %02x", j, curdata[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001686 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001687 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1688 break;
1689 }
1690 curdata += size;
1691 i++;
Linus Walleij9d22ce02008-05-28 20:39:29 +00001692 if ((size == 8) && (type == 0))
1693 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001694 }
Linus Walleij0d762cc2010-04-04 23:34:27 +00001695 if (!entries) {
1696 free (*ce);
1697 *ce = NULL;
1698 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001699 return entries;
1700}
1701
1702/*
Linus Walleijb02a0662006-04-25 08:05:09 +00001703 PTP USB Event container unpack for Nikon events.
1704*/
1705#define PTP_nikon_ec_Length 0
1706#define PTP_nikon_ec_Code 2
1707#define PTP_nikon_ec_Param1 4
1708#define PTP_nikon_ec_Size 6
1709static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001710ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00001711{
1712 int i;
1713
1714 *ec = NULL;
1715 if (data == NULL)
1716 return;
1717 if (len < PTP_nikon_ec_Code)
1718 return;
1719 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
1720 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
1721 return;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001722 if (!*cnt)
1723 return;
1724
Linus Walleij7e756532009-05-06 21:25:09 +00001725 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00001726
1727 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00001728 memset(&(*ec)[i],0,sizeof(PTPContainer));
1729 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
1730 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
1731 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00001732 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001733}
1734
1735
Linus Walleijb02a0662006-04-25 08:05:09 +00001736static inline uint32_t
1737ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
1738 int i, len = 0;
1739 uint8_t retlen;
1740 unsigned char *curdata;
1741
1742 len = 2*(strlen(text->title)+1)+1+
1743 2*(strlen(text->line[0])+1)+1+
1744 2*(strlen(text->line[1])+1)+1+
1745 2*(strlen(text->line[2])+1)+1+
1746 2*(strlen(text->line[3])+1)+1+
1747 2*(strlen(text->line[4])+1)+1+
1748 4*2+2*4+2+4+2+5*4*2;
1749 *data = malloc(len);
1750 if (!*data) return 0;
1751
1752 curdata = *data;
1753 htod16a(curdata,100);curdata+=2;
1754 htod16a(curdata,1);curdata+=2;
1755 htod16a(curdata,0);curdata+=2;
1756 htod16a(curdata,1000);curdata+=2;
1757
1758 htod32a(curdata,0);curdata+=4;
1759 htod32a(curdata,0);curdata+=4;
1760
1761 htod16a(curdata,6);curdata+=2;
1762 htod32a(curdata,0);curdata+=4;
1763
1764 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1765 htod16a(curdata,0x10);curdata+=2;
1766
1767 for (i=0;i<5;i++) {
1768 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1769 htod16a(curdata,0x10);curdata+=2;
1770 htod16a(curdata,0x01);curdata+=2;
1771 htod16a(curdata,0x02);curdata+=2;
1772 htod16a(curdata,0x06);curdata+=2;
1773 }
1774 return len;
1775}
Linus Walleij7347d0f2006-10-23 07:23:39 +00001776
1777#define ptp_canon_dir_version 0x00
1778#define ptp_canon_dir_ofc 0x02
1779#define ptp_canon_dir_unk1 0x04
1780#define ptp_canon_dir_objectid 0x08
1781#define ptp_canon_dir_parentid 0x0c
1782#define ptp_canon_dir_previd 0x10 /* in same dir */
1783#define ptp_canon_dir_nextid 0x14 /* in same dir */
1784#define ptp_canon_dir_nextchild 0x18 /* down one dir */
1785#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
1786#define ptp_canon_dir_name 0x20
1787#define ptp_canon_dir_flags 0x2c
1788#define ptp_canon_dir_size 0x30
1789#define ptp_canon_dir_unixtime 0x34
1790#define ptp_canon_dir_year 0x38
1791#define ptp_canon_dir_month 0x39
1792#define ptp_canon_dir_mday 0x3a
1793#define ptp_canon_dir_hour 0x3b
1794#define ptp_canon_dir_minute 0x3c
1795#define ptp_canon_dir_second 0x3d
1796#define ptp_canon_dir_unk2 0x3e
1797#define ptp_canon_dir_thumbsize 0x40
1798#define ptp_canon_dir_width 0x44
1799#define ptp_canon_dir_height 0x48
1800
1801static inline uint16_t
1802ptp_unpack_canon_directory (
1803 PTPParams *params,
1804 unsigned char *dir,
1805 uint32_t cnt,
1806 PTPObjectHandles *handles,
1807 PTPObjectInfo **oinfos, /* size(handles->n) */
1808 uint32_t **flags /* size(handles->n) */
1809) {
1810 unsigned int i, j, nrofobs = 0, curob = 0;
1811
1812#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
1813 for (i=0;i<cnt;i++)
1814 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
1815 handles->n = nrofobs;
1816 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
1817 if (!handles->Handler) return PTP_RC_GeneralError;
1818 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
1819 if (!*oinfos) return PTP_RC_GeneralError;
1820 *flags = calloc(sizeof((*flags)[0]),nrofobs);
1821 if (!*flags) return PTP_RC_GeneralError;
1822
1823 /* Migrate data into objects ids, handles into
1824 * the object handler array.
1825 */
1826 curob = 0;
1827 for (i=0;i<cnt;i++) {
1828 unsigned char *cur = dir+i*0x4c;
1829 PTPObjectInfo *oi = (*oinfos)+curob;
1830
1831 if (!ISOBJECT(cur))
1832 continue;
1833
1834 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
1835 oi->StorageID = 0xffffffff;
1836 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
1837 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
1838 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
1839 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
1840 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
1841 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
1842 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
1843 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
1844 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
1845 curob++;
1846 }
1847 /* Walk over Storage ID entries and distribute the IDs to
1848 * the parent objects. */
1849 for (i=0;i<cnt;i++) {
1850 unsigned char *cur = dir+i*0x4c;
1851 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1852
1853 if (ISOBJECT(cur))
1854 continue;
1855 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1856 if (j == handles->n) continue;
1857 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
1858 }
1859 /* Walk over all objects and distribute the storage ids */
1860 while (1) {
1861 int changed = 0;
1862 for (i=0;i<cnt;i++) {
1863 unsigned char *cur = dir+i*0x4c;
1864 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
1865 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
1866 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1867 uint32_t storageid;
1868
1869 if (!ISOBJECT(cur))
1870 continue;
1871 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
1872 if (j == handles->n) {
1873 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
1874 continue;
1875 }
1876 storageid = (*oinfos)[j].StorageID;
1877 if (storageid == 0xffffffff) continue;
1878 if (nextoid != 0xffffffff) {
1879 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
1880 if (j == handles->n) {
1881 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
1882 continue;
1883 }
1884 if ((*oinfos)[j].StorageID == 0xffffffff) {
1885 (*oinfos)[j].StorageID = storageid;
1886 changed++;
1887 }
1888 }
1889 if (nextchild != 0xffffffff) {
1890 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1891 if (j == handles->n) {
1892 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
1893 continue;
1894 }
1895 if ((*oinfos)[j].StorageID == 0xffffffff) {
1896 (*oinfos)[j].StorageID = storageid;
1897 changed++;
1898 }
1899 }
1900 }
1901 /* Check if we:
1902 * - changed no entry (nothing more to do)
1903 * - changed all of them at once (usually happens)
1904 * break if we do.
1905 */
1906 if (!changed || (changed==nrofobs-1))
1907 break;
1908 }
1909#undef ISOBJECT
1910 return PTP_RC_OK;
1911}