blob: 71c82d628badc618301f040445b01037bff8eaba [file] [log] [blame]
Linus Walleija381e8a2013-03-05 21:00:06 +01001/* ptp-pack.c
2 *
3 * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
4 * Copyright (C) 2003-2012 Marcus Meissner <marcus@jet.franken.de>
5 * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
6 * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
7 * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
Linus Walleij9783ce32014-06-02 21:44:29 +020021 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301 USA
Linus Walleija381e8a2013-03-05 21:00:06 +010023 */
24
Linus Walleijb02a0662006-04-25 08:05:09 +000025/* currently this file is included into ptp.c */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000026
Linus Walleij9783ce32014-06-02 21:44:29 +020027#ifdef HAVE_LIMITS_H
28#include <limits.h>
29#endif
30#ifndef UINT_MAX
31# define UINT_MAX 0xFFFFFFFF
32#endif
Linus Walleij6db174f2009-05-09 13:15:26 +000033#ifdef HAVE_ICONV
Linus Walleija823a702006-08-27 21:27:46 +000034#include <iconv.h>
Linus Walleij6db174f2009-05-09 13:15:26 +000035#endif
Linus Walleija823a702006-08-27 21:27:46 +000036
Linus Walleijb02a0662006-04-25 08:05:09 +000037static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000038htod16p (PTPParams *params, uint16_t var)
39{
40 return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
41}
42
Linus Walleijb02a0662006-04-25 08:05:09 +000043static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000044htod32p (PTPParams *params, uint32_t var)
45{
46 return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
47}
48
Linus Walleijb02a0662006-04-25 08:05:09 +000049static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000050htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
51{
52 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000053 htole16a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020054 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000055 htobe16a(a,val);
56}
57
Linus Walleijb02a0662006-04-25 08:05:09 +000058static inline void
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000059htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
60{
61 if (params->byteorder==PTP_DL_LE)
Linus Walleijb02a0662006-04-25 08:05:09 +000062 htole32a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020063 else
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000064 htobe32a(a,val);
65}
66
Linus Walleijabf54752007-07-30 19:51:54 +000067static inline void
68htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
69{
70 if (params->byteorder==PTP_DL_LE)
71 htole64a(a,val);
Linus Walleije206af62011-04-19 01:51:39 +020072 else
Linus Walleijabf54752007-07-30 19:51:54 +000073 htobe64a(a,val);
74}
75
Linus Walleijb02a0662006-04-25 08:05:09 +000076static inline uint16_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000077dtoh16p (PTPParams *params, uint16_t var)
78{
79 return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
80}
81
Linus Walleijb02a0662006-04-25 08:05:09 +000082static inline uint32_t
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000083dtoh32p (PTPParams *params, uint32_t var)
84{
85 return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
86}
87
Linus Walleijabf54752007-07-30 19:51:54 +000088static inline uint64_t
89dtoh64p (PTPParams *params, uint64_t var)
90{
91 return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
92}
93
Linus Walleijb02a0662006-04-25 08:05:09 +000094static inline uint16_t
Linus Walleij1a0c3012009-07-23 23:06:58 +000095dtoh16ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +000096{
97 return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
98}
99
Linus Walleijb02a0662006-04-25 08:05:09 +0000100static inline uint32_t
Linus Walleij1a0c3012009-07-23 23:06:58 +0000101dtoh32ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000102{
103 return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
104}
105
Linus Walleijb02a0662006-04-25 08:05:09 +0000106static inline uint64_t
Linus Walleij1a0c3012009-07-23 23:06:58 +0000107dtoh64ap (PTPParams *params, const unsigned char *a)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000108{
Linus Walleijabf54752007-07-30 19:51:54 +0000109 return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000110}
111
Linus Walleijb02a0662006-04-25 08:05:09 +0000112#define htod8a(a,x) *(uint8_t*)(a) = x
113#define htod16a(a,x) htod16ap(params,a,x)
114#define htod32a(a,x) htod32ap(params,a,x)
Linus Walleijabf54752007-07-30 19:51:54 +0000115#define htod64a(a,x) htod64ap(params,a,x)
Linus Walleijb02a0662006-04-25 08:05:09 +0000116#define htod16(x) htod16p(params,x)
117#define htod32(x) htod32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +0000118#define htod64(x) htod64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +0000119
120#define dtoh8a(x) (*(uint8_t*)(x))
121#define dtoh16a(a) dtoh16ap(params,a)
122#define dtoh32a(a) dtoh32ap(params,a)
123#define dtoh64a(a) dtoh64ap(params,a)
124#define dtoh16(x) dtoh16p(params,x)
125#define dtoh32(x) dtoh32p(params,x)
Linus Walleijabf54752007-07-30 19:51:54 +0000126#define dtoh64(x) dtoh64p(params,x)
Linus Walleijb02a0662006-04-25 08:05:09 +0000127
128
129static inline char*
130ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000131{
Linus Walleija8a19cc2007-02-02 22:13:17 +0000132 uint8_t length;
133 uint16_t string[PTP_MAXSTRLEN+1];
134 /* allow for UTF-8: max of 3 bytes per UCS-2 char, plus final null */
Linus Walleije206af62011-04-19 01:51:39 +0200135 char loclstr[PTP_MAXSTRLEN*3+1];
Linus Walleija8a19cc2007-02-02 22:13:17 +0000136 size_t nconv, srclen, destlen;
137 char *src, *dest;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000138
Linus Walleija8a19cc2007-02-02 22:13:17 +0000139 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
140 *len = length;
141 if (length == 0) /* nothing to do? */
142 return(NULL);
143
144 /* copy to string[] to ensure correct alignment for iconv(3) */
145 memcpy(string, &data[offset+1], length * sizeof(string[0]));
146 string[length] = 0x0000U; /* be paranoid! add a terminator. */
147 loclstr[0] = '\0';
Linus Walleije206af62011-04-19 01:51:39 +0200148
Linus Walleija8a19cc2007-02-02 22:13:17 +0000149 /* convert from camera UCS-2 to our locale */
150 src = (char *)string;
151 srclen = length * sizeof(string[0]);
152 dest = loclstr;
153 destlen = sizeof(loclstr)-1;
Linus Walleij6db174f2009-05-09 13:15:26 +0000154 nconv = (size_t)-1;
155#ifdef HAVE_ICONV
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100156 if (params->cd_ucs2_to_locale != (iconv_t)-1)
157 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, &dest, &destlen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000158#endif
Linus Walleija8a19cc2007-02-02 22:13:17 +0000159 if (nconv == (size_t) -1) { /* do it the hard way */
160 int i;
161 /* try the old way, in case iconv is broken */
162 for (i=0;i<length;i++) {
163 if (dtoh16a(&data[offset+1+2*i])>127)
164 loclstr[i] = '?';
165 else
166 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000167 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000168 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000169 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000170 *dest = '\0';
171 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
172 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000173}
174
Linus Walleija823a702006-08-27 21:27:46 +0000175static inline int
176ucs2strlen(uint16_t const * const unicstr)
177{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200178 int length = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000179
180 /* Unicode strings are terminated with 2 * 0x00 */
181 for(length = 0; unicstr[length] != 0x0000U; length ++);
182 return length;
183}
184
185
Linus Walleijb02a0662006-04-25 08:05:09 +0000186static inline void
187ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000188{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200189 int packedlen = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000190 uint16_t ucs2str[PTP_MAXSTRLEN+1];
191 char *ucs2strp = (char *) ucs2str;
Linus Walleija823a702006-08-27 21:27:46 +0000192 size_t convlen = strlen(string);
Linus Walleija823a702006-08-27 21:27:46 +0000193
194 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000195 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
Linus Walleij6db174f2009-05-09 13:15:26 +0000196#ifdef HAVE_ICONV
Linus Walleijd000c372011-12-20 08:32:23 +0100197 if (params->cd_locale_to_ucs2 != (iconv_t)-1) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000198 size_t nconv;
199 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
200 char *stringp = string;
201
202 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
203 &ucs2strp, &convmax);
204 if (nconv == (size_t) -1)
205 ucs2str[0] = 0x0000U;
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100206 } else
Linus Walleijd000c372011-12-20 08:32:23 +0100207#endif
Linus Walleij6db174f2009-05-09 13:15:26 +0000208 {
Linus Walleij2ad5b722013-11-04 02:07:44 +0100209 unsigned int i;
210
Linus Walleij6db174f2009-05-09 13:15:26 +0000211 for (i=0;i<convlen;i++) {
212 ucs2str[i] = string[i];
213 }
214 ucs2str[convlen] = 0;
215 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000216 /*
217 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
218 * why do we need ucs2strlen()?
219 */
Linus Walleija823a702006-08-27 21:27:46 +0000220 packedlen = ucs2strlen(ucs2str);
221 if (packedlen > PTP_MAXSTRLEN-1) {
222 *len=0;
223 return;
224 }
Linus Walleij958441f2006-08-29 15:30:11 +0000225
Linus Walleij7f234382006-12-09 19:41:00 +0000226 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000227 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000228 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
229 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000230
231 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000232 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000233}
234
235static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000236ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000237{
Richard Low8b42ca32006-11-15 08:52:17 +0000238 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000239 size_t plen;
240 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000241
242 if (string == NULL)
243 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
244 else
245 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
246
Linus Walleij958441f2006-08-29 15:30:11 +0000247 /* returned length is in characters, then one byte for string length */
248 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000249
Linus Walleija823a702006-08-27 21:27:46 +0000250 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000251 if (!retcopy) {
252 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000253 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000254 }
Linus Walleija823a702006-08-27 21:27:46 +0000255 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000256 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000257 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000258}
259
Linus Walleijb02a0662006-04-25 08:05:09 +0000260static inline uint32_t
261ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000262{
263 uint32_t n, i=0;
264
Linus Walleij9783ce32014-06-02 21:44:29 +0200265 *array = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000266 n=dtoh32a(&data[offset]);
Linus Walleij9783ce32014-06-02 21:44:29 +0200267 if (n >= UINT_MAX/sizeof(uint32_t))
268 return 0;
269 if (!n)
270 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000271 *array = malloc (n*sizeof(uint32_t));
Linus Walleij9783ce32014-06-02 21:44:29 +0200272 for (i=0;i<n;i++)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000273 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000274 return n;
275}
276
Linus Walleijb02a0662006-04-25 08:05:09 +0000277static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000278ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
279{
280 uint32_t i=0;
281
282 *data = malloc ((arraylen+1)*sizeof(uint32_t));
283 htod32a(&(*data)[0],arraylen);
284 for (i=0;i<arraylen;i++)
285 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
286 return (arraylen+1)*sizeof(uint32_t);
287}
288
289static inline uint32_t
Linus Walleijb02a0662006-04-25 08:05:09 +0000290ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, uint16_t offset, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000291{
292 uint32_t n, i=0;
293
Linus Walleij9783ce32014-06-02 21:44:29 +0200294 *array = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000295 n=dtoh32a(&data[offset]);
Linus Walleij9783ce32014-06-02 21:44:29 +0200296 if (n >= UINT_MAX/sizeof(uint16_t))
297 return 0;
298 if (!n)
299 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000300 *array = malloc (n*sizeof(uint16_t));
Linus Walleij9783ce32014-06-02 21:44:29 +0200301 for (i=0;i<n;i++)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000302 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000303 return n;
304}
305
306/* DeviceInfo pack/unpack */
307
308#define PTP_di_StandardVersion 0
309#define PTP_di_VendorExtensionID 2
310#define PTP_di_VendorExtensionVersion 6
311#define PTP_di_VendorExtensionDesc 8
312#define PTP_di_FunctionalMode 8
313#define PTP_di_OperationsSupported 10
314
Linus Walleijb02a0662006-04-25 08:05:09 +0000315static inline void
316ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000317{
318 uint8_t len;
319 unsigned int totallen;
Linus Walleij7e756532009-05-06 21:25:09 +0000320
Linus Walleijd4637502009-06-14 23:03:33 +0000321 if (!data) return;
322 if (datalen < 12) return;
Linus Walleij7347d0f2006-10-23 07:23:39 +0000323 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000324 di->VendorExtensionID =
325 dtoh32a(&data[PTP_di_VendorExtensionID]);
326 di->VendorExtensionVersion =
327 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
328 di->VendorExtensionDesc =
329 ptp_unpack_string(params, data,
330 PTP_di_VendorExtensionDesc, &len);
331 totallen=len*2+1;
332 di->FunctionalMode =
333 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
334 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
335 PTP_di_OperationsSupported+totallen,
336 &di->OperationsSupported);
337 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
338 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
339 PTP_di_OperationsSupported+totallen,
340 &di->EventsSupported);
341 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
342 di->DevicePropertiesSupported_len =
343 ptp_unpack_uint16_t_array(params, data,
344 PTP_di_OperationsSupported+totallen,
345 &di->DevicePropertiesSupported);
346 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
347 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
348 PTP_di_OperationsSupported+totallen,
349 &di->CaptureFormats);
350 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
351 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
352 PTP_di_OperationsSupported+totallen,
353 &di->ImageFormats);
354 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
355 di->Manufacturer = ptp_unpack_string(params, data,
356 PTP_di_OperationsSupported+totallen,
357 &len);
358 totallen+=len*2+1;
359 di->Model = ptp_unpack_string(params, data,
360 PTP_di_OperationsSupported+totallen,
361 &len);
362 totallen+=len*2+1;
363 di->DeviceVersion = ptp_unpack_string(params, data,
364 PTP_di_OperationsSupported+totallen,
365 &len);
366 totallen+=len*2+1;
367 di->SerialNumber = ptp_unpack_string(params, data,
368 PTP_di_OperationsSupported+totallen,
369 &len);
370}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000371
Linus Walleij2ad5b722013-11-04 02:07:44 +0100372inline static void
Linus Walleija8a19cc2007-02-02 22:13:17 +0000373ptp_free_DI (PTPDeviceInfo *di) {
374 if (di->SerialNumber) free (di->SerialNumber);
375 if (di->DeviceVersion) free (di->DeviceVersion);
376 if (di->Model) free (di->Model);
377 if (di->Manufacturer) free (di->Manufacturer);
378 if (di->ImageFormats) free (di->ImageFormats);
379 if (di->CaptureFormats) free (di->CaptureFormats);
380 if (di->VendorExtensionDesc) free (di->VendorExtensionDesc);
381 if (di->OperationsSupported) free (di->OperationsSupported);
382 if (di->EventsSupported) free (di->EventsSupported);
383 if (di->DevicePropertiesSupported) free (di->DevicePropertiesSupported);
384}
Linus Walleij7e756532009-05-06 21:25:09 +0000385
386/* EOS Device Info unpack */
387static inline void
388ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
389{
Linus Walleij2ad5b722013-11-04 02:07:44 +0100390 unsigned int totallen = 4;
Linus Walleij96aa0e32012-03-25 12:25:25 +0200391
392 memset (di,0, sizeof(*di));
Linus Walleij7e756532009-05-06 21:25:09 +0000393 if (datalen < 8) return;
394
395 /* uint32_t struct len - ignore */
396 di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
397 totallen, &di->EventsSupported);
398 if (!di->EventsSupported) return;
399 totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
400 if (totallen >= datalen) return;
401
402 di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
403 totallen, &di->DevicePropertiesSupported);
404 if (!di->DevicePropertiesSupported) return;
405 totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
406 if (totallen >= datalen) return;
407
408 di->unk_len = ptp_unpack_uint32_t_array(params, data,
409 totallen, &di->unk);
410 if (!di->unk) return;
411 totallen += di->unk_len*sizeof(uint32_t)+4;
412 return;
413}
Linus Walleij0d762cc2010-04-04 23:34:27 +0000414
415static inline void
416ptp_free_EOS_DI (PTPCanonEOSDeviceInfo *di)
417{
418 free (di->EventsSupported);
419 free (di->DevicePropertiesSupported);
420 free (di->unk);
421}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000422
423/* ObjectHandles array pack/unpack */
424
425#define PTP_oh 0
426
Linus Walleijb02a0662006-04-25 08:05:09 +0000427static inline void
428ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000429{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000430 if (len) {
431 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, &oh->Handler);
432 } else {
433 oh->n = 0;
434 oh->Handler = NULL;
435 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000436}
437
438/* StoreIDs array pack/unpack */
439
440#define PTP_sids 0
441
Linus Walleijb02a0662006-04-25 08:05:09 +0000442static inline void
443ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000444{
Linus Walleij2ad5b722013-11-04 02:07:44 +0100445 if (!data || !len) {
Linus Walleij96aa0e32012-03-25 12:25:25 +0200446 sids->n = 0;
447 sids->Storage = NULL;
448 return;
449 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000450 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids,
451 &sids->Storage);
452}
453
454/* StorageInfo pack/unpack */
455
456#define PTP_si_StorageType 0
457#define PTP_si_FilesystemType 2
458#define PTP_si_AccessCapability 4
459#define PTP_si_MaxCapability 6
460#define PTP_si_FreeSpaceInBytes 14
461#define PTP_si_FreeSpaceInImages 22
462#define PTP_si_StorageDescription 26
463
Linus Walleijb02a0662006-04-25 08:05:09 +0000464static inline void
465ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000466{
467 uint8_t storagedescriptionlen;
468
469 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
470 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
471 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000472 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
473 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
474 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
475 si->StorageDescription=ptp_unpack_string(params, data,
476 PTP_si_StorageDescription, &storagedescriptionlen);
477 si->VolumeLabel=ptp_unpack_string(params, data,
478 PTP_si_StorageDescription+storagedescriptionlen*2+1,
479 &storagedescriptionlen);
480}
481
482/* ObjectInfo pack/unpack */
483
484#define PTP_oi_StorageID 0
485#define PTP_oi_ObjectFormat 4
486#define PTP_oi_ProtectionStatus 6
487#define PTP_oi_ObjectCompressedSize 8
488#define PTP_oi_ThumbFormat 12
489#define PTP_oi_ThumbCompressedSize 14
490#define PTP_oi_ThumbPixWidth 18
491#define PTP_oi_ThumbPixHeight 22
492#define PTP_oi_ImagePixWidth 26
493#define PTP_oi_ImagePixHeight 30
494#define PTP_oi_ImageBitDepth 34
495#define PTP_oi_ParentObject 38
496#define PTP_oi_AssociationType 42
497#define PTP_oi_AssociationDesc 44
498#define PTP_oi_SequenceNumber 48
499#define PTP_oi_filenamelen 52
500#define PTP_oi_Filename 53
501
Linus Walleija0323272007-01-07 12:21:30 +0000502/* the max length assuming zero length dates. We have need 3 */
503/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000504#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
505
Linus Walleijb02a0662006-04-25 08:05:09 +0000506static inline uint32_t
507ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000508{
Linus Walleijb02a0662006-04-25 08:05:09 +0000509 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000510 uint8_t filenamelen;
511 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000512 /* let's allocate some memory first; correct assuming zero length dates */
Marcus Meissner0546a762012-04-10 18:49:10 +0200513 oidata=malloc(PTP_oi_MaxLen + params->ocs64*4);
514 *oidataptr=oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000515 /* the caller should free it after use! */
516#if 0
517 char *capture_date="20020101T010101"; /* XXX Fake date */
518#endif
Marcus Meissner0546a762012-04-10 18:49:10 +0200519 memset (oidata, 0, PTP_oi_MaxLen + params->ocs64*4);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000520 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
521 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
522 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
523 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
Marcus Meissner0546a762012-04-10 18:49:10 +0200524 if (params->ocs64)
525 oidata += 4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000526 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
527 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
528 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
529 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
530 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
531 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
532 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
533 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
534 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
535 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
536 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
537
538 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
539/*
540 filenamelen=(uint8_t)strlen(oi->Filename);
541 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
542 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
543 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
544 }
545*/
546 /*
547 *XXX Fake date.
548 * for example Kodak sets Capture date on the basis of EXIF data.
549 * Spec says that this field is from perspective of Initiator.
550 */
551#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
552 capturedatelen=strlen(capture_date);
553 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
554 capturedatelen+1);
555 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
556 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
557 }
558 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
559 capturedatelen+1);
560 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
561 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
562 capture_date[i];
563 }
564#endif
565 /* XXX this function should return dataset length */
Marcus Meissner0546a762012-04-10 18:49:10 +0200566 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3)+params->ocs64*4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000567}
568
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000569static time_t
Linus Walleij6db174f2009-05-09 13:15:26 +0000570ptp_unpack_PTPTIME (const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000571 char ptpdate[40];
572 char tmp[5];
Linus Walleija381e8a2013-03-05 21:00:06 +0100573 size_t ptpdatelen;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000574 struct tm tm;
575
576 if (!str)
577 return 0;
578 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000579 if (ptpdatelen >= sizeof (ptpdate)) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000580 /*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000581 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000582 }
Linus Walleij7e756532009-05-06 21:25:09 +0000583 if (ptpdatelen<15) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000584 /*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000585 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000586 }
Linus Walleija381e8a2013-03-05 21:00:06 +0100587 strncpy (ptpdate, str, sizeof(ptpdate));
588 ptpdate[sizeof(ptpdate) - 1] = '\0';
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000589
590 memset(&tm,0,sizeof(tm));
591 strncpy (tmp, ptpdate, 4);
592 tmp[4] = 0;
593 tm.tm_year=atoi (tmp) - 1900;
594 strncpy (tmp, ptpdate + 4, 2);
595 tmp[2] = 0;
596 tm.tm_mon = atoi (tmp) - 1;
597 strncpy (tmp, ptpdate + 6, 2);
598 tmp[2] = 0;
599 tm.tm_mday = atoi (tmp);
600 strncpy (tmp, ptpdate + 9, 2);
601 tmp[2] = 0;
602 tm.tm_hour = atoi (tmp);
603 strncpy (tmp, ptpdate + 11, 2);
604 tmp[2] = 0;
605 tm.tm_min = atoi (tmp);
606 strncpy (tmp, ptpdate + 13, 2);
607 tmp[2] = 0;
608 tm.tm_sec = atoi (tmp);
Linus Walleije206af62011-04-19 01:51:39 +0200609 tm.tm_isdst = -1;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000610 return mktime (&tm);
611}
612
Linus Walleijb02a0662006-04-25 08:05:09 +0000613static inline void
614ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000615{
616 uint8_t filenamelen;
617 uint8_t capturedatelen;
618 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000619
620 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
621 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
622 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
623 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200624
625 /* Stupid Samsung Galaxy developers emit a 64bit objectcompressedsize */
626 if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0)) {
627 params->ocs64 = 1;
628 data += 4;
629 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000630 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
631 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
632 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
633 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
634 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
635 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
636 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
637 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
638 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
639 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
640 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200641
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000642 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, &filenamelen);
643
644 capture_date = ptp_unpack_string(params, data,
645 PTP_oi_filenamelen+filenamelen*2+1, &capturedatelen);
646 /* subset of ISO 8601, without '.s' tenths of second and
647 * time zone
648 */
Linus Walleij6db174f2009-05-09 13:15:26 +0000649 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000650 free(capture_date);
651
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000652 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000653 capture_date = ptp_unpack_string(params, data,
654 PTP_oi_filenamelen+filenamelen*2
655 +capturedatelen*2+2,&capturedatelen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000656 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000657 free(capture_date);
658}
659
660/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000661#define CTVAL(target,func) { \
662 if (total - *offset < sizeof(target)) \
663 return 0; \
664 target = func(&data[*offset]); \
665 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000666}
667
Linus Walleijb02a0662006-04-25 08:05:09 +0000668#define RARR(val,member,func) { \
Linus Walleij9783ce32014-06-02 21:44:29 +0200669 unsigned int n,j; \
Linus Walleijb02a0662006-04-25 08:05:09 +0000670 if (total - *offset < sizeof(uint32_t)) \
671 return 0; \
672 n = dtoh32a (&data[*offset]); \
673 *offset += sizeof(uint32_t); \
674 \
Linus Walleij9783ce32014-06-02 21:44:29 +0200675 if (n >= UINT_MAX/sizeof(val->a.v[0])) \
676 return 0; \
Linus Walleijb02a0662006-04-25 08:05:09 +0000677 val->a.count = n; \
678 val->a.v = malloc(sizeof(val->a.v[0])*n); \
679 if (!val->a.v) return 0; \
680 for (j=0;j<n;j++) \
681 CTVAL(val->a.v[j].member, func); \
682}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000683
Linus Walleij2ad5b722013-11-04 02:07:44 +0100684static inline unsigned int
Linus Walleijb02a0662006-04-25 08:05:09 +0000685ptp_unpack_DPV (
Linus Walleij2ad5b722013-11-04 02:07:44 +0100686 PTPParams *params, unsigned char* data, unsigned int *offset, int total,
Linus Walleijb02a0662006-04-25 08:05:09 +0000687 PTPPropertyValue* value, uint16_t datatype
688) {
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000689 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000690 case PTP_DTC_INT8:
691 CTVAL(value->i8,dtoh8a);
692 break;
693 case PTP_DTC_UINT8:
694 CTVAL(value->u8,dtoh8a);
695 break;
696 case PTP_DTC_INT16:
697 CTVAL(value->i16,dtoh16a);
698 break;
699 case PTP_DTC_UINT16:
700 CTVAL(value->u16,dtoh16a);
701 break;
702 case PTP_DTC_INT32:
703 CTVAL(value->i32,dtoh32a);
704 break;
705 case PTP_DTC_UINT32:
706 CTVAL(value->u32,dtoh32a);
707 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000708 case PTP_DTC_INT64:
709 CTVAL(value->i64,dtoh64a);
710 break;
711 case PTP_DTC_UINT64:
712 CTVAL(value->u64,dtoh64a);
713 break;
714
Linus Walleij037a1252006-12-16 20:36:52 +0000715 case PTP_DTC_UINT128:
716 *offset += 16;
717 /*fprintf(stderr,"unhandled unpack of uint128n");*/
718 break;
719 case PTP_DTC_INT128:
720 *offset += 16;
721 /*fprintf(stderr,"unhandled unpack of int128n");*/
722 break;
723
724
725
Linus Walleijb02a0662006-04-25 08:05:09 +0000726 case PTP_DTC_AINT8:
727 RARR(value,i8,dtoh8a);
728 break;
729 case PTP_DTC_AUINT8:
730 RARR(value,u8,dtoh8a);
731 break;
732 case PTP_DTC_AUINT16:
733 RARR(value,u16,dtoh16a);
734 break;
735 case PTP_DTC_AINT16:
736 RARR(value,i16,dtoh16a);
737 break;
738 case PTP_DTC_AUINT32:
739 RARR(value,u32,dtoh32a);
740 break;
741 case PTP_DTC_AINT32:
742 RARR(value,i32,dtoh32a);
743 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000744 case PTP_DTC_AUINT64:
745 RARR(value,u64,dtoh64a);
746 break;
747 case PTP_DTC_AINT64:
748 RARR(value,i64,dtoh64a);
749 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000750 /* XXX: other int types are unimplemented */
751 /* XXX: other int arrays are unimplemented also */
752 case PTP_DTC_STR: {
753 uint8_t len;
754 /* XXX: max size */
755 value->str = ptp_unpack_string(params,data,*offset,&len);
756 *offset += len*2+1;
757 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000758 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000759 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000760 }
Linus Walleij037a1252006-12-16 20:36:52 +0000761 default:
762 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000763 }
764 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000765}
766
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000767/* Device Property pack/unpack */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000768#define PTP_dpd_DevicePropertyCode 0
769#define PTP_dpd_DataType 2
770#define PTP_dpd_GetSet 4
771#define PTP_dpd_FactoryDefaultValue 5
772
Linus Walleijb02a0662006-04-25 08:05:09 +0000773static inline int
774ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000775{
Linus Walleij9783ce32014-06-02 21:44:29 +0200776 unsigned int offset = 0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000777
Linus Walleijb02a0662006-04-25 08:05:09 +0000778 memset (dpd, 0, sizeof(*dpd));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000779 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
780 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
781 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000782 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000783
784 offset = PTP_dpd_FactoryDefaultValue;
785 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
786 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000787 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
788 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000789 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
790 if (!ret) goto outofmemory;
791
792 /* if offset==0 then Data Type format is not supported by this
793 code or the Data Type is a string (with two empty strings as
794 values). In both cases Form Flag should be set to 0x00 and FORM is
795 not present. */
796
Linus Walleijb02a0662006-04-25 08:05:09 +0000797 if (offset==PTP_dpd_FactoryDefaultValue)
798 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000799
Linus Walleijb02a0662006-04-25 08:05:09 +0000800 dpd->FormFlag=dtoh8a(&data[offset]);
801 offset+=sizeof(uint8_t);
802
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000803 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000804 case PTP_DPFF_Range:
805 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
806 if (!ret) goto outofmemory;
807 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
808 if (!ret) goto outofmemory;
809 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
810 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000811 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000812 case PTP_DPFF_Enumeration: {
813 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000814#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000815 N = dtoh16a(&data[offset]);
816 offset+=sizeof(uint16_t);
817 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
818 if (!dpd->FORM.Enum.SupportedValue)
819 goto outofmemory;
820
821 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
822 for (i=0;i<N;i++) {
823 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
824
825 /* Slightly different handling here. The HP PhotoSmart 120
826 * specifies an enumeration with N in wrong endian
827 * 00 01 instead of 01 00, so we count the enum just until the
828 * the end of the packet.
829 */
830 if (!ret) {
831 if (!i)
832 goto outofmemory;
833 dpd->FORM.Enum.NumberOfValues = i;
834 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000835 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000836 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000837 }
838 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000839#undef N
840 return 1;
841outofmemory:
842 ptp_free_devicepropdesc(dpd);
843 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000844}
845
Linus Walleij9783ce32014-06-02 21:44:29 +0200846/* Device Property pack/unpack */
847#define PTP_dpd_Sony_DevicePropertyCode 0
848#define PTP_dpd_Sony_DataType 2
849#define PTP_dpd_Sony_GetSet 4
850#define PTP_dpd_Sony_Unknown 5
851#define PTP_dpd_Sony_FactoryDefaultValue 6
852
853static inline int
854ptp_unpack_Sony_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen, unsigned int *poffset)
855{
856 unsigned int ret;
857
858 memset (dpd, 0, sizeof(*dpd));
859 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_Sony_DevicePropertyCode]);
860 dpd->DataType=dtoh16a(&data[PTP_dpd_Sony_DataType]);
861
862#if 0
863 dpd->GetSet=dtoh8a(&data[PTP_dpd_Sony_GetSet]);
864#endif
865 dpd->GetSet=1;
866
867 dpd->FormFlag=PTP_DPFF_None;
868
869 *poffset = PTP_dpd_Sony_FactoryDefaultValue;
870 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
871 if (!ret) goto outofmemory;
872 if ((dpd->DataType == PTP_DTC_STR) && (*poffset == dpdlen))
873 return 1;
874 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->CurrentValue, dpd->DataType);
875 if (!ret) goto outofmemory;
876
877 /* if offset==0 then Data Type format is not supported by this
878 code or the Data Type is a string (with two empty strings as
879 values). In both cases Form Flag should be set to 0x00 and FORM is
880 not present. */
881
882 if (*poffset==PTP_dpd_Sony_FactoryDefaultValue)
883 return 1;
884
885 dpd->FormFlag=dtoh8a(&data[*poffset]);
886 *poffset+=sizeof(uint8_t);
887
888 switch (dpd->FormFlag) {
889 case PTP_DPFF_Range:
890 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
891 if (!ret) goto outofmemory;
892 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
893 if (!ret) goto outofmemory;
894 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
895 if (!ret) goto outofmemory;
896 break;
897 case PTP_DPFF_Enumeration: {
898 int i;
899#define N dpd->FORM.Enum.NumberOfValues
900 N = dtoh16a(&data[*poffset]);
901 *poffset+=sizeof(uint16_t);
902 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
903 if (!dpd->FORM.Enum.SupportedValue)
904 goto outofmemory;
905
906 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
907 for (i=0;i<N;i++) {
908 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
909
910 /* Slightly different handling here. The HP PhotoSmart 120
911 * specifies an enumeration with N in wrong endian
912 * 00 01 instead of 01 00, so we count the enum just until the
913 * the end of the packet.
914 */
915 if (!ret) {
916 if (!i)
917 goto outofmemory;
918 dpd->FORM.Enum.NumberOfValues = i;
919 break;
920 }
921 }
922 }
923 }
924#undef N
925 return 1;
926outofmemory:
927 ptp_free_devicepropdesc(dpd);
928 return 0;
929}
930
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100931static inline void
932duplicate_PropertyValue (const PTPPropertyValue *src, PTPPropertyValue *dst, uint16_t type) {
Linus Walleij9783ce32014-06-02 21:44:29 +0200933 if (type == PTP_DTC_STR) {
934 if (src->str)
935 dst->str = strdup(src->str);
936 else
937 dst->str = NULL;
938 return;
939 }
940
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100941 if (type & PTP_DTC_ARRAY_MASK) {
Linus Walleij2ad5b722013-11-04 02:07:44 +0100942 unsigned int i;
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100943
944 dst->a.count = src->a.count;
Linus Walleij9783ce32014-06-02 21:44:29 +0200945 dst->a.v = malloc (sizeof(src->a.v[0])*src->a.count);
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100946 for (i=0;i<src->a.count;i++)
947 duplicate_PropertyValue (&src->a.v[i], &dst->a.v[i], type & ~PTP_DTC_ARRAY_MASK);
948 return;
949 }
950 switch (type & ~PTP_DTC_ARRAY_MASK) {
951 case PTP_DTC_INT8: dst->i8 = src->i8; break;
952 case PTP_DTC_UINT8: dst->u8 = src->u8; break;
953 case PTP_DTC_INT16: dst->i16 = src->i16; break;
954 case PTP_DTC_UINT16: dst->u16 = src->u16; break;
955 case PTP_DTC_INT32: dst->i32 = src->i32; break;
956 case PTP_DTC_UINT32: dst->u32 = src->u32; break;
957 case PTP_DTC_UINT64: dst->u64 = src->u64; break;
958 case PTP_DTC_INT64: dst->i64 = src->i64; break;
959#if 0
960 case PTP_DTC_INT128: dst->i128 = src->i128; break;
961 case PTP_DTC_UINT128: dst->u128 = src->u128; break;
962#endif
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100963 default: break;
964 }
965 return;
966}
967
968static inline void
969duplicate_DevicePropDesc(const PTPDevicePropDesc *src, PTPDevicePropDesc *dst) {
970 int i;
971
972 dst->DevicePropertyCode = src->DevicePropertyCode;
973 dst->DataType = src->DataType;
974 dst->GetSet = src->GetSet;
975
Linus Walleij9783ce32014-06-02 21:44:29 +0200976 duplicate_PropertyValue (&src->FactoryDefaultValue, &dst->FactoryDefaultValue, src->DataType);
977 duplicate_PropertyValue (&src->CurrentValue, &dst->CurrentValue, src->DataType);
Linus Walleijd9ee8cd2013-11-04 01:54:35 +0100978
979 dst->FormFlag = src->FormFlag;
980 switch (src->FormFlag) {
981 case PTP_DPFF_Range:
982 duplicate_PropertyValue (&src->FORM.Range.MinimumValue, &dst->FORM.Range.MinimumValue, src->DataType);
983 duplicate_PropertyValue (&src->FORM.Range.MaximumValue, &dst->FORM.Range.MaximumValue, src->DataType);
984 duplicate_PropertyValue (&src->FORM.Range.StepSize, &dst->FORM.Range.StepSize, src->DataType);
985 break;
986 case PTP_DPFF_Enumeration:
987 dst->FORM.Enum.NumberOfValues = src->FORM.Enum.NumberOfValues;
988 dst->FORM.Enum.SupportedValue = malloc (sizeof(dst->FORM.Enum.SupportedValue[0])*src->FORM.Enum.NumberOfValues);
989 for (i = 0; i<src->FORM.Enum.NumberOfValues ; i++)
990 duplicate_PropertyValue (&src->FORM.Enum.SupportedValue[i], &dst->FORM.Enum.SupportedValue[i], src->DataType);
991 break;
992 case PTP_DPFF_None:
993 break;
994 }
995}
996
Linus Walleijb02a0662006-04-25 08:05:09 +0000997#define PTP_opd_ObjectPropertyCode 0
998#define PTP_opd_DataType 2
999#define PTP_opd_GetSet 4
1000#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001001
Linus Walleijb02a0662006-04-25 08:05:09 +00001002static inline int
1003ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001004{
Linus Walleij2ad5b722013-11-04 02:07:44 +01001005 unsigned int offset=0, ret;
Linus Walleijb02a0662006-04-25 08:05:09 +00001006
1007 memset (opd, 0, sizeof(*opd));
1008 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
1009 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
1010 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
1011
1012 offset = PTP_opd_FactoryDefaultValue;
1013 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
1014 if (!ret) goto outofmemory;
1015
1016 opd->GroupCode=dtoh32a(&data[offset]);
1017 offset+=sizeof(uint32_t);
1018
1019 opd->FormFlag=dtoh8a(&data[offset]);
1020 offset+=sizeof(uint8_t);
1021
1022 switch (opd->FormFlag) {
1023 case PTP_OPFF_Range:
1024 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
1025 if (!ret) goto outofmemory;
1026 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
1027 if (!ret) goto outofmemory;
1028 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
1029 if (!ret) goto outofmemory;
1030 break;
1031 case PTP_OPFF_Enumeration: {
Linus Walleij2ad5b722013-11-04 02:07:44 +01001032 unsigned int i;
Linus Walleijb02a0662006-04-25 08:05:09 +00001033#define N opd->FORM.Enum.NumberOfValues
1034 N = dtoh16a(&data[offset]);
1035 offset+=sizeof(uint16_t);
1036 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
1037 if (!opd->FORM.Enum.SupportedValue)
1038 goto outofmemory;
1039
1040 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
1041 for (i=0;i<N;i++) {
1042 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
1043
1044 /* Slightly different handling here. The HP PhotoSmart 120
1045 * specifies an enumeration with N in wrong endian
1046 * 00 01 instead of 01 00, so we count the enum just until the
1047 * the end of the packet.
1048 */
1049 if (!ret) {
1050 if (!i)
1051 goto outofmemory;
1052 opd->FORM.Enum.NumberOfValues = i;
1053 break;
1054 }
1055 }
1056#undef N
1057 }
1058 }
1059 return 1;
1060outofmemory:
1061 ptp_free_objectpropdesc(opd);
1062 return 0;
1063}
1064
1065
1066static inline uint32_t
1067ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
1068{
1069 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001070 uint32_t size=0;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001071 unsigned int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001072
1073 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +00001074 case PTP_DTC_INT8:
1075 size=sizeof(int8_t);
1076 dpv=malloc(size);
1077 htod8a(dpv,value->i8);
1078 break;
1079 case PTP_DTC_UINT8:
1080 size=sizeof(uint8_t);
1081 dpv=malloc(size);
1082 htod8a(dpv,value->u8);
1083 break;
1084 case PTP_DTC_INT16:
1085 size=sizeof(int16_t);
1086 dpv=malloc(size);
1087 htod16a(dpv,value->i16);
1088 break;
1089 case PTP_DTC_UINT16:
1090 size=sizeof(uint16_t);
1091 dpv=malloc(size);
1092 htod16a(dpv,value->u16);
1093 break;
1094 case PTP_DTC_INT32:
1095 size=sizeof(int32_t);
1096 dpv=malloc(size);
1097 htod32a(dpv,value->i32);
1098 break;
1099 case PTP_DTC_UINT32:
1100 size=sizeof(uint32_t);
1101 dpv=malloc(size);
1102 htod32a(dpv,value->u32);
1103 break;
Linus Walleijabf54752007-07-30 19:51:54 +00001104 case PTP_DTC_INT64:
1105 size=sizeof(int64_t);
1106 dpv=malloc(size);
1107 htod64a(dpv,value->i64);
1108 break;
1109 case PTP_DTC_UINT64:
1110 size=sizeof(uint64_t);
1111 dpv=malloc(size);
1112 htod64a(dpv,value->u64);
1113 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001114 case PTP_DTC_AUINT8:
1115 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
1116 dpv=malloc(size);
1117 htod32a(dpv,value->a.count);
1118 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001119 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +00001120 break;
1121 case PTP_DTC_AINT8:
1122 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
1123 dpv=malloc(size);
1124 htod32a(dpv,value->a.count);
1125 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001126 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +00001127 break;
1128 case PTP_DTC_AUINT16:
1129 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
1130 dpv=malloc(size);
1131 htod32a(dpv,value->a.count);
1132 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001133 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +00001134 break;
1135 case PTP_DTC_AINT16:
1136 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
1137 dpv=malloc(size);
1138 htod32a(dpv,value->a.count);
1139 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001140 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +00001141 break;
1142 case PTP_DTC_AUINT32:
1143 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
1144 dpv=malloc(size);
1145 htod32a(dpv,value->a.count);
1146 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001147 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +00001148 break;
1149 case PTP_DTC_AINT32:
1150 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
1151 dpv=malloc(size);
1152 htod32a(dpv,value->a.count);
1153 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001154 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +00001155 break;
Linus Walleijabf54752007-07-30 19:51:54 +00001156 case PTP_DTC_AUINT64:
1157 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
1158 dpv=malloc(size);
1159 htod32a(dpv,value->a.count);
1160 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001161 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +00001162 break;
1163 case PTP_DTC_AINT64:
1164 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
1165 dpv=malloc(size);
1166 htod32a(dpv,value->a.count);
1167 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001168 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +00001169 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001170 /* XXX: other int types are unimplemented */
1171 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +00001172 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001173 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001174 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001175 }
1176 *dpvptr=dpv;
1177 return size;
1178}
1179
Linus Walleij99310d42006-11-01 08:29:39 +00001180#define MAX_MTP_PROPS 127
1181static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +00001182ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +00001183{
1184 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001185 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +00001186 unsigned char *packedprops[MAX_MTP_PROPS];
1187 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +00001188 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +00001189 uint16_t packedpropsids[MAX_MTP_PROPS];
1190 uint16_t packedpropstypes[MAX_MTP_PROPS];
1191 uint32_t totalsize = 0;
1192 uint32_t bufp = 0;
1193 uint32_t noitems = 0;
1194 uint32_t i;
1195
1196 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +00001197 propitr = props;
1198 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +00001199 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +00001200 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +00001201 totalsize += sizeof(uint32_t); /* Object ID */
1202 /* Metadata type */
1203 packedpropsids[noitems]=propitr->property;
1204 totalsize += sizeof(uint16_t);
1205 /* Data type */
1206 packedpropstypes[noitems]= propitr->datatype;
1207 totalsize += sizeof(uint16_t);
1208 /* Add each property to be sent. */
1209 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
1210 totalsize += packedpropslens[noitems];
1211 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001212 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +00001213 }
1214
1215 /* Allocate memory for the packed property list */
1216 opldata = malloc(totalsize);
1217
1218 htod32a(&opldata[bufp],noitems);
1219 bufp += 4;
1220
1221 /* Copy into a nice packed list */
1222 for (i = 0; i < noitems; i++) {
1223 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +00001224 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +00001225 bufp += sizeof(uint32_t);
1226 htod16a(&opldata[bufp],packedpropsids[i]);
1227 bufp += sizeof(uint16_t);
1228 htod16a(&opldata[bufp],packedpropstypes[i]);
1229 bufp += sizeof(uint16_t);
1230 /* The copy the actual property */
1231 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1232 bufp += packedpropslens[i];
1233 free(packedprops[i]);
1234 }
1235 *opldataptr = opldata;
1236 return totalsize;
1237}
1238
Linus Walleij1e9a0332007-09-12 19:35:56 +00001239static int
1240_compare_func(const void* x, const void *y) {
1241 const MTPProperties *px = x;
1242 const MTPProperties *py = y;
1243
1244 return px->ObjectHandle - py->ObjectHandle;
1245}
1246
Richard Low8d82d2f2006-11-16 20:37:43 +00001247static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001248ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001249{
Linus Walleij277cd532006-11-20 14:57:46 +00001250 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001251 MTPProperties *props = NULL;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001252 unsigned int offset = 0, i;
Linus Walleij277cd532006-11-20 14:57:46 +00001253
1254 if (prop_count == 0) {
Linus Walleij1e9a0332007-09-12 19:35:56 +00001255 *pprops = NULL;
Linus Walleij277cd532006-11-20 14:57:46 +00001256 return 0;
1257 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001258 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001259 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001260 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001261 props = malloc(prop_count * sizeof(MTPProperties));
1262 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001263 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001264 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001265 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001266 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL", i);
1267 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001268 qsort (props, i, sizeof(MTPProperties),_compare_func);
1269 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001270 return i;
1271 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001272 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001273 data += sizeof(uint32_t);
1274 len -= sizeof(uint32_t);
1275
Linus Walleij1e9a0332007-09-12 19:35:56 +00001276 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001277 data += sizeof(uint16_t);
1278 len -= sizeof(uint16_t);
1279
Linus Walleij1e9a0332007-09-12 19:35:56 +00001280 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001281 data += sizeof(uint16_t);
1282 len -= sizeof(uint16_t);
1283
1284 offset = 0;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001285 ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype);
Linus Walleij277cd532006-11-20 14:57:46 +00001286 data += offset;
1287 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001288 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001289 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1290 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001291 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001292}
1293
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001294/*
1295 PTP USB Event container unpack
1296 Copyright (c) 2003 Nikolai Kopanygin
1297*/
1298
1299#define PTP_ec_Length 0
1300#define PTP_ec_Type 4
1301#define PTP_ec_Code 6
1302#define PTP_ec_TransId 8
1303#define PTP_ec_Param1 12
1304#define PTP_ec_Param2 16
1305#define PTP_ec_Param3 20
1306
Linus Walleijb02a0662006-04-25 08:05:09 +00001307static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001308ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001309{
Linus Walleij9783ce32014-06-02 21:44:29 +02001310 unsigned int length;
Linus Walleij7e756532009-05-06 21:25:09 +00001311 int type;
1312
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001313 if (data==NULL)
1314 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001315 memset(ec,0,sizeof(*ec));
Linus Walleij9783ce32014-06-02 21:44:29 +02001316
Linus Walleij7e756532009-05-06 21:25:09 +00001317 length=dtoh32a(&data[PTP_ec_Length]);
Linus Walleij9783ce32014-06-02 21:44:29 +02001318 if (length > len) {
1319 ptp_debug (params, "length %d in container, but data only %d bytes?!", length, len);
1320 return;
1321 }
Linus Walleij7e756532009-05-06 21:25:09 +00001322 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001323
Linus Walleij7e756532009-05-06 21:25:09 +00001324 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1325 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1326
1327 if (type!=PTP_USB_CONTAINER_EVENT) {
1328 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1329 return;
1330 }
1331 if (length>=(PTP_ec_Param1+4)) {
1332 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1333 ec->Nparam=1;
1334 }
1335 if (length>=(PTP_ec_Param2+4)) {
1336 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1337 ec->Nparam=2;
1338 }
1339 if (length>=(PTP_ec_Param3+4)) {
1340 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1341 ec->Nparam=3;
1342 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001343}
1344
1345/*
1346 PTP Canon Folder Entry unpack
1347 Copyright (c) 2003 Nikolai Kopanygin
1348*/
1349#define PTP_cfe_ObjectHandle 0
1350#define PTP_cfe_ObjectFormatCode 4
1351#define PTP_cfe_Flags 6
1352#define PTP_cfe_ObjectSize 7
1353#define PTP_cfe_Time 11
1354#define PTP_cfe_Filename 15
1355
Linus Walleijb02a0662006-04-25 08:05:09 +00001356static inline void
1357ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001358{
1359 int i;
1360 if (data==NULL)
1361 return;
1362 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1363 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1364 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001365 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001366 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1367 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001368 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1369}
1370
Linus Walleij96aa0e32012-03-25 12:25:25 +02001371/*
1372 PTP Canon EOS Folder Entry unpack
13730: 00 00 08 a0 objectid
13744: 01 00 02 00 storageid
13758: 01 30 00 00 ofc
137612: 01 00
137714: 00 00
137816: 11 00 00 00
137920: 00 00 00 00
138024: 00 00 00 80
138128: 00 00 08 a0
138232: 4d 49 53 43-00 00 00 00 00 00 00 00 name
138300 00 00 00
138484 bc 74 46 objectime
1385
1386
1387(normal PTP GetObjectInfo)
1388ObjectInfo for 'IMG_0199.JPG':
1389 Object ID: 0x92740c72
1390 StorageID: 0x00020001
1391 ObjectFormat: 0x3801
1392 ProtectionStatus: 0x0000
1393 ObjectCompressedSize: 2217241
1394 ThumbFormat: 0x3808
1395 ThumbCompressedSize: 5122
1396 ThumbPixWidth: 160
1397 ThumbPixHeight: 120
1398 ImagePixWidth: 4000
1399 ImagePixHeight: 3000
1400 ImageBitDepth: 24
1401 ParentObject: 0x92740000
1402 AssociationType: 0x0000
1403 AssociationDesc: 0x00000000
1404 SequenceNumber: 0x00000000
1405 ModificationDate: 0x4d985ff0
1406 CaptureDate: 0x4d985ff0
1407
14080010 38 00 00 00 Size of this entry
14090014 72 0c 74 92 OID
14100018 01 00 02 00 StorageID
1411001c 01 38 00 00 OFC
14120020 00 00 00 00 00 00 00 00 ?
14130028 19 d5 21 00 Size
1414002c 00 00 74 92 ?
14150030 70 0c 74 92 OID
14160034 49 4d 47 5f-30 31 39 39 2e 4a 50 47 IMG_0199.JPG
14170040 00 00 00 00
14180044 10 7c 98 4d Time
1419
1420
1421*/
1422#define PTP_cefe_ObjectHandle 0
1423#define PTP_cefe_StorageID 4
1424#define PTP_cefe_ObjectFormatCode 8
1425#define PTP_cefe_Flags 12
1426#define PTP_cefe_ObjectSize 20
1427#define PTP_cefe_Filename 32
1428#define PTP_cefe_Time 48
1429
1430static inline void
1431ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
1432{
1433 int i;
1434
1435 fe->ObjectHandle=dtoh32a(&data[PTP_cefe_ObjectHandle]);
1436 fe->ObjectFormatCode=dtoh16a(&data[PTP_cefe_ObjectFormatCode]);
1437 fe->Flags=dtoh8a(&data[PTP_cefe_Flags]);
1438 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cefe_ObjectSize]);
1439 fe->Time=(time_t)dtoh32a(&data[PTP_cefe_Time]);
1440 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
1441 fe->Filename[i]=(char)data[PTP_cefe_Filename+i];
1442}
1443
1444
Linus Walleij1a0c3012009-07-23 23:06:58 +00001445static inline uint16_t
1446ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1447{
1448 /*
Marcus Meissner0546a762012-04-10 18:49:10 +02001449 EOS ImageFormat entries (of at least the 5DM2 and the 400D) look like this:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001450 uint32: number of entries / generated files (1 or 2)
1451 uint32: size of this entry in bytes (most likely allways 0x10)
1452 uint32: image type (1 == JPG, 6 == RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001453 uint32: image size (0 == Large, 1 == Medium, 2 == Small, 0xe == S1, 0xf == S2, 0x10 == S3)
Linus Walleij1a0c3012009-07-23 23:06:58 +00001454 uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001455 If the number of entries is 2 the last 4 uint32 repeat.
Linus Walleij1a0c3012009-07-23 23:06:58 +00001456
1457 example:
1458 0: 0x 1
1459 1: 0x 10
1460 2: 0x 6
1461 3: 0x 1
1462 4: 0x 4
1463
Marcus Meissner0546a762012-04-10 18:49:10 +02001464 The idea is to simply 'condense' these values to just one uint16 to be able to conveniently
Linus Walleij1a0c3012009-07-23 23:06:58 +00001465 use the available enumeration facilities (look-up table). The image size and compression
1466 values fully describe the image format. Hence we generate a uint16 with the four nibles set
1467 as follows: entry 1 size | entry 1 compression | entry 2 size | entry 2 compression.
1468 The above example would result in the value 0x1400.
Marcus Meissner0546a762012-04-10 18:49:10 +02001469
1470 The EOS 5D Mark III (and possibly other high-end EOS as well) added the extra fancy S1, S2
1471 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 +00001472 */
1473
1474 const unsigned char* d = *data;
1475 uint32_t n = dtoh32a( d );
1476 uint32_t l, s1, c1, s2 = 0, c2 = 0;
1477
1478 if (n != 1 && n !=2) {
1479 ptp_debug (params, "parsing EOS ImageFormat property failed (n != 1 && n != 2: %d)", n);
1480 return 0;
1481 }
1482
1483 l = dtoh32a( d+=4 );
1484 if (l != 0x10) {
1485 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1486 return 0;
1487 }
1488
1489 d+=4; /* skip type */
1490 s1 = dtoh32a( d+=4 );
1491 c1 = dtoh32a( d+=4 );
1492
1493 if (n == 2) {
1494 l = dtoh32a( d+=4 );
1495 if (l != 0x10) {
1496 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1497 return 0;
1498 }
1499 d+=4; /* skip type */
1500 s2 = dtoh32a( d+=4 );
1501 c2 = dtoh32a( d+=4 );
1502 }
1503
1504 *data = (unsigned char*) d+4;
1505
Marcus Meissner0546a762012-04-10 18:49:10 +02001506 /* deal with S1/S2/S3 JPEG sizes, see above. */
1507 if( s1 >= 0xe )
1508 s1--;
1509 if( s2 >= 0xe )
1510 s2--;
1511
Linus Walleij1a0c3012009-07-23 23:06:58 +00001512 return ((s1 & 0xF) << 12) | ((c1 & 0xF) << 8) | ((s2 & 0xF) << 4) | ((c2 & 0xF) << 0);
1513}
1514
1515static inline uint32_t
1516ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value)
1517{
1518 uint32_t n = (value & 0xFF) ? 2 : 1;
1519 uint32_t s = 4 + 0x10 * n;
1520
1521 if( !data )
1522 return s;
1523
Marcus Meissner0546a762012-04-10 18:49:10 +02001524#define PACK_5DM3_SMALL_JPEG_SIZE( X ) (X) >= 0xd ? (X)+1 : (X)
1525
Linus Walleij1a0c3012009-07-23 23:06:58 +00001526 htod32a(data+=0, n);
1527 htod32a(data+=4, 0x10);
1528 htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001529 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 12) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001530 htod32a(data+=4, (value >> 8) & 0xF);
1531
1532 if (n==2) {
1533 htod32a(data+=4, 0x10);
1534 htod32a(data+=4, ((value >> 0) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001535 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 4) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001536 htod32a(data+=4, (value >> 0) & 0xF);
1537 }
1538
Marcus Meissner0546a762012-04-10 18:49:10 +02001539#undef PACK_5DM3_SMALL_JPEG_SIZE
1540
1541 return s;
1542}
1543
1544static inline char*
1545ptp_unpack_EOS_CustomFuncEx (PTPParams* params, unsigned char** data )
1546{
1547 uint32_t s = dtoh32a( *data );
1548 uint32_t n = s/4, i;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001549 char* str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/
Marcus Meissner0546a762012-04-10 18:49:10 +02001550 if (!str)
1551 return str;
1552 char* p = str;
1553
1554 for (i=0; i < n; ++i)
1555 p += sprintf(p, "%x,", dtoh32a( *data + 4*i ));
1556
1557 return str;
1558}
1559
1560static inline uint32_t
1561ptp_pack_EOS_CustomFuncEx (PTPParams* params, unsigned char* data, char* str)
1562{
1563 uint32_t s = strtoul(str, NULL, 16);
1564 uint32_t n = s/4, i, v;
1565
1566 if (!data)
1567 return s;
1568
1569 for (i=0; i<n; i++)
1570 {
1571 v = strtoul(str, &str, 16);
Linus Walleija381e8a2013-03-05 21:00:06 +01001572 str++; /* skip the ',' delimiter */
Marcus Meissner0546a762012-04-10 18:49:10 +02001573 htod32a(data + i*4, v);
1574 }
1575
Linus Walleij1a0c3012009-07-23 23:06:58 +00001576 return s;
1577}
1578
Linus Walleijb02a0662006-04-25 08:05:09 +00001579/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001580 PTP EOS Changes Entry unpack
1581*/
1582#define PTP_ece_Size 0
1583#define PTP_ece_Type 4
1584
1585#define PTP_ece_Prop_Subtype 8 /* only for properties */
1586#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1587#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1588#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1589#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1590
Linus Walleijd4637502009-06-14 23:03:33 +00001591/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
1592#define PTP_ece_OI_ObjectID 8
1593#define PTP_ece_OI_OFC 0x0c
1594#define PTP_ece_OI_Size 0x14
1595#define PTP_ece_OI_Name 0x1c
1596
1597/* for PTP_EC_CANON_EOS_ObjectAddedEx */
1598#define PTP_ece_OA_ObjectID 8
1599#define PTP_ece_OA_StorageID 0x0c
1600#define PTP_ece_OA_OFC 0x10
1601#define PTP_ece_OA_Size 0x1c
1602#define PTP_ece_OA_Parent 0x20
1603#define PTP_ece_OA_Name 0x28
Linus Walleijf0bf4372007-07-01 21:47:38 +00001604
1605static inline int
Linus Walleij9783ce32014-06-02 21:44:29 +02001606ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **pce)
Linus Walleijf0bf4372007-07-01 21:47:38 +00001607{
1608 int i = 0, entries = 0;
1609 unsigned char *curdata = data;
Linus Walleij9783ce32014-06-02 21:44:29 +02001610 PTPCanon_changes_entry *ce;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001611
1612 if (data==NULL)
1613 return 0;
1614 while (curdata - data < datasize) {
1615 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1616 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1617
Linus Walleijf0bf4372007-07-01 21:47:38 +00001618 if ((size == 8) && (type == 0))
1619 break;
Linus Walleij9783ce32014-06-02 21:44:29 +02001620 if (type == PTP_EC_CANON_EOS_OLCInfoChanged) {
1621 unsigned int j;
1622
1623 for (j=0;j<31;j++)
1624 if (dtoh32a(curdata+12) & (1<<j))
1625 entries++;
1626 }
1627 curdata += size;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001628 entries++;
1629 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001630 ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
1631 if (!ce) return 0;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001632
1633 curdata = data;
1634 while (curdata - data < datasize) {
1635 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1636 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1637
Linus Walleij9783ce32014-06-02 21:44:29 +02001638 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1639 ce[i].u.info = NULL;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001640 switch (type) {
Linus Walleijd4637502009-06-14 23:03:33 +00001641 case PTP_EC_CANON_EOS_ObjectAddedEx:
Linus Walleij9783ce32014-06-02 21:44:29 +02001642 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1643 ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
1644 ce[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
1645 ce[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
1646 ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
1647 ce[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
1648 ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
1649 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);
Linus Walleijd4637502009-06-14 23:03:33 +00001650 break;
1651 case PTP_EC_CANON_EOS_RequestObjectTransfer:
Linus Walleij9783ce32014-06-02 21:44:29 +02001652 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
1653 ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
1654 ce[i].u.object.oi.StorageID = 0; /* use as marker */
1655 ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
1656 ce[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
1657 ce[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
1658 ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001659
Linus Walleij9783ce32014-06-02 21:44:29 +02001660 ptp_debug (params, "event %d: request object transfer oid %08lx, ofc %04x, size %d, filename %p", 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 +00001661 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001662 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001663 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1664 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1665 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
Linus Walleije206af62011-04-19 01:51:39 +02001666 unsigned char *xdata = &curdata[PTP_ece_Prop_Desc_Data];
Linus Walleij2ad5b722013-11-04 02:07:44 +01001667 unsigned int j;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001668 PTPDevicePropDesc *dpd;
1669
Linus Walleij7e756532009-05-06 21:25:09 +00001670 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 +00001671 for (j=0;j<params->nrofcanon_props;j++)
1672 if (params->canon_props[j].proptype == proptype)
1673 break;
1674 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001675 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001676 break;
1677 }
1678 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001679 /* 1 - uint16 ?
1680 * 3 - uint16
1681 * 7 - string?
1682 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001683 if (propxtype != 3) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001684 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled.", i, propxtype, proptype);
1685 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001686 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001687 break;
1688 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001689 if (! propxcnt)
1690 break;
Linus Walleij9783ce32014-06-02 21:44:29 +02001691 if (propxcnt >= 2<<16) /* buggy or exploit */
1692 break;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001693
1694 ptp_debug (params, "event %d: propxtype is %x, prop is 0x%04x, data type is 0x%04x, propxcnt is %d.",
1695 i, propxtype, proptype, dpd->DataType, propxcnt);
1696 dpd->FormFlag = PTP_DPFF_Enumeration;
1697 dpd->FORM.Enum.NumberOfValues = propxcnt;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001698 if (dpd->FORM.Enum.SupportedValue) free (dpd->FORM.Enum.SupportedValue);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001699 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
1700
1701 switch (proptype) {
1702 case PTP_DPC_CANON_EOS_ImageFormat:
1703 case PTP_DPC_CANON_EOS_ImageFormatCF:
1704 case PTP_DPC_CANON_EOS_ImageFormatSD:
1705 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1706 /* special handling of ImageFormat properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001707 for (j=0;j<propxcnt;j++) {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001708 dpd->FORM.Enum.SupportedValue[j].u16 =
Linus Walleij9783ce32014-06-02 21:44:29 +02001709 ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001710 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, dpd->FORM.Enum.SupportedValue[j].u16);
1711 }
1712 break;
1713 default:
1714 /* 'normal' enumerated types */
1715 switch (dpd->DataType) {
1716#define XX( TYPE, CONV )\
1717 for (j=0;j<propxcnt;j++) { \
Linus Walleije206af62011-04-19 01:51:39 +02001718 dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \
1719 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \
1720 xdata += 4; /* might only be for propxtype 3 */ \
Linus Walleij1a0c3012009-07-23 23:06:58 +00001721 } \
1722 break;
1723
1724 case PTP_DTC_INT16: XX( i16, dtoh16a );
1725 case PTP_DTC_UINT32: XX( u32, dtoh32a );
1726 case PTP_DTC_UINT16: XX( u16, dtoh16a );
1727 case PTP_DTC_UINT8: XX( u8, dtoh8a );
1728#undef XX
1729 default:
Linus Walleije206af62011-04-19 01:51:39 +02001730 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata));
1731 for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */
1732 ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001733 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001734 }
1735 }
1736 break;
1737 }
Linus Walleij7e756532009-05-06 21:25:09 +00001738 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001739 if (size >= 0xc) { /* property info */
Linus Walleij2ad5b722013-11-04 02:07:44 +01001740 unsigned int j;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001741 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
Linus Walleije206af62011-04-19 01:51:39 +02001742 unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00001743 PTPDevicePropDesc *dpd;
1744
Linus Walleij1a0c3012009-07-23 23:06:58 +00001745 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 +00001746 for (j=0;j<params->nrofcanon_props;j++)
1747 if (params->canon_props[j].proptype == proptype)
1748 break;
1749 if (j<params->nrofcanon_props) {
1750 if ( (params->canon_props[j].size != size) ||
Linus Walleije206af62011-04-19 01:51:39 +02001751 (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00001752 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001753 memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001754 }
1755 } else {
1756 if (j)
1757 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1758 else
1759 params->canon_props = malloc(sizeof(params->canon_props[0]));
1760 params->canon_props[j].type = type;
1761 params->canon_props[j].proptype = proptype;
1762 params->canon_props[j].size = size;
1763 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02001764 memcpy(params->canon_props[j].data, xdata, size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001765 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1766 params->canon_props[j].dpd.GetSet = 1;
1767 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1768 params->nrofcanon_props = j+1;
1769 }
1770 dpd = &params->canon_props[j].dpd;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001771
Linus Walleij9783ce32014-06-02 21:44:29 +02001772 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
1773 ce[i].u.propid = proptype;
Linus Walleijd7072c32010-12-07 20:43:00 +00001774
Linus Walleij1a0c3012009-07-23 23:06:58 +00001775 /* fix GetSet value */
1776 switch (proptype) {
1777#define XX(x) case PTP_DPC_CANON_##x:
1778 XX(EOS_FocusMode)
1779 XX(EOS_BatteryPower)
1780 XX(EOS_BatterySelect)
1781 XX(EOS_ModelID)
1782 XX(EOS_PTPExtensionVersion)
1783 XX(EOS_DPOFVersion)
1784 XX(EOS_AvailableShots)
1785 XX(EOS_CurrentStorage)
1786 XX(EOS_CurrentFolder)
1787 XX(EOS_MyMenu)
1788 XX(EOS_MyMenuList)
1789 XX(EOS_HDDirectoryStructure)
1790 XX(EOS_BatteryInfo)
1791 XX(EOS_AdapterInfo)
1792 XX(EOS_LensStatus)
1793 XX(EOS_CardExtension)
1794 XX(EOS_TempStatus)
1795 XX(EOS_ShutterCounter)
1796 XX(EOS_SerialNumber)
1797 XX(EOS_DepthOfFieldPreview)
1798 XX(EOS_EVFRecordStatus)
1799 XX(EOS_LvAfSystem)
1800 XX(EOS_FocusInfoEx)
1801 XX(EOS_DepthOfField)
1802 XX(EOS_Brightness)
1803 XX(EOS_EFComp)
1804 XX(EOS_LensName)
1805 XX(EOS_LensID)
1806#undef XX
1807 dpd->GetSet = PTP_DPGS_Get;
1808 break;
1809 }
1810
1811 /* set DataType */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001812 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00001813 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleij9783ce32014-06-02 21:44:29 +02001814 case PTP_DPC_CANON_EOS_UTCTime:
1815 case PTP_DPC_CANON_EOS_Summertime: /* basical the DST flag */
Linus Walleijd4637502009-06-14 23:03:33 +00001816 case PTP_DPC_CANON_EOS_AvailableShots:
Linus Walleijd4637502009-06-14 23:03:33 +00001817 case PTP_DPC_CANON_EOS_CaptureDestination:
1818 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
1819 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
Linus Walleijd4637502009-06-14 23:03:33 +00001820 case PTP_DPC_CANON_EOS_CurrentStorage:
1821 case PTP_DPC_CANON_EOS_CurrentFolder:
1822 case PTP_DPC_CANON_EOS_ShutterCounter:
1823 case PTP_DPC_CANON_EOS_ModelID:
1824 case PTP_DPC_CANON_EOS_LensID:
1825 case PTP_DPC_CANON_EOS_StroboFiring:
Linus Walleijac052c12007-07-18 18:37:10 +00001826 dpd->DataType = PTP_DTC_UINT32;
1827 break;
Linus Walleij0d762cc2010-04-04 23:34:27 +00001828 /* enumeration for AEM is never provided, but is available to set */
1829 case PTP_DPC_CANON_EOS_AutoExposureMode:
1830 dpd->DataType = PTP_DTC_UINT16;
1831 dpd->FormFlag = PTP_DPFF_Enumeration;
1832 dpd->FORM.Enum.NumberOfValues = 0;
1833 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001834 case PTP_DPC_CANON_EOS_Aperture:
1835 case PTP_DPC_CANON_EOS_ShutterSpeed:
1836 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00001837 case PTP_DPC_CANON_EOS_FocusMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001838 case PTP_DPC_CANON_EOS_ColorSpace:
1839 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleije29ca682010-01-30 08:15:25 +00001840 case PTP_DPC_CANON_EOS_BatterySelect:
Linus Walleijd4637502009-06-14 23:03:33 +00001841 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001842 case PTP_DPC_CANON_EOS_DriveMode:
1843 case PTP_DPC_CANON_EOS_AEB:
Linus Walleije29ca682010-01-30 08:15:25 +00001844 case PTP_DPC_CANON_EOS_BracketMode:
1845 case PTP_DPC_CANON_EOS_QuickReviewTime:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001846 case PTP_DPC_CANON_EOS_EVFMode:
1847 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleija381e8a2013-03-05 21:00:06 +01001848 case PTP_DPC_CANON_EOS_AutoPowerOff:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001849 dpd->DataType = PTP_DTC_UINT16;
1850 break;
1851 case PTP_DPC_CANON_EOS_PictureStyle:
1852 case PTP_DPC_CANON_EOS_WhiteBalance:
1853 case PTP_DPC_CANON_EOS_MeteringMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001854 case PTP_DPC_CANON_EOS_ExpCompensation: /* actually int8 if you calculate */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001855 dpd->DataType = PTP_DTC_UINT8;
1856 break;
1857 case PTP_DPC_CANON_EOS_Owner:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001858 case PTP_DPC_CANON_EOS_Artist:
1859 case PTP_DPC_CANON_EOS_Copyright:
1860 case PTP_DPC_CANON_EOS_SerialNumber:
1861 case PTP_DPC_CANON_EOS_LensName:
Linus Walleijf0bf4372007-07-01 21:47:38 +00001862 dpd->DataType = PTP_DTC_STR;
1863 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001864 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
1865 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
1866 dpd->DataType = PTP_DTC_INT16;
1867 break;
1868 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
Linus Walleij7e756532009-05-06 21:25:09 +00001869 case PTP_DPC_CANON_EOS_DPOFVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001870 dpd->DataType = PTP_DTC_UINT16;
1871 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
1872 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001873 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001874 break;
Linus Walleij7e756532009-05-06 21:25:09 +00001875 case PTP_DPC_CANON_EOS_CustomFunc1:
1876 case PTP_DPC_CANON_EOS_CustomFunc2:
1877 case PTP_DPC_CANON_EOS_CustomFunc3:
1878 case PTP_DPC_CANON_EOS_CustomFunc4:
1879 case PTP_DPC_CANON_EOS_CustomFunc5:
1880 case PTP_DPC_CANON_EOS_CustomFunc6:
1881 case PTP_DPC_CANON_EOS_CustomFunc7:
1882 case PTP_DPC_CANON_EOS_CustomFunc8:
1883 case PTP_DPC_CANON_EOS_CustomFunc9:
1884 case PTP_DPC_CANON_EOS_CustomFunc10:
1885 case PTP_DPC_CANON_EOS_CustomFunc11:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001886 dpd->DataType = PTP_DTC_UINT8;
1887 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 +00001888 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001889 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001890 /* 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 +02001891 xdata += 4;
Linus Walleij7e756532009-05-06 21:25:09 +00001892 break;
1893 /* yet unknown 32bit props */
1894 case PTP_DPC_CANON_EOS_ColorTemperature:
Linus Walleij7e756532009-05-06 21:25:09 +00001895 case PTP_DPC_CANON_EOS_WftStatus:
1896 case PTP_DPC_CANON_EOS_LensStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001897 case PTP_DPC_CANON_EOS_CardExtension:
1898 case PTP_DPC_CANON_EOS_TempStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00001899 case PTP_DPC_CANON_EOS_PhotoStudioMode:
Linus Walleij7e756532009-05-06 21:25:09 +00001900 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
1901 case PTP_DPC_CANON_EOS_EVFSharpness:
1902 case PTP_DPC_CANON_EOS_EVFWBMode:
1903 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
1904 case PTP_DPC_CANON_EOS_EVFColorTemp:
Linus Walleijd4637502009-06-14 23:03:33 +00001905 case PTP_DPC_CANON_EOS_EVFRecordStatus:
1906 case PTP_DPC_CANON_EOS_ExposureSimMode:
1907 case PTP_DPC_CANON_EOS_LvAfSystem:
1908 case PTP_DPC_CANON_EOS_MovSize:
1909 case PTP_DPC_CANON_EOS_DepthOfField:
1910 case PTP_DPC_CANON_EOS_LvViewTypeSelect:
Linus Walleij2ad5b722013-11-04 02:07:44 +01001911 case PTP_DPC_CANON_EOS_AloMode:
Linus Walleij9783ce32014-06-02 21:44:29 +02001912 case PTP_DPC_CANON_EOS_Brightness:
Linus Walleij0d762cc2010-04-04 23:34:27 +00001913 dpd->DataType = PTP_DTC_UINT32;
Linus Walleij7e756532009-05-06 21:25:09 +00001914 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 +00001915 if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
1916 ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
1917 for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
Linus Walleije206af62011-04-19 01:51:39 +02001918 ptp_debug (params, " %d: 0x%8x", j, ((uint32_t*)xdata)[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00001919 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001920 /* ImageFormat properties have to be ignored here, see special handling below */
1921 case PTP_DPC_CANON_EOS_ImageFormat:
1922 case PTP_DPC_CANON_EOS_ImageFormatCF:
1923 case PTP_DPC_CANON_EOS_ImageFormatSD:
1924 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
Marcus Meissner0546a762012-04-10 18:49:10 +02001925 case PTP_DPC_CANON_EOS_CustomFuncEx:
Linus Walleijd7072c32010-12-07 20:43:00 +00001926 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001927 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001928 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
1929 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001930 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001931 break;
1932 }
1933 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00001934 case PTP_DTC_UINT32:
Linus Walleije206af62011-04-19 01:51:39 +02001935 dpd->FactoryDefaultValue.u32 = dtoh32a(xdata);
1936 dpd->CurrentValue.u32 = dtoh32a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001937 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00001938 break;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001939 case PTP_DTC_INT16:
1940 dpd->FactoryDefaultValue.i16 = dtoh16a(xdata);
1941 dpd->CurrentValue.i16 = dtoh16a(xdata);
1942 ptp_debug (params,"event %d: currentvalue of %x is %d", i, proptype, dpd->CurrentValue.i16);
1943 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001944 case PTP_DTC_UINT16:
Linus Walleije206af62011-04-19 01:51:39 +02001945 dpd->FactoryDefaultValue.u16 = dtoh16a(xdata);
1946 dpd->CurrentValue.u16 = dtoh16a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001947 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001948 break;
1949 case PTP_DTC_UINT8:
Linus Walleije206af62011-04-19 01:51:39 +02001950 dpd->FactoryDefaultValue.u8 = dtoh8a(xdata);
1951 dpd->CurrentValue.u8 = dtoh8a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001952 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001953 break;
1954 case PTP_DTC_STR: {
Linus Walleij1a0c3012009-07-23 23:06:58 +00001955#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001956 uint8_t len = 0;
1957 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
1958 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij1a0c3012009-07-23 23:06:58 +00001959#else
Linus Walleij0d762cc2010-04-04 23:34:27 +00001960 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001961 dpd->FactoryDefaultValue.str = strdup( (char*)xdata );
Linus Walleij0d762cc2010-04-04 23:34:27 +00001962
1963 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02001964 dpd->CurrentValue.str = strdup( (char*)xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00001965#endif
Linus Walleij7e756532009-05-06 21:25:09 +00001966 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001967 break;
1968 }
1969 default:
1970 /* debug is printed in switch above this one */
1971 break;
1972 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001973
Marcus Meissner0546a762012-04-10 18:49:10 +02001974 /* ImageFormat and customFuncEx special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
Linus Walleijd7072c32010-12-07 20:43:00 +00001975 switch (proptype) {
1976 case PTP_DPC_CANON_EOS_ImageFormat:
1977 case PTP_DPC_CANON_EOS_ImageFormatCF:
1978 case PTP_DPC_CANON_EOS_ImageFormatSD:
1979 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
1980 dpd->DataType = PTP_DTC_UINT16;
Linus Walleije206af62011-04-19 01:51:39 +02001981 dpd->FactoryDefaultValue.u16 = ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleijd7072c32010-12-07 20:43:00 +00001982 dpd->CurrentValue.u16 = dpd->FactoryDefaultValue.u16;
1983 ptp_debug (params,"event %d: decoded imageformat, currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
1984 break;
Marcus Meissner0546a762012-04-10 18:49:10 +02001985 case PTP_DPC_CANON_EOS_CustomFuncEx:
1986 dpd->DataType = PTP_DTC_STR;
1987 if (dpd->FactoryDefaultValue.str) free (dpd->FactoryDefaultValue.str);
1988 if (dpd->CurrentValue.str) free (dpd->CurrentValue.str);
1989 dpd->FactoryDefaultValue.str = ptp_unpack_EOS_CustomFuncEx( params, &data );
1990 dpd->CurrentValue.str = strdup( (char*)dpd->FactoryDefaultValue.str );
1991 ptp_debug (params,"event %d: decoded custom function, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
1992 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00001993 }
1994
Linus Walleijf0bf4372007-07-01 21:47:38 +00001995 break;
1996 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001997 /* one more information record handed to us */
1998 case PTP_EC_CANON_EOS_OLCInfoChanged: {
1999 uint32_t len, curoff;
2000 uint16_t mask,proptype;
2001 unsigned int j;
2002 PTPDevicePropDesc *dpd;
2003
2004 /* unclear what OLC stands for */
2005 ptp_debug (params, "event %d: EOS event OLCInfoChanged (size %d)", i, size);
2006 if (size >= 0x8) { /* event info */
2007 unsigned int j;
2008 for (j=8;j<size;j++)
2009 ptp_debug (params, " %d: %02x", j-8, curdata[j]);
2010 }
2011 len = dtoh32a(curdata+8);
2012 if (len != size-8) {
2013 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2014 ptp_debug (params, "event %d: size %d, len %d", i, size, len);
2015 break;
2016 }
2017 mask = dtoh16a(curdata+8+4);
2018 curoff = 8+4+4;
2019 if (mask & CANON_EOS_OLC_BUTTON) {
2020 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2021 ce[i].u.info = malloc(strlen("Button 1234567"));
2022 sprintf(ce[i].u.info, "Button %d", dtoh16a(curdata+curoff));
2023 i++;
2024 curoff += 2;
2025 }
2026
2027 if (mask & CANON_EOS_OLC_SHUTTERSPEED) {
2028 /* 6 bytes: 01 01 98 10 00 60 */
2029 /* this seesm to be the shutter speed record */
2030 proptype = PTP_DPC_CANON_EOS_ShutterSpeed;
2031 for (j=0;j<params->nrofcanon_props;j++)
2032 if (params->canon_props[j].proptype == proptype)
2033 break;
2034 if (j == params->nrofcanon_props)
2035 ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
2036
2037 dpd = &params->canon_props[j].dpd;
2038 dpd->CurrentValue.u16 = curdata[curoff+5]; /* just use last byte */
2039
2040 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2041 ce[i].u.propid = proptype;
2042 curoff += 6;
2043 i++;
2044 }
2045 if (mask & CANON_EOS_OLC_APERTURE) {
2046 /* 5 bytes: 01 01 5b 30 30 */
2047 /* this seesm to be the aperture record */
2048 proptype = PTP_DPC_CANON_EOS_Aperture;
2049 for (j=0;j<params->nrofcanon_props;j++)
2050 if (params->canon_props[j].proptype == proptype)
2051 break;
2052 if (j == params->nrofcanon_props)
2053 ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
2054
2055 dpd = &params->canon_props[j].dpd;
2056 dpd->CurrentValue.u16 = curdata[curoff+4]; /* just use last byte */
2057
2058 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2059 ce[i].u.propid = proptype;
2060 curoff += 5;
2061 i++;
2062 }
2063 if (mask & CANON_EOS_OLC_ISO) {
2064 /* 5 bytes: 01 01 00 78 */
2065 /* this seesm to be the aperture record */
2066 proptype = PTP_DPC_CANON_EOS_ISOSpeed;
2067 for (j=0;j<params->nrofcanon_props;j++)
2068 if (params->canon_props[j].proptype == proptype)
2069 break;
2070 if (j == params->nrofcanon_props)
2071 ptp_debug (params, "event %d: shutterspeed not found yet, handle this", i);
2072
2073 dpd = &params->canon_props[j].dpd;
2074 dpd->CurrentValue.u16 = curdata[curoff+3]; /* just use last byte */
2075
2076 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2077 ce[i].u.propid = proptype;
2078 curoff += 4;
2079 i++;
2080 }
2081 if (mask & 0x0010) {
2082 /* mask 0x0010: 4 bytes, 04 00 00 00 observed */
2083 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2084 ce[i].u.info = malloc(strlen("OLCInfo event 0x0010 content 01234567")+1);
2085 sprintf(ce[i].u.info,"OLCInfo event 0x0010 content %02x%02x%02x%02x",
2086 curdata[curoff],
2087 curdata[curoff+1],
2088 curdata[curoff+2],
2089 curdata[curoff+3]
2090 );
2091 curoff += 4;
2092 i++;
2093 }
2094 if (mask & 0x0020) {
2095 /* mask 0x0020: 6 bytes, 00 00 00 00 00 00 observed */
2096 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2097 ce[i].u.info = malloc(strlen("OLCInfo event 0x0020 content 0123456789ab")+1);
2098 sprintf(ce[i].u.info,"OLCInfo event 0x0020 content %02x%02x%02x%02x%02x%02x",
2099 curdata[curoff],
2100 curdata[curoff+1],
2101 curdata[curoff+2],
2102 curdata[curoff+3],
2103 curdata[curoff+4],
2104 curdata[curoff+5]
2105 );
2106 curoff += 6;
2107 i++;
2108 }
2109 if (mask & 0x0040) {
2110 /* mask 0x0040: 7 bytes, 01 01 00 00 00 00 00 observed */
2111 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2112 ce[i].u.info = malloc(strlen("OLCInfo event 0x0040 content 0123456789abcd")+1);
2113 sprintf(ce[i].u.info,"OLCInfo event 0x0040 content %02x%02x%02x%02x%02x%02x%02x",
2114 curdata[curoff],
2115 curdata[curoff+1],
2116 curdata[curoff+2],
2117 curdata[curoff+3],
2118 curdata[curoff+4],
2119 curdata[curoff+5],
2120 curdata[curoff+6]
2121 );
2122 curoff += 7;
2123 i++;
2124 }
2125 if (mask & 0x0080) {
2126 /* mask 0x0080: 4 bytes, 00 00 00 00 observed */
2127 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2128 ce[i].u.info = malloc(strlen("OLCInfo event 0x0080 content 01234567")+1);
2129 sprintf(ce[i].u.info,"OLCInfo event 0x0080 content %02x%02x%02x%02x",
2130 curdata[curoff],
2131 curdata[curoff+1],
2132 curdata[curoff+2],
2133 curdata[curoff+3]
2134 );
2135 curoff += 4;
2136 i++;
2137 }
2138 if (mask & 0x0100) {
2139 /* mask 0x0100: 6 bytes, 00 00 00 00 00 00 (before focus) and 00 00 00 00 01 00 (on focus) observed */
2140 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2141 ce[i].u.info = malloc(strlen("OLCInfo event 0x0100 content 0123456789ab")+1);
2142 sprintf(ce[i].u.info,"OLCInfo event 0x0100 content %02x%02x%02x%02x%02x%02x",
2143 curdata[curoff],
2144 curdata[curoff+1],
2145 curdata[curoff+2],
2146 curdata[curoff+3],
2147 curdata[curoff+4],
2148 curdata[curoff+5]
2149 );
2150 curoff += 6;
2151 i++;
2152 }
2153 if (mask & 0x0200) {
2154 /* mask 0x0200: 7 bytes, 00 00 00 00 00 00 00 observed */
2155 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2156 ce[i].u.info = malloc(strlen("OLCInfo event 0x0200 content 0123456789abcd")+1);
2157 sprintf(ce[i].u.info,"OLCInfo event 0x0200 content %02x%02x%02x%02x%02x%02x%02x",
2158 curdata[curoff],
2159 curdata[curoff+1],
2160 curdata[curoff+2],
2161 curdata[curoff+3],
2162 curdata[curoff+4],
2163 curdata[curoff+5],
2164 curdata[curoff+6]
2165 );
2166 curoff += 7;
2167 i++;
2168 }
2169 if (mask & 0x0400) {
2170 /* mask 0x0400: 7 bytes, 00 00 00 00 00 00 00 observed */
2171 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2172 ce[i].u.info = malloc(strlen("OLCInfo event 0x0400 content 0123456789abcd")+1);
2173 sprintf(ce[i].u.info,"OLCInfo event 0x0400 content %02x%02x%02x%02x%02x%02x%02x",
2174 curdata[curoff],
2175 curdata[curoff+1],
2176 curdata[curoff+2],
2177 curdata[curoff+3],
2178 curdata[curoff+4],
2179 curdata[curoff+5],
2180 curdata[curoff+6]
2181 );
2182 curoff += 7;
2183 i++;
2184 }
2185 if (mask & 0x0800) {
2186 /* mask 0x0800: 8 bytes, 00 00 00 00 00 00 00 00 and 19 01 00 00 00 00 00 00 and others observed */
2187 /* might be mask of focus points selected */
2188 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2189 ce[i].u.info = malloc(strlen("OLCInfo event 0x0800 content 0123456789abcdef")+1);
2190 sprintf(ce[i].u.info,"OLCInfo event 0x0800 content %02x%02x%02x%02x%02x%02x%02x%02x",
2191 curdata[curoff],
2192 curdata[curoff+1],
2193 curdata[curoff+2],
2194 curdata[curoff+3],
2195 curdata[curoff+4],
2196 curdata[curoff+5],
2197 curdata[curoff+6],
2198 curdata[curoff+7]
2199 );
2200 curoff += 8;
2201 i++;
2202 }
2203 if (mask & 0x1000) {
2204 /* mask 0x1000: 1 byte, 00 observed */
2205 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2206 ce[i].u.info = malloc(strlen("OLCInfo event 0x1000 content 01")+1);
2207 sprintf(ce[i].u.info,"OLCInfo event 0x1000 content %02x",
2208 curdata[curoff]
2209 );
2210 curoff += 1;
2211 i++;
2212 }
2213 /* handle more masks */
2214 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2215 ce[i].u.info = malloc(strlen("OLCInfo event mask 0123456789")+1);
2216 sprintf(ce[i].u.info, "OLCInfo event mask=%x", mask);
2217 break;
2218 }
Linus Walleijd7072c32010-12-07 20:43:00 +00002219 case PTP_EC_CANON_EOS_CameraStatusChanged:
Linus Walleij9783ce32014-06-02 21:44:29 +02002220 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS;
2221 ce[i].u.status = dtoh32a(curdata+8);
2222 ptp_debug (params, "event %d: EOS event CameraStatusChanged (size %d) = %d", i, size, dtoh32a(curdata+8));
Linus Walleij9e09ad02011-02-10 13:14:01 +01002223 params->eos_camerastatus = dtoh32a(curdata+8);
Linus Walleijd7072c32010-12-07 20:43:00 +00002224 break;
Linus Walleij7e756532009-05-06 21:25:09 +00002225 case 0: /* end marker */
2226 if (size == 8) /* no output */
2227 break;
2228 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
2229 break;
Linus Walleij96aa0e32012-03-25 12:25:25 +02002230 case PTP_EC_CANON_EOS_BulbExposureTime:
Linus Walleij9783ce32014-06-02 21:44:29 +02002231 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2232 ce[i].u.info = malloc(strlen("BulbExposureTime 123456789"));
2233 sprintf (ce[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8));
Linus Walleij96aa0e32012-03-25 12:25:25 +02002234 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002235 default:
Linus Walleijd4637502009-06-14 23:03:33 +00002236 switch (type) {
Linus Walleijd7072c32010-12-07 20:43:00 +00002237#define XX(x) case PTP_EC_CANON_EOS_##x: \
2238 ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); \
Linus Walleij9783ce32014-06-02 21:44:29 +02002239 ce[i].u.info = malloc(strlen("unhandled EOS event "#x" (size 123456789)")); \
2240 sprintf (ce[i].u.info, "unhandled EOS event "#x" (size %d)", size); \
Linus Walleijd7072c32010-12-07 20:43:00 +00002241 break;
Linus Walleijd4637502009-06-14 23:03:33 +00002242 XX(RequestGetEvent)
2243 XX(ObjectRemoved)
2244 XX(RequestGetObjectInfoEx)
2245 XX(StorageStatusChanged)
2246 XX(StorageInfoChanged)
2247 XX(ObjectInfoChangedEx)
2248 XX(ObjectContentChanged)
Linus Walleijd4637502009-06-14 23:03:33 +00002249 XX(WillSoonShutdown)
2250 XX(ShutdownTimerUpdated)
2251 XX(RequestCancelTransfer)
2252 XX(RequestObjectTransferDT)
2253 XX(RequestCancelTransferDT)
2254 XX(StoreAdded)
2255 XX(StoreRemoved)
2256 XX(BulbExposureTime)
2257 XX(RecordingTime)
2258 XX(RequestObjectTransferTS)
2259 XX(AfResult)
2260#undef XX
2261 default:
2262 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
2263 break;
2264 }
Linus Walleij7e756532009-05-06 21:25:09 +00002265 if (size >= 0x8) { /* event info */
Linus Walleij2ad5b722013-11-04 02:07:44 +01002266 unsigned int j;
Linus Walleijd4637502009-06-14 23:03:33 +00002267 for (j=8;j<size;j++)
2268 ptp_debug (params, " %d: %02x", j, curdata[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00002269 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002270 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002271 break;
2272 }
2273 curdata += size;
Linus Walleij9d22ce02008-05-28 20:39:29 +00002274 if ((size == 8) && (type == 0))
2275 break;
Linus Walleij9783ce32014-06-02 21:44:29 +02002276 i++;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002277 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002278 if (!i) {
2279 free (ce);
2280 ce = NULL;
Linus Walleij0d762cc2010-04-04 23:34:27 +00002281 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002282 *pce = ce;
2283 return i;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002284}
2285
2286/*
Linus Walleijb02a0662006-04-25 08:05:09 +00002287 PTP USB Event container unpack for Nikon events.
2288*/
2289#define PTP_nikon_ec_Length 0
2290#define PTP_nikon_ec_Code 2
2291#define PTP_nikon_ec_Param1 4
2292#define PTP_nikon_ec_Size 6
2293static inline void
Linus Walleij2ad5b722013-11-04 02:07:44 +01002294ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, unsigned int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00002295{
Linus Walleij2ad5b722013-11-04 02:07:44 +01002296 unsigned int i;
Linus Walleijb02a0662006-04-25 08:05:09 +00002297
2298 *ec = NULL;
2299 if (data == NULL)
2300 return;
2301 if (len < PTP_nikon_ec_Code)
2302 return;
2303 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
2304 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) /* broken cnt? */
2305 return;
Linus Walleij0d762cc2010-04-04 23:34:27 +00002306 if (!*cnt)
2307 return;
2308
Linus Walleij7e756532009-05-06 21:25:09 +00002309 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00002310
2311 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00002312 memset(&(*ec)[i],0,sizeof(PTPContainer));
2313 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
2314 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
2315 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00002316 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00002317}
2318
2319
Linus Walleijb02a0662006-04-25 08:05:09 +00002320static inline uint32_t
2321ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
2322 int i, len = 0;
2323 uint8_t retlen;
2324 unsigned char *curdata;
2325
2326 len = 2*(strlen(text->title)+1)+1+
2327 2*(strlen(text->line[0])+1)+1+
2328 2*(strlen(text->line[1])+1)+1+
2329 2*(strlen(text->line[2])+1)+1+
2330 2*(strlen(text->line[3])+1)+1+
2331 2*(strlen(text->line[4])+1)+1+
2332 4*2+2*4+2+4+2+5*4*2;
2333 *data = malloc(len);
2334 if (!*data) return 0;
2335
2336 curdata = *data;
2337 htod16a(curdata,100);curdata+=2;
2338 htod16a(curdata,1);curdata+=2;
2339 htod16a(curdata,0);curdata+=2;
2340 htod16a(curdata,1000);curdata+=2;
2341
2342 htod32a(curdata,0);curdata+=4;
2343 htod32a(curdata,0);curdata+=4;
2344
2345 htod16a(curdata,6);curdata+=2;
2346 htod32a(curdata,0);curdata+=4;
2347
2348 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
2349 htod16a(curdata,0x10);curdata+=2;
2350
2351 for (i=0;i<5;i++) {
2352 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
2353 htod16a(curdata,0x10);curdata+=2;
2354 htod16a(curdata,0x01);curdata+=2;
2355 htod16a(curdata,0x02);curdata+=2;
2356 htod16a(curdata,0x06);curdata+=2;
2357 }
2358 return len;
2359}
Linus Walleij7347d0f2006-10-23 07:23:39 +00002360
2361#define ptp_canon_dir_version 0x00
2362#define ptp_canon_dir_ofc 0x02
2363#define ptp_canon_dir_unk1 0x04
2364#define ptp_canon_dir_objectid 0x08
2365#define ptp_canon_dir_parentid 0x0c
2366#define ptp_canon_dir_previd 0x10 /* in same dir */
2367#define ptp_canon_dir_nextid 0x14 /* in same dir */
2368#define ptp_canon_dir_nextchild 0x18 /* down one dir */
2369#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
2370#define ptp_canon_dir_name 0x20
2371#define ptp_canon_dir_flags 0x2c
2372#define ptp_canon_dir_size 0x30
2373#define ptp_canon_dir_unixtime 0x34
2374#define ptp_canon_dir_year 0x38
2375#define ptp_canon_dir_month 0x39
2376#define ptp_canon_dir_mday 0x3a
2377#define ptp_canon_dir_hour 0x3b
2378#define ptp_canon_dir_minute 0x3c
2379#define ptp_canon_dir_second 0x3d
2380#define ptp_canon_dir_unk2 0x3e
2381#define ptp_canon_dir_thumbsize 0x40
2382#define ptp_canon_dir_width 0x44
2383#define ptp_canon_dir_height 0x48
2384
2385static inline uint16_t
2386ptp_unpack_canon_directory (
2387 PTPParams *params,
2388 unsigned char *dir,
2389 uint32_t cnt,
2390 PTPObjectHandles *handles,
2391 PTPObjectInfo **oinfos, /* size(handles->n) */
2392 uint32_t **flags /* size(handles->n) */
2393) {
2394 unsigned int i, j, nrofobs = 0, curob = 0;
2395
2396#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
2397 for (i=0;i<cnt;i++)
2398 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
2399 handles->n = nrofobs;
2400 handles->Handler = calloc(sizeof(handles->Handler[0]),nrofobs);
2401 if (!handles->Handler) return PTP_RC_GeneralError;
2402 *oinfos = calloc(sizeof((*oinfos)[0]),nrofobs);
2403 if (!*oinfos) return PTP_RC_GeneralError;
2404 *flags = calloc(sizeof((*flags)[0]),nrofobs);
2405 if (!*flags) return PTP_RC_GeneralError;
2406
2407 /* Migrate data into objects ids, handles into
2408 * the object handler array.
2409 */
2410 curob = 0;
2411 for (i=0;i<cnt;i++) {
2412 unsigned char *cur = dir+i*0x4c;
2413 PTPObjectInfo *oi = (*oinfos)+curob;
2414
2415 if (!ISOBJECT(cur))
2416 continue;
2417
2418 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
2419 oi->StorageID = 0xffffffff;
2420 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
2421 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
2422 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
2423 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
2424 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
2425 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
2426 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
2427 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
2428 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
2429 curob++;
2430 }
2431 /* Walk over Storage ID entries and distribute the IDs to
2432 * the parent objects. */
2433 for (i=0;i<cnt;i++) {
2434 unsigned char *cur = dir+i*0x4c;
2435 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2436
2437 if (ISOBJECT(cur))
2438 continue;
2439 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2440 if (j == handles->n) continue;
2441 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
2442 }
2443 /* Walk over all objects and distribute the storage ids */
2444 while (1) {
Linus Walleij2ad5b722013-11-04 02:07:44 +01002445 unsigned int changed = 0;
Linus Walleij7347d0f2006-10-23 07:23:39 +00002446 for (i=0;i<cnt;i++) {
2447 unsigned char *cur = dir+i*0x4c;
2448 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
2449 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
2450 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2451 uint32_t storageid;
2452
2453 if (!ISOBJECT(cur))
2454 continue;
2455 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
2456 if (j == handles->n) {
2457 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
2458 continue;
2459 }
2460 storageid = (*oinfos)[j].StorageID;
2461 if (storageid == 0xffffffff) continue;
2462 if (nextoid != 0xffffffff) {
2463 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
2464 if (j == handles->n) {
2465 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
2466 continue;
2467 }
2468 if ((*oinfos)[j].StorageID == 0xffffffff) {
2469 (*oinfos)[j].StorageID = storageid;
2470 changed++;
2471 }
2472 }
2473 if (nextchild != 0xffffffff) {
2474 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2475 if (j == handles->n) {
2476 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
2477 continue;
2478 }
2479 if ((*oinfos)[j].StorageID == 0xffffffff) {
2480 (*oinfos)[j].StorageID = storageid;
2481 changed++;
2482 }
2483 }
2484 }
2485 /* Check if we:
2486 * - changed no entry (nothing more to do)
2487 * - changed all of them at once (usually happens)
2488 * break if we do.
2489 */
2490 if (!changed || (changed==nrofobs-1))
2491 break;
2492 }
2493#undef ISOBJECT
2494 return PTP_RC_OK;
2495}