Last year big HID parser modification introduced a regression reported
by Benjamin Baier [0].  He confirmed that the diff below fixes it for
his use case.  

I'm looking for more tests to know if this does not break anything else.

[0] http://marc.info/?l=openbsd-bugs&m=142153086729320&w=2

Index: parse.c
===================================================================
RCS file: /cvs/src/lib/libusbhid/parse.c,v
retrieving revision 1.10
diff -u -p -r1.10 parse.c
--- parse.c     18 Jan 2015 17:16:06 -0000      1.10
+++ parse.c     31 Jan 2015 11:34:55 -0000
@@ -67,6 +67,8 @@ struct hid_data {
        uint8_t ousage;         /* current "usages_min/max" offset */
        uint8_t susage;         /* usage set flags */
        int32_t reportid;       /* requested report ID */
+       struct hid_item savedcoll; /* save coll until we know the ID */
+       uint8_t hassavedcoll;
 };
 
 static void
@@ -151,6 +153,7 @@ hid_start_parse(report_desc_t d, int kin
        s->end = d->data + d->size;
        s->kindset = kindset;
        s->reportid = id;
+       s->hassavedcoll = 0;
        return (s);
 }
 
@@ -191,10 +194,20 @@ hid_get_byte(struct hid_data *s, const u
        return (retval);
 }
 
+#define REPORT_SAVED_COLL \
+       do { \
+               if (s->hassavedcoll) { \
+                       *h = s->savedcoll; \
+                       h->report_ID = c->report_ID; \
+                       s->hassavedcoll = 0; \
+                       return (1); \
+               } \
+       } while(0)
+
 static int
 hid_get_item_raw(hid_data_t s, hid_item_t *h)
 {
-       hid_item_t *c;
+       hid_item_t nc, *c;
        unsigned int bTag, bType, bSize;
        int32_t mask;
        int32_t dval;
@@ -207,6 +220,7 @@ hid_get_item_raw(hid_data_t s, hid_item_
  top:
        /* check if there is an array of items */
        if (s->icount < s->ncount) {
+               REPORT_SAVED_COLL;
                /* get current usage */
                if (s->iusage < s->nusage) {
                        dval = s->usages_min[s->iusage] + s->ousage;
@@ -328,13 +342,23 @@ hid_get_item_raw(hid_data_t s, hid_item_
                                c->collection = dval;
                                c->collevel++;
                                c->usage = s->usage_last;
-                               *h = *c;
-                               return (1);
+                               nc = *c;
+                               if (s->hassavedcoll) {
+                                       *h = s->savedcoll;
+                                       h->report_ID = nc.report_ID;
+                                       s->savedcoll = nc;
+                                       return (1);
+                               } else {
+                                       s->hassavedcoll = 1;
+                                       s->savedcoll = nc;
+                               }
+                               goto top;
                        case 11:        /* Feature */
                                c->kind = hid_feature;
                                c->flags = dval;
                                goto ret;
                        case 12:        /* End collection */
+                               REPORT_SAVED_COLL;
                                c->kind = hid_endcollection;
                                if (c->collevel == 0) {
                                        /* Invalid end collection. */

Reply via email to