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