Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/hid/hidp.c | 52 +++++++++++++++++++++++++++++----------- dlls/hidparse.sys/main.c | 4 ++-- include/wine/hid.h | 3 ++- 3 files changed, 42 insertions(+), 17 deletions(-)
diff --git a/dlls/hid/hidp.c b/dlls/hid/hidp.c index 547f935f850..4a1771e586c 100644 --- a/dlls/hid/hidp.c +++ b/dlls/hid/hidp.c @@ -293,19 +293,24 @@ struct get_usage_params
static NTSTATUS get_usage( const struct hid_value_caps *caps, void *user ) { + const struct hid_value_caps *end = caps; + ULONG index_min, index_max, bit, last; struct get_usage_params *params = user; unsigned char *report_buf; - ULONG bit, last; BYTE index;
report_buf = (unsigned char *)params->report_buf + caps->start_byte;
if (HID_VALUE_CAPS_IS_ARRAY( caps )) { + while (end->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) end++; + index_min = end - caps + 1; + index_max = index_min + caps->usage_max - caps->usage_min; + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) { - if (!(index = report_buf[bit / 8])) continue; - if (params->usages < params->usages_end) *params->usages = caps->usage_min + index - caps->start_index; + if (!(index = report_buf[bit / 8]) || index < index_min || index > index_max) continue; + if (params->usages < params->usages_end) *params->usages = caps->usage_min + index - index_min; params->usages++; } return HIDP_STATUS_SUCCESS; @@ -499,18 +504,22 @@ struct set_usage_params
static NTSTATUS set_usage( const struct hid_value_caps *caps, void *user ) { + const struct hid_value_caps *end = caps; struct set_usage_params *params = user; + ULONG index_min, bit, last; unsigned char *report_buf; - ULONG bit, last;
report_buf = (unsigned char *)params->report_buf + caps->start_byte;
if (HID_VALUE_CAPS_IS_ARRAY( caps )) { + while (end->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) end++; + index_min = end - caps + 1; + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) { if (report_buf[bit / 8]) continue; - report_buf[bit / 8] = caps->start_index + params->usage - caps->usage_min; + report_buf[bit / 8] = index_min + params->usage - caps->usage_min; break; }
@@ -559,18 +568,22 @@ struct unset_usage_params
static NTSTATUS unset_usage( const struct hid_value_caps *caps, void *user ) { + ULONG index, index_min, index_max, bit, last; + const struct hid_value_caps *end = caps; struct unset_usage_params *params = user; unsigned char *report_buf; - ULONG bit, index, last;
report_buf = (unsigned char *)params->report_buf + caps->start_byte;
if (HID_VALUE_CAPS_IS_ARRAY( caps )) { + while (end->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) end++; + index_min = end - caps + 1; + index_max = index_min + caps->usage_max - caps->usage_min; + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) { - index = caps->start_index + params->usage - caps->usage_min; - if (report_buf[bit / 8] != index) continue; + if (!(index = report_buf[bit / 8]) || index < index_min || index > index_max) continue; report_buf[bit / 8] = 0; params->found = TRUE; break; @@ -758,21 +771,26 @@ struct get_usage_and_page_params static NTSTATUS get_usage_and_page( const struct hid_value_caps *caps, void *user ) { struct get_usage_and_page_params *params = user; + const struct hid_value_caps *end = caps; + ULONG index_min, index_max, bit, last; unsigned char *report_buf; - ULONG bit, last; BYTE index;
report_buf = (unsigned char *)params->report_buf + caps->start_byte;
if (HID_VALUE_CAPS_IS_ARRAY( caps )) { + while (end->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) end++; + index_min = end - caps + 1; + index_max = index_min + caps->usage_max - caps->usage_min; + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) { - if (!(index = report_buf[bit / 8])) continue; + if (!(index = report_buf[bit / 8]) || index < index_min || index > index_max) continue; if (params->usages < params->usages_end) { params->usages->UsagePage = caps->usage_page; - params->usages->Usage = caps->usage_min + index - caps->start_index; + params->usages->Usage = caps->usage_min + index - index_min; } params->usages++; } @@ -848,7 +866,8 @@ static NTSTATUS find_all_data( const struct hid_value_caps *caps, void *user ) { struct find_all_data_params *params = user; HIDP_DATA *data = params->data, *data_end = params->data_end; - ULONG bit, last, bit_count = caps->bit_size * caps->report_count; + ULONG index_min, index_max, bit, last, bit_count; + const struct hid_value_caps *end = caps; unsigned char *report_buf; BYTE index;
@@ -858,12 +877,16 @@ static NTSTATUS find_all_data( const struct hid_value_caps *caps, void *user )
if (HID_VALUE_CAPS_IS_ARRAY( caps )) { + while (end->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) end++; + index_min = end - caps + 1; + index_max = index_min + caps->usage_max - caps->usage_min; + for (bit = caps->start_bit, last = bit + caps->report_count * caps->bit_size - 1; bit <= last; bit += 8) { - if (!(index = report_buf[bit / 8])) continue; + if (!(index = report_buf[bit / 8]) || index < index_min || index > index_max) continue; if (data < data_end) { - data->DataIndex = caps->data_index_min + index - caps->start_index; + data->DataIndex = caps->data_index_min + index - index_min; data->On = 1; } data++; @@ -888,6 +911,7 @@ static NTSTATUS find_all_data( const struct hid_value_caps *caps, void *user ) { data->DataIndex = caps->data_index_min; data->RawValue = 0; + bit_count = caps->bit_size * caps->report_count; if ((bit_count + 7) / 8 > sizeof(data->RawValue)) return HIDP_STATUS_BUFFER_TOO_SMALL; copy_bits( (void *)&data->RawValue, report_buf, bit_count, -caps->start_bit ); } diff --git a/dlls/hidparse.sys/main.c b/dlls/hidparse.sys/main.c index 73b9858f741..2f7f417a7aa 100644 --- a/dlls/hidparse.sys/main.c +++ b/dlls/hidparse.sys/main.c @@ -354,13 +354,14 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY } value = state->values[type] + *value_idx;
- state->items.start_index = usages_size; if (!(is_array = HID_VALUE_CAPS_IS_ARRAY( &state->items ))) state->items.report_count -= usages_size - 1; else start_bit -= state->items.report_count * state->items.bit_size;
while (usages_size--) { if (!is_array) start_bit -= state->items.report_count * state->items.bit_size; + else if (usages_size) state->items.flags |= HID_VALUE_CAPS_ARRAY_HAS_MORE; + else state->items.flags &= ~HID_VALUE_CAPS_ARRAY_HAS_MORE; state->items.start_byte = start_bit / 8; state->items.start_bit = start_bit % 8; state->items.usage_page = state->usages_page[usages_size]; @@ -372,7 +373,6 @@ static BOOL parse_new_value_caps( struct hid_parser_state *state, HIDP_REPORT_TY *value++ = state->items; *value_idx += 1; if (!is_array) state->items.report_count = 1; - else state->items.start_index -= 1; }
state->items.usage_page = usage_page; diff --git a/include/wine/hid.h b/include/wine/hid.h index 4f388404885..a6c585b2ff4 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -52,7 +52,6 @@ struct hid_value_caps USHORT report_count; UCHAR start_bit; USHORT start_byte; - ULONG start_index; LONG logical_min; LONG logical_max; LONG physical_min; @@ -61,6 +60,8 @@ struct hid_value_caps ULONG units_exp; };
+/* named array continues on next caps */ +#define HID_VALUE_CAPS_ARRAY_HAS_MORE 0x01 #define HID_VALUE_CAPS_IS_RANGE 0x10 #define HID_VALUE_CAPS_IS_STRING_RANGE 0x40 #define HID_VALUE_CAPS_IS_DESIGNATOR_RANGE 0x80