[NET][MC] Move NET USER strings from net.exe to netmsg.dll.
[reactos.git] / sdk / lib / inflib / 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 size_t
17 InfpSubstituteString(PINFCACHE Inf,
18 const WCHAR *text,
19 WCHAR *buffer,
20 size_t size);
21
22 static void
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
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
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
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 = (PVOID)CacheSection;
217 (*Context)->Line = (PVOID)CacheLine;
218
219 return INF_STATUS_SUCCESS;
220 }
221
222
223 INFSTATUS
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 if (ContextIn->Line == NULL)
233 return INF_STATUS_INVALID_PARAMETER;
234
235 CacheLine = (PINFCACHELINE)ContextIn->Line;
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 = (PVOID)(CacheLine->Next);
245
246 return INF_STATUS_SUCCESS;
247 }
248
249
250 INFSTATUS
251 InfpFindFirstMatchLine(PINFCONTEXT ContextIn,
252 PCWSTR Key,
253 PINFCONTEXT ContextOut)
254 {
255 PINFCACHELINE CacheLine;
256
257 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
258 return INF_STATUS_INVALID_PARAMETER;
259
260 if (ContextIn->Inf == NULL || ContextIn->Section == NULL)
261 return INF_STATUS_INVALID_PARAMETER;
262
263 CacheLine = ((PINFCACHESECTION)(ContextIn->Section))->FirstLine;
264 while (CacheLine != NULL)
265 {
266 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0)
267 {
268
269 if (ContextIn != ContextOut)
270 {
271 ContextOut->Inf = ContextIn->Inf;
272 ContextOut->Section = ContextIn->Section;
273 }
274 ContextOut->Line = (PVOID)CacheLine;
275
276 return INF_STATUS_SUCCESS;
277 }
278
279 CacheLine = CacheLine->Next;
280 }
281
282 return INF_STATUS_NOT_FOUND;
283 }
284
285
286 INFSTATUS
287 InfpFindNextMatchLine(PINFCONTEXT ContextIn,
288 PCWSTR Key,
289 PINFCONTEXT ContextOut)
290 {
291 PINFCACHELINE CacheLine;
292
293 if (ContextIn == NULL || ContextOut == NULL || Key == NULL || *Key == 0)
294 return INF_STATUS_INVALID_PARAMETER;
295
296 if (ContextIn->Inf == NULL || ContextIn->Section == NULL || ContextIn->Line == NULL)
297 return INF_STATUS_INVALID_PARAMETER;
298
299 CacheLine = (PINFCACHELINE)ContextIn->Line;
300 while (CacheLine != NULL)
301 {
302 if (CacheLine->Key != NULL && strcmpiW (CacheLine->Key, Key) == 0)
303 {
304
305 if (ContextIn != ContextOut)
306 {
307 ContextOut->Inf = ContextIn->Inf;
308 ContextOut->Section = ContextIn->Section;
309 }
310 ContextOut->Line = (PVOID)CacheLine;
311
312 return INF_STATUS_SUCCESS;
313 }
314
315 CacheLine = CacheLine->Next;
316 }
317
318 return INF_STATUS_NOT_FOUND;
319 }
320
321
322 LONG
323 InfpGetLineCount(HINF InfHandle,
324 PCWSTR Section)
325 {
326 PINFCACHE Cache;
327 PINFCACHESECTION CacheSection;
328
329 if (InfHandle == NULL || Section == NULL)
330 {
331 DPRINT("Invalid parameter\n");
332 return -1;
333 }
334
335 Cache = (PINFCACHE)InfHandle;
336
337 /* Iterate through list of sections */
338 CacheSection = Cache->FirstSection;
339 while (CacheSection != NULL)
340 {
341 /* Are the section names the same? */
342 if (strcmpiW(CacheSection->Name, Section) == 0)
343 {
344 return CacheSection->LineCount;
345 }
346
347 /* Get the next section */
348 CacheSection = CacheSection->Next;
349 }
350
351 DPRINT("Section not found\n");
352
353 return -1;
354 }
355
356
357 /* InfpGetLineText */
358
359
360 LONG
361 InfpGetFieldCount(PINFCONTEXT Context)
362 {
363 if (Context == NULL || Context->Line == NULL)
364 return 0;
365
366 return ((PINFCACHELINE)Context->Line)->FieldCount;
367 }
368
369
370 INFSTATUS
371 InfpGetBinaryField(PINFCONTEXT Context,
372 ULONG FieldIndex,
373 PUCHAR ReturnBuffer,
374 ULONG ReturnBufferSize,
375 PULONG RequiredSize)
376 {
377 PINFCACHELINE CacheLine;
378 PINFCACHEFIELD CacheField;
379 ULONG Index;
380 ULONG Size;
381 PUCHAR Ptr;
382
383 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
384 {
385 DPRINT("Invalid parameter\n");
386 return INF_STATUS_INVALID_PARAMETER;
387 }
388
389 if (RequiredSize != NULL)
390 *RequiredSize = 0;
391
392 CacheLine = (PINFCACHELINE)Context->Line;
393
394 if (FieldIndex > (ULONG)CacheLine->FieldCount)
395 return INF_STATUS_NOT_FOUND;
396
397 CacheField = CacheLine->FirstField;
398 for (Index = 1; Index < FieldIndex; Index++)
399 CacheField = CacheField->Next;
400
401 Size = (ULONG)CacheLine->FieldCount - FieldIndex + 1;
402
403 if (RequiredSize != NULL)
404 *RequiredSize = Size;
405
406 if (ReturnBuffer != NULL)
407 {
408 if (ReturnBufferSize < Size)
409 return INF_STATUS_BUFFER_OVERFLOW;
410
411 /* Copy binary data */
412 Ptr = ReturnBuffer;
413 while (CacheField != NULL)
414 {
415 *Ptr = (UCHAR)strtoulW(CacheField->Data, NULL, 16);
416
417 Ptr++;
418 CacheField = CacheField->Next;
419 }
420 }
421
422 return INF_STATUS_SUCCESS;
423 }
424
425
426 INFSTATUS
427 InfpGetIntField(PINFCONTEXT Context,
428 ULONG FieldIndex,
429 INT *IntegerValue)
430 {
431 PINFCACHELINE CacheLine;
432 PINFCACHEFIELD CacheField;
433 ULONG Index;
434 PWCHAR Ptr;
435
436 if (Context == NULL || Context->Line == NULL || IntegerValue == NULL)
437 {
438 DPRINT("Invalid parameter\n");
439 return INF_STATUS_INVALID_PARAMETER;
440 }
441
442 CacheLine = (PINFCACHELINE)Context->Line;
443
444 if (FieldIndex > (ULONG)CacheLine->FieldCount)
445 {
446 DPRINT("Invalid parameter\n");
447 return INF_STATUS_INVALID_PARAMETER;
448 }
449
450 if (FieldIndex == 0)
451 {
452 Ptr = CacheLine->Key;
453 }
454 else
455 {
456 CacheField = CacheLine->FirstField;
457 for (Index = 1; Index < FieldIndex; Index++)
458 CacheField = CacheField->Next;
459
460 Ptr = CacheField->Data;
461 }
462
463 *IntegerValue = (LONG)strtolW(Ptr, NULL, 0);
464
465 return INF_STATUS_SUCCESS;
466 }
467
468
469 INFSTATUS
470 InfpGetMultiSzField(PINFCONTEXT Context,
471 ULONG FieldIndex,
472 PWSTR ReturnBuffer,
473 ULONG ReturnBufferSize,
474 PULONG RequiredSize)
475 {
476 PINFCACHELINE CacheLine;
477 PINFCACHEFIELD CacheField;
478 PINFCACHEFIELD FieldPtr;
479 ULONG Index;
480 ULONG Size;
481 PWCHAR Ptr;
482
483 if (Context == NULL || Context->Line == NULL || FieldIndex == 0)
484 {
485 DPRINT("Invalid parameter\n");
486 return INF_STATUS_INVALID_PARAMETER;
487 }
488
489 if (RequiredSize != NULL)
490 *RequiredSize = 0;
491
492 CacheLine = (PINFCACHELINE)Context->Line;
493
494 if (FieldIndex > (ULONG)CacheLine->FieldCount)
495 return INF_STATUS_INVALID_PARAMETER;
496
497 CacheField = CacheLine->FirstField;
498 for (Index = 1; Index < FieldIndex; Index++)
499 CacheField = CacheField->Next;
500
501 /* Calculate the required buffer size */
502 FieldPtr = CacheField;
503 Size = 0;
504 while (FieldPtr != NULL)
505 {
506 Size += ((ULONG)strlenW(FieldPtr->Data) + 1);
507 FieldPtr = FieldPtr->Next;
508 }
509 Size++;
510
511 if (RequiredSize != NULL)
512 *RequiredSize = Size;
513
514 if (ReturnBuffer != NULL)
515 {
516 if (ReturnBufferSize < Size)
517 return INF_STATUS_BUFFER_OVERFLOW;
518
519 /* Copy multi-sz string */
520 Ptr = ReturnBuffer;
521 FieldPtr = CacheField;
522 while (FieldPtr != NULL)
523 {
524 Size = (ULONG)strlenW(FieldPtr->Data) + 1;
525
526 strcpyW(Ptr, FieldPtr->Data);
527
528 Ptr = Ptr + Size;
529 FieldPtr = FieldPtr->Next;
530 }
531 *Ptr = 0;
532 }
533
534 return INF_STATUS_SUCCESS;
535 }
536
537
538 INFSTATUS
539 InfpGetStringField(PINFCONTEXT Context,
540 ULONG FieldIndex,
541 PWSTR ReturnBuffer,
542 ULONG ReturnBufferSize,
543 PULONG RequiredSize)
544 {
545 PINFCACHELINE CacheLine;
546 PINFCACHEFIELD CacheField;
547 ULONG Index;
548 PWCHAR Ptr;
549 SIZE_T Size;
550
551 if (Context == NULL || Context->Line == NULL)
552 {
553 DPRINT("Invalid parameter\n");
554 return INF_STATUS_INVALID_PARAMETER;
555 }
556
557 if (RequiredSize != NULL)
558 *RequiredSize = 0;
559
560 CacheLine = (PINFCACHELINE)Context->Line;
561
562 if (FieldIndex > (ULONG)CacheLine->FieldCount)
563 return INF_STATUS_INVALID_PARAMETER;
564
565 if (FieldIndex == 0)
566 {
567 Ptr = CacheLine->Key;
568 }
569 else
570 {
571 CacheField = CacheLine->FirstField;
572 for (Index = 1; Index < FieldIndex; Index++)
573 CacheField = CacheField->Next;
574
575 Ptr = CacheField->Data;
576 }
577
578 // Size = (ULONG)strlenW(Ptr) + 1;
579 Size = InfpSubstituteString(Context->Inf,
580 Ptr,
581 NULL,
582 0);
583
584 if (RequiredSize != NULL)
585 *RequiredSize = Size + 1;
586
587 if (ReturnBuffer != NULL)
588 {
589 if (ReturnBufferSize <= Size)
590 return INF_STATUS_BUFFER_OVERFLOW;
591
592 // strcpyW(ReturnBuffer, Ptr);
593 InfpSubstituteString(Context->Inf,
594 Ptr,
595 ReturnBuffer,
596 ReturnBufferSize);
597 }
598
599 return INF_STATUS_SUCCESS;
600 }
601
602
603 INFSTATUS
604 InfpGetData(PINFCONTEXT Context,
605 PWCHAR *Key,
606 PWCHAR *Data)
607 {
608 PINFCACHELINE CacheKey;
609
610 if (Context == NULL || Context->Line == NULL || Data == NULL)
611 {
612 DPRINT("Invalid parameter\n");
613 return INF_STATUS_INVALID_PARAMETER;
614 }
615
616 CacheKey = (PINFCACHELINE)Context->Line;
617 if (Key != NULL)
618 *Key = CacheKey->Key;
619
620 if (Data != NULL)
621 {
622 if (CacheKey->FirstField == NULL)
623 {
624 *Data = NULL;
625 }
626 else
627 {
628 *Data = CacheKey->FirstField->Data;
629 }
630 }
631
632 return INF_STATUS_SUCCESS;
633 }
634
635
636 INFSTATUS
637 InfpGetDataField(PINFCONTEXT Context,
638 ULONG FieldIndex,
639 PWCHAR *Data)
640 {
641 PINFCACHELINE CacheLine;
642 PINFCACHEFIELD CacheField;
643 ULONG Index;
644
645 if (Context == NULL || Context->Line == NULL || Data == NULL)
646 {
647 DPRINT("Invalid parameter\n");
648 return INF_STATUS_INVALID_PARAMETER;
649 }
650
651 CacheLine = (PINFCACHELINE)Context->Line;
652
653 if (FieldIndex > (ULONG)CacheLine->FieldCount)
654 return INF_STATUS_INVALID_PARAMETER;
655
656 if (FieldIndex == 0)
657 {
658 *Data = CacheLine->Key;
659 }
660 else
661 {
662 CacheField = CacheLine->FirstField;
663 for (Index = 1; Index < FieldIndex; Index++)
664 CacheField = CacheField->Next;
665
666 *Data = CacheField->Data;
667 }
668
669 return INF_STATUS_SUCCESS;
670 }
671
672 VOID
673 InfpFreeContext(PINFCONTEXT Context)
674 {
675 FREE(Context);
676 }
677
678 /* EOF */