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