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