| /** @file | |
| This contains some useful functions for parsing INF files. | |
| Copyright (c) 2004 - 2014, 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 <assert.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include <stdlib.h> | |
| #include "EfiUtilityMsgs.h" | |
| #include "ParseInf.h" | |
| #include "CommonLib.h" | |
| CHAR8 * | |
| ReadLine ( | |
| IN MEMORY_FILE *InputFile, | |
| IN OUT CHAR8 *InputBuffer, | |
| IN UINTN MaxLength | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function reads a line, stripping any comments. | |
| The function reads a string from the input stream argument and stores it in | |
| the input string. ReadLine reads characters from the current file position | |
| to and including the first newline character, to the end of the stream, or | |
| until the number of characters read is equal to MaxLength - 1, whichever | |
| comes first. The newline character, if read, is replaced with a \0. | |
| Arguments: | |
| InputFile Memory file image. | |
| InputBuffer Buffer to read into, must be MaxLength size. | |
| MaxLength The maximum size of the input buffer. | |
| Returns: | |
| NULL if error or EOF | |
| InputBuffer otherwise | |
| --*/ | |
| { | |
| CHAR8 *CharPtr; | |
| CHAR8 *EndOfLine; | |
| UINTN CharsToCopy; | |
| // | |
| // Verify input parameters are not null | |
| // | |
| assert (InputBuffer); | |
| assert (InputFile->FileImage); | |
| assert (InputFile->Eof); | |
| assert (InputFile->CurrentFilePointer); | |
| // | |
| // Check for end of file condition | |
| // | |
| if (InputFile->CurrentFilePointer >= InputFile->Eof) { | |
| return NULL; | |
| } | |
| // | |
| // Find the next newline char | |
| // | |
| EndOfLine = strchr (InputFile->CurrentFilePointer, '\n'); | |
| // | |
| // Determine the number of characters to copy. | |
| // | |
| if (EndOfLine == 0) { | |
| // | |
| // If no newline found, copy to the end of the file. | |
| // | |
| CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; | |
| } else if (EndOfLine >= InputFile->Eof) { | |
| // | |
| // If the newline found was beyond the end of file, copy to the eof. | |
| // | |
| CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; | |
| } else { | |
| // | |
| // Newline found in the file. | |
| // | |
| CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; | |
| } | |
| // | |
| // If the end of line is too big for the current buffer, set it to the max | |
| // size of the buffer (leaving room for the \0. | |
| // | |
| if (CharsToCopy > MaxLength - 1) { | |
| CharsToCopy = MaxLength - 1; | |
| } | |
| // | |
| // Copy the line. | |
| // | |
| memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy); | |
| // | |
| // Add the null termination over the 0x0D | |
| // | |
| if (InputBuffer[CharsToCopy - 1] == '\r') { | |
| InputBuffer[CharsToCopy - 1] = '\0'; | |
| } else { | |
| InputBuffer[CharsToCopy] = '\0'; | |
| } | |
| // | |
| // Increment the current file pointer (include the 0x0A) | |
| // | |
| InputFile->CurrentFilePointer += CharsToCopy + 1; | |
| // | |
| // Strip any comments | |
| // | |
| CharPtr = strstr (InputBuffer, "//"); | |
| if (CharPtr != 0) { | |
| CharPtr[0] = 0; | |
| } | |
| // | |
| // Return the string | |
| // | |
| return InputBuffer; | |
| } | |
| BOOLEAN | |
| FindSection ( | |
| IN MEMORY_FILE *InputFile, | |
| IN CHAR8 *Section | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function parses a file from the beginning to find a section. | |
| The section string may be anywhere within a line. | |
| Arguments: | |
| InputFile Memory file image. | |
| Section Section to search for | |
| Returns: | |
| FALSE if error or EOF | |
| TRUE if section found | |
| --*/ | |
| { | |
| CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; | |
| CHAR8 *CurrentToken; | |
| // | |
| // Verify input is not NULL | |
| // | |
| assert (InputFile->FileImage); | |
| assert (InputFile->Eof); | |
| assert (InputFile->CurrentFilePointer); | |
| assert (Section); | |
| // | |
| // Rewind to beginning of file | |
| // | |
| InputFile->CurrentFilePointer = InputFile->FileImage; | |
| // | |
| // Read lines until the section is found | |
| // | |
| while (InputFile->CurrentFilePointer < InputFile->Eof) { | |
| // | |
| // Read a line | |
| // | |
| ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH); | |
| // | |
| // Check if the section is found | |
| // | |
| CurrentToken = strstr (InputBuffer, Section); | |
| if (CurrentToken != NULL) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| EFI_STATUS | |
| FindToken ( | |
| IN MEMORY_FILE *InputFile, | |
| IN CHAR8 *Section, | |
| IN CHAR8 *Token, | |
| IN UINTN Instance, | |
| OUT CHAR8 *Value | |
| ) | |
| /*++ | |
| Routine Description: | |
| Finds a token value given the section and token to search for. | |
| Arguments: | |
| InputFile Memory file image. | |
| Section The section to search for, a string within []. | |
| Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. | |
| Instance The instance of the token to search for. Zero is the first instance. | |
| Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size. | |
| Returns: | |
| EFI_SUCCESS Value found. | |
| EFI_ABORTED Format error detected in INF file. | |
| EFI_INVALID_PARAMETER Input argument was null. | |
| EFI_LOAD_ERROR Error reading from the file. | |
| EFI_NOT_FOUND Section/Token/Value not found. | |
| --*/ | |
| { | |
| CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; | |
| CHAR8 *CurrentToken; | |
| CHAR8 *Delimiter; | |
| BOOLEAN ParseError; | |
| BOOLEAN ReadError; | |
| UINTN Occurrance; | |
| // | |
| // Check input parameters | |
| // | |
| if (InputFile->FileImage == NULL || | |
| InputFile->Eof == NULL || | |
| InputFile->CurrentFilePointer == NULL || | |
| Section == NULL || | |
| strlen (Section) == 0 || | |
| Token == NULL || | |
| strlen (Token) == 0 || | |
| Value == NULL | |
| ) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Initialize error codes | |
| // | |
| ParseError = FALSE; | |
| ReadError = FALSE; | |
| // | |
| // Initialize our instance counter for the search token | |
| // | |
| Occurrance = 0; | |
| if (FindSection (InputFile, Section)) { | |
| // | |
| // Found the desired section, find and read the desired token | |
| // | |
| do { | |
| // | |
| // Read a line from the file | |
| // | |
| if (ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH) == NULL) { | |
| // | |
| // Error reading from input file | |
| // | |
| ReadError = TRUE; | |
| break; | |
| } | |
| // | |
| // Get the first non-whitespace string | |
| // | |
| Delimiter = strchr (InputBuffer, '='); | |
| if (Delimiter != NULL) { | |
| *Delimiter = 0; | |
| } | |
| CurrentToken = strtok (InputBuffer, " \t\n"); | |
| if (CurrentToken == NULL || Delimiter == NULL) { | |
| // | |
| // Whitespace line found (or comment) so continue | |
| // | |
| CurrentToken = InputBuffer; | |
| continue; | |
| } | |
| // | |
| // Make sure we have not reached the end of the current section | |
| // | |
| if (CurrentToken[0] == '[') { | |
| break; | |
| } | |
| // | |
| // Compare the current token with the desired token | |
| // | |
| if (strcmp (CurrentToken, Token) == 0) { | |
| // | |
| // Found it | |
| // | |
| // | |
| // Check if it is the correct instance | |
| // | |
| if (Instance == Occurrance) { | |
| // | |
| // Copy the contents following the = | |
| // | |
| CurrentToken = Delimiter + 1; | |
| if (*CurrentToken == 0) { | |
| // | |
| // Nothing found, parsing error | |
| // | |
| ParseError = TRUE; | |
| } else { | |
| // | |
| // Strip leading white space | |
| // | |
| while (*CurrentToken == ' ' || *CurrentToken == '\t') { | |
| CurrentToken++; | |
| } | |
| // | |
| // Copy the current token to the output value | |
| // | |
| strcpy (Value, CurrentToken); | |
| // | |
| // Strip trailing white space | |
| // | |
| while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) { | |
| *(Value + strlen(Value) - 1) = 0; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| } else { | |
| // | |
| // Increment the occurrance found | |
| // | |
| Occurrance++; | |
| } | |
| } | |
| } while ( | |
| !ParseError && | |
| !ReadError && | |
| InputFile->CurrentFilePointer < InputFile->Eof && | |
| CurrentToken[0] != '[' && | |
| Occurrance <= Instance | |
| ); | |
| } | |
| // | |
| // Distinguish between read errors and INF file format errors. | |
| // | |
| if (ReadError) { | |
| return EFI_LOAD_ERROR; | |
| } | |
| if (ParseError) { | |
| return EFI_ABORTED; | |
| } | |
| return EFI_NOT_FOUND; | |
| } | |
| EFI_STATUS | |
| StringToGuid ( | |
| IN CHAR8 *AsciiGuidBuffer, | |
| OUT EFI_GUID *GuidBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| Converts a string to an EFI_GUID. The string must be in the | |
| xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. | |
| Arguments: | |
| AsciiGuidBuffer - pointer to ascii string | |
| GuidBuffer - pointer to destination Guid | |
| Returns: | |
| EFI_ABORTED Could not convert the string | |
| EFI_SUCCESS The string was successfully converted | |
| EFI_INVALID_PARAMETER Input parameter is invalid. | |
| --*/ | |
| { | |
| INT32 Index; | |
| unsigned Data1; | |
| unsigned Data2; | |
| unsigned Data3; | |
| unsigned Data4[8]; | |
| if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | |
| // | |
| for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) { | |
| if (Index == 8 || Index == 13 || Index == 18 || Index == 23) { | |
| if (AsciiGuidBuffer[Index] != '-') { | |
| break; | |
| } | |
| } else { | |
| if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) || | |
| ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) || | |
| ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) { | |
| continue; | |
| } else { | |
| break; | |
| } | |
| } | |
| } | |
| if (Index < 36 || AsciiGuidBuffer[36] != '\0') { | |
| Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Scan the guid string into the buffer | |
| // | |
| Index = sscanf ( | |
| AsciiGuidBuffer, | |
| "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", | |
| &Data1, | |
| &Data2, | |
| &Data3, | |
| &Data4[0], | |
| &Data4[1], | |
| &Data4[2], | |
| &Data4[3], | |
| &Data4[4], | |
| &Data4[5], | |
| &Data4[6], | |
| &Data4[7] | |
| ); | |
| // | |
| // Verify the correct number of items were scanned. | |
| // | |
| if (Index != 11) { | |
| Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Copy the data into our GUID. | |
| // | |
| GuidBuffer->Data1 = (UINT32) Data1; | |
| GuidBuffer->Data2 = (UINT16) Data2; | |
| GuidBuffer->Data3 = (UINT16) Data3; | |
| GuidBuffer->Data4[0] = (UINT8) Data4[0]; | |
| GuidBuffer->Data4[1] = (UINT8) Data4[1]; | |
| GuidBuffer->Data4[2] = (UINT8) Data4[2]; | |
| GuidBuffer->Data4[3] = (UINT8) Data4[3]; | |
| GuidBuffer->Data4[4] = (UINT8) Data4[4]; | |
| GuidBuffer->Data4[5] = (UINT8) Data4[5]; | |
| GuidBuffer->Data4[6] = (UINT8) Data4[6]; | |
| GuidBuffer->Data4[7] = (UINT8) Data4[7]; | |
| return EFI_SUCCESS; | |
| } | |
| EFI_STATUS | |
| AsciiStringToUint64 ( | |
| IN CONST CHAR8 *AsciiString, | |
| IN BOOLEAN IsHex, | |
| OUT UINT64 *ReturnValue | |
| ) | |
| /*++ | |
| Routine Description: | |
| Converts a null terminated ascii string that represents a number into a | |
| UINT64 value. A hex number may be preceeded by a 0x, but may not be | |
| succeeded by an h. A number without 0x or 0X is considered to be base 10 | |
| unless the IsHex input is true. | |
| Arguments: | |
| AsciiString The string to convert. | |
| IsHex Force the string to be treated as a hex number. | |
| ReturnValue The return value. | |
| Returns: | |
| EFI_SUCCESS Number successfully converted. | |
| EFI_ABORTED Invalid character encountered. | |
| --*/ | |
| { | |
| UINT8 Index; | |
| UINT64 Value; | |
| CHAR8 CurrentChar; | |
| // | |
| // Initialize the result | |
| // | |
| Value = 0; | |
| Index = 0; | |
| // | |
| // Check input paramter | |
| // | |
| if (AsciiString == NULL || ReturnValue == NULL) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| while (AsciiString[Index] == ' ') { | |
| Index ++; | |
| } | |
| // | |
| // Add each character to the result | |
| // | |
| // | |
| // Skip first two chars only if the string starts with '0x' or '0X' | |
| // | |
| if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) { | |
| IsHex = TRUE; | |
| Index += 2; | |
| } | |
| if (IsHex) { | |
| // | |
| // Convert the hex string. | |
| // | |
| for (; AsciiString[Index] != '\0'; Index++) { | |
| CurrentChar = AsciiString[Index]; | |
| if (CurrentChar == ' ') { | |
| break; | |
| } | |
| // | |
| // Verify Hex string | |
| // | |
| if (isxdigit ((int)CurrentChar) == 0) { | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Add hex value | |
| // | |
| Value *= 16; | |
| if (CurrentChar >= '0' && CurrentChar <= '9') { | |
| Value += CurrentChar - '0'; | |
| } else if (CurrentChar >= 'a' && CurrentChar <= 'f') { | |
| Value += CurrentChar - 'a' + 10; | |
| } else if (CurrentChar >= 'A' && CurrentChar <= 'F') { | |
| Value += CurrentChar - 'A' + 10; | |
| } | |
| } | |
| *ReturnValue = Value; | |
| } else { | |
| // | |
| // Convert dec string is a number | |
| // | |
| for (; Index < strlen (AsciiString); Index++) { | |
| CurrentChar = AsciiString[Index]; | |
| if (CurrentChar == ' ') { | |
| break; | |
| } | |
| // | |
| // Verify Dec string | |
| // | |
| if (isdigit ((int)CurrentChar) == 0) { | |
| return EFI_ABORTED; | |
| } | |
| // | |
| // Add dec value | |
| // | |
| Value = Value * 10; | |
| Value += CurrentChar - '0'; | |
| } | |
| *ReturnValue = Value; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| CHAR8 * | |
| ReadLineInStream ( | |
| IN FILE *InputFile, | |
| IN OUT CHAR8 *InputBuffer | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function reads a line, stripping any comments. | |
| // BUGBUG: This is obsolete once genmake goes away... | |
| Arguments: | |
| InputFile Stream pointer. | |
| InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size. | |
| Returns: | |
| NULL if error or EOF | |
| InputBuffer otherwise | |
| --*/ | |
| { | |
| CHAR8 *CharPtr; | |
| // | |
| // Verify input parameters are not null | |
| // | |
| assert (InputFile); | |
| assert (InputBuffer); | |
| // | |
| // Read a line | |
| // | |
| if (fgets (InputBuffer, MAX_LONG_FILE_PATH, InputFile) == NULL) { | |
| return NULL; | |
| } | |
| // | |
| // Strip any comments | |
| // | |
| CharPtr = strstr (InputBuffer, "//"); | |
| if (CharPtr != 0) { | |
| CharPtr[0] = 0; | |
| } | |
| CharPtr = strstr (InputBuffer, "#"); | |
| if (CharPtr != 0) { | |
| CharPtr[0] = 0; | |
| } | |
| // | |
| // Return the string | |
| // | |
| return InputBuffer; | |
| } | |
| BOOLEAN | |
| FindSectionInStream ( | |
| IN FILE *InputFile, | |
| IN CHAR8 *Section | |
| ) | |
| /*++ | |
| Routine Description: | |
| This function parses a stream file from the beginning to find a section. | |
| The section string may be anywhere within a line. | |
| // BUGBUG: This is obsolete once genmake goes away... | |
| Arguments: | |
| InputFile Stream pointer. | |
| Section Section to search for | |
| Returns: | |
| FALSE if error or EOF | |
| TRUE if section found | |
| --*/ | |
| { | |
| CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; | |
| CHAR8 *CurrentToken; | |
| // | |
| // Verify input is not NULL | |
| // | |
| assert (InputFile); | |
| assert (Section); | |
| // | |
| // Rewind to beginning of file | |
| // | |
| if (fseek (InputFile, 0, SEEK_SET) != 0) { | |
| return FALSE; | |
| } | |
| // | |
| // Read lines until the section is found | |
| // | |
| while (feof (InputFile) == 0) { | |
| // | |
| // Read a line | |
| // | |
| ReadLineInStream (InputFile, InputBuffer); | |
| // | |
| // Check if the section is found | |
| // | |
| CurrentToken = strstr (InputBuffer, Section); | |
| if (CurrentToken != NULL) { | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } |