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