1/* ptp-pack.c
2 *
3 * Copyright (C) 2001-2004 Mariusz Woloszyn <emsi@ipartners.pl>
4 * Copyright (C) 2003-2016 Marcus Meissner <marcus@jet.franken.de>
5 * Copyright (C) 2006-2008 Linus Walleij <triad@df.lth.se>
6 * Copyright (C) 2007 Tero Saarni <tero.saarni@gmail.com>
7 * Copyright (C) 2009 Axel Waggershauser <awagger@web.de>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA  02110-1301  USA
23 */
24
25/* currently this file is included into ptp.c */
26
27#ifdef HAVE_LIMITS_H
28#include <limits.h>
29#endif
30#ifndef UINT_MAX
31# define UINT_MAX 0xFFFFFFFF
32#endif
33#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
34#include <iconv.h>
35#endif
36
37static inline uint16_t
38htod16p (PTPParams *params, uint16_t var)
39{
40	return ((params->byteorder==PTP_DL_LE)?htole16(var):htobe16(var));
41}
42
43static inline uint32_t
44htod32p (PTPParams *params, uint32_t var)
45{
46	return ((params->byteorder==PTP_DL_LE)?htole32(var):htobe32(var));
47}
48
49static inline void
50htod16ap (PTPParams *params, unsigned char *a, uint16_t val)
51{
52	if (params->byteorder==PTP_DL_LE)
53		htole16a(a,val);
54	else
55		htobe16a(a,val);
56}
57
58static inline void
59htod32ap (PTPParams *params, unsigned char *a, uint32_t val)
60{
61	if (params->byteorder==PTP_DL_LE)
62		htole32a(a,val);
63	else
64		htobe32a(a,val);
65}
66
67static inline void
68htod64ap (PTPParams *params, unsigned char *a, uint64_t val)
69{
70	if (params->byteorder==PTP_DL_LE)
71		htole64a(a,val);
72	else
73		htobe64a(a,val);
74}
75
76static inline uint16_t
77dtoh16p (PTPParams *params, uint16_t var)
78{
79	return ((params->byteorder==PTP_DL_LE)?le16toh(var):be16toh(var));
80}
81
82static inline uint32_t
83dtoh32p (PTPParams *params, uint32_t var)
84{
85	return ((params->byteorder==PTP_DL_LE)?le32toh(var):be32toh(var));
86}
87
88static inline uint64_t
89dtoh64p (PTPParams *params, uint64_t var)
90{
91	return ((params->byteorder==PTP_DL_LE)?le64toh(var):be64toh(var));
92}
93
94static inline uint16_t
95dtoh16ap (PTPParams *params, const unsigned char *a)
96{
97	return ((params->byteorder==PTP_DL_LE)?le16atoh(a):be16atoh(a));
98}
99
100static inline uint32_t
101dtoh32ap (PTPParams *params, const unsigned char *a)
102{
103	return ((params->byteorder==PTP_DL_LE)?le32atoh(a):be32atoh(a));
104}
105
106static inline uint64_t
107dtoh64ap (PTPParams *params, const unsigned char *a)
108{
109	return ((params->byteorder==PTP_DL_LE)?le64atoh(a):be64atoh(a));
110}
111
112#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)
115#define htod64a(a,x)	htod64ap(params,a,x)
116#define htod16(x)	htod16p(params,x)
117#define htod32(x)	htod32p(params,x)
118#define htod64(x)	htod64p(params,x)
119
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)
126#define dtoh64(x)	dtoh64p(params,x)
127
128
129static inline char*
130ptp_unpack_string(PTPParams *params, unsigned char* data, uint16_t offset, uint32_t total, uint8_t *len)
131{
132	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 */
135	char loclstr[PTP_MAXSTRLEN*3+1];
136	size_t nconv, srclen, destlen;
137	char *src, *dest;
138
139	if (offset + 1 >= total)
140		return NULL;
141
142	length = dtoh8a(&data[offset]);	/* PTP_MAXSTRLEN == 255, 8 bit len */
143	*len = length;
144	if (length == 0)		/* nothing to do? */
145		return NULL;
146
147	if (offset + 1 + length*sizeof(string[0]) > total)
148		return NULL;
149
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';
154
155	/* 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;
160	nconv = (size_t)-1;
161#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
162	if (params->cd_ucs2_to_locale != (iconv_t)-1)
163		nconv = iconv(params->cd_ucs2_to_locale, &src, &srclen, &dest, &destlen);
164#endif
165	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]);
173		}
174		dest = loclstr+length;
175	}
176	*dest = '\0';
177	loclstr[sizeof(loclstr)-1] = '\0';   /* be safe? */
178	return(strdup(loclstr));
179}
180
181static inline int
182ucs2strlen(uint16_t const * const unicstr)
183{
184	int length = 0;
185
186	/* Unicode strings are terminated with 2 * 0x00 */
187	for(length = 0; unicstr[length] != 0x0000U; length ++);
188	return length;
189}
190
191
192static inline void
193ptp_pack_string(PTPParams *params, char *string, unsigned char* data, uint16_t offset, uint8_t *len)
194{
195	int packedlen = 0;
196	uint16_t ucs2str[PTP_MAXSTRLEN+1];
197	char *ucs2strp = (char *) ucs2str;
198	size_t convlen = strlen(string);
199
200	/* Cannot exceed 255 (PTP_MAXSTRLEN) since it is a single byte, duh ... */
201	memset(ucs2strp, 0, sizeof(ucs2str));  /* XXX: necessary? */
202#if defined(HAVE_ICONV) && defined(HAVE_LANGINFO_H)
203	if (params->cd_locale_to_ucs2 != (iconv_t)-1) {
204		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;
212	} else
213#endif
214	{
215		unsigned int i;
216
217		for (i=0;i<convlen;i++) {
218			ucs2str[i] = string[i];
219		}
220		ucs2str[convlen] = 0;
221	}
222	/*
223	 * XXX: isn't packedlen just ( (uint16_t *)ucs2strp - ucs2str )?
224	 *      why do we need ucs2strlen()?
225	 */
226	packedlen = ucs2strlen(ucs2str);
227	if (packedlen > PTP_MAXSTRLEN-1) {
228		*len=0;
229		return;
230	}
231
232	/* number of characters including terminating 0 (PTP standard confirmed) */
233	htod8a(&data[offset],packedlen+1);
234	memcpy(&data[offset+1], &ucs2str[0], packedlen * sizeof(ucs2str[0]));
235	htod16a(&data[offset+packedlen*2+1], 0x0000);  /* terminate 0 */
236
237	/* The returned length is in number of characters */
238	*len = (uint8_t) packedlen+1;
239}
240
241static inline unsigned char *
242ptp_get_packed_stringcopy(PTPParams *params, char *string, uint32_t *packed_size)
243{
244	uint8_t packed[PTP_MAXSTRLEN*2+3], len;
245	size_t plen;
246	unsigned char *retcopy = NULL;
247
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
253	/* returned length is in characters, then one byte for string length */
254	plen = len*2 + 1;
255
256	retcopy = malloc(plen);
257	if (!retcopy) {
258		*packed_size = 0;
259		return NULL;
260	}
261	memcpy(retcopy, packed, plen);
262	*packed_size = plen;
263	return (retcopy);
264}
265
266static inline uint32_t
267ptp_unpack_uint32_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint32_t **array)
268{
269	uint32_t n, i=0;
270
271	if (!data)
272		return 0;
273
274	if (offset >= datalen)
275		return 0;
276
277	if (offset + sizeof(uint32_t) > datalen)
278		return 0;
279
280	*array = NULL;
281	n=dtoh32a(&data[offset]);
282	if (n >= UINT_MAX/sizeof(uint32_t))
283		return 0;
284	if (!n)
285		return 0;
286
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
292	*array = malloc (n*sizeof(uint32_t));
293	if (!*array)
294		return 0;
295	for (i=0;i<n;i++)
296		(*array)[i]=dtoh32a(&data[offset+(sizeof(uint32_t)*(i+1))]);
297	return n;
298}
299
300static inline uint32_t
301ptp_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));
306	if (!*data)
307		return 0;
308	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
315ptp_unpack_uint16_t_array(PTPParams *params, unsigned char* data, unsigned int offset, unsigned int datalen, uint16_t **array)
316{
317	uint32_t n, i=0;
318
319	if (!data)
320		return 0;
321	*array = NULL;
322	n=dtoh32a(&data[offset]);
323	if (n >= UINT_MAX/sizeof(uint16_t))
324		return 0;
325	if (!n)
326		return 0;
327	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	}
333	*array = malloc (n*sizeof(uint16_t));
334	if (!*array)
335		return 0;
336	for (i=0;i<n;i++)
337		(*array)[i]=dtoh16a(&data[offset+(sizeof(uint16_t)*(i+2))]);
338	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
350static inline int
351ptp_unpack_DI (PTPParams *params, unsigned char* data, PTPDeviceInfo *di, unsigned int datalen)
352{
353	uint8_t len;
354	unsigned int totallen;
355
356	if (!data) return 0;
357	if (datalen < 12) return 0;
358	memset (di, 0, sizeof(*di));
359	di->StandardVersion = dtoh16a(&data[PTP_di_StandardVersion]);
360	di->VendorExtensionID =
361		dtoh32a(&data[PTP_di_VendorExtensionID]);
362	di->VendorExtensionVersion =
363		dtoh16a(&data[PTP_di_VendorExtensionVersion]);
364	di->VendorExtensionDesc =
365		ptp_unpack_string(params, data,
366		PTP_di_VendorExtensionDesc,
367		datalen,
368		&len);
369	totallen=len*2+1;
370	if (datalen <= totallen) return 0;
371	di->FunctionalMode =
372		dtoh16a(&data[PTP_di_FunctionalMode+totallen]);
373	di->OperationsSupported_len = ptp_unpack_uint16_t_array(params, data,
374		PTP_di_OperationsSupported+totallen,
375		datalen,
376		&di->OperationsSupported);
377	totallen=totallen+di->OperationsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
378	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
379	di->EventsSupported_len = ptp_unpack_uint16_t_array(params, data,
380		PTP_di_OperationsSupported+totallen,
381		datalen,
382		&di->EventsSupported);
383	totallen=totallen+di->EventsSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
384	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
385	di->DevicePropertiesSupported_len =
386		ptp_unpack_uint16_t_array(params, data,
387		PTP_di_OperationsSupported+totallen,
388		datalen,
389		&di->DevicePropertiesSupported);
390	totallen=totallen+di->DevicePropertiesSupported_len*sizeof(uint16_t)+sizeof(uint32_t);
391	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
392	di->CaptureFormats_len = ptp_unpack_uint16_t_array(params, data,
393		PTP_di_OperationsSupported+totallen,
394		datalen,
395		&di->CaptureFormats);
396	totallen=totallen+di->CaptureFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
397	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
398	di->ImageFormats_len = ptp_unpack_uint16_t_array(params, data,
399		PTP_di_OperationsSupported+totallen,
400		datalen,
401		&di->ImageFormats);
402	totallen=totallen+di->ImageFormats_len*sizeof(uint16_t)+sizeof(uint32_t);
403	if (datalen <= totallen+PTP_di_OperationsSupported) return 0;
404	di->Manufacturer = ptp_unpack_string(params, data,
405		PTP_di_OperationsSupported+totallen,
406		datalen,
407		&len);
408	totallen+=len*2+1;
409	/* be more relaxed ... as these are optional its ok if they are not here */
410	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
411	di->Model = ptp_unpack_string(params, data,
412		PTP_di_OperationsSupported+totallen,
413		datalen,
414		&len);
415	totallen+=len*2+1;
416	/* be more relaxed ... as these are optional its ok if they are not here */
417	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
418	di->DeviceVersion = ptp_unpack_string(params, data,
419		PTP_di_OperationsSupported+totallen,
420		datalen,
421		&len);
422	totallen+=len*2+1;
423	/* be more relaxed ... as these are optional its ok if they are not here */
424	if (datalen <= totallen+PTP_di_OperationsSupported) return 1;
425	di->SerialNumber = ptp_unpack_string(params, data,
426		PTP_di_OperationsSupported+totallen,
427		datalen,
428		&len);
429	return 1;
430}
431
432inline static void
433ptp_free_DI (PTPDeviceInfo *di) {
434	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);
444	memset(di, 0, sizeof(*di));
445}
446
447/* EOS Device Info unpack */
448static inline int
449ptp_unpack_EOS_DI (PTPParams *params, unsigned char* data, PTPCanonEOSDeviceInfo *di, unsigned int datalen)
450{
451	unsigned int totallen = 4;
452
453	memset (di,0, sizeof(*di));
454	if (datalen < 8) return 0;
455
456	/* uint32_t struct len - ignore */
457	di->EventsSupported_len = ptp_unpack_uint32_t_array(params, data,
458		totallen, datalen, &di->EventsSupported);
459	if (!di->EventsSupported) return 0;
460	totallen += di->EventsSupported_len*sizeof(uint32_t)+4;
461	if (totallen >= datalen) return 0;
462
463	di->DevicePropertiesSupported_len = ptp_unpack_uint32_t_array(params, data,
464		totallen, datalen, &di->DevicePropertiesSupported);
465	if (!di->DevicePropertiesSupported) return 0;
466	totallen += di->DevicePropertiesSupported_len*sizeof(uint32_t)+4;
467	if (totallen >= datalen) return 0;
468
469	di->unk_len = ptp_unpack_uint32_t_array(params, data,
470		totallen, datalen, &di->unk);
471	if (!di->unk) return 0;
472	totallen += di->unk_len*sizeof(uint32_t)+4;
473	return 1;
474}
475
476static inline void
477ptp_free_EOS_DI (PTPCanonEOSDeviceInfo *di)
478{
479	free (di->EventsSupported);
480	free (di->DevicePropertiesSupported);
481	free (di->unk);
482}
483
484/* ObjectHandles array pack/unpack */
485
486#define PTP_oh				 0
487
488static inline void
489ptp_unpack_OH (PTPParams *params, unsigned char* data, PTPObjectHandles *oh, unsigned int len)
490{
491	if (len) {
492		oh->n = ptp_unpack_uint32_t_array(params, data, PTP_oh, len, &oh->Handler);
493	} else {
494		oh->n = 0;
495		oh->Handler = NULL;
496	}
497}
498
499/* StoreIDs array pack/unpack */
500
501#define PTP_sids			 0
502
503static inline void
504ptp_unpack_SIDs (PTPParams *params, unsigned char* data, PTPStorageIDs *sids, unsigned int len)
505{
506	sids->n = 0;
507	sids->Storage = NULL;
508
509	if (!data || !len)
510		return;
511
512	sids->n = ptp_unpack_uint32_t_array(params, data, PTP_sids, len, &sids->Storage);
513}
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
525static inline int
526ptp_unpack_SI (PTPParams *params, unsigned char* data, PTPStorageInfo *si, unsigned int len)
527{
528	uint8_t storagedescriptionlen;
529
530	if (len < 26) return 0;
531	si->StorageType=dtoh16a(&data[PTP_si_StorageType]);
532	si->FilesystemType=dtoh16a(&data[PTP_si_FilesystemType]);
533	si->AccessCapability=dtoh16a(&data[PTP_si_AccessCapability]);
534	si->MaxCapability=dtoh64a(&data[PTP_si_MaxCapability]);
535	si->FreeSpaceInBytes=dtoh64a(&data[PTP_si_FreeSpaceInBytes]);
536	si->FreeSpaceInImages=dtoh32a(&data[PTP_si_FreeSpaceInImages]);
537
538	/* FIXME: check more lengths here */
539	si->StorageDescription=ptp_unpack_string(params, data,
540		PTP_si_StorageDescription,
541		len,
542		&storagedescriptionlen);
543	si->VolumeLabel=ptp_unpack_string(params, data,
544		PTP_si_StorageDescription+storagedescriptionlen*2+1,
545		len,
546		&storagedescriptionlen);
547	return 1;
548}
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
570/* the max length assuming zero length dates. We have need 3 */
571/* bytes for these. */
572#define PTP_oi_MaxLen PTP_oi_Filename+(PTP_MAXSTRLEN+1)*2+3
573
574static inline uint32_t
575ptp_pack_OI (PTPParams *params, PTPObjectInfo *oi, unsigned char** oidataptr)
576{
577	unsigned char* oidata;
578	uint8_t filenamelen;
579	uint8_t capturedatelen=0;
580	/* let's allocate some memory first; correct assuming zero length dates */
581	oidata=malloc(PTP_oi_MaxLen + params->ocs64*4);
582	*oidataptr=oidata;
583	/* the caller should free it after use! */
584#if 0
585	char *capture_date="20020101T010101"; /* XXX Fake date */
586#endif
587	memset (oidata, 0, PTP_oi_MaxLen + params->ocs64*4);
588	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);
592	if (params->ocs64)
593		oidata += 4;
594	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 */
634	return (PTP_oi_Filename+filenamelen*2+(capturedatelen+1)*3)+params->ocs64*4;
635}
636
637static time_t
638ptp_unpack_PTPTIME (const char *str) {
639	char ptpdate[40];
640	char tmp[5];
641	size_t  ptpdatelen;
642	struct tm tm;
643
644	if (!str)
645		return 0;
646	ptpdatelen = strlen(str);
647	if (ptpdatelen >= sizeof (ptpdate)) {
648		/*ptp_debug (params ,"datelen is larger then size of buffer", ptpdatelen, (int)sizeof(ptpdate));*/
649		return 0;
650	}
651	if (ptpdatelen<15) {
652		/*ptp_debug (params ,"datelen is less than 15 (%d)", ptpdatelen);*/
653		return 0;
654	}
655	strncpy (ptpdate, str, sizeof(ptpdate));
656	ptpdate[sizeof(ptpdate) - 1] = '\0';
657
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);
677	tm.tm_isdst = -1;
678	return mktime (&tm);
679}
680
681static inline void
682ptp_unpack_OI (PTPParams *params, unsigned char* data, PTPObjectInfo *oi, unsigned int len)
683{
684	uint8_t filenamelen;
685	uint8_t capturedatelen;
686	char *capture_date;
687
688	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 */
694	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]);
698
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	}
704	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]);
715
716	oi->Filename= ptp_unpack_string(params, data, PTP_oi_filenamelen, len, &filenamelen);
717
718	capture_date = ptp_unpack_string(params, data,
719		PTP_oi_filenamelen+filenamelen*2+1, len, &capturedatelen);
720	/* subset of ISO 8601, without '.s' tenths of second and
721	 * time zone
722	 */
723	oi->CaptureDate = ptp_unpack_PTPTIME(capture_date);
724	free(capture_date);
725
726	/* now the modification date ... */
727	capture_date = ptp_unpack_string(params, data,
728		PTP_oi_filenamelen+filenamelen*2
729		+capturedatelen*2+2, len, &capturedatelen);
730	oi->ModificationDate = ptp_unpack_PTPTIME(capture_date);
731	free(capture_date);
732}
733
734/* Custom Type Value Assignement (without Length) macro frequently used below */
735#define CTVAL(target,func) {			\
736	if (total - *offset < sizeof(target))	\
737		return 0;			\
738	target = func(&data[*offset]);		\
739	*offset += sizeof(target);		\
740}
741
742#define RARR(val,member,func)	{			\
743	unsigned int n,j;				\
744	if (total - *offset < sizeof(uint32_t))		\
745		return 0;				\
746	n = dtoh32a (&data[*offset]);			\
747	*offset += sizeof(uint32_t);			\
748							\
749	if (n >= UINT_MAX/sizeof(val->a.v[0]))		\
750		return 0;				\
751	if (n > (total - (*offset))/sizeof(val->a.v[0]))\
752		return 0;				\
753	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}
759
760static inline unsigned int
761ptp_unpack_DPV (
762	PTPParams *params, unsigned char* data, unsigned int *offset, unsigned int total,
763	PTPPropertyValue* value, uint16_t datatype
764) {
765	if (*offset >= total)	/* we are at the end or over the end of the buffer */
766		return 0;
767
768	switch (datatype) {
769	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;
787	case PTP_DTC_INT64:
788		CTVAL(value->i64,dtoh64a);
789		break;
790	case PTP_DTC_UINT64:
791		CTVAL(value->u64,dtoh64a);
792		break;
793
794	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
805	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;
823	case PTP_DTC_AUINT64:
824		RARR(value,u64,dtoh64a);
825		break;
826	case PTP_DTC_AINT64:
827		RARR(value,i64,dtoh64a);
828		break;
829	/* 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 */
834
835		if (*offset >= total+1)
836			return 0;
837
838		value->str = ptp_unpack_string(params,data,*offset,total,&len);
839		*offset += len*2+1;
840		if (!value->str)
841			return 1;
842		break;
843	}
844	default:
845		return 0;
846	}
847	return 1;
848}
849
850/* Device Property pack/unpack */
851#define PTP_dpd_DevicePropertyCode	0
852#define PTP_dpd_DataType		2
853#define PTP_dpd_GetSet			4
854#define PTP_dpd_FactoryDefaultValue	5
855
856static inline int
857ptp_unpack_DPD (PTPParams *params, unsigned char* data, PTPDevicePropDesc *dpd, unsigned int dpdlen)
858{
859	unsigned int offset = 0, ret;
860
861	memset (dpd, 0, sizeof(*dpd));
862	if (dpdlen <= 5)
863		return 0;
864	dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
865	dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
866	dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
867	dpd->FormFlag=PTP_DPFF_None;
868
869	offset = PTP_dpd_FactoryDefaultValue;
870	ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
871	if (!ret) goto outofmemory;
872	if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
873		return 1;
874	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
882	if (offset==PTP_dpd_FactoryDefaultValue)
883		return 1;
884
885	dpd->FormFlag=dtoh8a(&data[offset]);
886	offset+=sizeof(uint8_t);
887
888	switch (dpd->FormFlag) {
889	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;
896		break;
897	case PTP_DPFF_Enumeration: {
898		int i;
899#define N	dpd->FORM.Enum.NumberOfValues
900		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;
920			}
921		}
922		}
923	}
924#undef N
925	return 1;
926outofmemory:
927	ptp_free_devicepropdesc(dpd);
928	return 0;
929}
930
931/* 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;
942#if 0
943	unsigned int unk1, unk2;
944#endif
945
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
951	/* 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);
955#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
1022static inline void
1023duplicate_PropertyValue (const PTPPropertyValue *src, PTPPropertyValue *dst, uint16_t type) {
1024	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
1032	if (type & PTP_DTC_ARRAY_MASK) {
1033		unsigned int i;
1034
1035		dst->a.count = src->a.count;
1036		dst->a.v = malloc (sizeof(src->a.v[0])*src->a.count);
1037		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
1054	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
1067	duplicate_PropertyValue (&src->FactoryDefaultValue, &dst->FactoryDefaultValue, src->DataType);
1068	duplicate_PropertyValue (&src->CurrentValue, &dst->CurrentValue, src->DataType);
1069
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
1088#define PTP_opd_ObjectPropertyCode	0
1089#define PTP_opd_DataType		2
1090#define PTP_opd_GetSet			4
1091#define PTP_opd_FactoryDefaultValue	5
1092
1093static inline int
1094ptp_unpack_OPD (PTPParams *params, unsigned char* data, PTPObjectPropDesc *opd, unsigned int opdlen)
1095{
1096	unsigned int offset=0, ret;
1097
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: {
1123		unsigned int i;
1124#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;
1161	uint32_t size=0;
1162	unsigned int i;
1163
1164	switch (datatype) {
1165	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;
1195	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;
1205	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++)
1210			htod8a(&dpv[sizeof(uint32_t)+i*sizeof(uint8_t)],value->a.v[i].u8);
1211		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++)
1217			htod8a(&dpv[sizeof(uint32_t)+i*sizeof(int8_t)],value->a.v[i].i8);
1218		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++)
1224			htod16a(&dpv[sizeof(uint32_t)+i*sizeof(uint16_t)],value->a.v[i].u16);
1225		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++)
1231			htod16a(&dpv[sizeof(uint32_t)+i*sizeof(int16_t)],value->a.v[i].i16);
1232		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++)
1238			htod32a(&dpv[sizeof(uint32_t)+i*sizeof(uint32_t)],value->a.v[i].u32);
1239		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++)
1245			htod32a(&dpv[sizeof(uint32_t)+i*sizeof(int32_t)],value->a.v[i].i32);
1246		break;
1247	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++)
1252			htod64a(&dpv[sizeof(uint32_t)+i*sizeof(uint64_t)],value->a.v[i].u64);
1253		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++)
1259			htod64a(&dpv[sizeof(uint32_t)+i*sizeof(int64_t)],value->a.v[i].i64);
1260		break;
1261	/* XXX: other int types are unimplemented */
1262	case PTP_DTC_STR: {
1263		dpv=ptp_get_packed_stringcopy(params, value->str, &size);
1264		break;
1265	}
1266	}
1267	*dpvptr=dpv;
1268	return size;
1269}
1270
1271#define MAX_MTP_PROPS 127
1272static inline uint32_t
1273ptp_pack_OPL (PTPParams *params, MTPProperties *props, int nrofprops, unsigned char** opldataptr)
1274{
1275	unsigned char* opldata;
1276	MTPProperties *propitr;
1277	unsigned char *packedprops[MAX_MTP_PROPS];
1278	uint32_t packedpropslens[MAX_MTP_PROPS];
1279	uint32_t packedobjecthandles[MAX_MTP_PROPS];
1280	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 */
1288	propitr = props;
1289	while (nrofprops-- && noitems < MAX_MTP_PROPS) {
1290		/* Object Handle */
1291		packedobjecthandles[noitems]=propitr->ObjectHandle;
1292		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 ++;
1303		propitr ++;
1304	}
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 */
1315		htod32a(&opldata[bufp],packedobjecthandles[i]);
1316		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
1330static 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
1338static inline int
1339ptp_unpack_OPL (PTPParams *params, unsigned char* data, MTPProperties **pprops, unsigned int len)
1340{
1341	uint32_t prop_count = dtoh32a(data);
1342	MTPProperties *props = NULL;
1343	unsigned int offset = 0, i;
1344
1345	*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);
1350		return 0;
1351	}
1352	ptp_debug (params ,"Unpacking MTP OPL, size %d (prop_count %d)", len, prop_count);
1353	data += sizeof(uint32_t);
1354	len -= sizeof(uint32_t);
1355	props = malloc(prop_count * sizeof(MTPProperties));
1356	if (!props) return 0;
1357	for (i = 0; i < prop_count; i++) {
1358		if (len <= 0) {
1359			ptp_debug (params ,"short MTP Object Property List at property %d (of %d)", i, prop_count);
1360			ptp_debug (params ,"device probably needs DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL");
1361			ptp_debug (params ,"or even DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST", i);
1362			qsort (props, i, sizeof(MTPProperties),_compare_func);
1363			*pprops = props;
1364			return i;
1365		}
1366		props[i].ObjectHandle = dtoh32a(data);
1367		data += sizeof(uint32_t);
1368		len -= sizeof(uint32_t);
1369
1370		props[i].property = dtoh16a(data);
1371		data += sizeof(uint16_t);
1372		len -= sizeof(uint16_t);
1373
1374		props[i].datatype = dtoh16a(data);
1375		data += sizeof(uint16_t);
1376		len -= sizeof(uint16_t);
1377
1378		offset = 0;
1379		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		}
1385		data += offset;
1386		len -= offset;
1387	}
1388	qsort (props, prop_count, sizeof(MTPProperties),_compare_func);
1389	*pprops = props;
1390	return prop_count;
1391}
1392
1393/*
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
1406static inline void
1407ptp_unpack_EC (PTPParams *params, unsigned char* data, PTPContainer *ec, unsigned int len)
1408{
1409	unsigned int	length;
1410	int	type;
1411
1412	if (data==NULL)
1413		return;
1414	memset(ec,0,sizeof(*ec));
1415
1416	length=dtoh32a(&data[PTP_ec_Length]);
1417	if (length > len) {
1418		ptp_debug (params, "length %d in container, but data only %d bytes?!", length, len);
1419		return;
1420	}
1421	type = dtoh16a(&data[PTP_ec_Type]);
1422
1423	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	}
1442}
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
1455static inline void
1456ptp_unpack_Canon_FE (PTPParams *params, unsigned char* data, PTPCANONFolderEntry *fe)
1457{
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]);
1464	fe->ObjectSize=dtoh32a((unsigned char*)&data[PTP_cfe_ObjectSize]);
1465	fe->Time=(time_t)dtoh32a(&data[PTP_cfe_Time]);
1466	for (i=0; i<PTP_CANON_FilenameBufferLen; i++)
1467		fe->Filename[i]=(char)dtoh8a(&data[PTP_cfe_Filename+i]);
1468}
1469
1470/*
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
15110020  00 00 00 00 ??
15120024  21 00 00 00  flags (4 bytes? 1 byte?)
15130028  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
1525#define PTP_cefe_Flags			16
1526#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
1545static inline uint16_t
1546ptp_unpack_EOS_ImageFormat (PTPParams* params, unsigned char** data )
1547{
1548	/*
1549	  EOS ImageFormat entries (of at least the 5DM2 and the 400D) look like this:
1550		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)
1553		uint32: image size (0 == Large, 1 == Medium, 2 == Small, 0xe == S1, 0xf == S2, 0x10 == S3)
1554		uint32: image compression (2 == Standard/JPG, 3 == Fine/JPG, 4 == Lossles/RAW)
1555	  If the number of entries is 2 the last 4 uint32 repeat.
1556
1557	  example:
1558		0: 0x       1
1559		1: 0x      10
1560		2: 0x       6
1561		3: 0x       1
1562		4: 0x       4
1563
1564	  The idea is to simply 'condense' these values to just one uint16 to be able to conveniently
1565	  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.
1569
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.
1572	  */
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
1606	/* deal with S1/S2/S3 JPEG sizes, see above. */
1607	if( s1 >= 0xe )
1608		s1--;
1609	if( s2 >= 0xe )
1610		s2--;
1611
1612	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
1624#define PACK_5DM3_SMALL_JPEG_SIZE( X ) (X) >= 0xd ? (X)+1 : (X)
1625
1626	htod32a(data+=0, n);
1627	htod32a(data+=4, 0x10);
1628	htod32a(data+=4, ((value >> 8) & 0xF) == 4 ? 6 : 1);
1629	htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 12) & 0xF));
1630	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);
1635		htod32a(data+=4, PACK_5DM3_SMALL_JPEG_SIZE((value >> 4) & 0xF));
1636		htod32a(data+=4, (value >> 0) & 0xF);
1637	}
1638
1639#undef PACK_5DM3_SMALL_JPEG_SIZE
1640
1641	return s;
1642}
1643
1644/* 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*
1663ptp_unpack_EOS_FocusInfoEx (PTPParams* params, unsigned char** data, uint32_t datasize )
1664{
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
1678	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 ,*/
1681	/* inital things around lets say 100 chars at most.
1682	 * 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;
1694	if (halfsize != size-4) {
1695		ptp_error(params, "halfsize %d is not expected %d", halfsize, size-4);
1696		return strdup("bad size 4");
1697	}
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);
1700		return strdup("bad size 5");
1701	}
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
1707	ptp_debug(params,"d1d3 version %d", version);
1708	ptp_debug(params,"d1d3 size %d", size);
1709	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++) {
1730		if ((1<<(i%8)) & ((*data)[focus_points_in_struct*8+20+i/8]))
1731			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++) {
1736		if ((p-str) > maxlen - 4)
1737			break;
1738		p+=sprintf(p,"%02x", (*data)[i]);
1739	}
1740	p += sprintf(p,"}");
1741	return str;
1742}
1743
1744
1745static 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;
1750	char	*str, *p;
1751
1752	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;
1761	for (i=0; i < n; ++i)
1762		p += sprintf(p, "%x,", dtoh32a( *data + 4*i ));
1763	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);
1778		str++; /* skip the ',' delimiter */
1779		htod32a(data + i*4, v);
1780	}
1781
1782	return s;
1783}
1784
1785/*
1786    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
1797/* 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
1810
1811#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
1823static 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
1849static inline int
1850ptp_unpack_CANON_changes (PTPParams *params, unsigned char* data, int datasize, PTPCanon_changes_entry **pce)
1851{
1852	int	i = 0, entries = 0;
1853	unsigned char	*curdata = data;
1854	PTPCanon_changes_entry *ce;
1855
1856	if (data==NULL)
1857		return 0;
1858	while (curdata - data + 8 < datasize) {
1859		uint32_t	size = dtoh32a(&curdata[PTP_ece_Size]);
1860		uint32_t	type = dtoh32a(&curdata[PTP_ece_Type]);
1861
1862		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		}
1870		if ((size == 8) && (type == 0))
1871			break;
1872		if ((curdata - data) + size >= datasize) {
1873			ptp_debug (params, "canon eos event decoder ran over supplied data, skipping entries");
1874			break;
1875		}
1876		if (type == PTP_EC_CANON_EOS_OLCInfoChanged) {
1877			unsigned int j;
1878
1879			entries++;
1880			if (size >= 12+2) {
1881				for (j=0;j<31;j++)
1882					if (dtoh16a(curdata+12) & (1<<j))
1883						entries++;
1884			}
1885		}
1886		curdata += size;
1887		entries++;
1888	}
1889	ce = malloc (sizeof(PTPCanon_changes_entry)*(entries+1));
1890	if (!ce) return 0;
1891
1892	curdata = data;
1893	while (curdata - data  + 8 < datasize) {
1894		uint32_t	size = dtoh32a(&curdata[PTP_ece_Size]);
1895		uint32_t	type = dtoh32a(&curdata[PTP_ece_Type]);
1896
1897		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
1914		ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
1915		ce[i].u.info = NULL;
1916		switch (type) {
1917		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			}
1922			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTINFO;
1923			ce[i].u.object.oid    		= dtoh32a(&curdata[PTP_ece_OA_ObjectID]);
1924			ce[i].u.object.oi.StorageID	= dtoh32a(&curdata[PTP_ece_OA_StorageID]);
1925			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]);
1928			ce[i].u.object.oi.Filename 	= strdup(((char*)&curdata[PTP_ece_OA_Name]));
1929			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);
1930			break;
1931                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			}
1951			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_OBJECTTRANSFER;
1952			ce[i].u.object.oid    		= dtoh32a(&curdata[PTP_ece_OI_ObjectID]);
1953			ce[i].u.object.oi.StorageID 	= 0; /* use as marker */
1954			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]);
1957			ce[i].u.object.oi.Filename 	= strdup(((char*)&curdata[PTP_ece_OI_Name]));
1958
1959			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);
1960			break;
1961		case PTP_EC_CANON_EOS_AvailListChanged: {	/* property desc */
1962			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]);
1965			unsigned char	*xdata = &curdata[PTP_ece_Prop_Desc_Data];
1966			unsigned int	j;
1967			PTPDevicePropDesc	*dpd;
1968
1969			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
1974			ptp_debug (params, "event %d: EOS prop %04x desc record, datasize %d, propxtype %d", i, proptype, size-PTP_ece_Prop_Desc_Data, propxtype);
1975			for (j=0;j<params->nrofcanon_props;j++)
1976				if (params->canon_props[j].proptype == proptype)
1977					break;
1978			if (j==params->nrofcanon_props) {
1979				ptp_debug (params, "event %d: propdesc %x, default value not found.", i, proptype);
1980				break;
1981			}
1982			dpd = &params->canon_props[j].dpd;
1983			/* 1 - uint16 ?
1984			 * 3 - uint16
1985			 * 7 - string?
1986			 */
1987			if (propxtype != 3) {
1988				ptp_debug (params, "event %d: propxtype is %x for %04x, unhandled, size %d", i, propxtype, proptype, size);
1989				for (j=0;j<size-PTP_ece_Prop_Desc_Data;j++)
1990					ptp_debug (params, "    %d: %02x", j, xdata[j]);
1991				break;
1992			}
1993			if (! propxcnt)
1994				break;
1995			if (propxcnt >= 2<<16) /* buggy or exploit */
1996				break;
1997
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;
2002			free (dpd->FORM.Enum.SupportedValue);
2003			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 */
2011				for (j=0;j<propxcnt;j++) {
2012					dpd->FORM.Enum.SupportedValue[j].u16 =
2013							ptp_unpack_EOS_ImageFormat( params, &xdata );
2014					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 )\
2021					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); 	\
2027						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 */ \
2029					} \
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:
2038					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);
2042					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));
2044					break;
2045				}
2046			}
2047			break;
2048		}
2049		case PTP_EC_CANON_EOS_PropValueChanged:
2050			if (size >= 0xc) {	/* property info */
2051				unsigned int j;
2052				uint32_t	proptype = dtoh32a(&curdata[PTP_ece_Prop_Subtype]);
2053				unsigned char	*xdata = &curdata[PTP_ece_Prop_Val_Data];
2054				PTPDevicePropDesc	*dpd;
2055
2056				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				}
2060				ptp_debug (params, "event %d: EOS prop %04x info record, datasize is %d", i, proptype, size-PTP_ece_Prop_Val_Data);
2061				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) ||
2066						(memcmp(params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data))) {
2067						params->canon_props[j].data = realloc(params->canon_props[j].data,size-PTP_ece_Prop_Val_Data);
2068						params->canon_props[j].size = size;
2069						memcpy (params->canon_props[j].data,xdata,size-PTP_ece_Prop_Val_Data);
2070					}
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]));
2076					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);
2079					memcpy(params->canon_props[j].data, xdata, size-PTP_ece_Prop_Val_Data);
2080					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;
2086
2087				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_PROPERTY;
2088				ce[i].u.propid = proptype;
2089
2090				/* 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 */
2127				switch (proptype) {
2128				case PTP_DPC_CANON_EOS_CameraTime:
2129				case PTP_DPC_CANON_EOS_UTCTime:
2130				case PTP_DPC_CANON_EOS_Summertime: /* basical the DST flag */
2131				case PTP_DPC_CANON_EOS_AvailableShots:
2132				case PTP_DPC_CANON_EOS_CaptureDestination:
2133				case PTP_DPC_CANON_EOS_WhiteBalanceXA:
2134				case PTP_DPC_CANON_EOS_WhiteBalanceXB:
2135				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:
2141				case PTP_DPC_CANON_EOS_AFSelectFocusArea:
2142				case PTP_DPC_CANON_EOS_ContinousAFMode:
2143				case PTP_DPC_CANON_EOS_MirrorUpSetting:
2144					dpd->DataType = PTP_DTC_UINT32;
2145					break;
2146				/* 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;
2152				case PTP_DPC_CANON_EOS_Aperture:
2153				case PTP_DPC_CANON_EOS_ShutterSpeed:
2154				case PTP_DPC_CANON_EOS_ISOSpeed:
2155				case PTP_DPC_CANON_EOS_FocusMode:
2156				case PTP_DPC_CANON_EOS_ColorSpace:
2157				case PTP_DPC_CANON_EOS_BatteryPower:
2158				case PTP_DPC_CANON_EOS_BatterySelect:
2159				case PTP_DPC_CANON_EOS_PTPExtensionVersion:
2160				case PTP_DPC_CANON_EOS_DriveMode:
2161				case PTP_DPC_CANON_EOS_AEB:
2162				case PTP_DPC_CANON_EOS_BracketMode:
2163				case PTP_DPC_CANON_EOS_QuickReviewTime:
2164				case PTP_DPC_CANON_EOS_EVFMode:
2165				case PTP_DPC_CANON_EOS_EVFOutputDevice:
2166				case PTP_DPC_CANON_EOS_AutoPowerOff:
2167				case PTP_DPC_CANON_EOS_EVFRecordStatus:
2168					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:
2173				case PTP_DPC_CANON_EOS_ExpCompensation:
2174					dpd->DataType = PTP_DTC_UINT8;
2175					break;
2176				case PTP_DPC_CANON_EOS_Owner:
2177				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:
2181					dpd->DataType = PTP_DTC_STR;
2182					break;
2183				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 */
2188				case PTP_DPC_CANON_EOS_DPOFVersion:
2189					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++)
2192						ptp_debug (params, "    %d: %02x", j, xdata[j]);
2193					break;
2194				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:
2205					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);
2207					for (j=0;j<size-PTP_ece_Prop_Val_Data;j++)
2208						ptp_debug (params, "    %d: %02x", j, xdata[j]);
2209					/* custom func entries look like this on the 400D: '5 0 0 0 ?' = 4 bytes size + 1 byte data */
2210					xdata += 4;
2211					break;
2212				/* yet unknown 32bit props */
2213				case PTP_DPC_CANON_EOS_ColorTemperature:
2214				case PTP_DPC_CANON_EOS_WftStatus:
2215				case PTP_DPC_CANON_EOS_LensStatus:
2216				case PTP_DPC_CANON_EOS_CardExtension:
2217				case PTP_DPC_CANON_EOS_TempStatus:
2218				case PTP_DPC_CANON_EOS_PhotoStudioMode:
2219				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:
2224				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:
2229				case PTP_DPC_CANON_EOS_AloMode:
2230				case PTP_DPC_CANON_EOS_Brightness:
2231					dpd->DataType = PTP_DTC_UINT32;
2232					ptp_debug (params, "event %d: Unknown EOS property %04x, datasize is %d, using uint32", i ,proptype, size-PTP_ece_Prop_Val_Data);
2233					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++)
2236						ptp_debug (params, "    %d: 0x%8x", j, dtoh32a(xdata+j*4));
2237					break;
2238				/* 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:
2243				case PTP_DPC_CANON_EOS_CustomFuncEx:
2244				case PTP_DPC_CANON_EOS_FocusInfoEx:
2245					break;
2246				default:
2247					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++)
2249						ptp_debug (params, "    %d: %02x", j, xdata[j]);
2250					break;
2251				}
2252				switch (dpd->DataType) {
2253				case PTP_DTC_UINT32:
2254					dpd->FactoryDefaultValue.u32	= dtoh32a(xdata);
2255					dpd->CurrentValue.u32		= dtoh32a(xdata);
2256					ptp_debug (params ,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u32);
2257					break;
2258				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;
2263				case PTP_DTC_UINT16:
2264					dpd->FactoryDefaultValue.u16	= dtoh16a(xdata);
2265					dpd->CurrentValue.u16		= dtoh16a(xdata);
2266					ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u16);
2267					break;
2268				case PTP_DTC_UINT8:
2269					dpd->FactoryDefaultValue.u8	= dtoh8a(xdata);
2270					dpd->CurrentValue.u8		= dtoh8a(xdata);
2271					ptp_debug (params,"event %d: currentvalue of %x is %x", i, proptype, dpd->CurrentValue.u8);
2272					break;
2273				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;
2278				case PTP_DTC_STR: {
2279#if 0 /* 5D MII and 400D aktually store plain ASCII in their string properties */
2280					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);
2283#else
2284					free (dpd->FactoryDefaultValue.str);
2285					dpd->FactoryDefaultValue.str	= strdup( (char*)xdata );
2286
2287					free (dpd->CurrentValue.str);
2288					dpd->CurrentValue.str		= strdup( (char*)xdata );
2289#endif
2290					ptp_debug (params,"event %d: currentvalue of %x is %s", i, proptype, dpd->CurrentValue.str);
2291					break;
2292				}
2293				default:
2294					/* debug is printed in switch above this one */
2295					break;
2296				}
2297
2298				/* ImageFormat and customFuncEx special handling (WARNING: dont move this in front of the dpd->DataType switch!) */
2299				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;
2305					dpd->FactoryDefaultValue.u16	= ptp_unpack_EOS_ImageFormat( params, &xdata );
2306					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;
2309				case PTP_DPC_CANON_EOS_CustomFuncEx:
2310					dpd->DataType = PTP_DTC_STR;
2311					free (dpd->FactoryDefaultValue.str);
2312					free (dpd->CurrentValue.str);
2313					dpd->FactoryDefaultValue.str	= ptp_unpack_EOS_CustomFuncEx( params, &xdata );
2314					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;
2317				case PTP_DPC_CANON_EOS_FocusInfoEx:
2318					dpd->DataType = PTP_DTC_STR;
2319					free (dpd->FactoryDefaultValue.str);
2320					free (dpd->CurrentValue.str);
2321					dpd->FactoryDefaultValue.str	= ptp_unpack_EOS_FocusInfoEx( params, &xdata, size );
2322					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;
2325				}
2326
2327				break;
2328		}
2329		/* one more information record handed to us */
2330		case PTP_EC_CANON_EOS_OLCInfoChanged: {
2331			uint32_t		len, curoff;
2332			uint16_t		mask,proptype;
2333			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 */
2338				unsigned int k;
2339				for (k=8;k<size;k++)
2340					ptp_debug (params, "    %d: %02x", k-8, curdata[k]);
2341			}
2342			len = dtoh32a(curdata+8);
2343			if ((len != size-8) && (len != size-4)) {
2344				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2345				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);
2347				break;
2348			}
2349			mask = dtoh16a(curdata+8+4);
2350			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			}
2356			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;
2369				dpd = _lookup_or_allocate_canon_prop(params, proptype);
2370				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;
2381				dpd = _lookup_or_allocate_canon_prop(params, proptype);
2382				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;
2393				dpd = _lookup_or_allocate_canon_prop(params, proptype);
2394				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) {
2430				int	value = (signed char)curdata[curoff+2];
2431				/* mask 0x0040: 7 bytes, 01 01 00 00 00 00 00 observed */
2432				/* exposure indicator */
2433				ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2434				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)",
2436					curdata[curoff],
2437					curdata[curoff+1],
2438					value/10,abs(value)%10,
2439					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 */
2462				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",
2465					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 */
2477				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",
2480					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		}
2541		case PTP_EC_CANON_EOS_CameraStatusChanged:
2542			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));
2545			params->eos_camerastatus = dtoh32a(curdata+8);
2546			break;
2547		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;
2552		case PTP_EC_CANON_EOS_BulbExposureTime:
2553			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2554			ce[i].u.info = malloc(strlen("BulbExposureTime 123456789012345678"));
2555			sprintf (ce[i].u.info, "BulbExposureTime %d",  dtoh32a(curdata+8));
2556			break;
2557		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;
2561		default:
2562			switch (type) {
2563#define XX(x)		case PTP_EC_CANON_EOS_##x: 								\
2564				ptp_debug (params, "event %d: unhandled EOS event "#x" (size %d)", i, size); 	\
2565				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);		\
2567				break;
2568			XX(RequestGetEvent)
2569			XX(RequestGetObjectInfoEx)
2570			XX(StorageStatusChanged)
2571			XX(StorageInfoChanged)
2572			XX(ObjectInfoChangedEx)
2573			XX(ObjectContentChanged)
2574			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			}
2590			if (size >= 0x8) {	/* event info */
2591				unsigned int j;
2592				/*ptp_debug (params, "data=%p, curdata=%p, datsize=%d, size=%d", data, curdata, datasize, size);*/
2593				for (j=8;j<size;j++)
2594					ptp_debug (params, "    %d: %02x", j, curdata[j]);
2595			}
2596			ce[i].type = PTP_CANON_EOS_CHANGES_TYPE_UNKNOWN;
2597			break;
2598		}
2599		curdata += size;
2600		i++;
2601		if (i >= entries) {
2602			ptp_debug (params, "BAD: i %d, entries %d", i, entries);
2603		}
2604	}
2605	if (!i) {
2606		free (ce);
2607		ce = NULL;
2608	}
2609	*pce = ce;
2610	return i;
2611}
2612
2613/*
2614    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
2621ptp_unpack_Nikon_EC (PTPParams *params, unsigned char* data, unsigned int len, PTPContainer **ec, unsigned int *cnt)
2622{
2623	unsigned int i;
2624
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]);
2631	if (*cnt > (len-PTP_nikon_ec_Code)/PTP_nikon_ec_Size) { /* broken cnt? */
2632		*cnt = 0;
2633		return;
2634	}
2635	if (!*cnt)
2636		return;
2637
2638	*ec = malloc(sizeof(PTPContainer)*(*cnt));
2639
2640	for (i=0;i<*cnt;i++) {
2641		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;
2645	}
2646}
2647
2648
2649static 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}
2689
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;
2729	handles->Handler = calloc(nrofobs,sizeof(handles->Handler[0]));
2730	if (!handles->Handler) return PTP_RC_GeneralError;
2731	*oinfos = calloc(nrofobs,sizeof((*oinfos)[0]));
2732	if (!*oinfos) return PTP_RC_GeneralError;
2733	*flags  = calloc(nrofobs,sizeof((*flags)[0]));
2734	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) {
2774		unsigned int changed = 0;
2775		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}
2825