blob: ae8addcc3c18d61ffe618d4bd2fc65cfea8c6a3a [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 Walleijb02a0662006-04-25 08:05:09 +00007static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00008htod16p (PTPParams *params, uint16_t var)
9{
10 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
11}
12
Linus Walleijb02a0662006-04-25 08:05:09 +000013static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000014htod32p (PTPParams *params, uint32_t var)
15{
16 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
17}
18
Linus Walleijb02a0662006-04-25 08:05:09 +000019static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000020htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
21{
22 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000023 htole16a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020024 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000025 htobe16a(a,val);
26}
27
Linus Walleijb02a0662006-04-25 08:05:09 +000028static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000029htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
30{
31 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000032 htole32a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020033 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000034 htobe32a(a,val);
35}
36
Linus Walleijabf54752007-07-30 19:51:54 +000037static inline void
38htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
39{
40 if (params->byteorder==PTP_DL_LE)
41 htole64a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020042 else
Linus Walleijabf54752007-07-30 19:51:54 +000043 htobe64a(a,val);
44}
45
Linus Walleijb02a0662006-04-25 08:05:09 +000046static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000047dtoh16p (PTPParams *params, uint16_t var)
48{
49 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
50}
51
Linus Walleijb02a0662006-04-25 08:05:09 +000052static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000053dtoh32p (PTPParams *params, uint32_t var)
54{
55 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
56}
57
Linus Walleijabf54752007-07-30 19:51:54 +000058static inline uint64_t
59dtoh64p (PTPParams *params, uint64_t var)
60{
61 return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
62}
63
Linus Walleijb02a0662006-04-25 08:05:09 +000064static inline uint16_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000065dtoh16ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000066{
67 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
68}
69
Linus Walleijb02a0662006-04-25 08:05:09 +000070static inline uint32_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000071dtoh32ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000072{
73 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
74}
75
Linus Walleijb02a0662006-04-25 08:05:09 +000076static inline uint64_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000077dtoh64ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000078{
Linus Walleijabf54752007-07-30 19:51:54 +000079 return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000080}
81
Linus Walleijb02a0662006-04-25 08:05:09 +000082#define htod8a(a,x) *(uint8_t*)(a) = x
83#define htod16a(a,x) htod16ap(params,a,x)
84#define htod32a(a,x) htod32ap(params,a,x)
Linus Walleijabf54752007-07-30 19:51:54 +000085#define htod64a(a,x) htod64ap(params,a,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000086#define htod16(x) htod16p(params,x)
87#define htod32(x) htod32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000088#define htod64(x) htod64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000089
90#define dtoh8a(x) (*(uint8_t*)(x))
91#define dtoh16a(a) dtoh16ap(params,a)
92#define dtoh32a(a) dtoh32ap(params,a)
93#define dtoh64a(a) dtoh64ap(params,a)
94#define dtoh16(x) dtoh16p(params,x)
95#define dtoh32(x) dtoh32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000096#define dtoh64(x) dtoh64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000097
98
99static inline char*
100ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000101{
Linus Walleija8a19cc2007-02-02 22:13:17 +0000102 uint8_t length;
103 uint16_t string[PTP_MAXSTRLEN+1];
104 /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
Linus Walleije206af62011-04-19 01:51:39 +0200105 char loclstr[PTP_MAXSTRLEN*3+1];
Linus Walleija8a19cc2007-02-02 22:13:17 +0000106 size_t nconv, srclen, destlen;
107 char *src, *dest;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000108
Linus Walleija8a19cc2007-02-02 22:13:17 +0000109 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
110 *len = length;
111 if (length == 0) /* nothing to do? */
112 return(NULL);
113
114 /* copy to string[] to ensure correct alignment for iconv(3) */
115 memcpy(string, &data[offset+1], length * sizeof(string[0]));
116 string[length] = 0x0000U; /* be paranoid! add a terminator. */
117 loclstr[0] = '\0';
Linus Walleije206af62011-04-19 01:51:39 +0200118
Linus Walleija8a19cc2007-02-02 22:13:17 +0000119 /* convert from camera UCS-2 to our locale */
120 src = (char *)string;
121 srclen = length * sizeof(string[0]);
122 dest = loclstr;
123 destlen = sizeof(loclstr)-1;
Linus Walleij6db174f2009-05-09 13:15:26 +0000124 nconv = (size_t)-1;
125#ifdef HAVE_ICONV
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100126 if (params->cd_ucs2_to_locale != (iconv_t)-1)
127 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, &dest, &destlen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000128#endif
Linus Walleija8a19cc2007-02-02 22:13:17 +0000129 if (nconv == (size_t) -1) { /* do it the hard way */
130 int i;
131 /* try the old way, in case iconv is broken */
132 for (i=0;i<length;i++) {
133 if (dtoh16a(&data[offset+1+2*i])>127)
134 loclstr[i] = '?';
135 else
136 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000137 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000138 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000139 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000140 *dest = '\0';
141 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
142 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000143}
144
Linus Walleija823a702006-08-27 21:27:46 +0000145static inline int
146ucs2strlen(uint16_t const * const unicstr)
147{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200148 int length = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000149
150 /* Unicode strings are terminated with 2 * 0x00 */
151 for(length = 0; unicstr[length] != 0x0000U; length ++);
152 return length;
153}
154
155
Linus Walleijb02a0662006-04-25 08:05:09 +0000156static inline void
157ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000158{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200159 int packedlen = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000160 uint16_t ucs2str[PTP_MAXSTRLEN+1];
161 char *ucs2strp = (char *) ucs2str;
Linus Walleija823a702006-08-27 21:27:46 +0000162 size_t convlen = strlen(string);
Linus Walleija823a702006-08-27 21:27:46 +0000163
164 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000165 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
Linus Walleij6db174f2009-05-09 13:15:26 +0000166#ifdef HAVE_ICONV
Linus Walleijd000c372011-12-20 08:32:23 +0100167 if (params->cd_locale_to_ucs2 != (iconv_t)-1) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000168 size_t nconv;
169 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
170 char *stringp = string;
171
172 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
173 &ucs2strp, &convmax);
174 if (nconv == (size_t) -1)
175 ucs2str[0] = 0x0000U;
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100176 } else
Linus Walleijd000c372011-12-20 08:32:23 +0100177#endif
Linus Walleij6db174f2009-05-09 13:15:26 +0000178 {
179 int i;
180 for (i=0;i<convlen;i++) {
181 ucs2str[i] = string[i];
182 }
183 ucs2str[convlen] = 0;
184 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000185 /*
186 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
187 * why do we need ucs2strlen()?
188 */
Linus Walleija823a702006-08-27 21:27:46 +0000189 packedlen = ucs2strlen(ucs2str);
190 if (packedlen > PTP_MAXSTRLEN-1) {
191 *len=0;
192 return;
193 }
Linus Walleij958441f2006-08-29 15:30:11 +0000194
Linus Walleij7f234382006-12-09 19:41:00 +0000195 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000196 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000197 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
198 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000199
200 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000201 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000202}
203
204static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000205ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000206{
Richard Low8b42ca32006-11-15 08:52:17 +0000207 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000208 size_t plen;
209 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000210
211 if (string == NULL)
212 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
213 else
214 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
215
Linus Walleij958441f2006-08-29 15:30:11 +0000216 /* returned length is in characters, then one byte for string length */
217 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000218
Linus Walleija823a702006-08-27 21:27:46 +0000219 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000220 if (!retcopy) {
221 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000222 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000223 }
Linus Walleija823a702006-08-27 21:27:46 +0000224 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000225 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000226 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000227}
228
Linus Walleijb02a0662006-04-25 08:05:09 +0000229static inline uint32_t
230ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000231{
232 uint32_t n, i=0;
233
234 n=dtoh32a(&data[offset]);
235 *array = malloc (n*sizeof(uint32_t));
236 while (n>i) {
237 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
238 i++;
239 }
240 return n;
241}
242
Linus Walleijb02a0662006-04-25 08:05:09 +0000243static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000244ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
245{
246 uint32_t i=0;
247
248 *data = malloc ((arraylen+1)*sizeof(uint32_t));
249 htod32a(&(*data)[0],arraylen);
250 for (i=0;i<arraylen;i++)
251 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
252 return (arraylen+1)*sizeof(uint32_t);
253}
254
255static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000256ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000257{
258 uint32_t n, i=0;
259
260 n=dtoh32a(&data[offset]);
261 *array = malloc (n*sizeof(uint16_t));
262 while (n>i) {
263 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
264 i++;
265 }
266 return n;
267}
268
269/* DeviceInfo pack/unpack */
270
271#define PTP_di_StandardVersion 0
272#define PTP_di_VendorExtensionID 2
273#define PTP_di_VendorExtensionVersion 6
274#define PTP_di_VendorExtensionDesc 8
275#define PTP_di_FunctionalMode 8
276#define PTP_di_OperationsSupported 10
277
Linus Walleijb02a0662006-04-25 08:05:09 +0000278static inline void
279ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000280{
281 uint8_t len;
282 unsigned int totallen;
Linus Walleij7e756532009-05-06 21:25:09 +0000283
Linus Walleijd4637502009-06-14 23:03:33 +0000284 if (!data) return;
285 if (datalen < 12) return;
Linus Walleij7347d0f2006-10-23 07:23:39 +0000286 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000287 di->VendorExtensionID =
288 dtoh32a(&data[PTP_di_VendorExtensionID]);
289 di->VendorExtensionVersion =
290 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
291 di->VendorExtensionDesc =
292 ptp_unpack_string(params, data,
293 PTP_di_VendorExtensionDesc, &len);
294 totallen=len*2+1;
295 di->FunctionalMode =
296 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
297 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
298 PTP_di_OperationsSupported+totallen,
299 &di->OperationsSupported);
300 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
301 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
302 PTP_di_OperationsSupported+totallen,
303 &di->EventsSupported);
304 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
305 di->DevicePropertiesSupported_len =
306 ptp_unpack_uint16_t_array(params, data,
307 PTP_di_OperationsSupported+totallen,
308 &di->DevicePropertiesSupported);
309 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
310 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
311 PTP_di_OperationsSupported+totallen,
312 &di->CaptureFormats);
313 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
314 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
315 PTP_di_OperationsSupported+totallen,
316 &di->ImageFormats);
317 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
318 di->Manufacturer = ptp_unpack_string(params, data,
319 PTP_di_OperationsSupported+totallen,
320 &len);
321 totallen+=len*2+1;
322 di->Model = ptp_unpack_string(params, data,
323 PTP_di_OperationsSupported+totallen,
324 &len);
325 totallen+=len*2+1;
326 di->DeviceVersion = ptp_unpack_string(params, data,
327 PTP_di_OperationsSupported+totallen,
328 &len);
329 totallen+=len*2+1;
330 di->SerialNumber = ptp_unpack_string(params, data,
331 PTP_di_OperationsSupported+totallen,
332 &len);
333}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000334
Linus Walleije206af62011-04-19 01:51:39 +0200335static void inline
Linus Walleija8a19cc2007-02-02 22:13:17 +0000336ptp_free_DI (PTPDeviceInfo *di) {
337 if (di->SerialNumber) free (di->SerialNumber);
338 if (di->DeviceVersion) free (di->DeviceVersion);
339 if (di->Model) free (di->Model);
340 if (di->Manufacturer) free (di->Manufacturer);
341 if (di->ImageFormats) free (di->ImageFormats);
342 if (di->CaptureFormats) free (di->CaptureFormats);
343 if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
344 if (di->OperationsSupported) free (di->OperationsSupported);
345 if (di->EventsSupported) free (di->EventsSupported);
346 if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
347}
Linus Walleij7e756532009-05-06 21:25:09 +0000348
349/* EOS Device Info unpack */
350static inline void
351ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
352{
353 int totallen = 4;
Linus Walleij96aa0e32012-03-25 12:25:25 +0200354
355 memset (di,0, sizeof(*di));
Linus Walleij7e756532009-05-06 21:25:09 +0000356 if (datalen < 8) return;
357
358 /* uint32_t struct len - ignore */
359 di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
360 totallen, &di->EventsSupported);
361 if (!di->EventsSupported) return;
362 totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
363 if (totallen >= datalen) return;
364
365 di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
366 totallen, &di->DevicePropertiesSupported);
367 if (!di->DevicePropertiesSupported) return;
368 totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
369 if (totallen >= datalen) return;
370
371 di->unk_len = ptp_unpack_uint32_t_array(params, data,
372 totallen, &di->unk);
373 if (!di->unk) return;
374 totallen += di->unk_len*sizeof(uint32_t)+4;
375 return;
376}
Linus Walleij0d762cc2010-04-04 23:34:27 +0000377
378static inline void
379ptp_free_EOS_DI (PTPCanonEOSDeviceInfo *di)
380{
381 free (di->EventsSupported);
382 free (di->DevicePropertiesSupported);
383 free (di->unk);
384}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000385
386/* ObjectHandles array pack/unpack */
387
388#define PTP_oh 0
389
Linus Walleijb02a0662006-04-25 08:05:09 +0000390static inline void
391ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000392{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000393 if (len) {
394 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
395 } else {
396 oh->n = 0;
397 oh->Handler = NULL;
398 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000399}
400
401/* StoreIDs array pack/unpack */
402
403#define PTP_sids 0
404
Linus Walleijb02a0662006-04-25 08:05:09 +0000405static inline void
406ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000407{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200408 if (!data && !len) {
409 sids->n = 0;
410 sids->Storage = NULL;
411 return;
412 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000413 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
414 &sids->Storage);
415}
416
417/* StorageInfo pack/unpack */
418
419#define PTP_si_StorageType 0
420#define PTP_si_FilesystemType 2
421#define PTP_si_AccessCapability 4
422#define PTP_si_MaxCapability 6
423#define PTP_si_FreeSpaceInBytes 14
424#define PTP_si_FreeSpaceInImages 22
425#define PTP_si_StorageDescription 26
426
Linus Walleijb02a0662006-04-25 08:05:09 +0000427static inline void
428ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000429{
430 uint8_t storagedescriptionlen;
431
432 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
433 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
434 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000435 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
436 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
437 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
438 si->StorageDescription=ptp_unpack_string(params, data,
439 PTP_si_StorageDescription, &storagedescriptionlen);
440 si->VolumeLabel=ptp_unpack_string(params, data,
441 PTP_si_StorageDescription+storagedescriptionlen*2+1,
442 &storagedescriptionlen);
443}
444
445/* ObjectInfo pack/unpack */
446
447#define PTP_oi_StorageID 0
448#define PTP_oi_ObjectFormat 4
449#define PTP_oi_ProtectionStatus 6
450#define PTP_oi_ObjectCompressedSize 8
451#define PTP_oi_ThumbFormat 12
452#define PTP_oi_ThumbCompressedSize 14
453#define PTP_oi_ThumbPixWidth 18
454#define PTP_oi_ThumbPixHeight 22
455#define PTP_oi_ImagePixWidth 26
456#define PTP_oi_ImagePixHeight 30
457#define PTP_oi_ImageBitDepth 34
458#define PTP_oi_ParentObject 38
459#define PTP_oi_AssociationType 42
460#define PTP_oi_AssociationDesc 44
461#define PTP_oi_SequenceNumber 48
462#define PTP_oi_filenamelen 52
463#define PTP_oi_Filename 53
464
Linus Walleija0323272007-01-07 12:21:30 +0000465/* the max length assuming zero length dates. We have need 3 */
466/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000467#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
468
Linus Walleijb02a0662006-04-25 08:05:09 +0000469static inline uint32_t
470ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000471{
Linus Walleijb02a0662006-04-25 08:05:09 +0000472 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000473 uint8_t filenamelen;
474 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000475 /* let's allocate some memory first; correct assuming zero length dates */
476 oidata=malloc(PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000477 /* the caller should free it after use! */
478#if 0
479 char *capture_date="20020101T010101"; /* XXX Fake date */
480#endif
Richard Lowa679b1c2006-12-29 20:08:14 +0000481 memset (oidata, 0, PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000482 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
483 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
484 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
485 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
486 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
487 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
488 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
489 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
490 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
491 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
492 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
493 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
494 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
495 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
496 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
497
498 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
499/*
500 filenamelen=(uint8_t)strlen(oi->Filename);
501 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
502 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
503 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
504 }
505*/
506 /*
507 *XXX Fake date.
508 * for example Kodak sets Capture date on the basis of EXIF data.
509 * Spec says that this field is from perspective of Initiator.
510 */
511#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
512 capturedatelen=strlen(capture_date);
513 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
514 capturedatelen+1);
515 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
516 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
517 }
518 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
519 capturedatelen+1);
520 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
521 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
522 capture_date[i];
523 }
524#endif
525 /* XXX this function should return dataset length */
526
527 *oidataptr=oidata;
Richard Lowa679b1c2006-12-29 20:08:14 +0000528 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000529}
530
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000531static time_t
Linus Walleij6db174f2009-05-09 13:15:26 +0000532ptp_unpack_PTPTIME (const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000533 char ptpdate[40];
534 char tmp[5];
535 int ptpdatelen;
536 struct tm tm;
537
538 if (!str)
539 return 0;
540 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000541 if (ptpdatelen >= sizeof (ptpdate)) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000542 /*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000543 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000544 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000545 strcpy (ptpdate, str);
Linus Walleij7e756532009-05-06 21:25:09 +0000546 if (ptpdatelen<15) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000547 /*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000548 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000549 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000550
551 memset(&tm,0,sizeof(tm));
552 strncpy (tmp, ptpdate, 4);
553 tmp[4] = 0;
554 tm.tm_year=atoi (tmp) - 1900;
555 strncpy (tmp, ptpdate + 4, 2);
556 tmp[2] = 0;
557 tm.tm_mon = atoi (tmp) - 1;
558 strncpy (tmp, ptpdate + 6, 2);
559 tmp[2] = 0;
560 tm.tm_mday = atoi (tmp);
561 strncpy (tmp, ptpdate + 9, 2);
562 tmp[2] = 0;
563 tm.tm_hour = atoi (tmp);
564 strncpy (tmp, ptpdate + 11, 2);
565 tmp[2] = 0;
566 tm.tm_min = atoi (tmp);
567 strncpy (tmp, ptpdate + 13, 2);
568 tmp[2] = 0;
569 tm.tm_sec = atoi (tmp);
Linus Walleije206af62011-04-19 01:51:39 +0200570 tm.tm_isdst = -1;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000571 return mktime (&tm);
572}
573
Linus Walleijb02a0662006-04-25 08:05:09 +0000574static inline void
575ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000576{
577 uint8_t filenamelen;
578 uint8_t capturedatelen;
579 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000580
581 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
582 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
583 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
584 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
585 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
586 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
587 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
588 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
589 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
590 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
591 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
592 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
593 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
594 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
595 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
596 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
597
598 capture_date = ptp_unpack_string(params, data,
599 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
600 /* subset of ISO 8601, without '.s' tenths of second and
601 * time zone
602 */
Linus Walleij6db174f2009-05-09 13:15:26 +0000603 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000604 free(capture_date);
605
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000606 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000607 capture_date = ptp_unpack_string(params, data,
608 PTP_oi_filenamelen+filenamelen*2
609 +capturedatelen*2+2,&capturedatelen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000610 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000611 free(capture_date);
612}
613
614/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000615#define CTVAL(target,func) { \
616 if (total - *offset < sizeof(target)) \
617 return 0; \
618 target = func(&data[*offset]); \
619 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000620}
621
Linus Walleijb02a0662006-04-25 08:05:09 +0000622#define RARR(val,member,func) { \
623 int n,j; \
624 if (total - *offset < sizeof(uint32_t)) \
625 return 0; \
626 n = dtoh32a (&data[*offset]); \
627 *offset += sizeof(uint32_t); \
628 \
629 val->a.count = n; \
630 val->a.v = malloc(sizeof(val->a.v[0])*n); \
631 if (!val->a.v) return 0; \
632 for (j=0;j<n;j++) \
633 CTVAL(val->a.v[j].member, func); \
634}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000635
Linus Walleijb02a0662006-04-25 08:05:09 +0000636static inline int
637ptp_unpack_DPV (
638 PTPParams *params, unsigned char* data, int *offset, int total,
639 PTPPropertyValue* value, uint16_t datatype
640) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000641 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000642 case PTP_DTC_INT8:
643 CTVAL(value->i8,dtoh8a);
644 break;
645 case PTP_DTC_UINT8:
646 CTVAL(value->u8,dtoh8a);
647 break;
648 case PTP_DTC_INT16:
649 CTVAL(value->i16,dtoh16a);
650 break;
651 case PTP_DTC_UINT16:
652 CTVAL(value->u16,dtoh16a);
653 break;
654 case PTP_DTC_INT32:
655 CTVAL(value->i32,dtoh32a);
656 break;
657 case PTP_DTC_UINT32:
658 CTVAL(value->u32,dtoh32a);
659 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000660 case PTP_DTC_INT64:
661 CTVAL(value->i64,dtoh64a);
662 break;
663 case PTP_DTC_UINT64:
664 CTVAL(value->u64,dtoh64a);
665 break;
666
Linus Walleij037a1252006-12-16 20:36:52 +0000667 case PTP_DTC_UINT128:
668 *offset += 16;
669 /*fprintf(stderr,"unhandled unpack of uint128n");*/
670 break;
671 case PTP_DTC_INT128:
672 *offset += 16;
673 /*fprintf(stderr,"unhandled unpack of int128n");*/
674 break;
675
676
677
Linus Walleijb02a0662006-04-25 08:05:09 +0000678 case PTP_DTC_AINT8:
679 RARR(value,i8,dtoh8a);
680 break;
681 case PTP_DTC_AUINT8:
682 RARR(value,u8,dtoh8a);
683 break;
684 case PTP_DTC_AUINT16:
685 RARR(value,u16,dtoh16a);
686 break;
687 case PTP_DTC_AINT16:
688 RARR(value,i16,dtoh16a);
689 break;
690 case PTP_DTC_AUINT32:
691 RARR(value,u32,dtoh32a);
692 break;
693 case PTP_DTC_AINT32:
694 RARR(value,i32,dtoh32a);
695 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000696 case PTP_DTC_AUINT64:
697 RARR(value,u64,dtoh64a);
698 break;
699 case PTP_DTC_AINT64:
700 RARR(value,i64,dtoh64a);
701 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000702 /* XXX: other int types are unimplemented */
703 /* XXX: other int arrays are unimplemented also */
704 case PTP_DTC_STR: {
705 uint8_t len;
706 /* XXX: max size */
707 value->str = ptp_unpack_string(params,data,*offset,&len);
708 *offset += len*2+1;
709 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000710 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000711 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000712 }
Linus Walleij037a1252006-12-16 20:36:52 +0000713 default:
714 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000715 }
716 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000717}
718
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000719/* Device Property pack/unpack */
720
721#define PTP_dpd_DevicePropertyCode 0
722#define PTP_dpd_DataType 2
723#define PTP_dpd_GetSet 4
724#define PTP_dpd_FactoryDefaultValue 5
725
Linus Walleijb02a0662006-04-25 08:05:09 +0000726static inline int
727ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000728{
Linus Walleijb02a0662006-04-25 08:05:09 +0000729 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000730
Linus Walleijb02a0662006-04-25 08:05:09 +0000731 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000732 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
733 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
734 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000735 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000736
737 offset = PTP_dpd_FactoryDefaultValue;
738 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
739 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000740 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
741 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000742 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
743 if (!ret) goto outofmemory;
744
745 /* if offset==0 then Data Type format is not supported by this
746 code or the Data Type is a string (with two empty strings as
747 values). In both cases Form Flag should be set to 0x00 and FORM is
748 not present. */
749
Linus Walleijb02a0662006-04-25 08:05:09 +0000750 if (offset==PTP_dpd_FactoryDefaultValue)
751 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000752
Linus Walleijb02a0662006-04-25 08:05:09 +0000753 dpd->FormFlag=dtoh8a(&data[offset]);
754 offset+=sizeof(uint8_t);
755
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000756 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000757 case PTP_DPFF_Range:
758 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
759 if (!ret) goto outofmemory;
760 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
761 if (!ret) goto outofmemory;
762 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
763 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000764 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000765 case PTP_DPFF_Enumeration: {
766 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000767#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000768 N = dtoh16a(&data[offset]);
769 offset+=sizeof(uint16_t);
770 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
771 if (!dpd->FORM.Enum.SupportedValue)
772 goto outofmemory;
773
774 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
775 for (i=0;i<N;i++) {
776 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
777
778 /* Slightly different handling here. The HP PhotoSmart 120
779 * specifies an enumeration with N in wrong endian
780 * 00 01 instead of 01 00, so we count the enum just until the
781 * the end of the packet.
782 */
783 if (!ret) {
784 if (!i)
785 goto outofmemory;
786 dpd->FORM.Enum.NumberOfValues = i;
787 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000788 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000789 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000790 }
791 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000792#undef N
793 return 1;
794outofmemory:
795 ptp_free_devicepropdesc(dpd);
796 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000797}
798
Linus Walleijb02a0662006-04-25 08:05:09 +0000799/* (MTP) Object Property pack/unpack */
800#define PTP_opd_ObjectPropertyCode 0
801#define PTP_opd_DataType 2
802#define PTP_opd_GetSet 4
803#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000804
Linus Walleijb02a0662006-04-25 08:05:09 +0000805static inline int
806ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000807{
Linus Walleijb02a0662006-04-25 08:05:09 +0000808 int offset=0, ret;
809
810 memset (opd, 0, sizeof(*opd));
811 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
812 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
813 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
814
815 offset = PTP_opd_FactoryDefaultValue;
816 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
817 if (!ret) goto outofmemory;
818
819 opd->GroupCode=dtoh32a(&data[offset]);
820 offset+=sizeof(uint32_t);
821
822 opd->FormFlag=dtoh8a(&data[offset]);
823 offset+=sizeof(uint8_t);
824
825 switch (opd->FormFlag) {
826 case PTP_OPFF_Range:
827 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
828 if (!ret) goto outofmemory;
829 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
830 if (!ret) goto outofmemory;
831 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
832 if (!ret) goto outofmemory;
833 break;
834 case PTP_OPFF_Enumeration: {
835 int i;
836#define N opd->FORM.Enum.NumberOfValues
837 N = dtoh16a(&data[offset]);
838 offset+=sizeof(uint16_t);
839 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
840 if (!opd->FORM.Enum.SupportedValue)
841 goto outofmemory;
842
843 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
844 for (i=0;i<N;i++) {
845 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
846
847 /* Slightly different handling here. The HP PhotoSmart 120
848 * specifies an enumeration with N in wrong endian
849 * 00 01 instead of 01 00, so we count the enum just until the
850 * the end of the packet.
851 */
852 if (!ret) {
853 if (!i)
854 goto outofmemory;
855 opd->FORM.Enum.NumberOfValues = i;
856 break;
857 }
858 }
859#undef N
860 }
861 }
862 return 1;
863outofmemory:
864 ptp_free_objectpropdesc(opd);
865 return 0;
866}
867
868
869static inline uint32_t
870ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
871{
872 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000873 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000874 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000875
876 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000877 case PTP_DTC_INT8:
878 size=sizeof(int8_t);
879 dpv=malloc(size);
880 htod8a(dpv,value->i8);
881 break;
882 case PTP_DTC_UINT8:
883 size=sizeof(uint8_t);
884 dpv=malloc(size);
885 htod8a(dpv,value->u8);
886 break;
887 case PTP_DTC_INT16:
888 size=sizeof(int16_t);
889 dpv=malloc(size);
890 htod16a(dpv,value->i16);
891 break;
892 case PTP_DTC_UINT16:
893 size=sizeof(uint16_t);
894 dpv=malloc(size);
895 htod16a(dpv,value->u16);
896 break;
897 case PTP_DTC_INT32:
898 size=sizeof(int32_t);
899 dpv=malloc(size);
900 htod32a(dpv,value->i32);
901 break;
902 case PTP_DTC_UINT32:
903 size=sizeof(uint32_t);
904 dpv=malloc(size);
905 htod32a(dpv,value->u32);
906 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000907 case PTP_DTC_INT64:
908 size=sizeof(int64_t);
909 dpv=malloc(size);
910 htod64a(dpv,value->i64);
911 break;
912 case PTP_DTC_UINT64:
913 size=sizeof(uint64_t);
914 dpv=malloc(size);
915 htod64a(dpv,value->u64);
916 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000917 case PTP_DTC_AUINT8:
918 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
919 dpv=malloc(size);
920 htod32a(dpv,value->a.count);
921 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000922 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000923 break;
924 case PTP_DTC_AINT8:
925 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
926 dpv=malloc(size);
927 htod32a(dpv,value->a.count);
928 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000929 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000930 break;
931 case PTP_DTC_AUINT16:
932 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
933 dpv=malloc(size);
934 htod32a(dpv,value->a.count);
935 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000936 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000937 break;
938 case PTP_DTC_AINT16:
939 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
940 dpv=malloc(size);
941 htod32a(dpv,value->a.count);
942 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000943 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000944 break;
945 case PTP_DTC_AUINT32:
946 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
947 dpv=malloc(size);
948 htod32a(dpv,value->a.count);
949 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000950 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000951 break;
952 case PTP_DTC_AINT32:
953 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
954 dpv=malloc(size);
955 htod32a(dpv,value->a.count);
956 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000957 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000958 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000959 case PTP_DTC_AUINT64:
960 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
961 dpv=malloc(size);
962 htod32a(dpv,value->a.count);
963 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000964 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +0000965 break;
966 case PTP_DTC_AINT64:
967 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
968 dpv=malloc(size);
969 htod32a(dpv,value->a.count);
970 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000971 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +0000972 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000973 /* XXX: other int types are unimplemented */
974 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000975 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000976 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000977 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000978 }
979 *dpvptr=dpv;
980 return size;
981}
982
Linus Walleij99310d42006-11-01 08:29:39 +0000983#define MAX_MTP_PROPS 127
984static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +0000985ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +0000986{
987 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000988 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +0000989 unsigned char *packedprops[MAX_MTP_PROPS];
990 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +0000991 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +0000992 uint16_t packedpropsids[MAX_MTP_PROPS];
993 uint16_t packedpropstypes[MAX_MTP_PROPS];
994 uint32_t totalsize = 0;
995 uint32_t bufp = 0;
996 uint32_t noitems = 0;
997 uint32_t i;
998
999 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +00001000 propitr = props;
1001 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +00001002 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +00001003 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +00001004 totalsize += sizeof(uint32_t); /* Object ID */
1005 /* Metadata type */
1006 packedpropsids[noitems]=propitr->property;
1007 totalsize += sizeof(uint16_t);
1008 /* Data type */
1009 packedpropstypes[noitems]= propitr->datatype;
1010 totalsize += sizeof(uint16_t);
1011 /* Add each property to be sent. */
1012 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
1013 totalsize += packedpropslens[noitems];
1014 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001015 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +00001016 }
1017
1018 /* Allocate memory for the packed property list */
1019 opldata = malloc(totalsize);
1020
1021 htod32a(&opldata[bufp],noitems);
1022 bufp += 4;
1023
1024 /* Copy into a nice packed list */
1025 for (i = 0; i < noitems; i++) {
1026 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +00001027 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +00001028 bufp += sizeof(uint32_t);
1029 htod16a(&opldata[bufp],packedpropsids[i]);
1030 bufp += sizeof(uint16_t);
1031 htod16a(&opldata[bufp],packedpropstypes[i]);
1032 bufp += sizeof(uint16_t);
1033 /* The copy the actual property */
1034 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1035 bufp += packedpropslens[i];
1036 free(packedprops[i]);
1037 }
1038 *opldataptr = opldata;
1039 return totalsize;
1040}
1041
Linus Walleij1e9a0332007-09-12 19:35:56 +00001042static int
1043_compare_func(const void* x, const void *y) {
1044 const MTPProperties *px = x;
1045 const MTPProperties *py = y;
1046
1047 return px->ObjectHandle - py->ObjectHandle;
1048}
1049
Richard Low8d82d2f2006-11-16 20:37:43 +00001050static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001051ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001052{
Linus Walleij277cd532006-11-20 14:57:46 +00001053 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001054 MTPProperties *props = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001055 int offset = 0, i;
1056
1057 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +00001058 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001059 return 0;
1060 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001061 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001062 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001063 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001064 props = malloc(prop_count * sizeof(MTPProperties));
1065 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001066 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001067 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001068 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001069 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1070 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001071 qsort (props, i, sizeof(MTPProperties),_compare_func);
1072 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001073 return i;
1074 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001075 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001076 data += sizeof(uint32_t);
1077 len -= sizeof(uint32_t);
1078
Linus Walleij1e9a0332007-09-12 19:35:56 +00001079 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001080 data += sizeof(uint16_t);
1081 len -= sizeof(uint16_t);
1082
Linus Walleij1e9a0332007-09-12 19:35:56 +00001083 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001084 data += sizeof(uint16_t);
1085 len -= sizeof(uint16_t);
1086
1087 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001088 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001089 data += offset;
1090 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001091 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001092 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1093 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001094 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001095}
1096
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001097/*
1098 PTP USB Event container unpack
1099 Copyright (c) 2003 Nikolai Kopanygin
1100*/
1101
1102#define PTP_ec_Length 0
1103#define PTP_ec_Type 4
1104#define PTP_ec_Code 6
1105#define PTP_ec_TransId 8
1106#define PTP_ec_Param1 12
1107#define PTP_ec_Param2 16
1108#define PTP_ec_Param3 20
1109
Linus Walleijb02a0662006-04-25 08:05:09 +00001110static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001111ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001112{
Linus Walleij7e756532009-05-06 21:25:09 +00001113 int length;
1114 int type;
1115
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001116 if (data==NULL)
1117 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001118 memset(ec,0,sizeof(*ec));
1119 length=dtoh32a(&data[PTP_ec_Length]);
1120 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001121
Linus Walleij7e756532009-05-06 21:25:09 +00001122 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1123 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1124
1125 if (type!=PTP_USB_CONTAINER_EVENT) {
1126 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1127 return;
1128 }
1129 if (length>=(PTP_ec_Param1+4)) {
1130 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1131 ec->Nparam=1;
1132 }
1133 if (length>=(PTP_ec_Param2+4)) {
1134 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1135 ec->Nparam=2;
1136 }
1137 if (length>=(PTP_ec_Param3+4)) {
1138 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1139 ec->Nparam=3;
1140 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001141}
1142
1143/*
1144 PTP Canon Folder Entry unpack
1145 Copyright (c) 2003 Nikolai Kopanygin
1146*/
1147#define PTP_cfe_ObjectHandle 0
1148#define PTP_cfe_ObjectFormatCode 4
1149#define PTP_cfe_Flags 6
1150#define PTP_cfe_ObjectSize 7
1151#define PTP_cfe_Time 11
1152#define PTP_cfe_Filename 15
1153
Linus Walleijb02a0662006-04-25 08:05:09 +00001154static inline void
1155ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001156{
1157 int i;
1158 if (data==NULL)
1159 return;
1160 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1161 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1162 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001163 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001164 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1165 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001166 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1167}
1168
Linus Walleij96aa0e32012-03-25 12:25:25 +02001169/*
1170 PTP Canon EOS Folder Entry unpack
11710: 00 00 08 a0 objectid
11724: 01 00 02 00 storageid
11738: 01 30 00 00 ofc
117412: 01 00
117514: 00 00
117616: 11 00 00 00
117720: 00 00 00 00
117824: 00 00 00 80
117928: 00 00 08 a0
118032: 4d 49 53 43-00 00 00 00 00 00 00 00 name
118100 00 00 00
118284 bc 74 46 objectime
1183
1184
1185(normal PTP GetObjectInfo)
1186ObjectInfo for 'IMG_0199.JPG':
1187 Object ID: 0x92740c72
1188 StorageID: 0x00020001
1189 ObjectFormat: 0x3801
1190 ProtectionStatus: 0x0000
1191 ObjectCompressedSize: 2217241
1192 ThumbFormat: 0x3808
1193 ThumbCompressedSize: 5122
1194 ThumbPixWidth: 160
1195 ThumbPixHeight: 120
1196 ImagePixWidth: 4000
1197 ImagePixHeight: 3000
1198 ImageBitDepth: 24
1199 ParentObject: 0x92740000
1200 AssociationType: 0x0000
1201 AssociationDesc: 0x00000000
1202 SequenceNumber: 0x00000000
1203 ModificationDate: 0x4d985ff0
1204 CaptureDate: 0x4d985ff0
1205
12060010 38 00 00 00 Size of this entry
12070014 72 0c 74 92 OID
12080018 01 00 02 00 StorageID
1209001c 01 38 00 00 OFC
12100020 00 00 00 00 00 00 00 00 ?
12110028 19 d5 21 00 Size
1212002c 00 00 74 92 ?
12130030 70 0c 74 92 OID
12140034 49 4d 47 5f-30 31 39 39 2e 4a 50 47 IMG_0199.JPG
12150040 00 00 00 00
12160044 10 7c 98 4d Time
1217
1218
1219*/
1220#define PTP_cefe_ObjectHandle 0
1221#define PTP_cefe_StorageID 4
1222#define PTP_cefe_ObjectFormatCode 8
1223#define PTP_cefe_Flags 12
1224#define PTP_cefe_ObjectSize 20
1225#define PTP_cefe_Filename 32
1226#define PTP_cefe_Time 48
1227
1228static inline void
1229ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
1230{
1231 int i;
1232
1233 fe->ObjectHandle=dtoh32a(&data[PTP_cefe_ObjectHandle]);
1234 fe->ObjectFormatCode=dtoh16a(&data[PTP_cefe_ObjectFormatCode]);
1235 fe->Flags=dtoh8a(&data[PTP_cefe_Flags]);
1236 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cefe_ObjectSize]);
1237 fe->Time=(time_t)dtoh32a(&data[PTP_cefe_Time]);
1238 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
1239 fe->Filename[i]=(char)data[PTP_cefe_Filename+i];
1240}
1241
1242
Linus Walleij1a0c3012009-07-23 23:06:58 +00001243static inline uint16_t
1244ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1245{
1246 /*
1247 EOS ImageFormat entries (of at least the 5DMII and the 400D ) look like this:
1248 uint32: number of entries / generated files (1 or 2)
1249 uint32: size of this entry in bytes (most likely allways 0x10)
1250 uint32: image type (1 == JPG, 6 == RAW)
1251 uint32: image size (0 == Large, 1 == Medium, 2 == Small)
1252 uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
1253 If number of entries is 2 the last uint32 repeat.
1254
1255 example:
1256 0: 0x 1
1257 1: 0x 10
1258 2: 0x 6
1259 3: 0x 1
1260 4: 0x 4
1261
1262 The idea is to simply 'condense' these values to just one uint16 to be able to conveniontly
1263 use the available enumeration facilities (look-up table). The image size and compression
1264 values fully describe the image format. Hence we generate a uint16 with the four nibles set
1265 as follows: entry 1 size | entry 1 compression | entry 2 size | entry 2 compression.
1266 The above example would result in the value 0x1400.
1267 */
1268
1269 const unsigned char* d = *data;
1270 uint32_t n = dtoh32a( d );
1271 uint32_t l, s1, c1, s2 = 0, c2 = 0;
1272
1273 if (n != 1 && n !=2) {
1274 ptp_debug (params, "parsing EOS ImageFormat property failed (n != 1 && n != 2: %d)", n);
1275 return 0;
1276 }
1277
1278 l = dtoh32a( d+=4 );
1279 if (l != 0x10) {
1280 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1281 return 0;
1282 }
1283
1284 d+=4; /* skip type */
1285 s1 = dtoh32a( d+=4 );
1286 c1 = dtoh32a( d+=4 );
1287
1288 if (n == 2) {
1289 l = dtoh32a( d+=4 );
1290 if (l != 0x10) {
1291 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1292 return 0;
1293 }
1294 d+=4; /* skip type */
1295 s2 = dtoh32a( d+=4 );
1296 c2 = dtoh32a( d+=4 );
1297 }
1298
1299 *data = (unsigned char*) d+4;
1300
1301 return ((s1 & 0xF) << 12) | ((c1 & 0xF) << 8) | ((s2 & 0xF) << 4) | ((c2 & 0xF) << 0);
1302}
1303
1304static inline uint32_t
1305ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value)
1306{
1307 uint32_t n = (value & 0xFF) ? 2 : 1;
1308 uint32_t s = 4 + 0x10 * n;
1309
1310 if( !data )
1311 return s;
1312
1313 htod32a(data+=0, n);
1314 htod32a(data+=4, 0x10);
1315 htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
1316 htod32a(data+=4, (value >> 12) & 0xF);
1317 htod32a(data+=4, (value >> 8) & 0xF);
1318
1319 if (n==2) {
1320 htod32a(data+=4, 0x10);
1321 htod32a(data+=4, ((value >> 0) & 0xF) == 4 ? 6 : 1);
1322 htod32a(data+=4, (value >> 4) & 0xF);
1323 htod32a(data+=4, (value >> 0) & 0xF);
1324 }
1325
1326 return s;
1327}
1328
Linus Walleijb02a0662006-04-25 08:05:09 +00001329/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001330 PTP EOS Changes Entry unpack
1331*/
1332#define PTP_ece_Size 0
1333#define PTP_ece_Type 4
1334
1335#define PTP_ece_Prop_Subtype 8 /* only for properties */
1336#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1337#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1338#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1339#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1340
Linus Walleijd4637502009-06-14 23:03:33 +00001341/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
1342#define PTP_ece_OI_ObjectID 8
1343#define PTP_ece_OI_OFC 0x0c
1344#define PTP_ece_OI_Size 0x14
1345#define PTP_ece_OI_Name 0x1c
1346
1347/* for PTP_EC_CANON_EOS_ObjectAddedEx */
1348#define PTP_ece_OA_ObjectID 8
1349#define PTP_ece_OA_StorageID 0x0c
1350#define PTP_ece_OA_OFC 0x10
1351#define PTP_ece_OA_Size 0x1c
1352#define PTP_ece_OA_Parent 0x20
1353#define PTP_ece_OA_Name 0x28
Linus Walleijf0bf4372007-07-01 21:47:38 +00001354
1355static inline int
1356ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
1357{
1358 int i = 0, entries = 0;
1359 unsigned char *curdata = data;
1360
1361 if (data==NULL)
1362 return 0;
1363 while (curdata - data < datasize) {
1364 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1365 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1366
1367 curdata += size;
1368 if ((size == 8) && (type == 0))
1369 break;
1370 entries++;
1371 }
Linus Walleij9d22ce02008-05-28 20:39:29 +00001372 *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001373 if (!*ce) return 0;
1374
1375 curdata = data;
1376 while (curdata - data < datasize) {
1377 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1378 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1379
Linus Walleijd4637502009-06-14 23:03:33 +00001380 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Linus Walleijd7072c32010-12-07 20:43:00 +00001381 (*ce)[i].u.info = NULL;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001382 switch (type) {
Linus Walleijd4637502009-06-14 23:03:33 +00001383 case PTP_EC_CANON_EOS_ObjectAddedEx:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001384 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
Linus Walleijd4637502009-06-14 23:03:33 +00001385 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
1386 (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
1387 (*ce)[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
1388 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
1389 (*ce)[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
1390 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
1391 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);
1392 break;
1393 case PTP_EC_CANON_EOS_RequestObjectTransfer:
1394 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001395 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
Linus Walleijd4637502009-06-14 23:03:33 +00001396 (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001397 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
Linus Walleijd4637502009-06-14 23:03:33 +00001398 (*ce)[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001399 (*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1400 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001401
Linus Walleijd4637502009-06-14 23:03:33 +00001402 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 +00001403 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001404 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001405 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1406 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1407 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
Linus Walleije206af62011-04-19 01:51:39 +02001408 unsigned char *xdata = &curdata[PTP_ece_Prop_Desc_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00001409 int j;
1410 PTPDevicePropDesc *dpd;
1411
Linus Walleij7e756532009-05-06 21:25:09 +00001412 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 +00001413 for (j=0;j<params->nrofcanon_props;j++)
1414 if (params->canon_props[j].proptype == proptype)
1415 break;
1416 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001417 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001418 break;
1419 }
1420 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001421 /* 1 - uint16 ?
1422 * 3 - uint16
1423 * 7 - string?
1424 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001425 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001426 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1427 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001428 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001429 break;
1430 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001431 if (! propxcnt)
1432 break;
1433
1434 ptp_debug (params, "event %d: propxtype is %x, prop is 0x%04x, data type is 0x%04x, propxcnt is %d.",
1435 i, propxtype, proptype, dpd->DataType, propxcnt);
1436 dpd->FormFlag = PTP_DPFF_Enumeration;
1437 dpd->FORM.Enum.NumberOfValues = propxcnt;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001438 if (dpd->FORM.Enum.SupportedValue) free (dpd->FORM.Enum.SupportedValue);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001439 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1440
1441 switch (proptype) {
1442 case PTP_DPC_CANON_EOS_ImageFormat:
1443 case PTP_DPC_CANON_EOS_ImageFormatCF:
1444 case PTP_DPC_CANON_EOS_ImageFormatSD:
1445 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1446 /* special handling of ImageFormat properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001447 for (j=0;j<propxcnt;j++) {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001448 dpd->FORM.Enum.SupportedValue[j].u16 =
Linus Walleije206af62011-04-19 01:51:39 +02001449 dtoh16( ptp_unpack_EOS_ImageFormat( params, &xdata ) );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001450 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, dpd->FORM.Enum.SupportedValue[j].u16);
1451 }
1452 break;
1453 default:
1454 /* 'normal' enumerated types */
1455 switch (dpd->DataType) {
1456#define XX( TYPE, CONV )\
1457 for (j=0;j<propxcnt;j++) { \
Linus Walleije206af62011-04-19 01:51:39 +02001458 dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \
1459 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \
1460 xdata += 4; /* might only be for propxtype 3 */ \
Linus Walleij1a0c3012009-07-23 23:06:58 +00001461 } \
1462 break;
1463
1464 case PTP_DTC_INT16: XX( i16, dtoh16a );
1465 case PTP_DTC_UINT32: XX( u32, dtoh32a );
1466 case PTP_DTC_UINT16: XX( u16, dtoh16a );
1467 case PTP_DTC_UINT8: XX( u8, dtoh8a );
1468#undef XX
1469 default:
Linus Walleije206af62011-04-19 01:51:39 +02001470 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata));
1471 for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */
1472 ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001473 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001474 }
1475 }
1476 break;
1477 }
Linus Walleij7e756532009-05-06 21:25:09 +00001478 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001479 if (size >= 0xc) { /* property info */
1480 int j;
1481 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
Linus Walleije206af62011-04-19 01:51:39 +02001482 unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00001483 PTPDevicePropDesc *dpd;
1484
Linus Walleij1a0c3012009-07-23 23:06:58 +00001485 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 +00001486 for (j=0;j<params->nrofcanon_props;j++)
1487 if (params->canon_props[j].proptype == proptype)
1488 break;
1489 if (j<params->nrofcanon_props) {
1490 if ( (params->canon_props[j].size != size) ||
Linus Walleije206af62011-04-19 01:51:39 +02001491 (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00001492 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001493 memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001494 }
1495 } else {
1496 if (j)
1497 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1498 else
1499 params->canon_props = malloc(sizeof(params->canon_props[0]));
1500 params->canon_props[j].type = type;
1501 params->canon_props[j].proptype = proptype;
1502 params->canon_props[j].size = size;
1503 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001504 memcpy(params->canon_props[j].data, xdata, size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001505 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1506 params->canon_props[j].dpd.GetSet = 1;
1507 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1508 params->nrofcanon_props = j+1;
1509 }
1510 dpd = &params->canon_props[j].dpd;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001511
Linus Walleijd7072c32010-12-07 20:43:00 +00001512 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
1513 (*ce)[i].u.propid = proptype;
1514
Linus Walleij1a0c3012009-07-23 23:06:58 +00001515 /* fix GetSet value */
1516 switch (proptype) {
1517#define XX(x) case PTP_DPC_CANON_##x:
1518 XX(EOS_FocusMode)
1519 XX(EOS_BatteryPower)
1520 XX(EOS_BatterySelect)
1521 XX(EOS_ModelID)
1522 XX(EOS_PTPExtensionVersion)
1523 XX(EOS_DPOFVersion)
1524 XX(EOS_AvailableShots)
1525 XX(EOS_CurrentStorage)
1526 XX(EOS_CurrentFolder)
1527 XX(EOS_MyMenu)
1528 XX(EOS_MyMenuList)
1529 XX(EOS_HDDirectoryStructure)
1530 XX(EOS_BatteryInfo)
1531 XX(EOS_AdapterInfo)
1532 XX(EOS_LensStatus)
1533 XX(EOS_CardExtension)
1534 XX(EOS_TempStatus)
1535 XX(EOS_ShutterCounter)
1536 XX(EOS_SerialNumber)
1537 XX(EOS_DepthOfFieldPreview)
1538 XX(EOS_EVFRecordStatus)
1539 XX(EOS_LvAfSystem)
1540 XX(EOS_FocusInfoEx)
1541 XX(EOS_DepthOfField)
1542 XX(EOS_Brightness)
1543 XX(EOS_EFComp)
1544 XX(EOS_LensName)
1545 XX(EOS_LensID)
1546#undef XX
1547 dpd->GetSet = PTP_DPGS_Get;
1548 break;
1549 }
1550
1551 /* set DataType */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001552 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001553 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleijd4637502009-06-14 23:03:33 +00001554 case PTP_DPC_CANON_EOS_AvailableShots:
Linus Walleijd4637502009-06-14 23:03:33 +00001555 case PTP_DPC_CANON_EOS_CaptureDestination:
1556 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
1557 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
Linus Walleijd4637502009-06-14 23:03:33 +00001558 case PTP_DPC_CANON_EOS_CurrentStorage:
1559 case PTP_DPC_CANON_EOS_CurrentFolder:
1560 case PTP_DPC_CANON_EOS_ShutterCounter:
1561 case PTP_DPC_CANON_EOS_ModelID:
1562 case PTP_DPC_CANON_EOS_LensID:
1563 case PTP_DPC_CANON_EOS_StroboFiring:
Linus Walleijac052c12007-07-18 18:37:10 +00001564 dpd->DataType = PTP_DTC_UINT32;
1565 break;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001566 /* enumeration for AEM is never provided, but is available to set */
1567 case PTP_DPC_CANON_EOS_AutoExposureMode:
1568 dpd->DataType = PTP_DTC_UINT16;
1569 dpd->FormFlag = PTP_DPFF_Enumeration;
1570 dpd->FORM.Enum.NumberOfValues = 0;
1571 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001572 case PTP_DPC_CANON_EOS_Aperture:
1573 case PTP_DPC_CANON_EOS_ShutterSpeed:
1574 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00001575 case PTP_DPC_CANON_EOS_FocusMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001576 case PTP_DPC_CANON_EOS_ColorSpace:
1577 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleije29ca682010-01-30 08:15:25 +00001578 case PTP_DPC_CANON_EOS_BatterySelect:
Linus Walleijd4637502009-06-14 23:03:33 +00001579 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001580 case PTP_DPC_CANON_EOS_DriveMode:
1581 case PTP_DPC_CANON_EOS_AEB:
Linus Walleije29ca682010-01-30 08:15:25 +00001582 case PTP_DPC_CANON_EOS_BracketMode:
1583 case PTP_DPC_CANON_EOS_QuickReviewTime:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001584 case PTP_DPC_CANON_EOS_EVFMode:
1585 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001586 dpd->DataType = PTP_DTC_UINT16;
1587 break;
1588 case PTP_DPC_CANON_EOS_PictureStyle:
1589 case PTP_DPC_CANON_EOS_WhiteBalance:
1590 case PTP_DPC_CANON_EOS_MeteringMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001591 case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001592 dpd->DataType = PTP_DTC_UINT8;
1593 break;
1594 case PTP_DPC_CANON_EOS_Owner:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001595 case PTP_DPC_CANON_EOS_Artist:
1596 case PTP_DPC_CANON_EOS_Copyright:
1597 case PTP_DPC_CANON_EOS_SerialNumber:
1598 case PTP_DPC_CANON_EOS_LensName:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001599 dpd->DataType = PTP_DTC_STR;
1600 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001601 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
1602 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
1603 dpd->DataType = PTP_DTC_INT16;
1604 break;
1605 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
Linus Walleij7e756532009-05-06 21:25:09 +00001606 case 0xd114:
Linus Walleij7e756532009-05-06 21:25:09 +00001607 case PTP_DPC_CANON_EOS_DPOFVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001608 dpd->DataType = PTP_DTC_UINT16;
1609 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
1610 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001611 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001612 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001613 case PTP_DPC_CANON_EOS_CustomFunc1:
1614 case PTP_DPC_CANON_EOS_CustomFunc2:
1615 case PTP_DPC_CANON_EOS_CustomFunc3:
1616 case PTP_DPC_CANON_EOS_CustomFunc4:
1617 case PTP_DPC_CANON_EOS_CustomFunc5:
1618 case PTP_DPC_CANON_EOS_CustomFunc6:
1619 case PTP_DPC_CANON_EOS_CustomFunc7:
1620 case PTP_DPC_CANON_EOS_CustomFunc8:
1621 case PTP_DPC_CANON_EOS_CustomFunc9:
1622 case PTP_DPC_CANON_EOS_CustomFunc10:
1623 case PTP_DPC_CANON_EOS_CustomFunc11:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001624 dpd->DataType = PTP_DTC_UINT8;
1625 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 +00001626 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001627 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001628 /* custom func entries look like this on the 400D: '5 0 0 0 ?' = 4 bytes size + 1 byte data */
Linus Walleije206af62011-04-19 01:51:39 +02001629 xdata += 4;
Linus Walleij7e756532009-05-06 21:25:09 +00001630 break;
1631 /* yet unknown 32bit props */
1632 case PTP_DPC_CANON_EOS_ColorTemperature:
Linus Walleij7e756532009-05-06 21:25:09 +00001633 case PTP_DPC_CANON_EOS_WftStatus:
1634 case PTP_DPC_CANON_EOS_LensStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001635 case PTP_DPC_CANON_EOS_CardExtension:
1636 case PTP_DPC_CANON_EOS_TempStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001637 case PTP_DPC_CANON_EOS_PhotoStudioMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001638 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
1639 case PTP_DPC_CANON_EOS_EVFSharpness:
1640 case PTP_DPC_CANON_EOS_EVFWBMode:
1641 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
1642 case PTP_DPC_CANON_EOS_EVFColorTemp:
Linus Walleijd4637502009-06-14 23:03:33 +00001643 case PTP_DPC_CANON_EOS_EVFRecordStatus:
1644 case PTP_DPC_CANON_EOS_ExposureSimMode:
1645 case PTP_DPC_CANON_EOS_LvAfSystem:
1646 case PTP_DPC_CANON_EOS_MovSize:
1647 case PTP_DPC_CANON_EOS_DepthOfField:
1648 case PTP_DPC_CANON_EOS_LvViewTypeSelect:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001649 case PTP_DPC_CANON_EOS_CustomFuncEx:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001650 dpd->DataType = PTP_DTC_UINT32;
Linus Walleij7e756532009-05-06 21:25:09 +00001651 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 +00001652 if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
1653 ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
1654 for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
Linus Walleije206af62011-04-19 01:51:39 +02001655 ptp_debug (params, " %d: 0x%8x", j, ((uint32_t*)xdata)[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001656 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001657 /* ImageFormat properties have to be ignored here, see special handling below */
1658 case PTP_DPC_CANON_EOS_ImageFormat:
1659 case PTP_DPC_CANON_EOS_ImageFormatCF:
1660 case PTP_DPC_CANON_EOS_ImageFormatSD:
1661 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1662 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001663 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001664 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1665 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001666 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001667 break;
1668 }
1669 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001670 case PTP_DTC_UINT32:
Linus Walleije206af62011-04-19 01:51:39 +02001671 dpd->FactoryDefaultValue.u32 = dtoh32a(xdata);
1672 dpd->CurrentValue.u32 = dtoh32a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001673 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001674 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001675 case PTP_DTC_UINT16:
Linus Walleije206af62011-04-19 01:51:39 +02001676 dpd->FactoryDefaultValue.u16 = dtoh16a(xdata);
1677 dpd->CurrentValue.u16 = dtoh16a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001678 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001679 break;
1680 case PTP_DTC_UINT8:
Linus Walleije206af62011-04-19 01:51:39 +02001681 dpd->FactoryDefaultValue.u8 = dtoh8a(xdata);
1682 dpd->CurrentValue.u8 = dtoh8a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001683 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001684 break;
1685 case PTP_DTC_STR: {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001686#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001687 uint8_t len = 0;
1688 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1689 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001690#else
Linus Walleij0d762cc2010-04-04 23:34:27 +00001691 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001692 dpd->FactoryDefaultValue.str = strdup( (char*)xdata );
Linus Walleij0d762cc2010-04-04 23:34:27 +00001693
1694 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001695 dpd->CurrentValue.str = strdup( (char*)xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001696#endif
Linus Walleij7e756532009-05-06 21:25:09 +00001697 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001698 break;
1699 }
1700 default:
1701 /* debug is printed in switch above this one */
1702 break;
1703 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001704
Linus Walleijd7072c32010-12-07 20:43:00 +00001705 /* ImageFormat special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
1706 switch (proptype) {
1707 case PTP_DPC_CANON_EOS_ImageFormat:
1708 case PTP_DPC_CANON_EOS_ImageFormatCF:
1709 case PTP_DPC_CANON_EOS_ImageFormatSD:
1710 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1711 dpd->DataType = PTP_DTC_UINT16;
Linus Walleije206af62011-04-19 01:51:39 +02001712 dpd->FactoryDefaultValue.u16 = ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleijd7072c32010-12-07 20:43:00 +00001713 dpd->CurrentValue.u16 = dpd->FactoryDefaultValue.u16;
1714 ptp_debug (params,"event %d: decoded imageformat, currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
1715 break;
1716 }
1717
Linus Walleijf0bf4372007-07-01 21:47:38 +00001718 break;
1719 }
Linus Walleijd7072c32010-12-07 20:43:00 +00001720 case PTP_EC_CANON_EOS_CameraStatusChanged:
1721 ptp_debug (params, "event %d: EOS event CameraStatusChanged (size %d)", i, size);
1722 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS;
1723 (*ce)[i].u.status = dtoh32a(curdata+8);
Linus Walleij9e09ad02011-02-10 13:14:01 +01001724 params->eos_camerastatus = dtoh32a(curdata+8);
Linus Walleijd7072c32010-12-07 20:43:00 +00001725 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001726 case 0: /* end marker */
1727 if (size == 8) /* no output */
1728 break;
1729 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
1730 break;
Linus Walleij96aa0e32012-03-25 12:25:25 +02001731 case PTP_EC_CANON_EOS_BulbExposureTime:
1732 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1733 (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789"));
1734 sprintf ((*ce)[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8));
1735 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001736 default:
Linus Walleijd4637502009-06-14 23:03:33 +00001737 switch (type) {
Linus Walleijd7072c32010-12-07 20:43:00 +00001738#define XX(x) case PTP_EC_CANON_EOS_##x: \
1739 ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); \
1740 (*ce)[i].u.info = malloc(strlen("unhandled EOS event "#x" (size 123456789)")); \
1741 sprintf ((*ce)[i].u.info, "unhandled EOS event "#x" (size %d)", size); \
1742 break;
Linus Walleijd4637502009-06-14 23:03:33 +00001743 XX(RequestGetEvent)
1744 XX(ObjectRemoved)
1745 XX(RequestGetObjectInfoEx)
1746 XX(StorageStatusChanged)
1747 XX(StorageInfoChanged)
1748 XX(ObjectInfoChangedEx)
1749 XX(ObjectContentChanged)
Linus Walleijd4637502009-06-14 23:03:33 +00001750 XX(WillSoonShutdown)
1751 XX(ShutdownTimerUpdated)
1752 XX(RequestCancelTransfer)
1753 XX(RequestObjectTransferDT)
1754 XX(RequestCancelTransferDT)
1755 XX(StoreAdded)
1756 XX(StoreRemoved)
1757 XX(BulbExposureTime)
1758 XX(RecordingTime)
1759 XX(RequestObjectTransferTS)
1760 XX(AfResult)
1761#undef XX
1762 default:
1763 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
1764 break;
1765 }
Linus Walleij7e756532009-05-06 21:25:09 +00001766 if (size >= 0x8) { /* event info */
1767 int j;
Linus Walleijd4637502009-06-14 23:03:33 +00001768 for (j=8;j<size;j++)
1769 ptp_debug (params, " %d: %02x", j, curdata[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001770 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001771 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1772 break;
1773 }
1774 curdata += size;
1775 i++;
Linus Walleij9d22ce02008-05-28 20:39:29 +00001776 if ((size == 8) && (type == 0))
1777 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001778 }
Linus Walleij0d762cc2010-04-04 23:34:27 +00001779 if (!entries) {
1780 free (*ce);
1781 *ce = NULL;
1782 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001783 return entries;
1784}
1785
1786/*
Linus Walleijb02a0662006-04-25 08:05:09 +00001787 PTP USB Event container unpack for Nikon events.
1788*/
1789#define PTP_nikon_ec_Length 0
1790#define PTP_nikon_ec_Code 2
1791#define PTP_nikon_ec_Param1 4
1792#define PTP_nikon_ec_Size 6
1793static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001794ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00001795{
1796 int i;
1797
1798 *ec = NULL;
1799 if (data == NULL)
1800 return;
1801 if (len < PTP_nikon_ec_Code)
1802 return;
1803 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
1804 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
1805 return;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001806 if (!*cnt)
1807 return;
1808
Linus Walleij7e756532009-05-06 21:25:09 +00001809 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00001810
1811 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00001812 memset(&(*ec)[i],0,sizeof(PTPContainer));
1813 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
1814 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
1815 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00001816 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001817}
1818
1819
Linus Walleijb02a0662006-04-25 08:05:09 +00001820static inline uint32_t
1821ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
1822 int i, len = 0;
1823 uint8_t retlen;
1824 unsigned char *curdata;
1825
1826 len = 2*(strlen(text->title)+1)+1+
1827 2*(strlen(text->line[0])+1)+1+
1828 2*(strlen(text->line[1])+1)+1+
1829 2*(strlen(text->line[2])+1)+1+
1830 2*(strlen(text->line[3])+1)+1+
1831 2*(strlen(text->line[4])+1)+1+
1832 4*2+2*4+2+4+2+5*4*2;
1833 *data = malloc(len);
1834 if (!*data) return 0;
1835
1836 curdata = *data;
1837 htod16a(curdata,100);curdata+=2;
1838 htod16a(curdata,1);curdata+=2;
1839 htod16a(curdata,0);curdata+=2;
1840 htod16a(curdata,1000);curdata+=2;
1841
1842 htod32a(curdata,0);curdata+=4;
1843 htod32a(curdata,0);curdata+=4;
1844
1845 htod16a(curdata,6);curdata+=2;
1846 htod32a(curdata,0);curdata+=4;
1847
1848 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1849 htod16a(curdata,0x10);curdata+=2;
1850
1851 for (i=0;i<5;i++) {
1852 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1853 htod16a(curdata,0x10);curdata+=2;
1854 htod16a(curdata,0x01);curdata+=2;
1855 htod16a(curdata,0x02);curdata+=2;
1856 htod16a(curdata,0x06);curdata+=2;
1857 }
1858 return len;
1859}
Linus Walleij7347d0f2006-10-23 07:23:39 +00001860
1861#define ptp_canon_dir_version 0x00
1862#define ptp_canon_dir_ofc 0x02
1863#define ptp_canon_dir_unk1 0x04
1864#define ptp_canon_dir_objectid 0x08
1865#define ptp_canon_dir_parentid 0x0c
1866#define ptp_canon_dir_previd 0x10 /* in same dir */
1867#define ptp_canon_dir_nextid 0x14 /* in same dir */
1868#define ptp_canon_dir_nextchild 0x18 /* down one dir */
1869#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
1870#define ptp_canon_dir_name 0x20
1871#define ptp_canon_dir_flags 0x2c
1872#define ptp_canon_dir_size 0x30
1873#define ptp_canon_dir_unixtime 0x34
1874#define ptp_canon_dir_year 0x38
1875#define ptp_canon_dir_month 0x39
1876#define ptp_canon_dir_mday 0x3a
1877#define ptp_canon_dir_hour 0x3b
1878#define ptp_canon_dir_minute 0x3c
1879#define ptp_canon_dir_second 0x3d
1880#define ptp_canon_dir_unk2 0x3e
1881#define ptp_canon_dir_thumbsize 0x40
1882#define ptp_canon_dir_width 0x44
1883#define ptp_canon_dir_height 0x48
1884
1885static inline uint16_t
1886ptp_unpack_canon_directory (
1887 PTPParams *params,
1888 unsigned char *dir,
1889 uint32_t cnt,
1890 PTPObjectHandles *handles,
1891 PTPObjectInfo **oinfos, /* size(handles->n) */
1892 uint32_t **flags /* size(handles->n) */
1893) {
1894 unsigned int i, j, nrofobs = 0, curob = 0;
1895
1896#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
1897 for (i=0;i<cnt;i++)
1898 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
1899 handles->n = nrofobs;
1900 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
1901 if (!handles->Handler) return PTP_RC_GeneralError;
1902 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
1903 if (!*oinfos) return PTP_RC_GeneralError;
1904 *flags = calloc(sizeof((*flags)[0]),nrofobs);
1905 if (!*flags) return PTP_RC_GeneralError;
1906
1907 /* Migrate data into objects ids, handles into
1908 * the object handler array.
1909 */
1910 curob = 0;
1911 for (i=0;i<cnt;i++) {
1912 unsigned char *cur = dir+i*0x4c;
1913 PTPObjectInfo *oi = (*oinfos)+curob;
1914
1915 if (!ISOBJECT(cur))
1916 continue;
1917
1918 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
1919 oi->StorageID = 0xffffffff;
1920 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
1921 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
1922 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
1923 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
1924 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
1925 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
1926 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
1927 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
1928 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
1929 curob++;
1930 }
1931 /* Walk over Storage ID entries and distribute the IDs to
1932 * the parent objects. */
1933 for (i=0;i<cnt;i++) {
1934 unsigned char *cur = dir+i*0x4c;
1935 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1936
1937 if (ISOBJECT(cur))
1938 continue;
1939 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1940 if (j == handles->n) continue;
1941 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
1942 }
1943 /* Walk over all objects and distribute the storage ids */
1944 while (1) {
1945 int changed = 0;
1946 for (i=0;i<cnt;i++) {
1947 unsigned char *cur = dir+i*0x4c;
1948 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
1949 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
1950 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1951 uint32_t storageid;
1952
1953 if (!ISOBJECT(cur))
1954 continue;
1955 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
1956 if (j == handles->n) {
1957 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
1958 continue;
1959 }
1960 storageid = (*oinfos)[j].StorageID;
1961 if (storageid == 0xffffffff) continue;
1962 if (nextoid != 0xffffffff) {
1963 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
1964 if (j == handles->n) {
1965 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
1966 continue;
1967 }
1968 if ((*oinfos)[j].StorageID == 0xffffffff) {
1969 (*oinfos)[j].StorageID = storageid;
1970 changed++;
1971 }
1972 }
1973 if (nextchild != 0xffffffff) {
1974 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1975 if (j == handles->n) {
1976 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
1977 continue;
1978 }
1979 if ((*oinfos)[j].StorageID == 0xffffffff) {
1980 (*oinfos)[j].StorageID = storageid;
1981 changed++;
1982 }
1983 }
1984 }
1985 /* Check if we:
1986 * - changed no entry (nothing more to do)
1987 * - changed all of them at once (usually happens)
1988 * break if we do.
1989 */
1990 if (!changed || (changed==nrofobs-1))
1991 break;
1992 }
1993#undef ISOBJECT
1994 return PTP_RC_OK;
1995}