[PATCH 4/6] hidclass.sys: Add a stack to parser_state to store global items.
Rémi Bernon
rbernon at codeweavers.com
Thu Jun 17 03:20:19 CDT 2021
This adds a todo_wine, because although Wine didn't get the correct
caps, some transient value was used incorrectly in Range.UsageMax, this
is resetting local items as it should.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/hidclass.sys/descriptor.c | 124 ++++++++++++++++-------------
dlls/ntoskrnl.exe/tests/ntoskrnl.c | 1 +
2 files changed, 71 insertions(+), 54 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c
index b66e9deb9a0..b57ab2a7da8 100644
--- a/dlls/hidclass.sys/descriptor.c
+++ b/dlls/hidclass.sys/descriptor.c
@@ -128,11 +128,6 @@ struct collection {
struct list collections;
};
-struct caps_stack {
- struct list entry;
- struct hid_value_caps caps;
-};
-
static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps )
{
if (!caps) return "(null)";
@@ -298,17 +293,69 @@ struct hid_parser_state
DWORD usages_size;
struct hid_value_caps items;
+
+ struct hid_value_caps *stack;
+ DWORD stack_size;
+ DWORD global_idx;
};
+static BOOL array_reserve( struct hid_value_caps **array, DWORD *array_size, DWORD index )
+{
+ if (index < *array_size) return TRUE;
+ if ((*array_size = *array_size ? (*array_size * 3 / 2) : 32) <= index) return FALSE;
+ if (!(*array = realloc( *array, *array_size * sizeof(**array) ))) return FALSE;
+ return TRUE;
+}
+
+static void copy_global_items( struct hid_value_caps *dst, const struct hid_value_caps *src )
+{
+ dst->usage_page = src->usage_page;
+ dst->logical_min = src->logical_min;
+ dst->logical_max = src->logical_max;
+ dst->physical_min = src->physical_min;
+ dst->physical_max = src->physical_max;
+ dst->units_exp = src->units_exp;
+ dst->units = src->units;
+ dst->bit_size = src->bit_size;
+ dst->report_id = src->report_id;
+ dst->report_count = src->report_count;
+}
+
static void reset_local_items( struct hid_parser_state *state )
{
- state->items.is_range = FALSE;
- state->items.is_string_range = FALSE;
- state->items.is_designator_range = FALSE;
- state->items.usage_min = FALSE;
+ struct hid_value_caps tmp;
+ copy_global_items( &tmp, &state->items );
+ memset( &state->items, 0, sizeof(state->items) );
+ copy_global_items( &state->items, &tmp );
state->usages_size = 0;
}
+static BOOL parse_global_push( struct hid_parser_state *state )
+{
+ if (!array_reserve( &state->stack, &state->stack_size, state->global_idx ))
+ {
+ ERR( "HID parser stack overflow!\n" );
+ return FALSE;
+ }
+
+ copy_global_items( state->stack + state->global_idx, &state->items );
+ state->global_idx++;
+ return TRUE;
+}
+
+static BOOL parse_global_pop( struct hid_parser_state *state )
+{
+ if (!state->global_idx)
+ {
+ ERR( "HID parser global stack underflow!\n" );
+ return FALSE;
+ }
+
+ state->global_idx--;
+ copy_global_items( &state->items, state->stack + state->global_idx );
+ return TRUE;
+}
+
static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage )
{
state->usages[state->usages_size] = usage;
@@ -317,6 +364,13 @@ static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage )
return state->usages_size <= 255;
}
+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 );
+ free( state->stack );
+ free( state );
+}
+
static void parse_io_feature(unsigned int bSize, int itemVal, int bTag,
unsigned int *feature_index,
struct feature *feature)
@@ -366,7 +420,7 @@ static void parse_collection(unsigned int bSize, int itemVal,
static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int length,
unsigned int *feature_index, unsigned int *collection_index,
- struct collection *collection, struct hid_parser_state *state, struct list *stack )
+ struct collection *collection, struct hid_parser_state *state )
{
int i, j;
UINT32 value;
@@ -445,7 +499,7 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int
reset_local_items( state );
if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index,
- subcollection, state, stack )) < 0)
+ subcollection, state )) < 0)
return i;
continue;
}
@@ -484,34 +538,11 @@ static int parse_descriptor( BYTE *descriptor, unsigned int index, unsigned int
state->items.report_count = value;
break;
case SHORT_ITEM(TAG_GLOBAL_PUSH, TAG_TYPE_GLOBAL):
- {
- struct caps_stack *saved;
- if (!(saved = malloc(sizeof(*saved)))) return -1;
- saved->caps = state->items;
- TRACE("Push\n");
- list_add_tail(stack, &saved->entry);
+ if (!parse_global_push( state )) return -1;
break;
- }
case SHORT_ITEM(TAG_GLOBAL_POP, TAG_TYPE_GLOBAL):
- {
- struct list *tail;
- struct caps_stack *saved;
- TRACE("Pop\n");
- tail = list_tail(stack);
- if (tail)
- {
- saved = LIST_ENTRY(tail, struct caps_stack, entry);
- state->items = saved->caps;
- list_remove(tail);
- free(saved);
- }
- else
- {
- ERR("Pop but no stack!\n");
- return -1;
- }
+ if (!parse_global_pop( state )) return -1;
break;
- }
case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL):
if (!parse_local_usage( state, value )) return -1;
@@ -775,8 +806,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
struct collection *base;
int i;
- struct list caps_stack;
-
unsigned int feature_count = 0;
unsigned int cidx;
@@ -791,8 +820,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
}
}
- list_init(&caps_stack);
-
if (!(state = calloc( 1, sizeof(*state) ))) return NULL;
if (!(base = calloc( 1, sizeof(*base) )))
{
@@ -804,30 +831,19 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
list_init(&base->collections);
cidx = 0;
- if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state, &caps_stack ) < 0)
+ if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state ) < 0)
{
free_collection(base);
- free( state );
+ free_parser_state( state );
return NULL;
}
debug_collection(base);
- if (!list_empty(&caps_stack))
- {
- struct caps_stack *entry, *cursor;
- ERR("%i unpopped device caps on the stack\n", list_count(&caps_stack));
- LIST_FOR_EACH_ENTRY_SAFE(entry, cursor, &caps_stack, struct caps_stack, entry)
- {
- list_remove(&entry->entry);
- free(entry);
- }
- }
-
if ((data = build_PreparseData(base, cidx)))
debug_print_preparsed(data);
free_collection(base);
- free( state );
+ free_parser_state( state );
return data;
}
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 735d1a0d996..ff1db96a06a 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -2093,6 +2093,7 @@ static void test_hidp(HANDLE file, int report_id)
check_member(value_caps[4], value_caps[3], "%d", PhysicalMax);
todo_wine
check_member(value_caps[4], value_caps[3], "%04x", Range.UsageMin);
+ todo_wine
check_member(value_caps[4], value_caps[3], "%04x", Range.UsageMax);
check_member(value_caps[4], value_caps[3], "%d", Range.StringMin);
check_member(value_caps[4], value_caps[3], "%d", Range.StringMax);
--
2.31.0
More information about the wine-devel
mailing list