summaryrefslogtreecommitdiff
path: root/SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c')
-rw-r--r--SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c563
1 files changed, 563 insertions, 0 deletions
diff --git a/SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c b/SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c
new file mode 100644
index 0000000..a7adeb5
--- /dev/null
+++ b/SDL-3.2.8/src/hidapi/windows/test/hid_report_reconstructor_test.c
@@ -0,0 +1,563 @@
1#if defined(__MINGW32__)
2 // Needed for %zu
3 #define __USE_MINGW_ANSI_STDIO 1
4#endif
5
6#include "../hidapi_descriptor_reconstruct.h"
7
8#include <stddef.h>
9#include <stdio.h>
10#include <string.h>
11
12static hidp_preparsed_data * alloc_preparsed_data_from_file(char* filename)
13{
14 FILE* file;
15 errno_t err = fopen_s(&file, filename, "r");
16
17 if (err != 0) {
18 fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
19 return NULL;
20 }
21
22 char line[256];
23
24 {
25 unsigned short vendor_id = 0;
26 unsigned short product_id = 0;
27 unsigned short usage = 0;
28 unsigned short usage_page = 0;
29 unsigned short release_number = 0;
30 int interface_number = -1;
31 BOOLEAN header_read_success = FALSE;
32 char manufacturer_string[128];
33 manufacturer_string[0] = '\0';
34 char product_string[128];
35 product_string[0] = '\0';
36 // char path[128];
37 // path[0] = '\0';
38
39 while (fgets(line, sizeof(line), file) != NULL) {
40 if (line[0] == '\r' || line[0] == '\n') {
41 line[0] = '\0';
42 }
43 if (line[0] == '\0') {
44 // read the 'metadata' only until the first empty line
45 header_read_success = TRUE;
46 break;
47 }
48 if (sscanf(line, "dev->vendor_id = 0x%04hX\n", &vendor_id)) continue;
49 if (sscanf(line, "dev->product_id = 0x%04hX\n", &product_id)) continue;
50 if (sscanf(line, "dev->usage_page = 0x%04hX\n", &usage_page)) continue;
51 if (sscanf(line, "dev->usage = 0x%04hX\n", &usage)) continue;
52 if (sscanf(line, "dev->manufacturer_string = \"%127[^\"\n]", manufacturer_string)) continue;
53 if (sscanf(line, "dev->product_string = \"%127[^\"\n]", product_string)) continue;
54 if (sscanf(line, "dev->release_number = 0x%04hX\n", &release_number)) continue;
55 if (sscanf(line, "dev->interface_number = %d\n", &interface_number)) continue;
56 // if (sscanf(line, "dev->path = \"%127[^\"]\n", path)) continue;
57 }
58 if (!header_read_success) {
59 fprintf(stderr, "ERROR: Couldn't read PP Data header (missing newline)\n");
60 fclose(file);
61 return NULL;
62 }
63 printf("'Virtual' Device Read: %04hx %04hx\n", vendor_id, product_id);
64 if (manufacturer_string[0] != '\0') {
65 printf(" Manufacturer: %s\n", manufacturer_string);
66 }
67 if (product_string[0] != '\0') {
68 printf(" Product: %s\n", product_string);
69 }
70 printf(" Release: %hx\n", release_number);
71 printf(" Interface: %d\n", interface_number);
72 printf(" Usage (page): 0x%hx (0x%hx)\n", usage, usage_page);
73 }
74
75 hidp_preparsed_data static_pp_data;
76 memset(&static_pp_data, 0, sizeof(static_pp_data));
77 hidp_preparsed_data *pp_data = &static_pp_data;
78
79 unsigned int rt_idx;
80 unsigned int caps_idx;
81 unsigned int token_idx;
82 unsigned int coll_idx;
83 USAGE temp_usage;
84 BOOLEAN temp_boolean[3];
85 UCHAR temp_uchar[3];
86 USHORT temp_ushort;
87 ULONG temp_ulong;
88 LONG temp_long;
89
90 USHORT FirstByteOfLinkCollectionArray = 0;
91 USHORT NumberLinkCollectionNodes = 0;
92
93 while (fgets(line, sizeof(line), file) != NULL) {
94 if (line[0] == '#')
95 continue;
96
97 if (FirstByteOfLinkCollectionArray != 0 && NumberLinkCollectionNodes != 0) {
98 size_t size_of_preparsed_data = offsetof(hidp_preparsed_data, caps) + FirstByteOfLinkCollectionArray + (NumberLinkCollectionNodes * sizeof(hid_pp_link_collection_node));
99 pp_data->FirstByteOfLinkCollectionArray = FirstByteOfLinkCollectionArray;
100 pp_data->NumberLinkCollectionNodes = NumberLinkCollectionNodes;
101 FirstByteOfLinkCollectionArray = 0;
102 NumberLinkCollectionNodes = 0;
103 pp_data = malloc(size_of_preparsed_data);
104 memcpy(pp_data, &static_pp_data, sizeof(static_pp_data));
105 }
106
107 if (sscanf(line, "pp_data->MagicKey = 0x%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX\n", &pp_data->MagicKey[0], &pp_data->MagicKey[1], &pp_data->MagicKey[2], &pp_data->MagicKey[3], &pp_data->MagicKey[4], &pp_data->MagicKey[5], &pp_data->MagicKey[6], &pp_data->MagicKey[7])) continue;
108 if (sscanf(line, "pp_data->Usage = 0x%04hX\n", &pp_data->Usage)) continue;
109 if (sscanf(line, "pp_data->UsagePage = 0x%04hX\n", &pp_data->UsagePage)) continue;
110 if (sscanf(line, "pp_data->Reserved = 0x%04hX%04hX\n", &pp_data->Reserved[0], &pp_data->Reserved[1])) continue;
111
112 if (sscanf(line, "pp_data->caps_info[%u]", &rt_idx) == 1) {
113 const size_t caps_info_count = sizeof(pp_data->caps_info) / sizeof(pp_data->caps_info[0]);
114 if (rt_idx >= caps_info_count) {
115 fprintf(stderr, "Broken pp_data file, pp_data->caps_info[<idx>] can have at most %zu elements, accessing %ud, (%s)", caps_info_count, rt_idx, line);
116 continue;
117 }
118 if (sscanf(line, "pp_data->caps_info[%u]->FirstCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
119 pp_data->caps_info[rt_idx].FirstCap = temp_ushort;
120 continue;
121 }
122 if (sscanf(line, "pp_data->caps_info[%u]->LastCap = %hu\n", &rt_idx, &temp_ushort) == 2) {
123 pp_data->caps_info[rt_idx].LastCap = temp_ushort;
124 continue;
125 }
126 if (sscanf(line, "pp_data->caps_info[%u]->NumberOfCaps = %hu\n", &rt_idx, &temp_ushort) == 2) {
127 pp_data->caps_info[rt_idx].NumberOfCaps = temp_ushort;
128 continue;
129 }
130 if (sscanf(line, "pp_data->caps_info[%u]->ReportByteLength = %hu\n", &rt_idx, &temp_ushort) == 2) {
131 pp_data->caps_info[rt_idx].ReportByteLength = temp_ushort;
132 continue;
133 }
134 fprintf(stderr, "Ignoring unimplemented caps_info field: %s", line);
135 continue;
136 }
137
138 if (sscanf(line, "pp_data->FirstByteOfLinkCollectionArray = 0x%04hX\n", &FirstByteOfLinkCollectionArray)) {
139 continue;
140 }
141 if (sscanf(line, "pp_data->NumberLinkCollectionNodes = %hu\n", &NumberLinkCollectionNodes)) {
142 continue;
143 }
144
145 if (sscanf(line, "pp_data->cap[%u]", &caps_idx) == 1) {
146 if (pp_data->FirstByteOfLinkCollectionArray == 0) {
147 fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray is 0 or not reported yet\n", line);
148 continue;
149 }
150 if ((caps_idx + 1) * sizeof(hid_pp_cap) > pp_data->FirstByteOfLinkCollectionArray) {
151 fprintf(stderr, "Error reading pp_data file (%s): the caps index (%u) is out of pp_data bytes boundary (%hu vs %hu)\n", line, caps_idx, (unsigned short) ((caps_idx + 1) * sizeof(hid_pp_cap)), pp_data->FirstByteOfLinkCollectionArray);
152 continue;
153 }
154 if (sscanf(line, "pp_data->cap[%u]->UsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
155 pp_data->caps[caps_idx].UsagePage = temp_usage;
156 continue;
157 }
158 if (sscanf(line, "pp_data->cap[%u]->ReportID = 0x%02hhX\n", &caps_idx, &temp_uchar[0]) == 2) {
159 pp_data->caps[caps_idx].ReportID = temp_uchar[0];
160 continue;
161 }
162 if (sscanf(line, "pp_data->cap[%u]->BitPosition = %hhu\n", &caps_idx, &temp_uchar[0]) == 2) {
163 pp_data->caps[caps_idx].BitPosition = temp_uchar[0];
164 continue;
165 }
166 if (sscanf(line, "pp_data->cap[%u]->BitSize = %hu\n", &caps_idx, &temp_ushort) == 2) {
167 pp_data->caps[caps_idx].ReportSize = temp_ushort;
168 continue;
169 }
170 if (sscanf(line, "pp_data->cap[%u]->ReportCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
171 pp_data->caps[caps_idx].ReportCount = temp_ushort;
172 continue;
173 }
174 if (sscanf(line, "pp_data->cap[%u]->BytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
175 pp_data->caps[caps_idx].BytePosition = temp_ushort;
176 continue;
177 }
178 if (sscanf(line, "pp_data->cap[%u]->BitCount = %hu\n", &caps_idx, &temp_ushort) == 2) {
179 pp_data->caps[caps_idx].BitCount = temp_ushort;
180 continue;
181 }
182 if (sscanf(line, "pp_data->cap[%u]->BitField = 0x%02lX\n", &caps_idx, &temp_ulong) == 2) {
183 pp_data->caps[caps_idx].BitField = temp_ulong;
184 continue;
185 }
186 if (sscanf(line, "pp_data->cap[%u]->NextBytePosition = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
187 pp_data->caps[caps_idx].NextBytePosition = temp_ushort;
188 continue;
189 }
190 if (sscanf(line, "pp_data->cap[%u]->LinkCollection = 0x%04hX\n", &caps_idx, &temp_ushort) == 2) {
191 pp_data->caps[caps_idx].LinkCollection = temp_ushort;
192 continue;
193 }
194 if (sscanf(line, "pp_data->cap[%u]->LinkUsagePage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
195 pp_data->caps[caps_idx].LinkUsagePage = temp_usage;
196 continue;
197 }
198 if (sscanf(line, "pp_data->cap[%u]->LinkUsage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
199 pp_data->caps[caps_idx].LinkUsage = temp_usage;
200 continue;
201 }
202
203 // 8 Flags in one byte
204 if (sscanf(line, "pp_data->cap[%u]->IsMultipleItemsForArray = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
205 pp_data->caps[caps_idx].IsMultipleItemsForArray = temp_boolean[0];
206 continue;
207 }
208 if (sscanf(line, "pp_data->cap[%u]->IsButtonCap = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
209 pp_data->caps[caps_idx].IsButtonCap = temp_boolean[0];
210 continue;
211 }
212 if (sscanf(line, "pp_data->cap[%u]->IsPadding = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
213 pp_data->caps[caps_idx].IsPadding = temp_boolean[0];
214 continue;
215 }
216 if (sscanf(line, "pp_data->cap[%u]->IsAbsolute = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
217 pp_data->caps[caps_idx].IsAbsolute = temp_boolean[0];
218 continue;
219 }
220 if (sscanf(line, "pp_data->cap[%u]->IsRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
221 pp_data->caps[caps_idx].IsRange = temp_boolean[0];
222 continue;
223 }
224 if (sscanf(line, "pp_data->cap[%u]->IsAlias = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
225 pp_data->caps[caps_idx].IsAlias = temp_boolean[0];
226 continue;
227 }
228 if (sscanf(line, "pp_data->cap[%u]->IsStringRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
229 pp_data->caps[caps_idx].IsStringRange = temp_boolean[0];
230 continue;
231 }
232 if (sscanf(line, "pp_data->cap[%u]->IsDesignatorRange = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
233 pp_data->caps[caps_idx].IsDesignatorRange = temp_boolean[0];
234 continue;
235 }
236
237 if (sscanf(line, "pp_data->cap[%u]->Reserved1 = 0x%hhu%hhu%hhu\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
238 pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
239 pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
240 pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
241 continue;
242 }
243
244 if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u]", &caps_idx, &token_idx) == 2) {
245 const size_t unknown_tokens_count = sizeof(pp_data->caps[0].UnknownTokens) / sizeof(pp_data->caps[0].UnknownTokens[0]);
246 if (token_idx >= unknown_tokens_count) {
247 fprintf(stderr, "Broken pp_data file, pp_data->caps[<idx>].UnknownTokens[<idx>] can have at most %zu elements, accessing %ud, (%s)", unknown_tokens_count, token_idx, line);
248 continue;
249 }
250 if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].Token = 0x%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0]) == 3) {
251 pp_data->caps[caps_idx].UnknownTokens[token_idx].Token = temp_uchar[0];
252 continue;
253 }
254 if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].Reserved = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &token_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 5) {
255 pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[0] = temp_uchar[0];
256 pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[1] = temp_uchar[1];
257 pp_data->caps[caps_idx].UnknownTokens[token_idx].Reserved[2] = temp_uchar[2];
258 continue;
259 }
260 if (sscanf(line, "pp_data->cap[%u]->pp_cap->UnknownTokens[%u].BitField = 0x%08lX\n", &caps_idx, &token_idx, &temp_ulong) == 3) {
261 pp_data->caps[caps_idx].UnknownTokens[token_idx].BitField = temp_ulong;
262 continue;
263 }
264 fprintf(stderr, "Ignoring unimplemented pp_data->cap[]->pp_cap->UnknownTokens field: %s", line);
265 continue;
266 }
267
268 // Range
269 if (sscanf(line, "pp_data->cap[%u]->Range.UsageMin = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
270 pp_data->caps[caps_idx].Range.UsageMin = temp_usage;
271 continue;
272 }
273 if (sscanf(line, "pp_data->cap[%u]->Range.UsageMax = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
274 pp_data->caps[caps_idx].Range.UsageMax = temp_usage;
275 continue;
276 }
277 if (sscanf(line, "pp_data->cap[%u]->Range.StringMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
278 pp_data->caps[caps_idx].Range.StringMin = temp_ushort;
279 continue;
280 }
281 if (sscanf(line, "pp_data->cap[%u]->Range.StringMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
282 pp_data->caps[caps_idx].Range.StringMax = temp_ushort;
283 continue;
284 }
285 if (sscanf(line, "pp_data->cap[%u]->Range.DesignatorMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
286 pp_data->caps[caps_idx].Range.DesignatorMin = temp_ushort;
287 continue;
288 }
289 if (sscanf(line, "pp_data->cap[%u]->Range.DesignatorMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
290 pp_data->caps[caps_idx].Range.DesignatorMax = temp_ushort;
291 continue;
292 }
293 if (sscanf(line, "pp_data->cap[%u]->Range.DataIndexMin = %hu\n", &caps_idx, &temp_ushort) == 2) {
294 pp_data->caps[caps_idx].Range.DataIndexMin = temp_ushort;
295 continue;
296 }
297 if (sscanf(line, "pp_data->cap[%u]->Range.DataIndexMax = %hu\n", &caps_idx, &temp_ushort) == 2) {
298 pp_data->caps[caps_idx].Range.DataIndexMax = temp_ushort;
299 continue;
300 }
301
302 // NotRange
303 if (sscanf(line, "pp_data->cap[%u]->NotRange.Usage = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
304 pp_data->caps[caps_idx].NotRange.Usage = temp_usage;
305 continue;
306 }
307 if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved1 = 0x%04hX\n", &caps_idx, &temp_usage) == 2) {
308 pp_data->caps[caps_idx].NotRange.Reserved1 = temp_usage;
309 continue;
310 }
311 if (sscanf(line, "pp_data->cap[%u]->NotRange.StringIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
312 pp_data->caps[caps_idx].NotRange.StringIndex = temp_ushort;
313 continue;
314 }
315 if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved2 = %hu\n", &caps_idx, &temp_ushort) == 2) {
316 pp_data->caps[caps_idx].NotRange.Reserved2 = temp_ushort;
317 continue;
318 }
319 if (sscanf(line, "pp_data->cap[%u]->NotRange.DesignatorIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
320 pp_data->caps[caps_idx].NotRange.DesignatorIndex = temp_ushort;
321 continue;
322 }
323 if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved3 = %hu\n", &caps_idx, &temp_ushort) == 2) {
324 pp_data->caps[caps_idx].NotRange.Reserved3 = temp_ushort;
325 continue;
326 }
327 if (sscanf(line, "pp_data->cap[%u]->NotRange.DataIndex = %hu\n", &caps_idx, &temp_ushort) == 2) {
328 pp_data->caps[caps_idx].NotRange.DataIndex = temp_ushort;
329 continue;
330 }
331 if (sscanf(line, "pp_data->cap[%u]->NotRange.Reserved4 = %hu\n", &caps_idx, &temp_ushort) == 2) {
332 pp_data->caps[caps_idx].NotRange.Reserved4 = temp_ushort;
333 continue;
334 }
335
336 // Button
337 if (sscanf(line, "pp_data->cap[%u]->Button.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
338 pp_data->caps[caps_idx].Button.LogicalMin = temp_long;
339 continue;
340 }
341 if (sscanf(line, "pp_data->cap[%u]->Button.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
342 pp_data->caps[caps_idx].Button.LogicalMax = temp_long;
343 continue;
344 }
345
346 // NotButton
347 if (sscanf(line, "pp_data->cap[%u]->NotButton.HasNull = %hhu\n", &caps_idx, &temp_boolean[0]) == 2) {
348 pp_data->caps[caps_idx].NotButton.HasNull = temp_boolean[0];
349 continue;
350 }
351 if (sscanf(line, "pp_data->cap[%u]->NotButton.Reserved4 = 0x%02hhX%02hhX%02hhX\n", &caps_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
352 pp_data->caps[caps_idx].NotButton.Reserved4[0] = temp_uchar[0];
353 pp_data->caps[caps_idx].NotButton.Reserved4[1] = temp_uchar[1];
354 pp_data->caps[caps_idx].NotButton.Reserved4[2] = temp_uchar[2];
355 continue;
356 }
357 if (sscanf(line, "pp_data->cap[%u]->NotButton.LogicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
358 pp_data->caps[caps_idx].NotButton.LogicalMin = temp_long;
359 continue;
360 }
361 if (sscanf(line, "pp_data->cap[%u]->NotButton.LogicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
362 pp_data->caps[caps_idx].NotButton.LogicalMax = temp_long;
363 continue;
364 }
365 if (sscanf(line, "pp_data->cap[%u]->NotButton.PhysicalMin = %ld\n", &caps_idx, &temp_long) == 2) {
366 pp_data->caps[caps_idx].NotButton.PhysicalMin = temp_long;
367 continue;
368 }
369 if (sscanf(line, "pp_data->cap[%u]->NotButton.PhysicalMax = %ld\n", &caps_idx, &temp_long) == 2) {
370 pp_data->caps[caps_idx].NotButton.PhysicalMax = temp_long;
371 continue;
372 }
373
374 if (sscanf(line, "pp_data->cap[%u]->Units = %lu\n", &caps_idx, &temp_ulong) == 2) {
375 pp_data->caps[caps_idx].Units = temp_ulong;
376 continue;
377 }
378 if (sscanf(line, "pp_data->cap[%u]->UnitsExp = %lu\n", &caps_idx, &temp_ulong) == 2) {
379 pp_data->caps[caps_idx].UnitsExp = temp_ulong;
380 continue;
381 }
382 if (sscanf(line, "pp_data->cap[%u]->Reserved1 = 0x%02hhu%02hhu%02hhu\n", &coll_idx, &temp_uchar[0], &temp_uchar[1], &temp_uchar[2]) == 4) {
383 pp_data->caps[caps_idx].Reserved1[0] = temp_uchar[0];
384 pp_data->caps[caps_idx].Reserved1[1] = temp_uchar[1];
385 pp_data->caps[caps_idx].Reserved1[2] = temp_uchar[2];
386 continue;
387 }
388 fprintf(stderr, "Ignoring unimplemented cap field: %s", line);
389 continue;
390 }
391
392 if (sscanf(line, "pp_data->LinkCollectionArray[%u]", &coll_idx) == 1) {
393 if (pp_data->FirstByteOfLinkCollectionArray == 0 || pp_data->NumberLinkCollectionNodes == 0) {
394 fprintf(stderr, "Error reading pp_data file (%s): FirstByteOfLinkCollectionArray or NumberLinkCollectionNodes is 0 or not reported yet\n", line);
395 continue;
396 }
397 if (coll_idx >= pp_data->NumberLinkCollectionNodes) {
398 fprintf(stderr, "Error reading pp_data file (%s): the LinkCollection index (%u) is out of boundary (%hu)\n", line, coll_idx, pp_data->NumberLinkCollectionNodes);
399 continue;
400 }
401 phid_pp_link_collection_node pcoll = (phid_pp_link_collection_node)(((unsigned char*)&pp_data->caps[0]) + pp_data->FirstByteOfLinkCollectionArray);
402 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->LinkUsage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
403 pcoll[coll_idx].LinkUsage = temp_usage;
404 continue;
405 }
406 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->LinkUsagePage = 0x%04hX\n", &coll_idx, &temp_usage) == 2) {
407 pcoll[coll_idx].LinkUsagePage = temp_usage;
408 continue;
409 }
410 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->Parent = %hu\n", &coll_idx, &temp_ushort) == 2) {
411 pcoll[coll_idx].Parent = temp_ushort;
412 continue;
413 }
414 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->NumberOfChildren = %hu\n", &coll_idx, &temp_ushort) == 2) {
415 pcoll[coll_idx].NumberOfChildren = temp_ushort;
416 continue;
417 }
418 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->NextSibling = %hu\n", &coll_idx, &temp_ushort) == 2) {
419 pcoll[coll_idx].NextSibling = temp_ushort;
420 continue;
421 }
422 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->FirstChild = %hu\n", &coll_idx, &temp_ushort) == 2) {
423 pcoll[coll_idx].FirstChild = temp_ushort;
424 continue;
425 }
426 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->CollectionType = %lu\n", &coll_idx, &temp_ulong) == 2) {
427 pcoll[coll_idx].CollectionType = temp_ulong;
428 continue;
429 }
430 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->IsAlias = %lu\n", &coll_idx, &temp_ulong) == 2) {
431 pcoll[coll_idx].IsAlias = temp_ulong;
432 continue;
433 }
434 if (sscanf(line, "pp_data->LinkCollectionArray[%u]->Reserved = %lu\n", &coll_idx, &temp_ulong) == 2) {
435 pcoll[coll_idx].Reserved = temp_ulong;
436 continue;
437 }
438 fprintf(stderr, "Ignoring unimplemented LinkCollectionArray field: %s", line);
439 continue;
440 }
441 }
442
443//end:
444 fclose(file);
445
446 if (pp_data == &static_pp_data) {
447 return NULL;
448 }
449
450 return pp_data;
451}
452
453static BOOLEAN read_hex_data_from_text_file(const char *filename, unsigned char *data_out, size_t data_size, size_t *actual_read)
454{
455 size_t read_index = 0;
456 FILE* file = NULL;
457 errno_t err = fopen_s(&file, filename, "r");
458 if (err != 0) {
459 fprintf(stderr, "ERROR: Couldn't open file '%s' for reading: %s\n", filename, strerror(err));
460 return FALSE;
461 }
462
463 BOOLEAN result = TRUE;
464 unsigned int val;
465 char buf[16];
466 while (fscanf(file, "%15s", buf) == 1) {
467 if (sscanf(buf, "0x%X", &val) != 1) {
468 fprintf(stderr, "Invalid HEX text ('%s') file, got %s\n", filename, buf);
469 result = FALSE;
470 goto end;
471 }
472
473 if (read_index >= data_size) {
474 fprintf(stderr, "Buffer for file read is too small. Got only %zu bytes to read '%s'\n", data_size, filename);
475 result = FALSE;
476 goto end;
477 }
478
479 if (val > (unsigned char)-1) {
480 fprintf(stderr, "Invalid HEX text ('%s') file, got a value of: %u\n", filename, val);
481 result = FALSE;
482 goto end;
483 }
484
485 data_out[read_index] = (unsigned char) val;
486
487 read_index++;
488 }
489
490 if (!feof(file)) {
491 fprintf(stderr, "Invalid HEX text ('%s') file - failed to read all values\n", filename);
492 result = FALSE;
493 goto end;
494 }
495
496 *actual_read = read_index;
497
498end:
499 fclose(file);
500 return result;
501}
502
503
504int main(int argc, char* argv[])
505{
506 if (argc != 3) {
507 fprintf(stderr, "Expected 2 arguments for the test ('<>.pp_data' and '<>_expected.rpt_desc'), got: %d\n", argc - 1);
508 return EXIT_FAILURE;
509 }
510
511 printf("Checking: '%s' / '%s'\n", argv[1], argv[2]);
512
513 hidp_preparsed_data *pp_data = alloc_preparsed_data_from_file(argv[1]);
514 if (pp_data == NULL) {
515 return EXIT_FAILURE;
516 }
517
518 int result = EXIT_SUCCESS;
519
520 unsigned char report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
521
522 int res = hid_winapi_descriptor_reconstruct_pp_data(pp_data, report_descriptor, sizeof(report_descriptor));
523
524 if (res < 0) {
525 result = EXIT_FAILURE;
526 fprintf(stderr, "Failed to reconstruct descriptor");
527 goto end;
528 }
529 size_t report_descriptor_size = (size_t) res;
530
531 unsigned char expected_report_descriptor[HID_API_MAX_REPORT_DESCRIPTOR_SIZE];
532 size_t expected_report_descriptor_size = 0;
533 if (!read_hex_data_from_text_file(argv[2], expected_report_descriptor, sizeof(expected_report_descriptor), &expected_report_descriptor_size)) {
534 result = EXIT_FAILURE;
535 goto end;
536 }
537
538 if (report_descriptor_size == expected_report_descriptor_size) {
539 if (memcmp(report_descriptor, expected_report_descriptor, report_descriptor_size) == 0) {
540 printf("Reconstructed Report Descriptor matches the expected descriptor\n");
541 goto end;
542 }
543 else {
544 result = EXIT_FAILURE;
545 fprintf(stderr, "Reconstructed Report Descriptor has different content than expected\n");
546 }
547 }
548 else {
549 result = EXIT_FAILURE;
550 fprintf(stderr, "Reconstructed Report Descriptor has different size: %zu when expected %zu\n", report_descriptor_size, expected_report_descriptor_size);
551 }
552
553 printf(" Reconstructed Report Descriptor:\n");
554 for (int i = 0; i < res; i++) {
555 printf("0x%02X, ", report_descriptor[i]);
556 }
557 printf("\n");
558 fflush(stdout);
559
560end:
561 free(pp_data);
562 return result;
563}