From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Library/IniParsingLib/IniParsingLib.c | 1277 ++++++++++++++++++++ 1 file changed, 1277 insertions(+) create mode 100644 roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c (limited to 'roms/edk2/SignedCapsulePkg/Library/IniParsingLib/IniParsingLib.c') 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#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; +} -- cgit