aboutsummaryrefslogtreecommitdiffstats
path: root/roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
diff options
context:
space:
mode:
authorAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
committerAngelos Mouzakitis <a.mouzakitis@virtualopensystems.com>2023-10-10 14:33:42 +0000
commitaf1a266670d040d2f4083ff309d732d648afba2a (patch)
tree2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
parente02cda008591317b1625707ff8e115a4841aa889 (diff)
Add submodule dependency filesHEADmaster
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c')
-rw-r--r--roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c b/roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
new file mode 100644
index 000000000..bea45e0d3
--- /dev/null
+++ b/roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
@@ -0,0 +1,1277 @@
+/** @file
+ This library parses the INI configuration file.
+
+ The INI file format is:
+ ================
+ [SectionName]
+ EntryName=EntryValue
+ ================
+
+ Where:
+ 1) SectionName is an ASCII string. The valid format is [A-Za-z0-9_]+
+ 2) EntryName is an ASCII string. The valid format is [A-Za-z0-9_]+
+ 3) EntryValue can be:
+ 3.1) an ASCII String. The valid format is [A-Za-z0-9_]+
+ 3.2) a GUID. The valid format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, where x is [A-Fa-f0-9]
+ 3.3) a decimal value. The valid format is [0-9]+
+ 3.4) a hexadecimal value. The valid format is 0x[A-Fa-f0-9]+
+ 4) '#' or ';' can be used as comment at anywhere.
+ 5) TAB(0x20) or SPACE(0x9) can be used as separator.
+ 6) LF(\n, 0xA) or CR(\r, 0xD) can be used as line break.
+
+ Caution: This module requires additional review when modified.
+ This driver will have external input - INI data file.
+
+ OpenIniFile(), PreProcessDataFile(), ProfileGetSection(), ProfileGetEntry()
+ will receive untrusted input and do basic validation.
+
+ Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#define IS_HYPHEN(a) ((a) == '-')
+#define IS_NULL(a) ((a) == '\0')
+
+// This is default allocation. Reallocation will happen if it is not enough.
+#define MAX_LINE_LENGTH 512
+
+typedef struct _INI_SECTION_ITEM SECTION_ITEM;
+struct _INI_SECTION_ITEM {
+ CHAR8 *PtrSection;
+ UINTN SecNameLen;
+ CHAR8 *PtrEntry;
+ CHAR8 *PtrValue;
+ SECTION_ITEM *PtrNext;
+};
+
+typedef struct _INI_COMMENT_LINE COMMENT_LINE;
+struct _INI_COMMENT_LINE {
+ CHAR8 *PtrComment;
+ COMMENT_LINE *PtrNext;
+};
+
+typedef struct {
+ SECTION_ITEM *SectionHead;
+ COMMENT_LINE *CommentHead;
+} INI_PARSING_LIB_CONTEXT;
+
+/**
+ Return if the digital char is valid.
+
+ @param[in] DigitalChar The digital char to be checked.
+ @param[in] IncludeHex If it include HEX char.
+
+ @retval TRUE The digital char is valid.
+ @retval FALSE The digital char is invalid.
+**/
+BOOLEAN
+IsValidDigitalChar (
+ IN CHAR8 DigitalChar,
+ IN BOOLEAN IncludeHex
+ )
+{
+ if (DigitalChar >= '0' && DigitalChar <= '9') {
+ return TRUE;
+ }
+ if (IncludeHex) {
+ if (DigitalChar >= 'a' && DigitalChar <= 'f') {
+ return TRUE;
+ }
+ if (DigitalChar >= 'A' && DigitalChar <= 'F') {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Return if the name char is valid.
+
+ @param[in] NameChar The name char to be checked.
+
+ @retval TRUE The name char is valid.
+ @retval FALSE The name char is invalid.
+**/
+BOOLEAN
+IsValidNameChar (
+ IN CHAR8 NameChar
+ )
+{
+ if (NameChar >= 'a' && NameChar <= 'z') {
+ return TRUE;
+ }
+ if (NameChar >= 'A' && NameChar <= 'Z') {
+ return TRUE;
+ }
+ if (NameChar >= '0' && NameChar <= '9') {
+ return TRUE;
+ }
+ if (NameChar == '_') {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Return if the digital string is valid.
+
+ @param[in] Digital The digital to be checked.
+ @param[in] Length The length of digital string in bytes.
+ @param[in] IncludeHex If it include HEX char.
+
+ @retval TRUE The digital string is valid.
+ @retval FALSE The digital string is invalid.
+**/
+BOOLEAN
+IsValidDigital (
+ IN CHAR8 *Digital,
+ IN UINTN Length,
+ IN BOOLEAN IncludeHex
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Length; Index++) {
+ if (!IsValidDigitalChar(Digital[Index], IncludeHex)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Return if the decimal string is valid.
+
+ @param[in] Decimal The decimal string to be checked.
+ @param[in] Length The length of decimal string in bytes.
+
+ @retval TRUE The decimal string is valid.
+ @retval FALSE The decimal string is invalid.
+**/
+BOOLEAN
+IsValidDecimalString (
+ IN CHAR8 *Decimal,
+ IN UINTN Length
+ )
+{
+ return IsValidDigital(Decimal, Length, FALSE);
+}
+
+/**
+ Return if the hexadecimal string is valid.
+
+ @param[in] Hex The hexadecimal string to be checked.
+ @param[in] Length The length of hexadecimal string in bytes.
+
+ @retval TRUE The hexadecimal string is valid.
+ @retval FALSE The hexadecimal string is invalid.
+**/
+BOOLEAN
+IsValidHexString (
+ IN CHAR8 *Hex,
+ IN UINTN Length
+ )
+{
+ if (Length <= 2) {
+ return FALSE;
+ }
+ if (Hex[0] != '0') {
+ return FALSE;
+ }
+ if (Hex[1] != 'x' && Hex[1] != 'X') {
+ return FALSE;
+ }
+ return IsValidDigital(&Hex[2], Length - 2, TRUE);
+}
+
+/**
+ Return if the name string is valid.
+
+ @param[in] Name The name to be checked.
+ @param[in] Length The length of name string in bytes.
+
+ @retval TRUE The name string is valid.
+ @retval FALSE The name string is invalid.
+**/
+BOOLEAN
+IsValidName (
+ IN CHAR8 *Name,
+ IN UINTN Length
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < Length; Index++) {
+ if (!IsValidNameChar(Name[Index])) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/**
+ Return if the value string is valid GUID.
+
+ @param[in] Value The value to be checked.
+ @param[in] Length The length of value string in bytes.
+
+ @retval TRUE The value string is valid GUID.
+ @retval FALSE The value string is invalid GUID.
+**/
+BOOLEAN
+IsValidGuid (
+ IN CHAR8 *Value,
+ IN UINTN Length
+ )
+{
+ if (Length != sizeof("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") - 1) {
+ return FALSE;
+ }
+ if (!IS_HYPHEN(Value[8])) {
+ return FALSE;
+ }
+ if (!IS_HYPHEN(Value[13])) {
+ return FALSE;
+ }
+ if (!IS_HYPHEN(Value[18])) {
+ return FALSE;
+ }
+ if (!IS_HYPHEN(Value[23])) {
+ return FALSE;
+ }
+ if (!IsValidDigital(&Value[0], 8, TRUE)) {
+ return FALSE;
+ }
+ if (!IsValidDigital(&Value[9], 4, TRUE)) {
+ return FALSE;
+ }
+ if (!IsValidDigital(&Value[14], 4, TRUE)) {
+ return FALSE;
+ }
+ if (!IsValidDigital(&Value[19], 4, TRUE)) {
+ return FALSE;
+ }
+ if (!IsValidDigital(&Value[24], 12, TRUE)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Return if the value string is valid.
+
+ @param[in] Value The value to be checked.
+ @param[in] Length The length of value string in bytes.
+
+ @retval TRUE The name string is valid.
+ @retval FALSE The name string is invalid.
+**/
+BOOLEAN
+IsValidValue (
+ IN CHAR8 *Value,
+ IN UINTN Length
+ )
+{
+ if (IsValidName(Value, Length) || IsValidGuid(Value, Length)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Dump an INI config file context.
+
+ @param[in] Context INI Config file context.
+**/
+VOID
+DumpIniSection (
+ IN VOID *Context
+ )
+{
+ INI_PARSING_LIB_CONTEXT *IniContext;
+ SECTION_ITEM *PtrSection;
+ SECTION_ITEM *Section;
+
+ if (Context == NULL) {
+ return;
+ }
+
+ IniContext = Context;
+ Section = IniContext->SectionHead;
+
+ while (Section != NULL) {
+ PtrSection = Section;
+ Section = Section->PtrNext;
+ if (PtrSection->PtrSection != NULL) {
+ DEBUG((DEBUG_VERBOSE, "Section - %a\n", PtrSection->PtrSection));
+ }
+ if (PtrSection->PtrEntry != NULL) {
+ DEBUG ((DEBUG_VERBOSE, " Entry - %a\n", PtrSection->PtrEntry));
+ }
+ if (PtrSection->PtrValue != NULL) {
+ DEBUG((DEBUG_VERBOSE, " Value - %a\n", PtrSection->PtrValue));
+ }
+ }
+}
+
+/**
+ Copy one line data from buffer data to the line buffer.
+
+ @param[in] Buffer Buffer data.
+ @param[in] BufferSize Buffer Size.
+ @param[in, out] LineBuffer Line buffer to store the found line data.
+ @param[in, out] LineSize On input, size of the input line buffer.
+ On output, size of the actual line buffer.
+
+ @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough.
+ @retval EFI_SUCCESS Copy line data into the line buffer.
+
+**/
+EFI_STATUS
+ProfileGetLine (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT UINT8 *LineBuffer,
+ IN OUT UINTN *LineSize
+ )
+{
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINTN PtrEnd;
+
+ PtrBuf = Buffer;
+ PtrEnd = (UINTN)Buffer + BufferSize;
+
+ //
+ // 0x0D indicates a line break. Otherwise there is no line break
+ //
+ while ((UINTN)PtrBuf < PtrEnd) {
+ if (*PtrBuf == 0x0D || *PtrBuf == 0x0A) {
+ break;
+ }
+ PtrBuf++;
+ }
+
+ if ((UINTN)PtrBuf >= (PtrEnd - 1)) {
+ //
+ // The buffer ends without any line break
+ // or it is the last character of the buffer
+ //
+ Length = BufferSize;
+ } else if (*(PtrBuf + 1) == 0x0A) {
+ //
+ // Further check if a 0x0A follows. If yes, count 0xA
+ //
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 2;
+ } else {
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 1;
+ }
+
+ if (Length > (*LineSize)) {
+ *LineSize = Length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ SetMem (LineBuffer, *LineSize, 0x0);
+ *LineSize = Length;
+ CopyMem (LineBuffer, Buffer, Length);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
+
+ @param[in, out] Buffer On input, buffer data to be trimmed.
+ On output, the trimmed buffer.
+ @param[in, out] BufferSize On input, size of original buffer data.
+ On output, size of the trimmed buffer.
+
+**/
+VOID
+ProfileTrim (
+ IN OUT UINT8 *Buffer,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINT8 *PtrEnd;
+
+ if (*BufferSize == 0) {
+ return;
+ }
+
+ //
+ // Trim the tail first, include CR, LF, TAB, and SPACE.
+ //
+ Length = *BufferSize;
+ PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1);
+ while (PtrBuf >= Buffer) {
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
+ break;
+ }
+ PtrBuf --;
+ }
+
+ //
+ // all spaces, a blank line, return directly;
+ //
+ if (PtrBuf < Buffer) {
+ *BufferSize = 0;
+ return;
+ }
+
+ Length = (UINTN)PtrBuf - (UINTN)Buffer + 1;
+ PtrEnd = PtrBuf;
+ PtrBuf = Buffer;
+
+ //
+ // Now skip the heading CR, LF, TAB and SPACE
+ //
+ while (PtrBuf <= PtrEnd) {
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
+ break;
+ }
+ PtrBuf++;
+ }
+
+ //
+ // If no heading CR, LF, TAB or SPACE, directly return
+ //
+ if (PtrBuf == Buffer) {
+ *BufferSize = Length;
+ return;
+ }
+
+ *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;
+
+ //
+ // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
+ // Now move out all these characters.
+ //
+ while (PtrBuf <= PtrEnd) {
+ *Buffer = *PtrBuf;
+ Buffer++;
+ PtrBuf++;
+ }
+
+ return;
+}
+
+/**
+ Insert new comment item into comment head.
+
+ @param[in] Buffer Comment buffer to be added.
+ @param[in] BufferSize Size of comment buffer.
+ @param[in, out] CommentHead Comment Item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS New comment item is inserted.
+
+**/
+EFI_STATUS
+ProfileGetComments (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT COMMENT_LINE **CommentHead
+ )
+{
+ COMMENT_LINE *CommentItem;
+
+ CommentItem = NULL;
+ CommentItem = AllocatePool (sizeof (COMMENT_LINE));
+ if (CommentItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CommentItem->PtrNext = *CommentHead;
+ *CommentHead = CommentItem;
+
+ //
+ // Add a trailing '\0'
+ //
+ CommentItem->PtrComment = AllocatePool (BufferSize + 1);
+ if (CommentItem->PtrComment == NULL) {
+ FreePool (CommentItem);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (CommentItem->PtrComment, Buffer, BufferSize);
+ *(CommentItem->PtrComment + BufferSize) = '\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add new section item into Section head.
+
+ @param[in] Buffer Section item data buffer.
+ @param[in] BufferSize Size of section item.
+ @param[in, out] SectionHead Section item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Section item is NULL or Section item is added.
+
+**/
+EFI_STATUS
+ProfileGetSection (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead
+ )
+{
+ SECTION_ITEM *SectionItem;
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINT8 *PtrEnd;
+
+ ASSERT(BufferSize >= 1);
+ //
+ // The first character of Buffer is '[', now we want for ']'
+ //
+ PtrEnd = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
+ PtrBuf = (UINT8 *)((UINTN)Buffer + 1);
+ while (PtrBuf <= PtrEnd) {
+ if (*PtrBuf == ']') {
+ break;
+ }
+ PtrBuf ++;
+ }
+ if (PtrBuf > PtrEnd) {
+ //
+ // Not found. Invalid line
+ //
+ return EFI_NOT_FOUND;
+ }
+ if (PtrBuf <= Buffer + 1) {
+ // Empty name
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // excluding the heading '[' and tailing ']'
+ //
+ Length = PtrBuf - Buffer - 1;
+ ProfileTrim (
+ Buffer + 1,
+ &Length
+ );
+
+ //
+ // Invalid line if the section name is null
+ //
+ if (Length == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!IsValidName((CHAR8 *)Buffer + 1, Length)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));
+ if (SectionItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SectionItem->PtrSection = NULL;
+ SectionItem->SecNameLen = Length;
+ SectionItem->PtrEntry = NULL;
+ SectionItem->PtrValue = NULL;
+ SectionItem->PtrNext = *SectionHead;
+ *SectionHead = SectionItem;
+
+ //
+ // Add a trailing '\0'
+ //
+ SectionItem->PtrSection = AllocatePool (Length + 1);
+ if (SectionItem->PtrSection == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // excluding the heading '['
+ //
+ CopyMem (SectionItem->PtrSection, Buffer + 1, Length);
+ *(SectionItem->PtrSection + Length) = '\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add new section entry and entry value into Section head.
+
+ @param[in] Buffer Section entry data buffer.
+ @param[in] BufferSize Size of section entry.
+ @param[in, out] SectionHead Section item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Section entry is added.
+ @retval EFI_NOT_FOUND Section entry is not found.
+ @retval EFI_INVALID_PARAMETER Section entry is invalid.
+
+**/
+EFI_STATUS
+ProfileGetEntry (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead
+ )
+{
+ EFI_STATUS Status;
+ SECTION_ITEM *SectionItem;
+ SECTION_ITEM *PtrSection;
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINT8 *PtrEnd;
+
+ Status = EFI_SUCCESS;
+ PtrBuf = Buffer;
+ PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1);
+
+ //
+ // First search for '='
+ //
+ while (PtrBuf <= PtrEnd) {
+ if (*PtrBuf == '=') {
+ break;
+ }
+ PtrBuf++;
+ }
+ if (PtrBuf > PtrEnd) {
+ //
+ // Not found. Invalid line
+ //
+ return EFI_NOT_FOUND;
+ }
+ if (PtrBuf <= Buffer) {
+ // Empty name
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // excluding the tailing '='
+ //
+ Length = PtrBuf - Buffer;
+ ProfileTrim (
+ Buffer,
+ &Length
+ );
+
+ //
+ // Invalid line if the entry name is null
+ //
+ if (Length == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!IsValidName((CHAR8 *)Buffer, Length)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Omit this line if no section header has been found before
+ //
+ if (*SectionHead == NULL) {
+ return Status;
+ }
+ PtrSection = *SectionHead;
+
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));
+ if (SectionItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SectionItem->PtrSection = NULL;
+ SectionItem->PtrEntry = NULL;
+ SectionItem->PtrValue = NULL;
+ SectionItem->SecNameLen = PtrSection->SecNameLen;
+ SectionItem->PtrNext = *SectionHead;
+ *SectionHead = SectionItem;
+
+ //
+ // SectionName, add a trailing '\0'
+ //
+ SectionItem->PtrSection = AllocatePool (PtrSection->SecNameLen + 1);
+ if (SectionItem->PtrSection == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->PtrSection, PtrSection->PtrSection, PtrSection->SecNameLen + 1);
+
+ //
+ // EntryName, add a trailing '\0'
+ //
+ SectionItem->PtrEntry = AllocatePool (Length + 1);
+ if (SectionItem->PtrEntry == NULL) {
+ FreePool(SectionItem->PtrSection);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->PtrEntry, Buffer, Length);
+ *(SectionItem->PtrEntry + Length) = '\0';
+
+ //
+ // Next search for '#' or ';'
+ //
+ PtrBuf = PtrBuf + 1;
+ Buffer = PtrBuf;
+ while (PtrBuf <= PtrEnd) {
+ if (*PtrBuf == '#' || *PtrBuf == ';') {
+ break;
+ }
+ PtrBuf++;
+ }
+ if (PtrBuf <= Buffer) {
+ // Empty name
+ FreePool(SectionItem->PtrEntry);
+ FreePool(SectionItem->PtrSection);
+ return EFI_NOT_FOUND;
+ }
+ Length = PtrBuf - Buffer;
+ ProfileTrim (
+ Buffer,
+ &Length
+ );
+
+ //
+ // Invalid line if the entry value is null
+ //
+ if (Length == 0) {
+ FreePool(SectionItem->PtrEntry);
+ FreePool(SectionItem->PtrSection);
+ return EFI_NOT_FOUND;
+ }
+
+ if (!IsValidValue((CHAR8 *)Buffer, Length)) {
+ FreePool(SectionItem->PtrEntry);
+ FreePool(SectionItem->PtrSection);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // EntryValue, add a trailing '\0'
+ //
+ SectionItem->PtrValue = AllocatePool (Length + 1);
+ if (SectionItem->PtrValue == NULL) {
+ FreePool(SectionItem->PtrEntry);
+ FreePool(SectionItem->PtrSection);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->PtrValue, Buffer, Length);
+ *(SectionItem->PtrValue + Length) = '\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free all comment entry and section entry.
+
+ @param[in] Section Section entry list.
+ @param[in] Comment Comment entry list.
+
+**/
+VOID
+FreeAllList (
+ IN SECTION_ITEM *Section,
+ IN COMMENT_LINE *Comment
+ )
+{
+ SECTION_ITEM *PtrSection;
+ COMMENT_LINE *PtrComment;
+
+ while (Section != NULL) {
+ PtrSection = Section;
+ Section = Section->PtrNext;
+ if (PtrSection->PtrEntry != NULL) {
+ FreePool (PtrSection->PtrEntry);
+ }
+ if (PtrSection->PtrSection != NULL) {
+ FreePool (PtrSection->PtrSection);
+ }
+ if (PtrSection->PtrValue != NULL) {
+ FreePool (PtrSection->PtrValue);
+ }
+ FreePool (PtrSection);
+ }
+
+ while (Comment != NULL) {
+ PtrComment = Comment;
+ Comment = Comment->PtrNext;
+ if (PtrComment->PtrComment != NULL) {
+ FreePool (PtrComment->PtrComment);
+ }
+ FreePool (PtrComment);
+ }
+
+ return;
+}
+
+/**
+ Get section entry value.
+
+ @param[in] Section Section entry list.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] EntryValue Point to the got entry value.
+
+ @retval EFI_NOT_FOUND Section is not found.
+ @retval EFI_SUCCESS Section entry value is got.
+
+**/
+EFI_STATUS
+UpdateGetProfileString (
+ IN SECTION_ITEM *Section,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT CHAR8 **EntryValue
+ )
+{
+ *EntryValue = NULL;
+
+ while (Section != NULL) {
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->PtrSection, (CONST CHAR8 *) SectionName) == 0) {
+ if (Section->PtrEntry != NULL) {
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->PtrEntry, (CONST CHAR8 *) EntryName) == 0) {
+ break;
+ }
+ }
+ }
+ Section = Section->PtrNext;
+ }
+
+ if (Section == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *EntryValue = Section->PtrValue;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pre process config data buffer into Section entry list and Comment entry list.
+
+ @param[in] DataBuffer Config raw file buffer.
+ @param[in] BufferSize Size of raw buffer.
+ @param[in, out] SectionHead Pointer to the section entry list.
+ @param[in, out] CommentHead Pointer to the comment entry list.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Config data buffer is preprocessed.
+ @retval EFI_NOT_FOUND Config data buffer is invalid, because Section or Entry is not found.
+ @retval EFI_INVALID_PARAMETER Config data buffer is invalid, because Section or Entry is invalid.
+
+**/
+EFI_STATUS
+PreProcessDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead,
+ IN OUT COMMENT_LINE **CommentHead
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *Source;
+ CHAR8 *CurrentPtr;
+ CHAR8 *BufferEnd;
+ CHAR8 *PtrLine;
+ UINTN LineLength;
+ UINTN SourceLength;
+ UINTN MaxLineLength;
+
+ *SectionHead = NULL;
+ *CommentHead = NULL;
+ BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize);
+ CurrentPtr = (CHAR8 *) DataBuffer;
+ MaxLineLength = MAX_LINE_LENGTH;
+ Status = EFI_SUCCESS;
+
+ PtrLine = AllocatePool (MaxLineLength);
+ if (PtrLine == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (CurrentPtr < BufferEnd) {
+ Source = CurrentPtr;
+ SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr;
+ LineLength = MaxLineLength;
+ //
+ // With the assumption that line length is less than 512
+ // characters. Otherwise BUFFER_TOO_SMALL will be returned.
+ //
+ Status = ProfileGetLine (
+ (UINT8 *) Source,
+ SourceLength,
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // If buffer too small, re-allocate the buffer according
+ // to the returned LineLength and try again.
+ //
+ FreePool (PtrLine);
+ PtrLine = NULL;
+ PtrLine = AllocatePool (LineLength);
+ if (PtrLine == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ SourceLength = LineLength;
+ Status = ProfileGetLine (
+ (UINT8 *) Source,
+ SourceLength,
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ MaxLineLength = LineLength;
+ } else {
+ break;
+ }
+ }
+ CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength);
+
+ //
+ // Line got. Trim the line before processing it.
+ //
+ ProfileTrim (
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+
+ //
+ // Blank line
+ //
+ if (LineLength == 0) {
+ continue;
+ }
+
+ if (PtrLine[0] == '#' || PtrLine[0] == ';') {
+ Status = ProfileGetComments (
+ (UINT8 *) PtrLine,
+ LineLength,
+ CommentHead
+ );
+ } else if (PtrLine[0] == '[') {
+ Status = ProfileGetSection (
+ (UINT8 *) PtrLine,
+ LineLength,
+ SectionHead
+ );
+ } else {
+ Status = ProfileGetEntry (
+ (UINT8 *) PtrLine,
+ LineLength,
+ SectionHead
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Free buffer
+ //
+ FreePool (PtrLine);
+
+ return Status;
+}
+
+/**
+ Open an INI config file and return a context.
+
+ @param[in] DataBuffer Config raw file buffer.
+ @param[in] BufferSize Size of raw buffer.
+
+ @return Config data buffer is opened and context is returned.
+ @retval NULL No enough memory is allocated.
+ @retval NULL Config data buffer is invalid.
+**/
+VOID *
+EFIAPI
+OpenIniFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ INI_PARSING_LIB_CONTEXT *IniContext;
+
+ if (DataBuffer == NULL || BufferSize == 0) {
+ return NULL;
+ }
+
+ IniContext = AllocateZeroPool(sizeof(INI_PARSING_LIB_CONTEXT));
+ if (IniContext == NULL) {
+ return NULL;
+ }
+
+ //
+ // First process the data buffer and get all sections and entries
+ //
+ Status = PreProcessDataFile (
+ DataBuffer,
+ BufferSize,
+ &IniContext->SectionHead,
+ &IniContext->CommentHead
+ );
+ if (EFI_ERROR(Status)) {
+ FreePool(IniContext);
+ return NULL;
+ }
+ DEBUG_CODE_BEGIN ();
+ DumpIniSection(IniContext);
+ DEBUG_CODE_END ();
+ return IniContext;
+}
+
+/**
+ Get section entry string value.
+
+ @param[in] Context INI Config file context.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] EntryValue Point to the got entry string value.
+
+ @retval EFI_SUCCESS Section entry string value is got.
+ @retval EFI_NOT_FOUND Section is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetStringFromDataFile(
+ IN VOID *Context,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT CHAR8 **EntryValue
+ )
+{
+ INI_PARSING_LIB_CONTEXT *IniContext;
+ EFI_STATUS Status;
+
+ if (Context == NULL || SectionName == NULL || EntryName == NULL || EntryValue == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ IniContext = Context;
+
+ *EntryValue = NULL;
+ Status = UpdateGetProfileString (
+ IniContext->SectionHead,
+ SectionName,
+ EntryName,
+ EntryValue
+ );
+ return Status;
+}
+
+/**
+ Get section entry GUID value.
+
+ @param[in] Context INI Config file context.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] Guid Point to the got GUID value.
+
+ @retval EFI_SUCCESS Section entry GUID value is got.
+ @retval EFI_NOT_FOUND Section is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetGuidFromDataFile (
+ IN VOID *Context,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT EFI_GUID *Guid
+ )
+{
+ CHAR8 *Value;
+ EFI_STATUS Status;
+ RETURN_STATUS RStatus;
+
+ if (Context == NULL || SectionName == NULL || EntryName == NULL || Guid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetStringFromDataFile(
+ Context,
+ SectionName,
+ EntryName,
+ &Value
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (Value != NULL);
+ RStatus = AsciiStrToGuid (Value, Guid);
+ if (RETURN_ERROR (RStatus) || (Value[GUID_STRING_LENGTH] != '\0')) {
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Get section entry decimal UINTN value.
+
+ @param[in] Context INI Config file context.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] Data Point to the got decimal UINTN value.
+
+ @retval EFI_SUCCESS Section entry decimal UINTN value is got.
+ @retval EFI_NOT_FOUND Section is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetDecimalUintnFromDataFile (
+ IN VOID *Context,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT UINTN *Data
+ )
+{
+ CHAR8 *Value;
+ EFI_STATUS Status;
+
+ if (Context == NULL || SectionName == NULL || EntryName == NULL || Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetStringFromDataFile(
+ Context,
+ SectionName,
+ EntryName,
+ &Value
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (Value != NULL);
+ if (!IsValidDecimalString(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ *Data = AsciiStrDecimalToUintn(Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ Get section entry hexadecimal UINTN value.
+
+ @param[in] Context INI Config file context.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] Data Point to the got hexadecimal UINTN value.
+
+ @retval EFI_SUCCESS Section entry hexadecimal UINTN value is got.
+ @retval EFI_NOT_FOUND Section is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetHexUintnFromDataFile (
+ IN VOID *Context,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT UINTN *Data
+ )
+{
+ CHAR8 *Value;
+ EFI_STATUS Status;
+
+ if (Context == NULL || SectionName == NULL || EntryName == NULL || Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetStringFromDataFile(
+ Context,
+ SectionName,
+ EntryName,
+ &Value
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (Value != NULL);
+ if (!IsValidHexString(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ *Data = AsciiStrHexToUintn(Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ Get section entry hexadecimal UINT64 value.
+
+ @param[in] Context INI Config file context.
+ @param[in] SectionName Section name.
+ @param[in] EntryName Section entry name.
+ @param[out] Data Point to the got hexadecimal UINT64 value.
+
+ @retval EFI_SUCCESS Section entry hexadecimal UINT64 value is got.
+ @retval EFI_NOT_FOUND Section is not found.
+**/
+EFI_STATUS
+EFIAPI
+GetHexUint64FromDataFile (
+ IN VOID *Context,
+ IN CHAR8 *SectionName,
+ IN CHAR8 *EntryName,
+ OUT UINT64 *Data
+ )
+{
+ CHAR8 *Value;
+ EFI_STATUS Status;
+
+ if (Context == NULL || SectionName == NULL || EntryName == NULL || Data == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = GetStringFromDataFile(
+ Context,
+ SectionName,
+ EntryName,
+ &Value
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_NOT_FOUND;
+ }
+ ASSERT (Value != NULL);
+ if (!IsValidHexString(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ *Data = AsciiStrHexToUint64(Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ Close an INI config file and free the context.
+
+ @param[in] Context INI Config file context.
+**/
+VOID
+EFIAPI
+CloseIniFile (
+ IN VOID *Context
+ )
+{
+ INI_PARSING_LIB_CONTEXT *IniContext;
+
+ if (Context == NULL) {
+ return ;
+ }
+
+ IniContext = Context;
+ FreeAllList(IniContext->SectionHead, IniContext->CommentHead);
+
+ return;
+}