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