summaryrefslogtreecommitdiffstats
path: root/SignedCapsulePkg
diff options
context:
space:
mode:
Diffstat (limited to 'SignedCapsulePkg')
-rw-r--r--SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c1420
-rw-r--r--SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf43
-rw-r--r--SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.uni22
3 files changed, 1485 insertions, 0 deletions
diff --git a/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
new file mode 100644
index 0000000000..a8773c1a80
--- /dev/null
+++ b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c
@@ -0,0 +1,1420 @@
+/** @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 heximal 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, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#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 _SECTION_ITEM SECTION_ITEM;
+struct _SECTION_ITEM {
+ CHAR8 *PtrSection;
+ UINTN SecNameLen;
+ CHAR8 *PtrEntry;
+ CHAR8 *PtrValue;
+ SECTION_ITEM *PtrNext;
+};
+
+typedef struct _COMMENT_LINE COMMENT_LINE;
+struct _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 heximal string is valid.
+
+ @param[in] Hex The heximal string to be checked.
+ @param[in] Length The length of heximal string in bytes.
+
+ @retval TRUE The heximal string is valid.
+ @retval FALSE The heximal 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 trimed.
+ 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;
+}
+
+/**
+ Converts a list of string to a specified buffer.
+
+ @param[out] Buf The output buffer that contains the string.
+ @param[in] BufferLength The length of the buffer
+ @param[in] Str The input string that contains the hex number
+
+ @retval EFI_SUCCESS The string was successfully converted to the buffer.
+
+**/
+EFI_STATUS
+AsciiStrToBuf (
+ OUT UINT8 *Buf,
+ IN UINTN BufferLength,
+ IN CHAR8 *Str
+ )
+{
+ UINTN Index;
+ UINTN StrLength;
+ UINT8 Digit;
+ UINT8 Byte;
+
+ Digit = 0;
+
+ //
+ // Two hex char make up one byte
+ //
+ StrLength = BufferLength * 2;
+
+ for(Index = 0; Index < StrLength; Index++, Str++) {
+
+ if ((*Str >= 'a') && (*Str <= 'f')) {
+ Digit = (UINT8) (*Str - 'a' + 0x0A);
+ } else if ((*Str >= 'A') && (*Str <= 'F')) {
+ Digit = (UINT8) (*Str - 'A' + 0x0A);
+ } else if ((*Str >= '0') && (*Str <= '9')) {
+ Digit = (UINT8) (*Str - '0');
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For odd characters, write the upper nibble for each buffer byte,
+ // and for even characters, the lower nibble.
+ //
+ if ((Index & 1) == 0) {
+ Byte = (UINT8) (Digit << 4);
+ } else {
+ Byte = Buf[Index / 2];
+ Byte &= 0xF0;
+ Byte = (UINT8) (Byte | Digit);
+ }
+
+ Buf[Index / 2] = Byte;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Converts a string to GUID value.
+ Guid Format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
+
+ @param[in] Str The registry format GUID string that contains the GUID value.
+ @param[out] Guid A pointer to the converted GUID value.
+
+ @retval EFI_SUCCESS The GUID string was successfully converted to the GUID value.
+ @retval EFI_UNSUPPORTED The input string is not in registry format.
+ @return others Some error occurred when converting part of GUID value.
+
+**/
+EFI_STATUS
+AsciiStrToGuid (
+ IN CHAR8 *Str,
+ OUT EFI_GUID *Guid
+ )
+{
+ //
+ // Get the first UINT32 data
+ //
+ Guid->Data1 = (UINT32) AsciiStrHexToUint64 (Str);
+ while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
+ Str ++;
+ }
+
+ if (IS_HYPHEN (*Str)) {
+ Str++;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the second UINT16 data
+ //
+ Guid->Data2 = (UINT16) AsciiStrHexToUint64 (Str);
+ while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
+ Str ++;
+ }
+
+ if (IS_HYPHEN (*Str)) {
+ Str++;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the third UINT16 data
+ //
+ Guid->Data3 = (UINT16) AsciiStrHexToUint64 (Str);
+ while (!IS_HYPHEN (*Str) && !IS_NULL (*Str)) {
+ Str ++;
+ }
+
+ if (IS_HYPHEN (*Str)) {
+ Str++;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the following 8 bytes data
+ //
+ AsciiStrToBuf (&Guid->Data4[0], 2, Str);
+ //
+ // Skip 2 byte hex chars
+ //
+ Str += 2 * 2;
+
+ if (IS_HYPHEN (*Str)) {
+ Str++;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ AsciiStrToBuf (&Guid->Data4[2], 6, Str);
+
+ 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;
+
+ 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;
+ }
+ if (!IsValidGuid(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ Status = AsciiStrToGuid(Value, Guid);
+ if (EFI_ERROR (Status)) {
+ 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;
+ }
+ if (!IsValidDecimalString(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ *Data = AsciiStrDecimalToUintn(Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ Get section entry heximal 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 heximal UINTN value.
+
+ @retval EFI_SUCCESS Section entry heximal 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;
+ }
+ if (!IsValidHexString(Value, AsciiStrLen(Value))) {
+ return EFI_NOT_FOUND;
+ }
+ *Data = AsciiStrHexToUintn(Value);
+ return EFI_SUCCESS;
+}
+
+/**
+ Get section entry heximal 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 heximal UINT64 value.
+
+ @retval EFI_SUCCESS Section entry heximal 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;
+ }
+ 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;
+}
diff --git a/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf
new file mode 100644
index 0000000000..00f1d40858
--- /dev/null
+++ b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.inf
@@ -0,0 +1,43 @@
+## @file
+# INI configuration parsing library.
+#
+# This library parses the INI configuration file.
+#
+# Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IniParsingLib
+ MODULE_UNI_FILE = IniParsingLib.uni
+ FILE_GUID = 6E4CD200-43E5-43CE-89E9-D715CF9526C4
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = IniParsingLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ IniParsingLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ SignedCapsulePkg/SignedCapsulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
diff --git a/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.uni b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.uni
new file mode 100644
index 0000000000..9b198e8f6e
--- /dev/null
+++ b/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.uni
@@ -0,0 +1,22 @@
+// /** @file
+// INI configuration parsing library.
+//
+// This library parses the INI configuration file.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "INI configuration parsing library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library parses the INI configuration file."
+