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