From: "Rémi Bernon" Subject: [PATCH 2/6] hidclass.sys: Use a single switch to parse all item types. Message-Id: <20210617082021.2262040-2-rbernon@codeweavers.com> Date: Thu, 17 Jun 2021 10:20:17 +0200 In-Reply-To: <20210617082021.2262040-1-rbernon@codeweavers.com> References: <20210617082021.2262040-1-rbernon@codeweavers.com> Signed-off-by: Rémi Bernon --- dlls/hidclass.sys/descriptor.c | 365 +++++++++++++++------------------ 1 file changed, 165 insertions(+), 200 deletions(-) diff --git a/dlls/hidclass.sys/descriptor.c b/dlls/hidclass.sys/descriptor.c index cf0e8436b91..c1e9b93bed5 100644 --- a/dlls/hidclass.sys/descriptor.c +++ b/dlls/hidclass.sys/descriptor.c @@ -318,16 +318,16 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l { int usages_top = 0; USAGE usages[256]; - int i; + int i, j; UINT32 value; INT32 signed_value; + struct feature *feature; for (i = index; i < length;) { - BYTE b0 = descriptor[i++]; - int size = b0 & 0x03; - int bType = (b0 >> 2) & 0x03; - int bTag = (b0 >> 4) & 0x0F; + BYTE item = descriptor[i++]; + BYTE tag = item >> 4; + int size = item & 0x03; if (size == 3) size = 4; if (length - i < size) @@ -347,215 +347,180 @@ static int parse_descriptor(BYTE *descriptor, unsigned int index, unsigned int l } i += size; - if (bType == TAG_TYPE_RESERVED && bTag == 0x0F && size == 2) +#define SHORT_ITEM(tag,type) (((tag)<<4)|((type)<<2)) + switch (item & SHORT_ITEM(0xf,0x3)) { - /* Long data items: Should be unused */ - ERR("Long Data Item, should be unused\n"); - return -1; - } - else - { - unsigned int j; - - TRACE(" 0x%x[%i], type %i , tag %i, size %i, val %i\n",b0,i-size-1,bType, bTag, size, value ); - - if (bType == TAG_TYPE_MAIN) + 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++) { - struct feature *feature; - switch(bTag) + if (!(feature = calloc(1, sizeof(*feature)))) return -1; + list_add_tail(&collection->features, &feature->entry); + if (tag == TAG_MAIN_INPUT) + feature->type = HidP_Input; + else if (tag == TAG_MAIN_OUTPUT) + feature->type = HidP_Output; + 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; + feature->caps.ReportCount = 1; + feature->collection = collection; + if (j+1 >= usages_top) { - case TAG_MAIN_INPUT: - case TAG_MAIN_OUTPUT: - case TAG_MAIN_FEATURE: - for (j = 0; j < caps->ReportCount; j++) - { - if (!(feature = calloc(1, sizeof(*feature)))) return -1; - list_add_tail(&collection->features, &feature->entry); - if (bTag == TAG_MAIN_INPUT) - feature->type = HidP_Input; - else if (bTag == TAG_MAIN_OUTPUT) - feature->type = HidP_Output; - else - feature->type = HidP_Feature; - parse_io_feature(size, value, bTag, feature_index, feature); - if (j < usages_top) - caps->NotRange.Usage = usages[j]; - feature->caps = *caps; - feature->caps.ReportCount = 1; - feature->collection = collection; - if (j+1 >= usages_top) - { - feature->caps.ReportCount += caps->ReportCount - (j + 1); - break; - } - } - usages_top = 0; - new_caps(caps); - break; - case TAG_MAIN_COLLECTION: - { - struct collection *subcollection; - if (!(subcollection = calloc(1, sizeof(struct collection)))) return -1; - list_add_tail(&collection->collections, &subcollection->entry); - 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; - 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); - - if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; - continue; - } - case TAG_MAIN_END_COLLECTION: - return i; - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; + feature->caps.ReportCount += caps->ReportCount - (j + 1); + break; } } - else if (bType == TAG_TYPE_GLOBAL) + usages_top = 0; + new_caps(caps); + break; + case SHORT_ITEM(TAG_MAIN_COLLECTION, TAG_TYPE_MAIN): + { + struct collection *subcollection; + if (!(subcollection = calloc(1, sizeof(struct collection)))) return -1; + list_add_tail(&collection->collections, &subcollection->entry); + subcollection->parent = collection; + /* Only set our collection once... + We do not properly handle composite devices yet. */ + if (usages_top) { - switch(bTag) - { - case TAG_GLOBAL_USAGE_PAGE: - caps->UsagePage = value; - break; - case TAG_GLOBAL_LOGICAL_MINIMUM: - caps->LogicalMin = signed_value; - break; - case TAG_GLOBAL_LOGICAL_MAXIMUM: - caps->LogicalMax = signed_value; - break; - case TAG_GLOBAL_PHYSICAL_MINIMUM: - caps->PhysicalMin = signed_value; - break; - case TAG_GLOBAL_PHYSICAL_MAXIMUM: - caps->PhysicalMax = signed_value; - break; - case TAG_GLOBAL_UNIT_EXPONENT: - caps->UnitsExp = signed_value; - break; - case TAG_GLOBAL_UNIT: - caps->Units = signed_value; - break; - case TAG_GLOBAL_REPORT_SIZE: - caps->BitSize = value; - break; - case TAG_GLOBAL_REPORT_ID: - caps->ReportID = value; - break; - case TAG_GLOBAL_REPORT_COUNT: - caps->ReportCount = value; - break; - case TAG_GLOBAL_PUSH: - { - struct caps_stack *saved; - if (!(saved = malloc(sizeof(*saved)))) return -1; - saved->caps = *caps; - TRACE("Push\n"); - list_add_tail(stack, &saved->entry); - break; - } - case TAG_GLOBAL_POP: - { - struct list *tail; - struct caps_stack *saved; - TRACE("Pop\n"); - tail = list_tail(stack); - if (tail) - { - saved = LIST_ENTRY(tail, struct caps_stack, entry); - *caps = saved->caps; - list_remove(tail); - free(saved); - } - else - { - ERR("Pop but no stack!\n"); - return -1; - } - break; - } - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; - } + caps->NotRange.Usage = usages[usages_top-1]; + usages_top = 0; } - else if (bType == TAG_TYPE_LOCAL) + if (*collection_index == 0) + collection->caps = *caps; + subcollection->caps = *caps; + 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); + + if ((i = parse_descriptor(descriptor, i, length, feature_index, collection_index, subcollection, caps, stack)) < 0) return i; + continue; + } + case SHORT_ITEM(TAG_MAIN_END_COLLECTION, TAG_TYPE_MAIN): + return i; + + case SHORT_ITEM(TAG_GLOBAL_USAGE_PAGE, TAG_TYPE_GLOBAL): + caps->UsagePage = value; + break; + case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MINIMUM, TAG_TYPE_GLOBAL): + caps->LogicalMin = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_LOGICAL_MAXIMUM, TAG_TYPE_GLOBAL): + caps->LogicalMax = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MINIMUM, TAG_TYPE_GLOBAL): + caps->PhysicalMin = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_PHYSICAL_MAXIMUM, TAG_TYPE_GLOBAL): + caps->PhysicalMax = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_UNIT_EXPONENT, TAG_TYPE_GLOBAL): + caps->UnitsExp = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_UNIT, TAG_TYPE_GLOBAL): + caps->Units = signed_value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_SIZE, TAG_TYPE_GLOBAL): + caps->BitSize = value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_ID, TAG_TYPE_GLOBAL): + caps->ReportID = value; + break; + case SHORT_ITEM(TAG_GLOBAL_REPORT_COUNT, TAG_TYPE_GLOBAL): + caps->ReportCount = 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; + TRACE("Push\n"); + list_add_tail(stack, &saved->entry); + 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) { - switch(bTag) - { - case TAG_LOCAL_USAGE: - if (usages_top == sizeof(usages)) - { - ERR("More than 256 individual usages defined\n"); - return -1; - } - else - { - usages[usages_top++] = value; - caps->IsRange = FALSE; - } - break; - case TAG_LOCAL_USAGE_MINIMUM: - caps->Range.UsageMin = value; - caps->IsRange = TRUE; - break; - case TAG_LOCAL_USAGE_MAXIMUM: - caps->Range.UsageMax = value; - caps->IsRange = TRUE; - break; - case TAG_LOCAL_DESIGNATOR_INDEX: - caps->NotRange.DesignatorIndex = value; - caps->IsDesignatorRange = FALSE; - break; - case TAG_LOCAL_DESIGNATOR_MINIMUM: - caps->Range.DesignatorMin = value; - caps->IsDesignatorRange = TRUE; - break; - case TAG_LOCAL_DESIGNATOR_MAXIMUM: - caps->Range.DesignatorMax = value; - caps->IsDesignatorRange = TRUE; - break; - case TAG_LOCAL_STRING_INDEX: - caps->NotRange.StringIndex = value; - caps->IsStringRange = FALSE; - break; - case TAG_LOCAL_STRING_MINIMUM: - caps->Range.StringMin = value; - caps->IsStringRange = TRUE; - break; - case TAG_LOCAL_STRING_MAXIMUM: - caps->Range.StringMax = value; - caps->IsStringRange = TRUE; - break; - case TAG_LOCAL_DELIMITER: - FIXME("delimiter %d not implemented!\n", value); - return -1; - default: - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); - return -1; - } + saved = LIST_ENTRY(tail, struct caps_stack, entry); + *caps = saved->caps; + list_remove(tail); + free(saved); } else { - ERR("Unknown (bTag: 0x%x, bType: 0x%x)\n", bTag, bType); + ERR("Pop but no stack!\n"); + return -1; + } + break; + } + + 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; + } + break; + case SHORT_ITEM(TAG_LOCAL_USAGE_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.UsageMin = value; + caps->IsRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_USAGE_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.UsageMax = value; + caps->IsRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_INDEX, TAG_TYPE_LOCAL): + caps->NotRange.DesignatorIndex = value; + caps->IsDesignatorRange = FALSE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.DesignatorMin = value; + caps->IsDesignatorRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DESIGNATOR_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.DesignatorMax = value; + caps->IsDesignatorRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_INDEX, TAG_TYPE_LOCAL): + caps->NotRange.StringIndex = value; + caps->IsStringRange = FALSE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_MINIMUM, TAG_TYPE_LOCAL): + caps->Range.StringMin = value; + caps->IsStringRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_STRING_MAXIMUM, TAG_TYPE_LOCAL): + caps->Range.StringMax = value; + caps->IsStringRange = TRUE; + break; + case SHORT_ITEM(TAG_LOCAL_DELIMITER, TAG_TYPE_LOCAL): + FIXME("delimiter %d not implemented!\n", value); + return -1; + + default: + FIXME("item type %x not implemented!\n", item); + return -1; } +#undef SHORT_ITEM } return i; } -- 2.31.0