[PATCH 1/6] hidclass.sys: Create link collection caps during parsing.

Rémi Bernon rbernon at codeweavers.com
Fri Jun 18 02:39:35 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/hidclass.sys/descriptor.c     | 67 ++++++++++++++++++------------
 dlls/ntoskrnl.exe/tests/ntoskrnl.c | 25 ++++++-----
 2 files changed, 56 insertions(+), 36 deletions(-)

diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c
index 86b68863308..f7fcccf55d4 100644
--- a/dlls/hidclass.sys/descriptor.c
+++ b/dlls/hidclass.sys/descriptor.c
@@ -306,6 +306,9 @@ struct hid_parser_state
     DWORD                  stack_size;
     DWORD                  global_idx;
     DWORD                  collection_idx;
+
+    struct hid_value_caps *collections;
+    DWORD                  collections_size;
 };
 
 static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index )
@@ -390,12 +393,24 @@ static BOOL parse_new_collection( struct hid_parser_state *state )
         return FALSE;
     }
 
+    if (!array_reserve( &state->collections, &state->collections_size, state->caps.NumberLinkCollectionNodes ))
+    {
+        ERR( "HID parser collections overflow!\n" );
+        return FALSE;
+    }
+
     copy_collection_items( state->stack + state->collection_idx, &state->items );
     state->collection_idx++;
 
+    state->collections[state->caps.NumberLinkCollectionNodes] = state->items;
     state->items.link_collection = state->caps.NumberLinkCollectionNodes;
     state->items.link_usage_page = state->items.usage_page;
     state->items.link_usage = state->items.usage_min;
+    if (!state->caps.NumberLinkCollectionNodes)
+    {
+        state->caps.UsagePage = state->items.usage_page;
+        state->caps.Usage = state->items.usage_min;
+    }
     state->caps.NumberLinkCollectionNodes++;
 
     reset_local_items( state );
@@ -421,6 +436,7 @@ static void free_parser_state( struct hid_parser_state *state )
     if (state->global_idx) ERR( "%u unpopped device caps on the stack\n", state->global_idx );
     if (state->collection_idx) ERR( "%u unpopped device collection on the stack\n", state->collection_idx );
     free( state->stack );
+    free( state->collections );
     free( state );
 }
 
@@ -727,10 +743,8 @@ static void preparse_collection(const struct collection *root, const struct coll
         WINE_HIDP_PREPARSED_DATA *data, struct preparse_ctx *ctx)
 {
     WINE_HID_ELEMENT *elem = HID_ELEMS(data);
-    WINE_HID_LINK_COLLECTION_NODE *nodes = HID_NODES(data);
     struct feature *f;
     struct collection *c;
-    struct list *entry;
 
     LIST_FOR_EACH_ENTRY(f, &base->features, struct feature, entry)
     {
@@ -775,33 +789,18 @@ static void preparse_collection(const struct collection *root, const struct coll
         }
     }
 
-    if (root != base)
-    {
-        nodes[base->index].LinkUsagePage = base->caps.UsagePage;
-        nodes[base->index].LinkUsage = base->caps.NotRange.Usage;
-        nodes[base->index].Parent = base->parent == root ? 0 : base->parent->index;
-        nodes[base->index].CollectionType = base->type;
-        nodes[base->index].IsAlias = 0;
-
-        if ((entry = list_head(&base->collections)))
-            nodes[base->index].FirstChild = LIST_ENTRY(entry, struct collection, entry)->index;
-    }
-
     LIST_FOR_EACH_ENTRY(c, &base->collections, struct collection, entry)
-    {
         preparse_collection(root, c, data, ctx);
-
-        if ((entry = list_next(&base->collections, &c->entry)))
-            nodes[c->index].NextSibling = LIST_ENTRY(entry, struct collection, entry)->index;
-        if (root != base) nodes[base->index].NumberOfChildren++;
-    }
 }
 
