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
,
22 /* retrieve the string substitution for a given string, or NULL if not found */
23 /* if found, len is set to the substitution length */
25 InfpGetSubstitutionString(PINFCACHE Inf
,
28 BOOL no_trailing_slash
)
30 static const WCHAR percent
= '%';
32 INFSTATUS Status
= INF_STATUS_NOT_FOUND
;
33 PINFCONTEXT Context
= NULL
;
35 WCHAR ValueName
[MAX_INF_STRING_LENGTH
+1];
36 WCHAR StringLangId
[13];
38 if (!*len
) /* empty string (%%) is replaced by single percent */
44 memcpy(ValueName
, str
, *len
* sizeof(WCHAR
));
47 DPRINT("Value name: %S\n", ValueName
);
49 if (Inf
->LanguageId
!= 0)
51 swprintf(StringLangId
,
55 Status
= InfpFindFirstLine(Inf
,
59 if (Status
!= INF_STATUS_SUCCESS
)
61 swprintf(StringLangId
,
63 MAKELANGID(PRIMARYLANGID(Inf
->LanguageId
), SUBLANG_NEUTRAL
));
65 Status
= InfpFindFirstLine(Inf
,
69 if (Status
!= INF_STATUS_SUCCESS
)
71 Status
= InfpFindFirstLine(Inf
,
80 Status
= InfpFindFirstLine(Inf
,
86 if (Status
!= INF_STATUS_SUCCESS
|| Context
== NULL
)
89 Status
= InfpGetData(Context
,
93 InfpFreeContext(Context
);
95 if (Status
== STATUS_SUCCESS
)
98 DPRINT("Substitute: %S Length: %ul\n", Data
, *len
);
106 /* do string substitutions on the specified text */
107 /* the buffer is assumed to be large enough */
108 /* returns necessary length not including terminating null */
110 InfpSubstituteString(PINFCACHE Inf
,
115 const WCHAR
*start
, *subst
, *p
;
116 unsigned int len
, total
= 0;
119 if (!buffer
) size
= MAX_INF_STRING_LENGTH
+ 1;
120 for (p
= start
= text
; *p
; p
++)
122 if (*p
!= '%') continue;
124 if (inside
) /* start of a %xx% string */
126 len
= (unsigned int)(p
- start
);
127 if (len
> size
- 1) len
= size
- 1;
128 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
133 else /* end of the %xx% string, find substitution */
135 len
= (unsigned int)(p
- start
- 1);
136 subst
= InfpGetSubstitutionString( Inf
, start
+ 1, &len
, p
[1] == '\\' );
140 len
= (unsigned int)(p
- start
+ 1);
142 if (len
> size
- 1) len
= size
- 1;
143 if (buffer
) memcpy( buffer
+ total
, subst
, len
* sizeof(WCHAR
) );
150 if (start
!= p
) /* unfinished string, copy it */
152 len
= (unsigned int)(p
- start
);
153 if (len
> size
- 1) len
= size
- 1;
154 if (buffer
) memcpy( buffer
+ total
, start
, len
* sizeof(WCHAR
) );
157 if (buffer
&& size
) buffer
[total
] = 0;
163 InfpFindFirstLine(PINFCACHE Cache
,
166 PINFCONTEXT
*Context
)
168 PINFCACHESECTION CacheSection
;
169 PINFCACHELINE CacheLine
;
171 if (Cache
== NULL
|| Section
== NULL
|| Context
== NULL
)
173 DPRINT1("Invalid parameter\n");
174 return INF_STATUS_INVALID_PARAMETER
;
177 CacheSection
= InfpFindSection(Cache
, Section
);
178 if (NULL
== CacheSection
)
180 DPRINT("Section not found\n");
181 return INF_STATUS_NOT_FOUND
;
186 CacheLine
= InfpFindKeyLine(CacheSection
, Key
);
190 CacheLine
= CacheSection
->FirstLine
;
193 if (NULL
== CacheLine
)
195 DPRINT("Key not found\n");
196 return INF_STATUS_NOT_FOUND
;
199 *Context
= MALLOC(sizeof(INFCONTEXT
));
200 if (NULL
== *Context
)
202 DPRINT1("MALLOC() failed\n");
203 return INF_STATUS_NO_MEMORY
;
205 (*Context
)->Inf
= (PVOID
)Cache
;
206 (*Context
)->Section
= (PVOID
)CacheSection
;
207 (*Context
)->Line
= (PVOID
)CacheLine
;
209 return INF_STATUS_SUCCESS
;
214 InfpFindNextLine(PINFCONTEXT ContextIn
,
215 PINFCONTEXT ContextOut
)
217 PINFCACHELINE CacheLine
;
219 if (ContextIn
== NULL
|| ContextOut
== NULL
)
220 return INF_STATUS_INVALID_PARAMETER
;
222 if (ContextIn
->Line
== NULL
)
223 return INF_STATUS_INVALID_PARAMETER
;
225 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
226 if (CacheLine
->Next
== NULL
)
227 return INF_STATUS_NOT_FOUND
;
229 if (ContextIn
!= ContextOut
)
231 ContextOut
->Inf
= ContextIn
->Inf
;
232 ContextOut
->Section
= ContextIn
->Section
;
234 ContextOut
->Line
= (PVOID
)(CacheLine
->Next
);
236 return INF_STATUS_SUCCESS
;
241 InfpFindFirstMatchLine(PINFCONTEXT ContextIn
,
243 PINFCONTEXT ContextOut
)
245 PINFCACHELINE CacheLine
;
247 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
248 return INF_STATUS_INVALID_PARAMETER
;
250 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
)
251 return INF_STATUS_INVALID_PARAMETER
;
253 CacheLine
= ((PINFCACHESECTION
)(ContextIn
->Section
))->FirstLine
;
254 while (CacheLine
!= NULL
)
256 if (CacheLine
->Key
!= NULL
&& strcmpiW (CacheLine
->Key
, Key
) == 0)
259 if (ContextIn
!= ContextOut
)
261 ContextOut
->Inf
= ContextIn
->Inf
;
262 ContextOut
->Section
= ContextIn
->Section
;
264 ContextOut
->Line
= (PVOID
)CacheLine
;
266 return INF_STATUS_SUCCESS
;
269 CacheLine
= CacheLine
->Next
;
272 return INF_STATUS_NOT_FOUND
;
277 InfpFindNextMatchLine(PINFCONTEXT ContextIn
,
279 PINFCONTEXT ContextOut
)
281 PINFCACHELINE CacheLine
;
283 if (ContextIn
== NULL
|| ContextOut
== NULL
|| Key
== NULL
|| *Key
== 0)
284 return INF_STATUS_INVALID_PARAMETER
;
286 if (ContextIn
->Inf
== NULL
|| ContextIn
->Section
== NULL
|| ContextIn
->Line
== NULL
)
287 return INF_STATUS_INVALID_PARAMETER
;
289 CacheLine
= (PINFCACHELINE
)ContextIn
->Line
;
290 while (CacheLine
!= NULL
)
292 if (CacheLine
->Key
!= NULL
&& strcmpiW (CacheLine
->Key
, Key
) == 0)
295 if (ContextIn
!= ContextOut
)
297 ContextOut
->Inf
= ContextIn
->Inf
;
298 ContextOut
->Section
= ContextIn
->Section
;
300 ContextOut
->Line
= (PVOID
)CacheLine
;
302 return INF_STATUS_SUCCESS
;
305 CacheLine
= CacheLine
->Next
;
308 return INF_STATUS_NOT_FOUND
;
313 InfpGetLineCount(HINF InfHandle
,
317 PINFCACHESECTION CacheSection
;
319 if (InfHandle
== NULL
|| Section
== NULL
)
321 DPRINT("Invalid parameter\n");
325 Cache
= (PINFCACHE
)InfHandle
;
327 /* Iterate through list of sections */
328 CacheSection
= Cache
->FirstSection
;
329 while (CacheSection
!= NULL
)
331 /* Are the section names the same? */
332 if (strcmpiW(CacheSection
->Name
, Section
) == 0)
334 return CacheSection
->LineCount
;
337 /* Get the next section */
338 CacheSection
= CacheSection
->Next
;
341 DPRINT("Section not found\n");
347 /* InfpGetLineText */
351 InfpGetFieldCount(PINFCONTEXT Context
)
353 if (Context
== NULL
|| Context
->Line
== NULL
)
356 return ((PINFCACHELINE
)Context
->Line
)->FieldCount
;
361 InfpGetBinaryField(PINFCONTEXT Context
,
364 ULONG ReturnBufferSize
,
367 PINFCACHELINE CacheLine
;
368 PINFCACHEFIELD CacheField
;
373 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
375 DPRINT("Invalid parameter\n");
376 return INF_STATUS_INVALID_PARAMETER
;
379 if (RequiredSize
!= NULL
)
382 CacheLine
= (PINFCACHELINE
)Context
->Line
;
384 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
385 return INF_STATUS_NOT_FOUND
;
387 CacheField
= CacheLine
->FirstField
;
388 for (Index
= 1; Index
< FieldIndex
; Index
++)
389 CacheField
= CacheField
->Next
;
391 Size
= (ULONG
)CacheLine
->FieldCount
- FieldIndex
+ 1;
393 if (RequiredSize
!= NULL
)
394 *RequiredSize
= Size
;
396 if (ReturnBuffer
!= NULL
)
398 if (ReturnBufferSize
< Size
)
399 return INF_STATUS_BUFFER_OVERFLOW
;
401 /* Copy binary data */
403 while (CacheField
!= NULL
)
405 *Ptr
= (UCHAR
)strtoulW(CacheField
->Data
, NULL
, 16);
408 CacheField
= CacheField
->Next
;
412 return INF_STATUS_SUCCESS
;
417 InfpGetIntField(PINFCONTEXT Context
,
421 PINFCACHELINE CacheLine
;
422 PINFCACHEFIELD CacheField
;
426 if (Context
== NULL
|| Context
->Line
== NULL
|| IntegerValue
== NULL
)
428 DPRINT("Invalid parameter\n");
429 return INF_STATUS_INVALID_PARAMETER
;
432 CacheLine
= (PINFCACHELINE
)Context
->Line
;
434 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
436 DPRINT("Invalid parameter\n");
437 return INF_STATUS_INVALID_PARAMETER
;
442 Ptr
= CacheLine
->Key
;
446 CacheField
= CacheLine
->FirstField
;
447 for (Index
= 1; Index
< FieldIndex
; Index
++)
448 CacheField
= CacheField
->Next
;
450 Ptr
= CacheField
->Data
;
453 *IntegerValue
= (LONG
)strtolW(Ptr
, NULL
, 0);
455 return INF_STATUS_SUCCESS
;
460 InfpGetMultiSzField(PINFCONTEXT Context
,
463 ULONG ReturnBufferSize
,
466 PINFCACHELINE CacheLine
;
467 PINFCACHEFIELD CacheField
;
468 PINFCACHEFIELD FieldPtr
;
473 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
475 DPRINT("Invalid parameter\n");
476 return INF_STATUS_INVALID_PARAMETER
;
479 if (RequiredSize
!= NULL
)
482 CacheLine
= (PINFCACHELINE
)Context
->Line
;
484 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
485 return INF_STATUS_INVALID_PARAMETER
;
487 CacheField
= CacheLine
->FirstField
;
488 for (Index
= 1; Index
< FieldIndex
; Index
++)
489 CacheField
= CacheField
->Next
;
491 /* Calculate the required buffer size */
492 FieldPtr
= CacheField
;
494 while (FieldPtr
!= NULL
)
496 Size
+= ((ULONG
)strlenW(FieldPtr
->Data
) + 1);
497 FieldPtr
= FieldPtr
->Next
;
501 if (RequiredSize
!= NULL
)
502 *RequiredSize
= Size
;
504 if (ReturnBuffer
!= NULL
)
506 if (ReturnBufferSize
< Size
)
507 return INF_STATUS_BUFFER_OVERFLOW
;
509 /* Copy multi-sz string */
511 FieldPtr
= CacheField
;
512 while (FieldPtr
!= NULL
)
514 Size
= (ULONG
)strlenW(FieldPtr
->Data
) + 1;
516 strcpyW(Ptr
, FieldPtr
->Data
);
519 FieldPtr
= FieldPtr
->Next
;
524 return INF_STATUS_SUCCESS
;
529 InfpGetStringField(PINFCONTEXT Context
,
532 ULONG ReturnBufferSize
,
535 PINFCACHELINE CacheLine
;
536 PINFCACHEFIELD CacheField
;
541 if (Context
== NULL
|| Context
->Line
== NULL
|| FieldIndex
== 0)
543 DPRINT("Invalid parameter\n");
544 return INF_STATUS_INVALID_PARAMETER
;
547 if (RequiredSize
!= NULL
)
550 CacheLine
= (PINFCACHELINE
)Context
->Line
;
552 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
553 return INF_STATUS_INVALID_PARAMETER
;
557 Ptr
= CacheLine
->Key
;
561 CacheField
= CacheLine
->FirstField
;
562 for (Index
= 1; Index
< FieldIndex
; Index
++)
563 CacheField
= CacheField
->Next
;
565 Ptr
= CacheField
->Data
;
568 // Size = (ULONG)strlenW(Ptr) + 1;
569 Size
= InfpSubstituteString(Context
->Inf
,
574 if (RequiredSize
!= NULL
)
575 *RequiredSize
= Size
+ 1;
577 if (ReturnBuffer
!= NULL
)
579 if (ReturnBufferSize
<= Size
)
580 return INF_STATUS_BUFFER_OVERFLOW
;
582 // strcpyW(ReturnBuffer, Ptr);
583 InfpSubstituteString(Context
->Inf
,
589 return INF_STATUS_SUCCESS
;
594 InfpGetData(PINFCONTEXT Context
,
598 PINFCACHELINE CacheKey
;
600 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
602 DPRINT("Invalid parameter\n");
603 return INF_STATUS_INVALID_PARAMETER
;
606 CacheKey
= (PINFCACHELINE
)Context
->Line
;
608 *Key
= CacheKey
->Key
;
612 if (CacheKey
->FirstField
== NULL
)
618 *Data
= CacheKey
->FirstField
->Data
;
622 return INF_STATUS_SUCCESS
;
627 InfpGetDataField(PINFCONTEXT Context
,
631 PINFCACHELINE CacheLine
;
632 PINFCACHEFIELD CacheField
;
635 if (Context
== NULL
|| Context
->Line
== NULL
|| Data
== NULL
)
637 DPRINT("Invalid parameter\n");
638 return INF_STATUS_INVALID_PARAMETER
;
641 CacheLine
= (PINFCACHELINE
)Context
->Line
;
643 if (FieldIndex
> (ULONG
)CacheLine
->FieldCount
)
644 return INF_STATUS_INVALID_PARAMETER
;
648 *Data
= CacheLine
->Key
;
652 CacheField
= CacheLine
->FirstField
;
653 for (Index
= 1; Index
< FieldIndex
; Index
++)
654 CacheField
= CacheField
->Next
;
656 *Data
= CacheField
->Data
;
659 return INF_STATUS_SUCCESS
;
663 InfpFreeContext(PINFCONTEXT Context
)