/** @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; }