blob: 22b9ae7cd30b8775860c04d0c6eeefd87e22317a [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>
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01004 * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
Linus Walleija381e8a2013-03-05 21:00:06 +01005 * 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
Marcus Meissner3d692dc2016-02-21 12:34:06 +010033#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
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*
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100130ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t total, 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
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100139 if (offset + 1 >= total)
140 return NULL;
141
Linus Walleija8a19cc2007-02-02 22:13:17 +0000142 length = dtoh8a(&data[offset]); /* PTP_MAXSTRLEN == 255, 8 bit len */
143 *len = length;
144 if (length == 0) /* nothing to do? */
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100145 return NULL;
146
147 if (offset + 1 + length*sizeof(string[0]) > total)
148 return NULL;
Linus Walleija8a19cc2007-02-02 22:13:17 +0000149
150 /* copy to string[] to ensure correct alignment for iconv(3) */
151 memcpy(string, &data[offset+1], length * sizeof(string[0]));
152 string[length] = 0x0000U; /* be paranoid! add a terminator. */
153 loclstr[0] = '\0';
Linus Walleije206af62011-04-19 01:51:39 +0200154
Linus Walleija8a19cc2007-02-02 22:13:17 +0000155 /* convert from camera UCS-2 to our locale */
156 src = (char *)string;
157 srclen = length * sizeof(string[0]);
158 dest = loclstr;
159 destlen = sizeof(loclstr)-1;
Linus Walleij6db174f2009-05-09 13:15:26 +0000160 nconv = (size_t)-1;
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100161#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100162 if (params->cd_ucs2_to_locale != (iconv_t)-1)
163 nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, &dest, &destlen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000164#endif
Linus Walleija8a19cc2007-02-02 22:13:17 +0000165 if (nconv == (size_t) -1) { /* do it the hard way */
166 int i;
167 /* try the old way, in case iconv is broken */
168 for (i=0;i<length;i++) {
169 if (dtoh16a(&data[offset+1+2*i])>127)
170 loclstr[i] = '?';
171 else
172 loclstr[i] = dtoh16a(&data[offset+1+2*i]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000173 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000174 dest = loclstr+length;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000175 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000176 *dest = '\0';
177 loclstr[sizeof(loclstr)-1] = '\0'; /* be safe? */
178 return(strdup(loclstr));
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000179}
180
Linus Walleija823a702006-08-27 21:27:46 +0000181static inline int
182ucs2strlen(uint16_t const * const unicstr)
183{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200184 int length = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000185
186 /* Unicode strings are terminated with 2 * 0x00 */
187 for(length = 0; unicstr[length] != 0x0000U; length ++);
188 return length;
189}
190
191
Linus Walleijb02a0662006-04-25 08:05:09 +0000192static inline void
193ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000194{
Linus Walleij96aa0e32012-03-25 12:25:25 +0200195 int packedlen = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000196 uint16_t ucs2str[PTP_MAXSTRLEN+1];
197 char *ucs2strp = (char *) ucs2str;
Linus Walleija823a702006-08-27 21:27:46 +0000198 size_t convlen = strlen(string);
Linus Walleija823a702006-08-27 21:27:46 +0000199
200 /* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
Linus Walleija8a19cc2007-02-02 22:13:17 +0000201 memset(ucs2strp, 0, sizeof(ucs2str)); /* XXX: necessary? */
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100202#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
Linus Walleijd000c372011-12-20 08:32:23 +0100203 if (params->cd_locale_to_ucs2 != (iconv_t)-1) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000204 size_t nconv;
205 size_t convmax = PTP_MAXSTRLEN * 2; /* Includes the terminator */
206 char *stringp = string;
207
208 nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen,
209 &ucs2strp, &convmax);
210 if (nconv == (size_t) -1)
211 ucs2str[0] = 0x0000U;
Linus Walleijd6f25ba2011-11-14 23:00:52 +0100212 } else
Linus Walleijd000c372011-12-20 08:32:23 +0100213#endif
Linus Walleij6db174f2009-05-09 13:15:26 +0000214 {
Linus Walleij2ad5b722013-11-04 02:07:44 +0100215 unsigned int i;
216
Linus Walleij6db174f2009-05-09 13:15:26 +0000217 for (i=0;i<convlen;i++) {
218 ucs2str[i] = string[i];
219 }
220 ucs2str[convlen] = 0;
221 }
Linus Walleija8a19cc2007-02-02 22:13:17 +0000222 /*
223 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
224 * why do we need ucs2strlen()?
225 */
Linus Walleija823a702006-08-27 21:27:46 +0000226 packedlen = ucs2strlen(ucs2str);
227 if (packedlen > PTP_MAXSTRLEN-1) {
228 *len=0;
229 return;
230 }
Linus Walleij958441f2006-08-29 15:30:11 +0000231
Linus Walleij7f234382006-12-09 19:41:00 +0000232 /* number of characters including terminating 0 (PTP standard confirmed) */
Linus Walleija823a702006-08-27 21:27:46 +0000233 htod8a(&data[offset],packedlen+1);
Linus Walleija8a19cc2007-02-02 22:13:17 +0000234 memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
235 htod16a(&data[offset+packedlen*2+1], 0x0000); /* terminate 0 */
Linus Walleij958441f2006-08-29 15:30:11 +0000236
237 /* The returned length is in number of characters */
Linus Walleij048d9382006-12-04 08:19:19 +0000238 *len = (uint8_t) packedlen+1;
Linus Walleija823a702006-08-27 21:27:46 +0000239}
240
241static inline unsigned char *
Linus Walleij735f4162006-08-29 09:18:17 +0000242ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
Linus Walleija823a702006-08-27 21:27:46 +0000243{
Richard Low8b42ca32006-11-15 08:52:17 +0000244 uint8_t packed[PTP_MAXSTRLEN*2+3], len;
Linus Walleija823a702006-08-27 21:27:46 +0000245 size_t plen;
246 unsigned char *retcopy = NULL;
Richard Lowd47b9212007-08-16 21:14:23 +0000247
248 if (string == NULL)
249 ptp_pack_string(params, "", (unsigned char*) packed, 0, &len);
250 else
251 ptp_pack_string(params, string, (unsigned char*) packed, 0, &len);
252
Linus Walleij958441f2006-08-29 15:30:11 +0000253 /* returned length is in characters, then one byte for string length */
254 plen = len*2 + 1;
Linus Walleij048d9382006-12-04 08:19:19 +0000255
Linus Walleija823a702006-08-27 21:27:46 +0000256 retcopy = malloc(plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000257 if (!retcopy) {
258 *packed_size = 0;
Linus Walleija823a702006-08-27 21:27:46 +0000259 return NULL;
Linus Walleij735f4162006-08-29 09:18:17 +0000260 }
Linus Walleija823a702006-08-27 21:27:46 +0000261 memcpy(retcopy, packed, plen);
Linus Walleij735f4162006-08-29 09:18:17 +0000262 *packed_size = plen;
Linus Walleija823a702006-08-27 21:27:46 +0000263 return (retcopy);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000264}
265
Linus Walleijb02a0662006-04-25 08:05:09 +0000266static inline uint32_t
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100267ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint32_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000268{
269 uint32_t n, i=0;
270
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100271 if (!data)
272 return 0;
273
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100274 if (offset >= datalen)
275 return 0;
276
277 if (offset + sizeof(uint32_t) > datalen)
278 return 0;
279
Linus Walleij9783ce32014-06-02 21:44:29 +0200280 *array = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000281 n=dtoh32a(&data[offset]);
Linus Walleij9783ce32014-06-02 21:44:29 +0200282 if (n >= UINT_MAX/sizeof(uint32_t))
283 return 0;
284 if (!n)
285 return 0;
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100286
287 if (offset + sizeof(uint32_t)*(n+1) > datalen) {
288 ptp_debug (params ,"array runs over datalen bufferend (%d vs %d)", offset + sizeof(uint32_t)*(n+1) , datalen);
289 return 0;
290 }
291
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000292 *array = malloc (n*sizeof(uint32_t));
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100293 if (!*array)
294 return 0;
Linus Walleij9783ce32014-06-02 21:44:29 +0200295 for (i=0;i<n;i++)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000296 (*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000297 return n;
298}
299
Linus Walleijb02a0662006-04-25 08:05:09 +0000300static inline uint32_t
Linus Walleijf67bca92006-05-29 09:33:39 +0000301ptp_pack_uint32_t_array(PTPParams *params, uint32_t *array, uint32_t arraylen, unsigned char **data )
302{
303 uint32_t i=0;
304
305 *data = malloc ((arraylen+1)*sizeof(uint32_t));
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100306 if (!*data)
307 return 0;
Linus Walleijf67bca92006-05-29 09:33:39 +0000308 htod32a(&(*data)[0],arraylen);
309 for (i=0;i<arraylen;i++)
310 htod32a(&(*data)[sizeof(uint32_t)*(i+1)], array[i]);
311 return (arraylen+1)*sizeof(uint32_t);
312}
313
314static inline uint32_t
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100315ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint16_t **array)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000316{
317 uint32_t n, i=0;
318
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100319 if (!data)
320 return 0;
Linus Walleij9783ce32014-06-02 21:44:29 +0200321 *array = NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000322 n=dtoh32a(&data[offset]);
Linus Walleij9783ce32014-06-02 21:44:29 +0200323 if (n >= UINT_MAX/sizeof(uint16_t))
324 return 0;
325 if (!n)
326 return 0;
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100327 if (offset + sizeof(uint32_t) > datalen)
328 return 0;
329 if (offset + sizeof(uint32_t)+sizeof(uint16_t)*n > datalen) {
330 ptp_debug (params ,"array runs over datalen bufferend (%d vs %d)", offset + sizeof(uint32_t)+n*sizeof(uint16_t) , datalen);
331 return 0;
332 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000333 *array = malloc (n*sizeof(uint16_t));
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100334 if (!*array)
335 return 0;
Linus Walleij9783ce32014-06-02 21:44:29 +0200336 for (i=0;i<n;i++)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000337 (*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000338 return n;
339}
340
341/* DeviceInfo pack/unpack */
342
343#define PTP_di_StandardVersion 0
344#define PTP_di_VendorExtensionID 2
345#define PTP_di_VendorExtensionVersion 6
346#define PTP_di_VendorExtensionDesc 8
347#define PTP_di_FunctionalMode 8
348#define PTP_di_OperationsSupported 10
349
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100350static inline int
Linus Walleijb02a0662006-04-25 08:05:09 +0000351ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000352{
353 uint8_t len;
354 unsigned int totallen;
Linus Walleij7e756532009-05-06 21:25:09 +0000355
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100356 if (!data) return 0;
357 if (datalen < 12) return 0;
358 memset (di, 0, sizeof(*di));
Linus Walleij7347d0f2006-10-23 07:23:39 +0000359 di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000360 di->VendorExtensionID =
361 dtoh32a(&data[PTP_di_VendorExtensionID]);
362 di->VendorExtensionVersion =
363 dtoh16a(&data[PTP_di_VendorExtensionVersion]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100364 di->VendorExtensionDesc =
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000365 ptp_unpack_string(params, data,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100366 PTP_di_VendorExtensionDesc,
367 datalen,
368 &len);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000369 totallen=len*2+1;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100370 if (datalen <= totallen) return 0;
371 di->FunctionalMode =
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000372 dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
373 di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
374 PTP_di_OperationsSupported+totallen,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100375 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000376 &di->OperationsSupported);
377 totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100378 if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000379 di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
380 PTP_di_OperationsSupported+totallen,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100381 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000382 &di->EventsSupported);
383 totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100384 if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000385 di->DevicePropertiesSupported_len =
386 ptp_unpack_uint16_t_array(params, data,
387 PTP_di_OperationsSupported+totallen,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100388 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000389 &di->DevicePropertiesSupported);
390 totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100391 if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000392 di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
393 PTP_di_OperationsSupported+totallen,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100394 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000395 &di->CaptureFormats);
396 totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100397 if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000398 di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
399 PTP_di_OperationsSupported+totallen,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100400 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000401 &di->ImageFormats);
402 totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100403 if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000404 di->Manufacturer = ptp_unpack_string(params, data,
405 PTP_di_OperationsSupported+totallen,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100406 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000407 &len);
408 totallen+=len*2+1;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100409 /* be more relaxed ... as these are optional its ok if they are not here */
410 if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000411 di->Model = ptp_unpack_string(params, data,
412 PTP_di_OperationsSupported+totallen,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100413 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000414 &len);
415 totallen+=len*2+1;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100416 /* be more relaxed ... as these are optional its ok if they are not here */
417 if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000418 di->DeviceVersion = ptp_unpack_string(params, data,
419 PTP_di_OperationsSupported+totallen,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100420 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000421 &len);
422 totallen+=len*2+1;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100423 /* be more relaxed ... as these are optional its ok if they are not here */
424 if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000425 di->SerialNumber = ptp_unpack_string(params, data,
426 PTP_di_OperationsSupported+totallen,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100427 datalen,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000428 &len);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100429 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000430}
Linus Walleija8a19cc2007-02-02 22:13:17 +0000431
Linus Walleij2ad5b722013-11-04 02:07:44 +0100432inline static void
Linus Walleija8a19cc2007-02-02 22:13:17 +0000433ptp_free_DI (PTPDeviceInfo *di) {
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100434 free (di->SerialNumber);
435 free (di->DeviceVersion);
436 free (di->Model);
437 free (di->Manufacturer);
438 free (di->ImageFormats);
439 free (di->CaptureFormats);
440 free (di->VendorExtensionDesc);
441 free (di->OperationsSupported);
442 free (di->EventsSupported);
443 free (di->DevicePropertiesSupported);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100444 memset(di, 0, sizeof(*di));
Linus Walleija8a19cc2007-02-02 22:13:17 +0000445}
Linus Walleij7e756532009-05-06 21:25:09 +0000446
447/* EOS Device Info unpack */
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100448static inline int
Linus Walleij7e756532009-05-06 21:25:09 +0000449ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
450{
Linus Walleij2ad5b722013-11-04 02:07:44 +0100451 unsigned int totallen = 4;
Linus Walleij96aa0e32012-03-25 12:25:25 +0200452
453 memset (di,0, sizeof(*di));
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100454 if (datalen < 8) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000455
456 /* uint32_t struct len - ignore */
457 di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100458 totallen, datalen, &di->EventsSupported);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100459 if (!di->EventsSupported) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000460 totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100461 if (totallen >= datalen) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000462
463 di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100464 totallen, datalen, &di->DevicePropertiesSupported);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100465 if (!di->DevicePropertiesSupported) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000466 totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100467 if (totallen >= datalen) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000468
469 di->unk_len = ptp_unpack_uint32_t_array(params, data,
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100470 totallen, datalen, &di->unk);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100471 if (!di->unk) return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000472 totallen += di->unk_len*sizeof(uint32_t)+4;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100473 return 1;
Linus Walleij7e756532009-05-06 21:25:09 +0000474}
Linus Walleij0d762cc2010-04-04 23:34:27 +0000475
476static inline void
477ptp_free_EOS_DI (PTPCanonEOSDeviceInfo *di)
478{
479 free (di->EventsSupported);
480 free (di->DevicePropertiesSupported);
481 free (di->unk);
482}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000483
484/* ObjectHandles array pack/unpack */
485
486#define PTP_oh 0
487
Linus Walleijb02a0662006-04-25 08:05:09 +0000488static inline void
489ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000490{
Linus Walleijf0bf4372007-07-01 21:47:38 +0000491 if (len) {
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100492 oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, len, &oh->Handler);
Linus Walleijf0bf4372007-07-01 21:47:38 +0000493 } else {
494 oh->n = 0;
495 oh->Handler = NULL;
496 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000497}
498
499/* StoreIDs array pack/unpack */
500
501#define PTP_sids 0
502
Linus Walleijb02a0662006-04-25 08:05:09 +0000503static inline void
504ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000505{
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100506 sids->n = 0;
507 sids->Storage = NULL;
508
509 if (!data || !len)
Linus Walleij96aa0e32012-03-25 12:25:25 +0200510 return;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100511
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100512 sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, len, &sids->Storage);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000513}
514
515/* StorageInfo pack/unpack */
516
517#define PTP_si_StorageType 0
518#define PTP_si_FilesystemType 2
519#define PTP_si_AccessCapability 4
520#define PTP_si_MaxCapability 6
521#define PTP_si_FreeSpaceInBytes 14
522#define PTP_si_FreeSpaceInImages 22
523#define PTP_si_StorageDescription 26
524
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100525static inline int
Linus Walleijb02a0662006-04-25 08:05:09 +0000526ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000527{
528 uint8_t storagedescriptionlen;
529
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100530 if (len < 26) return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000531 si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
532 si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
533 si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000534 si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
535 si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
536 si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100537
538 /* FIXME: check more lengths here */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000539 si->StorageDescription=ptp_unpack_string(params, data,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100540 PTP_si_StorageDescription,
541 len,
542 &storagedescriptionlen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000543 si->VolumeLabel=ptp_unpack_string(params, data,
544 PTP_si_StorageDescription+storagedescriptionlen*2+1,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100545 len,
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000546 &storagedescriptionlen);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100547 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000548}
549
550/* ObjectInfo pack/unpack */
551
552#define PTP_oi_StorageID 0
553#define PTP_oi_ObjectFormat 4
554#define PTP_oi_ProtectionStatus 6
555#define PTP_oi_ObjectCompressedSize 8
556#define PTP_oi_ThumbFormat 12
557#define PTP_oi_ThumbCompressedSize 14
558#define PTP_oi_ThumbPixWidth 18
559#define PTP_oi_ThumbPixHeight 22
560#define PTP_oi_ImagePixWidth 26
561#define PTP_oi_ImagePixHeight 30
562#define PTP_oi_ImageBitDepth 34
563#define PTP_oi_ParentObject 38
564#define PTP_oi_AssociationType 42
565#define PTP_oi_AssociationDesc 44
566#define PTP_oi_SequenceNumber 48
567#define PTP_oi_filenamelen 52
568#define PTP_oi_Filename 53
569
Linus Walleija0323272007-01-07 12:21:30 +0000570/* the max length assuming zero length dates. We have need 3 */
571/* bytes for these. */
Richard Lowa679b1c2006-12-29 20:08:14 +0000572#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
573
Linus Walleijb02a0662006-04-25 08:05:09 +0000574static inline uint32_t
575ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000576{
Linus Walleijb02a0662006-04-25 08:05:09 +0000577 unsigned char* oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000578 uint8_t filenamelen;
579 uint8_t capturedatelen=0;
Richard Lowa679b1c2006-12-29 20:08:14 +0000580 /* let's allocate some memory first; correct assuming zero length dates */
Marcus Meissner0546a762012-04-10 18:49:10 +0200581 oidata=malloc(PTP_oi_MaxLen + params->ocs64*4);
582 *oidataptr=oidata;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000583 /* the caller should free it after use! */
584#if 0
585 char *capture_date="20020101T010101"; /* XXX Fake date */
586#endif
Marcus Meissner0546a762012-04-10 18:49:10 +0200587 memset (oidata, 0, PTP_oi_MaxLen + params->ocs64*4);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000588 htod32a(&oidata[PTP_oi_StorageID],oi->StorageID);
589 htod16a(&oidata[PTP_oi_ObjectFormat],oi->ObjectFormat);
590 htod16a(&oidata[PTP_oi_ProtectionStatus],oi->ProtectionStatus);
591 htod32a(&oidata[PTP_oi_ObjectCompressedSize],oi->ObjectCompressedSize);
Marcus Meissner0546a762012-04-10 18:49:10 +0200592 if (params->ocs64)
593 oidata += 4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000594 htod16a(&oidata[PTP_oi_ThumbFormat],oi->ThumbFormat);
595 htod32a(&oidata[PTP_oi_ThumbCompressedSize],oi->ThumbCompressedSize);
596 htod32a(&oidata[PTP_oi_ThumbPixWidth],oi->ThumbPixWidth);
597 htod32a(&oidata[PTP_oi_ThumbPixHeight],oi->ThumbPixHeight);
598 htod32a(&oidata[PTP_oi_ImagePixWidth],oi->ImagePixWidth);
599 htod32a(&oidata[PTP_oi_ImagePixHeight],oi->ImagePixHeight);
600 htod32a(&oidata[PTP_oi_ImageBitDepth],oi->ImageBitDepth);
601 htod32a(&oidata[PTP_oi_ParentObject],oi->ParentObject);
602 htod16a(&oidata[PTP_oi_AssociationType],oi->AssociationType);
603 htod32a(&oidata[PTP_oi_AssociationDesc],oi->AssociationDesc);
604 htod32a(&oidata[PTP_oi_SequenceNumber],oi->SequenceNumber);
605
606 ptp_pack_string(params, oi->Filename, oidata, PTP_oi_filenamelen, &filenamelen);
607/*
608 filenamelen=(uint8_t)strlen(oi->Filename);
609 htod8a(&req->data[PTP_oi_filenamelen],filenamelen+1);
610 for (i=0;i<filenamelen && i< PTP_MAXSTRLEN; i++) {
611 req->data[PTP_oi_Filename+i*2]=oi->Filename[i];
612 }
613*/
614 /*
615 *XXX Fake date.
616 * for example Kodak sets Capture date on the basis of EXIF data.
617 * Spec says that this field is from perspective of Initiator.
618 */
619#if 0 /* seems now we don't need any data packed in OI dataset... for now ;)*/
620 capturedatelen=strlen(capture_date);
621 htod8a(&data[PTP_oi_Filename+(filenamelen+1)*2],
622 capturedatelen+1);
623 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
624 data[PTP_oi_Filename+(i+filenamelen+1)*2+1]=capture_date[i];
625 }
626 htod8a(&data[PTP_oi_Filename+(filenamelen+capturedatelen+2)*2+1],
627 capturedatelen+1);
628 for (i=0;i<capturedatelen && i< PTP_MAXSTRLEN; i++) {
629 data[PTP_oi_Filename+(i+filenamelen+capturedatelen+2)*2+2]=
630 capture_date[i];
631 }
632#endif
633 /* XXX this function should return dataset length */
Marcus Meissner0546a762012-04-10 18:49:10 +0200634 return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3)+params->ocs64*4;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000635}
636
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000637static time_t
Linus Walleij6db174f2009-05-09 13:15:26 +0000638ptp_unpack_PTPTIME (const char *str) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000639 char ptpdate[40];
640 char tmp[5];
Linus Walleija381e8a2013-03-05 21:00:06 +0100641 size_t ptpdatelen;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000642 struct tm tm;
643
644 if (!str)
645 return 0;
646 ptpdatelen = strlen(str);
Linus Walleij7e756532009-05-06 21:25:09 +0000647 if (ptpdatelen >= sizeof (ptpdate)) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000648 /*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000649 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000650 }
Linus Walleij7e756532009-05-06 21:25:09 +0000651 if (ptpdatelen<15) {
Linus Walleij6db174f2009-05-09 13:15:26 +0000652 /*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000653 return 0;
Linus Walleij7e756532009-05-06 21:25:09 +0000654 }
Linus Walleija381e8a2013-03-05 21:00:06 +0100655 strncpy (ptpdate, str, sizeof(ptpdate));
656 ptpdate[sizeof(ptpdate) - 1] = '\0';
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000657
658 memset(&tm,0,sizeof(tm));
659 strncpy (tmp, ptpdate, 4);
660 tmp[4] = 0;
661 tm.tm_year=atoi (tmp) - 1900;
662 strncpy (tmp, ptpdate + 4, 2);
663 tmp[2] = 0;
664 tm.tm_mon = atoi (tmp) - 1;
665 strncpy (tmp, ptpdate + 6, 2);
666 tmp[2] = 0;
667 tm.tm_mday = atoi (tmp);
668 strncpy (tmp, ptpdate + 9, 2);
669 tmp[2] = 0;
670 tm.tm_hour = atoi (tmp);
671 strncpy (tmp, ptpdate + 11, 2);
672 tmp[2] = 0;
673 tm.tm_min = atoi (tmp);
674 strncpy (tmp, ptpdate + 13, 2);
675 tmp[2] = 0;
676 tm.tm_sec = atoi (tmp);
Linus Walleije206af62011-04-19 01:51:39 +0200677 tm.tm_isdst = -1;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000678 return mktime (&tm);
679}
680
Linus Walleijb02a0662006-04-25 08:05:09 +0000681static inline void
682ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000683{
684 uint8_t filenamelen;
685 uint8_t capturedatelen;
686 char *capture_date;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000687
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100688 if (len < PTP_oi_SequenceNumber)
689 return;
690
691 oi->Filename = oi->Keywords = NULL;
692
693 /* FIXME: also handle length with all the strings at the end */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000694 oi->StorageID=dtoh32a(&data[PTP_oi_StorageID]);
695 oi->ObjectFormat=dtoh16a(&data[PTP_oi_ObjectFormat]);
696 oi->ProtectionStatus=dtoh16a(&data[PTP_oi_ProtectionStatus]);
697 oi->ObjectCompressedSize=dtoh32a(&data[PTP_oi_ObjectCompressedSize]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200698
699 /* Stupid Samsung Galaxy developers emit a 64bit objectcompressedsize */
700 if ((data[PTP_oi_filenamelen] == 0) && (data[PTP_oi_filenamelen+4] != 0)) {
701 params->ocs64 = 1;
702 data += 4;
703 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000704 oi->ThumbFormat=dtoh16a(&data[PTP_oi_ThumbFormat]);
705 oi->ThumbCompressedSize=dtoh32a(&data[PTP_oi_ThumbCompressedSize]);
706 oi->ThumbPixWidth=dtoh32a(&data[PTP_oi_ThumbPixWidth]);
707 oi->ThumbPixHeight=dtoh32a(&data[PTP_oi_ThumbPixHeight]);
708 oi->ImagePixWidth=dtoh32a(&data[PTP_oi_ImagePixWidth]);
709 oi->ImagePixHeight=dtoh32a(&data[PTP_oi_ImagePixHeight]);
710 oi->ImageBitDepth=dtoh32a(&data[PTP_oi_ImageBitDepth]);
711 oi->ParentObject=dtoh32a(&data[PTP_oi_ParentObject]);
712 oi->AssociationType=dtoh16a(&data[PTP_oi_AssociationType]);
713 oi->AssociationDesc=dtoh32a(&data[PTP_oi_AssociationDesc]);
714 oi->SequenceNumber=dtoh32a(&data[PTP_oi_SequenceNumber]);
Marcus Meissner0546a762012-04-10 18:49:10 +0200715
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100716 oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, len, &filenamelen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000717
718 capture_date = ptp_unpack_string(params, data,
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100719 PTP_oi_filenamelen+filenamelen*2+1, len, &capturedatelen);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000720 /* subset of ISO 8601, without '.s' tenths of second and
721 * time zone
722 */
Linus Walleij6db174f2009-05-09 13:15:26 +0000723 oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000724 free(capture_date);
725
Linus Walleij3bc0d7f2008-11-01 23:06:24 +0000726 /* now the modification date ... */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000727 capture_date = ptp_unpack_string(params, data,
728 PTP_oi_filenamelen+filenamelen*2
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100729 +capturedatelen*2+2, len, &capturedatelen);
Linus Walleij6db174f2009-05-09 13:15:26 +0000730 oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000731 free(capture_date);
732}
733
734/* Custom Type Value Assignement (without Length) macro frequently used below */
Linus Walleijb02a0662006-04-25 08:05:09 +0000735#define CTVAL(target,func) { \
736 if (total - *offset < sizeof(target)) \
737 return 0; \
738 target = func(&data[*offset]); \
739 *offset += sizeof(target); \
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000740}
741
Linus Walleijb02a0662006-04-25 08:05:09 +0000742#define RARR(val,member,func) { \
Linus Walleij9783ce32014-06-02 21:44:29 +0200743 unsigned int n,j; \
Linus Walleijb02a0662006-04-25 08:05:09 +0000744 if (total - *offset < sizeof(uint32_t)) \
745 return 0; \
746 n = dtoh32a (&data[*offset]); \
747 *offset += sizeof(uint32_t); \
748 \
Linus Walleij9783ce32014-06-02 21:44:29 +0200749 if (n >= UINT_MAX/sizeof(val->a.v[0])) \
750 return 0; \
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100751 if (n > (total - (*offset))/sizeof(val->a.v[0]))\
752 return 0; \
Linus Walleijb02a0662006-04-25 08:05:09 +0000753 val->a.count = n; \
754 val->a.v = malloc(sizeof(val->a.v[0])*n); \
755 if (!val->a.v) return 0; \
756 for (j=0;j<n;j++) \
757 CTVAL(val->a.v[j].member, func); \
758}
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000759
Linus Walleij2ad5b722013-11-04 02:07:44 +0100760static inline unsigned int
Linus Walleijb02a0662006-04-25 08:05:09 +0000761ptp_unpack_DPV (
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100762 PTPParams *params, unsigned char* data, unsigned int *offset, unsigned int total,
Linus Walleijb02a0662006-04-25 08:05:09 +0000763 PTPPropertyValue* value, uint16_t datatype
764) {
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100765 if (*offset >= total) /* we are at the end or over the end of the buffer */
766 return 0;
767
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000768 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000769 case PTP_DTC_INT8:
770 CTVAL(value->i8,dtoh8a);
771 break;
772 case PTP_DTC_UINT8:
773 CTVAL(value->u8,dtoh8a);
774 break;
775 case PTP_DTC_INT16:
776 CTVAL(value->i16,dtoh16a);
777 break;
778 case PTP_DTC_UINT16:
779 CTVAL(value->u16,dtoh16a);
780 break;
781 case PTP_DTC_INT32:
782 CTVAL(value->i32,dtoh32a);
783 break;
784 case PTP_DTC_UINT32:
785 CTVAL(value->u32,dtoh32a);
786 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000787 case PTP_DTC_INT64:
788 CTVAL(value->i64,dtoh64a);
789 break;
790 case PTP_DTC_UINT64:
791 CTVAL(value->u64,dtoh64a);
792 break;
793
Linus Walleij037a1252006-12-16 20:36:52 +0000794 case PTP_DTC_UINT128:
795 *offset += 16;
796 /*fprintf(stderr,"unhandled unpack of uint128n");*/
797 break;
798 case PTP_DTC_INT128:
799 *offset += 16;
800 /*fprintf(stderr,"unhandled unpack of int128n");*/
801 break;
802
803
804
Linus Walleijb02a0662006-04-25 08:05:09 +0000805 case PTP_DTC_AINT8:
806 RARR(value,i8,dtoh8a);
807 break;
808 case PTP_DTC_AUINT8:
809 RARR(value,u8,dtoh8a);
810 break;
811 case PTP_DTC_AUINT16:
812 RARR(value,u16,dtoh16a);
813 break;
814 case PTP_DTC_AINT16:
815 RARR(value,i16,dtoh16a);
816 break;
817 case PTP_DTC_AUINT32:
818 RARR(value,u32,dtoh32a);
819 break;
820 case PTP_DTC_AINT32:
821 RARR(value,i32,dtoh32a);
822 break;
Linus Walleijabf54752007-07-30 19:51:54 +0000823 case PTP_DTC_AUINT64:
824 RARR(value,u64,dtoh64a);
825 break;
826 case PTP_DTC_AINT64:
827 RARR(value,i64,dtoh64a);
828 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000829 /* XXX: other int types are unimplemented */
830 /* XXX: other int arrays are unimplemented also */
831 case PTP_DTC_STR: {
832 uint8_t len;
833 /* XXX: max size */
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100834
835 if (*offset >= total+1)
836 return 0;
837
838 value->str = ptp_unpack_string(params,data,*offset,total,&len);
Linus Walleijb02a0662006-04-25 08:05:09 +0000839 *offset += len*2+1;
840 if (!value->str)
Linus Walleijdeddc342008-08-16 23:52:06 +0000841 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000842 break;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000843 }
Linus Walleij037a1252006-12-16 20:36:52 +0000844 default:
845 return 0;
Linus Walleijb02a0662006-04-25 08:05:09 +0000846 }
847 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000848}
849
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000850/* Device Property pack/unpack */
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000851#define PTP_dpd_DevicePropertyCode 0
852#define PTP_dpd_DataType 2
853#define PTP_dpd_GetSet 4
854#define PTP_dpd_FactoryDefaultValue 5
855
Linus Walleijb02a0662006-04-25 08:05:09 +0000856static inline int
857ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000858{
Linus Walleij9783ce32014-06-02 21:44:29 +0200859 unsigned int offset = 0, ret;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000860
Linus Walleijb02a0662006-04-25 08:05:09 +0000861 memset (dpd, 0, sizeof(*dpd));
Marcus Meissneraa7d91a2017-03-16 15:59:48 +0100862 if (dpdlen <= 5)
863 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000864 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
865 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
866 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
Linus Walleijdeddc342008-08-16 23:52:06 +0000867 dpd->FormFlag=PTP_DPFF_None;
Linus Walleijb02a0662006-04-25 08:05:09 +0000868
869 offset = PTP_dpd_FactoryDefaultValue;
870 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
871 if (!ret) goto outofmemory;
Linus Walleijdeddc342008-08-16 23:52:06 +0000872 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
873 return 1;
Linus Walleijb02a0662006-04-25 08:05:09 +0000874 ret = ptp_unpack_DPV (params, data, &offset, 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
Linus Walleijb02a0662006-04-25 08:05:09 +0000882 if (offset==PTP_dpd_FactoryDefaultValue)
883 return 1;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000884
Linus Walleijb02a0662006-04-25 08:05:09 +0000885 dpd->FormFlag=dtoh8a(&data[offset]);
886 offset+=sizeof(uint8_t);
887
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000888 switch (dpd->FormFlag) {
Linus Walleijb02a0662006-04-25 08:05:09 +0000889 case PTP_DPFF_Range:
890 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
891 if (!ret) goto outofmemory;
892 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
893 if (!ret) goto outofmemory;
894 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
895 if (!ret) goto outofmemory;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000896 break;
Linus Walleijb02a0662006-04-25 08:05:09 +0000897 case PTP_DPFF_Enumeration: {
898 int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000899#define N dpd->FORM.Enum.NumberOfValues
Linus Walleijb02a0662006-04-25 08:05:09 +0000900 N = dtoh16a(&data[offset]);
901 offset+=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, &offset, 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;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000920 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000921 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000922 }
923 }
Linus Walleijb02a0662006-04-25 08:05:09 +0000924#undef N
925 return 1;
926outofmemory:
927 ptp_free_devicepropdesc(dpd);
928 return 0;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +0000929}
930
Linus Walleij9783ce32014-06-02 21:44:29 +0200931/* Device Property pack/unpack */
932#define PTP_dpd_Sony_DevicePropertyCode 0
933#define PTP_dpd_Sony_DataType 2
934#define PTP_dpd_Sony_GetSet 4
935#define PTP_dpd_Sony_Unknown 5
936#define PTP_dpd_Sony_FactoryDefaultValue 6
937
938static inline int
939ptp_unpack_Sony_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen, unsigned int *poffset)
940{
941 unsigned int ret;
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100942#if 0
943 unsigned int unk1, unk2;
944#endif
Linus Walleij9783ce32014-06-02 21:44:29 +0200945
946 memset (dpd, 0, sizeof(*dpd));
947 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_Sony_DevicePropertyCode]);
948 dpd->DataType=dtoh16a(&data[PTP_dpd_Sony_DataType]);
949
950#if 0
Marcus Meissner3d692dc2016-02-21 12:34:06 +0100951 /* get set ? */
952 unk1 = dtoh8a(&data[PTP_dpd_Sony_GetSet]);
953 unk2 = dtoh8a(&data[PTP_dpd_Sony_Unknown]);
954 ptp_debug (params, "prop 0x%04x, datatype 0x%04x, unk1 %d unk2 %d", dpd->DevicePropertyCode, dpd->DataType, unk1, unk2);
Linus Walleij9783ce32014-06-02 21:44:29 +0200955#endif
956 dpd->GetSet=1;
957
958 dpd->FormFlag=PTP_DPFF_None;
959
960 *poffset = PTP_dpd_Sony_FactoryDefaultValue;
961 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
962 if (!ret) goto outofmemory;
963 if ((dpd->DataType == PTP_DTC_STR) && (*poffset == dpdlen))
964 return 1;
965 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->CurrentValue, dpd->DataType);
966 if (!ret) goto outofmemory;
967
968 /* if offset==0 then Data Type format is not supported by this
969 code or the Data Type is a string (with two empty strings as
970 values). In both cases Form Flag should be set to 0x00 and FORM is
971 not present. */
972
973 if (*poffset==PTP_dpd_Sony_FactoryDefaultValue)
974 return 1;
975
976 dpd->FormFlag=dtoh8a(&data[*poffset]);
977 *poffset+=sizeof(uint8_t);
978
979 switch (dpd->FormFlag) {
980 case PTP_DPFF_Range:
981 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.MinimumValue, dpd->DataType);
982 if (!ret) goto outofmemory;
983 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.MaximumValue, dpd->DataType);
984 if (!ret) goto outofmemory;
985 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Range.StepSize, dpd->DataType);
986 if (!ret) goto outofmemory;
987 break;
988 case PTP_DPFF_Enumeration: {
989 int i;
990#define N dpd->FORM.Enum.NumberOfValues
991 N = dtoh16a(&data[*poffset]);
992 *poffset+=sizeof(uint16_t);
993 dpd->FORM.Enum.SupportedValue = malloc(N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
994 if (!dpd->FORM.Enum.SupportedValue)
995 goto outofmemory;
996
997 memset (dpd->FORM.Enum.SupportedValue,0 , N*sizeof(dpd->FORM.Enum.SupportedValue[0]));
998 for (i=0;i<N;i++) {
999 ret = ptp_unpack_DPV (params, data, poffset, dpdlen, &dpd->FORM.Enum.SupportedValue[i], dpd->DataType);
1000
1001 /* Slightly different handling here. The HP PhotoSmart 120
1002 * specifies an enumeration with N in wrong endian
1003 * 00 01 instead of 01 00, so we count the enum just until the
1004 * the end of the packet.
1005 */
1006 if (!ret) {
1007 if (!i)
1008 goto outofmemory;
1009 dpd->FORM.Enum.NumberOfValues = i;
1010 break;
1011 }
1012 }
1013 }
1014 }
1015#undef N
1016 return 1;
1017outofmemory:
1018 ptp_free_devicepropdesc(dpd);
1019 return 0;
1020}
1021
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001022static inline void
1023duplicate_PropertyValue (const PTPPropertyValue *src, PTPPropertyValue *dst, uint16_t type) {
Linus Walleij9783ce32014-06-02 21:44:29 +02001024 if (type == PTP_DTC_STR) {
1025 if (src->str)
1026 dst->str = strdup(src->str);
1027 else
1028 dst->str = NULL;
1029 return;
1030 }
1031
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001032 if (type & PTP_DTC_ARRAY_MASK) {
Linus Walleij2ad5b722013-11-04 02:07:44 +01001033 unsigned int i;
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001034
1035 dst->a.count = src->a.count;
Linus Walleij9783ce32014-06-02 21:44:29 +02001036 dst->a.v = malloc (sizeof(src->a.v[0])*src->a.count);
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001037 for (i=0;i<src->a.count;i++)
1038 duplicate_PropertyValue (&src->a.v[i], &dst->a.v[i], type & ~PTP_DTC_ARRAY_MASK);
1039 return;
1040 }
1041 switch (type & ~PTP_DTC_ARRAY_MASK) {
1042 case PTP_DTC_INT8: dst->i8 = src->i8; break;
1043 case PTP_DTC_UINT8: dst->u8 = src->u8; break;
1044 case PTP_DTC_INT16: dst->i16 = src->i16; break;
1045 case PTP_DTC_UINT16: dst->u16 = src->u16; break;
1046 case PTP_DTC_INT32: dst->i32 = src->i32; break;
1047 case PTP_DTC_UINT32: dst->u32 = src->u32; break;
1048 case PTP_DTC_UINT64: dst->u64 = src->u64; break;
1049 case PTP_DTC_INT64: dst->i64 = src->i64; break;
1050#if 0
1051 case PTP_DTC_INT128: dst->i128 = src->i128; break;
1052 case PTP_DTC_UINT128: dst->u128 = src->u128; break;
1053#endif
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001054 default: break;
1055 }
1056 return;
1057}
1058
1059static inline void
1060duplicate_DevicePropDesc(const PTPDevicePropDesc *src, PTPDevicePropDesc *dst) {
1061 int i;
1062
1063 dst->DevicePropertyCode = src->DevicePropertyCode;
1064 dst->DataType = src->DataType;
1065 dst->GetSet = src->GetSet;
1066
Linus Walleij9783ce32014-06-02 21:44:29 +02001067 duplicate_PropertyValue (&src->FactoryDefaultValue, &dst->FactoryDefaultValue, src->DataType);
1068 duplicate_PropertyValue (&src->CurrentValue, &dst->CurrentValue, src->DataType);
Linus Walleijd9ee8cd2013-11-04 01:54:35 +01001069
1070 dst->FormFlag = src->FormFlag;
1071 switch (src->FormFlag) {
1072 case PTP_DPFF_Range:
1073 duplicate_PropertyValue (&src->FORM.Range.MinimumValue, &dst->FORM.Range.MinimumValue, src->DataType);
1074 duplicate_PropertyValue (&src->FORM.Range.MaximumValue, &dst->FORM.Range.MaximumValue, src->DataType);
1075 duplicate_PropertyValue (&src->FORM.Range.StepSize, &dst->FORM.Range.StepSize, src->DataType);
1076 break;
1077 case PTP_DPFF_Enumeration:
1078 dst->FORM.Enum.NumberOfValues = src->FORM.Enum.NumberOfValues;
1079 dst->FORM.Enum.SupportedValue = malloc (sizeof(dst->FORM.Enum.SupportedValue[0])*src->FORM.Enum.NumberOfValues);
1080 for (i = 0; i<src->FORM.Enum.NumberOfValues ; i++)
1081 duplicate_PropertyValue (&src->FORM.Enum.SupportedValue[i], &dst->FORM.Enum.SupportedValue[i], src->DataType);
1082 break;
1083 case PTP_DPFF_None:
1084 break;
1085 }
1086}
1087
Linus Walleijb02a0662006-04-25 08:05:09 +00001088#define PTP_opd_ObjectPropertyCode 0
1089#define PTP_opd_DataType 2
1090#define PTP_opd_GetSet 4
1091#define PTP_opd_FactoryDefaultValue 5
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001092
Linus Walleijb02a0662006-04-25 08:05:09 +00001093static inline int
1094ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001095{
Linus Walleij2ad5b722013-11-04 02:07:44 +01001096 unsigned int offset=0, ret;
Linus Walleijb02a0662006-04-25 08:05:09 +00001097
1098 memset (opd, 0, sizeof(*opd));
1099 opd->ObjectPropertyCode=dtoh16a(&data[PTP_opd_ObjectPropertyCode]);
1100 opd->DataType=dtoh16a(&data[PTP_opd_DataType]);
1101 opd->GetSet=dtoh8a(&data[PTP_opd_GetSet]);
1102
1103 offset = PTP_opd_FactoryDefaultValue;
1104 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FactoryDefaultValue, opd->DataType);
1105 if (!ret) goto outofmemory;
1106
1107 opd->GroupCode=dtoh32a(&data[offset]);
1108 offset+=sizeof(uint32_t);
1109
1110 opd->FormFlag=dtoh8a(&data[offset]);
1111 offset+=sizeof(uint8_t);
1112
1113 switch (opd->FormFlag) {
1114 case PTP_OPFF_Range:
1115 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MinimumValue, opd->DataType);
1116 if (!ret) goto outofmemory;
1117 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.MaximumValue, opd->DataType);
1118 if (!ret) goto outofmemory;
1119 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Range.StepSize, opd->DataType);
1120 if (!ret) goto outofmemory;
1121 break;
1122 case PTP_OPFF_Enumeration: {
Linus Walleij2ad5b722013-11-04 02:07:44 +01001123 unsigned int i;
Linus Walleijb02a0662006-04-25 08:05:09 +00001124#define N opd->FORM.Enum.NumberOfValues
1125 N = dtoh16a(&data[offset]);
1126 offset+=sizeof(uint16_t);
1127 opd->FORM.Enum.SupportedValue = malloc(N*sizeof(opd->FORM.Enum.SupportedValue[0]));
1128 if (!opd->FORM.Enum.SupportedValue)
1129 goto outofmemory;
1130
1131 memset (opd->FORM.Enum.SupportedValue,0 , N*sizeof(opd->FORM.Enum.SupportedValue[0]));
1132 for (i=0;i<N;i++) {
1133 ret = ptp_unpack_DPV (params, data, &offset, opdlen, &opd->FORM.Enum.SupportedValue[i], opd->DataType);
1134
1135 /* Slightly different handling here. The HP PhotoSmart 120
1136 * specifies an enumeration with N in wrong endian
1137 * 00 01 instead of 01 00, so we count the enum just until the
1138 * the end of the packet.
1139 */
1140 if (!ret) {
1141 if (!i)
1142 goto outofmemory;
1143 opd->FORM.Enum.NumberOfValues = i;
1144 break;
1145 }
1146 }
1147#undef N
1148 }
1149 }
1150 return 1;
1151outofmemory:
1152 ptp_free_objectpropdesc(opd);
1153 return 0;
1154}
1155
1156
1157static inline uint32_t
1158ptp_pack_DPV (PTPParams *params, PTPPropertyValue* value, unsigned char** dpvptr, uint16_t datatype)
1159{
1160 unsigned char* dpv=NULL;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001161 uint32_t size=0;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001162 unsigned int i;
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001163
1164 switch (datatype) {
Linus Walleijb02a0662006-04-25 08:05:09 +00001165 case PTP_DTC_INT8:
1166 size=sizeof(int8_t);
1167 dpv=malloc(size);
1168 htod8a(dpv,value->i8);
1169 break;
1170 case PTP_DTC_UINT8:
1171 size=sizeof(uint8_t);
1172 dpv=malloc(size);
1173 htod8a(dpv,value->u8);
1174 break;
1175 case PTP_DTC_INT16:
1176 size=sizeof(int16_t);
1177 dpv=malloc(size);
1178 htod16a(dpv,value->i16);
1179 break;
1180 case PTP_DTC_UINT16:
1181 size=sizeof(uint16_t);
1182 dpv=malloc(size);
1183 htod16a(dpv,value->u16);
1184 break;
1185 case PTP_DTC_INT32:
1186 size=sizeof(int32_t);
1187 dpv=malloc(size);
1188 htod32a(dpv,value->i32);
1189 break;
1190 case PTP_DTC_UINT32:
1191 size=sizeof(uint32_t);
1192 dpv=malloc(size);
1193 htod32a(dpv,value->u32);
1194 break;
Linus Walleijabf54752007-07-30 19:51:54 +00001195 case PTP_DTC_INT64:
1196 size=sizeof(int64_t);
1197 dpv=malloc(size);
1198 htod64a(dpv,value->i64);
1199 break;
1200 case PTP_DTC_UINT64:
1201 size=sizeof(uint64_t);
1202 dpv=malloc(size);
1203 htod64a(dpv,value->u64);
1204 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001205 case PTP_DTC_AUINT8:
1206 size=sizeof(uint32_t)+value->a.count*sizeof(uint8_t);
1207 dpv=malloc(size);
1208 htod32a(dpv,value->a.count);
1209 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001210 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
Linus Walleijb02a0662006-04-25 08:05:09 +00001211 break;
1212 case PTP_DTC_AINT8:
1213 size=sizeof(uint32_t)+value->a.count*sizeof(int8_t);
1214 dpv=malloc(size);
1215 htod32a(dpv,value->a.count);
1216 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001217 htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
Linus Walleijb02a0662006-04-25 08:05:09 +00001218 break;
1219 case PTP_DTC_AUINT16:
1220 size=sizeof(uint32_t)+value->a.count*sizeof(uint16_t);
1221 dpv=malloc(size);
1222 htod32a(dpv,value->a.count);
1223 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001224 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
Linus Walleijb02a0662006-04-25 08:05:09 +00001225 break;
1226 case PTP_DTC_AINT16:
1227 size=sizeof(uint32_t)+value->a.count*sizeof(int16_t);
1228 dpv=malloc(size);
1229 htod32a(dpv,value->a.count);
1230 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001231 htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
Linus Walleijb02a0662006-04-25 08:05:09 +00001232 break;
1233 case PTP_DTC_AUINT32:
1234 size=sizeof(uint32_t)+value->a.count*sizeof(uint32_t);
1235 dpv=malloc(size);
1236 htod32a(dpv,value->a.count);
1237 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001238 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
Linus Walleijb02a0662006-04-25 08:05:09 +00001239 break;
1240 case PTP_DTC_AINT32:
1241 size=sizeof(uint32_t)+value->a.count*sizeof(int32_t);
1242 dpv=malloc(size);
1243 htod32a(dpv,value->a.count);
1244 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001245 htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
Linus Walleijb02a0662006-04-25 08:05:09 +00001246 break;
Linus Walleijabf54752007-07-30 19:51:54 +00001247 case PTP_DTC_AUINT64:
1248 size=sizeof(uint32_t)+value->a.count*sizeof(uint64_t);
1249 dpv=malloc(size);
1250 htod32a(dpv,value->a.count);
1251 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001252 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
Linus Walleijabf54752007-07-30 19:51:54 +00001253 break;
1254 case PTP_DTC_AINT64:
1255 size=sizeof(uint32_t)+value->a.count*sizeof(int64_t);
1256 dpv=malloc(size);
1257 htod32a(dpv,value->a.count);
1258 for (i=0;i<value->a.count;i++)
Richard Lowcc265902007-07-30 20:14:12 +00001259 htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
Linus Walleijabf54752007-07-30 19:51:54 +00001260 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001261 /* XXX: other int types are unimplemented */
1262 case PTP_DTC_STR: {
Linus Walleij735f4162006-08-29 09:18:17 +00001263 dpv=ptp_get_packed_stringcopy(params, value->str, &size);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001264 break;
Linus Walleijb02a0662006-04-25 08:05:09 +00001265 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001266 }
1267 *dpvptr=dpv;
1268 return size;
1269}
1270
Linus Walleij99310d42006-11-01 08:29:39 +00001271#define MAX_MTP_PROPS 127
1272static inline uint32_t
Linus Walleij1e9a0332007-09-12 19:35:56 +00001273ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
Linus Walleij99310d42006-11-01 08:29:39 +00001274{
1275 unsigned char* opldata;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001276 MTPProperties *propitr;
Linus Walleij99310d42006-11-01 08:29:39 +00001277 unsigned char *packedprops[MAX_MTP_PROPS];
1278 uint32_t packedpropslens[MAX_MTP_PROPS];
Linus Walleij39b93742006-11-27 11:25:59 +00001279 uint32_t packedobjecthandles[MAX_MTP_PROPS];
Linus Walleij99310d42006-11-01 08:29:39 +00001280 uint16_t packedpropsids[MAX_MTP_PROPS];
1281 uint16_t packedpropstypes[MAX_MTP_PROPS];
1282 uint32_t totalsize = 0;
1283 uint32_t bufp = 0;
1284 uint32_t noitems = 0;
1285 uint32_t i;
1286
1287 totalsize = sizeof(uint32_t); /* 4 bytes to store the number of elements */
Linus Walleij1e9a0332007-09-12 19:35:56 +00001288 propitr = props;
1289 while (nrofprops-- && noitems < MAX_MTP_PROPS) {
Richard Low6c0a6ce2006-11-26 10:42:08 +00001290 /* Object Handle */
Linus Walleij39b93742006-11-27 11:25:59 +00001291 packedobjecthandles[noitems]=propitr->ObjectHandle;
Linus Walleij99310d42006-11-01 08:29:39 +00001292 totalsize += sizeof(uint32_t); /* Object ID */
1293 /* Metadata type */
1294 packedpropsids[noitems]=propitr->property;
1295 totalsize += sizeof(uint16_t);
1296 /* Data type */
1297 packedpropstypes[noitems]= propitr->datatype;
1298 totalsize += sizeof(uint16_t);
1299 /* Add each property to be sent. */
1300 packedpropslens[noitems] = ptp_pack_DPV (params, &propitr->propval, &packedprops[noitems], propitr->datatype);
1301 totalsize += packedpropslens[noitems];
1302 noitems ++;
Linus Walleij1e9a0332007-09-12 19:35:56 +00001303 propitr ++;
Linus Walleij99310d42006-11-01 08:29:39 +00001304 }
1305
1306 /* Allocate memory for the packed property list */
1307 opldata = malloc(totalsize);
1308
1309 htod32a(&opldata[bufp],noitems);
1310 bufp += 4;
1311
1312 /* Copy into a nice packed list */
1313 for (i = 0; i < noitems; i++) {
1314 /* Object ID */
Richard Low6c0a6ce2006-11-26 10:42:08 +00001315 htod32a(&opldata[bufp],packedobjecthandles[i]);
Linus Walleij99310d42006-11-01 08:29:39 +00001316 bufp += sizeof(uint32_t);
1317 htod16a(&opldata[bufp],packedpropsids[i]);
1318 bufp += sizeof(uint16_t);
1319 htod16a(&opldata[bufp],packedpropstypes[i]);
1320 bufp += sizeof(uint16_t);
1321 /* The copy the actual property */
1322 memcpy(&opldata[bufp], packedprops[i], packedpropslens[i]);
1323 bufp += packedpropslens[i];
1324 free(packedprops[i]);
1325 }
1326 *opldataptr = opldata;
1327 return totalsize;
1328}
1329
Linus Walleij1e9a0332007-09-12 19:35:56 +00001330static int
1331_compare_func(const void* x, const void *y) {
1332 const MTPProperties *px = x;
1333 const MTPProperties *py = y;
1334
1335 return px->ObjectHandle - py->ObjectHandle;
1336}
1337
Richard Low8d82d2f2006-11-16 20:37:43 +00001338static inline int
Linus Walleij1e9a0332007-09-12 19:35:56 +00001339ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
Richard Low8d82d2f2006-11-16 20:37:43 +00001340{
Linus Walleij277cd532006-11-20 14:57:46 +00001341 uint32_t prop_count = dtoh32a(data);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001342 MTPProperties *props = NULL;
Linus Walleij2ad5b722013-11-04 02:07:44 +01001343 unsigned int offset = 0, i;
Linus Walleij277cd532006-11-20 14:57:46 +00001344
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001345 *pprops = NULL;
1346 if (prop_count == 0)
1347 return 0;
1348 if (prop_count >= INT_MAX/sizeof(MTPProperties)) {
1349 ptp_debug (params ,"prop_count %d is too large", prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001350 return 0;
1351 }
Linus Walleijd49955b2008-11-09 17:20:00 +00001352 ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
Linus Walleij277cd532006-11-20 14:57:46 +00001353 data += sizeof(uint32_t);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001354 len -= sizeof(uint32_t);
Linus Walleij1e9a0332007-09-12 19:35:56 +00001355 props = malloc(prop_count * sizeof(MTPProperties));
1356 if (!props) return 0;
Linus Walleij277cd532006-11-20 14:57:46 +00001357 for (i = 0; i < prop_count; i++) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001358 if (len <= 0) {
Linus Walleijd49955b2008-11-09 17:20:00 +00001359 ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001360 ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL");
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001361 ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
Linus Walleijd49955b2008-11-09 17:20:00 +00001362 qsort (props, i, sizeof(MTPProperties),_compare_func);
1363 *pprops = props;
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001364 return i;
1365 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001366 props[i].ObjectHandle = dtoh32a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001367 data += sizeof(uint32_t);
1368 len -= sizeof(uint32_t);
1369
Linus Walleij1e9a0332007-09-12 19:35:56 +00001370 props[i].property = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001371 data += sizeof(uint16_t);
1372 len -= sizeof(uint16_t);
1373
Linus Walleij1e9a0332007-09-12 19:35:56 +00001374 props[i].datatype = dtoh16a(data);
Linus Walleij277cd532006-11-20 14:57:46 +00001375 data += sizeof(uint16_t);
1376 len -= sizeof(uint16_t);
1377
1378 offset = 0;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001379 if (!ptp_unpack_DPV(params, data, &offset, len, &props[i].propval, props[i].datatype)) {
1380 ptp_debug (params ,"unpacking DPV of property %d encountered insufficient buffer. attack?", i);
1381 qsort (props, i, sizeof(MTPProperties),_compare_func);
1382 *pprops = props;
1383 return i;
1384 }
Linus Walleij277cd532006-11-20 14:57:46 +00001385 data += offset;
1386 len -= offset;
Linus Walleij277cd532006-11-20 14:57:46 +00001387 }
Linus Walleij1e9a0332007-09-12 19:35:56 +00001388 qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1389 *pprops = props;
Linus Walleij277cd532006-11-20 14:57:46 +00001390 return prop_count;
Richard Low8d82d2f2006-11-16 20:37:43 +00001391}
1392
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001393/*
1394 PTP USB Event container unpack
1395 Copyright (c) 2003 Nikolai Kopanygin
1396*/
1397
1398#define PTP_ec_Length 0
1399#define PTP_ec_Type 4
1400#define PTP_ec_Code 6
1401#define PTP_ec_TransId 8
1402#define PTP_ec_Param1 12
1403#define PTP_ec_Param2 16
1404#define PTP_ec_Param3 20
1405
Linus Walleijb02a0662006-04-25 08:05:09 +00001406static inline void
Linus Walleij7e756532009-05-06 21:25:09 +00001407ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001408{
Linus Walleij9783ce32014-06-02 21:44:29 +02001409 unsigned int length;
Linus Walleij7e756532009-05-06 21:25:09 +00001410 int type;
1411
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001412 if (data==NULL)
1413 return;
Linus Walleij7e756532009-05-06 21:25:09 +00001414 memset(ec,0,sizeof(*ec));
Linus Walleij9783ce32014-06-02 21:44:29 +02001415
Linus Walleij7e756532009-05-06 21:25:09 +00001416 length=dtoh32a(&data[PTP_ec_Length]);
Linus Walleij9783ce32014-06-02 21:44:29 +02001417 if (length > len) {
1418 ptp_debug (params, "length %d in container, but data only %d bytes?!", length, len);
1419 return;
1420 }
Linus Walleij7e756532009-05-06 21:25:09 +00001421 type = dtoh16a(&data[PTP_ec_Type]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001422
Linus Walleij7e756532009-05-06 21:25:09 +00001423 ec->Code=dtoh16a(&data[PTP_ec_Code]);
1424 ec->Transaction_ID=dtoh32a(&data[PTP_ec_TransId]);
1425
1426 if (type!=PTP_USB_CONTAINER_EVENT) {
1427 ptp_debug (params, "Unknown canon event type %d (code=%x,tid=%x), please report!",type,ec->Code,ec->Transaction_ID);
1428 return;
1429 }
1430 if (length>=(PTP_ec_Param1+4)) {
1431 ec->Param1=dtoh32a(&data[PTP_ec_Param1]);
1432 ec->Nparam=1;
1433 }
1434 if (length>=(PTP_ec_Param2+4)) {
1435 ec->Param2=dtoh32a(&data[PTP_ec_Param2]);
1436 ec->Nparam=2;
1437 }
1438 if (length>=(PTP_ec_Param3+4)) {
1439 ec->Param3=dtoh32a(&data[PTP_ec_Param3]);
1440 ec->Nparam=3;
1441 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001442}
1443
1444/*
1445 PTP Canon Folder Entry unpack
1446 Copyright (c) 2003 Nikolai Kopanygin
1447*/
1448#define PTP_cfe_ObjectHandle 0
1449#define PTP_cfe_ObjectFormatCode 4
1450#define PTP_cfe_Flags 6
1451#define PTP_cfe_ObjectSize 7
1452#define PTP_cfe_Time 11
1453#define PTP_cfe_Filename 15
1454
Linus Walleijb02a0662006-04-25 08:05:09 +00001455static inline void
1456ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001457{
1458 int i;
1459 if (data==NULL)
1460 return;
1461 fe->ObjectHandle=dtoh32a(&data[PTP_cfe_ObjectHandle]);
1462 fe->ObjectFormatCode=dtoh16a(&data[PTP_cfe_ObjectFormatCode]);
1463 fe->Flags=dtoh8a(&data[PTP_cfe_Flags]);
Linus Walleijb02a0662006-04-25 08:05:09 +00001464 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00001465 fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1466 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
Linus Walleijb02a0662006-04-25 08:05:09 +00001467 fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1468}
1469
Linus Walleij96aa0e32012-03-25 12:25:25 +02001470/*
1471 PTP Canon EOS Folder Entry unpack
14720: 00 00 08 a0 objectid
14734: 01 00 02 00 storageid
14748: 01 30 00 00 ofc
147512: 01 00
147614: 00 00
147716: 11 00 00 00
147820: 00 00 00 00
147924: 00 00 00 80
148028: 00 00 08 a0
148132: 4d 49 53 43-00 00 00 00 00 00 00 00 name
148200 00 00 00
148384 bc 74 46 objectime
1484
1485
1486(normal PTP GetObjectInfo)
1487ObjectInfo for 'IMG_0199.JPG':
1488 Object ID: 0x92740c72
1489 StorageID: 0x00020001
1490 ObjectFormat: 0x3801
1491 ProtectionStatus: 0x0000
1492 ObjectCompressedSize: 2217241
1493 ThumbFormat: 0x3808
1494 ThumbCompressedSize: 5122
1495 ThumbPixWidth: 160
1496 ThumbPixHeight: 120
1497 ImagePixWidth: 4000
1498 ImagePixHeight: 3000
1499 ImageBitDepth: 24
1500 ParentObject: 0x92740000
1501 AssociationType: 0x0000
1502 AssociationDesc: 0x00000000
1503 SequenceNumber: 0x00000000
1504 ModificationDate: 0x4d985ff0
1505 CaptureDate: 0x4d985ff0
1506
15070010 38 00 00 00 Size of this entry
15080014 72 0c 74 92 OID
15090018 01 00 02 00 StorageID
1510001c 01 38 00 00 OFC
Marcus Meissner3d692dc2016-02-21 12:34:06 +010015110020 00 00 00 00 ??
15120024 21 00 00 00 flags (4 bytes? 1 byte?)
Linus Walleij96aa0e32012-03-25 12:25:25 +020015130028 19 d5 21 00 Size
1514002c 00 00 74 92 ?
15150030 70 0c 74 92 OID
15160034 49 4d 47 5f-30 31 39 39 2e 4a 50 47 IMG_0199.JPG
15170040 00 00 00 00
15180044 10 7c 98 4d Time
1519
1520
1521*/
1522#define PTP_cefe_ObjectHandle 0
1523#define PTP_cefe_StorageID 4
1524#define PTP_cefe_ObjectFormatCode 8
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001525#define PTP_cefe_Flags 16
Linus Walleij96aa0e32012-03-25 12:25:25 +02001526#define PTP_cefe_ObjectSize 20
1527#define PTP_cefe_Filename 32
1528#define PTP_cefe_Time 48
1529
1530static inline void
1531ptp_unpack_Canon_EOS_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
1532{
1533 int i;
1534
1535 fe->ObjectHandle=dtoh32a(&data[PTP_cefe_ObjectHandle]);
1536 fe->ObjectFormatCode=dtoh16a(&data[PTP_cefe_ObjectFormatCode]);
1537 fe->Flags=dtoh8a(&data[PTP_cefe_Flags]);
1538 fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cefe_ObjectSize]);
1539 fe->Time=(time_t)dtoh32a(&data[PTP_cefe_Time]);
1540 for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
1541 fe->Filename[i]=(char)data[PTP_cefe_Filename+i];
1542}
1543
1544
Linus Walleij1a0c3012009-07-23 23:06:58 +00001545static inline uint16_t
1546ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1547{
1548 /*
Marcus Meissner0546a762012-04-10 18:49:10 +02001549 EOS ImageFormat entries (of at least the 5DM2 and the 400D) look like this:
Linus Walleij1a0c3012009-07-23 23:06:58 +00001550 uint32: number of entries / generated files (1 or 2)
1551 uint32: size of this entry in bytes (most likely allways 0x10)
1552 uint32: image type (1 == JPG, 6 == RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001553 uint32: image size (0 == Large, 1 == Medium, 2 == Small, 0xe == S1, 0xf == S2, 0x10 == S3)
Linus Walleij1a0c3012009-07-23 23:06:58 +00001554 uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
Marcus Meissner0546a762012-04-10 18:49:10 +02001555 If the number of entries is 2 the last 4 uint32 repeat.
Linus Walleij1a0c3012009-07-23 23:06:58 +00001556
1557 example:
1558 0: 0x 1
1559 1: 0x 10
1560 2: 0x 6
1561 3: 0x 1
1562 4: 0x 4
1563
Marcus Meissner0546a762012-04-10 18:49:10 +02001564 The idea is to simply 'condense' these values to just one uint16 to be able to conveniently
Linus Walleij1a0c3012009-07-23 23:06:58 +00001565 use the available enumeration facilities (look-up table). The image size and compression
1566 values fully describe the image format. Hence we generate a uint16 with the four nibles set
1567 as follows: entry 1 size | entry 1 compression | entry 2 size | entry 2 compression.
1568 The above example would result in the value 0x1400.
Marcus Meissner0546a762012-04-10 18:49:10 +02001569
1570 The EOS 5D Mark III (and possibly other high-end EOS as well) added the extra fancy S1, S2
1571 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 +00001572 */
1573
1574 const unsigned char* d = *data;
1575 uint32_t n = dtoh32a( d );
1576 uint32_t l, s1, c1, s2 = 0, c2 = 0;
1577
1578 if (n != 1 && n !=2) {
1579 ptp_debug (params, "parsing EOS ImageFormat property failed (n != 1 && n != 2: %d)", n);
1580 return 0;
1581 }
1582
1583 l = dtoh32a( d+=4 );
1584 if (l != 0x10) {
1585 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1586 return 0;
1587 }
1588
1589 d+=4; /* skip type */
1590 s1 = dtoh32a( d+=4 );
1591 c1 = dtoh32a( d+=4 );
1592
1593 if (n == 2) {
1594 l = dtoh32a( d+=4 );
1595 if (l != 0x10) {
1596 ptp_debug (params, "parsing EOS ImageFormat property failed (l != 0x10: 0x%x)", l);
1597 return 0;
1598 }
1599 d+=4; /* skip type */
1600 s2 = dtoh32a( d+=4 );
1601 c2 = dtoh32a( d+=4 );
1602 }
1603
1604 *data = (unsigned char*) d+4;
1605
Marcus Meissner0546a762012-04-10 18:49:10 +02001606 /* deal with S1/S2/S3 JPEG sizes, see above. */
1607 if( s1 >= 0xe )
1608 s1--;
1609 if( s2 >= 0xe )
1610 s2--;
1611
Linus Walleij1a0c3012009-07-23 23:06:58 +00001612 return ((s1 & 0xF) << 12) | ((c1 & 0xF) << 8) | ((s2 & 0xF) << 4) | ((c2 & 0xF) << 0);
1613}
1614
1615static inline uint32_t
1616ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value)
1617{
1618 uint32_t n = (value & 0xFF) ? 2 : 1;
1619 uint32_t s = 4 + 0x10 * n;
1620
1621 if( !data )
1622 return s;
1623
Marcus Meissner0546a762012-04-10 18:49:10 +02001624#define PACK_5DM3_SMALL_JPEG_SIZE( X ) (X) >= 0xd ? (X)+1 : (X)
1625
Linus Walleij1a0c3012009-07-23 23:06:58 +00001626 htod32a(data+=0, n);
1627 htod32a(data+=4, 0x10);
1628 htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001629 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 12) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001630 htod32a(data+=4, (value >> 8) & 0xF);
1631
1632 if (n==2) {
1633 htod32a(data+=4, 0x10);
1634 htod32a(data+=4, ((value >> 0) & 0xF) == 4 ? 6 : 1);
Marcus Meissner0546a762012-04-10 18:49:10 +02001635 htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 4) & 0xF));
Linus Walleij1a0c3012009-07-23 23:06:58 +00001636 htod32a(data+=4, (value >> 0) & 0xF);
1637 }
1638
Marcus Meissner0546a762012-04-10 18:49:10 +02001639#undef PACK_5DM3_SMALL_JPEG_SIZE
1640
1641 return s;
1642}
1643
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001644/* 00: 32 bit size
1645 * 04: 16 bit subsize
1646 * 08: 16 bit version (?)
1647 * 0c: 16 bit focus_points_in_struct
1648 * 10: 16 bit focus_points_in_use
1649 * 14: variable arrays:
1650 * 16 bit sizex, 16 bit sizey
1651 * 16 bit othersizex, 16 bit othersizey
1652 * 16 bit array height[focus_points_in_struct]
1653 * 16 bit array width[focus_points_in_struct]
1654 * 16 bit array offsetheight[focus_points_in_struct] middle is 0
1655 * 16 bit array offsetwidth[focus_points_in_struct] middle is ?
1656 * bitfield of selected focus points, starting with 0 [size focus_points_in_struct in bits]
1657 * unknown stuff , likely which are active
1658 * 16 bit 0xffff
1659 *
1660 * size=NxN,size2=NxN,points={NxNxNxN,NxNxNxN,...},selected={0,1,2}
1661 */
1662static inline char*
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001663ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data, uint32_t datasize )
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001664{
1665 uint32_t size = dtoh32a( *data );
1666 uint32_t halfsize = dtoh16a( (*data) + 4);
1667 uint32_t version = dtoh16a( (*data) + 6);
1668 uint32_t focus_points_in_struct = dtoh16a( (*data) + 8);
1669 uint32_t focus_points_in_use = dtoh16a( (*data) + 10);
1670 uint32_t sizeX = dtoh16a( (*data) + 12);
1671 uint32_t sizeY = dtoh16a( (*data) + 14);
1672 uint32_t size2X = dtoh16a( (*data) + 16);
1673 uint32_t size2Y = dtoh16a( (*data) + 18);
1674 uint32_t i;
1675 uint32_t maxlen;
1676 char *str, *p;
1677
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001678 if ((size >= datasize) || (size < 20))
1679 return strdup("bad size 1");
1680 /* every focuspoint gets 4 (16 bit number possible "-" sign and a x) and a ,*/
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001681 /* inital things around lets say 100 chars at most.
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001682 * FIXME: check selected when we decode it
1683 */
1684 if (size < focus_points_in_struct*8) {
1685 ptp_error(params, "focus_points_in_struct %d is too large vs size %d", focus_points_in_struct, size);
1686 return strdup("bad size 2");
1687 }
1688 if (focus_points_in_use > focus_points_in_struct) {
1689 ptp_error(params, "focus_points_in_use %d is larger than focus_points_in_struct %d", focus_points_in_use, focus_points_in_struct);
1690 return strdup("bad size 3");
1691 }
1692
1693 maxlen = focus_points_in_use*32 + 100 + (size - focus_points_in_struct*8)*2;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001694 if (halfsize != size-4) {
1695 ptp_error(params, "halfsize %d is not expected %d", halfsize, size-4);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001696 return strdup("bad size 4");
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001697 }
1698 if (20 + focus_points_in_struct*8 + (focus_points_in_struct+7)/8 > size) {
1699 ptp_error(params, "size %d is too large for fp in struct %d", focus_points_in_struct*8 + 20 + (focus_points_in_struct+7)/8, size);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001700 return strdup("bad size 5");
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001701 }
1702#if 0
1703 ptp_debug(params,"d1d3 content:");
1704 for (i=0;i<size;i+=2)
1705 ptp_debug(params,"%d: %02x %02x", i, (*data)[i], (*data)[i+1]);
1706#endif
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001707 ptp_debug(params,"d1d3 version %d", version);
1708 ptp_debug(params,"d1d3 size %d", size);
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001709 ptp_debug(params,"d1d3 focus points in struct %d, in use %d", focus_points_in_struct, focus_points_in_use);
1710
1711 str = (char*)malloc( maxlen );
1712 if (!str)
1713 return NULL;
1714 p = str;
1715
1716 p += sprintf(p,"eosversion=%d,size=%dx%d,size2=%dx%d,points={", version, sizeX, sizeY, size2X, size2Y);
1717 for (i=0;i<focus_points_in_use;i++) {
1718 int16_t x = dtoh16a((*data) + focus_points_in_struct*4 + 20 + 2*i);
1719 int16_t y = dtoh16a((*data) + focus_points_in_struct*6 + 20 + 2*i);
1720 int16_t w = dtoh16a((*data) + focus_points_in_struct*2 + 20 + 2*i);
1721 int16_t h = dtoh16a((*data) + focus_points_in_struct*0 + 20 + 2*i);
1722
1723 p += sprintf(p,"{%d,%d,%d,%d}",x,y,w,h);
1724
1725 if (i<focus_points_in_use-1)
1726 p += sprintf(p,",");
1727 }
1728 p += sprintf(p,"},select={");
1729 for (i=0;i<focus_points_in_use;i++) {
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001730 if ((1<<(i%8)) & ((*data)[focus_points_in_struct*8+20+i/8]))
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001731 p+=sprintf(p,"%d,", i);
1732 }
1733
1734 p += sprintf(p,"},unknown={");
1735 for (i=focus_points_in_struct*8+(focus_points_in_struct+7)/8+20;i<size;i++) {
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001736 if ((p-str) > maxlen - 4)
1737 break;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001738 p+=sprintf(p,"%02x", (*data)[i]);
1739 }
1740 p += sprintf(p,"}");
1741 return str;
1742}
1743
1744
Marcus Meissner0546a762012-04-10 18:49:10 +02001745static inline char*
1746ptp_unpack_EOS_CustomFuncEx (PTPParams* params, unsigned char** data )
1747{
1748 uint32_t s = dtoh32a( *data );
1749 uint32_t n = s/4, i;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001750 char *str, *p;
Marcus Meissner0546a762012-04-10 18:49:10 +02001751
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001752 if (s > 1024) {
1753 ptp_debug (params, "customfuncex data is larger than 1k / %d... unexpected?", s);
1754 return strdup("bad length");
1755 }
1756 str = (char*)malloc( s*2+s/4+1 ); /* n is size in uint32, maximum %x len is 8 chars and \0*/
1757 if (!str)
1758 return strdup("malloc failed");
1759
1760 p = str;
Marcus Meissner0546a762012-04-10 18:49:10 +02001761 for (i=0; i < n; ++i)
1762 p += sprintf(p, "%x,", dtoh32a( *data + 4*i ));
Marcus Meissner0546a762012-04-10 18:49:10 +02001763 return str;
1764}
1765
1766static inline uint32_t
1767ptp_pack_EOS_CustomFuncEx (PTPParams* params, unsigned char* data, char* str)
1768{
1769 uint32_t s = strtoul(str, NULL, 16);
1770 uint32_t n = s/4, i, v;
1771
1772 if (!data)
1773 return s;
1774
1775 for (i=0; i<n; i++)
1776 {
1777 v = strtoul(str, &str, 16);
Linus Walleija381e8a2013-03-05 21:00:06 +01001778 str++; /* skip the ',' delimiter */
Marcus Meissner0546a762012-04-10 18:49:10 +02001779 htod32a(data + i*4, v);
1780 }
1781
Linus Walleij1a0c3012009-07-23 23:06:58 +00001782 return s;
1783}
1784
Linus Walleijb02a0662006-04-25 08:05:09 +00001785/*
Linus Walleijf0bf4372007-07-01 21:47:38 +00001786 PTP EOS Changes Entry unpack
1787*/
1788#define PTP_ece_Size 0
1789#define PTP_ece_Type 4
1790
1791#define PTP_ece_Prop_Subtype 8 /* only for properties */
1792#define PTP_ece_Prop_Val_Data 0xc /* only for properties */
1793#define PTP_ece_Prop_Desc_Type 0xc /* only for property descs */
1794#define PTP_ece_Prop_Desc_Count 0x10 /* only for property descs */
1795#define PTP_ece_Prop_Desc_Data 0x14 /* only for property descs */
1796
Linus Walleijd4637502009-06-14 23:03:33 +00001797/* for PTP_EC_CANON_EOS_RequestObjectTransfer */
1798#define PTP_ece_OI_ObjectID 8
1799#define PTP_ece_OI_OFC 0x0c
1800#define PTP_ece_OI_Size 0x14
1801#define PTP_ece_OI_Name 0x1c
1802
1803/* for PTP_EC_CANON_EOS_ObjectAddedEx */
1804#define PTP_ece_OA_ObjectID 8
1805#define PTP_ece_OA_StorageID 0x0c
1806#define PTP_ece_OA_OFC 0x10
1807#define PTP_ece_OA_Size 0x1c
1808#define PTP_ece_OA_Parent 0x20
1809#define PTP_ece_OA_Name 0x28
Linus Walleijf0bf4372007-07-01 21:47:38 +00001810
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001811#define PTP_ece2_OA_ObjectID 8 /* OK */
1812#define PTP_ece2_OA_StorageID 0x0c /* OK */
1813#define PTP_ece2_OA_OFC 0x10 /* OK */
1814#define PTP_ece2_OA_Size 0x1c /* OK, might be 64 bit now? */
1815#define PTP_ece2_OA_Parent 0x24
1816#define PTP_ece2_OA_2ndOID 0x28
1817#define PTP_ece2_OA_Name 0x2c /* OK */
1818
1819/* for PTP_EC_CANON_EOS_ObjectAddedNew */
1820#define PTP_ece_OAN_OFC 0x0c
1821#define PTP_ece_OAN_Size 0x14
1822
Marcus Meissner3d692dc2016-02-21 12:34:06 +01001823static PTPDevicePropDesc*
1824_lookup_or_allocate_canon_prop(PTPParams *params, uint16_t proptype)
1825{
1826 unsigned int j;
1827
1828 for (j=0;j<params->nrofcanon_props;j++)
1829 if (params->canon_props[j].proptype == proptype)
1830 break;
1831 if (j<params->nrofcanon_props)
1832 return &params->canon_props[j].dpd;
1833
1834 if (j)
1835 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
1836 else
1837 params->canon_props = malloc(sizeof(params->canon_props[0]));
1838 params->canon_props[j].proptype = proptype;
1839 params->canon_props[j].size = 0;
1840 params->canon_props[j].data = NULL;
1841 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
1842 params->canon_props[j].dpd.GetSet = 1;
1843 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
1844 params->nrofcanon_props = j+1;
1845 return &params->canon_props[j].dpd;
1846}
1847
1848
Linus Walleijf0bf4372007-07-01 21:47:38 +00001849static inline int
Linus Walleij9783ce32014-06-02 21:44:29 +02001850ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **pce)
Linus Walleijf0bf4372007-07-01 21:47:38 +00001851{
1852 int i = 0, entries = 0;
1853 unsigned char *curdata = data;
Linus Walleij9783ce32014-06-02 21:44:29 +02001854 PTPCanon_changes_entry *ce;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001855
1856 if (data==NULL)
1857 return 0;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001858 while (curdata - data + 8 < datasize) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00001859 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1860 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1861
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001862 if (size > datasize) {
1863 ptp_debug (params, "size %d is larger than datasize %d", size, datasize);
1864 break;
1865 }
1866 if (size < 8) {
1867 ptp_debug (params, "size %d is smaller than 8.", size);
1868 break;
1869 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00001870 if ((size == 8) && (type == 0))
1871 break;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001872 if ((curdata - data) + size >= datasize) {
1873 ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries");
1874 break;
1875 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001876 if (type == PTP_EC_CANON_EOS_OLCInfoChanged) {
1877 unsigned int j;
1878
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001879 entries++;
1880 if (size >= 12+2) {
1881 for (j=0;j<31;j++)
1882 if (dtoh16a(curdata+12) & (1<<j))
1883 entries++;
1884 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001885 }
1886 curdata += size;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001887 entries++;
1888 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001889 ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
1890 if (!ce) return 0;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001891
1892 curdata = data;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001893 while (curdata - data + 8 < datasize) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00001894 uint32_t size = dtoh32a(&curdata[PTP_ece_Size]);
1895 uint32_t type = dtoh32a(&curdata[PTP_ece_Type]);
1896
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001897 if (size > datasize) {
1898 ptp_debug (params, "size %d is larger than datasize %d", size, datasize);
1899 break;
1900 }
1901 if (size < 8) {
1902 ptp_debug (params, "size %d is smaller than 8", size);
1903 break;
1904 }
1905
1906 if ((size == 8) && (type == 0))
1907 break;
1908
1909 if ((curdata - data) + size >= datasize) {
1910 ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries");
1911 break;
1912 }
1913
Linus Walleij9783ce32014-06-02 21:44:29 +02001914 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1915 ce[i].u.info = NULL;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001916 switch (type) {
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001917 case PTP_EC_CANON_EOS_ObjectAddedEx:
1918 if (size < PTP_ece_OA_Name+1) {
1919 ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OA_Name+1);
1920 break;
1921 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001922 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1923 ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001924 ce[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece_OA_StorageID]);
Linus Walleij9783ce32014-06-02 21:44:29 +02001925 ce[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece_OA_Parent]);
1926 ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OA_OFC]);
1927 ce[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece_OA_Size]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001928 ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OA_Name]));
Linus Walleij9783ce32014-06-02 21:44:29 +02001929 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 +00001930 break;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001931 case PTP_EC_CANON_EOS_ObjectAddedUnknown: /* FIXME: review if the data used is correct */
1932 if (size < PTP_ece2_OA_Name+1) {
1933 ptp_debug (params, "size %d is smaller than %d", size, PTP_ece2_OA_Name+1);
1934 break;
1935 }
1936 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1937 ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece2_OA_ObjectID]);
1938 ce[i].u.object.oi.StorageID = dtoh32a(&curdata[PTP_ece2_OA_StorageID]);
1939 ce[i].u.object.oi.ParentObject = dtoh32a(&curdata[PTP_ece2_OA_Parent]);
1940 ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece2_OA_OFC]);
1941 ce[i].u.object.oi.ObjectCompressedSize= dtoh32a(&curdata[PTP_ece2_OA_Size]); /* FIXME: might be 64bit now */
1942 ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece2_OA_Name]));
1943 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);
1944 break;
1945 case PTP_EC_CANON_EOS_RequestObjectTransfer:
1946 case PTP_EC_CANON_EOS_RequestObjectTransferNew: /* FIXME: confirm */
1947 if (size < PTP_ece_OI_Name+1) {
1948 ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_OI_Name+1);
1949 break;
1950 }
Linus Walleij9783ce32014-06-02 21:44:29 +02001951 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
1952 ce[i].u.object.oid = dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001953 ce[i].u.object.oi.StorageID = 0; /* use as marker */
Linus Walleij9783ce32014-06-02 21:44:29 +02001954 ce[i].u.object.oi.ObjectFormat = dtoh16a(&curdata[PTP_ece_OI_OFC]);
1955 ce[i].u.object.oi.ParentObject = 0; /* check, but use as marker */
1956 ce[i].u.object.oi.ObjectCompressedSize = dtoh32a(&curdata[PTP_ece_OI_Size]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001957 ce[i].u.object.oi.Filename = strdup(((char*)&curdata[PTP_ece_OI_Name]));
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001958
Linus Walleij9783ce32014-06-02 21:44:29 +02001959 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 +00001960 break;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001961 case PTP_EC_CANON_EOS_AvailListChanged: { /* property desc */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001962 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
1963 uint32_t propxtype = dtoh32a(&curdata[PTP_ece_Prop_Desc_Type]);
1964 uint32_t propxcnt = dtoh32a(&curdata[PTP_ece_Prop_Desc_Count]);
Linus Walleije206af62011-04-19 01:51:39 +02001965 unsigned char *xdata = &curdata[PTP_ece_Prop_Desc_Data];
Linus Walleij2ad5b722013-11-04 02:07:44 +01001966 unsigned int j;
Linus Walleijf0bf4372007-07-01 21:47:38 +00001967 PTPDevicePropDesc *dpd;
1968
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001969 if (size < PTP_ece_Prop_Desc_Data) {
1970 ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Desc_Data);
1971 break;
1972 }
1973
Linus Walleij7e756532009-05-06 21:25:09 +00001974 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 +00001975 for (j=0;j<params->nrofcanon_props;j++)
1976 if (params->canon_props[j].proptype == proptype)
1977 break;
1978 if (j==params->nrofcanon_props) {
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001979 ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001980 break;
1981 }
1982 dpd = &params->canon_props[j].dpd;
Linus Walleij7e756532009-05-06 21:25:09 +00001983 /* 1 - uint16 ?
1984 * 3 - uint16
1985 * 7 - string?
1986 */
Linus Walleijf0bf4372007-07-01 21:47:38 +00001987 if (propxtype != 3) {
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01001988 ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled, size %d", i, propxtype, proptype, size);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00001989 for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02001990 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00001991 break;
1992 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00001993 if (! propxcnt)
1994 break;
Linus Walleij9783ce32014-06-02 21:44:29 +02001995 if (propxcnt >= 2<<16) /* buggy or exploit */
1996 break;
Linus Walleij1a0c3012009-07-23 23:06:58 +00001997
1998 ptp_debug (params, "event %d: propxtype is %x, prop is 0x%04x, data type is 0x%04x, propxcnt is %d.",
1999 i, propxtype, proptype, dpd->DataType, propxcnt);
2000 dpd->FormFlag = PTP_DPFF_Enumeration;
2001 dpd->FORM.Enum.NumberOfValues = propxcnt;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002002 free (dpd->FORM.Enum.SupportedValue);
Linus Walleij1a0c3012009-07-23 23:06:58 +00002003 dpd->FORM.Enum.SupportedValue = malloc (sizeof (PTPPropertyValue)*propxcnt);
2004
2005 switch (proptype) {
2006 case PTP_DPC_CANON_EOS_ImageFormat:
2007 case PTP_DPC_CANON_EOS_ImageFormatCF:
2008 case PTP_DPC_CANON_EOS_ImageFormatSD:
2009 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
2010 /* special handling of ImageFormat properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00002011 for (j=0;j<propxcnt;j++) {
Linus Walleij1a0c3012009-07-23 23:06:58 +00002012 dpd->FORM.Enum.SupportedValue[j].u16 =
Linus Walleij9783ce32014-06-02 21:44:29 +02002013 ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00002014 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, dpd->FORM.Enum.SupportedValue[j].u16);
2015 }
2016 break;
2017 default:
2018 /* 'normal' enumerated types */
2019 switch (dpd->DataType) {
2020#define XX( TYPE, CONV )\
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002021 if (sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data > size) { \
2022 ptp_debug (params, "size %d does not match needed %d", sizeof(dpd->FORM.Enum.SupportedValue[j].TYPE)*propxcnt + PTP_ece_Prop_Desc_Data, size); \
2023 break; \
2024 } \
2025 for (j=0;j<propxcnt;j++) { \
2026 dpd->FORM.Enum.SupportedValue[j].TYPE = CONV(xdata); \
Linus Walleije206af62011-04-19 01:51:39 +02002027 ptp_debug (params, "event %d: suppval[%d] of %x is 0x%x.", i, j, proptype, CONV(xdata)); \
2028 xdata += 4; /* might only be for propxtype 3 */ \
Linus Walleij1a0c3012009-07-23 23:06:58 +00002029 } \
2030 break;
2031
2032 case PTP_DTC_INT16: XX( i16, dtoh16a );
2033 case PTP_DTC_UINT32: XX( u32, dtoh32a );
2034 case PTP_DTC_UINT16: XX( u16, dtoh16a );
2035 case PTP_DTC_UINT8: XX( u8, dtoh8a );
2036#undef XX
2037 default:
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002038 free (dpd->FORM.Enum.SupportedValue);
2039 dpd->FORM.Enum.SupportedValue = NULL;
2040 dpd->FORM.Enum.NumberOfValues = 0;
2041 ptp_debug (params ,"event %d: data type 0x%04x of %x unhandled, size %d, raw values:", i, dpd->DataType, proptype, dtoh32a(xdata), size);
Linus Walleije206af62011-04-19 01:51:39 +02002042 for (j=0;j<(size-PTP_ece_Prop_Desc_Data)/4;j++, xdata+=4) /* 4 is good for propxtype 3 */
2043 ptp_debug (params, " %3d: 0x%8x", j, dtoh32a(xdata));
Linus Walleij1a0c3012009-07-23 23:06:58 +00002044 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002045 }
2046 }
2047 break;
2048 }
Linus Walleij7e756532009-05-06 21:25:09 +00002049 case PTP_EC_CANON_EOS_PropValueChanged:
Linus Walleijf0bf4372007-07-01 21:47:38 +00002050 if (size >= 0xc) { /* property info */
Linus Walleij2ad5b722013-11-04 02:07:44 +01002051 unsigned int j;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002052 uint32_t proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
Linus Walleije206af62011-04-19 01:51:39 +02002053 unsigned char *xdata = &curdata[PTP_ece_Prop_Val_Data];
Linus Walleijf0bf4372007-07-01 21:47:38 +00002054 PTPDevicePropDesc *dpd;
2055
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002056 if (size < PTP_ece_Prop_Val_Data) {
2057 ptp_debug (params, "size %d is smaller than %d", size, PTP_ece_Prop_Val_Data);
2058 break;
2059 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00002060 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 +00002061 for (j=0;j<params->nrofcanon_props;j++)
2062 if (params->canon_props[j].proptype == proptype)
2063 break;
2064 if (j<params->nrofcanon_props) {
2065 if ( (params->canon_props[j].size != size) ||
Linus Walleije206af62011-04-19 01:51:39 +02002066 (memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
Linus Walleijf0bf4372007-07-01 21:47:38 +00002067 params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002068 params->canon_props[j].size = size;
Linus Walleije206af62011-04-19 01:51:39 +02002069 memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002070 }
2071 } else {
2072 if (j)
2073 params->canon_props = realloc(params->canon_props, sizeof(params->canon_props[0])*(j+1));
2074 else
2075 params->canon_props = malloc(sizeof(params->canon_props[0]));
Linus Walleijf0bf4372007-07-01 21:47:38 +00002076 params->canon_props[j].proptype = proptype;
2077 params->canon_props[j].size = size;
2078 params->canon_props[j].data = malloc(size-PTP_ece_Prop_Val_Data);
Linus Walleije206af62011-04-19 01:51:39 +02002079 memcpy(params->canon_props[j].data, xdata, size-PTP_ece_Prop_Val_Data);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002080 memset (&params->canon_props[j].dpd,0,sizeof(params->canon_props[j].dpd));
2081 params->canon_props[j].dpd.GetSet = 1;
2082 params->canon_props[j].dpd.FormFlag = PTP_DPFF_None;
2083 params->nrofcanon_props = j+1;
2084 }
2085 dpd = &params->canon_props[j].dpd;
Linus Walleij1a0c3012009-07-23 23:06:58 +00002086
Linus Walleij9783ce32014-06-02 21:44:29 +02002087 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2088 ce[i].u.propid = proptype;
Linus Walleijd7072c32010-12-07 20:43:00 +00002089
Linus Walleij1a0c3012009-07-23 23:06:58 +00002090 /* fix GetSet value */
2091 switch (proptype) {
2092#define XX(x) case PTP_DPC_CANON_##x:
2093 XX(EOS_FocusMode)
2094 XX(EOS_BatteryPower)
2095 XX(EOS_BatterySelect)
2096 XX(EOS_ModelID)
2097 XX(EOS_PTPExtensionVersion)
2098 XX(EOS_DPOFVersion)
2099 XX(EOS_AvailableShots)
2100 XX(EOS_CurrentStorage)
2101 XX(EOS_CurrentFolder)
2102 XX(EOS_MyMenu)
2103 XX(EOS_MyMenuList)
2104 XX(EOS_HDDirectoryStructure)
2105 XX(EOS_BatteryInfo)
2106 XX(EOS_AdapterInfo)
2107 XX(EOS_LensStatus)
2108 XX(EOS_CardExtension)
2109 XX(EOS_TempStatus)
2110 XX(EOS_ShutterCounter)
2111 XX(EOS_SerialNumber)
2112 XX(EOS_DepthOfFieldPreview)
2113 XX(EOS_EVFRecordStatus)
2114 XX(EOS_LvAfSystem)
2115 XX(EOS_FocusInfoEx)
2116 XX(EOS_DepthOfField)
2117 XX(EOS_Brightness)
2118 XX(EOS_EFComp)
2119 XX(EOS_LensName)
2120 XX(EOS_LensID)
2121#undef XX
2122 dpd->GetSet = PTP_DPGS_Get;
2123 break;
2124 }
2125
2126 /* set DataType */
Linus Walleijf0bf4372007-07-01 21:47:38 +00002127 switch (proptype) {
Linus Walleijac052c12007-07-18 18:37:10 +00002128 case PTP_DPC_CANON_EOS_CameraTime:
Linus Walleij9783ce32014-06-02 21:44:29 +02002129 case PTP_DPC_CANON_EOS_UTCTime:
2130 case PTP_DPC_CANON_EOS_Summertime: /* basical the DST flag */
Linus Walleijd4637502009-06-14 23:03:33 +00002131 case PTP_DPC_CANON_EOS_AvailableShots:
Linus Walleijd4637502009-06-14 23:03:33 +00002132 case PTP_DPC_CANON_EOS_CaptureDestination:
2133 case PTP_DPC_CANON_EOS_WhiteBalanceXA:
2134 case PTP_DPC_CANON_EOS_WhiteBalanceXB:
Linus Walleijd4637502009-06-14 23:03:33 +00002135 case PTP_DPC_CANON_EOS_CurrentStorage:
2136 case PTP_DPC_CANON_EOS_CurrentFolder:
2137 case PTP_DPC_CANON_EOS_ShutterCounter:
2138 case PTP_DPC_CANON_EOS_ModelID:
2139 case PTP_DPC_CANON_EOS_LensID:
2140 case PTP_DPC_CANON_EOS_StroboFiring:
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002141 case PTP_DPC_CANON_EOS_AFSelectFocusArea:
2142 case PTP_DPC_CANON_EOS_ContinousAFMode:
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002143 case PTP_DPC_CANON_EOS_MirrorUpSetting:
Linus Walleijac052c12007-07-18 18:37:10 +00002144 dpd->DataType = PTP_DTC_UINT32;
2145 break;
Linus Walleij0d762cc2010-04-04 23:34:27 +00002146 /* enumeration for AEM is never provided, but is available to set */
2147 case PTP_DPC_CANON_EOS_AutoExposureMode:
2148 dpd->DataType = PTP_DTC_UINT16;
2149 dpd->FormFlag = PTP_DPFF_Enumeration;
2150 dpd->FORM.Enum.NumberOfValues = 0;
2151 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002152 case PTP_DPC_CANON_EOS_Aperture:
2153 case PTP_DPC_CANON_EOS_ShutterSpeed:
2154 case PTP_DPC_CANON_EOS_ISOSpeed:
Linus Walleij7e756532009-05-06 21:25:09 +00002155 case PTP_DPC_CANON_EOS_FocusMode:
Linus Walleij7e756532009-05-06 21:25:09 +00002156 case PTP_DPC_CANON_EOS_ColorSpace:
2157 case PTP_DPC_CANON_EOS_BatteryPower:
Linus Walleije29ca682010-01-30 08:15:25 +00002158 case PTP_DPC_CANON_EOS_BatterySelect:
Linus Walleijd4637502009-06-14 23:03:33 +00002159 case PTP_DPC_CANON_EOS_PTPExtensionVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00002160 case PTP_DPC_CANON_EOS_DriveMode:
2161 case PTP_DPC_CANON_EOS_AEB:
Linus Walleije29ca682010-01-30 08:15:25 +00002162 case PTP_DPC_CANON_EOS_BracketMode:
2163 case PTP_DPC_CANON_EOS_QuickReviewTime:
Linus Walleij0d762cc2010-04-04 23:34:27 +00002164 case PTP_DPC_CANON_EOS_EVFMode:
2165 case PTP_DPC_CANON_EOS_EVFOutputDevice:
Linus Walleija381e8a2013-03-05 21:00:06 +01002166 case PTP_DPC_CANON_EOS_AutoPowerOff:
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002167 case PTP_DPC_CANON_EOS_EVFRecordStatus:
Linus Walleijf0bf4372007-07-01 21:47:38 +00002168 dpd->DataType = PTP_DTC_UINT16;
2169 break;
2170 case PTP_DPC_CANON_EOS_PictureStyle:
2171 case PTP_DPC_CANON_EOS_WhiteBalance:
2172 case PTP_DPC_CANON_EOS_MeteringMode:
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002173 case PTP_DPC_CANON_EOS_ExpCompensation:
Linus Walleijf0bf4372007-07-01 21:47:38 +00002174 dpd->DataType = PTP_DTC_UINT8;
2175 break;
2176 case PTP_DPC_CANON_EOS_Owner:
Linus Walleij1a0c3012009-07-23 23:06:58 +00002177 case PTP_DPC_CANON_EOS_Artist:
2178 case PTP_DPC_CANON_EOS_Copyright:
2179 case PTP_DPC_CANON_EOS_SerialNumber:
2180 case PTP_DPC_CANON_EOS_LensName:
Linus Walleijf0bf4372007-07-01 21:47:38 +00002181 dpd->DataType = PTP_DTC_STR;
2182 break;
Linus Walleij7e756532009-05-06 21:25:09 +00002183 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustA:
2184 case PTP_DPC_CANON_EOS_WhiteBalanceAdjustB:
2185 dpd->DataType = PTP_DTC_INT16;
2186 break;
2187 /* unknown props, listed from dump.... all 16 bit, but vals might be smaller */
Linus Walleij7e756532009-05-06 21:25:09 +00002188 case PTP_DPC_CANON_EOS_DPOFVersion:
Linus Walleij1a0c3012009-07-23 23:06:58 +00002189 dpd->DataType = PTP_DTC_UINT16;
2190 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint16", i ,proptype, size-PTP_ece_Prop_Val_Data);
2191 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02002192 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00002193 break;
Linus Walleij7e756532009-05-06 21:25:09 +00002194 case PTP_DPC_CANON_EOS_CustomFunc1:
2195 case PTP_DPC_CANON_EOS_CustomFunc2:
2196 case PTP_DPC_CANON_EOS_CustomFunc3:
2197 case PTP_DPC_CANON_EOS_CustomFunc4:
2198 case PTP_DPC_CANON_EOS_CustomFunc5:
2199 case PTP_DPC_CANON_EOS_CustomFunc6:
2200 case PTP_DPC_CANON_EOS_CustomFunc7:
2201 case PTP_DPC_CANON_EOS_CustomFunc8:
2202 case PTP_DPC_CANON_EOS_CustomFunc9:
2203 case PTP_DPC_CANON_EOS_CustomFunc10:
2204 case PTP_DPC_CANON_EOS_CustomFunc11:
Linus Walleij1a0c3012009-07-23 23:06:58 +00002205 dpd->DataType = PTP_DTC_UINT8;
2206 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 +00002207 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02002208 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleij1a0c3012009-07-23 23:06:58 +00002209 /* 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 +02002210 xdata += 4;
Linus Walleij7e756532009-05-06 21:25:09 +00002211 break;
2212 /* yet unknown 32bit props */
2213 case PTP_DPC_CANON_EOS_ColorTemperature:
Linus Walleij7e756532009-05-06 21:25:09 +00002214 case PTP_DPC_CANON_EOS_WftStatus:
2215 case PTP_DPC_CANON_EOS_LensStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00002216 case PTP_DPC_CANON_EOS_CardExtension:
2217 case PTP_DPC_CANON_EOS_TempStatus:
Linus Walleij7e756532009-05-06 21:25:09 +00002218 case PTP_DPC_CANON_EOS_PhotoStudioMode:
Linus Walleij7e756532009-05-06 21:25:09 +00002219 case PTP_DPC_CANON_EOS_DepthOfFieldPreview:
2220 case PTP_DPC_CANON_EOS_EVFSharpness:
2221 case PTP_DPC_CANON_EOS_EVFWBMode:
2222 case PTP_DPC_CANON_EOS_EVFClickWBCoeffs:
2223 case PTP_DPC_CANON_EOS_EVFColorTemp:
Linus Walleijd4637502009-06-14 23:03:33 +00002224 case PTP_DPC_CANON_EOS_ExposureSimMode:
2225 case PTP_DPC_CANON_EOS_LvAfSystem:
2226 case PTP_DPC_CANON_EOS_MovSize:
2227 case PTP_DPC_CANON_EOS_DepthOfField:
2228 case PTP_DPC_CANON_EOS_LvViewTypeSelect:
Linus Walleij2ad5b722013-11-04 02:07:44 +01002229 case PTP_DPC_CANON_EOS_AloMode:
Linus Walleij9783ce32014-06-02 21:44:29 +02002230 case PTP_DPC_CANON_EOS_Brightness:
Linus Walleij0d762cc2010-04-04 23:34:27 +00002231 dpd->DataType = PTP_DTC_UINT32;
Linus Walleij7e756532009-05-06 21:25:09 +00002232 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 +00002233 if ((size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) != 0)
2234 ptp_debug (params, "event %d: Warning: datasize modulo sizeof(uint32) is not 0: ", i, (size-PTP_ece_Prop_Val_Data) % sizeof(uint32_t) );
2235 for (j=0;j<(size-PTP_ece_Prop_Val_Data)/sizeof(uint32_t);j++)
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002236 ptp_debug (params, " %d: 0x%8x", j, dtoh32a(xdata+j*4));
Linus Walleij7e756532009-05-06 21:25:09 +00002237 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00002238 /* ImageFormat properties have to be ignored here, see special handling below */
2239 case PTP_DPC_CANON_EOS_ImageFormat:
2240 case PTP_DPC_CANON_EOS_ImageFormatCF:
2241 case PTP_DPC_CANON_EOS_ImageFormatSD:
2242 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
Marcus Meissner0546a762012-04-10 18:49:10 +02002243 case PTP_DPC_CANON_EOS_CustomFuncEx:
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002244 case PTP_DPC_CANON_EOS_FocusInfoEx:
Linus Walleijd7072c32010-12-07 20:43:00 +00002245 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002246 default:
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00002247 ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d", i ,proptype, size-PTP_ece_Prop_Val_Data);
2248 for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
Linus Walleije206af62011-04-19 01:51:39 +02002249 ptp_debug (params, " %d: %02x", j, xdata[j]);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002250 break;
2251 }
2252 switch (dpd->DataType) {
Linus Walleijac052c12007-07-18 18:37:10 +00002253 case PTP_DTC_UINT32:
Linus Walleije206af62011-04-19 01:51:39 +02002254 dpd->FactoryDefaultValue.u32 = dtoh32a(xdata);
2255 dpd->CurrentValue.u32 = dtoh32a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00002256 ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
Linus Walleijac052c12007-07-18 18:37:10 +00002257 break;
Linus Walleij2ad5b722013-11-04 02:07:44 +01002258 case PTP_DTC_INT16:
2259 dpd->FactoryDefaultValue.i16 = dtoh16a(xdata);
2260 dpd->CurrentValue.i16 = dtoh16a(xdata);
2261 ptp_debug (params,"event %d: currentvalue of %x is %d", i, proptype, dpd->CurrentValue.i16);
2262 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002263 case PTP_DTC_UINT16:
Linus Walleije206af62011-04-19 01:51:39 +02002264 dpd->FactoryDefaultValue.u16 = dtoh16a(xdata);
2265 dpd->CurrentValue.u16 = dtoh16a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00002266 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002267 break;
2268 case PTP_DTC_UINT8:
Linus Walleije206af62011-04-19 01:51:39 +02002269 dpd->FactoryDefaultValue.u8 = dtoh8a(xdata);
2270 dpd->CurrentValue.u8 = dtoh8a(xdata);
Linus Walleij3bc0d7f2008-11-01 23:06:24 +00002271 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002272 break;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002273 case PTP_DTC_INT8:
2274 dpd->FactoryDefaultValue.i8 = dtoh8a(xdata);
2275 dpd->CurrentValue.i8 = dtoh8a(xdata);
2276 ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.i8);
2277 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002278 case PTP_DTC_STR: {
Linus Walleij1a0c3012009-07-23 23:06:58 +00002279#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
Linus Walleijf0bf4372007-07-01 21:47:38 +00002280 uint8_t len = 0;
2281 dpd->FactoryDefaultValue.str = ptp_unpack_string(params, data, 0, &len);
2282 dpd->CurrentValue.str = ptp_unpack_string(params, data, 0, &len);
Linus Walleij1a0c3012009-07-23 23:06:58 +00002283#else
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002284 free (dpd->FactoryDefaultValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02002285 dpd->FactoryDefaultValue.str = strdup( (char*)xdata );
Linus Walleij0d762cc2010-04-04 23:34:27 +00002286
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002287 free (dpd->CurrentValue.str);
Linus Walleije206af62011-04-19 01:51:39 +02002288 dpd->CurrentValue.str = strdup( (char*)xdata );
Linus Walleij1a0c3012009-07-23 23:06:58 +00002289#endif
Linus Walleij7e756532009-05-06 21:25:09 +00002290 ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
Linus Walleijf0bf4372007-07-01 21:47:38 +00002291 break;
2292 }
2293 default:
2294 /* debug is printed in switch above this one */
2295 break;
2296 }
Linus Walleij1a0c3012009-07-23 23:06:58 +00002297
Marcus Meissner0546a762012-04-10 18:49:10 +02002298 /* ImageFormat and customFuncEx special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
Linus Walleijd7072c32010-12-07 20:43:00 +00002299 switch (proptype) {
2300 case PTP_DPC_CANON_EOS_ImageFormat:
2301 case PTP_DPC_CANON_EOS_ImageFormatCF:
2302 case PTP_DPC_CANON_EOS_ImageFormatSD:
2303 case PTP_DPC_CANON_EOS_ImageFormatExtHD:
2304 dpd->DataType = PTP_DTC_UINT16;
Linus Walleije206af62011-04-19 01:51:39 +02002305 dpd->FactoryDefaultValue.u16 = ptp_unpack_EOS_ImageFormat( params, &xdata );
Linus Walleijd7072c32010-12-07 20:43:00 +00002306 dpd->CurrentValue.u16 = dpd->FactoryDefaultValue.u16;
2307 ptp_debug (params,"event %d: decoded imageformat, currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
2308 break;
Marcus Meissner0546a762012-04-10 18:49:10 +02002309 case PTP_DPC_CANON_EOS_CustomFuncEx:
2310 dpd->DataType = PTP_DTC_STR;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002311 free (dpd->FactoryDefaultValue.str);
2312 free (dpd->CurrentValue.str);
2313 dpd->FactoryDefaultValue.str = ptp_unpack_EOS_CustomFuncEx( params, &xdata );
Marcus Meissner0546a762012-04-10 18:49:10 +02002314 dpd->CurrentValue.str = strdup( (char*)dpd->FactoryDefaultValue.str );
2315 ptp_debug (params,"event %d: decoded custom function, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
2316 break;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002317 case PTP_DPC_CANON_EOS_FocusInfoEx:
2318 dpd->DataType = PTP_DTC_STR;
2319 free (dpd->FactoryDefaultValue.str);
2320 free (dpd->CurrentValue.str);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002321 dpd->FactoryDefaultValue.str = ptp_unpack_EOS_FocusInfoEx( params, &xdata, size );
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002322 dpd->CurrentValue.str = strdup( (char*)dpd->FactoryDefaultValue.str );
2323 ptp_debug (params,"event %d: decoded focus info, currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
2324 break;
Linus Walleijd7072c32010-12-07 20:43:00 +00002325 }
2326
Linus Walleijf0bf4372007-07-01 21:47:38 +00002327 break;
2328 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002329 /* one more information record handed to us */
2330 case PTP_EC_CANON_EOS_OLCInfoChanged: {
2331 uint32_t len, curoff;
2332 uint16_t mask,proptype;
Linus Walleij9783ce32014-06-02 21:44:29 +02002333 PTPDevicePropDesc *dpd;
2334
2335 /* unclear what OLC stands for */
2336 ptp_debug (params, "event %d: EOS event OLCInfoChanged (size %d)", i, size);
2337 if (size >= 0x8) { /* event info */
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002338 unsigned int k;
2339 for (k=8;k<size;k++)
2340 ptp_debug (params, " %d: %02x", k-8, curdata[k]);
Linus Walleij9783ce32014-06-02 21:44:29 +02002341 }
2342 len = dtoh32a(curdata+8);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002343 if ((len != size-8) && (len != size-4)) {
Linus Walleij9783ce32014-06-02 21:44:29 +02002344 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002345 ce[i].u.info = strdup("OLC size unexpected");
2346 ptp_debug (params, "event %d: OLC unexpected size %d for blob len %d (not -4 nor -8)", i, size, len);
Linus Walleij9783ce32014-06-02 21:44:29 +02002347 break;
2348 }
2349 mask = dtoh16a(curdata+8+4);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002350 if (size < 14) {
2351 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2352 ce[i].u.info = strdup("OLC size too small");
2353 ptp_debug (params, "event %d: OLC unexpected size %d", i, size);
2354 break;
2355 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002356 curoff = 8+4+4;
2357 if (mask & CANON_EOS_OLC_BUTTON) {
2358 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2359 ce[i].u.info = malloc(strlen("Button 1234567"));
2360 sprintf(ce[i].u.info, "Button %d", dtoh16a(curdata+curoff));
2361 i++;
2362 curoff += 2;
2363 }
2364
2365 if (mask & CANON_EOS_OLC_SHUTTERSPEED) {
2366 /* 6 bytes: 01 01 98 10 00 60 */
2367 /* this seesm to be the shutter speed record */
2368 proptype = PTP_DPC_CANON_EOS_ShutterSpeed;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002369 dpd = _lookup_or_allocate_canon_prop(params, proptype);
Linus Walleij9783ce32014-06-02 21:44:29 +02002370 dpd->CurrentValue.u16 = curdata[curoff+5]; /* just use last byte */
2371
2372 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2373 ce[i].u.propid = proptype;
2374 curoff += 6;
2375 i++;
2376 }
2377 if (mask & CANON_EOS_OLC_APERTURE) {
2378 /* 5 bytes: 01 01 5b 30 30 */
2379 /* this seesm to be the aperture record */
2380 proptype = PTP_DPC_CANON_EOS_Aperture;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002381 dpd = _lookup_or_allocate_canon_prop(params, proptype);
Linus Walleij9783ce32014-06-02 21:44:29 +02002382 dpd->CurrentValue.u16 = curdata[curoff+4]; /* just use last byte */
2383
2384 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2385 ce[i].u.propid = proptype;
2386 curoff += 5;
2387 i++;
2388 }
2389 if (mask & CANON_EOS_OLC_ISO) {
2390 /* 5 bytes: 01 01 00 78 */
2391 /* this seesm to be the aperture record */
2392 proptype = PTP_DPC_CANON_EOS_ISOSpeed;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002393 dpd = _lookup_or_allocate_canon_prop(params, proptype);
Linus Walleij9783ce32014-06-02 21:44:29 +02002394 dpd->CurrentValue.u16 = curdata[curoff+3]; /* just use last byte */
2395
2396 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2397 ce[i].u.propid = proptype;
2398 curoff += 4;
2399 i++;
2400 }
2401 if (mask & 0x0010) {
2402 /* mask 0x0010: 4 bytes, 04 00 00 00 observed */
2403 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2404 ce[i].u.info = malloc(strlen("OLCInfo event 0x0010 content 01234567")+1);
2405 sprintf(ce[i].u.info,"OLCInfo event 0x0010 content %02x%02x%02x%02x",
2406 curdata[curoff],
2407 curdata[curoff+1],
2408 curdata[curoff+2],
2409 curdata[curoff+3]
2410 );
2411 curoff += 4;
2412 i++;
2413 }
2414 if (mask & 0x0020) {
2415 /* mask 0x0020: 6 bytes, 00 00 00 00 00 00 observed */
2416 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2417 ce[i].u.info = malloc(strlen("OLCInfo event 0x0020 content 0123456789ab")+1);
2418 sprintf(ce[i].u.info,"OLCInfo event 0x0020 content %02x%02x%02x%02x%02x%02x",
2419 curdata[curoff],
2420 curdata[curoff+1],
2421 curdata[curoff+2],
2422 curdata[curoff+3],
2423 curdata[curoff+4],
2424 curdata[curoff+5]
2425 );
2426 curoff += 6;
2427 i++;
2428 }
2429 if (mask & 0x0040) {
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002430 int value = (signed char)curdata[curoff+2];
Linus Walleij9783ce32014-06-02 21:44:29 +02002431 /* mask 0x0040: 7 bytes, 01 01 00 00 00 00 00 observed */
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002432 /* exposure indicator */
Linus Walleij9783ce32014-06-02 21:44:29 +02002433 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002434 ce[i].u.info = malloc(strlen("OLCInfo exposure indicator 012345678901234567890123456789abcd")+1);
2435 sprintf(ce[i].u.info,"OLCInfo exposure indicator %d,%d,%d.%d (%02x%02x%02x%02x)",
Linus Walleij9783ce32014-06-02 21:44:29 +02002436 curdata[curoff],
2437 curdata[curoff+1],
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002438 value/10,abs(value)%10,
Linus Walleij9783ce32014-06-02 21:44:29 +02002439 curdata[curoff+3],
2440 curdata[curoff+4],
2441 curdata[curoff+5],
2442 curdata[curoff+6]
2443 );
2444 curoff += 7;
2445 i++;
2446 }
2447 if (mask & 0x0080) {
2448 /* mask 0x0080: 4 bytes, 00 00 00 00 observed */
2449 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2450 ce[i].u.info = malloc(strlen("OLCInfo event 0x0080 content 01234567")+1);
2451 sprintf(ce[i].u.info,"OLCInfo event 0x0080 content %02x%02x%02x%02x",
2452 curdata[curoff],
2453 curdata[curoff+1],
2454 curdata[curoff+2],
2455 curdata[curoff+3]
2456 );
2457 curoff += 4;
2458 i++;
2459 }
2460 if (mask & 0x0100) {
2461 /* mask 0x0100: 6 bytes, 00 00 00 00 00 00 (before focus) and 00 00 00 00 01 00 (on focus) observed */
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002462 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_FOCUSINFO;
2463 ce[i].u.info = malloc(strlen("0123456789ab")+1);
2464 sprintf(ce[i].u.info,"%02x%02x%02x%02x%02x%02x",
Linus Walleij9783ce32014-06-02 21:44:29 +02002465 curdata[curoff],
2466 curdata[curoff+1],
2467 curdata[curoff+2],
2468 curdata[curoff+3],
2469 curdata[curoff+4],
2470 curdata[curoff+5]
2471 );
2472 curoff += 6;
2473 i++;
2474 }
2475 if (mask & 0x0200) {
2476 /* mask 0x0200: 7 bytes, 00 00 00 00 00 00 00 observed */
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002477 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_FOCUSMASK;
2478 ce[i].u.info = malloc(strlen("0123456789abcd0123456789abcdef")+1);
2479 sprintf(ce[i].u.info,"%02x%02x%02x%02x%02x%02x%02x",
Linus Walleij9783ce32014-06-02 21:44:29 +02002480 curdata[curoff],
2481 curdata[curoff+1],
2482 curdata[curoff+2],
2483 curdata[curoff+3],
2484 curdata[curoff+4],
2485 curdata[curoff+5],
2486 curdata[curoff+6]
2487 );
2488 curoff += 7;
2489 i++;
2490 }
2491 if (mask & 0x0400) {
2492 /* mask 0x0400: 7 bytes, 00 00 00 00 00 00 00 observed */
2493 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2494 ce[i].u.info = malloc(strlen("OLCInfo event 0x0400 content 0123456789abcd")+1);
2495 sprintf(ce[i].u.info,"OLCInfo event 0x0400 content %02x%02x%02x%02x%02x%02x%02x",
2496 curdata[curoff],
2497 curdata[curoff+1],
2498 curdata[curoff+2],
2499 curdata[curoff+3],
2500 curdata[curoff+4],
2501 curdata[curoff+5],
2502 curdata[curoff+6]
2503 );
2504 curoff += 7;
2505 i++;
2506 }
2507 if (mask & 0x0800) {
2508 /* mask 0x0800: 8 bytes, 00 00 00 00 00 00 00 00 and 19 01 00 00 00 00 00 00 and others observed */
2509 /* might be mask of focus points selected */
2510 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2511 ce[i].u.info = malloc(strlen("OLCInfo event 0x0800 content 0123456789abcdef")+1);
2512 sprintf(ce[i].u.info,"OLCInfo event 0x0800 content %02x%02x%02x%02x%02x%02x%02x%02x",
2513 curdata[curoff],
2514 curdata[curoff+1],
2515 curdata[curoff+2],
2516 curdata[curoff+3],
2517 curdata[curoff+4],
2518 curdata[curoff+5],
2519 curdata[curoff+6],
2520 curdata[curoff+7]
2521 );
2522 curoff += 8;
2523 i++;
2524 }
2525 if (mask & 0x1000) {
2526 /* mask 0x1000: 1 byte, 00 observed */
2527 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2528 ce[i].u.info = malloc(strlen("OLCInfo event 0x1000 content 01")+1);
2529 sprintf(ce[i].u.info,"OLCInfo event 0x1000 content %02x",
2530 curdata[curoff]
2531 );
2532 curoff += 1;
2533 i++;
2534 }
2535 /* handle more masks */
2536 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2537 ce[i].u.info = malloc(strlen("OLCInfo event mask 0123456789")+1);
2538 sprintf(ce[i].u.info, "OLCInfo event mask=%x", mask);
2539 break;
2540 }
Linus Walleijd7072c32010-12-07 20:43:00 +00002541 case PTP_EC_CANON_EOS_CameraStatusChanged:
Linus Walleij9783ce32014-06-02 21:44:29 +02002542 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_CAMERASTATUS;
2543 ce[i].u.status = dtoh32a(curdata+8);
2544 ptp_debug (params, "event %d: EOS event CameraStatusChanged (size %d) = %d", i, size, dtoh32a(curdata+8));
Linus Walleij9e09ad02011-02-10 13:14:01 +01002545 params->eos_camerastatus = dtoh32a(curdata+8);
Linus Walleijd7072c32010-12-07 20:43:00 +00002546 break;
Linus Walleij7e756532009-05-06 21:25:09 +00002547 case 0: /* end marker */
2548 if (size == 8) /* no output */
2549 break;
2550 ptp_debug (params, "event %d: EOS event 0, but size %d", i, size);
2551 break;
Linus Walleij96aa0e32012-03-25 12:25:25 +02002552 case PTP_EC_CANON_EOS_BulbExposureTime:
Linus Walleij9783ce32014-06-02 21:44:29 +02002553 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002554 ce[i].u.info = malloc(strlen("BulbExposureTime 123456789012345678"));
Linus Walleij9783ce32014-06-02 21:44:29 +02002555 sprintf (ce[i].u.info, "BulbExposureTime %d", dtoh32a(curdata+8));
Linus Walleij96aa0e32012-03-25 12:25:25 +02002556 break;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002557 case PTP_EC_CANON_EOS_ObjectRemoved:
2558 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTREMOVED;
2559 ce[i].u.object.oid = dtoh32a(curdata+8);
2560 break;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002561 default:
Linus Walleijd4637502009-06-14 23:03:33 +00002562 switch (type) {
Linus Walleijd7072c32010-12-07 20:43:00 +00002563#define XX(x) case PTP_EC_CANON_EOS_##x: \
2564 ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); \
Linus Walleij9783ce32014-06-02 21:44:29 +02002565 ce[i].u.info = malloc(strlen("unhandled EOS event "#x" (size 123456789)")); \
2566 sprintf (ce[i].u.info, "unhandled EOS event "#x" (size %d)", size); \
Linus Walleijd7072c32010-12-07 20:43:00 +00002567 break;
Linus Walleijd4637502009-06-14 23:03:33 +00002568 XX(RequestGetEvent)
Linus Walleijd4637502009-06-14 23:03:33 +00002569 XX(RequestGetObjectInfoEx)
2570 XX(StorageStatusChanged)
2571 XX(StorageInfoChanged)
2572 XX(ObjectInfoChangedEx)
2573 XX(ObjectContentChanged)
Linus Walleijd4637502009-06-14 23:03:33 +00002574 XX(WillSoonShutdown)
2575 XX(ShutdownTimerUpdated)
2576 XX(RequestCancelTransfer)
2577 XX(RequestObjectTransferDT)
2578 XX(RequestCancelTransferDT)
2579 XX(StoreAdded)
2580 XX(StoreRemoved)
2581 XX(BulbExposureTime)
2582 XX(RecordingTime)
2583 XX(RequestObjectTransferTS)
2584 XX(AfResult)
2585#undef XX
2586 default:
2587 ptp_debug (params, "event %d: unknown EOS event %04x", i, type);
2588 break;
2589 }
Linus Walleij7e756532009-05-06 21:25:09 +00002590 if (size >= 0x8) { /* event info */
Linus Walleij2ad5b722013-11-04 02:07:44 +01002591 unsigned int j;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002592 /*ptp_debug (params, "data=%p, curdata=%p, datsize=%d, size=%d", data, curdata, datasize, size);*/
Linus Walleijd4637502009-06-14 23:03:33 +00002593 for (j=8;j<size;j++)
2594 ptp_debug (params, " %d: %02x", j, curdata[j]);
Linus Walleij7e756532009-05-06 21:25:09 +00002595 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002596 ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002597 break;
2598 }
2599 curdata += size;
Linus Walleij9783ce32014-06-02 21:44:29 +02002600 i++;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002601 if (i >= entries) {
2602 ptp_debug (params, "BAD: i %d, entries %d", i, entries);
2603 }
Linus Walleijf0bf4372007-07-01 21:47:38 +00002604 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002605 if (!i) {
2606 free (ce);
2607 ce = NULL;
Linus Walleij0d762cc2010-04-04 23:34:27 +00002608 }
Linus Walleij9783ce32014-06-02 21:44:29 +02002609 *pce = ce;
2610 return i;
Linus Walleijf0bf4372007-07-01 21:47:38 +00002611}
2612
2613/*
Linus Walleijb02a0662006-04-25 08:05:09 +00002614 PTP USB Event container unpack for Nikon events.
2615*/
2616#define PTP_nikon_ec_Length 0
2617#define PTP_nikon_ec_Code 2
2618#define PTP_nikon_ec_Param1 4
2619#define PTP_nikon_ec_Size 6
2620static inline void
Linus Walleij2ad5b722013-11-04 02:07:44 +01002621ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, unsigned int *cnt)
Linus Walleijb02a0662006-04-25 08:05:09 +00002622{
Linus Walleij2ad5b722013-11-04 02:07:44 +01002623 unsigned int i;
Linus Walleijb02a0662006-04-25 08:05:09 +00002624
2625 *ec = NULL;
2626 if (data == NULL)
2627 return;
2628 if (len < PTP_nikon_ec_Code)
2629 return;
2630 *cnt = dtoh16a(&data[PTP_nikon_ec_Length]);
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002631 if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) { /* broken cnt? */
2632 *cnt = 0;
Linus Walleijb02a0662006-04-25 08:05:09 +00002633 return;
Marcus Meissneraa7d91a2017-03-16 15:59:48 +01002634 }
Linus Walleij0d762cc2010-04-04 23:34:27 +00002635 if (!*cnt)
2636 return;
2637
Linus Walleij7e756532009-05-06 21:25:09 +00002638 *ec = malloc(sizeof(PTPContainer)*(*cnt));
Linus Walleijb02a0662006-04-25 08:05:09 +00002639
2640 for (i=0;i<*cnt;i++) {
Linus Walleij7e756532009-05-06 21:25:09 +00002641 memset(&(*ec)[i],0,sizeof(PTPContainer));
2642 (*ec)[i].Code = dtoh16a(&data[PTP_nikon_ec_Code+PTP_nikon_ec_Size*i]);
2643 (*ec)[i].Param1 = dtoh32a(&data[PTP_nikon_ec_Param1+PTP_nikon_ec_Size*i]);
2644 (*ec)[i].Nparam = 1;
Linus Walleijb02a0662006-04-25 08:05:09 +00002645 }
Linus Walleijeb8c6fe2006-02-03 09:46:22 +00002646}
2647
2648
Linus Walleijb02a0662006-04-25 08:05:09 +00002649static inline uint32_t
2650ptp_pack_EK_text(PTPParams *params, PTPEKTextParams *text, unsigned char **data) {
2651 int i, len = 0;
2652 uint8_t retlen;
2653 unsigned char *curdata;
2654
2655 len = 2*(strlen(text->title)+1)+1+
2656 2*(strlen(text->line[0])+1)+1+
2657 2*(strlen(text->line[1])+1)+1+
2658 2*(strlen(text->line[2])+1)+1+
2659 2*(strlen(text->line[3])+1)+1+
2660 2*(strlen(text->line[4])+1)+1+
2661 4*2+2*4+2+4+2+5*4*2;
2662 *data = malloc(len);
2663 if (!*data) return 0;
2664
2665 curdata = *data;
2666 htod16a(curdata,100);curdata+=2;
2667 htod16a(curdata,1);curdata+=2;
2668 htod16a(curdata,0);curdata+=2;
2669 htod16a(curdata,1000);curdata+=2;
2670
2671 htod32a(curdata,0);curdata+=4;
2672 htod32a(curdata,0);curdata+=4;
2673
2674 htod16a(curdata,6);curdata+=2;
2675 htod32a(curdata,0);curdata+=4;
2676
2677 ptp_pack_string(params, text->title, curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
2678 htod16a(curdata,0x10);curdata+=2;
2679
2680 for (i=0;i<5;i++) {
2681 ptp_pack_string(params, text->line[i], curdata, 0, &retlen); curdata+=2*retlen+1;htod16a(curdata,0);curdata+=2;
2682 htod16a(curdata,0x10);curdata+=2;
2683 htod16a(curdata,0x01);curdata+=2;
2684 htod16a(curdata,0x02);curdata+=2;
2685 htod16a(curdata,0x06);curdata+=2;
2686 }
2687 return len;
2688}
Linus Walleij7347d0f2006-10-23 07:23:39 +00002689
2690#define ptp_canon_dir_version 0x00
2691#define ptp_canon_dir_ofc 0x02
2692#define ptp_canon_dir_unk1 0x04
2693#define ptp_canon_dir_objectid 0x08
2694#define ptp_canon_dir_parentid 0x0c
2695#define ptp_canon_dir_previd 0x10 /* in same dir */
2696#define ptp_canon_dir_nextid 0x14 /* in same dir */
2697#define ptp_canon_dir_nextchild 0x18 /* down one dir */
2698#define ptp_canon_dir_storageid 0x1c /* only in storage entry */
2699#define ptp_canon_dir_name 0x20
2700#define ptp_canon_dir_flags 0x2c
2701#define ptp_canon_dir_size 0x30
2702#define ptp_canon_dir_unixtime 0x34
2703#define ptp_canon_dir_year 0x38
2704#define ptp_canon_dir_month 0x39
2705#define ptp_canon_dir_mday 0x3a
2706#define ptp_canon_dir_hour 0x3b
2707#define ptp_canon_dir_minute 0x3c
2708#define ptp_canon_dir_second 0x3d
2709#define ptp_canon_dir_unk2 0x3e
2710#define ptp_canon_dir_thumbsize 0x40
2711#define ptp_canon_dir_width 0x44
2712#define ptp_canon_dir_height 0x48
2713
2714static inline uint16_t
2715ptp_unpack_canon_directory (
2716 PTPParams *params,
2717 unsigned char *dir,
2718 uint32_t cnt,
2719 PTPObjectHandles *handles,
2720 PTPObjectInfo **oinfos, /* size(handles->n) */
2721 uint32_t **flags /* size(handles->n) */
2722) {
2723 unsigned int i, j, nrofobs = 0, curob = 0;
2724
2725#define ISOBJECT(ptr) (dtoh32a((ptr)+ptp_canon_dir_storageid) == 0xffffffff)
2726 for (i=0;i<cnt;i++)
2727 if (ISOBJECT(dir+i*0x4c)) nrofobs++;
2728 handles->n = nrofobs;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002729 handles->Handler = calloc(nrofobs,sizeof(handles->Handler[0]));
Linus Walleij7347d0f2006-10-23 07:23:39 +00002730 if (!handles->Handler) return PTP_RC_GeneralError;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002731 *oinfos = calloc(nrofobs,sizeof((*oinfos)[0]));
Linus Walleij7347d0f2006-10-23 07:23:39 +00002732 if (!*oinfos) return PTP_RC_GeneralError;
Marcus Meissner3d692dc2016-02-21 12:34:06 +01002733 *flags = calloc(nrofobs,sizeof((*flags)[0]));
Linus Walleij7347d0f2006-10-23 07:23:39 +00002734 if (!*flags) return PTP_RC_GeneralError;
2735
2736 /* Migrate data into objects ids, handles into
2737 * the object handler array.
2738 */
2739 curob = 0;
2740 for (i=0;i<cnt;i++) {
2741 unsigned char *cur = dir+i*0x4c;
2742 PTPObjectInfo *oi = (*oinfos)+curob;
2743
2744 if (!ISOBJECT(cur))
2745 continue;
2746
2747 handles->Handler[curob] = dtoh32a(cur + ptp_canon_dir_objectid);
2748 oi->StorageID = 0xffffffff;
2749 oi->ObjectFormat = dtoh16a(cur + ptp_canon_dir_ofc);
2750 oi->ParentObject = dtoh32a(cur + ptp_canon_dir_parentid);
2751 oi->Filename = strdup((char*)(cur + ptp_canon_dir_name));
2752 oi->ObjectCompressedSize= dtoh32a(cur + ptp_canon_dir_size);
2753 oi->ThumbCompressedSize = dtoh32a(cur + ptp_canon_dir_thumbsize);
2754 oi->ImagePixWidth = dtoh32a(cur + ptp_canon_dir_width);
2755 oi->ImagePixHeight = dtoh32a(cur + ptp_canon_dir_height);
2756 oi->CaptureDate = oi->ModificationDate = dtoh32a(cur + ptp_canon_dir_unixtime);
2757 (*flags)[curob] = dtoh32a(cur + ptp_canon_dir_flags);
2758 curob++;
2759 }
2760 /* Walk over Storage ID entries and distribute the IDs to
2761 * the parent objects. */
2762 for (i=0;i<cnt;i++) {
2763 unsigned char *cur = dir+i*0x4c;
2764 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2765
2766 if (ISOBJECT(cur))
2767 continue;
2768 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2769 if (j == handles->n) continue;
2770 (*oinfos)[j].StorageID = dtoh32a(cur + ptp_canon_dir_storageid);
2771 }
2772 /* Walk over all objects and distribute the storage ids */
2773 while (1) {
Linus Walleij2ad5b722013-11-04 02:07:44 +01002774 unsigned int changed = 0;
Linus Walleij7347d0f2006-10-23 07:23:39 +00002775 for (i=0;i<cnt;i++) {
2776 unsigned char *cur = dir+i*0x4c;
2777 uint32_t oid = dtoh32a(cur + ptp_canon_dir_objectid);
2778 uint32_t nextoid = dtoh32a(cur + ptp_canon_dir_nextid);
2779 uint32_t nextchild = dtoh32a(cur + ptp_canon_dir_nextchild);
2780 uint32_t storageid;
2781
2782 if (!ISOBJECT(cur))
2783 continue;
2784 for (j=0;j<handles->n;j++) if (oid == handles->Handler[j]) break;
2785 if (j == handles->n) {
2786 /*fprintf(stderr,"did not find oid in lookup pass for current oid\n");*/
2787 continue;
2788 }
2789 storageid = (*oinfos)[j].StorageID;
2790 if (storageid == 0xffffffff) continue;
2791 if (nextoid != 0xffffffff) {
2792 for (j=0;j<handles->n;j++) if (nextoid == handles->Handler[j]) break;
2793 if (j == handles->n) {
2794 /*fprintf(stderr,"did not find oid in lookup pass for next oid\n");*/
2795 continue;
2796 }
2797 if ((*oinfos)[j].StorageID == 0xffffffff) {
2798 (*oinfos)[j].StorageID = storageid;
2799 changed++;
2800 }
2801 }
2802 if (nextchild != 0xffffffff) {
2803 for (j=0;j<handles->n;j++) if (nextchild == handles->Handler[j]) break;
2804 if (j == handles->n) {
2805 /*fprintf(stderr,"did not find oid in lookup pass for next child\n");*/
2806 continue;
2807 }
2808 if ((*oinfos)[j].StorageID == 0xffffffff) {
2809 (*oinfos)[j].StorageID = storageid;
2810 changed++;
2811 }
2812 }
2813 }
2814 /* Check if we:
2815 * - changed no entry (nothing more to do)
2816 * - changed all of them at once (usually happens)
2817 * break if we do.
2818 */
2819 if (!changed || (changed==nrofobs-1))
2820 break;
2821 }
2822#undef ISOBJECT
2823 return PTP_RC_OK;
2824}