xref: /reactos/sdk/lib/inflib/infget.c (revision a75e4db8)
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