]> git.proxmox.com Git - mirror_edk2.git/blob - SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / SignedCapsulePkg / Library / IniParsingLib / IniParsingLib.c
1 /** @file
2 This library parses the INI configuration file.
3
4 The INI file format is:
5 ================
6 [SectionName]
7 EntryName=EntryValue
8 ================
9
10 Where:
11 1) SectionName is an ASCII string. The valid format is [A-Za-z0-9_]+
12 2) EntryName is an ASCII string. The valid format is [A-Za-z0-9_]+
13 3) EntryValue can be:
14 3.1) an ASCII String. The valid format is [A-Za-z0-9_]+
15 3.2) a GUID. The valid format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, where x is [A-Fa-f0-9]
16 3.3) a decimal value. The valid format is [0-9]+
17 3.4) a hexadecimal value. The valid format is 0x[A-Fa-f0-9]+
18 4) '#' or ';' can be used as comment at anywhere.
19 5) TAB(0x20) or SPACE(0x9) can be used as separator.
20 6) LF(\n, 0xA) or CR(\r, 0xD) can be used as line break.
21
22 Caution: This module requires additional review when modified.
23 This driver will have external input - INI data file.
24
25 OpenIniFile(), PreProcessDataFile(), ProfileGetSection(), ProfileGetEntry()
26 will receive untrusted input and do basic validation.
27
28 Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
29
30 SPDX-License-Identifier: BSD-2-Clause-Patent
31
32 **/
33
34 #include <Uefi.h>
35 #include <Library/BaseLib.h>
36 #include <Library/BaseMemoryLib.h>
37 #include <Library/DebugLib.h>
38 #include <Library/MemoryAllocationLib.h>
39
40 #define IS_HYPHEN(a) ((a) == '-')
41 #define IS_NULL(a) ((a) == '\0')
42
43 // This is default allocation. Reallocation will happen if it is not enough.
44 #define MAX_LINE_LENGTH 512
45
46 typedef struct _INI_SECTION_ITEM SECTION_ITEM;
47 struct _INI_SECTION_ITEM {
48 CHAR8 *PtrSection;
49 UINTN SecNameLen;
50 CHAR8 *PtrEntry;
51 CHAR8 *PtrValue;
52 SECTION_ITEM *PtrNext;
53 };
54
55 typedef struct _INI_COMMENT_LINE COMMENT_LINE;
56 struct _INI_COMMENT_LINE {
57 CHAR8 *PtrComment;
58 COMMENT_LINE *PtrNext;
59 };
60
61 typedef struct {
62 SECTION_ITEM *SectionHead;
63 COMMENT_LINE *CommentHead;
64 } INI_PARSING_LIB_CONTEXT;
65
66 /**
67 Return if the digital char is valid.
68
69 @param[in] DigitalChar The digital char to be checked.
70 @param[in] IncludeHex If it include HEX char.
71
72 @retval TRUE The digital char is valid.
73 @retval FALSE The digital char is invalid.
74 **/
75 BOOLEAN
76 IsValidDigitalChar (
77 IN CHAR8 DigitalChar,
78 IN BOOLEAN IncludeHex
79 )
80 {
81 if ((DigitalChar >= '0') && (DigitalChar <= '9')) {
82 return TRUE;
83 }
84
85 if (IncludeHex) {
86 if ((DigitalChar >= 'a') && (DigitalChar <= 'f')) {
87 return TRUE;
88 }
89
90 if ((DigitalChar >= 'A') && (DigitalChar <= 'F')) {
91 return TRUE;
92 }
93 }
94
95 return FALSE;
96 }
97
98 /**
99 Return if the name char is valid.
100
101 @param[in] NameChar The name char to be checked.
102
103 @retval TRUE The name char is valid.
104 @retval FALSE The name char is invalid.
105 **/
106 BOOLEAN
107 IsValidNameChar (
108 IN CHAR8 NameChar
109 )
110 {
111 if ((NameChar >= 'a') && (NameChar <= 'z')) {
112 return TRUE;
113 }
114
115 if ((NameChar >= 'A') && (NameChar <= 'Z')) {
116 return TRUE;
117 }
118
119 if ((NameChar >= '0') && (NameChar <= '9')) {
120 return TRUE;
121 }
122
123 if (NameChar == '_') {
124 return TRUE;
125 }
126
127 return FALSE;
128 }
129
130 /**
131 Return if the digital string is valid.
132
133 @param[in] Digital The digital to be checked.
134 @param[in] Length The length of digital string in bytes.
135 @param[in] IncludeHex If it include HEX char.
136
137 @retval TRUE The digital string is valid.
138 @retval FALSE The digital string is invalid.
139 **/
140 BOOLEAN
141 IsValidDigital (
142 IN CHAR8 *Digital,
143 IN UINTN Length,
144 IN BOOLEAN IncludeHex
145 )
146 {
147 UINTN Index;
148
149 for (Index = 0; Index < Length; Index++) {
150 if (!IsValidDigitalChar (Digital[Index], IncludeHex)) {
151 return FALSE;
152 }
153 }
154
155 return TRUE;
156 }
157
158 /**
159 Return if the decimal string is valid.
160
161 @param[in] Decimal The decimal string to be checked.
162 @param[in] Length The length of decimal string in bytes.
163
164 @retval TRUE The decimal string is valid.
165 @retval FALSE The decimal string is invalid.
166 **/
167 BOOLEAN
168 IsValidDecimalString (
169 IN CHAR8 *Decimal,
170 IN UINTN Length
171 )
172 {
173 return IsValidDigital (Decimal, Length, FALSE);
174 }
175
176 /**
177 Return if the hexadecimal string is valid.
178
179 @param[in] Hex The hexadecimal string to be checked.
180 @param[in] Length The length of hexadecimal string in bytes.
181
182 @retval TRUE The hexadecimal string is valid.
183 @retval FALSE The hexadecimal string is invalid.
184 **/
185 BOOLEAN
186 IsValidHexString (
187 IN CHAR8 *Hex,
188 IN UINTN Length
189 )
190 {
191 if (Length <= 2) {
192 return FALSE;
193 }
194
195 if (Hex[0] != '0') {
196 return FALSE;
197 }
198
199 if ((Hex[1] != 'x') && (Hex[1] != 'X')) {
200 return FALSE;
201 }
202
203 return IsValidDigital (&Hex[2], Length - 2, TRUE);
204 }
205
206 /**
207 Return if the name string is valid.
208
209 @param[in] Name The name to be checked.
210 @param[in] Length The length of name string in bytes.
211
212 @retval TRUE The name string is valid.
213 @retval FALSE The name string is invalid.
214 **/
215 BOOLEAN
216 IsValidName (
217 IN CHAR8 *Name,
218 IN UINTN Length
219 )
220 {
221 UINTN Index;
222
223 for (Index = 0; Index < Length; Index++) {
224 if (!IsValidNameChar (Name[Index])) {
225 return FALSE;
226 }
227 }
228
229 return TRUE;
230 }
231
232 /**
233 Return if the value string is valid GUID.
234
235 @param[in] Value The value to be checked.
236 @param[in] Length The length of value string in bytes.
237
238 @retval TRUE The value string is valid GUID.
239 @retval FALSE The value string is invalid GUID.
240 **/
241 BOOLEAN
242 IsValidGuid (
243 IN CHAR8 *Value,
244 IN UINTN Length
245 )
246 {
247 if (Length != sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") - 1) {
248 return FALSE;
249 }
250
251 if (!IS_HYPHEN (Value[8])) {
252 return FALSE;
253 }
254
255 if (!IS_HYPHEN (Value[13])) {
256 return FALSE;
257 }
258
259 if (!IS_HYPHEN (Value[18])) {
260 return FALSE;
261 }
262
263 if (!IS_HYPHEN (Value[23])) {
264 return FALSE;
265 }
266
267 if (!IsValidDigital (&Value[0], 8, TRUE)) {
268 return FALSE;
269 }
270
271 if (!IsValidDigital (&Value[9], 4, TRUE)) {
272 return FALSE;
273 }
274
275 if (!IsValidDigital (&Value[14], 4, TRUE)) {
276 return FALSE;
277 }
278
279 if (!IsValidDigital (&Value[19], 4, TRUE)) {
280 return FALSE;
281 }
282
283 if (!IsValidDigital (&Value[24], 12, TRUE)) {
284 return FALSE;
285 }
286
287 return TRUE;
288 }
289
290 /**
291 Return if the value string is valid.
292
293 @param[in] Value The value to be checked.
294 @param[in] Length The length of value string in bytes.
295
296 @retval TRUE The name string is valid.
297 @retval FALSE The name string is invalid.
298 **/
299 BOOLEAN
300 IsValidValue (
301 IN CHAR8 *Value,
302 IN UINTN Length
303 )
304 {
305 if (IsValidName (Value, Length) || IsValidGuid (Value, Length)) {
306 return TRUE;
307 }
308
309 return FALSE;
310 }
311
312 /**
313 Dump an INI config file context.
314
315 @param[in] Context INI Config file context.
316 **/
317 VOID
318 DumpIniSection (
319 IN VOID *Context
320 )
321 {
322 INI_PARSING_LIB_CONTEXT *IniContext;
323 SECTION_ITEM *PtrSection;
324 SECTION_ITEM *Section;
325
326 if (Context == NULL) {
327 return;
328 }
329
330 IniContext = Context;
331 Section = IniContext->SectionHead;
332
333 while (Section != NULL) {
334 PtrSection = Section;
335 Section = Section->PtrNext;
336 if (PtrSection->PtrSection != NULL) {
337 DEBUG ((DEBUG_VERBOSE, "Section - %a\n", PtrSection->PtrSection));
338 }
339
340 if (PtrSection->PtrEntry != NULL) {
341 DEBUG ((DEBUG_VERBOSE, " Entry - %a\n", PtrSection->PtrEntry));
342 }
343
344 if (PtrSection->PtrValue != NULL) {
345 DEBUG ((DEBUG_VERBOSE, " Value - %a\n", PtrSection->PtrValue));
346 }
347 }
348 }
349
350 /**
351 Copy one line data from buffer data to the line buffer.
352
353 @param[in] Buffer Buffer data.
354 @param[in] BufferSize Buffer Size.
355 @param[in, out] LineBuffer Line buffer to store the found line data.
356 @param[in, out] LineSize On input, size of the input line buffer.
357 On output, size of the actual line buffer.
358
359 @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough.
360 @retval EFI_SUCCESS Copy line data into the line buffer.
361
362 **/
363 EFI_STATUS
364 ProfileGetLine (
365 IN UINT8 *Buffer,
366 IN UINTN BufferSize,
367 IN OUT UINT8 *LineBuffer,
368 IN OUT UINTN *LineSize
369 )
370 {
371 UINTN Length;
372 UINT8 *PtrBuf;
373 UINTN PtrEnd;
374
375 PtrBuf = Buffer;
376 PtrEnd = (UINTN)Buffer + BufferSize;
377
378 //
379 // 0x0D indicates a line break. Otherwise there is no line break
380 //
381 while ((UINTN)PtrBuf < PtrEnd) {
382 if ((*PtrBuf == 0x0D) || (*PtrBuf == 0x0A)) {
383 break;
384 }
385
386 PtrBuf++;
387 }
388
389 if ((UINTN)PtrBuf >= (PtrEnd - 1)) {
390 //
391 // The buffer ends without any line break
392 // or it is the last character of the buffer
393 //
394 Length = BufferSize;
395 } else if (*(PtrBuf + 1) == 0x0A) {
396 //
397 // Further check if a 0x0A follows. If yes, count 0xA
398 //
399 Length = (UINTN)PtrBuf - (UINTN)Buffer + 2;
400 } else {
401 Length = (UINTN)PtrBuf - (UINTN)Buffer + 1;
402 }
403
404 if (Length > (*LineSize)) {
405 *LineSize = Length;
406 return EFI_BUFFER_TOO_SMALL;
407 }
408
409 SetMem (LineBuffer, *LineSize, 0x0);
410 *LineSize = Length;
411 CopyMem (LineBuffer, Buffer, Length);
412
413 return EFI_SUCCESS;
414 }
415
416 /**
417 Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
418
419 @param[in, out] Buffer On input, buffer data to be trimmed.
420 On output, the trimmed buffer.
421 @param[in, out] BufferSize On input, size of original buffer data.
422 On output, size of the trimmed buffer.
423
424 **/
425 VOID
426 ProfileTrim (
427 IN OUT UINT8 *Buffer,
428 IN OUT UINTN *BufferSize
429 )
430 {
431 UINTN Length;
432 UINT8 *PtrBuf;
433 UINT8 *PtrEnd;
434
435 if (*BufferSize == 0) {
436 return;
437 }
438
439 //
440 // Trim the tail first, include CR, LF, TAB, and SPACE.
441 //
442 Length = *BufferSize;
443 PtrBuf = (UINT8 *)((UINTN)Buffer + Length - 1);
444 while (PtrBuf >= Buffer) {
445 if ( (*PtrBuf != 0x0D) && (*PtrBuf != 0x0A)
446 && (*PtrBuf != 0x20) && (*PtrBuf != 0x09))
447 {
448 break;
449 }
450
451 PtrBuf--;
452 }
453
454 //
455 // all spaces, a blank line, return directly;
456 //
457 if (PtrBuf < Buffer) {
458 *BufferSize = 0;
459 return;
460 }
461
462 Length = (UINTN)PtrBuf - (UINTN)Buffer + 1;
463 PtrEnd = PtrBuf;
464 PtrBuf = Buffer;
465
466 //
467 // Now skip the heading CR, LF, TAB and SPACE
468 //
469 while (PtrBuf <= PtrEnd) {
470 if ( (*PtrBuf != 0x0D) && (*PtrBuf != 0x0A)
471 && (*PtrBuf != 0x20) && (*PtrBuf != 0x09))
472 {
473 break;
474 }
475
476 PtrBuf++;
477 }
478
479 //
480 // If no heading CR, LF, TAB or SPACE, directly return
481 //
482 if (PtrBuf == Buffer) {
483 *BufferSize = Length;
484 return;
485 }
486
487 *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;
488
489 //
490 // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
491 // Now move out all these characters.
492 //
493 while (PtrBuf <= PtrEnd) {
494 *Buffer = *PtrBuf;
495 Buffer++;
496 PtrBuf++;
497 }
498
499 return;
500 }
501
502 /**
503 Insert new comment item into comment head.
504
505 @param[in] Buffer Comment buffer to be added.
506 @param[in] BufferSize Size of comment buffer.
507 @param[in, out] CommentHead Comment Item head entry.
508
509 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
510 @retval EFI_SUCCESS New comment item is inserted.
511
512 **/
513 EFI_STATUS
514 ProfileGetComments (
515 IN UINT8 *Buffer,
516 IN UINTN BufferSize,
517 IN OUT COMMENT_LINE **CommentHead
518 )
519 {
520 COMMENT_LINE *CommentItem;
521
522 CommentItem = NULL;
523 CommentItem = AllocatePool (sizeof (COMMENT_LINE));
524 if (CommentItem == NULL) {
525 return EFI_OUT_OF_RESOURCES;
526 }
527
528 CommentItem->PtrNext = *CommentHead;
529 *CommentHead = CommentItem;
530
531 //
532 // Add a trailing '\0'
533 //
534 CommentItem->PtrComment = AllocatePool (BufferSize + 1);
535 if (CommentItem->PtrComment == NULL) {
536 FreePool (CommentItem);
537 return EFI_OUT_OF_RESOURCES;
538 }
539
540 CopyMem (CommentItem->PtrComment, Buffer, BufferSize);
541 *(CommentItem->PtrComment + BufferSize) = '\0';
542
543 return EFI_SUCCESS;
544 }
545
546 /**
547 Add new section item into Section head.
548
549 @param[in] Buffer Section item data buffer.
550 @param[in] BufferSize Size of section item.
551 @param[in, out] SectionHead Section item head entry.
552
553 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
554 @retval EFI_SUCCESS Section item is NULL or Section item is added.
555
556 **/
557 EFI_STATUS
558 ProfileGetSection (
559 IN UINT8 *Buffer,
560 IN UINTN BufferSize,
561 IN OUT SECTION_ITEM **SectionHead
562 )
563 {
564 SECTION_ITEM *SectionItem;
565 UINTN Length;
566 UINT8 *PtrBuf;
567 UINT8 *PtrEnd;
568
569 ASSERT (BufferSize >= 1);
570 //
571 // The first character of Buffer is '[', now we want for ']'
572 //
573 PtrEnd = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
574 PtrBuf = (UINT8 *)((UINTN)Buffer + 1);
575 while (PtrBuf <= PtrEnd) {
576 if (*PtrBuf == ']') {
577 break;
578 }
579
580 PtrBuf++;
581 }
582
583 if (PtrBuf > PtrEnd) {
584 //
585 // Not found. Invalid line
586 //
587 return EFI_NOT_FOUND;
588 }
589
590 if (PtrBuf <= Buffer + 1) {
591 // Empty name
592 return EFI_NOT_FOUND;
593 }
594
595 //
596 // excluding the heading '[' and tailing ']'
597 //
598 Length = PtrBuf - Buffer - 1;
599 ProfileTrim (
600 Buffer + 1,
601 &Length
602 );
603
604 //
605 // Invalid line if the section name is null
606 //
607 if (Length == 0) {
608 return EFI_NOT_FOUND;
609 }
610
611 if (!IsValidName ((CHAR8 *)Buffer + 1, Length)) {
612 return EFI_INVALID_PARAMETER;
613 }
614
615 SectionItem = AllocatePool (sizeof (SECTION_ITEM));
616 if (SectionItem == NULL) {
617 return EFI_OUT_OF_RESOURCES;
618 }
619
620 SectionItem->PtrSection = NULL;
621 SectionItem->SecNameLen = Length;
622 SectionItem->PtrEntry = NULL;
623 SectionItem->PtrValue = NULL;
624 SectionItem->PtrNext = *SectionHead;
625 *SectionHead = SectionItem;
626
627 //
628 // Add a trailing '\0'
629 //
630 SectionItem->PtrSection = AllocatePool (Length + 1);
631 if (SectionItem->PtrSection == NULL) {
632 return EFI_OUT_OF_RESOURCES;
633 }
634
635 //
636 // excluding the heading '['
637 //
638 CopyMem (SectionItem->PtrSection, Buffer + 1, Length);
639 *(SectionItem->PtrSection + Length) = '\0';
640
641 return EFI_SUCCESS;
642 }
643
644 /**
645 Add new section entry and entry value into Section head.
646
647 @param[in] Buffer Section entry data buffer.
648 @param[in] BufferSize Size of section entry.
649 @param[in, out] SectionHead Section item head entry.
650
651 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
652 @retval EFI_SUCCESS Section entry is added.
653 @retval EFI_NOT_FOUND Section entry is not found.
654 @retval EFI_INVALID_PARAMETER Section entry is invalid.
655
656 **/
657 EFI_STATUS
658 ProfileGetEntry (
659 IN UINT8 *Buffer,
660 IN UINTN BufferSize,
661 IN OUT SECTION_ITEM **SectionHead
662 )
663 {
664 EFI_STATUS Status;
665 SECTION_ITEM *SectionItem;
666 SECTION_ITEM *PtrSection;
667 UINTN Length;
668 UINT8 *PtrBuf;
669 UINT8 *PtrEnd;
670
671 Status = EFI_SUCCESS;
672 PtrBuf = Buffer;
673 PtrEnd = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
674
675 //
676 // First search for '='
677 //
678 while (PtrBuf <= PtrEnd) {
679 if (*PtrBuf == '=') {
680 break;
681 }
682
683 PtrBuf++;
684 }
685
686 if (PtrBuf > PtrEnd) {
687 //
688 // Not found. Invalid line
689 //
690 return EFI_NOT_FOUND;
691 }
692
693 if (PtrBuf <= Buffer) {
694 // Empty name
695 return EFI_NOT_FOUND;
696 }
697
698 //
699 // excluding the tailing '='
700 //
701 Length = PtrBuf - Buffer;
702 ProfileTrim (
703 Buffer,
704 &Length
705 );
706
707 //
708 // Invalid line if the entry name is null
709 //
710 if (Length == 0) {
711 return EFI_NOT_FOUND;
712 }
713
714 if (!IsValidName ((CHAR8 *)Buffer, Length)) {
715 return EFI_INVALID_PARAMETER;
716 }
717
718 //
719 // Omit this line if no section header has been found before
720 //
721 if (*SectionHead == NULL) {
722 return Status;
723 }
724
725 PtrSection = *SectionHead;
726
727 SectionItem = AllocatePool (sizeof (SECTION_ITEM));
728 if (SectionItem == NULL) {
729 return EFI_OUT_OF_RESOURCES;
730 }
731
732 SectionItem->PtrSection = NULL;
733 SectionItem->PtrEntry = NULL;
734 SectionItem->PtrValue = NULL;
735 SectionItem->SecNameLen = PtrSection->SecNameLen;
736 SectionItem->PtrNext = *SectionHead;
737 *SectionHead = SectionItem;
738
739 //
740 // SectionName, add a trailing '\0'
741 //
742 SectionItem->PtrSection = AllocatePool (PtrSection->SecNameLen + 1);
743 if (SectionItem->PtrSection == NULL) {
744 return EFI_OUT_OF_RESOURCES;
745 }
746
747 CopyMem (SectionItem->PtrSection, PtrSection->PtrSection, PtrSection->SecNameLen + 1);
748
749 //
750 // EntryName, add a trailing '\0'
751 //
752 SectionItem->PtrEntry = AllocatePool (Length + 1);
753 if (SectionItem->PtrEntry == NULL) {
754 FreePool (SectionItem->PtrSection);
755 return EFI_OUT_OF_RESOURCES;
756 }
757
758 CopyMem (SectionItem->PtrEntry, Buffer, Length);
759 *(SectionItem->PtrEntry + Length) = '\0';
760
761 //
762 // Next search for '#' or ';'
763 //
764 PtrBuf = PtrBuf + 1;
765 Buffer = PtrBuf;
766 while (PtrBuf <= PtrEnd) {
767 if ((*PtrBuf == '#') || (*PtrBuf == ';')) {
768 break;
769 }
770
771 PtrBuf++;
772 }
773
774 if (PtrBuf <= Buffer) {
775 // Empty name
776 FreePool (SectionItem->PtrEntry);
777 FreePool (SectionItem->PtrSection);
778 return EFI_NOT_FOUND;
779 }
780
781 Length = PtrBuf - Buffer;
782 ProfileTrim (
783 Buffer,
784 &Length
785 );
786
787 //
788 // Invalid line if the entry value is null
789 //
790 if (Length == 0) {
791 FreePool (SectionItem->PtrEntry);
792 FreePool (SectionItem->PtrSection);
793 return EFI_NOT_FOUND;
794 }
795
796 if (!IsValidValue ((CHAR8 *)Buffer, Length)) {
797 FreePool (SectionItem->PtrEntry);
798 FreePool (SectionItem->PtrSection);
799 return EFI_INVALID_PARAMETER;
800 }
801
802 //
803 // EntryValue, add a trailing '\0'
804 //
805 SectionItem->PtrValue = AllocatePool (Length + 1);
806 if (SectionItem->PtrValue == NULL) {
807 FreePool (SectionItem->PtrEntry);
808 FreePool (SectionItem->PtrSection);
809 return EFI_OUT_OF_RESOURCES;
810 }
811
812 CopyMem (SectionItem->PtrValue, Buffer, Length);
813 *(SectionItem->PtrValue + Length) = '\0';
814
815 return EFI_SUCCESS;
816 }
817
818 /**
819 Free all comment entry and section entry.
820
821 @param[in] Section Section entry list.
822 @param[in] Comment Comment entry list.
823
824 **/
825 VOID
826 FreeAllList (
827 IN SECTION_ITEM *Section,
828 IN COMMENT_LINE *Comment
829 )
830 {
831 SECTION_ITEM *PtrSection;
832 COMMENT_LINE *PtrComment;
833
834 while (Section != NULL) {
835 PtrSection = Section;
836 Section = Section->PtrNext;
837 if (PtrSection->PtrEntry != NULL) {
838 FreePool (PtrSection->PtrEntry);
839 }
840
841 if (PtrSection->PtrSection != NULL) {
842 FreePool (PtrSection->PtrSection);
843 }
844
845 if (PtrSection->PtrValue != NULL) {
846 FreePool (PtrSection->PtrValue);
847 }
848
849 FreePool (PtrSection);
850 }
851
852 while (Comment != NULL) {
853 PtrComment = Comment;
854 Comment = Comment->PtrNext;
855 if (PtrComment->PtrComment != NULL) {
856 FreePool (PtrComment->PtrComment);
857 }
858
859 FreePool (PtrComment);
860 }
861
862 return;
863 }
864
865 /**
866 Get section entry value.
867
868 @param[in] Section Section entry list.
869 @param[in] SectionName Section name.
870 @param[in] EntryName Section entry name.
871 @param[out] EntryValue Point to the got entry value.
872
873 @retval EFI_NOT_FOUND Section is not found.
874 @retval EFI_SUCCESS Section entry value is got.
875
876 **/
877 EFI_STATUS
878 UpdateGetProfileString (
879 IN SECTION_ITEM *Section,
880 IN CHAR8 *SectionName,
881 IN CHAR8 *EntryName,
882 OUT CHAR8 **EntryValue
883 )
884 {
885 *EntryValue = NULL;
886
887 while (Section != NULL) {
888 if (AsciiStrCmp ((CONST CHAR8 *)Section->PtrSection, (CONST CHAR8 *)SectionName) == 0) {
889 if (Section->PtrEntry != NULL) {
890 if (AsciiStrCmp ((CONST CHAR8 *)Section->PtrEntry, (CONST CHAR8 *)EntryName) == 0) {
891 break;
892 }
893 }
894 }
895
896 Section = Section->PtrNext;
897 }
898
899 if (Section == NULL) {
900 return EFI_NOT_FOUND;
901 }
902
903 *EntryValue = Section->PtrValue;
904
905 return EFI_SUCCESS;
906 }
907
908 /**
909 Pre process config data buffer into Section entry list and Comment entry list.
910
911 @param[in] DataBuffer Config raw file buffer.
912 @param[in] BufferSize Size of raw buffer.
913 @param[in, out] SectionHead Pointer to the section entry list.
914 @param[in, out] CommentHead Pointer to the comment entry list.
915
916 @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
917 @retval EFI_SUCCESS Config data buffer is preprocessed.
918 @retval EFI_NOT_FOUND Config data buffer is invalid, because Section or Entry is not found.
919 @retval EFI_INVALID_PARAMETER Config data buffer is invalid, because Section or Entry is invalid.
920
921 **/
922 EFI_STATUS
923 PreProcessDataFile (
924 IN UINT8 *DataBuffer,
925 IN UINTN BufferSize,
926 IN OUT SECTION_ITEM **SectionHead,
927 IN OUT COMMENT_LINE **CommentHead
928 )
929 {
930 EFI_STATUS Status;
931 CHAR8 *Source;
932 CHAR8 *CurrentPtr;
933 CHAR8 *BufferEnd;
934 CHAR8 *PtrLine;
935 UINTN LineLength;
936 UINTN SourceLength;
937 UINTN MaxLineLength;
938
939 *SectionHead = NULL;
940 *CommentHead = NULL;
941 BufferEnd = (CHAR8 *)((UINTN)DataBuffer + BufferSize);
942 CurrentPtr = (CHAR8 *)DataBuffer;
943 MaxLineLength = MAX_LINE_LENGTH;
944 Status = EFI_SUCCESS;
945
946 PtrLine = AllocatePool (MaxLineLength);
947 if (PtrLine == NULL) {
948 return EFI_OUT_OF_RESOURCES;
949 }
950
951 while (CurrentPtr < BufferEnd) {
952 Source = CurrentPtr;
953 SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr;
954 LineLength = MaxLineLength;
955 //
956 // With the assumption that line length is less than 512
957 // characters. Otherwise BUFFER_TOO_SMALL will be returned.
958 //
959 Status = ProfileGetLine (
960 (UINT8 *)Source,
961 SourceLength,
962 (UINT8 *)PtrLine,
963 &LineLength
964 );
965 if (EFI_ERROR (Status)) {
966 if (Status == EFI_BUFFER_TOO_SMALL) {
967 //
968 // If buffer too small, re-allocate the buffer according
969 // to the returned LineLength and try again.
970 //
971 FreePool (PtrLine);
972 PtrLine = NULL;
973 PtrLine = AllocatePool (LineLength);
974 if (PtrLine == NULL) {
975 Status = EFI_OUT_OF_RESOURCES;
976 break;
977 }
978
979 SourceLength = LineLength;
980 Status = ProfileGetLine (
981 (UINT8 *)Source,
982 SourceLength,
983 (UINT8 *)PtrLine,
984 &LineLength
985 );
986 if (EFI_ERROR (Status)) {
987 break;
988 }
989
990 MaxLineLength = LineLength;
991 } else {
992 break;
993 }
994 }
995
996 CurrentPtr = (CHAR8 *)((UINTN)CurrentPtr + LineLength);
997
998 //
999 // Line got. Trim the line before processing it.
1000 //
1001 ProfileTrim (
1002 (UINT8 *)PtrLine,
1003 &LineLength
1004 );
1005
1006 //
1007 // Blank line
1008 //
1009 if (LineLength == 0) {
1010 continue;
1011 }
1012
1013 if ((PtrLine[0] == '#') || (PtrLine[0] == ';')) {
1014 Status = ProfileGetComments (
1015 (UINT8 *)PtrLine,
1016 LineLength,
1017 CommentHead
1018 );
1019 } else if (PtrLine[0] == '[') {
1020 Status = ProfileGetSection (
1021 (UINT8 *)PtrLine,
1022 LineLength,
1023 SectionHead
1024 );
1025 } else {
1026 Status = ProfileGetEntry (
1027 (UINT8 *)PtrLine,
1028 LineLength,
1029 SectionHead
1030 );
1031 }
1032
1033 if (EFI_ERROR (Status)) {
1034 break;
1035 }
1036 }
1037
1038 //
1039 // Free buffer
1040 //
1041 FreePool (PtrLine);
1042
1043 return Status;
1044 }
1045
1046 /**
1047 Open an INI config file and return a context.
1048
1049 @param[in] DataBuffer Config raw file buffer.
1050 @param[in] BufferSize Size of raw buffer.
1051
1052 @return Config data buffer is opened and context is returned.
1053 @retval NULL No enough memory is allocated.
1054 @retval NULL Config data buffer is invalid.
1055 **/
1056 VOID *
1057 EFIAPI
1058 OpenIniFile (
1059 IN UINT8 *DataBuffer,
1060 IN UINTN BufferSize
1061 )
1062 {
1063 EFI_STATUS Status;
1064 INI_PARSING_LIB_CONTEXT *IniContext;
1065
1066 if ((DataBuffer == NULL) || (BufferSize == 0)) {
1067 return NULL;
1068 }
1069
1070 IniContext = AllocateZeroPool (sizeof (INI_PARSING_LIB_CONTEXT));
1071 if (IniContext == NULL) {
1072 return NULL;
1073 }
1074
1075 //
1076 // First process the data buffer and get all sections and entries
1077 //
1078 Status = PreProcessDataFile (
1079 DataBuffer,
1080 BufferSize,
1081 &IniContext->SectionHead,
1082 &IniContext->CommentHead
1083 );
1084 if (EFI_ERROR (Status)) {
1085 FreePool (IniContext);
1086 return NULL;
1087 }
1088
1089 DEBUG_CODE_BEGIN ();
1090 DumpIniSection (IniContext);
1091 DEBUG_CODE_END ();
1092 return IniContext;
1093 }
1094
1095 /**
1096 Get section entry string value.
1097
1098 @param[in] Context INI Config file context.
1099 @param[in] SectionName Section name.
1100 @param[in] EntryName Section entry name.
1101 @param[out] EntryValue Point to the got entry string value.
1102
1103 @retval EFI_SUCCESS Section entry string value is got.
1104 @retval EFI_NOT_FOUND Section is not found.
1105 **/
1106 EFI_STATUS
1107 EFIAPI
1108 GetStringFromDataFile (
1109 IN VOID *Context,
1110 IN CHAR8 *SectionName,
1111 IN CHAR8 *EntryName,
1112 OUT CHAR8 **EntryValue
1113 )
1114 {
1115 INI_PARSING_LIB_CONTEXT *IniContext;
1116 EFI_STATUS Status;
1117
1118 if ((Context == NULL) || (SectionName == NULL) || (EntryName == NULL) || (EntryValue == NULL)) {
1119 return EFI_INVALID_PARAMETER;
1120 }
1121
1122 IniContext = Context;
1123
1124 *EntryValue = NULL;
1125 Status = UpdateGetProfileString (
1126 IniContext->SectionHead,
1127 SectionName,
1128 EntryName,
1129 EntryValue
1130 );
1131 return Status;
1132 }
1133
1134 /**
1135 Get section entry GUID value.
1136
1137 @param[in] Context INI Config file context.
1138 @param[in] SectionName Section name.
1139 @param[in] EntryName Section entry name.
1140 @param[out] Guid Point to the got GUID value.
1141
1142 @retval EFI_SUCCESS Section entry GUID value is got.
1143 @retval EFI_NOT_FOUND Section is not found.
1144 **/
1145 EFI_STATUS
1146 EFIAPI
1147 GetGuidFromDataFile (
1148 IN VOID *Context,
1149 IN CHAR8 *SectionName,
1150 IN CHAR8 *EntryName,
1151 OUT EFI_GUID *Guid
1152 )
1153 {
1154 CHAR8 *Value;
1155 EFI_STATUS Status;
1156 RETURN_STATUS RStatus;
1157
1158 if ((Context == NULL) || (SectionName == NULL) || (EntryName == NULL) || (Guid == NULL)) {
1159 return EFI_INVALID_PARAMETER;
1160 }
1161
1162 Status = GetStringFromDataFile (
1163 Context,
1164 SectionName,
1165 EntryName,
1166 &Value
1167 );
1168 if (EFI_ERROR (Status)) {
1169 return EFI_NOT_FOUND;
1170 }
1171
1172 ASSERT (Value != NULL);
1173 RStatus = AsciiStrToGuid (Value, Guid);
1174 if (RETURN_ERROR (RStatus) || (Value[GUID_STRING_LENGTH] != '\0')) {
1175 return EFI_NOT_FOUND;
1176 }
1177
1178 return EFI_SUCCESS;
1179 }
1180
1181 /**
1182 Get section entry decimal UINTN value.
1183
1184 @param[in] Context INI Config file context.
1185 @param[in] SectionName Section name.
1186 @param[in] EntryName Section entry name.
1187 @param[out] Data Point to the got decimal UINTN value.
1188
1189 @retval EFI_SUCCESS Section entry decimal UINTN value is got.
1190 @retval EFI_NOT_FOUND Section is not found.
1191 **/
1192 EFI_STATUS
1193 EFIAPI
1194 GetDecimalUintnFromDataFile (
1195 IN VOID *Context,
1196 IN CHAR8 *SectionName,
1197 IN CHAR8 *EntryName,
1198 OUT UINTN *Data
1199 )
1200 {
1201 CHAR8 *Value;
1202 EFI_STATUS Status;
1203
1204 if ((Context == NULL) || (SectionName == NULL) || (EntryName == NULL) || (Data == NULL)) {
1205 return EFI_INVALID_PARAMETER;
1206 }
1207
1208 Status = GetStringFromDataFile (
1209 Context,
1210 SectionName,
1211 EntryName,
1212 &Value
1213 );
1214 if (EFI_ERROR (Status)) {
1215 return EFI_NOT_FOUND;
1216 }
1217
1218 ASSERT (Value != NULL);
1219 if (!IsValidDecimalString (Value, AsciiStrLen (Value))) {
1220 return EFI_NOT_FOUND;
1221 }
1222
1223 *Data = AsciiStrDecimalToUintn (Value);
1224 return EFI_SUCCESS;
1225 }
1226
1227 /**
1228 Get section entry hexadecimal UINTN value.
1229
1230 @param[in] Context INI Config file context.
1231 @param[in] SectionName Section name.
1232 @param[in] EntryName Section entry name.
1233 @param[out] Data Point to the got hexadecimal UINTN value.
1234
1235 @retval EFI_SUCCESS Section entry hexadecimal UINTN value is got.
1236 @retval EFI_NOT_FOUND Section is not found.
1237 **/
1238 EFI_STATUS
1239 EFIAPI
1240 GetHexUintnFromDataFile (
1241 IN VOID *Context,
1242 IN CHAR8 *SectionName,
1243 IN CHAR8 *EntryName,
1244 OUT UINTN *Data
1245 )
1246 {
1247 CHAR8 *Value;
1248 EFI_STATUS Status;
1249
1250 if ((Context == NULL) || (SectionName == NULL) || (EntryName == NULL) || (Data == NULL)) {
1251 return EFI_INVALID_PARAMETER;
1252 }
1253
1254 Status = GetStringFromDataFile (
1255 Context,
1256 SectionName,
1257 EntryName,
1258 &Value
1259 );
1260 if (EFI_ERROR (Status)) {
1261 return EFI_NOT_FOUND;
1262 }
1263
1264 ASSERT (Value != NULL);
1265 if (!IsValidHexString (Value, AsciiStrLen (Value))) {
1266 return EFI_NOT_FOUND;
1267 }
1268
1269 *Data = AsciiStrHexToUintn (Value);
1270 return EFI_SUCCESS;
1271 }
1272
1273 /**
1274 Get section entry hexadecimal UINT64 value.
1275
1276 @param[in] Context INI Config file context.
1277 @param[in] SectionName Section name.
1278 @param[in] EntryName Section entry name.
1279 @param[out] Data Point to the got hexadecimal UINT64 value.
1280
1281 @retval EFI_SUCCESS Section entry hexadecimal UINT64 value is got.
1282 @retval EFI_NOT_FOUND Section is not found.
1283 **/
1284 EFI_STATUS
1285 EFIAPI
1286 GetHexUint64FromDataFile (
1287 IN VOID *Context,
1288 IN CHAR8 *SectionName,
1289 IN CHAR8 *EntryName,
1290 OUT UINT64 *Data
1291 )
1292 {
1293 CHAR8 *Value;
1294 EFI_STATUS Status;
1295
1296 if ((Context == NULL) || (SectionName == NULL) || (EntryName == NULL) || (Data == NULL)) {
1297 return EFI_INVALID_PARAMETER;
1298 }
1299
1300 Status = GetStringFromDataFile (
1301 Context,
1302 SectionName,
1303 EntryName,
1304 &Value
1305 );
1306 if (EFI_ERROR (Status)) {
1307 return EFI_NOT_FOUND;
1308 }
1309
1310 ASSERT (Value != NULL);
1311 if (!IsValidHexString (Value, AsciiStrLen (Value))) {
1312 return EFI_NOT_FOUND;
1313 }
1314
1315 *Data = AsciiStrHexToUint64 (Value);
1316 return EFI_SUCCESS;
1317 }
1318
1319 /**
1320 Close an INI config file and free the context.
1321
1322 @param[in] Context INI Config file context.
1323 **/
1324 VOID
1325 EFIAPI
1326 CloseIniFile (
1327 IN VOID *Context
1328 )
1329 {
1330 INI_PARSING_LIB_CONTEXT *IniContext;
1331
1332 if (Context == NULL) {
1333 return;
1334 }
1335
1336 IniContext = Context;
1337 FreeAllList (IniContext->SectionHead, IniContext->CommentHead);
1338
1339 return;
1340 }