2 * PROJECT: .inf file parser
3 * LICENSE: GPL - See COPYING in the top level directory
4 * PROGRAMMER: Royce Mitchell III
6 * Ge van Geldorp <gvg@reactos.org>
9 /* INCLUDES *****************************************************************/
17 InfpSubstituteString(PINFCACHE Inf
,
23 ShortToHex(PWCHAR Buffer
,
26 WCHAR HexDigits
[] = L
"0123456789abcdef";
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];
34 /* retrieve the string substitution for a given string, or NULL if not found */
35 /* if found, len is set to the substitution length */
37 InfpGetSubstitutionString(PINFCACHE Inf
,
40 BOOL no_trailing_slash
)
42 static const WCHAR percent
= '%';
44 INFSTATUS Status
= INF_STATUS_NOT_FOUND
;
45 PINFCONTEXT Context
= NULL
;
47 WCHAR ValueName
[MAX_INF_STRING_LENGTH
+1];
48 WCHAR StringLangId
[] = L
"Strings.XXXX";
50 if (!*len
) /* empty string (%%) is replaced by single percent */
56 memcpy(ValueName
, str
, *len
* sizeof(WCHAR
));
59 DPRINT("Value name: %S\n", ValueName
);
61 if (Inf
->LanguageId
!= 0)
63 ShortToHex(&StringLangId
[sizeof("Strings.") - 1],
66 Status
= InfpFindFirstLine(Inf
,
70 if (Status
!= INF_STATUS_SUCCESS
)
72 ShortToHex(&StringLangId
[sizeof("Strings.") - 1],
73 MAKELANGID(PRIMARYLANGID(Inf
->LanguageId
), SUBLANG_NEUTRAL
));
75 Status
= InfpFindFirstLine(Inf
,
79 if (Status
!= INF_STATUS_SUCCESS
)
81 Status
= InfpFindFirstLine(Inf
,
90 Status
= InfpFindFirstLine(Inf
,
96 if (Status
!= INF_STATUS_SUCCESS
|| Context
== NULL
)
99 Status
= InfpGetData(Context
,
103 InfpFreeContext(Context
);
105 if (Status
== STATUS_SUCCESS
)
107 *len
= strlenW(Data
);
108 DPRINT("Substitute: %S Length: %ul\n", Data
, *len
);
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 */
120 InfpSubstituteString(PINFCACHE Inf
,
125 const WCHAR
*start
, *subst
, *p
;
126 unsigned int len
, total
= 0;
129 if (!buffer
) size
= MAX_INF_STRING_LENGTH
+ 1;
130 for (p
= start
= text
; *p
; p
++)
132 if (*p
!= '%') continue;
134 if (inside
) /* start of a %xx% string */
136 len
= (unsigned int)(p
- start
);
137 if (len
> size
- 1) len
= size
- 1;
138 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
143 else /* end of the %xx% string, find substitution */
145 len
= (unsigned int)(p
- start
- 1);
146 subst
= InfpGetSubstitutionString( Inf
, start
+ 1, &len
, p
[1] == '\\' );
150 len
= (unsigned int)(p
- start
+ 1);
152 if (len
> size
- 1) len
= size
- 1;
153 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
160 if (start
!= p
) /* unfinished string, copy it */
162 len
= (unsigned int)(p
- start
);
163 if (len
> size
- 1) len
= size
- 1;
164 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
167 if (buffer
&& size
) buffer
[total
] = 0;
173 InfpFindFirstLine(PINFCACHE Cache
,
176 PINFCONTEXT
*Context
)
178 PINFCACHESECTION CacheSection
;
179 PINFCACHELINE CacheLine
;
181 if (Cache
== NULL
|| Section
== NULL
|| Context
== NULL
)
183 DPRINT1("Invalid parameter\n");
184 return INF_STATUS_INVALID_PARAMETER
;
187 CacheSection
= InfpFindSection(Cache
, Section
);
188 if (NULL
== CacheSection
)
190 DPRINT("Section not found\n");
191 return INF_STATUS_NOT_FOUND
;
196 CacheLine
= InfpFindKeyLine(CacheSection
, Key
);
200 CacheLine
= CacheSection
->FirstLine
;
203 if (NULL
== CacheLine
)
205 DPRINT("Key not found\n");
206 return INF_STATUS_NOT_FOUND
;
209 *Context
= MALLOC(sizeof(INFCONTEXT
));
210 if (NULL
== *Context
)
212 DPRINT1("MALLOC() failed\n");
213 return INF_STATUS_NO_MEMORY
;
215 (*Context
)->Inf
= (PVOID
)Cache
;
216 (*Context
)->Section
= (PVOID
)CacheSection
;
217 (*Context
)->Line
= (PVOID
)CacheLine
;
219 return INF_STATUS_SUCCESS
;
224 InfpFindNextLine(PINFCONTEXT ContextIn
,
225 PINFCONTEXT ContextOut
)
227 PINFCACHELINE CacheLine
;
229 if (ContextIn
== NULL
|| ContextOut
== NULL
)
230 return INF_STATUS_INVALID_PARAMETER
;
232 if (ContextIn
->Line
== NULL
)
233 return INF_STATUS_INVALID_PARAMETER
;
235 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
236 if (CacheLine
->Next
== NULL
)
237 return INF_STATUS_NOT_FOUND
;
239 if (ContextIn
!= ContextOut
)
241 ContextOut
->Inf
= ContextIn
->Inf
;
242 ContextOut
->Section
= ContextIn
->Section
;
244 ContextOut
->Line
= (PVOID
)(CacheLine
->Next
);
246 return INF_STATUS_SUCCESS
;
251 InfpFindFirstMatchLine(PINFCONTEXT ContextIn
,
253 PINFCONTEXT ContextOut
)
255 PINFCACHELINE CacheLine
;
257 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
258 return INF_STATUS_INVALID_PARAMETER
;
260 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
)
261 return INF_STATUS_INVALID_PARAMETER
;
263 CacheLine
= ((PINFCACHESECTION
)(ContextIn
->Section
))->FirstLine
;
264 while (CacheLine
!= NULL
)
266 if (CacheLine
->Key
!= NULL
&& strcmpiW (CacheLine
->Key
, Key
) == 0)
269 if (ContextIn
!= ContextOut
)
271 ContextOut
->Inf
= ContextIn
->Inf
;
272 ContextOut
->Section
= ContextIn
->Section
;
274 ContextOut
->Line
= (PVOID
)CacheLine
;
276 return INF_STATUS_SUCCESS
;
279 CacheLine
= CacheLine
->Next
;
282 return INF_STATUS_NOT_FOUND
;
287 InfpFindNextMatchLine(PINFCONTEXT ContextIn
,
289 PINFCONTEXT ContextOut
)
291 PINFCACHELINE CacheLine
;
293 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
294 return INF_STATUS_INVALID_PARAMETER
;
296 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
|| ContextIn
->Line
== NULL
)
297 return INF_STATUS_INVALID_PARAMETER
;
299 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
300 while (CacheLine
!= NULL
)
302 if (CacheLine
->Key
!= NULL
&& strcmpiW (CacheLine
->Key
, Key
) == 0)
305 if (ContextIn
!= ContextOut
)
307 ContextOut
->Inf
= ContextIn
->Inf
;
308 ContextOut
->Section
= ContextIn
->Section
;
310 ContextOut
->Line
= (PVOID
)CacheLine
;
312 return INF_STATUS_SUCCESS
;
315 CacheLine
= CacheLine
->Next
;
318 return INF_STATUS_NOT_FOUND
;
323 InfpGetLineCount(HINF InfHandle
,
327 PINFCACHESECTION CacheSection
;
329 if (InfHandle
== NULL
|| Section
== NULL
)
331 DPRINT("Invalid parameter\n");
335 Cache
= (PINFCACHE
)InfHandle
;
337 /* Iterate through list of sections */
338 CacheSection
= Cache
->FirstSection
;
339 while (CacheSection
!= NULL
)
341 /* Are the section names the same? */
342 if (strcmpiW(CacheSection
->Name
, Section
) == 0)
344 return CacheSection
->LineCount
;
347 /* Get the next section */
348 CacheSection
= CacheSection
->Next
;
351 DPRINT("Section not found\n");
357 /* InfpGetLineText */
361 InfpGetFieldCount(PINFCONTEXT Context
)
363 if (Context
== NULL
|| Context
->Line
== NULL
)
366 return ((PINFCACHELINE
)Context
->Line
)->FieldCount
;
371 InfpGetBinaryField(PINFCONTEXT Context
,
374 ULONG ReturnBufferSize
,
377 PINFCACHELINE CacheLine
;
378 PINFCACHEFIELD CacheField
;
383 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
385 DPRINT("Invalid parameter\n");
386 return INF_STATUS_INVALID_PARAMETER
;
389 if (RequiredSize
!= NULL
)
392 CacheLine
= (PINFCACHELINE
)Context
->Line
;
394 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
395 return INF_STATUS_NOT_FOUND
;
397 CacheField
= CacheLine
->FirstField
;
398 for (Index
= 1; Index
< FieldIndex
; Index
++)
399 CacheField
= CacheField
->Next
;
401 Size
= (ULONG
)CacheLine
->FieldCount
- FieldIndex
+ 1;
403 if (RequiredSize
!= NULL
)
404 *RequiredSize
= Size
;
406 if (ReturnBuffer
!= NULL
)
408 if (ReturnBufferSize
< Size
)
409 return INF_STATUS_BUFFER_OVERFLOW
;
411 /* Copy binary data */
413 while (CacheField
!= NULL
)
415 *Ptr
= (UCHAR
)strtoulW(CacheField
->Data
, NULL
, 16);
418 CacheField
= CacheField
->Next
;
422 return INF_STATUS_SUCCESS
;
427 InfpGetIntField(PINFCONTEXT Context
,
431 PINFCACHELINE CacheLine
;
432 PINFCACHEFIELD CacheField
;
436 if (Context
== NULL
|| Context
->Line
== NULL
|| IntegerValue
== NULL
)
438 DPRINT("Invalid parameter\n");
439 return INF_STATUS_INVALID_PARAMETER
;
442 CacheLine
= (PINFCACHELINE
)Context
->Line
;
444 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
446 DPRINT("Invalid parameter\n");
447 return INF_STATUS_INVALID_PARAMETER
;
452 Ptr
= CacheLine
->Key
;
456 CacheField
= CacheLine
->FirstField
;
457 for (Index
= 1; Index
< FieldIndex
; Index
++)
458 CacheField
= CacheField
->Next
;
460 Ptr
= CacheField
->Data
;
463 *IntegerValue
= (LONG
)strtolW(Ptr
, NULL
, 0);
465 return INF_STATUS_SUCCESS
;
470 InfpGetMultiSzField(PINFCONTEXT Context
,
473 ULONG ReturnBufferSize
,
476 PINFCACHELINE CacheLine
;
477 PINFCACHEFIELD CacheField
;
478 PINFCACHEFIELD FieldPtr
;
483 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
485 DPRINT("Invalid parameter\n");
486 return INF_STATUS_INVALID_PARAMETER
;
489 if (RequiredSize
!= NULL
)
492 CacheLine
= (PINFCACHELINE
)Context
->Line
;
494 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
495 return INF_STATUS_INVALID_PARAMETER
;
497 CacheField
= CacheLine
->FirstField
;
498 for (Index
= 1; Index
< FieldIndex
; Index
++)
499 CacheField
= CacheField
->Next
;
501 /* Calculate the required buffer size */
502 FieldPtr
= CacheField
;
504 while (FieldPtr
!= NULL
)
506 Size
+= ((ULONG
)strlenW(FieldPtr
->Data
) + 1);
507 FieldPtr
= FieldPtr
->Next
;
511 if (RequiredSize
!= NULL
)
512 *RequiredSize
= Size
;
514 if (ReturnBuffer
!= NULL
)
516 if (ReturnBufferSize
< Size
)
517 return INF_STATUS_BUFFER_OVERFLOW
;
519 /* Copy multi-sz string */
521 FieldPtr
= CacheField
;
522 while (FieldPtr
!= NULL
)
524 Size
= (ULONG
)strlenW(FieldPtr
->Data
) + 1;
526 strcpyW(Ptr
, FieldPtr
->Data
);
529 FieldPtr
= FieldPtr
->Next
;
534 return INF_STATUS_SUCCESS
;
539 InfpGetStringField(PINFCONTEXT Context
,
542 ULONG ReturnBufferSize
,
545 PINFCACHELINE CacheLine
;
546 PINFCACHEFIELD CacheField
;
551 if (Context
== NULL
|| Context
->Line
== NULL
)
553 DPRINT("Invalid parameter\n");
554 return INF_STATUS_INVALID_PARAMETER
;
557 if (RequiredSize
!= NULL
)
560 CacheLine
= (PINFCACHELINE
)Context
->Line
;
562 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
563 return INF_STATUS_INVALID_PARAMETER
;
567 Ptr
= CacheLine
->Key
;
571 CacheField
= CacheLine
->FirstField
;
572 for (Index
= 1; Index
< FieldIndex
; Index
++)
573 CacheField
= CacheField
->Next
;
575 Ptr
= CacheField
->Data
;
578 // Size = (ULONG)strlenW(Ptr) + 1;
579 Size
= InfpSubstituteString(Context
->Inf
,
584 if (RequiredSize
!= NULL
)
585 *RequiredSize
= Size
+ 1;
587 if (ReturnBuffer
!= NULL
)
589 if (ReturnBufferSize
<= Size
)
590 return INF_STATUS_BUFFER_OVERFLOW
;
592 // strcpyW(ReturnBuffer, Ptr);
593 InfpSubstituteString(Context
->Inf
,
599 return INF_STATUS_SUCCESS
;
604 InfpGetData(PINFCONTEXT Context
,
608 PINFCACHELINE CacheKey
;
610 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
612 DPRINT("Invalid parameter\n");
613 return INF_STATUS_INVALID_PARAMETER
;
616 CacheKey
= (PINFCACHELINE
)Context
->Line
;
618 *Key
= CacheKey
->Key
;
622 if (CacheKey
->FirstField
== NULL
)
628 *Data
= CacheKey
->FirstField
->Data
;
632 return INF_STATUS_SUCCESS
;
637 InfpGetDataField(PINFCONTEXT Context
,
641 PINFCACHELINE CacheLine
;
642 PINFCACHEFIELD CacheField
;
645 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
647 DPRINT("Invalid parameter\n");
648 return INF_STATUS_INVALID_PARAMETER
;
651 CacheLine
= (PINFCACHELINE
)Context
->Line
;
653 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
654 return INF_STATUS_INVALID_PARAMETER
;
658 *Data
= CacheLine
->Key
;
662 CacheField
= CacheLine
->FirstField
;
663 for (Index
= 1; Index
< FieldIndex
; Index
++)
664 CacheField
= CacheField
->Next
;
666 *Data
= CacheField
->Data
;
669 return INF_STATUS_SUCCESS
;
673 InfpFreeContext(PINFCONTEXT Context
)