1 /*
2 * PROJECT: .inf file parser
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PROGRAMMER: Royce Mitchell III
5 * Eric Kohl
6 * Ge van Geldorp <gvg@reactos.org>
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include "inflib.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16 static size_t
17 InfpSubstituteString(PINFCACHE Inf,
18 const WCHAR *text,
19 WCHAR *buffer,
20 size_t size);
21
22 static void
ShortToHex(PWCHAR Buffer,USHORT Value)23 ShortToHex(PWCHAR Buffer,
24 USHORT Value)
25 {
26 WCHAR HexDigits[] = L"0123456789abcdef";
27
28 Buffer[0] = HexDigits[Value >> 12 & 0xf];
29 Buffer[1] = HexDigits[Value >> 8 & 0xf];
30 Buffer[2] = HexDigits[Value >> 4 & 0xf];
31 Buffer[3] = HexDigits[Value >> 0 & 0xf];
32 }
33
34 /* retrieve the string substitution for a given string, or NULL if not found */
35 /* if found, len is set to the substitution length */
36 static PCWSTR
InfpGetSubstitutionString(PINFCACHE Inf,PCWSTR str,size_t * len,BOOL no_trailing_slash)37 InfpGetSubstitutionString(PINFCACHE Inf,
38 PCWSTR str,
39 size_t *len,
40 BOOL no_trailing_slash)
41 {
42 static const WCHAR percent = '%';
43
44 INFSTATUS Status = INF_STATUS_NOT_FOUND;
45 PINFCONTEXT Context = NULL;
46 PWCHAR Data = NULL;
47 WCHAR ValueName[MAX_INF_STRING_LENGTH +1];
48 WCHAR StringLangId[] = L"Strings.XXXX";
49
50 if (!*len) /* empty string (%%) is replaced by single percent */
51 {
52 *len = 1;
53 return &percent;
54 }
55
56 memcpy(ValueName, str, *len * sizeof(WCHAR));
57 ValueName[*len] = 0;
58
59 DPRINT("Value name: %S\n", ValueName);
60
61 if (Inf->LanguageId != 0)
62 {
63 ShortToHex(&StringLangId[sizeof("Strings.") - 1],
64 Inf->LanguageId);
65
66 Status = InfpFindFirstLine(Inf,
67 StringLangId,
68 ValueName,
69 &Context);
70 if (Status != INF_STATUS_SUCCESS)
71 {
72 ShortToHex(&StringLangId[sizeof("Strings.") - 1],
73 MAKELANGID(PRIMARYLANGID(Inf->LanguageId), SUBLANG_NEUTRAL));
74
75 Status = InfpFindFirstLine(Inf,
76 StringLangId,
77 ValueName,
78 &Context);
79 if (Status != INF_STATUS_SUCCESS)
80 {
81 Status = InfpFindFirstLine(Inf,
82 L"Strings",
83 ValueName,
84 &Context);
85 }
86 }
87 }
88 else
89 {
90 Status = InfpFindFirstLine(Inf,
91 L"Strings",
92 ValueName,
93 &Context);
94 }
95
96 if (Status != INF_STATUS_SUCCESS || Context == NULL)
97 return NULL;
98
99 Status = InfpGetData(Context,
100 NULL,
101 &Data);
102
103 InfpFreeContext(Context);
104
105 if (Status == STATUS_SUCCESS)
106 {
107 *len = strlenW(Data);
108 DPRINT("Substitute: %S Length: %zu\n", Data, *len);
109 return Data;
110 }
111
112 return NULL;
113 }
114
115
116 /* do string substitutions on the specified text */
117 /* the buffer is assumed to be large enough */
118 /* returns necessary length not including terminating null */
119 static size_t
InfpSubstituteString(PINFCACHE Inf,PCWSTR text,PWSTR buffer,size_t size)120 InfpSubstituteString(PINFCACHE Inf,
121 PCWSTR text,
122 PWSTR buffer,
123 size_t size)
124 {
125 const WCHAR *start, *subst, *p;
126 size_t len, total = 0;
127 int inside = 0;
128
129 if (!buffer) size = MAX_INF_STRING_LENGTH + 1;
130 for (p = start = text; *p; p++)
131 {
132 if (*p != '%') continue;
133 inside = !inside;
134 if (inside) /* start of a %xx% string */
135 {
136 len = (p - start);
137 if (len > size - 1) len = size - 1;
138 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
139 total += len;
140 size -= len;
141 start = p;
142 }
143 else /* end of the %xx% string, find substitution */
144 {
145 len = (p - start - 1);
146 subst = InfpGetSubstitutionString( Inf, start + 1, &len, p[1] == '\\' );
147 if (!subst)
148 {
149 subst = start;
150 len = (p - start + 1);
151 }
152 if (len > size - 1) len = size - 1;
153 if (buffer) memcpy( buffer + total, subst, len * sizeof(WCHAR) );
154 total += len;
155 size -= len;
156 start = p + 1;
157 }
158 }
159
160 if (start != p) /* unfinished string, copy it */
161 {
162 len = (unsigned int)(p - start);
163 if (len > size - 1) len = size - 1;
164 if (buffer) memcpy( buffer + total, start, len * sizeof(WCHAR) );
165 total += len;
166 }
167 if (buffer && size) buffer[total] = 0;
168 return total;
169 }
170
171
172 INFSTATUS
InfpFindFirstLine(PINFCACHE Cache,PCWSTR Section,PCWSTR Key,PINFCONTEXT * Context)173 InfpFindFirstLine(PINFCACHE Cache,
174 PCWSTR Section,
175 PCWSTR Key,
176 PINFCONTEXT *Context)
177 {
178 PINFCACHESECTION CacheSection;
179 PINFCACHELINE CacheLine;
180
181 if (Cache == NULL || Section == NULL || Context == NULL)
182 {
183 DPRINT1("Invalid parameter\n");
184 return INF_STATUS_INVALID_PARAMETER;
185 }
186
187 CacheSection = InfpFindSection(Cache, Section);
188 if (NULL == CacheSection)
189 {
190 DPRINT("Section not found\n");
191 return INF_STATUS_NOT_FOUND;
192 }
193
194 if (Key != NULL)
195 {
196 CacheLine = InfpFindKeyLine(CacheSection, Key);
197 }
198 else
199 {
200 CacheLine = CacheSection->FirstLine;
201 }
202
203 if (NULL == CacheLine)
204 {
205 DPRINT("Key not found\n");
206 return INF_STATUS_NOT_FOUND;
207 }
208
209 *Context = MALLOC(sizeof(INFCONTEXT));
210 if (NULL == *Context)
211 {
212 DPRINT1("MALLOC() failed\n");
213 return INF_STATUS_NO_MEMORY;
214 }
215 (*Context)->Inf = (PVOID)Cache;
216 (*Context)->Section = CacheSection->Id;
217 (*Context)->Line = CacheLine->Id;
218
219 return INF_STATUS_SUCCESS;
220 }
221
222
223 INFSTATUS
InfpFindNextLine(PINFCONTEXT ContextIn,PINFCONTEXT ContextOut)224 InfpFindNextLine(PINFCONTEXT ContextIn,
225 PINFCONTEXT ContextOut)
226 {
227 PINFCACHELINE CacheLine;
228
229 if (ContextIn == NULL || ContextOut == NULL)
230 return INF_STATUS_INVALID_PARAMETER;
231
232 CacheLine = InfpGetLineForContext(ContextIn);
233 if (CacheLine == NULL)
234 return INF_STATUS_INVALID_PARAMETER;
235
236 if (CacheLine->Next == NULL)
237 return INF_STATUS_NOT_FOUND;
238
239 if (ContextIn != ContextOut)
240 {
241 ContextOut->Inf = ContextIn->Inf;
242 ContextOut->Section = ContextIn->Section;
243 }
244 ContextOut->Line = CacheLine->Next->Id;
245
246 return INF_STATUS_SUCCESS;
247 }
248
249
250 INFSTATUS
InfpFindFirstMatchLine(PINFCONTEXT ContextIn,PCWSTR Key,PINFCONTEXT ContextOut)251 InfpFindFirstMatchLine(PINFCONTEXT ContextIn,
252 PCWSTR Key,
253 PINFCONTEXT ContextOut)
254 {
255 PINFCACHESECTION Section;
256 PINFCACHELINE CacheLine;
257
258 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
259 return INF_STATUS_INVALID_PARAMETER;
260
261 Section = InfpGetSectionForContext(ContextIn);
262 if (Section == NULL)
263 return INF_STATUS_INVALID_PARAMETER;
264
265 CacheLine = Section->FirstLine;
266 while (CacheLine != NULL)
267 {
268 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0)
269 {
270
271 if (ContextIn != ContextOut)
272 {
273 ContextOut->Inf = ContextIn->Inf;
274 ContextOut->Section = ContextIn->Section;
275 }
276 ContextOut->Line = CacheLine->Id;
277
278 return INF_STATUS_SUCCESS;
279 }
280
281 CacheLine = CacheLine->Next;
282 }
283
284 return INF_STATUS_NOT_FOUND;
285 }
286
287
288 INFSTATUS
InfpFindNextMatchLine(PINFCONTEXT ContextIn,PCWSTR Key,PINFCONTEXT ContextOut)289 InfpFindNextMatchLine(PINFCONTEXT ContextIn,
290 PCWSTR Key,
291 PINFCONTEXT ContextOut)
292 {
293 PINFCACHESECTION Section;
294 PINFCACHELINE CacheLine;
295
296 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
297 return INF_STATUS_INVALID_PARAMETER;
298
299 Section = InfpGetSectionForContext(ContextIn);
300 if (Section == NULL)
301 return INF_STATUS_INVALID_PARAMETER;
302
303 CacheLine = InfpGetLineForContext(ContextIn);
304 while (CacheLine != NULL)
305 {
306 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0)
307 {
308
309 if (ContextIn != ContextOut)
310 {
311 ContextOut->Inf = ContextIn->Inf;
312 ContextOut->Section = ContextIn->Section;
313 }
314 ContextOut->Line = CacheLine->Id;
315
316 return INF_STATUS_SUCCESS;
317 }
318
319 CacheLine = CacheLine->Next;
320 }
321
322 return INF_STATUS_NOT_FOUND;
323 }
324
325
326 LONG
InfpGetLineCount(HINF InfHandle,PCWSTR Section)327 InfpGetLineCount(HINF InfHandle,
328 PCWSTR Section)
329 {
330 PINFCACHE Cache;
331 PINFCACHESECTION CacheSection;
332
333 if (InfHandle == NULL || Section == NULL)
334 {
335 DPRINT("Invalid parameter\n");
336 return -1;
337 }
338
339 Cache = (PINFCACHE)InfHandle;
340
341 /* Iterate through list of sections */
342 CacheSection = Cache->FirstSection;
343 while (CacheSection != NULL)
344 {
345 /* Are the section names the same? */
346 if (strcmpiW(CacheSection->Name, Section) == 0)
347 {
348 return CacheSection->LineCount;
349 }
350
351 /* Get the next section */
352 CacheSection = CacheSection->Next;
353 }
354
355 DPRINT("Section not found\n");
356
357 return -1;
358 }
359
360
361 /* InfpGetLineText */
362
363
364 LONG
InfpGetFieldCount(PINFCONTEXT Context)365 InfpGetFieldCount(PINFCONTEXT Context)
366 {
367 PINFCACHELINE Line;
368
369 Line = InfpGetLineForContext(Context);
370 if (Line == NULL)
371 return 0;
372 return Line->FieldCount;
373 }
374
375
376 INFSTATUS
InfpGetBinaryField(PINFCONTEXT Context,ULONG FieldIndex,PUCHAR ReturnBuffer,ULONG ReturnBufferSize,PULONG RequiredSize)377 InfpGetBinaryField(PINFCONTEXT Context,
378 ULONG FieldIndex,
379 PUCHAR ReturnBuffer,
380 ULONG ReturnBufferSize,
381 PULONG RequiredSize)
382 {
383 PINFCACHELINE CacheLine;
384 PINFCACHEFIELD CacheField;
385 ULONG Index;
386 ULONG Size;
387 PUCHAR Ptr;
388
389 if (Context == NULL || FieldIndex == 0)
390 {
391 DPRINT("Invalid parameter\n");
392 return INF_STATUS_INVALID_PARAMETER;
393 }
394
395 if (RequiredSize != NULL)
396 *RequiredSize = 0;
397
398 CacheLine = InfpGetLineForContext(Context);
399
400 if (FieldIndex > (ULONG)CacheLine->FieldCount)
401 return INF_STATUS_NOT_FOUND;
402
403 CacheField = CacheLine->FirstField;
404 for (Index = 1; Index < FieldIndex; Index++)
405 CacheField = CacheField->Next;
406
407 Size = (ULONG)CacheLine->FieldCount - FieldIndex + 1;
408
409 if (RequiredSize != NULL)
410 *RequiredSize = Size;
411
412 if (ReturnBuffer != NULL)
413 {
414 if (ReturnBufferSize < Size)
415 return INF_STATUS_BUFFER_OVERFLOW;
416
417 /* Copy binary data */
418 Ptr = ReturnBuffer;
419 while (CacheField != NULL)
420 {
421 *Ptr = (UCHAR)strtoulW(CacheField->Data, NULL, 16);
422
423 Ptr++;
424 CacheField = CacheField->Next;
425 }
426 }
427
428 return INF_STATUS_SUCCESS;
429 }
430
431
432 INFSTATUS
InfpGetIntField(PINFCONTEXT Context,ULONG FieldIndex,INT * IntegerValue)433 InfpGetIntField(PINFCONTEXT Context,
434 ULONG FieldIndex,
435 INT *IntegerValue)
436 {
437 PINFCACHELINE CacheLine;
438 PINFCACHEFIELD CacheField;
439 ULONG Index;
440 PWCHAR Ptr;
441
442 if (Context == NULL || IntegerValue == NULL)
443 {
444 DPRINT("Invalid parameter\n");
445 return INF_STATUS_INVALID_PARAMETER;
446 }
447
448 CacheLine = InfpGetLineForContext(Context);
449
450 if (FieldIndex > (ULONG)CacheLine->FieldCount)
451 {
452 DPRINT("Invalid parameter\n");
453 return INF_STATUS_INVALID_PARAMETER;
454 }
455
456 if (FieldIndex == 0)
457 {
458 Ptr = CacheLine->Key;
459 }
460 else
461 {
462 CacheField = CacheLine->FirstField;
463 for (Index = 1; Index < FieldIndex; Index++)
464 CacheField = CacheField->Next;
465
466 Ptr = CacheField->Data;
467 }
468
469 *IntegerValue = (LONG)strtolW(Ptr, NULL, 0);
470
471 return INF_STATUS_SUCCESS;
472 }
473
474
475 INFSTATUS
InfpGetMultiSzField(PINFCONTEXT Context,ULONG FieldIndex,PWSTR ReturnBuffer,ULONG ReturnBufferSize,PULONG RequiredSize)476 InfpGetMultiSzField(PINFCONTEXT Context,
477 ULONG FieldIndex,
478 PWSTR ReturnBuffer,
479 ULONG ReturnBufferSize,
480 PULONG RequiredSize)
481 {
482 PINFCACHELINE CacheLine;
483 PINFCACHEFIELD CacheField;
484 PINFCACHEFIELD FieldPtr;
485 ULONG Index;
486 ULONG Size;
487 PWCHAR Ptr;
488
489 if (Context == NULL || FieldIndex == 0)
490 {
491 DPRINT("Invalid parameter\n");
492 return INF_STATUS_INVALID_PARAMETER;
493 }
494
495 if (RequiredSize != NULL)
496 *RequiredSize = 0;
497
498 CacheLine = InfpGetLineForContext(Context);
499
500 if (FieldIndex > (ULONG)CacheLine->FieldCount)
501 return INF_STATUS_INVALID_PARAMETER;
502
503 CacheField = CacheLine->FirstField;
504 for (Index = 1; Index < FieldIndex; Index++)
505 CacheField = CacheField->Next;
506
507 /* Calculate the required buffer size */
508 FieldPtr = CacheField;
509 Size = 0;
510 while (FieldPtr != NULL)
511 {
512 Size += ((ULONG)strlenW(FieldPtr->Data) + 1);
513 FieldPtr = FieldPtr->Next;
514 }
515 Size++;
516
517 if (RequiredSize != NULL)
518 *RequiredSize = Size;
519
520 if (ReturnBuffer != NULL)
521 {
522 if (ReturnBufferSize < Size)
523 return INF_STATUS_BUFFER_OVERFLOW;
524
525 /* Copy multi-sz string */
526 Ptr = ReturnBuffer;
527 FieldPtr = CacheField;
528 while (FieldPtr != NULL)
529 {
530 Size = (ULONG)strlenW(FieldPtr->Data) + 1;
531
532 strcpyW(Ptr, FieldPtr->Data);
533
534 Ptr = Ptr + Size;
535 FieldPtr = FieldPtr->Next;
536 }
537 *Ptr = 0;
538 }
539
540 return INF_STATUS_SUCCESS;
541 }
542
543
544 INFSTATUS
InfpGetStringField(PINFCONTEXT Context,ULONG FieldIndex,PWSTR ReturnBuffer,ULONG ReturnBufferSize,PULONG RequiredSize)545 InfpGetStringField(PINFCONTEXT Context,
546 ULONG FieldIndex,
547 PWSTR ReturnBuffer,
548 ULONG ReturnBufferSize,
549 PULONG RequiredSize)
550 {
551 PINFCACHELINE CacheLine;
552 PINFCACHEFIELD CacheField;
553 ULONG Index;
554 PWCHAR Ptr;
555 SIZE_T Size;
556
557 if (Context == NULL)
558 {
559 DPRINT("Invalid parameter\n");
560 return INF_STATUS_INVALID_PARAMETER;
561 }
562
563 if (RequiredSize != NULL)
564 *RequiredSize = 0;
565
566 CacheLine = InfpGetLineForContext(Context);
567
568 if (FieldIndex > (ULONG)CacheLine->FieldCount)
569 return INF_STATUS_INVALID_PARAMETER;
570
571 if (FieldIndex == 0)
572 {
573 Ptr = CacheLine->Key;
574 }
575 else
576 {
577 CacheField = CacheLine->FirstField;
578 for (Index = 1; Index < FieldIndex; Index++)
579 CacheField = CacheField->Next;
580
581 Ptr = CacheField->Data;
582 }
583
584 // Size = (ULONG)strlenW(Ptr) + 1;
585 Size = InfpSubstituteString(Context->Inf,
586 Ptr,
587 NULL,
588 0);
589
590 if (RequiredSize != NULL)
591 *RequiredSize = (ULONG)Size + 1;
592
593 if (ReturnBuffer != NULL)
594 {
595 if (ReturnBufferSize <= Size)
596 return INF_STATUS_BUFFER_OVERFLOW;
597
598 // strcpyW(ReturnBuffer, Ptr);
599 InfpSubstituteString(Context->Inf,
600 Ptr,
601 ReturnBuffer,
602 ReturnBufferSize);
603 }
604
605 return INF_STATUS_SUCCESS;
606 }
607
608
609 INFSTATUS
InfpGetData(PINFCONTEXT Context,PWCHAR * Key,PWCHAR * Data)610 InfpGetData(PINFCONTEXT Context,
611 PWCHAR *Key,
612 PWCHAR *Data)
613 {
614 PINFCACHELINE CacheKey;
615
616 if (Context == NULL || Data == NULL)
617 {
618 DPRINT("Invalid parameter\n");
619 return INF_STATUS_INVALID_PARAMETER;
620 }
621
622 CacheKey = InfpGetLineForContext(Context);
623 if (Key != NULL)
624 *Key = CacheKey->Key;
625
626 if (Data != NULL)
627 {
628 if (CacheKey->FirstField == NULL)
629 {
630 *Data = NULL;
631 }
632 else
633 {
634 *Data = CacheKey->FirstField->Data;
635 }
636 }
637
638 return INF_STATUS_SUCCESS;
639 }
640
641
642 INFSTATUS
InfpGetDataField(PINFCONTEXT Context,ULONG FieldIndex,PWCHAR * Data)643 InfpGetDataField(PINFCONTEXT Context,
644 ULONG FieldIndex,
645 PWCHAR *Data)
646 {
647 PINFCACHELINE CacheLine;
648 PINFCACHEFIELD CacheField;
649 ULONG Index;
650
651 if (Context == NULL || Data == NULL)
652 {
653 DPRINT("Invalid parameter\n");
654 return INF_STATUS_INVALID_PARAMETER;
655 }
656
657 CacheLine = InfpGetLineForContext(Context);
658
659 if (FieldIndex > (ULONG)CacheLine->FieldCount)
660 return INF_STATUS_INVALID_PARAMETER;
661
662 if (FieldIndex == 0)
663 {
664 *Data = CacheLine->Key;
665 }
666 else
667 {
668 CacheField = CacheLine->FirstField;
669 for (Index = 1; Index < FieldIndex; Index++)
670 CacheField = CacheField->Next;
671
672 *Data = CacheField->Data;
673 }
674
675 return INF_STATUS_SUCCESS;
676 }
677
678 VOID
InfpFreeContext(PINFCONTEXT Context)679 InfpFreeContext(PINFCONTEXT Context)
680 {
681 FREE(Context);
682 }
683
684 /* EOF */
685