1 /* $FreeBSD: stable/10/lib/libusb/libusb20_desc.c 286333 2015-08-05 18:52:40Z pfg $ */
2 /*-
3 * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28 #include LIBUSB_GLOBAL_INCLUDE_FILE
29 #else
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <time.h>
34 #include <sys/queue.h>
35 #endif
36
37 #include "libusb20.h"
38 #include "libusb20_desc.h"
39 #include "libusb20_int.h"
40
41 static const uint32_t libusb20_me_encode_empty[2]; /* dummy */
42
43 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC);
44 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC);
45 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC);
46 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC);
47 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP);
48 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC);
49 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC);
50 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC);
51 LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_BOS_DESCRIPTOR);
52
53 /*------------------------------------------------------------------------*
54 * libusb20_parse_config_desc
55 *
56 * Return values:
57 * NULL: Out of memory.
58 * Else: A valid config structure pointer which must be passed to "free()"
59 *------------------------------------------------------------------------*/
60 struct libusb20_config *
libusb20_parse_config_desc(const void * config_desc)61 libusb20_parse_config_desc(const void *config_desc)
62 {
63 struct libusb20_config *lub_config;
64 struct libusb20_interface *lub_interface;
65 struct libusb20_interface *lub_alt_interface;
66 struct libusb20_interface *last_if;
67 struct libusb20_endpoint *lub_endpoint;
68 struct libusb20_endpoint *last_ep;
69
70 struct libusb20_me_struct pcdesc;
71 const uint8_t *ptr;
72 uint32_t size;
73 uint16_t niface_no_alt;
74 uint16_t niface;
75 uint16_t nendpoint;
76 uint16_t iface_no;
77
78 ptr = config_desc;
79 if (ptr[1] != LIBUSB20_DT_CONFIG) {
80 return (NULL); /* not config descriptor */
81 }
82 /*
83 * The first "bInterfaceNumber" should never have the value 0xff.
84 * Then it is corrupt.
85 */
86 niface_no_alt = 0;
87 nendpoint = 0;
88 niface = 0;
89 iface_no = 0xFFFF;
90 ptr = NULL;
91
92 /* get "wTotalLength" and setup "pcdesc" */
93 pcdesc.ptr = LIBUSB20_ADD_BYTES(config_desc, 0);
94 pcdesc.len =
95 ((const uint8_t *)config_desc)[2] |
96 (((const uint8_t *)config_desc)[3] << 8);
97 pcdesc.type = LIBUSB20_ME_IS_RAW;
98
99 /* descriptor pre-scan */
100 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
101 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
102 nendpoint++;
103 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
104 niface++;
105 /* check "bInterfaceNumber" */
106 if (ptr[2] != iface_no) {
107 iface_no = ptr[2];
108 niface_no_alt++;
109 }
110 }
111 }
112
113 /* sanity checking */
114 if (niface >= 256) {
115 return (NULL); /* corrupt */
116 }
117 if (nendpoint >= 256) {
118 return (NULL); /* corrupt */
119 }
120 size = sizeof(*lub_config) +
121 (niface * sizeof(*lub_interface)) +
122 (nendpoint * sizeof(*lub_endpoint)) +
123 pcdesc.len;
124
125 lub_config = malloc(size);
126 if (lub_config == NULL) {
127 return (NULL); /* out of memory */
128 }
129 /* make sure memory is initialised */
130 memset(lub_config, 0, size);
131
132 lub_interface = (void *)(lub_config + 1);
133 lub_alt_interface = (void *)(lub_interface + niface_no_alt);
134 lub_endpoint = (void *)(lub_interface + niface);
135
136 /*
137 * Make a copy of the config descriptor, so that the caller can free
138 * the inital config descriptor pointer!
139 */
140 memcpy((void *)(lub_endpoint + nendpoint), config_desc, pcdesc.len);
141
142 ptr = (const void *)(lub_endpoint + nendpoint);
143 pcdesc.ptr = LIBUSB20_ADD_BYTES(ptr, 0);
144
145 /* init config structure */
146
147 LIBUSB20_INIT(LIBUSB20_CONFIG_DESC, &lub_config->desc);
148
149 if (libusb20_me_decode(ptr, ptr[0], &lub_config->desc)) {
150 /* ignore */
151 }
152 lub_config->num_interface = 0;
153 lub_config->interface = lub_interface;
154 lub_config->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
155 lub_config->extra.len = -ptr[0];
156 lub_config->extra.type = LIBUSB20_ME_IS_RAW;
157
158 /* reset states */
159 niface = 0;
160 iface_no = 0xFFFF;
161 ptr = NULL;
162 lub_interface--;
163 lub_endpoint--;
164 last_if = NULL;
165 last_ep = NULL;
166
167 /* descriptor pre-scan */
168 while ((ptr = libusb20_desc_foreach(&pcdesc, ptr))) {
169 if (ptr[1] == LIBUSB20_DT_ENDPOINT) {
170 if (last_if) {
171 lub_endpoint++;
172 last_ep = lub_endpoint;
173 last_if->num_endpoints++;
174
175 LIBUSB20_INIT(LIBUSB20_ENDPOINT_DESC, &last_ep->desc);
176
177 if (libusb20_me_decode(ptr, ptr[0], &last_ep->desc)) {
178 /* ignore */
179 }
180 last_ep->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
181 last_ep->extra.len = 0;
182 last_ep->extra.type = LIBUSB20_ME_IS_RAW;
183 } else {
184 lub_config->extra.len += ptr[0];
185 }
186
187 } else if ((ptr[1] == LIBUSB20_DT_INTERFACE) && (ptr[0] >= 4)) {
188 if (ptr[2] != iface_no) {
189 /* new interface */
190 iface_no = ptr[2];
191 lub_interface++;
192 lub_config->num_interface++;
193 last_if = lub_interface;
194 niface++;
195 } else {
196 /* one more alternate setting */
197 lub_interface->num_altsetting++;
198 last_if = lub_alt_interface;
199 lub_alt_interface++;
200 }
201
202 LIBUSB20_INIT(LIBUSB20_INTERFACE_DESC, &last_if->desc);
203
204 if (libusb20_me_decode(ptr, ptr[0], &last_if->desc)) {
205 /* ignore */
206 }
207 /*
208 * Sometimes USB devices have corrupt interface
209 * descriptors and we need to overwrite the provided
210 * interface number!
211 */
212 last_if->desc.bInterfaceNumber = niface - 1;
213 last_if->extra.ptr = LIBUSB20_ADD_BYTES(ptr, ptr[0]);
214 last_if->extra.len = 0;
215 last_if->extra.type = LIBUSB20_ME_IS_RAW;
216 last_if->endpoints = lub_endpoint + 1;
217 last_if->altsetting = lub_alt_interface;
218 last_if->num_altsetting = 0;
219 last_if->num_endpoints = 0;
220 last_ep = NULL;
221 } else {
222 /* unknown descriptor */
223 if (last_if) {
224 if (last_ep) {
225 last_ep->extra.len += ptr[0];
226 } else {
227 last_if->extra.len += ptr[0];
228 }
229 } else {
230 lub_config->extra.len += ptr[0];
231 }
232 }
233 }
234 return (lub_config);
235 }
236
237 /*------------------------------------------------------------------------*
238 * libusb20_desc_foreach
239 *
240 * Safe traversal of USB descriptors.
241 *
242 * Return values:
243 * NULL: End of descriptors
244 * Else: Pointer to next descriptor
245 *------------------------------------------------------------------------*/
246 const uint8_t *
libusb20_desc_foreach(const struct libusb20_me_struct * pdesc,const uint8_t * psubdesc)247 libusb20_desc_foreach(const struct libusb20_me_struct *pdesc,
248 const uint8_t *psubdesc)
249 {
250 const uint8_t *start;
251 const uint8_t *end;
252 const uint8_t *desc_next;
253
254 /* be NULL safe */
255 if (pdesc == NULL)
256 return (NULL);
257
258 start = (const uint8_t *)pdesc->ptr;
259 end = LIBUSB20_ADD_BYTES(start, pdesc->len);
260
261 /* get start of next descriptor */
262 if (psubdesc == NULL)
263 psubdesc = start;
264 else
265 psubdesc = psubdesc + psubdesc[0];
266
267 /* check that the next USB descriptor is within the range */
268 if ((psubdesc < start) || (psubdesc >= end))
269 return (NULL); /* out of range, or EOD */
270
271 /* check start of the second next USB descriptor, if any */
272 desc_next = psubdesc + psubdesc[0];
273 if ((desc_next < start) || (desc_next > end))
274 return (NULL); /* out of range */
275
276 /* check minimum descriptor length */
277 if (psubdesc[0] < 3)
278 return (NULL); /* too short descriptor */
279
280 return (psubdesc); /* return start of next descriptor */
281 }
282
283 /*------------------------------------------------------------------------*
284 * libusb20_me_get_1 - safety wrapper to read out one byte
285 *------------------------------------------------------------------------*/
286 uint8_t
libusb20_me_get_1(const struct libusb20_me_struct * ie,uint16_t offset)287 libusb20_me_get_1(const struct libusb20_me_struct *ie, uint16_t offset)
288 {
289 if (offset < ie->len) {
290 return (*((uint8_t *)LIBUSB20_ADD_BYTES(ie->ptr, offset)));
291 }
292 return (0);
293 }
294
295 /*------------------------------------------------------------------------*
296 * libusb20_me_get_2 - safety wrapper to read out one word
297 *------------------------------------------------------------------------*/
298 uint16_t
libusb20_me_get_2(const struct libusb20_me_struct * ie,uint16_t offset)299 libusb20_me_get_2(const struct libusb20_me_struct *ie, uint16_t offset)
300 {
301 return (libusb20_me_get_1(ie, offset) |
302 (libusb20_me_get_1(ie, offset + 1) << 8));
303 }
304
305 /*------------------------------------------------------------------------*
306 * libusb20_me_encode - encode a message structure
307 *
308 * Description of parameters:
309 * "len" - maximum length of output buffer
310 * "ptr" - pointer to output buffer. If NULL, no data will be written
311 * "pd" - source structure
312 *
313 * Return values:
314 * 0..65535 - Number of bytes used, limited by the "len" input parameter.
315 *------------------------------------------------------------------------*/
316 uint16_t
libusb20_me_encode(void * ptr,uint16_t len,const void * pd)317 libusb20_me_encode(void *ptr, uint16_t len, const void *pd)
318 {
319 const uint8_t *pf; /* pointer to format data */
320 uint8_t *buf; /* pointer to output buffer */
321
322 uint32_t pd_offset; /* decoded structure offset */
323 uint16_t len_old; /* old length */
324 uint16_t pd_count; /* decoded element count */
325 uint8_t me; /* message element */
326
327 /* initialise */
328
329 len_old = len;
330 buf = ptr;
331 pd_offset = sizeof(void *);
332 pf = (*((struct libusb20_me_format *const *)pd))->format;
333
334 /* scan */
335
336 while (1) {
337
338 /* get information element */
339
340 me = (pf[0]) & LIBUSB20_ME_MASK;
341 pd_count = pf[1] | (pf[2] << 8);
342 pf += 3;
343
344 /* encode the message element */
345
346 switch (me) {
347 case LIBUSB20_ME_INT8:
348 while (pd_count--) {
349 uint8_t temp;
350
351 if (len < 1) /* overflow */
352 goto done;
353 if (buf) {
354 temp = *((const uint8_t *)
355 LIBUSB20_ADD_BYTES(pd, pd_offset));
356 buf[0] = temp;
357 buf += 1;
358 }
359 pd_offset += 1;
360 len -= 1;
361 }
362 break;
363
364 case LIBUSB20_ME_INT16:
365 pd_offset = -((-pd_offset) & ~1); /* align */
366 while (pd_count--) {
367 uint16_t temp;
368
369 if (len < 2) /* overflow */
370 goto done;
371
372 if (buf) {
373 temp = *((const uint16_t *)
374 LIBUSB20_ADD_BYTES(pd, pd_offset));
375 buf[1] = (temp >> 8) & 0xFF;
376 buf[0] = temp & 0xFF;
377 buf += 2;
378 }
379 pd_offset += 2;
380 len -= 2;
381 }
382 break;
383
384 case LIBUSB20_ME_INT32:
385 pd_offset = -((-pd_offset) & ~3); /* align */
386 while (pd_count--) {
387 uint32_t temp;
388
389 if (len < 4) /* overflow */
390 goto done;
391 if (buf) {
392 temp = *((const uint32_t *)
393 LIBUSB20_ADD_BYTES(pd, pd_offset));
394 buf[3] = (temp >> 24) & 0xFF;
395 buf[2] = (temp >> 16) & 0xFF;
396 buf[1] = (temp >> 8) & 0xFF;
397 buf[0] = temp & 0xFF;
398 buf += 4;
399 }
400 pd_offset += 4;
401 len -= 4;
402 }
403 break;
404
405 case LIBUSB20_ME_INT64:
406 pd_offset = -((-pd_offset) & ~7); /* align */
407 while (pd_count--) {
408 uint64_t temp;
409
410 if (len < 8) /* overflow */
411 goto done;
412 if (buf) {
413
414 temp = *((const uint64_t *)
415 LIBUSB20_ADD_BYTES(pd, pd_offset));
416 buf[7] = (temp >> 56) & 0xFF;
417 buf[6] = (temp >> 48) & 0xFF;
418 buf[5] = (temp >> 40) & 0xFF;
419 buf[4] = (temp >> 32) & 0xFF;
420 buf[3] = (temp >> 24) & 0xFF;
421 buf[2] = (temp >> 16) & 0xFF;
422 buf[1] = (temp >> 8) & 0xFF;
423 buf[0] = temp & 0xFF;
424 buf += 8;
425 }
426 pd_offset += 8;
427 len -= 8;
428 }
429 break;
430
431 case LIBUSB20_ME_STRUCT:
432 pd_offset = -((-pd_offset) &
433 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
434 while (pd_count--) {
435 void *src_ptr;
436 uint16_t src_len;
437 struct libusb20_me_struct *ps;
438
439 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
440
441 switch (ps->type) {
442 case LIBUSB20_ME_IS_RAW:
443 src_len = ps->len;
444 src_ptr = ps->ptr;
445 break;
446
447 case LIBUSB20_ME_IS_ENCODED:
448 if (ps->len == 0) {
449 /*
450 * Length is encoded
451 * in the data itself
452 * and should be
453 * correct:
454 */
455 ps->len = 0xFFFF;
456 }
457 src_len = libusb20_me_get_1(pd, 0);
458 src_ptr = LIBUSB20_ADD_BYTES(ps->ptr, 1);
459 if (src_len == 0xFF) {
460 /* length is escaped */
461 src_len = libusb20_me_get_2(pd, 1);
462 src_ptr =
463 LIBUSB20_ADD_BYTES(ps->ptr, 3);
464 }
465 break;
466
467 case LIBUSB20_ME_IS_DECODED:
468 /* reserve 3 length bytes */
469 src_len = libusb20_me_encode(NULL,
470 0xFFFF - 3, ps->ptr);
471 src_ptr = NULL;
472 break;
473
474 default: /* empty structure */
475 src_len = 0;
476 src_ptr = NULL;
477 break;
478 }
479
480 if (src_len > 0xFE) {
481 if (src_len > (0xFFFF - 3))
482 /* overflow */
483 goto done;
484
485 if (len < (src_len + 3))
486 /* overflow */
487 goto done;
488
489 if (buf) {
490 buf[0] = 0xFF;
491 buf[1] = (src_len & 0xFF);
492 buf[2] = (src_len >> 8) & 0xFF;
493 buf += 3;
494 }
495 len -= (src_len + 3);
496 } else {
497 if (len < (src_len + 1))
498 /* overflow */
499 goto done;
500
501 if (buf) {
502 buf[0] = (src_len & 0xFF);
503 buf += 1;
504 }
505 len -= (src_len + 1);
506 }
507
508 /* check for buffer and non-zero length */
509
510 if (buf && src_len) {
511 if (ps->type == LIBUSB20_ME_IS_DECODED) {
512 /*
513 * Repeat encode
514 * procedure - we have
515 * room for the
516 * complete structure:
517 */
518 uint16_t dummy;
519
520 dummy = libusb20_me_encode(buf,
521 0xFFFF - 3, ps->ptr);
522 } else {
523 bcopy(src_ptr, buf, src_len);
524 }
525 buf += src_len;
526 }
527 pd_offset += sizeof(struct libusb20_me_struct);
528 }
529 break;
530
531 default:
532 goto done;
533 }
534 }
535 done:
536 return (len_old - len);
537 }
538
539 /*------------------------------------------------------------------------*
540 * libusb20_me_decode - decode a message into a decoded structure
541 *
542 * Description of parameters:
543 * "ptr" - message pointer
544 * "len" - message length
545 * "pd" - pointer to decoded structure
546 *
547 * Returns:
548 * "0..65535" - number of bytes decoded, limited by "len"
549 *------------------------------------------------------------------------*/
550 uint16_t
libusb20_me_decode(const void * ptr,uint16_t len,void * pd)551 libusb20_me_decode(const void *ptr, uint16_t len, void *pd)
552 {
553 const uint8_t *pf; /* pointer to format data */
554 const uint8_t *buf; /* pointer to input buffer */
555
556 uint32_t pd_offset; /* decoded structure offset */
557 uint16_t len_old; /* old length */
558 uint16_t pd_count; /* decoded element count */
559 uint8_t me; /* message element */
560
561 /* initialise */
562
563 len_old = len;
564 buf = ptr;
565 pd_offset = sizeof(void *);
566 pf = (*((struct libusb20_me_format **)pd))->format;
567
568 /* scan */
569
570 while (1) {
571
572 /* get information element */
573
574 me = (pf[0]) & LIBUSB20_ME_MASK;
575 pd_count = pf[1] | (pf[2] << 8);
576 pf += 3;
577
578 /* decode the message element by type */
579
580 switch (me) {
581 case LIBUSB20_ME_INT8:
582 while (pd_count--) {
583 uint8_t temp;
584
585 if (len < 1) {
586 len = 0;
587 temp = 0;
588 } else {
589 len -= 1;
590 temp = buf[0];
591 buf++;
592 }
593 *((uint8_t *)LIBUSB20_ADD_BYTES(pd,
594 pd_offset)) = temp;
595 pd_offset += 1;
596 }
597 break;
598
599 case LIBUSB20_ME_INT16:
600 pd_offset = -((-pd_offset) & ~1); /* align */
601 while (pd_count--) {
602 uint16_t temp;
603
604 if (len < 2) {
605 len = 0;
606 temp = 0;
607 } else {
608 len -= 2;
609 temp = buf[1] << 8;
610 temp |= buf[0];
611 buf += 2;
612 }
613 *((uint16_t *)LIBUSB20_ADD_BYTES(pd,
614 pd_offset)) = temp;
615 pd_offset += 2;
616 }
617 break;
618
619 case LIBUSB20_ME_INT32:
620 pd_offset = -((-pd_offset) & ~3); /* align */
621 while (pd_count--) {
622 uint32_t temp;
623
624 if (len < 4) {
625 len = 0;
626 temp = 0;
627 } else {
628 len -= 4;
629 temp = buf[3] << 24;
630 temp |= buf[2] << 16;
631 temp |= buf[1] << 8;
632 temp |= buf[0];
633 buf += 4;
634 }
635
636 *((uint32_t *)LIBUSB20_ADD_BYTES(pd,
637 pd_offset)) = temp;
638 pd_offset += 4;
639 }
640 break;
641
642 case LIBUSB20_ME_INT64:
643 pd_offset = -((-pd_offset) & ~7); /* align */
644 while (pd_count--) {
645 uint64_t temp;
646
647 if (len < 8) {
648 len = 0;
649 temp = 0;
650 } else {
651 len -= 8;
652 temp = ((uint64_t)buf[7]) << 56;
653 temp |= ((uint64_t)buf[6]) << 48;
654 temp |= ((uint64_t)buf[5]) << 40;
655 temp |= ((uint64_t)buf[4]) << 32;
656 temp |= buf[3] << 24;
657 temp |= buf[2] << 16;
658 temp |= buf[1] << 8;
659 temp |= buf[0];
660 buf += 8;
661 }
662
663 *((uint64_t *)LIBUSB20_ADD_BYTES(pd,
664 pd_offset)) = temp;
665 pd_offset += 8;
666 }
667 break;
668
669 case LIBUSB20_ME_STRUCT:
670 pd_offset = -((-pd_offset) &
671 ~(LIBUSB20_ME_STRUCT_ALIGN - 1)); /* align */
672 while (pd_count--) {
673 uint16_t temp;
674 uint16_t dummy;
675 struct libusb20_me_struct *ps;
676
677 ps = LIBUSB20_ADD_BYTES(pd, pd_offset);
678
679 if (ps->type == LIBUSB20_ME_IS_ENCODED) {
680 /*
681 * Pre-store a de-constified
682 * pointer to the raw
683 * structure:
684 */
685 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
686
687 /*
688 * Get the correct number of
689 * length bytes:
690 */
691 if (len != 0) {
692 if (buf[0] == 0xFF) {
693 ps->len = 3;
694 } else {
695 ps->len = 1;
696 }
697 } else {
698 ps->len = 0;
699 }
700 }
701 /* get the structure length */
702
703 if (len != 0) {
704 if (buf[0] == 0xFF) {
705 if (len < 3) {
706 len = 0;
707 temp = 0;
708 } else {
709 len -= 3;
710 temp = buf[1] |
711 (buf[2] << 8);
712 buf += 3;
713 }
714 } else {
715 len -= 1;
716 temp = buf[0];
717 buf += 1;
718 }
719 } else {
720 len = 0;
721 temp = 0;
722 }
723 /* check for invalid length */
724
725 if (temp > len) {
726 len = 0;
727 temp = 0;
728 }
729 /* check wanted structure type */
730
731 switch (ps->type) {
732 case LIBUSB20_ME_IS_ENCODED:
733 /* check for zero length */
734 if (temp == 0) {
735 /*
736 * The pointer must
737 * be valid:
738 */
739 ps->ptr = LIBUSB20_ADD_BYTES(
740 libusb20_me_encode_empty, 0);
741 ps->len = 1;
742 } else {
743 ps->len += temp;
744 }
745 break;
746
747 case LIBUSB20_ME_IS_RAW:
748 /* update length and pointer */
749 ps->len = temp;
750 ps->ptr = LIBUSB20_ADD_BYTES(buf, 0);
751 break;
752
753 case LIBUSB20_ME_IS_EMPTY:
754 case LIBUSB20_ME_IS_DECODED:
755 /* check for non-zero length */
756 if (temp != 0) {
757 /* update type */
758 ps->type = LIBUSB20_ME_IS_DECODED;
759 ps->len = 0;
760 /*
761 * Recursivly decode
762 * the next structure
763 */
764 dummy = libusb20_me_decode(buf,
765 temp, ps->ptr);
766 } else {
767 /* update type */
768 ps->type = LIBUSB20_ME_IS_EMPTY;
769 ps->len = 0;
770 }
771 break;
772
773 default:
774 /*
775 * nothing to do - should
776 * not happen
777 */
778 ps->ptr = NULL;
779 ps->len = 0;
780 break;
781 }
782 buf += temp;
783 len -= temp;
784 pd_offset += sizeof(struct libusb20_me_struct);
785 }
786 break;
787
788 default:
789 goto done;
790 }
791 }
792 done:
793 return (len_old - len);
794 }
795