blob: 716e8cbc96ec1f82761d78f23a33a663513e0609 [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 */
Marcus Meissner0546a762012-04-10 18:49:10 +0200476 oidata=malloc(PTP_oi_MaxLen + params->ocs64*4);
477 *oidataptr=oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000478 /* the caller should free it after use! */
479#if 0
480 char *capture_date="20020101T010101"; /* XXX Fake date */
481#endif
Marcus Meissner0546a762012-04-10 18:49:10 +0200482 memset (oidata, 0, PTP_oi_MaxLen + params->ocs64*4);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000483 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
484 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
485 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
486 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
Marcus Meissner0546a762012-04-10 18:49:10 +0200487 if (params->ocs64)
488 oidata += 4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000489 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
490 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
491 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
492 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
493 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
494 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
495 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
496 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
497 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
498 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
499 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
500
501 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
502/*
503 filenamelen=(uint8_t)strlen(oi->Filename);
504 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
505 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
506 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
507 }
508*/
509 /*
510 *XXX Fake date.
511 * for example Kodak sets Capture date on the basis of EXIF data.
512 * Spec says that this field is from perspective of Initiator.
513 */
514#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
515 capturedatelen=strlen(capture_date);
516 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
517 capturedatelen+1);
518 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
519 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
520 }
521 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
522 capturedatelen+1);
523 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
524 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
525 capture_date[i];
526 }
527#endif
528 /* XXX this function should return dataset length */
Marcus Meissner0546a762012-04-10 18:49:10 +0200529 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3)+params->ocs64*4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000530}
531
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000532static time_t
Linus Walleij6db174f2009-05-09 13:15:26 +0000533ptp_unpack_PTPTIME (const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000534 char ptpdate[40];
535 char tmp[5];
536 int ptpdatelen;
537 struct tm tm;
538
539 if (!str)
540 return 0;
541 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000542 if (ptpdatelen >= sizeof (ptpdate)) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000543 /*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000544 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000545 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000546 strcpy (ptpdate, str);
Linus Walleij7e756532009-05-06 21:25:09 +0000547 if (ptpdatelen<15) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000548 /*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000549 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000550 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000551
552 memset(&tm,0,sizeof(tm));
553 strncpy (tmp, ptpdate, 4);
554 tmp[4] = 0;
555 tm.tm_year=atoi (tmp) - 1900;
556 strncpy (tmp, ptpdate + 4, 2);
557 tmp[2] = 0;
558 tm.tm_mon = atoi (tmp) - 1;
559 strncpy (tmp, ptpdate + 6, 2);
560 tmp[2] = 0;
561 tm.tm_mday = atoi (tmp);
562 strncpy (tmp, ptpdate + 9, 2);
563 tmp[2] = 0;
564 tm.tm_hour = atoi (tmp);
565 strncpy (tmp, ptpdate + 11, 2);
566 tmp[2] = 0;
567 tm.tm_min = atoi (tmp);
568 strncpy (tmp, ptpdate + 13, 2);
569 tmp[2] = 0;
570 tm.tm_sec = atoi (tmp);
Linus Walleije206af62011-04-19 01:51:39 +0200571 tm.tm_isdst = -1;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000572 return mktime (&tm);
573}
574
Linus Walleijb02a0662006-04-25 08:05:09 +0000575static inline void
576ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000577{
578 uint8_t filenamelen;
579 uint8_t capturedatelen;
580 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000581
582 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
583 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
584 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
585 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200586
587 /* Stupid Samsung Galaxy developers emit a 64bit objectcompressedsize */
588 if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0)) {
589 params->ocs64 = 1;
590 data += 4;
591 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000592 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
593 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
594 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
595 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
596 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
597 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
598 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
599 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
600 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
601 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
602 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200603
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000604 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
605
606 capture_date = ptp_unpack_string(params, data,
607 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
608 /* subset of ISO 8601, without '.s' tenths of second and
609 * time zone
610 */
Linus Walleij6db174f2009-05-09 13:15:26 +0000611 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000612 free(capture_date);
613
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000614 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000615 capture_date = ptp_unpack_string(params, data,
616 PTP_oi_filenamelen+filenamelen*2
617 +capturedatelen*2+2,&capturedatelen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000618 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000619 free(capture_date);
620}
621
622/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000623#define CTVAL(target,func) { \
624 if (total - *offset < sizeof(target)) \
625 return 0; \
626 target = func(&data[*offset]); \
627 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000628}
629
Linus Walleijb02a0662006-04-25 08:05:09 +0000630#define RARR(val,member,func) { \
631 int n,j; \
632 if (total - *offset < sizeof(uint32_t)) \
633 return 0; \
634 n = dtoh32a (&data[*offset]); \
635 *offset += sizeof(uint32_t); \
636 \
637 val->a.count = n; \
638 val->a.v = malloc(sizeof(val->a.v[0])*n); \
639 if (!val->a.v) return 0; \
640 for (j=0;j<n;j++) \
641 CTVAL(val->a.v[j].member, func); \
642}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000643
Linus Walleijb02a0662006-04-25 08:05:09 +0000644static inline int
645ptp_unpack_DPV (
646 PTPParams *params, unsigned char* data, int *offset, int total,
647 PTPPropertyValue* value, uint16_t datatype
648) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000649 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000650 case PTP_DTC_INT8:
651 CTVAL(value->i8,dtoh8a);
652 break;
653 case PTP_DTC_UINT8:
654 CTVAL(value->u8,dtoh8a);
655 break;
656 case PTP_DTC_INT16:
657 CTVAL(value->i16,dtoh16a);
658 break;
659 case PTP_DTC_UINT16:
660 CTVAL(value->u16,dtoh16a);
661 break;
662 case PTP_DTC_INT32:
663 CTVAL(value->i32,dtoh32a);
664 break;
665 case PTP_DTC_UINT32:
666 CTVAL(value->u32,dtoh32a);
667 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000668 case PTP_DTC_INT64:
669 CTVAL(value->i64,dtoh64a);
670 break;
671 case PTP_DTC_UINT64:
672 CTVAL(value->u64,dtoh64a);
673 break;
674
Linus Walleij037a1252006-12-16 20:36:52 +0000675 case PTP_DTC_UINT128:
676 *offset += 16;
677 /*fprintf(stderr,"unhandled unpack of uint128n");*/
678 break;
679 case PTP_DTC_INT128:
680 *offset += 16;
681 /*fprintf(stderr,"unhandled unpack of int128n");*/
682 break;
683
684
685
Linus Walleijb02a0662006-04-25 08:05:09 +0000686 case PTP_DTC_AINT8:
687 RARR(value,i8,dtoh8a);
688 break;
689 case PTP_DTC_AUINT8:
690 RARR(value,u8,dtoh8a);
691 break;
692 case PTP_DTC_AUINT16:
693 RARR(value,u16,dtoh16a);
694 break;
695 case PTP_DTC_AINT16:
696 RARR(value,i16,dtoh16a);
697 break;
698 case PTP_DTC_AUINT32:
699 RARR(value,u32,dtoh32a);
700 break;
701 case PTP_DTC_AINT32:
702 RARR(value,i32,dtoh32a);
703 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000704 case PTP_DTC_AUINT64:
705 RARR(value,u64,dtoh64a);
706 break;
707 case PTP_DTC_AINT64:
708 RARR(value,i64,dtoh64a);
709 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000710 /* XXX: other int types are unimplemented */
711 /* XXX: other int arrays are unimplemented also */
712 case PTP_DTC_STR: {
713 uint8_t len;
714 /* XXX: max size */
715 value->str = ptp_unpack_string(params,data,*offset,&len);
716 *offset += len*2+1;
717 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000718 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000719 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000720 }
Linus Walleij037a1252006-12-16 20:36:52 +0000721 default:
722 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000723 }
724 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000725}
726
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000727/* Device Property pack/unpack */
728
729#define PTP_dpd_DevicePropertyCode 0
730#define PTP_dpd_DataType 2
731#define PTP_dpd_GetSet 4
732#define PTP_dpd_FactoryDefaultValue 5
733
Linus Walleijb02a0662006-04-25 08:05:09 +0000734static inline int
735ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000736{
Linus Walleijb02a0662006-04-25 08:05:09 +0000737 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000738
Linus Walleijb02a0662006-04-25 08:05:09 +0000739 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000740 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
741 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
742 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000743 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000744
745 offset = PTP_dpd_FactoryDefaultValue;
746 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
747 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000748 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
749 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000750 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
751 if (!ret) goto outofmemory;
752
753 /* if offset==0 then Data Type format is not supported by this
754 code or the Data Type is a string (with two empty strings as
755 values). In both cases Form Flag should be set to 0x00 and FORM is
756 not present. */
757
Linus Walleijb02a0662006-04-25 08:05:09 +0000758 if (offset==PTP_dpd_FactoryDefaultValue)
759 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000760
Linus Walleijb02a0662006-04-25 08:05:09 +0000761 dpd->FormFlag=dtoh8a(&data[offset]);
762 offset+=sizeof(uint8_t);
763
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000764 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000765 case PTP_DPFF_Range:
766 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
767 if (!ret) goto outofmemory;
768 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
769 if (!ret) goto outofmemory;
770 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
771 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000772 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000773 case PTP_DPFF_Enumeration: {
774 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000775#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000776 N = dtoh16a(&data[offset]);
777 offset+=sizeof(uint16_t);
778 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
779 if (!dpd->FORM.Enum.SupportedValue)
780 goto outofmemory;
781
782 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
783 for (i=0;i<N;i++) {
784 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
785
786 /* Slightly different handling here. The HP PhotoSmart 120
787 * specifies an enumeration with N in wrong endian
788 * 00 01 instead of 01 00, so we count the enum just until the
789 * the end of the packet.
790 */
791 if (!ret) {
792 if (!i)
793 goto outofmemory;
794 dpd->FORM.Enum.NumberOfValues = i;
795 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000796 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000797 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000798 }
799 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000800#undef N
801 return 1;
802outofmemory:
803 ptp_free_devicepropdesc(dpd);
804 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000805}
806
Linus Walleijb02a0662006-04-25 08:05:09 +0000807/* (MTP) Object Property pack/unpack */
808#define PTP_opd_ObjectPropertyCode 0
809#define PTP_opd_DataType 2
810#define PTP_opd_GetSet 4
811#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000812
Linus Walleijb02a0662006-04-25 08:05:09 +0000813static inline int
814ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000815{
Linus Walleijb02a0662006-04-25 08:05:09 +0000816 int offset=0, ret;
817
818 memset (opd, 0, sizeof(*opd));
819 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
820 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
821 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
822
823 offset = PTP_opd_FactoryDefaultValue;
824 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
825 if (!ret) goto outofmemory;
826
827 opd->GroupCode=dtoh32a(&data[offset]);
828 offset+=sizeof(uint32_t);
829
830 opd->FormFlag=dtoh8a(&data[offset]);
831 offset+=sizeof(uint8_t);
832
833 switch (opd->FormFlag) {
834 case PTP_OPFF_Range:
835 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
836 if (!ret) goto outofmemory;
837 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
838 if (!ret) goto outofmemory;
839 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
840 if (!ret) goto outofmemory;
841 break;
842 case PTP_OPFF_Enumeration: {
843 int i;
844#define N opd->FORM.Enum.NumberOfValues
845 N = dtoh16a(&data[offset]);
846 offset+=sizeof(uint16_t);
847 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
848 if (!opd->FORM.Enum.SupportedValue)
849 goto outofmemory;
850
851 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
852 for (i=0;i<N;i++) {
853 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
854
855 /* Slightly different handling here. The HP PhotoSmart 120
856 * specifies an enumeration with N in wrong endian
857 * 00 01 instead of 01 00, so we count the enum just until the
858 * the end of the packet.
859 */
860 if (!ret) {
861 if (!i)
862 goto outofmemory;
863 opd->FORM.Enum.NumberOfValues = i;
864 break;
865 }
866 }
867#undef N
868 }
869 }
870 return 1;
871outofmemory:
872 ptp_free_objectpropdesc(opd);
873 return 0;
874}
875
876
877static inline uint32_t
878ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
879{
880 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000881 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000882 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000883
884 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000885 case PTP_DTC_INT8:
886 size=sizeof(int8_t);
887 dpv=malloc(size);
888 htod8a(dpv,value->i8);
889 break;
890 case PTP_DTC_UINT8:
891 size=sizeof(uint8_t);
892 dpv=malloc(size);
893 htod8a(dpv,value->u8);
894 break;
895 case PTP_DTC_INT16:
896 size=sizeof(int16_t);
897 dpv=malloc(size);
898 htod16a(dpv,value->i16);
899 break;
900 case PTP_DTC_UINT16:
901 size=sizeof(uint16_t);
902 dpv=malloc(size);
903 htod16a(dpv,value->u16);
904 break;
905 case PTP_DTC_INT32:
906 size=sizeof(int32_t);
907 dpv=malloc(size);
908 htod32a(dpv,value->i32);
909 break;
910 case PTP_DTC_UINT32:
911 size=sizeof(uint32_t);
912 dpv=malloc(size);
913 htod32a(dpv,value->u32);
914 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000915 case PTP_DTC_INT64:
916 size=sizeof(int64_t);
917 dpv=malloc(size);
918 htod64a(dpv,value->i64);
919 break;
920 case PTP_DTC_UINT64:
921 size=sizeof(uint64_t);
922 dpv=malloc(size);
923 htod64a(dpv,value->u64);
924 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000925 case PTP_DTC_AUINT8:
926 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
927 dpv=malloc(size);
928 htod32a(dpv,value->a.count);
929 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000930 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000931 break;
932 case PTP_DTC_AINT8:
933 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
934 dpv=malloc(size);
935 htod32a(dpv,value->a.count);
936 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000937 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000938 break;
939 case PTP_DTC_AUINT16:
940 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
941 dpv=malloc(size);
942 htod32a(dpv,value->a.count);
943 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000944 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000945 break;
946 case PTP_DTC_AINT16:
947 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
948 dpv=malloc(size);
949 htod32a(dpv,value->a.count);
950 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000951 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000952 break;
953 case PTP_DTC_AUINT32:
954 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
955 dpv=malloc(size);
956 htod32a(dpv,value->a.count);
957 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000958 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000959 break;
960 case PTP_DTC_AINT32:
961 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
962 dpv=malloc(size);
963 htod32a(dpv,value->a.count);
964 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000965 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000966 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000967 case PTP_DTC_AUINT64:
968 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
969 dpv=malloc(size);
970 htod32a(dpv,value->a.count);
971 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000972 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +0000973 break;
974 case PTP_DTC_AINT64:
975 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
976 dpv=malloc(size);
977 htod32a(dpv,value->a.count);
978 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000979 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +0000980 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000981 /* XXX: other int types are unimplemented */
982 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000983 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000984 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000985 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000986 }
987 *dpvptr=dpv;
988 return size;
989}
990
Linus Walleij99310d42006-11-01 08:29:39 +0000991#define MAX_MTP_PROPS 127
992static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +0000993ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +0000994{
995 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000996 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +0000997 unsigned char *packedprops[MAX_MTP_PROPS];
998 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +0000999 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +00001000 uint16_t packedpropsids[MAX_MTP_PROPS];
1001 uint16_t packedpropstypes[MAX_MTP_PROPS];
1002 uint32_t totalsize = 0;
1003 uint32_t bufp = 0;
1004 uint32_t noitems = 0;
1005 uint32_t i;
1006
1007 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +00001008 propitr = props;
1009 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +00001010 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +00001011 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +00001012 totalsize += sizeof(uint32_t); /* Object ID */
1013 /* Metadata type */
1014 packedpropsids[noitems]=propitr->property;
1015 totalsize += sizeof(uint16_t);
1016 /* Data type */
1017 packedpropstypes[noitems]= propitr->datatype;
1018 totalsize += sizeof(uint16_t);
1019 /* Add each property to be sent. */
1020 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
1021 totalsize += packedpropslens[noitems];
1022 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001023 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +00001024 }
1025
1026 /* Allocate memory for the packed property list */
1027 opldata = malloc(totalsize);
1028
1029 htod32a(&opldata[bufp],noitems);
1030 bufp += 4;
1031
1032 /* Copy into a nice packed list */
1033 for (i = 0; i < noitems; i++) {
1034 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +00001035 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +00001036 bufp += sizeof(uint32_t);
1037 htod16a(&opldata[bufp],packedpropsids[i]);
1038 bufp += sizeof(uint16_t);
1039 htod16a(&opldata[bufp],packedpropstypes[i]);
1040 bufp += sizeof(uint16_t);
1041 /* The copy the actual property */
1042 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1043 bufp += packedpropslens[i];
1044 free(packedprops[i]);
1045 }
1046 *opldataptr = opldata;
1047 return totalsize;
1048}
1049
Linus Walleij1e9a0332007-09-12 19:35:56 +00001050static int
1051_compare_func(const void* x, const void *y) {
1052 const MTPProperties *px = x;
1053 const MTPProperties *py = y;
1054
1055 return px->ObjectHandle - py->ObjectHandle;
1056}
1057
Richard Low8d82d2f2006-11-16 20:37:43 +00001058static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001059ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001060{
Linus Walleij277cd532006-11-20 14:57:46 +00001061 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001062 MTPProperties *props = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001063 int offset = 0, i;
1064
1065 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +00001066 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001067 return 0;
1068 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001069 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001070 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001071 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001072 props = malloc(prop_count * sizeof(MTPProperties));
1073 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001074 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001075 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001076 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001077 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1078 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001079 qsort (props, i, sizeof(MTPProperties),_compare_func);
1080 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001081 return i;
1082 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001083 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001084 data += sizeof(uint32_t);
1085 len -= sizeof(uint32_t);
1086
Linus Walleij1e9a0332007-09-12 19:35:56 +00001087 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001088 data += sizeof(uint16_t);
1089 len -= sizeof(uint16_t);
1090
Linus Walleij1e9a0332007-09-12 19:35:56 +00001091 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001092 data += sizeof(uint16_t);
1093 len -= sizeof(uint16_t);
1094
1095 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001096 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001097 data += offset;
1098 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001099 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001100 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1101 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001102 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001103}
1104
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001105/*
1106 PTP USB Event container unpack
1107 Copyright (c) 2003 Nikolai Kopanygin
1108*/
1109
1110#define PTP_ec_Length 0
1111#define PTP_ec_Type 4
1112#define PTP_ec_Code 6
1113#define PTP_ec_TransId 8
1114#define PTP_ec_Param1 12
1115#define PTP_ec_Param2 16
1116#define PTP_ec_Param3 20
1117
Linus Walleijb02a0662006-04-25 08:05:09 +00001118static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001119ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001120{
Linus Walleij7e756532009-05-06 21:25:09 +00001121 int length;
1122 int type;
1123
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001124 if (data==NULL)
1125 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001126 memset(ec,0,sizeof(*ec));
1127 length=dtoh32a(&data[PTP_ec_Length]);
1128 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001129
Linus Walleij7e756532009-05-06 21:25:09 +00001130 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1131 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1132
1133 if (type!=PTP_USB_CONTAINER_EVENT) {
1134 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1135 return;
1136 }
1137 if (length>=(PTP_ec_Param1+4)) {
1138 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1139 ec->Nparam=1;
1140 }
1141 if (length>=(PTP_ec_Param2+4)) {
1142 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1143 ec->Nparam=2;
1144 }
1145 if (length>=(PTP_ec_Param3+4)) {
1146 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1147 ec->Nparam=3;
1148 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001149}
1150
1151/*
1152 PTP Canon Folder Entry unpack
1153 Copyright (c) 2003 Nikolai Kopanygin
1154*/
1155#define PTP_cfe_ObjectHandle 0
1156#define PTP_cfe_ObjectFormatCode 4
1157#define PTP_cfe_Flags 6
1158#define PTP_cfe_ObjectSize 7
1159#define PTP_cfe_Time 11
1160#define PTP_cfe_Filename 15
1161
Linus Walleijb02a0662006-04-25 08:05:09 +00001162static inline void
1163ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001164{
1165 int i;
1166 if (data==NULL)
1167 return;
1168 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1169 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1170 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001171 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001172 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1173 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001174 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1175}
1176
Linus Walleij96aa0e32012-03-25 12:25:25 +02001177/*
1178 PTP Canon EOS Folder Entry unpack
11790: 00 00 08 a0 objectid
11804: 01 00 02 00 storageid
11818: 01 30 00 00 ofc
118212: 01 00
118314: 00 00
118416: 11 00 00 00
118520: 00 00 00 00
118624: 00 00 00 80
118728: 00 00 08 a0
118832: 4d 49 53 43-00 00 00 00 00 00 00 00 name
118900 00 00 00
119084 bc 74 46 objectime
1191
1192
1193(normal PTP GetObjectInfo)
1194ObjectInfo for 'IMG_0199.JPG':
1195 Object ID: 0x92740c72
1196 StorageID: 0x00020001
1197 ObjectFormat: 0x3801
1198 ProtectionStatus: 0x0000
1199 ObjectCompressedSize: 2217241
1200 ThumbFormat: 0x3808
1201 ThumbCompressedSize: 5122
1202 ThumbPixWidth: 160
1203 ThumbPixHeight: 120
1204 ImagePixWidth: 4000
1205 ImagePixHeight: 3000
1206 ImageBitDepth: 24
1207 ParentObject: 0x92740000
1208 AssociationType: 0x0000
1209 AssociationDesc: 0x00000000
1210 SequenceNumber: 0x00000000
1211 ModificationDate: 0x4d985ff0
1212 CaptureDate: 0x4d985ff0
1213
12140010 38 00 00 00 Size of this entry
12150014 72 0c 74 92 OID
12160018 01 00 02 00 StorageID
1217001c 01 38 00 00 OFC
12180020 00 00 00 00 00 00 00 00 ?
12190028 19 d5 21 00 Size
1220002c 00 00 74 92 ?
12210030 70 0c 74 92 OID
12220034 49 4d 47 5f-30 31 39 39 2e 4a 50 47 IMG_0199.JPG
12230040 00 00 00 00
12240044 10 7c 98 4d Time
1225
1226
1227*/
1228#define PTP_cefe_ObjectHandle 0
1229#define PTP_cefe_StorageID 4
1230#define PTP_cefe_ObjectFormatCode 8
1231#define PTP_cefe_Flags 12
1232#define PTP_cefe_ObjectSize 20
1233#define PTP_cefe_Filename 32
1234#define PTP_cefe_Time 48
1235
1236static inline void
1237ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
1238{
1239 int i;
1240
1241 fe->ObjectHandle=dtoh32a(&data[PTP_cefe_ObjectHandle]);
1242 fe->ObjectFormatCode=dtoh16a(&data[PTP_cefe_ObjectFormatCode]);
1243 fe->Flags=dtoh8a(&data[PTP_cefe_Flags]);
1244 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cefe_ObjectSize]);
1245 fe->Time=(time_t)dtoh32a(&data[PTP_cefe_Time]);
1246 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
1247 fe->Filename[i]=(char)data[PTP_cefe_Filename+i];
1248}
1249
1250
Linus Walleij1a0c3012009-07-23 23:06:58 +00001251static inline uint16_t
1252ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1253{
1254 /*
Marcus Meissner0546a762012-04-10 18:49:10 +02001255 EOS ImageFormat entries (of at least the 5DM2 and the 400D) look like this:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001256 uint32: number of entries / generated files (1 or 2)
1257 uint32: size of this entry in bytes (most likely allways 0x10)
1258 uint32: image type (1 == JPG, 6 == RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001259 uint32: image size (0 == Large, 1 == Medium, 2 == Small, 0xe == S1, 0xf == S2, 0x10 == S3)
Linus Walleij1a0c3012009-07-23 23:06:58 +00001260 uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001261 If the number of entries is 2 the last 4 uint32 repeat.
Linus Walleij1a0c3012009-07-23 23:06:58 +00001262
1263 example:
1264 0: 0x 1
1265 1: 0x 10
1266 2: 0x 6
1267 3: 0x 1
1268 4: 0x 4
1269
Marcus Meissner0546a762012-04-10 18:49:10 +02001270 The idea is to simply 'condense' these values to just one uint16 to be able to conveniently
Linus Walleij1a0c3012009-07-23 23:06:58 +00001271 use the available enumeration facilities (look-up table). The image size and compression
1272 values fully describe the image format. Hence we generate a uint16 with the four nibles set
1273 as follows: entry 1 size | entry 1 compression | entry 2 size | entry 2 compression.
1274 The above example would result in the value 0x1400.
Marcus Meissner0546a762012-04-10 18:49:10 +02001275
1276 The EOS 5D Mark III (and possibly other high-end EOS as well) added the extra fancy S1, S2
1277 and S3 JPEG options. S1 replaces the old Small. -1 the S1/S2/S3 to prevent the 0x10 overflow.
Linus Walleij1a0c3012009-07-23 23:06:58 +00001278 */
1279
1280 const unsigned char* d = *data;
1281 uint32_t n = dtoh32a( d );
1282 uint32_t l, s1, c1, s2 = 0, c2 = 0;
1283
1284 if (n != 1 && n !=2) {
1285 ptp_debug (params, "parsing EOS ImageFormat property failed (n != 1 && n != 2: %d)", n);
1286 return 0;
1287 }
1288
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
1295 d+=4; /* skip type */
1296 s1 = dtoh32a( d+=4 );
1297 c1 = dtoh32a( d+=4 );
1298
1299 if (n == 2) {
1300 l = dtoh32a( d+=4 );
1301 if (l != 0x10) {
1302 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1303 return 0;
1304 }
1305 d+=4; /* skip type */
1306 s2 = dtoh32a( d+=4 );
1307 c2 = dtoh32a( d+=4 );
1308 }
1309
1310 *data = (unsigned char*) d+4;
1311
Marcus Meissner0546a762012-04-10 18:49:10 +02001312 /* deal with S1/S2/S3 JPEG sizes, see above. */
1313 if( s1 >= 0xe )
1314 s1--;
1315 if( s2 >= 0xe )
1316 s2--;
1317
Linus Walleij1a0c3012009-07-23 23:06:58 +00001318 return ((s1 & 0xF) << 12) | ((c1 & 0xF) << 8) | ((s2 & 0xF) << 4) | ((c2 & 0xF) << 0);
1319}
1320
1321static inline uint32_t
1322ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value)
1323{
1324 uint32_t n = (value & 0xFF) ? 2 : 1;
1325 uint32_t s = 4 + 0x10 * n;
1326
1327 if( !data )
1328 return s;
1329
Marcus Meissner0546a762012-04-10 18:49:10 +02001330#define PACK_5DM3_SMALL_JPEG_SIZE( X ) (X) >= 0xd ? (X)+1 : (X)
1331
Linus Walleij1a0c3012009-07-23 23:06:58 +00001332 htod32a(data+=0, n);
1333 htod32a(data+=4, 0x10);
1334 htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001335 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 12) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001336 htod32a(data+=4, (value >> 8) & 0xF);
1337
1338 if (n==2) {
1339 htod32a(data+=4, 0x10);
1340 htod32a(data+=4, ((value >> 0) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001341 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 4) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001342 htod32a(data+=4, (value >> 0) & 0xF);
1343 }
1344
Marcus Meissner0546a762012-04-10 18:49:10 +02001345#undef PACK_5DM3_SMALL_JPEG_SIZE
1346
1347 return s;
1348}
1349
1350static inline char*
1351ptp_unpack_EOS_CustomFuncEx (PTPParams* params, unsigned char** data )
1352{
1353 uint32_t s = dtoh32a( *data );
1354 uint32_t n = s/4, i;
1355 char* str = (char*)malloc( s ); // n is size in uint32, average len(itoa(i)) < 4 -> alloc n chars
1356 if (!str)
1357 return str;
1358 char* p = str;
1359
1360 for (i=0; i < n; ++i)
1361 p += sprintf(p, "%x,", dtoh32a( *data + 4*i ));
1362
1363 return str;
1364}
1365
1366static inline uint32_t
1367ptp_pack_EOS_CustomFuncEx (PTPParams* params, unsigned char* data, char* str)
1368{
1369 uint32_t s = strtoul(str, NULL, 16);
1370 uint32_t n = s/4, i, v;
1371
1372 if (!data)
1373 return s;
1374
1375 for (i=0; i<n; i++)
1376 {
1377 v = strtoul(str, &str, 16);
1378 str++; // skip the ',' delimiter
1379 htod32a(data + i*4, v);
1380 }
1381
Linus Walleij1a0c3012009-07-23 23:06:58 +00001382 return s;
1383}
1384
Linus Walleijb02a0662006-04-25 08:05:09 +00001385/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001386 PTP EOS Changes Entry unpack
1387*/
1388#define PTP_ece_Size 0
1389#define PTP_ece_Type 4
1390
1391#define PTP_ece_Prop_Subtype 8 /* only for properties */
1392#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1393#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1394#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1395#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1396
Linus Walleijd4637502009-06-14 23:03:33 +00001397/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
1398#define PTP_ece_OI_ObjectID 8
1399#define PTP_ece_OI_OFC 0x0c
1400#define PTP_ece_OI_Size 0x14
1401#define PTP_ece_OI_Name 0x1c
1402
1403/* for PTP_EC_CANON_EOS_ObjectAddedEx */
1404#define PTP_ece_OA_ObjectID 8
1405#define PTP_ece_OA_StorageID 0x0c
1406#define PTP_ece_OA_OFC 0x10
1407#define PTP_ece_OA_Size 0x1c
1408#define PTP_ece_OA_Parent 0x20
1409#define PTP_ece_OA_Name 0x28
Linus Walleijf0bf4372007-07-01 21:47:38 +00001410
1411static inline int
1412ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
1413{
1414 int i = 0, entries = 0;
1415 unsigned char *curdata = data;
1416
1417 if (data==NULL)
1418 return 0;
1419 while (curdata - data < datasize) {
1420 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1421 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1422
1423 curdata += size;
1424 if ((size == 8) && (type == 0))
1425 break;
1426 entries++;
1427 }
Linus Walleij9d22ce02008-05-28 20:39:29 +00001428 *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001429 if (!*ce) return 0;
1430
1431 curdata = data;
1432 while (curdata - data < datasize) {
1433 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1434 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1435
Linus Walleijd4637502009-06-14 23:03:33 +00001436 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Linus Walleijd7072c32010-12-07 20:43:00 +00001437 (*ce)[i].u.info = NULL;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001438 switch (type) {
Linus Walleijd4637502009-06-14 23:03:33 +00001439 case PTP_EC_CANON_EOS_ObjectAddedEx:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001440 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
Linus Walleijd4637502009-06-14 23:03:33 +00001441 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
1442 (*ce)[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
1443 (*ce)[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
1444 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
1445 (*ce)[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
1446 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
1447 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);
1448 break;
1449 case PTP_EC_CANON_EOS_RequestObjectTransfer:
1450 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001451 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
Linus Walleijd4637502009-06-14 23:03:33 +00001452 (*ce)[i].u.object.oi.StorageID = 0; /* use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001453 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
Linus Walleijd4637502009-06-14 23:03:33 +00001454 (*ce)[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001455 (*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1456 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001457
Linus Walleijd4637502009-06-14 23:03:33 +00001458 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 +00001459 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001460 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001461 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1462 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1463 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
Linus Walleije206af62011-04-19 01:51:39 +02001464 unsigned char *xdata = &curdata[PTP_ece_Prop_Desc_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00001465 int j;
1466 PTPDevicePropDesc *dpd;
1467
Linus Walleij7e756532009-05-06 21:25:09 +00001468 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 +00001469 for (j=0;j<params->nrofcanon_props;j++)
1470 if (params->canon_props[j].proptype == proptype)
1471 break;
1472 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001473 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001474 break;
1475 }
1476 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001477 /* 1 - uint16 ?
1478 * 3 - uint16
1479 * 7 - string?
1480 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001481 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001482 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1483 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001484 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001485 break;
1486 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001487 if (! propxcnt)
1488 break;
1489
1490 ptp_debug (params, "event %d: propxtype is %x, prop is 0x%04x, data type is 0x%04x, propxcnt is %d.",
1491 i, propxtype, proptype, dpd->DataType, propxcnt);
1492 dpd->FormFlag = PTP_DPFF_Enumeration;
1493 dpd->FORM.Enum.NumberOfValues = propxcnt;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001494 if (dpd->FORM.Enum.SupportedValue) free (dpd->FORM.Enum.SupportedValue);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001495 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1496
1497 switch (proptype) {
1498 case PTP_DPC_CANON_EOS_ImageFormat:
1499 case PTP_DPC_CANON_EOS_ImageFormatCF:
1500 case PTP_DPC_CANON_EOS_ImageFormatSD:
1501 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1502 /* special handling of ImageFormat properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001503 for (j=0;j<propxcnt;j++) {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001504 dpd->FORM.Enum.SupportedValue[j].u16 =
Linus Walleije206af62011-04-19 01:51:39 +02001505 dtoh16( ptp_unpack_EOS_ImageFormat( params, &xdata ) );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001506 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, dpd->FORM.Enum.SupportedValue[j].u16);
1507 }
1508 break;
1509 default:
1510 /* 'normal' enumerated types */
1511 switch (dpd->DataType) {
1512#define XX( TYPE, CONV )\
1513 for (j=0;j<propxcnt;j++) { \
Linus Walleije206af62011-04-19 01:51:39 +02001514 dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \
1515 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \
1516 xdata += 4; /* might only be for propxtype 3 */ \
Linus Walleij1a0c3012009-07-23 23:06:58 +00001517 } \
1518 break;
1519
1520 case PTP_DTC_INT16: XX( i16, dtoh16a );
1521 case PTP_DTC_UINT32: XX( u32, dtoh32a );
1522 case PTP_DTC_UINT16: XX( u16, dtoh16a );
1523 case PTP_DTC_UINT8: XX( u8, dtoh8a );
1524#undef XX
1525 default:
Linus Walleije206af62011-04-19 01:51:39 +02001526 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata));
1527 for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */
1528 ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001529 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001530 }
1531 }
1532 break;
1533 }
Linus Walleij7e756532009-05-06 21:25:09 +00001534 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001535 if (size >= 0xc) { /* property info */
1536 int j;
1537 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
Linus Walleije206af62011-04-19 01:51:39 +02001538 unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00001539 PTPDevicePropDesc *dpd;
1540
Linus Walleij1a0c3012009-07-23 23:06:58 +00001541 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 +00001542 for (j=0;j<params->nrofcanon_props;j++)
1543 if (params->canon_props[j].proptype == proptype)
1544 break;
1545 if (j<params->nrofcanon_props) {
1546 if ( (params->canon_props[j].size != size) ||
Linus Walleije206af62011-04-19 01:51:39 +02001547 (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00001548 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001549 memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001550 }
1551 } else {
1552 if (j)
1553 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1554 else
1555 params->canon_props = malloc(sizeof(params->canon_props[0]));
1556 params->canon_props[j].type = type;
1557 params->canon_props[j].proptype = proptype;
1558 params->canon_props[j].size = size;
1559 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001560 memcpy(params->canon_props[j].data, xdata, size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001561 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1562 params->canon_props[j].dpd.GetSet = 1;
1563 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1564 params->nrofcanon_props = j+1;
1565 }
1566 dpd = &params->canon_props[j].dpd;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001567
Linus Walleijd7072c32010-12-07 20:43:00 +00001568 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
1569 (*ce)[i].u.propid = proptype;
1570
Linus Walleij1a0c3012009-07-23 23:06:58 +00001571 /* fix GetSet value */
1572 switch (proptype) {
1573#define XX(x) case PTP_DPC_CANON_##x:
1574 XX(EOS_FocusMode)
1575 XX(EOS_BatteryPower)
1576 XX(EOS_BatterySelect)
1577 XX(EOS_ModelID)
1578 XX(EOS_PTPExtensionVersion)
1579 XX(EOS_DPOFVersion)
1580 XX(EOS_AvailableShots)
1581 XX(EOS_CurrentStorage)
1582 XX(EOS_CurrentFolder)
1583 XX(EOS_MyMenu)
1584 XX(EOS_MyMenuList)
1585 XX(EOS_HDDirectoryStructure)
1586 XX(EOS_BatteryInfo)
1587 XX(EOS_AdapterInfo)
1588 XX(EOS_LensStatus)
1589 XX(EOS_CardExtension)
1590 XX(EOS_TempStatus)
1591 XX(EOS_ShutterCounter)
1592 XX(EOS_SerialNumber)
1593 XX(EOS_DepthOfFieldPreview)
1594 XX(EOS_EVFRecordStatus)
1595 XX(EOS_LvAfSystem)
1596 XX(EOS_FocusInfoEx)
1597 XX(EOS_DepthOfField)
1598 XX(EOS_Brightness)
1599 XX(EOS_EFComp)
1600 XX(EOS_LensName)
1601 XX(EOS_LensID)
1602#undef XX
1603 dpd->GetSet = PTP_DPGS_Get;
1604 break;
1605 }
1606
1607 /* set DataType */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001608 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001609 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleijd4637502009-06-14 23:03:33 +00001610 case PTP_DPC_CANON_EOS_AvailableShots:
Linus Walleijd4637502009-06-14 23:03:33 +00001611 case PTP_DPC_CANON_EOS_CaptureDestination:
1612 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
1613 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
Linus Walleijd4637502009-06-14 23:03:33 +00001614 case PTP_DPC_CANON_EOS_CurrentStorage:
1615 case PTP_DPC_CANON_EOS_CurrentFolder:
1616 case PTP_DPC_CANON_EOS_ShutterCounter:
1617 case PTP_DPC_CANON_EOS_ModelID:
1618 case PTP_DPC_CANON_EOS_LensID:
1619 case PTP_DPC_CANON_EOS_StroboFiring:
Linus Walleijac052c12007-07-18 18:37:10 +00001620 dpd->DataType = PTP_DTC_UINT32;
1621 break;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001622 /* enumeration for AEM is never provided, but is available to set */
1623 case PTP_DPC_CANON_EOS_AutoExposureMode:
1624 dpd->DataType = PTP_DTC_UINT16;
1625 dpd->FormFlag = PTP_DPFF_Enumeration;
1626 dpd->FORM.Enum.NumberOfValues = 0;
1627 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001628 case PTP_DPC_CANON_EOS_Aperture:
1629 case PTP_DPC_CANON_EOS_ShutterSpeed:
1630 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00001631 case PTP_DPC_CANON_EOS_FocusMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001632 case PTP_DPC_CANON_EOS_ColorSpace:
1633 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleije29ca682010-01-30 08:15:25 +00001634 case PTP_DPC_CANON_EOS_BatterySelect:
Linus Walleijd4637502009-06-14 23:03:33 +00001635 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001636 case PTP_DPC_CANON_EOS_DriveMode:
1637 case PTP_DPC_CANON_EOS_AEB:
Linus Walleije29ca682010-01-30 08:15:25 +00001638 case PTP_DPC_CANON_EOS_BracketMode:
1639 case PTP_DPC_CANON_EOS_QuickReviewTime:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001640 case PTP_DPC_CANON_EOS_EVFMode:
1641 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001642 dpd->DataType = PTP_DTC_UINT16;
1643 break;
1644 case PTP_DPC_CANON_EOS_PictureStyle:
1645 case PTP_DPC_CANON_EOS_WhiteBalance:
1646 case PTP_DPC_CANON_EOS_MeteringMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001647 case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001648 dpd->DataType = PTP_DTC_UINT8;
1649 break;
1650 case PTP_DPC_CANON_EOS_Owner:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001651 case PTP_DPC_CANON_EOS_Artist:
1652 case PTP_DPC_CANON_EOS_Copyright:
1653 case PTP_DPC_CANON_EOS_SerialNumber:
1654 case PTP_DPC_CANON_EOS_LensName:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001655 dpd->DataType = PTP_DTC_STR;
1656 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001657 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
1658 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
1659 dpd->DataType = PTP_DTC_INT16;
1660 break;
1661 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
Linus Walleij7e756532009-05-06 21:25:09 +00001662 case 0xd114:
Linus Walleij7e756532009-05-06 21:25:09 +00001663 case PTP_DPC_CANON_EOS_DPOFVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001664 dpd->DataType = PTP_DTC_UINT16;
1665 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
1666 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001667 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001668 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001669 case PTP_DPC_CANON_EOS_CustomFunc1:
1670 case PTP_DPC_CANON_EOS_CustomFunc2:
1671 case PTP_DPC_CANON_EOS_CustomFunc3:
1672 case PTP_DPC_CANON_EOS_CustomFunc4:
1673 case PTP_DPC_CANON_EOS_CustomFunc5:
1674 case PTP_DPC_CANON_EOS_CustomFunc6:
1675 case PTP_DPC_CANON_EOS_CustomFunc7:
1676 case PTP_DPC_CANON_EOS_CustomFunc8:
1677 case PTP_DPC_CANON_EOS_CustomFunc9:
1678 case PTP_DPC_CANON_EOS_CustomFunc10:
1679 case PTP_DPC_CANON_EOS_CustomFunc11:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001680 dpd->DataType = PTP_DTC_UINT8;
1681 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 +00001682 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001683 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001684 /* 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 +02001685 xdata += 4;
Linus Walleij7e756532009-05-06 21:25:09 +00001686 break;
1687 /* yet unknown 32bit props */
1688 case PTP_DPC_CANON_EOS_ColorTemperature:
Linus Walleij7e756532009-05-06 21:25:09 +00001689 case PTP_DPC_CANON_EOS_WftStatus:
1690 case PTP_DPC_CANON_EOS_LensStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001691 case PTP_DPC_CANON_EOS_CardExtension:
1692 case PTP_DPC_CANON_EOS_TempStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001693 case PTP_DPC_CANON_EOS_PhotoStudioMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001694 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
1695 case PTP_DPC_CANON_EOS_EVFSharpness:
1696 case PTP_DPC_CANON_EOS_EVFWBMode:
1697 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
1698 case PTP_DPC_CANON_EOS_EVFColorTemp:
Linus Walleijd4637502009-06-14 23:03:33 +00001699 case PTP_DPC_CANON_EOS_EVFRecordStatus:
1700 case PTP_DPC_CANON_EOS_ExposureSimMode:
1701 case PTP_DPC_CANON_EOS_LvAfSystem:
1702 case PTP_DPC_CANON_EOS_MovSize:
1703 case PTP_DPC_CANON_EOS_DepthOfField:
1704 case PTP_DPC_CANON_EOS_LvViewTypeSelect:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001705 dpd->DataType = PTP_DTC_UINT32;
Linus Walleij7e756532009-05-06 21:25:09 +00001706 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 +00001707 if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
1708 ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
1709 for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
Linus Walleije206af62011-04-19 01:51:39 +02001710 ptp_debug (params, " %d: 0x%8x", j, ((uint32_t*)xdata)[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001711 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001712 /* ImageFormat properties have to be ignored here, see special handling below */
1713 case PTP_DPC_CANON_EOS_ImageFormat:
1714 case PTP_DPC_CANON_EOS_ImageFormatCF:
1715 case PTP_DPC_CANON_EOS_ImageFormatSD:
1716 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
Marcus Meissner0546a762012-04-10 18:49:10 +02001717 case PTP_DPC_CANON_EOS_CustomFuncEx:
Linus Walleijd7072c32010-12-07 20:43:00 +00001718 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001719 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001720 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1721 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001722 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001723 break;
1724 }
1725 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001726 case PTP_DTC_UINT32:
Linus Walleije206af62011-04-19 01:51:39 +02001727 dpd->FactoryDefaultValue.u32 = dtoh32a(xdata);
1728 dpd->CurrentValue.u32 = dtoh32a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001729 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001730 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001731 case PTP_DTC_UINT16:
Linus Walleije206af62011-04-19 01:51:39 +02001732 dpd->FactoryDefaultValue.u16 = dtoh16a(xdata);
1733 dpd->CurrentValue.u16 = dtoh16a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001734 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001735 break;
1736 case PTP_DTC_UINT8:
Linus Walleije206af62011-04-19 01:51:39 +02001737 dpd->FactoryDefaultValue.u8 = dtoh8a(xdata);
1738 dpd->CurrentValue.u8 = dtoh8a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001739 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001740 break;
1741 case PTP_DTC_STR: {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001742#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001743 uint8_t len = 0;
1744 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1745 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001746#else
Linus Walleij0d762cc2010-04-04 23:34:27 +00001747 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001748 dpd->FactoryDefaultValue.str = strdup( (char*)xdata );
Linus Walleij0d762cc2010-04-04 23:34:27 +00001749
1750 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001751 dpd->CurrentValue.str = strdup( (char*)xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001752#endif
Linus Walleij7e756532009-05-06 21:25:09 +00001753 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001754 break;
1755 }
1756 default:
1757 /* debug is printed in switch above this one */
1758 break;
1759 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001760
Marcus Meissner0546a762012-04-10 18:49:10 +02001761 /* ImageFormat and customFuncEx special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
Linus Walleijd7072c32010-12-07 20:43:00 +00001762 switch (proptype) {
1763 case PTP_DPC_CANON_EOS_ImageFormat:
1764 case PTP_DPC_CANON_EOS_ImageFormatCF:
1765 case PTP_DPC_CANON_EOS_ImageFormatSD:
1766 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1767 dpd->DataType = PTP_DTC_UINT16;
Linus Walleije206af62011-04-19 01:51:39 +02001768 dpd->FactoryDefaultValue.u16 = ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleijd7072c32010-12-07 20:43:00 +00001769 dpd->CurrentValue.u16 = dpd->FactoryDefaultValue.u16;
1770 ptp_debug (params,"event %d: decoded imageformat, currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
1771 break;
Marcus Meissner0546a762012-04-10 18:49:10 +02001772 case PTP_DPC_CANON_EOS_CustomFuncEx:
1773 dpd->DataType = PTP_DTC_STR;
1774 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
1775 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
1776 dpd->FactoryDefaultValue.str = ptp_unpack_EOS_CustomFuncEx( params, &data );
1777 dpd->CurrentValue.str = strdup( (char*)dpd->FactoryDefaultValue.str );
1778 ptp_debug (params,"event %d: decoded custom function, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
1779 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001780 }
1781
Linus Walleijf0bf4372007-07-01 21:47:38 +00001782 break;
1783 }
Linus Walleijd7072c32010-12-07 20:43:00 +00001784 case PTP_EC_CANON_EOS_CameraStatusChanged:
1785 ptp_debug (params, "event %d: EOS event CameraStatusChanged (size %d)", i, size);
1786 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS;
1787 (*ce)[i].u.status = dtoh32a(curdata+8);
Linus Walleij9e09ad02011-02-10 13:14:01 +01001788 params->eos_camerastatus = dtoh32a(curdata+8);
Linus Walleijd7072c32010-12-07 20:43:00 +00001789 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001790 case 0: /* end marker */
1791 if (size == 8) /* no output */
1792 break;
1793 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
1794 break;
Linus Walleij96aa0e32012-03-25 12:25:25 +02001795 case PTP_EC_CANON_EOS_BulbExposureTime:
1796 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1797 (*ce)[i].u.info = malloc(strlen("BulbExposureTime 123456789"));
1798 sprintf ((*ce)[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8));
1799 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001800 default:
Linus Walleijd4637502009-06-14 23:03:33 +00001801 switch (type) {
Linus Walleijd7072c32010-12-07 20:43:00 +00001802#define XX(x) case PTP_EC_CANON_EOS_##x: \
1803 ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); \
1804 (*ce)[i].u.info = malloc(strlen("unhandled EOS event "#x" (size 123456789)")); \
1805 sprintf ((*ce)[i].u.info, "unhandled EOS event "#x" (size %d)", size); \
1806 break;
Linus Walleijd4637502009-06-14 23:03:33 +00001807 XX(RequestGetEvent)
1808 XX(ObjectRemoved)
1809 XX(RequestGetObjectInfoEx)
1810 XX(StorageStatusChanged)
1811 XX(StorageInfoChanged)
1812 XX(ObjectInfoChangedEx)
1813 XX(ObjectContentChanged)
Linus Walleijd4637502009-06-14 23:03:33 +00001814 XX(WillSoonShutdown)
1815 XX(ShutdownTimerUpdated)
1816 XX(RequestCancelTransfer)
1817 XX(RequestObjectTransferDT)
1818 XX(RequestCancelTransferDT)
1819 XX(StoreAdded)
1820 XX(StoreRemoved)
1821 XX(BulbExposureTime)
1822 XX(RecordingTime)
1823 XX(RequestObjectTransferTS)
1824 XX(AfResult)
1825#undef XX
1826 default:
1827 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
1828 break;
1829 }
Linus Walleij7e756532009-05-06 21:25:09 +00001830 if (size >= 0x8) { /* event info */
1831 int j;
Linus Walleijd4637502009-06-14 23:03:33 +00001832 for (j=8;j<size;j++)
1833 ptp_debug (params, " %d: %02x", j, curdata[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001834 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001835 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1836 break;
1837 }
1838 curdata += size;
1839 i++;
Linus Walleij9d22ce02008-05-28 20:39:29 +00001840 if ((size == 8) && (type == 0))
1841 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001842 }
Linus Walleij0d762cc2010-04-04 23:34:27 +00001843 if (!entries) {
1844 free (*ce);
1845 *ce = NULL;
1846 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001847 return entries;
1848}
1849
1850/*
Linus Walleijb02a0662006-04-25 08:05:09 +00001851 PTP USB Event container unpack for Nikon events.
1852*/
1853#define PTP_nikon_ec_Length 0
1854#define PTP_nikon_ec_Code 2
1855#define PTP_nikon_ec_Param1 4
1856#define PTP_nikon_ec_Size 6
1857static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001858ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00001859{
1860 int i;
1861
1862 *ec = NULL;
1863 if (data == NULL)
1864 return;
1865 if (len < PTP_nikon_ec_Code)
1866 return;
1867 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
1868 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
1869 return;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001870 if (!*cnt)
1871 return;
1872
Linus Walleij7e756532009-05-06 21:25:09 +00001873 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00001874
1875 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00001876 memset(&(*ec)[i],0,sizeof(PTPContainer));
1877 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
1878 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
1879 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00001880 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001881}
1882
1883
Linus Walleijb02a0662006-04-25 08:05:09 +00001884static inline uint32_t
1885ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
1886 int i, len = 0;
1887 uint8_t retlen;
1888 unsigned char *curdata;
1889
1890 len = 2*(strlen(text->title)+1)+1+
1891 2*(strlen(text->line[0])+1)+1+
1892 2*(strlen(text->line[1])+1)+1+
1893 2*(strlen(text->line[2])+1)+1+
1894 2*(strlen(text->line[3])+1)+1+
1895 2*(strlen(text->line[4])+1)+1+
1896 4*2+2*4+2+4+2+5*4*2;
1897 *data = malloc(len);
1898 if (!*data) return 0;
1899
1900 curdata = *data;
1901 htod16a(curdata,100);curdata+=2;
1902 htod16a(curdata,1);curdata+=2;
1903 htod16a(curdata,0);curdata+=2;
1904 htod16a(curdata,1000);curdata+=2;
1905
1906 htod32a(curdata,0);curdata+=4;
1907 htod32a(curdata,0);curdata+=4;
1908
1909 htod16a(curdata,6);curdata+=2;
1910 htod32a(curdata,0);curdata+=4;
1911
1912 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1913 htod16a(curdata,0x10);curdata+=2;
1914
1915 for (i=0;i<5;i++) {
1916 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1917 htod16a(curdata,0x10);curdata+=2;
1918 htod16a(curdata,0x01);curdata+=2;
1919 htod16a(curdata,0x02);curdata+=2;
1920 htod16a(curdata,0x06);curdata+=2;
1921 }
1922 return len;
1923}
Linus Walleij7347d0f2006-10-23 07:23:39 +00001924
1925#define ptp_canon_dir_version 0x00
1926#define ptp_canon_dir_ofc 0x02
1927#define ptp_canon_dir_unk1 0x04
1928#define ptp_canon_dir_objectid 0x08
1929#define ptp_canon_dir_parentid 0x0c
1930#define ptp_canon_dir_previd 0x10 /* in same dir */
1931#define ptp_canon_dir_nextid 0x14 /* in same dir */
1932#define ptp_canon_dir_nextchild 0x18 /* down one dir */
1933#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
1934#define ptp_canon_dir_name 0x20
1935#define ptp_canon_dir_flags 0x2c
1936#define ptp_canon_dir_size 0x30
1937#define ptp_canon_dir_unixtime 0x34
1938#define ptp_canon_dir_year 0x38
1939#define ptp_canon_dir_month 0x39
1940#define ptp_canon_dir_mday 0x3a
1941#define ptp_canon_dir_hour 0x3b
1942#define ptp_canon_dir_minute 0x3c
1943#define ptp_canon_dir_second 0x3d
1944#define ptp_canon_dir_unk2 0x3e
1945#define ptp_canon_dir_thumbsize 0x40
1946#define ptp_canon_dir_width 0x44
1947#define ptp_canon_dir_height 0x48
1948
1949static inline uint16_t
1950ptp_unpack_canon_directory (
1951 PTPParams *params,
1952 unsigned char *dir,
1953 uint32_t cnt,
1954 PTPObjectHandles *handles,
1955 PTPObjectInfo **oinfos, /* size(handles->n) */
1956 uint32_t **flags /* size(handles->n) */
1957) {
1958 unsigned int i, j, nrofobs = 0, curob = 0;
1959
1960#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
1961 for (i=0;i<cnt;i++)
1962 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
1963 handles->n = nrofobs;
1964 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
1965 if (!handles->Handler) return PTP_RC_GeneralError;
1966 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
1967 if (!*oinfos) return PTP_RC_GeneralError;
1968 *flags = calloc(sizeof((*flags)[0]),nrofobs);
1969 if (!*flags) return PTP_RC_GeneralError;
1970
1971 /* Migrate data into objects ids, handles into
1972 * the object handler array.
1973 */
1974 curob = 0;
1975 for (i=0;i<cnt;i++) {
1976 unsigned char *cur = dir+i*0x4c;
1977 PTPObjectInfo *oi = (*oinfos)+curob;
1978
1979 if (!ISOBJECT(cur))
1980 continue;
1981
1982 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
1983 oi->StorageID = 0xffffffff;
1984 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
1985 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
1986 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
1987 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
1988 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
1989 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
1990 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
1991 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
1992 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
1993 curob++;
1994 }
1995 /* Walk over Storage ID entries and distribute the IDs to
1996 * the parent objects. */
1997 for (i=0;i<cnt;i++) {
1998 unsigned char *cur = dir+i*0x4c;
1999 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2000
2001 if (ISOBJECT(cur))
2002 continue;
2003 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2004 if (j == handles->n) continue;
2005 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
2006 }
2007 /* Walk over all objects and distribute the storage ids */
2008 while (1) {
2009 int changed = 0;
2010 for (i=0;i<cnt;i++) {
2011 unsigned char *cur = dir+i*0x4c;
2012 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
2013 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
2014 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2015 uint32_t storageid;
2016
2017 if (!ISOBJECT(cur))
2018 continue;
2019 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
2020 if (j == handles->n) {
2021 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
2022 continue;
2023 }
2024 storageid = (*oinfos)[j].StorageID;
2025 if (storageid == 0xffffffff) continue;
2026 if (nextoid != 0xffffffff) {
2027 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
2028 if (j == handles->n) {
2029 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
2030 continue;
2031 }
2032 if ((*oinfos)[j].StorageID == 0xffffffff) {
2033 (*oinfos)[j].StorageID = storageid;
2034 changed++;
2035 }
2036 }
2037 if (nextchild != 0xffffffff) {
2038 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2039 if (j == handles->n) {
2040 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
2041 continue;
2042 }
2043 if ((*oinfos)[j].StorageID == 0xffffffff) {
2044 (*oinfos)[j].StorageID = storageid;
2045 changed++;
2046 }
2047 }
2048 }
2049 /* Check if we:
2050 * - changed no entry (nothing more to do)
2051 * - changed all of them at once (usually happens)
2052 * break if we do.
2053 */
2054 if (!changed || (changed==nrofobs-1))
2055 break;
2056 }
2057#undef ISOBJECT
2058 return PTP_RC_OK;
2059}