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