libusb20_desc.c revision 286333
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 41static const uint32_t libusb20_me_encode_empty[2]; /* dummy */ 42 43LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_DEVICE_DESC); 44LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_ENDPOINT_DESC); 45LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_INTERFACE_DESC); 46LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONFIG_DESC); 47LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_CONTROL_SETUP); 48LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_ENDPT_COMP_DESC); 49LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_USB_20_DEVCAP_DESC); 50LIBUSB20_MAKE_STRUCT_FORMAT(LIBUSB20_SS_USB_DEVCAP_DESC); 51LIBUSB20_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 *------------------------------------------------------------------------*/ 60struct libusb20_config * 61libusb20_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 *------------------------------------------------------------------------*/ 246const uint8_t * 247libusb20_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 *------------------------------------------------------------------------*/ 286uint8_t 287libusb20_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 *------------------------------------------------------------------------*/ 298uint16_t 299libusb20_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 *------------------------------------------------------------------------*/ 316uint16_t 317libusb20_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 } 535done: 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 *------------------------------------------------------------------------*/ 550uint16_t 551libusb20_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 } 792done: 793 return (len_old - len); 794} 795