[PATCH 3/6] hidclass.sys: Introduce new hid_parser_state struct.
Rémi Bernon
rbernon at codeweavers.com
Thu Jun 17 03:20:18 CDT 2021
And internal hid_value_caps struct, and use them to store items and
usages.
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/hidclass.sys/descriptor.c | 194 ++++++++++++++++++++-------------
include/wine/hid.h | 23 ++++
2 files changed, 141 insertions(+), 76 deletions(-)
diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c
index c1e9b93bed5..b66e9deb9a0 100644
--- a/dlls/hidclass.sys/descriptor.c
+++ b/dlls/hidclass.sys/descriptor.c
@@ -130,7 +130,7 @@ struct collection {
struct caps_stack {
struct list entry;
- HIDP_VALUE_CAPS caps;
+ struct hid_value_caps caps;
};
static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps )
@@ -145,6 +145,42 @@ static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps )
caps->Units, caps->UnitsExp, caps->LogicalMin, caps->LogicalMax, caps->PhysicalMin, caps->PhysicalMax );
}
+static void copy_hidp_value_caps( HIDP_VALUE_CAPS *out, const struct hid_value_caps *in )
+{
+ out->UsagePage = in->usage_page;
+ out->ReportID = in->report_id;
+ out->IsAlias = FALSE;
+ out->BitSize = in->bit_size;
+ out->ReportCount = in->report_count;
+ out->UnitsExp = in->units_exp;
+ out->Units = in->units;
+ out->LogicalMin = in->logical_min;
+ out->LogicalMax = in->logical_max;
+ out->PhysicalMin = in->physical_min;
+ out->PhysicalMax = in->physical_max;
+ if (!(out->IsRange = in->is_range))
+ out->NotRange.Usage = in->usage_min;
+ else
+ {
+ out->Range.UsageMin = in->usage_min;
+ out->Range.UsageMax = in->usage_max;
+ }
+ if (!(out->IsStringRange = in->is_string_range))
+ out->NotRange.StringIndex = in->string_min;
+ else
+ {
+ out->Range.StringMin = in->string_min;
+ out->Range.StringMax = in->string_max;
+ }
+ if ((out->IsDesignatorRange = in->is_designator_range))
+ out->NotRange.DesignatorIndex = in->designator_min;
+ else
+ {
+ out->Range.DesignatorMin = in->designator_min;
+ out->Range.DesignatorMax = in->designator_max;
+ }
+}
+
static void debug_feature(struct feature *feature)
{
if (!feature)
@@ -256,6 +292,31 @@ static void debug_print_preparsed(WINE_HIDP_PREPARSED_DATA *data)
}
}
+struct hid_parser_state
+{
+ USAGE usages[256];
+ DWORD usages_size;
+
+ struct hid_value_caps items;
+};
+
+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;
+ state->usages_size = 0;
+}
+
+static BOOL parse_local_usage( struct hid_parser_state *state, USAGE usage )
+{
+ state->usages[state->usages_size] = usage;
+ state->items.is_range = FALSE;
+ if (state->usages_size++ == 255) ERR( "HID parser usages stack overflow!\n" );
+ return state->usages_size <= 255;
+}
+
static void parse_io_feature(unsigned int bSize, int itemVal, int bTag,
unsigned int *feature_index,
struct feature *feature)
@@ -303,21 +364,10 @@ static void parse_collection(unsigned int bSize, int itemVal,
}
}
-static void new_caps(HIDP_VALUE_CAPS *caps)
-{
- caps->IsRange = 0;
- caps->IsStringRange = 0;
- caps->IsDesignatorRange = 0;
- caps->NotRange.Usage = 0;
-}
-
-static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int length,
- unsigned int *feature_index, unsigned int *collection_index,
- struct collection *collection, HIDP_VALUE_CAPS *caps,
- struct list *stack)
+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 )
{
- int usages_top = 0;
- USAGE usages[256];
int i, j;
UINT32 value;
INT32 signed_value;
@@ -353,7 +403,7 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l
case SHORT_ITEM(TAG_MAIN_INPUT, TAG_TYPE_MAIN):
case SHORT_ITEM(TAG_MAIN_OUTPUT, TAG_TYPE_MAIN):
case SHORT_ITEM(TAG_MAIN_FEATURE, TAG_TYPE_MAIN):
- for (j = 0; j < caps->ReportCount; j++)
+ for (j = 0; j < state->items.report_count; j++)
{
if (!(feature = calloc(1, sizeof(*feature)))) return -1;
list_add_tail(&collection->features, &feature->entry);
@@ -364,19 +414,17 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l
else
feature->type = HidP_Feature;
parse_io_feature(size, value, tag, feature_index, feature);
- if (j < usages_top)
- caps->NotRange.Usage = usages[j];
- feature->caps = *caps;
+ if (j < state->usages_size) state->items.usage_min = state->usages[j];
+ copy_hidp_value_caps( &feature->caps, &state->items );
feature->caps.ReportCount = 1;
feature->collection = collection;
- if (j+1 >= usages_top)
+ if (j + 1 >= state->usages_size)
{
- feature->caps.ReportCount += caps->ReportCount - (j + 1);
+ feature->caps.ReportCount += state->items.report_count - (j + 1);
break;
}
}
- usages_top = 0;
- new_caps(caps);
+ reset_local_items( state );
break;
case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN):
{
@@ -386,63 +434,60 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l
subcollection->parent = collection;
/* Only set our collection once...
We do not properly handle composite devices yet. */
- if (usages_top)
- {
- caps->NotRange.Usage = usages[usages_top-1];
- usages_top = 0;
- }
- if (*collection_index == 0)
- collection->caps = *caps;
- subcollection->caps = *caps;
+ if (state->usages_size) state->items.usage_min = state->usages[state->usages_size - 1];
+ if (*collection_index == 0) copy_hidp_value_caps( &collection->caps, &state->items );
+ copy_hidp_value_caps( &subcollection->caps, &state->items );
subcollection->index = *collection_index;
*collection_index = *collection_index + 1;
list_init(&subcollection->features);
list_init(&subcollection->collections);
- new_caps(caps);
-
parse_collection(size, value, subcollection);
+ reset_local_items( state );
- if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i;
+ if ((i = parse_descriptor( descriptor, i, length, feature_index, collection_index,
+ subcollection, state, stack )) < 0)
+ return i;
continue;
}
case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN):
+ reset_local_items( state );
return i;
case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL):
- caps->UsagePage = value;
+ state->items.usage_page = value;
break;
case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL):
- caps->LogicalMin = signed_value;
+ state->items.logical_min = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL):
- caps->LogicalMax = signed_value;
+ state->items.logical_max = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL):
- caps->PhysicalMin = signed_value;
+ state->items.physical_min = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL):
- caps->PhysicalMax = signed_value;
+ state->items.physical_max = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL):
- caps->UnitsExp = signed_value;
+ state->items.units_exp = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL):
- caps->Units = signed_value;
+ state->items.units = signed_value;
break;
case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL):
- caps->BitSize = value;
+ state->items.bit_size = value;
break;
case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL):
- caps->ReportID = value;
+ state->items.report_id = value;
break;
case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL):
- caps->ReportCount = value;
+ 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 = *caps;
+ saved->caps = state->items;
TRACE("Push\n");
list_add_tail(stack, &saved->entry);
break;
@@ -456,7 +501,7 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l
if (tail)
{
saved = LIST_ENTRY(tail, struct caps_stack, entry);
- *caps = saved->caps;
+ state->items = saved->caps;
list_remove(tail);
free(saved);
}
@@ -469,48 +514,39 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l
}
case SHORT_ITEM(TAG_LOCAL_USAGE, TAG_TYPE_LOCAL):
- if (usages_top == sizeof(usages))
- {
- ERR("More than 256 individual usages defined\n");
- return -1;
- }
- else
- {
- usages[usages_top++] = value;
- caps->IsRange = FALSE;
- }
+ if (!parse_local_usage( state, value )) return -1;
break;
case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL):
- caps->Range.UsageMin = value;
- caps->IsRange = TRUE;
+ state->items.usage_min = value;
+ state->items.is_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL):
- caps->Range.UsageMax = value;
- caps->IsRange = TRUE;
+ state->items.usage_max = value;
+ state->items.is_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL):
- caps->NotRange.DesignatorIndex = value;
- caps->IsDesignatorRange = FALSE;
+ state->items.designator_min = state->items.designator_max = value;
+ state->items.is_designator_range = FALSE;
break;
case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL):
- caps->Range.DesignatorMin = value;
- caps->IsDesignatorRange = TRUE;
+ state->items.designator_min = value;
+ state->items.is_designator_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL):
- caps->Range.DesignatorMax = value;
- caps->IsDesignatorRange = TRUE;
+ state->items.designator_max = value;
+ state->items.is_designator_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL):
- caps->NotRange.StringIndex = value;
- caps->IsStringRange = FALSE;
+ state->items.string_min = state->items.string_max = value;
+ state->items.is_string_range = FALSE;
break;
case SHORT_ITEM(TAG_LOCAL_STRING_MINIMUM, TAG_TYPE_LOCAL):
- caps->Range.StringMin = value;
- caps->IsStringRange = TRUE;
+ state->items.string_min = value;
+ state->items.is_string_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL):
- caps->Range.StringMax = value;
- caps->IsStringRange = TRUE;
+ state->items.string_max = value;
+ state->items.is_string_range = TRUE;
break;
case SHORT_ITEM(TAG_LOCAL_DELIMITER, TAG_TYPE_LOCAL):
FIXME("delimiter %d not implemented!\n", value);
@@ -735,8 +771,8 @@ static void free_collection(struct collection *collection)
WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
{
WINE_HIDP_PREPARSED_DATA *data = NULL;
+ struct hid_parser_state *state;
struct collection *base;
- HIDP_VALUE_CAPS caps;
int i;
struct list caps_stack;
@@ -757,16 +793,21 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
list_init(&caps_stack);
- if (!(base = calloc(1, sizeof(*base)))) return NULL;
+ if (!(state = calloc( 1, sizeof(*state) ))) return NULL;
+ if (!(base = calloc( 1, sizeof(*base) )))
+ {
+ free( state );
+ return NULL;
+ }
base->index = 1;
list_init(&base->features);
list_init(&base->collections);
- memset(&caps, 0, sizeof(caps));
cidx = 0;
- if (parse_descriptor(descriptor, 0, length, &feature_count, &cidx, base, &caps, &caps_stack) < 0)
+ if (parse_descriptor( descriptor, 0, length, &feature_count, &cidx, base, state, &caps_stack ) < 0)
{
free_collection(base);
+ free( state );
return NULL;
}
@@ -787,5 +828,6 @@ WINE_HIDP_PREPARSED_DATA* ParseDescriptor(BYTE *descriptor, unsigned int length)
debug_print_preparsed(data);
free_collection(base);
+ free( state );
return data;
}
diff --git a/include/wine/hid.h b/include/wine/hid.h
index cfb4f389eb9..50b1493ab62 100644
--- a/include/wine/hid.h
+++ b/include/wine/hid.h
@@ -68,6 +68,29 @@ C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.StringIndex) == offsetof(HIDP_VALU
C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.DesignatorIndex) == offsetof(HIDP_VALUE_CAPS, NotRange.DesignatorIndex) );
C_ASSERT( offsetof(HIDP_BUTTON_CAPS, NotRange.DataIndex) == offsetof(HIDP_VALUE_CAPS, NotRange.DataIndex) );
+struct hid_value_caps
+{
+ USAGE usage_page;
+ USAGE usage_min;
+ USAGE usage_max;
+ USHORT string_min;
+ USHORT string_max;
+ USHORT designator_min;
+ USHORT designator_max;
+ BOOLEAN is_range;
+ BOOLEAN is_string_range;
+ BOOLEAN is_designator_range;
+ UCHAR report_id;
+ USHORT bit_size;
+ USHORT report_count;
+ LONG logical_min;
+ LONG logical_max;
+ LONG physical_min;
+ LONG physical_max;
+ ULONG units;
+ ULONG units_exp;
+};
+
typedef struct __WINE_HID_REPORT
{
UCHAR reportID;
--
2.31.0
More information about the wine-devel
mailing list