-static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_collection, unsigned int node_count)
+static WINE_HIDP_PREPARSED_DATA *build_preparsed_data( struct collection *base_collection,
+                                                       struct hid_parser_state *state )
 {
+    WINE_HID_LINK_COLLECTION_NODE *nodes;
     WINE_HIDP_PREPARSED_DATA *data;
     unsigned int report_count;
     unsigned int size;
+    DWORD i;
 
     struct preparse_ctx ctx;
     unsigned int element_off;
@@ -816,18 +815,34 @@ static WINE_HIDP_PREPARSED_DATA* build_PreparseData(struct collection *base_coll
     size = element_off + (ctx.elem_count * sizeof(WINE_HID_ELEMENT));
 
     nodes_offset = size;
-    size += node_count * sizeof(WINE_HID_LINK_COLLECTION_NODE);
+    size += state->caps.NumberLinkCollectionNodes * sizeof(WINE_HID_LINK_COLLECTION_NODE);
 
     if (!(data = calloc(1, size))) return NULL;
     data->magic = HID_MAGIC;
     data->dwSize = size;
-    data->caps.Usage = base_collection->caps.NotRange.Usage;
-    data->caps.UsagePage = base_collection->caps.UsagePage;
-    data->caps.NumberLinkCollectionNodes = node_count;
+    data->caps = state->caps;
     data->elementOffset = element_off;
     data->nodesOffset = nodes_offset;
 
     preparse_collection(base_collection, base_collection, data, &ctx);
+
+    nodes = HID_NODES( data );
+    for (i = 0; i < data->caps.NumberLinkCollectionNodes; ++i)
+    {
+        nodes[i].LinkUsagePage = state->collections[i].usage_page;
+        nodes[i].LinkUsage = state->collections[i].usage_min;
+        nodes[i].Parent = state->collections[i].link_collection;
+        nodes[i].CollectionType = state->collections[i].bit_field;
+        nodes[i].IsAlias = 0;
+
+        if (i > 0)
+        {
+            nodes[i].NextSibling = nodes[nodes[i].Parent].FirstChild;
+            nodes[nodes[i].Parent].FirstChild = i;
+            nodes[nodes[i].Parent].NumberOfChildren++;
+        }
+    }
+
     return data;
 }
 
@@ -889,7 +904,7 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
 
     debug_collection(base);
 
-    if ((data = build_PreparseData(base, cidx)))
+    if ((data = build_preparsed_data( base, state )))
         debug_print_preparsed(data);
     free_collection(base);
 
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 5453af8ff1c..19099a5a19c 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -1500,6 +1500,20 @@ static void test_pnp_driver(struct testsign_context *ctx)
                         (val).member, (exp).member)
 #define check_member(val, exp, fmt, member) check_member_(__FILE__, __LINE__, val, exp, fmt, member)
 
+#define check_hidp_link_collection_node(a, b) check_hidp_link_collection_node_(__LINE__, a, b)
+static inline void check_hidp_link_collection_node_(int line, HIDP_LINK_COLLECTION_NODE *node,
+                                                    const HIDP_LINK_COLLECTION_NODE *exp)
+{
+    check_member_(__FILE__, line, *node, *exp, "%04x", LinkUsage);
+    check_member_(__FILE__, line, *node, *exp, "%04x", LinkUsagePage);
+    check_member_(__FILE__, line, *node, *exp, "%d", Parent);
+    check_member_(__FILE__, line, *node, *exp, "%d", NumberOfChildren);
+    check_member_(__FILE__, line, *node, *exp, "%d", NextSibling);
+    check_member_(__FILE__, line, *node, *exp, "%d", FirstChild);
+    check_member_(__FILE__, line, *node, *exp, "%d", CollectionType);
+    check_member_(__FILE__, line, *node, *exp, "%d", IsAlias);
+}
+
 #define check_hidp_button_caps(a, b) check_hidp_button_caps_(__LINE__, a, b)
 static inline void check_hidp_button_caps_(int line, HIDP_BUTTON_CAPS *caps, const HIDP_BUTTON_CAPS *exp)
 {
@@ -1850,16 +1864,7 @@ static void test_hidp(HANDLE file, int report_id)
     for (i = 0; i < ARRAY_SIZE(expect_collections); ++i)
     {
         winetest_push_context("collections[%d]", i);
-        check_member(collections[i], expect_collections[i], "%04x", LinkUsage);
-        check_member(collections[i], expect_collections[i], "%04x", LinkUsagePage);
-        check_member(collections[i], expect_collections[i], "%d", Parent);
-        check_member(collections[i], expect_collections[i], "%d", NumberOfChildren);
-        todo_wine_if(i == 1)
-        check_member(collections[i], expect_collections[i], "%d", NextSibling);
-        todo_wine_if(i == 0)
-        check_member(collections[i], expect_collections[i], "%d", FirstChild);
-        check_member(collections[i], expect_collections[i], "%d", CollectionType);
-        check_member(collections[i], expect_collections[i], "%d", IsAlias);
+        check_hidp_link_collection_node(&collections[i], &expect_collections[i]);
         winetest_pop_context();
     }
 
-- 
2.31.0




More information about the wine-devel mailing list