blob: a72c91e34d1485087172b21c4ba39881f20ddef4 [file] [log] [blame]
Linus Walleijb02a0662006-04-25 08:05:09 +00001/* currently this file is included into ptp.c */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00002
Linus Walleija823a702006-08-27 21:27:46 +00003#include <iconv.h>
4
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00005extern void
6ptp_debug (PTPParams *params, const char *format, ...);
7
Linus Walleijb02a0662006-04-25 08:05:09 +00008static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00009htod16p (PTPParams *params, uint16_t var)
10{
11 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
12}
13
Linus Walleijb02a0662006-04-25 08:05:09 +000014static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000015htod32p (PTPParams *params, uint32_t var)
16{
17 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
18}
19
Linus Walleijb02a0662006-04-25 08:05:09 +000020static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000021htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
22{
23 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000024 htole16a(a,val);
25 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000026 htobe16a(a,val);
27}
28
Linus Walleijb02a0662006-04-25 08:05:09 +000029static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000030htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
31{
32 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000033 htole32a(a,val);
34 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000035 htobe32a(a,val);
36}
37
Linus Walleijabf54752007-07-30 19:51:54 +000038static inline void
39htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
40{
41 if (params->byteorder==PTP_DL_LE)
42 htole64a(a,val);
43 else
44 htobe64a(a,val);
45}
46
Linus Walleijb02a0662006-04-25 08:05:09 +000047static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000048dtoh16p (PTPParams *params, uint16_t var)
49{
50 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
51}
52
Linus Walleijb02a0662006-04-25 08:05:09 +000053static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000054dtoh32p (PTPParams *params, uint32_t var)
55{
56 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
57}
58
Linus Walleijabf54752007-07-30 19:51:54 +000059static inline uint64_t
60dtoh64p (PTPParams *params, uint64_t var)
61{
62 return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
63}
64
Linus Walleijb02a0662006-04-25 08:05:09 +000065static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000066dtoh16ap (PTPParams *params, unsigned char *a)
67{
68 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
69}
70
Linus Walleijb02a0662006-04-25 08:05:09 +000071static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000072dtoh32ap (PTPParams *params, unsigned char *a)
73{
74 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
75}
76
Linus Walleijb02a0662006-04-25 08:05:09 +000077static inline uint64_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000078dtoh64ap (PTPParams *params, unsigned char *a)
79{
Linus Walleijabf54752007-07-30 19:51:54 +000080 return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000081}
82
Linus Walleijb02a0662006-04-25 08:05:09 +000083#define htod8a(a,x) *(uint8_t*)(a) = x
84#define htod16a(a,x) htod16ap(params,a,x)
85#define htod32a(a,x) htod32ap(params,a,x)
Linus Walleijabf54752007-07-30 19:51:54 +000086#define htod64a(a,x) htod64ap(params,a,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000087#define htod16(x) htod16p(params,x)
88#define htod32(x) htod32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000089#define htod64(x) htod64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000090
91#define dtoh8a(x) (*(uint8_t*)(x))
92#define dtoh16a(a) dtoh16ap(params,a)
93#define dtoh32a(a) dtoh32ap(params,a)
94#define dtoh64a(a) dtoh64ap(params,a)
95#define dtoh16(x) dtoh16p(params,x)
96#define dtoh32(x) dtoh32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +000097#define dtoh64(x) dtoh64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +000098
99
100static inline char*
101ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000102{
Linus Walleija8a19cc2007-02-02 22:13:17 +0000103 uint8_t length;
104 uint16_t string[PTP_MAXSTRLEN+1];
105 /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
106 char loclstr[PTP_MAXSTRLEN*3+1];
107 size_t nconv, srclen, destlen;
108 char *src, *dest;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000109
Linus Walleija8a19cc2007-02-02 22:13:17 +0000110 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
111 *len = length;
112 if (length == 0) /* nothing to do? */
113 return(NULL);
114
115 /* copy to string[] to ensure correct alignment for iconv(3) */
116 memcpy(string, &data[offset+1], length * sizeof(string[0]));
117 string[length] = 0x0000U; /* be paranoid! add a terminator. */
118 loclstr[0] = '\0';
119
120 /* convert from camera UCS-2 to our locale */
121 src = (char *)string;
122 srclen = length * sizeof(string[0]);
123 dest = loclstr;
124 destlen = sizeof(loclstr)-1;
125 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen,
126 &dest, &destlen);
127 if (nconv == (size_t) -1) { /* do it the hard way */
128 int i;
129 /* try the old way, in case iconv is broken */
130 for (i=0;i<length;i++) {
131 if (dtoh16a(&data[offset+1+2*i])>127)
132 loclstr[i] = '?';
133 else
134 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000135 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000136 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000137 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000138 *dest = '\0';
139 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
140 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000141}
142
Linus Walleija823a702006-08-27 21:27:46 +0000143static inline int
144ucs2strlen(uint16_t const * const unicstr)
145{
146 int length;
147
148 /* Unicode strings are terminated with 2 * 0x00 */
149 for(length = 0; unicstr[length] != 0x0000U; length ++);
150 return length;
151}
152
153
Linus Walleijb02a0662006-04-25 08:05:09 +0000154static inline void
155ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000156{
Linus Walleija823a702006-08-27 21:27:46 +0000157 int packedlen;
158 uint16_t ucs2str[PTP_MAXSTRLEN+1];
159 char *ucs2strp = (char *) ucs2str;
160 char *stringp = string;
161 size_t nconv;
162 size_t convlen = strlen(string);
163 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
164
165 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000166 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
167 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
168 &ucs2strp, &convmax);
Linus Walleij4f40d112006-09-21 07:44:53 +0000169 if (nconv == (size_t) -1)
Linus Walleija823a702006-08-27 21:27:46 +0000170 ucs2str[0] = 0x0000U;
Linus Walleija8a19cc2007-02-02 22:13:17 +0000171 /*
172 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
173 * why do we need ucs2strlen()?
174 */
Linus Walleija823a702006-08-27 21:27:46 +0000175 packedlen = ucs2strlen(ucs2str);
176 if (packedlen > PTP_MAXSTRLEN-1) {
177 *len=0;
178 return;
179 }
Linus Walleij958441f2006-08-29 15:30:11 +0000180
Linus Walleij7f234382006-12-09 19:41:00 +0000181 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000182 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000183 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
184 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000185
186 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000187 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000188}
189
190static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000191ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000192{
Richard Low8b42ca32006-11-15 08:52:17 +0000193 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000194 size_t plen;
195 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000196
197 if (string == NULL)
198 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
199 else
200 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
201
Linus Walleij958441f2006-08-29 15:30:11 +0000202 /* returned length is in characters, then one byte for string length */
203 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000204
Linus Walleija823a702006-08-27 21:27:46 +0000205 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000206 if (!retcopy) {
207 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000208 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000209 }
Linus Walleija823a702006-08-27 21:27:46 +0000210 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000211 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000212 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000213}
214
Linus Walleijb02a0662006-04-25 08:05:09 +0000215static inline uint32_t
216ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000217{
218 uint32_t n, i=0;
219
220 n=dtoh32a(&data[offset]);
221 *array = malloc (n*sizeof(uint32_t));
222 while (n>i) {
223 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
224 i++;
225 }
226 return n;
227}
228
Linus Walleijb02a0662006-04-25 08:05:09 +0000229static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000230ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
231{
232 uint32_t i=0;
233
234 *data = malloc ((arraylen+1)*sizeof(uint32_t));
235 htod32a(&(*data)[0],arraylen);
236 for (i=0;i<arraylen;i++)
237 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
238 return (arraylen+1)*sizeof(uint32_t);
239}
240
241static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000242ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000243{
244 uint32_t n, i=0;
245
246 n=dtoh32a(&data[offset]);
247 *array = malloc (n*sizeof(uint16_t));
248 while (n>i) {
249 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
250 i++;
251 }
252 return n;
253}
254
255/* DeviceInfo pack/unpack */
256
257#define PTP_di_StandardVersion 0
258#define PTP_di_VendorExtensionID 2
259#define PTP_di_VendorExtensionVersion 6
260#define PTP_di_VendorExtensionDesc 8
261#define PTP_di_FunctionalMode 8
262#define PTP_di_OperationsSupported 10
263
Linus Walleijb02a0662006-04-25 08:05:09 +0000264static inline void
265ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000266{
267 uint8_t len;
268 unsigned int totallen;
Linus Walleij7e756532009-05-06 21:25:09 +0000269
Linus Walleij7347d0f2006-10-23 07:23:39 +0000270 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000271 di->VendorExtensionID =
272 dtoh32a(&data[PTP_di_VendorExtensionID]);
273 di->VendorExtensionVersion =
274 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
275 di->VendorExtensionDesc =
276 ptp_unpack_string(params, data,
277 PTP_di_VendorExtensionDesc, &len);
278 totallen=len*2+1;
279 di->FunctionalMode =
280 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
281 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
282 PTP_di_OperationsSupported+totallen,
283 &di->OperationsSupported);
284 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
285 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
286 PTP_di_OperationsSupported+totallen,
287 &di->EventsSupported);
288 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
289 di->DevicePropertiesSupported_len =
290 ptp_unpack_uint16_t_array(params, data,
291 PTP_di_OperationsSupported+totallen,
292 &di->DevicePropertiesSupported);
293 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
294 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
295 PTP_di_OperationsSupported+totallen,
296 &di->CaptureFormats);
297 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
298 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
299 PTP_di_OperationsSupported+totallen,
300 &di->ImageFormats);
301 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
302 di->Manufacturer = ptp_unpack_string(params, data,
303 PTP_di_OperationsSupported+totallen,
304 &len);
305 totallen+=len*2+1;
306 di->Model = ptp_unpack_string(params, data,
307 PTP_di_OperationsSupported+totallen,
308 &len);
309 totallen+=len*2+1;
310 di->DeviceVersion = ptp_unpack_string(params, data,
311 PTP_di_OperationsSupported+totallen,
312 &len);
313 totallen+=len*2+1;
314 di->SerialNumber = ptp_unpack_string(params, data,
315 PTP_di_OperationsSupported+totallen,
316 &len);
317}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000318
319static void
320ptp_free_DI (PTPDeviceInfo *di) {
321 if (di->SerialNumber) free (di->SerialNumber);
322 if (di->DeviceVersion) free (di->DeviceVersion);
323 if (di->Model) free (di->Model);
324 if (di->Manufacturer) free (di->Manufacturer);
325 if (di->ImageFormats) free (di->ImageFormats);
326 if (di->CaptureFormats) free (di->CaptureFormats);
327 if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
328 if (di->OperationsSupported) free (di->OperationsSupported);
329 if (di->EventsSupported) free (di->EventsSupported);
330 if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
331}
Linus Walleij7e756532009-05-06 21:25:09 +0000332
333/* EOS Device Info unpack */
334static inline void
335ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
336{
337 int totallen = 4;
338 if (datalen < 8) return;
339
340 /* uint32_t struct len - ignore */
341 di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
342 totallen, &di->EventsSupported);
343 if (!di->EventsSupported) return;
344 totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
345 if (totallen >= datalen) return;
346
347 di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
348 totallen, &di->DevicePropertiesSupported);
349 if (!di->DevicePropertiesSupported) return;
350 totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
351 if (totallen >= datalen) return;
352
353 di->unk_len = ptp_unpack_uint32_t_array(params, data,
354 totallen, &di->unk);
355 if (!di->unk) return;
356 totallen += di->unk_len*sizeof(uint32_t)+4;
357 return;
358}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000359
360/* ObjectHandles array pack/unpack */
361
362#define PTP_oh 0
363
Linus Walleijb02a0662006-04-25 08:05:09 +0000364static inline void
365ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000366{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000367 if (len) {
368 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
369 } else {
370 oh->n = 0;
371 oh->Handler = NULL;
372 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000373}
374
375/* StoreIDs array pack/unpack */
376
377#define PTP_sids 0
378
Linus Walleijb02a0662006-04-25 08:05:09 +0000379static inline void
380ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000381{
382 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
383 &sids->Storage);
384}
385
386/* StorageInfo pack/unpack */
387
388#define PTP_si_StorageType 0
389#define PTP_si_FilesystemType 2
390#define PTP_si_AccessCapability 4
391#define PTP_si_MaxCapability 6
392#define PTP_si_FreeSpaceInBytes 14
393#define PTP_si_FreeSpaceInImages 22
394#define PTP_si_StorageDescription 26
395
Linus Walleijb02a0662006-04-25 08:05:09 +0000396static inline void
397ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000398{
399 uint8_t storagedescriptionlen;
400
401 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
402 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
403 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000404 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
405 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
406 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
407 si->StorageDescription=ptp_unpack_string(params, data,
408 PTP_si_StorageDescription, &storagedescriptionlen);
409 si->VolumeLabel=ptp_unpack_string(params, data,
410 PTP_si_StorageDescription+storagedescriptionlen*2+1,
411 &storagedescriptionlen);
412}
413
414/* ObjectInfo pack/unpack */
415
416#define PTP_oi_StorageID 0
417#define PTP_oi_ObjectFormat 4
418#define PTP_oi_ProtectionStatus 6
419#define PTP_oi_ObjectCompressedSize 8
420#define PTP_oi_ThumbFormat 12
421#define PTP_oi_ThumbCompressedSize 14
422#define PTP_oi_ThumbPixWidth 18
423#define PTP_oi_ThumbPixHeight 22
424#define PTP_oi_ImagePixWidth 26
425#define PTP_oi_ImagePixHeight 30
426#define PTP_oi_ImageBitDepth 34
427#define PTP_oi_ParentObject 38
428#define PTP_oi_AssociationType 42
429#define PTP_oi_AssociationDesc 44
430#define PTP_oi_SequenceNumber 48
431#define PTP_oi_filenamelen 52
432#define PTP_oi_Filename 53
433
Linus Walleija0323272007-01-07 12:21:30 +0000434/* the max length assuming zero length dates. We have need 3 */
435/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000436#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
437
Linus Walleijb02a0662006-04-25 08:05:09 +0000438static inline uint32_t
439ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000440{
Linus Walleijb02a0662006-04-25 08:05:09 +0000441 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000442 uint8_t filenamelen;
443 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000444 /* let's allocate some memory first; correct assuming zero length dates */
445 oidata=malloc(PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000446 /* the caller should free it after use! */
447#if 0
448 char *capture_date="20020101T010101"; /* XXX Fake date */
449#endif
Richard Lowa679b1c2006-12-29 20:08:14 +0000450 memset (oidata, 0, PTP_oi_MaxLen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000451 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
452 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
453 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
454 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
455 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
456 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
457 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
458 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
459 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
460 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
461 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
462 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
463 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
464 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
465 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
466
467 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
468/*
469 filenamelen=(uint8_t)strlen(oi->Filename);
470 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
471 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
472 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
473 }
474*/
475 /*
476 *XXX Fake date.
477 * for example Kodak sets Capture date on the basis of EXIF data.
478 * Spec says that this field is from perspective of Initiator.
479 */
480#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
481 capturedatelen=strlen(capture_date);
482 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
483 capturedatelen+1);
484 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
485 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
486 }
487 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
488 capturedatelen+1);
489 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
490 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
491 capture_date[i];
492 }
493#endif
494 /* XXX this function should return dataset length */
495
496 *oidataptr=oidata;
Richard Lowa679b1c2006-12-29 20:08:14 +0000497 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000498}
499
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000500static time_t
Linus Walleij7e756532009-05-06 21:25:09 +0000501ptp_unpack_PTPTIME (PTPParams *params, const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000502 char ptpdate[40];
503 char tmp[5];
504 int ptpdatelen;
505 struct tm tm;
506
507 if (!str)
508 return 0;
509 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000510 if (ptpdatelen >= sizeof (ptpdate)) {
511 ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000512 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000513 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000514 strcpy (ptpdate, str);
Linus Walleij7e756532009-05-06 21:25:09 +0000515 if (ptpdatelen<15) {
516 ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000517 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000518 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000519
520 memset(&tm,0,sizeof(tm));
521 strncpy (tmp, ptpdate, 4);
522 tmp[4] = 0;
523 tm.tm_year=atoi (tmp) - 1900;
524 strncpy (tmp, ptpdate + 4, 2);
525 tmp[2] = 0;
526 tm.tm_mon = atoi (tmp) - 1;
527 strncpy (tmp, ptpdate + 6, 2);
528 tmp[2] = 0;
529 tm.tm_mday = atoi (tmp);
530 strncpy (tmp, ptpdate + 9, 2);
531 tmp[2] = 0;
532 tm.tm_hour = atoi (tmp);
533 strncpy (tmp, ptpdate + 11, 2);
534 tmp[2] = 0;
535 tm.tm_min = atoi (tmp);
536 strncpy (tmp, ptpdate + 13, 2);
537 tmp[2] = 0;
538 tm.tm_sec = atoi (tmp);
Linus Walleij7e756532009-05-06 21:25:09 +0000539 ptp_debug (params ,"mktime gets %d", mktime(&tm));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000540 return mktime (&tm);
541}
542
Linus Walleijb02a0662006-04-25 08:05:09 +0000543static inline void
544ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000545{
546 uint8_t filenamelen;
547 uint8_t capturedatelen;
548 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000549
550 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
551 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
552 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
553 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
554 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
555 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
556 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
557 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
558 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
559 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
560 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
561 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
562 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
563 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
564 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
565 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
566
567 capture_date = ptp_unpack_string(params, data,
568 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
569 /* subset of ISO 8601, without '.s' tenths of second and
570 * time zone
571 */
Linus Walleij7e756532009-05-06 21:25:09 +0000572 oi->CaptureDate = ptp_unpack_PTPTIME(params,capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000573 free(capture_date);
574
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000575 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000576 capture_date = ptp_unpack_string(params, data,
577 PTP_oi_filenamelen+filenamelen*2
578 +capturedatelen*2+2,&capturedatelen);
Linus Walleij7e756532009-05-06 21:25:09 +0000579 oi->ModificationDate = ptp_unpack_PTPTIME(params,capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000580 free(capture_date);
581}
582
583/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000584#define CTVAL(target,func) { \
585 if (total - *offset < sizeof(target)) \
586 return 0; \
587 target = func(&data[*offset]); \
588 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000589}
590
Linus Walleijb02a0662006-04-25 08:05:09 +0000591#define RARR(val,member,func) { \
592 int n,j; \
593 if (total - *offset < sizeof(uint32_t)) \
594 return 0; \
595 n = dtoh32a (&data[*offset]); \
596 *offset += sizeof(uint32_t); \
597 \
598 val->a.count = n; \
599 val->a.v = malloc(sizeof(val->a.v[0])*n); \
600 if (!val->a.v) return 0; \
601 for (j=0;j<n;j++) \
602 CTVAL(val->a.v[j].member, func); \
603}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000604
Linus Walleijb02a0662006-04-25 08:05:09 +0000605static inline int
606ptp_unpack_DPV (
607 PTPParams *params, unsigned char* data, int *offset, int total,
608 PTPPropertyValue* value, uint16_t datatype
609) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000610 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000611 case PTP_DTC_INT8:
612 CTVAL(value->i8,dtoh8a);
613 break;
614 case PTP_DTC_UINT8:
615 CTVAL(value->u8,dtoh8a);
616 break;
617 case PTP_DTC_INT16:
618 CTVAL(value->i16,dtoh16a);
619 break;
620 case PTP_DTC_UINT16:
621 CTVAL(value->u16,dtoh16a);
622 break;
623 case PTP_DTC_INT32:
624 CTVAL(value->i32,dtoh32a);
625 break;
626 case PTP_DTC_UINT32:
627 CTVAL(value->u32,dtoh32a);
628 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000629 case PTP_DTC_INT64:
630 CTVAL(value->i64,dtoh64a);
631 break;
632 case PTP_DTC_UINT64:
633 CTVAL(value->u64,dtoh64a);
634 break;
635
Linus Walleij037a1252006-12-16 20:36:52 +0000636 case PTP_DTC_UINT128:
637 *offset += 16;
638 /*fprintf(stderr,"unhandled unpack of uint128n");*/
639 break;
640 case PTP_DTC_INT128:
641 *offset += 16;
642 /*fprintf(stderr,"unhandled unpack of int128n");*/
643 break;
644
645
646
Linus Walleijb02a0662006-04-25 08:05:09 +0000647 case PTP_DTC_AINT8:
648 RARR(value,i8,dtoh8a);
649 break;
650 case PTP_DTC_AUINT8:
651 RARR(value,u8,dtoh8a);
652 break;
653 case PTP_DTC_AUINT16:
654 RARR(value,u16,dtoh16a);
655 break;
656 case PTP_DTC_AINT16:
657 RARR(value,i16,dtoh16a);
658 break;
659 case PTP_DTC_AUINT32:
660 RARR(value,u32,dtoh32a);
661 break;
662 case PTP_DTC_AINT32:
663 RARR(value,i32,dtoh32a);
664 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000665 case PTP_DTC_AUINT64:
666 RARR(value,u64,dtoh64a);
667 break;
668 case PTP_DTC_AINT64:
669 RARR(value,i64,dtoh64a);
670 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000671 /* XXX: other int types are unimplemented */
672 /* XXX: other int arrays are unimplemented also */
673 case PTP_DTC_STR: {
674 uint8_t len;
675 /* XXX: max size */
676 value->str = ptp_unpack_string(params,data,*offset,&len);
677 *offset += len*2+1;
678 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000679 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000680 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000681 }
Linus Walleij037a1252006-12-16 20:36:52 +0000682 default:
683 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000684 }
685 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000686}
687
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000688/* Device Property pack/unpack */
689
690#define PTP_dpd_DevicePropertyCode 0
691#define PTP_dpd_DataType 2
692#define PTP_dpd_GetSet 4
693#define PTP_dpd_FactoryDefaultValue 5
694
Linus Walleijb02a0662006-04-25 08:05:09 +0000695static inline int
696ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000697{
Linus Walleijb02a0662006-04-25 08:05:09 +0000698 int offset=0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000699
Linus Walleijb02a0662006-04-25 08:05:09 +0000700 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000701 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
702 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
703 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000704 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000705
706 offset = PTP_dpd_FactoryDefaultValue;
707 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
708 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000709 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
710 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000711 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
712 if (!ret) goto outofmemory;
713
714 /* if offset==0 then Data Type format is not supported by this
715 code or the Data Type is a string (with two empty strings as
716 values). In both cases Form Flag should be set to 0x00 and FORM is
717 not present. */
718
Linus Walleijb02a0662006-04-25 08:05:09 +0000719 if (offset==PTP_dpd_FactoryDefaultValue)
720 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000721
Linus Walleijb02a0662006-04-25 08:05:09 +0000722 dpd->FormFlag=dtoh8a(&data[offset]);
723 offset+=sizeof(uint8_t);
724
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000725 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000726 case PTP_DPFF_Range:
727 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
728 if (!ret) goto outofmemory;
729 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
730 if (!ret) goto outofmemory;
731 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
732 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000733 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000734 case PTP_DPFF_Enumeration: {
735 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000736#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000737 N = dtoh16a(&data[offset]);
738 offset+=sizeof(uint16_t);
739 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
740 if (!dpd->FORM.Enum.SupportedValue)
741 goto outofmemory;
742
743 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
744 for (i=0;i<N;i++) {
745 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
746
747 /* Slightly different handling here. The HP PhotoSmart 120
748 * specifies an enumeration with N in wrong endian
749 * 00 01 instead of 01 00, so we count the enum just until the
750 * the end of the packet.
751 */
752 if (!ret) {
753 if (!i)
754 goto outofmemory;
755 dpd->FORM.Enum.NumberOfValues = i;
756 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000757 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000758 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000759 }
760 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000761#undef N
762 return 1;
763outofmemory:
764 ptp_free_devicepropdesc(dpd);
765 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000766}
767
Linus Walleijb02a0662006-04-25 08:05:09 +0000768/* (MTP) Object Property pack/unpack */
769#define PTP_opd_ObjectPropertyCode 0
770#define PTP_opd_DataType 2
771#define PTP_opd_GetSet 4
772#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000773
Linus Walleijb02a0662006-04-25 08:05:09 +0000774static inline int
775ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000776{
Linus Walleijb02a0662006-04-25 08:05:09 +0000777 int offset=0, ret;
778
779 memset (opd, 0, sizeof(*opd));
780 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
781 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
782 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
783
784 offset = PTP_opd_FactoryDefaultValue;
785 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
786 if (!ret) goto outofmemory;
787
788 opd->GroupCode=dtoh32a(&data[offset]);
789 offset+=sizeof(uint32_t);
790
791 opd->FormFlag=dtoh8a(&data[offset]);
792 offset+=sizeof(uint8_t);
793
794 switch (opd->FormFlag) {
795 case PTP_OPFF_Range:
796 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
797 if (!ret) goto outofmemory;
798 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
799 if (!ret) goto outofmemory;
800 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
801 if (!ret) goto outofmemory;
802 break;
803 case PTP_OPFF_Enumeration: {
804 int i;
805#define N opd->FORM.Enum.NumberOfValues
806 N = dtoh16a(&data[offset]);
807 offset+=sizeof(uint16_t);
808 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
809 if (!opd->FORM.Enum.SupportedValue)
810 goto outofmemory;
811
812 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
813 for (i=0;i<N;i++) {
814 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
815
816 /* Slightly different handling here. The HP PhotoSmart 120
817 * specifies an enumeration with N in wrong endian
818 * 00 01 instead of 01 00, so we count the enum just until the
819 * the end of the packet.
820 */
821 if (!ret) {
822 if (!i)
823 goto outofmemory;
824 opd->FORM.Enum.NumberOfValues = i;
825 break;
826 }
827 }
828#undef N
829 }
830 }
831 return 1;
832outofmemory:
833 ptp_free_objectpropdesc(opd);
834 return 0;
835}
836
837
838static inline uint32_t
839ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
840{
841 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000842 uint32_t size=0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000843 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000844
845 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000846 case PTP_DTC_INT8:
847 size=sizeof(int8_t);
848 dpv=malloc(size);
849 htod8a(dpv,value->i8);
850 break;
851 case PTP_DTC_UINT8:
852 size=sizeof(uint8_t);
853 dpv=malloc(size);
854 htod8a(dpv,value->u8);
855 break;
856 case PTP_DTC_INT16:
857 size=sizeof(int16_t);
858 dpv=malloc(size);
859 htod16a(dpv,value->i16);
860 break;
861 case PTP_DTC_UINT16:
862 size=sizeof(uint16_t);
863 dpv=malloc(size);
864 htod16a(dpv,value->u16);
865 break;
866 case PTP_DTC_INT32:
867 size=sizeof(int32_t);
868 dpv=malloc(size);
869 htod32a(dpv,value->i32);
870 break;
871 case PTP_DTC_UINT32:
872 size=sizeof(uint32_t);
873 dpv=malloc(size);
874 htod32a(dpv,value->u32);
875 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000876 case PTP_DTC_INT64:
877 size=sizeof(int64_t);
878 dpv=malloc(size);
879 htod64a(dpv,value->i64);
880 break;
881 case PTP_DTC_UINT64:
882 size=sizeof(uint64_t);
883 dpv=malloc(size);
884 htod64a(dpv,value->u64);
885 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000886 case PTP_DTC_AUINT8:
887 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
888 dpv=malloc(size);
889 htod32a(dpv,value->a.count);
890 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000891 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000892 break;
893 case PTP_DTC_AINT8:
894 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
895 dpv=malloc(size);
896 htod32a(dpv,value->a.count);
897 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000898 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +0000899 break;
900 case PTP_DTC_AUINT16:
901 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
902 dpv=malloc(size);
903 htod32a(dpv,value->a.count);
904 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000905 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000906 break;
907 case PTP_DTC_AINT16:
908 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
909 dpv=malloc(size);
910 htod32a(dpv,value->a.count);
911 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000912 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +0000913 break;
914 case PTP_DTC_AUINT32:
915 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
916 dpv=malloc(size);
917 htod32a(dpv,value->a.count);
918 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000919 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000920 break;
921 case PTP_DTC_AINT32:
922 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
923 dpv=malloc(size);
924 htod32a(dpv,value->a.count);
925 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000926 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +0000927 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000928 case PTP_DTC_AUINT64:
929 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
930 dpv=malloc(size);
931 htod32a(dpv,value->a.count);
932 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000933 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +0000934 break;
935 case PTP_DTC_AINT64:
936 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
937 dpv=malloc(size);
938 htod32a(dpv,value->a.count);
939 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +0000940 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +0000941 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000942 /* XXX: other int types are unimplemented */
943 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +0000944 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000945 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000946 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000947 }
948 *dpvptr=dpv;
949 return size;
950}
951
Linus Walleij99310d42006-11-01 08:29:39 +0000952#define MAX_MTP_PROPS 127
953static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +0000954ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +0000955{
956 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000957 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +0000958 unsigned char *packedprops[MAX_MTP_PROPS];
959 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +0000960 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +0000961 uint16_t packedpropsids[MAX_MTP_PROPS];
962 uint16_t packedpropstypes[MAX_MTP_PROPS];
963 uint32_t totalsize = 0;
964 uint32_t bufp = 0;
965 uint32_t noitems = 0;
966 uint32_t i;
967
968 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +0000969 propitr = props;
970 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +0000971 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +0000972 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +0000973 totalsize += sizeof(uint32_t); /* Object ID */
974 /* Metadata type */
975 packedpropsids[noitems]=propitr->property;
976 totalsize += sizeof(uint16_t);
977 /* Data type */
978 packedpropstypes[noitems]= propitr->datatype;
979 totalsize += sizeof(uint16_t);
980 /* Add each property to be sent. */
981 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
982 totalsize += packedpropslens[noitems];
983 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +0000984 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +0000985 }
986
987 /* Allocate memory for the packed property list */
988 opldata = malloc(totalsize);
989
990 htod32a(&opldata[bufp],noitems);
991 bufp += 4;
992
993 /* Copy into a nice packed list */
994 for (i = 0; i < noitems; i++) {
995 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +0000996 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +0000997 bufp += sizeof(uint32_t);
998 htod16a(&opldata[bufp],packedpropsids[i]);
999 bufp += sizeof(uint16_t);
1000 htod16a(&opldata[bufp],packedpropstypes[i]);
1001 bufp += sizeof(uint16_t);
1002 /* The copy the actual property */
1003 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1004 bufp += packedpropslens[i];
1005 free(packedprops[i]);
1006 }
1007 *opldataptr = opldata;
1008 return totalsize;
1009}
1010
Linus Walleij1e9a0332007-09-12 19:35:56 +00001011static int
1012_compare_func(const void* x, const void *y) {
1013 const MTPProperties *px = x;
1014 const MTPProperties *py = y;
1015
1016 return px->ObjectHandle - py->ObjectHandle;
1017}
1018
Richard Low8d82d2f2006-11-16 20:37:43 +00001019static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001020ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001021{
Linus Walleij277cd532006-11-20 14:57:46 +00001022 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001023 MTPProperties *props = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001024 int offset = 0, i;
1025
1026 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +00001027 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001028 return 0;
1029 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001030 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001031 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001032 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001033 props = malloc(prop_count * sizeof(MTPProperties));
1034 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001035 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001036 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001037 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001038 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1039 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001040 qsort (props, i, sizeof(MTPProperties),_compare_func);
1041 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001042 return i;
1043 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001044 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001045 data += sizeof(uint32_t);
1046 len -= sizeof(uint32_t);
1047
Linus Walleij1e9a0332007-09-12 19:35:56 +00001048 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001049 data += sizeof(uint16_t);
1050 len -= sizeof(uint16_t);
1051
Linus Walleij1e9a0332007-09-12 19:35:56 +00001052 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001053 data += sizeof(uint16_t);
1054 len -= sizeof(uint16_t);
1055
1056 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001057 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001058 data += offset;
1059 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001060 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001061 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1062 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001063 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001064}
1065
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001066/*
1067 PTP USB Event container unpack
1068 Copyright (c) 2003 Nikolai Kopanygin
1069*/
1070
1071#define PTP_ec_Length 0
1072#define PTP_ec_Type 4
1073#define PTP_ec_Code 6
1074#define PTP_ec_TransId 8
1075#define PTP_ec_Param1 12
1076#define PTP_ec_Param2 16
1077#define PTP_ec_Param3 20
1078
Linus Walleijb02a0662006-04-25 08:05:09 +00001079static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001080ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001081{
Linus Walleij7e756532009-05-06 21:25:09 +00001082 int length;
1083 int type;
1084
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001085 if (data==NULL)
1086 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001087 memset(ec,0,sizeof(*ec));
1088 length=dtoh32a(&data[PTP_ec_Length]);
1089 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001090
Linus Walleij7e756532009-05-06 21:25:09 +00001091 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1092 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1093
1094 if (type!=PTP_USB_CONTAINER_EVENT) {
1095 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1096 return;
1097 }
1098 if (length>=(PTP_ec_Param1+4)) {
1099 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1100 ec->Nparam=1;
1101 }
1102 if (length>=(PTP_ec_Param2+4)) {
1103 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1104 ec->Nparam=2;
1105 }
1106 if (length>=(PTP_ec_Param3+4)) {
1107 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1108 ec->Nparam=3;
1109 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001110}
1111
1112/*
1113 PTP Canon Folder Entry unpack
1114 Copyright (c) 2003 Nikolai Kopanygin
1115*/
1116#define PTP_cfe_ObjectHandle 0
1117#define PTP_cfe_ObjectFormatCode 4
1118#define PTP_cfe_Flags 6
1119#define PTP_cfe_ObjectSize 7
1120#define PTP_cfe_Time 11
1121#define PTP_cfe_Filename 15
1122
Linus Walleijb02a0662006-04-25 08:05:09 +00001123static inline void
1124ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001125{
1126 int i;
1127 if (data==NULL)
1128 return;
1129 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1130 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1131 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001132 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001133 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1134 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001135 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1136}
1137
1138/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001139 PTP EOS Changes Entry unpack
1140*/
1141#define PTP_ece_Size 0
1142#define PTP_ece_Type 4
1143
1144#define PTP_ece_Prop_Subtype 8 /* only for properties */
1145#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1146#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1147#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1148#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1149
1150#define PTP_ece_OI_ObjectID 8 /* only for objectinfos */
1151#define PTP_ece_OI_OFC 0x0c /* only for objectinfos */
1152#define PTP_ece_OI_Size 0x14 /* only for objectinfos */
1153#define PTP_ece_OI_Name 0x1c /* only for objectinfos */
1154
1155static inline int
1156ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **ce)
1157{
1158 int i = 0, entries = 0;
1159 unsigned char *curdata = data;
1160
1161 if (data==NULL)
1162 return 0;
1163 while (curdata - data < datasize) {
1164 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1165 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1166
1167 curdata += size;
1168 if ((size == 8) && (type == 0))
1169 break;
1170 entries++;
1171 }
Linus Walleij9d22ce02008-05-28 20:39:29 +00001172 *ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001173 if (!*ce) return 0;
1174
1175 curdata = data;
1176 while (curdata - data < datasize) {
1177 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1178 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1179
1180 switch (type) {
Linus Walleij7e756532009-05-06 21:25:09 +00001181 case PTP_EC_CANON_EOS_RequestObjectTransfer:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001182 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1183 (*ce)[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
1184 (*ce)[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
1185 (*ce)[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1186 (*ce)[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001187
1188 ptp_debug (params, "event %d: objectinfo oid %08lx, ofc %04x, size %d, filename %s", i, (*ce)[i].u.object.oid, (*ce)[i].u.object.oi.ObjectFormat, (*ce)[i].u.object.oi.ObjectCompressedSize, (*ce)[i].u.object.oi.Filename);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001189 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001190 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001191 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1192 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1193 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
1194 unsigned char *data = &curdata[PTP_ece_Prop_Desc_Data];
1195 int j;
1196 PTPDevicePropDesc *dpd;
1197
Linus Walleij7e756532009-05-06 21:25:09 +00001198 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 +00001199 for (j=0;j<params->nrofcanon_props;j++)
1200 if (params->canon_props[j].proptype == proptype)
1201 break;
1202 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001203 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001204 break;
1205 }
1206 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001207 /* 1 - uint16 ?
1208 * 3 - uint16
1209 * 7 - string?
1210 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001211 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001212 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1213 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
1214 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001215 break;
1216 }
1217 if (propxcnt) {
1218 dpd->FormFlag = PTP_DPFF_Enumeration;
1219 dpd->FORM.Enum.NumberOfValues = propxcnt;
1220 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1221 for (j=0;j<propxcnt;j++) {
1222 switch (dpd->DataType) {
Linus Walleij7e756532009-05-06 21:25:09 +00001223 case PTP_DTC_INT16:
1224 dpd->FORM.Enum.SupportedValue[j].i16 = dtoh16a(data);
1225 ptp_debug (params, "event %d: suppval[%d] of %x is %x.", i, j, proptype, dtoh16a(data));
1226 break;
1227 case PTP_DTC_UINT32:
1228 dpd->FORM.Enum.SupportedValue[j].u32 = dtoh32a(data);
1229 ptp_debug (params, "event %d: suppval[%d] of %x is %x.", i, j, proptype, dtoh32a(data));
1230 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001231 case PTP_DTC_UINT16:
1232 dpd->FORM.Enum.SupportedValue[j].u16 = dtoh16a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001233 ptp_debug (params, "event %d: suppval[%d] of %x is %x.", i, j, proptype, dtoh16a(data));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001234 break;
1235 case PTP_DTC_UINT8:
1236 dpd->FORM.Enum.SupportedValue[j].u8 = dtoh8a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001237 ptp_debug (params,"event %d: suppvalue[%d] of %x is %x", i, j, proptype, dtoh8a(data));
Linus Walleijf0bf4372007-07-01 21:47:38 +00001238 break;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001239 default: {
1240 int k;
1241 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, fill in (val=%x).", i, dpd->DataType, proptype, dtoh32a(data));
1242 for (k=0;k<size-PTP_ece_Prop_Desc_Data;k++)
1243 ptp_debug (params, " %d: %02x", k, data[k]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001244 break;
1245 }
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001246 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001247 data += 4; /* might only be for propxtype 3 */
1248 }
1249 }
1250 break;
1251 }
Linus Walleij7e756532009-05-06 21:25:09 +00001252 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001253 if (size >= 0xc) { /* property info */
1254 int j;
1255 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1256 unsigned char *data = &curdata[PTP_ece_Prop_Val_Data];
1257 PTPDevicePropDesc *dpd;
1258
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001259 ptp_debug (params, "event %d: EOS prop %04x info record, datasize %d", i, proptype, size-4);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001260 for (j=0;j<params->nrofcanon_props;j++)
1261 if (params->canon_props[j].proptype == proptype)
1262 break;
1263 if (j<params->nrofcanon_props) {
1264 if ( (params->canon_props[j].size != size) ||
1265 (memcmp(params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data))) {
1266 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
1267 memcpy (params->canon_props[j].data,data,size-PTP_ece_Prop_Val_Data);
1268 }
1269 } else {
1270 if (j)
1271 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1272 else
1273 params->canon_props = malloc(sizeof(params->canon_props[0]));
1274 params->canon_props[j].type = type;
1275 params->canon_props[j].proptype = proptype;
1276 params->canon_props[j].size = size;
1277 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
1278 memcpy(params->canon_props[j].data, data, size-PTP_ece_Prop_Val_Data);
1279 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1280 params->canon_props[j].dpd.GetSet = 1;
1281 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1282 params->nrofcanon_props = j+1;
1283 }
1284 dpd = &params->canon_props[j].dpd;
1285 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001286 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleij7e756532009-05-06 21:25:09 +00001287 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleijac052c12007-07-18 18:37:10 +00001288 dpd->DataType = PTP_DTC_UINT32;
1289 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001290 case PTP_DPC_CANON_EOS_Aperture:
1291 case PTP_DPC_CANON_EOS_ShutterSpeed:
1292 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00001293 case PTP_DPC_CANON_EOS_FocusMode:
1294 case PTP_DPC_CANON_EOS_AutoExposureMode:
1295 case PTP_DPC_CANON_EOS_ColorSpace:
1296 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001297 dpd->DataType = PTP_DTC_UINT16;
1298 break;
1299 case PTP_DPC_CANON_EOS_PictureStyle:
1300 case PTP_DPC_CANON_EOS_WhiteBalance:
1301 case PTP_DPC_CANON_EOS_MeteringMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001302 case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001303 dpd->DataType = PTP_DTC_UINT8;
1304 break;
1305 case PTP_DPC_CANON_EOS_Owner:
1306 dpd->DataType = PTP_DTC_STR;
1307 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001308 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
1309 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
1310 dpd->DataType = PTP_DTC_INT16;
1311 break;
1312 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
1313 case PTP_DPC_CANON_EOS_DriveMode:
1314 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
1315 case PTP_DPC_CANON_EOS_BatterySelect:
1316 case 0xd114:
1317 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
1318 case PTP_DPC_CANON_EOS_DPOFVersion:
1319 case PTP_DPC_CANON_EOS_AvailableShots:
1320 case PTP_DPC_CANON_EOS_CaptureDestination:
1321 case PTP_DPC_CANON_EOS_BracketMode:
1322 case PTP_DPC_CANON_EOS_CustomFunc1:
1323 case PTP_DPC_CANON_EOS_CustomFunc2:
1324 case PTP_DPC_CANON_EOS_CustomFunc3:
1325 case PTP_DPC_CANON_EOS_CustomFunc4:
1326 case PTP_DPC_CANON_EOS_CustomFunc5:
1327 case PTP_DPC_CANON_EOS_CustomFunc6:
1328 case PTP_DPC_CANON_EOS_CustomFunc7:
1329 case PTP_DPC_CANON_EOS_CustomFunc8:
1330 case PTP_DPC_CANON_EOS_CustomFunc9:
1331 case PTP_DPC_CANON_EOS_CustomFunc10:
1332 case PTP_DPC_CANON_EOS_CustomFunc11:
1333 dpd->DataType = PTP_DTC_UINT16;
1334 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
1335 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1336 ptp_debug (params, " %d: %02x", j, data[j]);
1337 break;
1338 /* yet unknown 32bit props */
1339 case PTP_DPC_CANON_EOS_ColorTemperature:
1340 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
1341 case PTP_DPC_CANON_EOS_ModelID:
1342 case PTP_DPC_CANON_EOS_CurrentStorage:
1343 case PTP_DPC_CANON_EOS_CurrentFolder:
1344 case PTP_DPC_CANON_EOS_WftStatus:
1345 case PTP_DPC_CANON_EOS_LensStatus:
1346 case PTP_DPC_CANON_EOS_QuickReviewTime:
1347 case PTP_DPC_CANON_EOS_CardExtension:
1348 case PTP_DPC_CANON_EOS_TempStatus:
1349 case PTP_DPC_CANON_EOS_ShutterCounter:
1350 case PTP_DPC_CANON_EOS_PhotoStudioMode:
1351 case PTP_DPC_CANON_EOS_EVFMode:
1352 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
1353 case PTP_DPC_CANON_EOS_EVFSharpness:
1354 case PTP_DPC_CANON_EOS_EVFWBMode:
1355 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
1356 case PTP_DPC_CANON_EOS_EVFColorTemp:
1357 dpd->DataType = PTP_DTC_UINT32;
1358 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint32", i ,proptype, size-PTP_ece_Prop_Val_Data);
1359 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1360 ptp_debug (params, " %d: %02x", j, data[j]);
1361 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001362 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001363 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1364 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
1365 ptp_debug (params, " %d: %02x", j, data[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001366 break;
1367 }
1368 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001369 case PTP_DTC_UINT32:
1370 dpd->FactoryDefaultValue.u32 = dtoh32a(data);
1371 dpd->CurrentValue.u32 = dtoh32a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001372 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001373 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001374 case PTP_DTC_UINT16:
1375 dpd->FactoryDefaultValue.u16 = dtoh16a(data);
1376 dpd->CurrentValue.u16 = dtoh16a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001377 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001378 break;
1379 case PTP_DTC_UINT8:
1380 dpd->FactoryDefaultValue.u8 = dtoh8a(data);
1381 dpd->CurrentValue.u8 = dtoh8a(data);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001382 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001383 break;
1384 case PTP_DTC_STR: {
1385 uint8_t len = 0;
1386 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1387 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij7e756532009-05-06 21:25:09 +00001388 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001389 break;
1390 }
1391 default:
1392 /* debug is printed in switch above this one */
1393 break;
1394 }
1395 break;
1396 }
Linus Walleij7e756532009-05-06 21:25:09 +00001397 case 0: /* end marker */
1398 if (size == 8) /* no output */
1399 break;
1400 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
1401 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001402 default:
Linus Walleij7e756532009-05-06 21:25:09 +00001403 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
1404 if (size >= 0x8) { /* event info */
1405 int j;
1406 for (j=8;j<size;j++) {
1407 ptp_debug (params, " %d: %02x", j, data[j]);
1408 }
1409 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001410 (*ce)[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1411 break;
1412 }
1413 curdata += size;
1414 i++;
Linus Walleij9d22ce02008-05-28 20:39:29 +00001415 if ((size == 8) && (type == 0))
1416 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001417 }
1418
1419 return entries;
1420}
1421
1422/*
Linus Walleijb02a0662006-04-25 08:05:09 +00001423 PTP USB Event container unpack for Nikon events.
1424*/
1425#define PTP_nikon_ec_Length 0
1426#define PTP_nikon_ec_Code 2
1427#define PTP_nikon_ec_Param1 4
1428#define PTP_nikon_ec_Size 6
1429static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001430ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00001431{
1432 int i;
1433
1434 *ec = NULL;
1435 if (data == NULL)
1436 return;
1437 if (len < PTP_nikon_ec_Code)
1438 return;
1439 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
1440 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
1441 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001442 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00001443
1444 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00001445 memset(&(*ec)[i],0,sizeof(PTPContainer));
1446 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
1447 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
1448 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00001449 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001450}
1451
1452
Linus Walleijb02a0662006-04-25 08:05:09 +00001453static inline uint32_t
1454ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
1455 int i, len = 0;
1456 uint8_t retlen;
1457 unsigned char *curdata;
1458
1459 len = 2*(strlen(text->title)+1)+1+
1460 2*(strlen(text->line[0])+1)+1+
1461 2*(strlen(text->line[1])+1)+1+
1462 2*(strlen(text->line[2])+1)+1+
1463 2*(strlen(text->line[3])+1)+1+
1464 2*(strlen(text->line[4])+1)+1+
1465 4*2+2*4+2+4+2+5*4*2;
1466 *data = malloc(len);
1467 if (!*data) return 0;
1468
1469 curdata = *data;
1470 htod16a(curdata,100);curdata+=2;
1471 htod16a(curdata,1);curdata+=2;
1472 htod16a(curdata,0);curdata+=2;
1473 htod16a(curdata,1000);curdata+=2;
1474
1475 htod32a(curdata,0);curdata+=4;
1476 htod32a(curdata,0);curdata+=4;
1477
1478 htod16a(curdata,6);curdata+=2;
1479 htod32a(curdata,0);curdata+=4;
1480
1481 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1482 htod16a(curdata,0x10);curdata+=2;
1483
1484 for (i=0;i<5;i++) {
1485 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
1486 htod16a(curdata,0x10);curdata+=2;
1487 htod16a(curdata,0x01);curdata+=2;
1488 htod16a(curdata,0x02);curdata+=2;
1489 htod16a(curdata,0x06);curdata+=2;
1490 }
1491 return len;
1492}
Linus Walleij7347d0f2006-10-23 07:23:39 +00001493
1494#define ptp_canon_dir_version 0x00
1495#define ptp_canon_dir_ofc 0x02
1496#define ptp_canon_dir_unk1 0x04
1497#define ptp_canon_dir_objectid 0x08
1498#define ptp_canon_dir_parentid 0x0c
1499#define ptp_canon_dir_previd 0x10 /* in same dir */
1500#define ptp_canon_dir_nextid 0x14 /* in same dir */
1501#define ptp_canon_dir_nextchild 0x18 /* down one dir */
1502#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
1503#define ptp_canon_dir_name 0x20
1504#define ptp_canon_dir_flags 0x2c
1505#define ptp_canon_dir_size 0x30
1506#define ptp_canon_dir_unixtime 0x34
1507#define ptp_canon_dir_year 0x38
1508#define ptp_canon_dir_month 0x39
1509#define ptp_canon_dir_mday 0x3a
1510#define ptp_canon_dir_hour 0x3b
1511#define ptp_canon_dir_minute 0x3c
1512#define ptp_canon_dir_second 0x3d
1513#define ptp_canon_dir_unk2 0x3e
1514#define ptp_canon_dir_thumbsize 0x40
1515#define ptp_canon_dir_width 0x44
1516#define ptp_canon_dir_height 0x48
1517
1518static inline uint16_t
1519ptp_unpack_canon_directory (
1520 PTPParams *params,
1521 unsigned char *dir,
1522 uint32_t cnt,
1523 PTPObjectHandles *handles,
1524 PTPObjectInfo **oinfos, /* size(handles->n) */
1525 uint32_t **flags /* size(handles->n) */
1526) {
1527 unsigned int i, j, nrofobs = 0, curob = 0;
1528
1529#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
1530 for (i=0;i<cnt;i++)
1531 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
1532 handles->n = nrofobs;
1533 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
1534 if (!handles->Handler) return PTP_RC_GeneralError;
1535 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
1536 if (!*oinfos) return PTP_RC_GeneralError;
1537 *flags = calloc(sizeof((*flags)[0]),nrofobs);
1538 if (!*flags) return PTP_RC_GeneralError;
1539
1540 /* Migrate data into objects ids, handles into
1541 * the object handler array.
1542 */
1543 curob = 0;
1544 for (i=0;i<cnt;i++) {
1545 unsigned char *cur = dir+i*0x4c;
1546 PTPObjectInfo *oi = (*oinfos)+curob;
1547
1548 if (!ISOBJECT(cur))
1549 continue;
1550
1551 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
1552 oi->StorageID = 0xffffffff;
1553 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
1554 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
1555 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
1556 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
1557 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
1558 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
1559 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
1560 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
1561 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
1562 curob++;
1563 }
1564 /* Walk over Storage ID entries and distribute the IDs to
1565 * the parent objects. */
1566 for (i=0;i<cnt;i++) {
1567 unsigned char *cur = dir+i*0x4c;
1568 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1569
1570 if (ISOBJECT(cur))
1571 continue;
1572 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1573 if (j == handles->n) continue;
1574 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
1575 }
1576 /* Walk over all objects and distribute the storage ids */
1577 while (1) {
1578 int changed = 0;
1579 for (i=0;i<cnt;i++) {
1580 unsigned char *cur = dir+i*0x4c;
1581 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
1582 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
1583 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
1584 uint32_t storageid;
1585
1586 if (!ISOBJECT(cur))
1587 continue;
1588 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
1589 if (j == handles->n) {
1590 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
1591 continue;
1592 }
1593 storageid = (*oinfos)[j].StorageID;
1594 if (storageid == 0xffffffff) continue;
1595 if (nextoid != 0xffffffff) {
1596 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
1597 if (j == handles->n) {
1598 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
1599 continue;
1600 }
1601 if ((*oinfos)[j].StorageID == 0xffffffff) {
1602 (*oinfos)[j].StorageID = storageid;
1603 changed++;
1604 }
1605 }
1606 if (nextchild != 0xffffffff) {
1607 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
1608 if (j == handles->n) {
1609 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
1610 continue;
1611 }
1612 if ((*oinfos)[j].StorageID == 0xffffffff) {
1613 (*oinfos)[j].StorageID = storageid;
1614 changed++;
1615 }
1616 }
1617 }
1618 /* Check if we:
1619 * - changed no entry (nothing more to do)
1620 * - changed all of them at once (usually happens)
1621 * break if we do.
1622 */
1623 if (!changed || (changed==nrofobs-1))
1624 break;
1625 }
1626#undef ISOBJECT
1627 return PTP_RC_OK;
1628}
1629