/*++ Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.
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. Module Name: GenFfsFile.c Abstract: This file contains functions required to generate a Firmware File System file. --*/ #include "TianoCommon.h" #include "EfiFirmwareFileSystem.h" #include "EfiFirmwareVolumeHeader.h" #include "EfiImageFormat.h" #include "EfiImage.h" #include "ParseInf.h" #include "Compress.h" #include "EfiCustomizedCompress.h" #include "crc32.h" #include "GenFfsFile.h" #include #include // for isalpha() // // include file for _spawnv // #include #include #include #include "CommonLib.h" #include "EfiUtilityMsgs.h" #include "SimpleFileParsing.h" #define UTILITY_NAME "GenFfsFile" #define UTILITY_VERSION "v1.1" #define MAX_ARRAY_SIZE 100 static INT32 GetNextLine ( OUT CHAR8 *Destination, IN FILE *Package, IN OUT UINT32 *LineNumber ); static void CheckSlash ( IN OUT CHAR8 *String, IN FILE *In, IN OUT UINT32 *LineNumber ); static INT32 FindSectionInPackage ( IN CHAR8 *BuildDirectory, IN FILE *OverridePackage, IN OUT UINT32 *LineNumber ); static STATUS ProcessCommandLineArgs ( int Argc, char *Argv[] ); static void PrintUsage ( void ); static void AddMacro ( UINT8 *MacroString ); static UINT8 * GetMacroValue ( UINT8 *MacroName ); static void FreeMacros ( ); static STATUS ReplaceMacros ( UINT8 *InputFile, UINT8 *OutputFile ); // // Linked list to keep track of all macros // typedef struct _MACRO { struct _MACRO *Next; UINT8 *Name; UINT8 *Value; } MACRO; // // Keep globals in this structure // static struct { UINT8 BuildDirectory[_MAX_PATH]; UINT8 PrimaryPackagePath[_MAX_PATH]; UINT8 OverridePackagePath[_MAX_PATH]; UINT8 OutputFilePath[_MAX_PATH]; BOOLEAN Verbose; MACRO *MacroList; } mGlobals; static EFI_GUID mZeroGuid = { 0 }; static UINT8 MinFfsDataAlignOverride = 0; static void StripQuotes ( IN OUT CHAR8 *String ) /*++ Routine Description: Removes quotes and/or whitespace from around a string Arguments: String - String to remove quotes from Returns: None --*/ { UINTN Index; UINTN Index2; UINTN StrLen; Index2 = strspn (String, "\" \t\n"); StrLen = strlen (String); for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) { String[Index - Index2] = String[Index]; } String[Index - Index2] = 0; } static void PrintUsage ( void ) /*++ Routine Description: Print Error / Help message. Arguments: void Returns: None --*/ { int Index; const char *Str[] = { UTILITY_NAME" "UTILITY_VERSION" - Intel Generate FFS File Utility", " Copyright (C), 2004 - 2009 Intel Corporation", #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) ) " Built from "UTILITY_BUILD", project of "UTILITY_VENDOR, #endif "", "Usage:", " "UTILITY_NAME" [OPTION]...", "Options:", " -b BuildDirectory Specifies the full path to the component build directory", " -p1 P1Path Specifies fully qualified file name to the primary package", " file. This file will normally exist in the same directory", " as the makefile for the component. Required.", " -p2 P2Path Specifies fully qualified file name to the override", " package. This file will normally exist in the build tip.", " Optional.", " -d Name=Value Add a macro definition for the package file. Optional.", " -o OutputFile Specifies the file name of output file. Optional.", " -v Verbose. Optional.", NULL }; for (Index = 0; Str[Index] != NULL; Index++) { fprintf (stdout, "%s\n", Str[Index]); } } static INT32 TestComment ( IN CHAR8 *String, IN FILE *In ) /*++ Routine Description: Tests input string to see if it is a comment, and if so goes to the next line in the file that is not a comment Arguments: String - String to test In - Open file to move pointer within Returns: -1 - End of file reached 0 - Not a comment 1 - Comment bypassed --*/ { CHAR8 CharBuffer; CharBuffer = 0; if ((String[0] == '/') && (String[1] == '/')) { while (CharBuffer != '\n') { fscanf (In, "%c", &CharBuffer); if (feof (In)) { return -1; } } } else { return 0; } return 1; } static void BreakString ( IN CONST CHAR8 *Source, OUT CHAR8 *Destination, IN INTN Direction ) /*++ Routine Description: Takes an input string and returns either the part before the =, or the part after the =, depending on direction Arguments: Source - String to break Destination - Buffer to place new string in Direction - 0 to return all of source string before = 1 to return all of source string after = Returns: None --*/ { UINTN Index; UINTN Index2; Index = 0; Index2 = 0; if (strchr (Source, '=') == NULL) { strcpy (Destination, Source); return ; } if (Direction == 0) { // // return part of string before = // while (Source[Index] != '=') { Destination[Index] = Source[Index++]; } Destination[Index] = 0; } else { // // return part of string after = // strcpy (Destination, strchr (Source, '=') + 1); } } static INT32 GetNextLine ( OUT CHAR8 *Destination, IN FILE *Package, IN OUT UINT32 *LineNumber ) /*++ Routine Description: Gets the next non-commented line from the file Arguments: Destination - Where to put string Package - Package to get string from LineNumber - The actual line number. Returns: -1 - End of file reached 0 - Success --*/ { CHAR8 String[_MAX_PATH]; fscanf (Package, "%s", &String); if (feof (Package)) { return -1; } while (TestComment (String, Package) == 1) { fscanf (Package, "%s", &String); if (feof (Package)) { return -1; } } strcpy (Destination, String); return 0; } static VOID CheckSlash ( IN OUT CHAR8 *String, IN FILE *In, IN OUT UINT32 *LineNumber ) /*++ Routine Description: Checks to see if string is line continuation character, if so goes to next valid line Arguments: String - String to test In - Open file to move pointer within LineNumber - The line number. Returns: None --*/ { CHAR8 ByteBuffer; ByteBuffer = 0; switch (String[0]) { case '\\': while (String[0] == '\\') { while (ByteBuffer != '\n') { fscanf (In, "%c", &ByteBuffer); } (*LineNumber)++; if (GetNextLine (String, In, LineNumber) == -1) { return ; } } break; case '\n': (*LineNumber)++; while (String[0] == '\n') { if (GetNextLine (String, In, LineNumber) == -1) { return ; } } break; default: break; } } static INT32 FindSectionInPackage ( IN CHAR8 *BuildDirectory, IN FILE *OverridePackage, IN OUT UINT32 *LineNumber ) /*++ Routine Description: Finds the matching section within the package Arguments: BuildDirectory - name of section to find OverridePackage - Package file to search within LineNumber - The line number. Returns: -1 - End of file reached 0 - Success --*/ { CHAR8 String[_MAX_PATH]; CHAR8 NewString[_MAX_PATH]; String[0] = 0; while (strcmp (BuildDirectory, String) != 0) { if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) { return -1; } if (NewString[0] == '[') { if (NewString[strlen (NewString) - 1] != ']') { // // have to construct string. // strcpy (String, NewString + 1); while (1) { fscanf (OverridePackage, "%s", &NewString); if (feof (OverridePackage)) { return -1; } if (NewString[0] != ']') { if (strlen (String) != 0) { strcat (String, " "); } strcat (String, NewString); if (String[strlen (String) - 1] == ']') { String[strlen (String) - 1] = 0; break; } } else { break; } } } else { NewString[strlen (NewString) - 1] = 0; strcpy (String, NewString + 1); } } } return 0; } static EFI_STATUS GenSimpleGuidSection ( IN OUT UINT8 *FileBuffer, IN OUT UINT32 *BufferSize, IN UINT32 DataSize, IN EFI_GUID SignGuid, IN UINT16 GuidedSectionAttributes ) /*++ Routine Description: add GUIDed section header for the data buffer. data stays in same location (overwrites source data). Arguments: FileBuffer - Buffer containing data to sign BufferSize - On input, the size of FileBuffer. On output, the size of actual section data (including added section header). DataSize - Length of data to Sign SignGuid - Guid to be add. GuidedSectionAttributes - The section attribute. Returns: EFI_SUCCESS - Successful EFI_OUT_OF_RESOURCES - Not enough resource. --*/ { UINT32 TotalSize; EFI_GUID_DEFINED_SECTION GuidSectionHeader; UINT8 *SwapBuffer; SwapBuffer = NULL; if (DataSize == 0) { *BufferSize = 0; return EFI_SUCCESS; } TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION); GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED; GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff); GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8); GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16); memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID)); GuidSectionHeader.Attributes = GuidedSectionAttributes; GuidSectionHeader.DataOffset = sizeof (EFI_GUID_DEFINED_SECTION); SwapBuffer = (UINT8 *) malloc (DataSize); if (SwapBuffer == NULL) { return EFI_OUT_OF_RESOURCES; } memcpy (SwapBuffer, FileBuffer, DataSize); memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION)); memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize); // // Make sure section ends on a DWORD boundary // while ((TotalSize & 0x03) != 0) { FileBuffer[TotalSize] = 0; TotalSize++; } *BufferSize = TotalSize; if (SwapBuffer != NULL) { free (SwapBuffer); } return EFI_SUCCESS; } static EFI_STATUS CompressSection ( UINT8 *FileBuffer, UINT32 *BufferSize, UINT32 DataSize, CHAR8 *Type ) /*++ Routine Description: Compress the data and add section header for the compressed data. Compressed data (with section header) stays in same location as the source (overwrites source data). Arguments: FileBuffer - Buffer containing data to Compress BufferSize - On input, the size of FileBuffer. On output, the size of actual compressed data (including added section header). When buffer is too small, this value indicates the size needed. DataSize - The size of data to compress Type - The compression type (not used currently). Assume EFI_HEAVY_COMPRESSION. Returns: EFI_BUFFER_TOO_SMALL - Buffer size is too small. EFI_UNSUPPORTED - Compress type can not be supported. EFI_SUCCESS - Successful EFI_OUT_OF_RESOURCES - Not enough resource. --*/ { EFI_STATUS Status; UINT8 *CompData; UINT32 CompSize; UINT32 TotalSize; EFI_COMPRESSION_SECTION CompressionSet; UINT8 CompressionType; COMPRESS_FUNCTION CompressFunction; Status = EFI_SUCCESS; CompData = NULL; CompSize = 0; TotalSize = 0; CompressFunction = NULL; // // Get the compress type // if (_strcmpi (Type, "Dummy") == 0) { // // Added "Dummy" to keep backward compatibility. // CompressionType = EFI_STANDARD_COMPRESSION; CompressFunction = (COMPRESS_FUNCTION) TianoCompress; } else if (_strcmpi (Type, "LZH") == 0) { // // EFI stardard compression (LZH) // CompressionType = EFI_STANDARD_COMPRESSION; CompressFunction = (COMPRESS_FUNCTION) TianoCompress; } else { // // Customized compression // Status = SetCustomizedCompressionType (Type); if (EFI_ERROR (Status)) { return Status; } CompressionType = EFI_CUSTOMIZED_COMPRESSION; CompressFunction = (COMPRESS_FUNCTION) CustomizedCompress; } // // Compress the raw data // Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize); if (Status == EFI_BUFFER_TOO_SMALL) { CompData = malloc (CompSize); if (!CompData) { return EFI_OUT_OF_RESOURCES; } Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize); } if (EFI_ERROR (Status)) { if (CompData != NULL) { free (CompData); } return Status; } TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION); // // Buffer too small? // if (TotalSize > *BufferSize) { *BufferSize = TotalSize; if (CompData != NULL) { free (CompData); } return EFI_BUFFER_TOO_SMALL; } // // Add the section header for the compressed data // CompressionSet.CommonHeader.Type = EFI_SECTION_COMPRESSION; CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff); CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8); CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16); CompressionSet.CompressionType = CompressionType; CompressionSet.UncompressedLength = DataSize; // // Copy header and data to the buffer // memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION)); memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize); // // Make sure section ends on a DWORD boundary // while ((TotalSize & 0x03) != 0) { FileBuffer[TotalSize] = 0; TotalSize++; } *BufferSize = TotalSize; if (CompData != NULL) { free (CompData); } return EFI_SUCCESS; } static void StripParens ( IN OUT CHAR8 *String ) /*++ Routine Description: Removes Parenthesis from around a string Arguments: String - String to remove parens from Returns: None --*/ { INT32 Index; if (String[0] != '(') { return ; } for (Index = 1; String[Index] != ')'; Index++) { String[Index - 1] = String[Index]; if (String[Index] == 0) { return ; } } String[Index - 1] = 0; return ; } static void StripEqualMark ( IN OUT CHAR8 *String ) /*++ Routine Description: Removes Equal Mark from around a string Arguments: String - String to remove equal mark from Returns: None --*/ { INT32 Index; if (String[0] != '=' && String[strlen (String) - 1] != '=') { return ; } if (String[0] == '=') { for (Index = 1; String[Index] != 0; Index++) { String[Index - 1] = String[Index]; } String[Index - 1] = 0; } if (String[strlen (String) - 1] == '=') { String[strlen (String) - 1] = 0; } return ; } static void SplitAttributesField ( IN CHAR8 *Buffer, IN CHAR8 *AttributesArray[], IN OUT UINT32 *NumberOfAttributes ) /* NumberOfAttributes: on input, it specifies the current number of attributes stored in AttributeArray. on output, it is updated to the latest number of attributes stored in AttributesArray. */ { UINT32 Index; UINT32 Index2; UINT32 z; CHAR8 *CharBuffer; CharBuffer = NULL; CharBuffer = (CHAR8 *) malloc (_MAX_PATH); ZeroMem (CharBuffer, _MAX_PATH); for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) { if (Buffer[Index] != '|') { CharBuffer[z] = Buffer[Index]; z++; } else { CharBuffer[z] = 0; AttributesArray[*NumberOfAttributes + Index2] = CharBuffer; Index2++; // // allocate new char buffer for the next attributes string // CharBuffer = (CHAR8 *) malloc (_MAX_PATH); ZeroMem (CharBuffer, _MAX_PATH); z = 0; } } CharBuffer[z] = 0; // // record the last attributes string in the Buffer // AttributesArray[*NumberOfAttributes + Index2] = CharBuffer; Index2++; *NumberOfAttributes += Index2; return ; } static INT32 GetToolArguments ( CHAR8 *ToolArgumentsArray[], FILE *Package, CHAR8 **PtrInputFileName, CHAR8 **PtrOutputFileName, EFI_GUID *Guid, UINT16 *GuidedSectionAttributes ) { CHAR8 Buffer[_MAX_PATH]; BOOLEAN ArgumentsFlag; BOOLEAN InputFlag; BOOLEAN OutputFlag; BOOLEAN GuidFlag; BOOLEAN AttributesFlag; UINT32 argc; UINT32 Index2; UINT32 z; CHAR8 *CharBuffer; INT32 ReturnValue; EFI_STATUS Status; CHAR8 *AttributesArray[MAX_ARRAY_SIZE]; UINT32 NumberOfAttributes; CHAR8 *InputFileName; CHAR8 *OutputFileName; UINT32 LineNumber; Buffer[_MAX_PATH]; ArgumentsFlag = FALSE; InputFlag = FALSE; OutputFlag = FALSE; GuidFlag = FALSE; AttributesFlag = FALSE; // // Start at 1, since ToolArgumentsArray[0] // is the program name. // argc = 1; Index2 = 0; z = 0; ReturnValue = 0; NumberOfAttributes = 0; InputFileName = NULL; OutputFileName = NULL; ZeroMem (Buffer, _MAX_PATH); ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE); LineNumber = 0; while (Buffer[0] != ')') { if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); StripEqualMark (Buffer); } else { Error (NULL, 0, 0, "failed to get next line from package file", NULL); return -1; } if (Buffer[0] == ')') { break; } else if (_strcmpi (Buffer, "ARGS") == 0) { ArgumentsFlag = TRUE; AttributesFlag = FALSE; continue; } else if (_strcmpi (Buffer, "INPUT") == 0) { InputFlag = TRUE; ArgumentsFlag = FALSE; AttributesFlag = FALSE; continue; } else if (_strcmpi (Buffer, "OUTPUT") == 0) { OutputFlag = TRUE; ArgumentsFlag = FALSE; AttributesFlag = FALSE; continue; } else if (_strcmpi (Buffer, "GUID") == 0) { GuidFlag = TRUE; ArgumentsFlag = FALSE; AttributesFlag = FALSE; // // fetch the GUID for the section // continue; } else if (_strcmpi (Buffer, "ATTRIBUTES") == 0) { AttributesFlag = TRUE; ArgumentsFlag = FALSE; // // fetch the GUIDed Section's Attributes // continue; } else if (_strcmpi (Buffer, "") == 0) { continue; } // // get all command arguments into ToolArgumentsArray // if (ArgumentsFlag) { StripEqualMark (Buffer); CharBuffer = (CHAR8 *) malloc (_MAX_PATH); if (CharBuffer == NULL) { goto ErrorExit; } ZeroMem (CharBuffer, sizeof (_MAX_PATH)); ToolArgumentsArray[argc] = CharBuffer; strcpy (ToolArgumentsArray[argc], Buffer); argc += 1; ToolArgumentsArray[argc] = NULL; continue; } if (InputFlag) { StripEqualMark (Buffer); InputFileName = (CHAR8 *) malloc (_MAX_PATH); if (InputFileName == NULL) { goto ErrorExit; } ZeroMem (InputFileName, sizeof (_MAX_PATH)); strcpy (InputFileName, Buffer); InputFlag = FALSE; continue; } if (OutputFlag) { StripEqualMark (Buffer); OutputFileName = (CHAR8 *) malloc (_MAX_PATH); if (OutputFileName == NULL) { goto ErrorExit; } ZeroMem (OutputFileName, sizeof (_MAX_PATH)); strcpy (OutputFileName, Buffer); OutputFlag = FALSE; continue; } if (GuidFlag) { StripEqualMark (Buffer); Status = StringToGuid (Buffer, Guid); if (EFI_ERROR (Status)) { ReturnValue = -1; goto ErrorExit; } GuidFlag = FALSE; } if (AttributesFlag) { StripEqualMark (Buffer); // // there might be no space between each attribute in the statement, // split them aside and return each attribute string // in the AttributesArray // SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes); } } // // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j); // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1); // for (z = 0; z < NumberOfAttributes; z++) { if (_strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) { *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED; } else if (_strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) { *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID; } } ErrorExit: for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) { if (AttributesArray[Index2] == NULL) { break; } free (AttributesArray[Index2]); } *PtrInputFileName = InputFileName; *PtrOutputFileName = OutputFileName; return ReturnValue; } static INT32 ProcessScript ( IN OUT UINT8 *FileBuffer, IN FILE *Package, IN CHAR8 *BuildDirectory, IN BOOLEAN ForceUncompress ) /*++ Routine Description: Signs the section, data stays in same location Arguments: FileBuffer - Data Buffer Package - Points to curly brace in Image Script BuildDirectory - Name of the source directory parameter ForceUncompress - Whether to force uncompress. Returns: Number of bytes added to file buffer -1 on error --*/ { EFI_STATUS Status; UINT32 Size; UINT32 OldSize; UINT32 Adjust; UINT16 TeStrippedSize; CHAR8 Buffer[_MAX_PATH]; CHAR8 Type[_MAX_PATH]; CHAR8 FileName[_MAX_PATH]; INT32 Index3; INT32 Index2; UINT32 ReturnValue; UINT8 ByteBuffer; FILE *InFile; UINT32 SourceDataSize; CHAR8 *ToolArgumentsArray[MAX_ARRAY_SIZE]; CHAR8 *OutputFileName; CHAR8 *InputFileName; CHAR8 ToolName[_MAX_PATH]; FILE *OutputFile; FILE *InputFile; UINT8 Temp; int returnint; UINT32 LineNumber; BOOLEAN IsError; EFI_GUID SignGuid; UINT16 GuidedSectionAttributes; UINT8 *TargetFileBuffer; OutputFileName = NULL; InputFileName = NULL; OutputFile = NULL; InputFile = NULL; IsError = FALSE; GuidedSectionAttributes = 0; TargetFileBuffer = NULL; Size = 0; LineNumber = 0; Buffer[0] = 0; for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) { ToolArgumentsArray[Index3] = NULL; } while (Buffer[0] != '}') { if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); } else { printf ("ERROR in IMAGE SCRIPT!\n"); IsError = TRUE; goto Done; } if (_strcmpi (Buffer, "Compress") == 0) { // // Handle compress // // // read compression type // if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); } StripParens (Buffer); strcpy (Type, Buffer); // // build buffer // while (Buffer[0] != '{') { if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); } } ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress); if (ReturnValue == -1) { IsError = TRUE; goto Done; } // // Call compress routine on buffer. // Occasionally, compressed data + section header would // be largere than the source and EFI_BUFFER_TOO_SMALL is // returned from CompressSection() // SourceDataSize = ReturnValue; if (!ForceUncompress) { Status = CompressSection ( &FileBuffer[Size], &ReturnValue, SourceDataSize, Type ); if (Status == EFI_BUFFER_TOO_SMALL) { Status = CompressSection ( &FileBuffer[Size], &ReturnValue, SourceDataSize, Type ); } if (EFI_ERROR (Status)) { IsError = TRUE; goto Done; } } Size += ReturnValue; } else if (_strcmpi (Buffer, "Tool") == 0) { ZeroMem (ToolName, _MAX_PATH); ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE); ZeroMem (&SignGuid, sizeof (EFI_GUID)); // // handle signing Tool // while (Buffer[0] != '(') { if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); } } if (_strcmpi (Buffer, "(") == 0) { if (GetNextLine (Buffer, Package, &LineNumber) != -1) { CheckSlash (Buffer, Package, &LineNumber); } } StripParens (Buffer); strcpy (ToolName, Buffer); ToolArgumentsArray[0] = ToolName; // // read ARGS // if (GetToolArguments ( ToolArgumentsArray, Package, &InputFileName, &OutputFileName, &SignGuid, &GuidedSectionAttributes ) == -1) { IsError = TRUE; goto Done; } // // if the tool need input file, // dump the file buffer to the specified input file. // if (InputFileName != NULL) { InputFile = fopen (InputFileName, "wb"); if (InputFile == NULL) { Error (NULL, 0, 0, InputFileName, "failed to open output file for writing"); IsError = TRUE; goto Done; } fwrite (FileBuffer, sizeof (UINT8), Size, InputFile); fclose (InputFile); InputFile = NULL; free (InputFileName); InputFileName = NULL; } // // dispatch signing tool // returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray); if (returnint != 0) { Error (NULL, 0, 0, ToolName, "external tool failed"); IsError = TRUE; goto Done; } // // if the tool has output file, // dump the output file to the file buffer // if (OutputFileName != NULL) { OutputFile = fopen (OutputFileName, "rb"); if (OutputFile == NULL) { Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); IsError = TRUE; goto Done; } TargetFileBuffer = &FileBuffer[Size]; SourceDataSize = Size; fread (&Temp, sizeof (UINT8), 1, OutputFile); while (!feof (OutputFile)) { FileBuffer[Size++] = Temp; fread (&Temp, sizeof (UINT8), 1, OutputFile); } while ((Size & 0x03) != 0) { FileBuffer[Size] = 0; Size++; } SourceDataSize = Size - SourceDataSize; fclose (OutputFile); OutputFile = NULL; free (OutputFileName); OutputFileName = NULL; if (CompareGuid (&SignGuid, &mZeroGuid) != 0) { ReturnValue = SourceDataSize; Status = GenSimpleGuidSection ( TargetFileBuffer, &ReturnValue, SourceDataSize, SignGuid, GuidedSectionAttributes ); if (EFI_ERROR (Status)) { IsError = TRUE; goto Done; } Size = ReturnValue; } } } else if (Buffer[0] != '}') { // // if we are here, we should see either a file name, // or a }. // Index3 = 0; FileName[0] = 0; // // Prepend the build directory to the file name if the // file name does not already contain a full path. // if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) { sprintf (FileName, "%s\\", BuildDirectory); } while (Buffer[Index3] != '\n') { if (Buffer[Index3] == 0) { break; } else { Index2 = strlen (FileName); FileName[Index2++] = Buffer[Index3++]; FileName[Index2] = 0; } } InFile = fopen (FileName, "rb"); if (InFile == NULL) { Error (NULL, 0, 0, FileName, "failed to open file for reading"); IsError = TRUE; goto Done; } OldSize = Size; fread (&ByteBuffer, sizeof (UINT8), 1, InFile); while (!feof (InFile)) { FileBuffer[Size++] = ByteBuffer; fread (&ByteBuffer, sizeof (UINT8), 1, InFile); } fclose (InFile); InFile = NULL; // // Adjust the TE Section for IPF so that the function entries are 16-byte aligned. // if (Size - OldSize >= sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER) && ((EFI_COMMON_SECTION_HEADER *) &FileBuffer[OldSize])->Type == EFI_SECTION_TE && ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->Machine == EFI_IMAGE_MACHINE_IA64) { TeStrippedSize = ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->StrippedSize; Adjust = TeStrippedSize - (OldSize + sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER)); Adjust &= 15; if (Adjust > 0) { memmove (&FileBuffer[OldSize + Adjust], &FileBuffer[OldSize], Size - OldSize); // // Pad with RAW Section type // *(UINT32 *)&FileBuffer[OldSize] = 0x19000000 | Adjust; Size += Adjust; // // Make sure the Data alignment in FFS header is no less than 1 (16-byte aligned) // MinFfsDataAlignOverride = 1; } } // // Make sure section ends on a DWORD boundary // while ((Size & 0x03) != 0) { FileBuffer[Size] = 0; Size++; } } } Done: for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) { if (ToolArgumentsArray[Index3] == NULL) { break; } free (ToolArgumentsArray[Index3]); } if (IsError) { return -1; } return Size; } static UINT8 StringToType ( IN CHAR8 *String ) /*++ Routine Description: Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an unrecognized file type was specified. Arguments: String - File type string Returns: File Type Value --*/ { if (_strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) { return EFI_FV_FILETYPE_RAW; } if (_strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) { return EFI_FV_FILETYPE_FREEFORM; } if (_strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) { return EFI_FV_FILETYPE_SECURITY_CORE; } if (_strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) { return EFI_FV_FILETYPE_PEI_CORE; } if (_strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) { return EFI_FV_FILETYPE_DXE_CORE; } if (_strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) { return EFI_FV_FILETYPE_PEIM; } if (_strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) { return EFI_FV_FILETYPE_DRIVER; } if (_strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) { return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER; } if (_strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) { return EFI_FV_FILETYPE_APPLICATION; } if (_strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) { return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE; } return EFI_FV_FILETYPE_ALL; } static UINT32 AdjustFileSize ( IN UINT8 *FileBuffer, IN UINT32 FileSize ) /*++ Routine Description: Adjusts file size to insure sectioned file is exactly the right length such that it ends on exactly the last byte of the last section. ProcessScript() may have padded beyond the end of the last section out to a 4 byte boundary. This padding is stripped. Arguments: FileBuffer - Data Buffer - contains a section stream FileSize - Size of FileBuffer as returned from ProcessScript() Returns: Corrected size of file. --*/ { UINT32 TotalLength; UINT32 CurrentLength; UINT32 SectionLength; UINT32 SectionStreamLength; EFI_COMMON_SECTION_HEADER *SectionHeader; EFI_COMMON_SECTION_HEADER *NextSectionHeader; TotalLength = 0; CurrentLength = 0; SectionStreamLength = FileSize; SectionHeader = (EFI_COMMON_SECTION_HEADER *) FileBuffer; while (TotalLength < SectionStreamLength) { SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff; TotalLength += SectionLength; if (TotalLength == SectionStreamLength) { return TotalLength; } // // Move to the next byte following the section... // SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength); CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer; // // Figure out where the next section begins // NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3); NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3); TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader; SectionHeader = NextSectionHeader; } return CurrentLength; } static INT32 MainEntry ( INT32 argc, CHAR8 *argv[], BOOLEAN ForceUncompress ) /*++ Routine Description: MainEntry function. Arguments: argc - Number of command line parameters. argv - Array of pointers to command line parameter strings. ForceUncompress - If TRUE, force to do not compress the sections even if compression is specified in the script. Otherwise, FALSE. Returns: STATUS_SUCCESS - Function exits successfully. STATUS_ERROR - Some error occurred during execution. --*/ { FILE *PrimaryPackage; FILE *OverridePackage; FILE *Out; CHAR8 BaseName[_MAX_PATH]; EFI_GUID FfsGuid; CHAR8 GuidString[_MAX_PATH]; EFI_FFS_FILE_HEADER FileHeader; CHAR8 FileType[_MAX_PATH]; EFI_FFS_FILE_ATTRIBUTES FfsAttrib; EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined; UINT64 FfsAlignment; UINT32 FfsAlignment32; CHAR8 InputString[_MAX_PATH]; BOOLEAN ImageScriptInOveride; UINT32 FileSize; UINT8 *FileBuffer; EFI_STATUS Status; UINT32 LineNumber; #if (PI_SPECIFICATION_VERSION < 0x00010000) EFI_FFS_FILE_TAIL TailValue; #endif BaseName[0] = 0; FileType[0] = 0; FfsAttrib = 0; FfsAttribDefined = 0; FfsAlignment = 0; FfsAlignment32 = 0; PrimaryPackage = NULL; Out = NULL; OverridePackage = NULL; FileBuffer = NULL; strcpy (GuidString, "00000000-0000-0000-0000-000000000000"); Status = StringToGuid (GuidString, &FfsGuid); if (Status != 0) { Error (NULL, 0, 0, GuidString, "error parsing GUID string"); return STATUS_ERROR; } GuidString[0] = 0; ImageScriptInOveride = FALSE; // // Initialize the simple file parsing routines. Then open // the primary package file for parsing. // SFPInit (); if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) { Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file"); goto Done; } // // First token in the file must be "PACKAGE.INF" // if (!SFPIsToken ("PACKAGE.INF")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL); goto Done; } // // Find the [.] section // if (!SFPSkipToToken ("[.]")) { Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL); goto Done; } // // Start parsing the data. The algorithm is essentially the same for each keyword: // 1. Identify the keyword // 2. Verify that the keyword/value pair has not already been defined // 3. Set some flag indicating that the keyword/value pair has been defined // 4. Skip over the "=" // 5. Get the value, which may be a number, TRUE, FALSE, or a string. // while (1) { if (SFPIsToken ("BASE_NAME")) { // // Found BASE_NAME, format: // BASE_NAME = MyBaseName // if (BaseName[0] != 0) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL); goto Done; } if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (!SFPGetNextToken (BaseName, sizeof (BaseName))) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL); goto Done; } } else if (SFPIsToken ("IMAGE_SCRIPT")) { // // Found IMAGE_SCRIPT. Break out and process below. // break; } else if (SFPIsToken ("FFS_FILEGUID")) { // // found FILEGUID, format: // FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A // if (GuidString[0] != 0) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL); goto Done; } if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL); goto Done; } Status = StringToGuid (GuidString, &FfsGuid); if (Status != 0) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL); goto Done; } } else if (SFPIsToken ("FFS_FILETYPE")) { // // *********************************************************************** // // Found FFS_FILETYPE, format: // FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION // if (FileType[0] != 0) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL); goto Done; } if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (!SFPGetNextToken (FileType, sizeof (FileType))) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL); goto Done; } } #if (PI_SPECIFICATION_VERSION < 0x00010000) else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) { // // *********************************************************************** // // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE // Spec says the bit is for future expansion, and must be false. // if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) { Error ( mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_HEADER_EXTENSION previously defined", NULL ); goto Done; } FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPIsToken ("TRUE")) { Error ( mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported", NULL ); goto Done; } else if (SFPIsToken ("FALSE")) { // // Default is FALSE // } else { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL); goto Done; } } #else else if (SFPIsToken ("FFS_ATTRIB_FIXED")) { // // *********************************************************************** // // Found: FFS_ATTRIB_FIXED = TRUE | FALSE // if (FfsAttribDefined & FFS_ATTRIB_FIXED) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_FIXED previously defined", NULL); goto Done; } FfsAttribDefined |= FFS_ATTRIB_FIXED; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPIsToken ("TRUE")) { FfsAttrib |= FFS_ATTRIB_FIXED; } else if (SFPIsToken ("FALSE")) { // // Default is FALSE // } else { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); goto Done; } } #endif else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) { // // *********************************************************************** // // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE // if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL); goto Done; } FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPIsToken ("TRUE")) { FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT; } else if (SFPIsToken ("FALSE")) { // // Default is FALSE // } else { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); goto Done; } } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) { // // *********************************************************************** // // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE // if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL); goto Done; } FfsAttribDefined |= FFS_ATTRIB_RECOVERY; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPIsToken ("TRUE")) { FfsAttrib |= FFS_ATTRIB_RECOVERY; } else if (SFPIsToken ("FALSE")) { // // Default is FALSE // } else { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); goto Done; } } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) { // // *********************************************************************** // // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE // if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL); goto Done; } FfsAttribDefined |= FFS_ATTRIB_CHECKSUM; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (SFPIsToken ("TRUE")) { FfsAttrib |= FFS_ATTRIB_CHECKSUM; } else if (SFPIsToken ("FALSE")) { // // Default is FALSE // } else { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); goto Done; } } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) { // // *********************************************************************** // // Found FFS_ALIGNMENT, formats: // FFS_ALIGNMENT = 0-7 // FFS_ATTRIB_DATA_ALIGNMENT = 0-7 // if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) { Error ( mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined", NULL ); goto Done; } FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT; if (!SFPIsToken ("=")) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL); goto Done; } if (!SFPGetNumber (&FfsAlignment32)) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL); goto Done; } if (FfsAlignment32 > 7) { Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL); goto Done; } FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3); } else { SFPGetNextToken (InputString, sizeof (InputString)); Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token"); goto Done; } } // // Close the primary package file // SFPCloseFile (); // // TODO: replace code below with basically a copy of the code above. Don't // forget to reset the FfsAttribDefined variable first. Also, you'll need // to somehow keep track of whether or not the basename is defined multiple // times in the override package. Ditto on the file GUID. // if (mGlobals.OverridePackagePath[0] != 0) { OverridePackage = fopen (mGlobals.OverridePackagePath, "r"); // // NOTE: For package override to work correctly, the code below must be modified to // SET or CLEAR bits properly. For example, if the primary package set // FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then // we'd need to clear the bit below. Since this is not happening, I'm guessing that // the override functionality is not being used, so should be made obsolete. If I'm // wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is // used, and we'll address it then. 4/10/2003 // Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL); goto Done; } else { OverridePackage = NULL; } #ifdef OVERRIDE_SUPPORTED if (OverridePackage != NULL) { // // Parse override package file // fscanf (OverridePackage, "%s", &InputString); if (_strcmpi (InputString, "PACKAGE.INF") != 0) { Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'"); goto Done; } // // Match [dir] to Build Directory // if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) { Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file"); goto Done; } InputString[0] = 0; while ((InputString[0] != '[') && (!feof (OverridePackage))) { if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) { if (InputString[0] != '[') { here: if (_strcmpi (InputString, "BASE_NAME") == 0) { // // found BASE_NAME, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); strcpy (BaseName, InputString); } else { BreakString (InputString, InputString, 1); strcpy (BaseName, InputString); } } else if (_strcmpi (InputString, "IMAGE_SCRIPT") == 0) { // // found IMAGE_SCRIPT, come back later to process it // ImageScriptInOveride = TRUE; fscanf (OverridePackage, "%s", &InputString); } else if (_strcmpi (InputString, "FFS_FILEGUID") == 0) { // // found FILEGUID, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); Status = StringToGuid (InputString, &FfsGuid); if (Status != 0) { Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format"); goto Done; } } else { BreakString (InputString, InputString, 1); Status = StringToGuid (InputString, &FfsGuid); if (Status != 0) { Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format"); goto Done; } } } else if (_strcmpi (InputString, "FFS_FILETYPE") == 0) { // // found FILETYPE, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); strcpy (FileType, InputString); } else { BreakString (InputString, InputString, 1); strcpy (FileType, InputString); } } else if (_strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) { // // found FFS_ATTRIB_RECOVERY, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (_strcmpi (InputString, "TRUE") == 0) { FfsAttrib |= FFS_ATTRIB_RECOVERY; } } else { BreakString (InputString, InputString, 1); if (_strcmpi (InputString, "TRUE") == 0) { FfsAttrib |= FFS_ATTRIB_RECOVERY; } } } else if (_strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) { // // found FFS_ATTRIB_CHECKSUM, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (_strcmpi (InputString, "TRUE") == 0) { FfsAttrib |= FFS_ATTRIB_CHECKSUM; } } else { BreakString (InputString, InputString, 1); if (_strcmpi (InputString, "TRUE") == 0) { FfsAttrib |= FFS_ATTRIB_CHECKSUM; } } } else if (_strcmpi (InputString, "FFS_ALIGNMENT") == 0) { // // found FFS_ALIGNMENT, next is = and string. // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); if (strlen (InputString) == 1) { // // string is just = // fscanf (OverridePackage, "%s", &InputString); CheckSlash (InputString, OverridePackage, &LineNumber); } else { BreakString (InputString, InputString, 1); } AsciiStringToUint64 (InputString, FALSE, &FfsAlignment); if (FfsAlignment > 7) { Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value"); goto Done; } FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3); } else if (strchr (InputString, '=') != NULL) { BreakString (InputString, String, 1); fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR); BreakString (InputString, InputString, 0); goto here; } } } } } #endif // #ifdef OVERRIDE_SUPPORTED // // Require that they specified a file GUID at least, since that's how we're // naming the file. // if (GuidString[0] == 0) { Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL); return STATUS_ERROR; } // // Build Header and process image script // FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8)); if (FileBuffer == NULL) { Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL); goto Done; } FileSize = 0; if (ImageScriptInOveride) { #ifdef OVERRIDE_SUPPORTED rewind (OverridePackage); LineNumber = 0; FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber); while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) { GetNextLine (InputString, OverridePackage, &LineNumber); CheckSlash (InputString, OverridePackage, &LineNumber); if (strchr (InputString, '=') != NULL) { BreakString (InputString, InputString, 0); } } while (InputString[0] != '{') { GetNextLine (InputString, OverridePackage, &LineNumber); CheckSlash (InputString, OverridePackage, &LineNumber); } // // Found start of image script, process it // FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress); if (FileSize == -1) { Error (NULL, 0, 0, "failed to process script", NULL); goto Done; } if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) { FileSize = AdjustFileSize (FileBuffer, FileSize); } if (BaseName[0] == '\"') { StripQuotes (BaseName); } if (mGlobals.OutputFilePath[0]) { // // Use user specified output file name // strcpy (InputString, mGlobals.OutputFilePath); } else { // // Construct the output file name according to FileType // if (BaseName[0] != 0) { sprintf (InputString, "%s-%s", GuidString, BaseName); } else { strcpy (InputString, GuidString); } switch (StringToType (FileType)) { case EFI_FV_FILETYPE_SECURITY_CORE: strcat (InputString, ".SEC"); break; case EFI_FV_FILETYPE_PEIM: case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: strcat (InputString, ".PEI"); break; case EFI_FV_FILETYPE_DRIVER: case EFI_FV_FILETYPE_DXE_CORE: strcat (InputString, ".DXE"); break; case EFI_FV_FILETYPE_APPLICATION: strcat (InputString, ".APP"); break; case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: strcat (InputString, ".FVI"); break; case EFI_FV_FILETYPE_RAW: strcat (InputString, ".RAW"); break; case EFI_FV_FILETYPE_ALL: Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL); goto Done; default: strcat (InputString, ".FFS"); break; } } if (ForceUncompress) { strcat (InputString, ".ORG"); } Out = fopen (InputString, "wb"); if (Out == NULL) { Error (NULL, 0, 0, InputString, "could not open output file for writing"); goto Done; } // // create ffs header // memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID)); FileHeader.Type = StringToType (FileType); if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) { FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3); } FileHeader.Attributes = FfsAttrib; // // Now FileSize includes the EFI_FFS_FILE_HEADER // FileSize += sizeof (EFI_FFS_FILE_HEADER); FileHeader.Size[0] = (UINT8) (FileSize & 0xFF); FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); // // Fill in checksums and state, these must be zero for checksumming // // FileHeader.IntegrityCheck.Checksum.Header = 0; // FileHeader.IntegrityCheck.Checksum.File = 0; // FileHeader.State = 0; // FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 ( (UINT8 *) &FileHeader, sizeof (EFI_FFS_FILE_HEADER) ); if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { #if (PI_SPECIFICATION_VERSION < 0x00010000) FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize); #else FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) ((UINTN)&FileHeader + sizeof (EFI_FFS_FILE_HEADER)), FileSize - sizeof (EFI_FFS_FILE_HEADER)); #endif } else { FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; } FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; // // write header // if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) { Error (NULL, 0, 0, "failed to write file header to output file", NULL); goto Done; } // // write data // if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) { Error (NULL, 0, 0, "failed to write all bytes to output file", NULL); goto Done; } fclose (Out); Out = NULL; #endif // #ifdef OVERRIDE_SUPPORTED } else { // // Open primary package file and process the IMAGE_SCRIPT section // PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r"); if (PrimaryPackage == NULL) { Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file"); goto Done; } LineNumber = 1; FindSectionInPackage (".", PrimaryPackage, &LineNumber); while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) { GetNextLine (InputString, PrimaryPackage, &LineNumber); CheckSlash (InputString, PrimaryPackage, &LineNumber); if (strchr (InputString, '=') != NULL) { BreakString (InputString, InputString, 0); } } while (InputString[0] != '{') { GetNextLine (InputString, PrimaryPackage, &LineNumber); CheckSlash (InputString, PrimaryPackage, &LineNumber); } // // Found start of image script, process it // FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress); if (FileSize == -1) { Error (NULL, 0, 0, "failed to process script", NULL); goto Done; } if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) { FileSize = AdjustFileSize (FileBuffer, FileSize); } if (BaseName[0] == '\"') { StripQuotes (BaseName); } if (mGlobals.OutputFilePath[0]) { // // Use user specified output file name // strcpy (InputString, mGlobals.OutputFilePath); } else { // // Construct the output file name according to FileType // if (BaseName[0] != 0) { sprintf (InputString, "%s-%s", GuidString, BaseName); } else { strcpy (InputString, GuidString); } switch (StringToType (FileType)) { case EFI_FV_FILETYPE_SECURITY_CORE: strcat (InputString, ".SEC"); break; case EFI_FV_FILETYPE_PEIM: case EFI_FV_FILETYPE_PEI_CORE: case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: strcat (InputString, ".PEI"); break; case EFI_FV_FILETYPE_DRIVER: case EFI_FV_FILETYPE_DXE_CORE: strcat (InputString, ".DXE"); break; case EFI_FV_FILETYPE_APPLICATION: strcat (InputString, ".APP"); break; case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: strcat (InputString, ".FVI"); break; case EFI_FV_FILETYPE_RAW: strcat (InputString, ".RAW"); break; case EFI_FV_FILETYPE_ALL: Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL); goto Done; default: strcat (InputString, ".FFS"); break; } } if (ForceUncompress) { strcat (InputString, ".ORG"); } Out = fopen (InputString, "wb"); if (Out == NULL) { Error (NULL, 0, 0, InputString, "failed to open output file for writing"); goto Done; } // // Initialize the FFS file header // memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER)); memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID)); FileHeader.Type = StringToType (FileType); if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) { FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3); } FileHeader.Attributes = FfsAttrib; // // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER // FileSize += sizeof (EFI_FFS_FILE_HEADER); // // If using a tail, then it adds two bytes // if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { // // Tail is not allowed for pad and 0-length files // if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) { Error ( mGlobals.PrimaryPackagePath, 1, 0, "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files", NULL ); goto Done; } FileSize += sizeof (EFI_FFS_FILE_TAIL); } FileHeader.Size[0] = (UINT8) (FileSize & 0xFF); FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); // // Fill in checksums and state, they must be 0 for checksumming. // // FileHeader.IntegrityCheck.Checksum.Header = 0; // FileHeader.IntegrityCheck.Checksum.File = 0; // FileHeader.State = 0; // FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 ( (UINT8 *) &FileHeader, sizeof (EFI_FFS_FILE_HEADER) ); if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { // // Cheating here. Since the header checksums, just calculate the checksum of the body. // Checksum does not include the tail // if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL) ); } else { FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER) ); } } else { FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; } // // Set the state now. Spec says the checksum assumes the state is 0 // FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; #if (PI_SPECIFICATION_VERSION < 0x00010000) // // If there is a tail, then set it // if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) { TailValue = FileHeader.IntegrityCheck.TailReference; TailValue = (UINT16) (~TailValue); memcpy ( (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL), &TailValue, sizeof (TailValue) ); } #endif // // Write the FFS file header // if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) { Error (NULL, 0, 0, "failed to write file header contents", NULL); goto Done; } // // Write data // if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) { Error (NULL, 0, 0, "failed to write file contents", NULL); goto Done; } } Done: SFPCloseFile (); if (Out != NULL) { fclose (Out); } if (PrimaryPackage != NULL) { fclose (PrimaryPackage); } if (FileBuffer != NULL) { free (FileBuffer); } if (OverridePackage != NULL) { fclose (OverridePackage); } return GetUtilityStatus (); } int main ( INT32 argc, CHAR8 *argv[] ) /*++ Routine Description: Main function. Arguments: argc - Number of command line parameters. argv - Array of pointers to parameter strings. Returns: STATUS_SUCCESS - Utility exits successfully. STATUS_ERROR - Some error occurred during execution. --*/ { STATUS Status; // // Set the name of our utility for error reporting purposes. // SetUtilityName (UTILITY_NAME); Status = ProcessCommandLineArgs (argc, argv); FreeMacros (); if (Status != STATUS_SUCCESS) { return Status; } Status = MainEntry (argc, argv, TRUE); if (Status == STATUS_SUCCESS) { MainEntry (argc, argv, FALSE); } // // If any errors were reported via the standard error reporting // routines, then the status has been saved. Get the value and // return it to the caller. // return GetUtilityStatus (); } static STATUS ProcessCommandLineArgs ( int Argc, char *Argv[] ) /*++ Routine Description: Process the command line arguments. Arguments: Argc - as passed in to main() Argv - as passed in to main() Returns: STATUS_SUCCESS - arguments all ok STATUS_ERROR - problem with args, so caller should exit --*/ { STATUS Status; UINT8 *OriginalPrimaryPackagePath; UINT8 *OriginalOverridePackagePath; UINT8 *PackageName; // // If no args, then print usage instructions and return an error // if (Argc == 1) { PrintUsage (); return STATUS_ERROR; } OriginalPrimaryPackagePath = NULL; OriginalOverridePackagePath = NULL; memset (&mGlobals, 0, sizeof (mGlobals)); Argc--; Argv++; while (Argc > 0) { if (_strcmpi (Argv[0], "-b") == 0) { // // OPTION: -b BuildDirectory // Make sure there is another argument, then save it to our globals. // if (Argc < 2) { Error (NULL, 0, 0, "-b option requires the build directory name", NULL); return STATUS_ERROR; } if (mGlobals.BuildDirectory[0]) { Error (NULL, 0, 0, Argv[0], "option can only be specified once"); return STATUS_ERROR; } strcpy (mGlobals.BuildDirectory, Argv[1]); Argc--; Argv++; } else if (_strcmpi (Argv[0], "-p1") == 0) { // // OPTION: -p1 PrimaryPackageFile // Make sure there is another argument, then save it to our globals. // if (Argc < 2) { Error (NULL, 0, 0, Argv[0], "option requires the primary package file name"); return STATUS_ERROR; } if (OriginalPrimaryPackagePath) { Error (NULL, 0, 0, Argv[0], "option can only be specified once"); return STATUS_ERROR; } OriginalPrimaryPackagePath = Argv[1]; Argc--; Argv++; } else if (_strcmpi (Argv[0], "-p2") == 0) { // // OPTION: -p2 OverridePackageFile // Make sure there is another argument, then save it to our globals. // if (Argc < 2) { Error (NULL, 0, 0, Argv[0], "option requires the override package file name"); return STATUS_ERROR; } if (OriginalOverridePackagePath) { Error (NULL, 0, 0, Argv[0], "option can only be specified once"); return STATUS_ERROR; } OriginalOverridePackagePath = Argv[1]; Argc--; Argv++; } else if (_strcmpi (Argv[0], "-o") == 0) { // // OPTION: -o OutputFilePath // Make sure there is another argument, then save it to out globals. // if (Argc < 2) { Error (NULL, 0, 0, Argv[0], "option requires the output file name"); return STATUS_ERROR; } if (mGlobals.OutputFilePath[0]) { Error (NULL, 0, 0, Argv[0], "option can only be specified once"); return STATUS_ERROR; } strcpy (mGlobals.OutputFilePath, Argv[1]); Argc--; Argv++; } else if (_strcmpi (Argv[0], "-v") == 0) { // // OPTION: -v verbose // mGlobals.Verbose = TRUE; } else if (_strcmpi (Argv[0], "-d") == 0) { // // OPTION: -d name=value // Make sure there is another argument, then add it to our macro list. // if (Argc < 2) { Error (NULL, 0, 0, Argv[0], "option requires the macro definition"); return STATUS_ERROR; } AddMacro (Argv[1]); Argc--; Argv++; } else if (_strcmpi (Argv[0], "-h") == 0) { // // OPTION: -h help // PrintUsage (); return STATUS_ERROR; } else if (_strcmpi (Argv[0], "-?") == 0) { // // OPTION: -? help // PrintUsage (); return STATUS_ERROR; } else { Error (NULL, 0, 0, Argv[0], "unrecognized option"); PrintUsage (); return STATUS_ERROR; } Argv++; Argc--; } // // Must have at least specified the build directory // if (!mGlobals.BuildDirectory[0]) { Error (NULL, 0, 0, "must specify build directory", NULL); return STATUS_ERROR; } // // Must have at least specified the package file name // if (OriginalPrimaryPackagePath == NULL) { Error (NULL, 0, 0, "must specify primary package file", NULL); return STATUS_ERROR; } PackageName = OriginalPrimaryPackagePath + strlen (OriginalPrimaryPackagePath); while ((*PackageName != '\\') && (*PackageName != '/') && (PackageName != OriginalPrimaryPackagePath)) { PackageName--; } // // Skip the '\' or '/' // if (PackageName != OriginalPrimaryPackagePath) { PackageName++; } sprintf (mGlobals.PrimaryPackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName); Status = ReplaceMacros (OriginalPrimaryPackagePath, mGlobals.PrimaryPackagePath); if (Status == STATUS_WARNING) { // // No macro replacement, use the previous package file // strcpy (mGlobals.PrimaryPackagePath, OriginalPrimaryPackagePath); } else if (Status != STATUS_SUCCESS) { return Status; } if (OriginalOverridePackagePath != NULL) { PackageName = OriginalOverridePackagePath + strlen (OriginalOverridePackagePath); while ((*PackageName != '\\') && (*PackageName != '/') && (PackageName != OriginalOverridePackagePath)) { PackageName--; } // // Skip the '\' or '/' // if (PackageName != OriginalOverridePackagePath) { PackageName++; } sprintf (mGlobals.OverridePackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName); Status = ReplaceMacros (OriginalOverridePackagePath, mGlobals.OverridePackagePath); if (Status == STATUS_WARNING) { // // No macro replacement, use the previous package file // strcpy (mGlobals.OverridePackagePath, OriginalOverridePackagePath); } else if (Status != STATUS_SUCCESS) { return Status; } } return STATUS_SUCCESS; } static void AddMacro ( UINT8 *MacroString ) /*++ Routine Description: Add or override a macro definition. Arguments: MacroString - macro definition string: name=value Returns: None --*/ { MACRO *Macro; MACRO *NewMacro; UINT8 *Value; // // Seperate macro name and value by '\0' // for (Value = MacroString; *Value && (*Value != '='); Value++); if (*Value == '=') { *Value = '\0'; Value ++; } // // We now have a macro name and value. // Look for an existing macro and overwrite it. // Macro = mGlobals.MacroList; while (Macro) { if (_strcmpi (MacroString, Macro->Name) == 0) { Macro->Value = Value; return; } Macro = Macro->Next; } // // Does not exist, create a new one // NewMacro = (MACRO *) malloc (sizeof (MACRO)); memset ((UINT8 *) NewMacro, 0, sizeof (MACRO)); NewMacro->Name = MacroString; NewMacro->Value = Value; // // Add it to the head of the list. // NewMacro->Next = mGlobals.MacroList; mGlobals.MacroList = NewMacro; return; } static UINT8 * GetMacroValue ( UINT8 *MacroName ) /*++ Routine Description: Look up a macro. Arguments: MacroName - The name of macro Returns: Pointer to the value of the macro if found NULL if the macro is not found --*/ { MACRO *Macro; UINT8 *Value; // // Scan for macro // Macro = mGlobals.MacroList; while (Macro) { if (_strcmpi (MacroName, Macro->Name) == 0) { return Macro->Value; } Macro = Macro->Next; } // // Try environment variable // Value = getenv (MacroName); if (Value == NULL) { printf ("Environment variable %s not found!\n", MacroName); } return Value; } static void FreeMacros ( ) /*++ Routine Description: Free the macro list. Arguments: None Returns: None --*/ { MACRO *Macro; MACRO *NextMacro; Macro = mGlobals.MacroList; while (Macro) { NextMacro = Macro->Next; free (Macro); Macro = NextMacro; } mGlobals.MacroList = NULL; return; } static STATUS ReplaceMacros ( UINT8 *InputFile, UINT8 *OutputFile ) /*++ Routine Description: Replace all the macros in InputFile to create the OutputFile. Arguments: InputFile - Input package file for macro replacement OutputFile - Output package file after macro replacement Returns: STATUS_SUCCESS - Output package file is created successfully after the macro replacement. STATUS_WARNING - Output package file is not created because of no macro replacement. STATUS_ERROR - Some error occurred during execution. --*/ { FILE *Fptr; UINT8 *SaveStart; UINT8 *FromPtr; UINT8 *ToPtr; UINT8 *Value; UINT8 *FileBuffer; UINTN FileSize; // // Get the file size, and then read the entire thing into memory. // Allocate extra space for a terminator character. // if ((Fptr = fopen (InputFile, "r")) == NULL) { Error (NULL, 0, 0, InputFile, "can't open input file"); return STATUS_ERROR; } fseek (Fptr, 0, SEEK_END); FileSize = ftell (Fptr); fseek (Fptr, 0, SEEK_SET); FileBuffer = malloc (FileSize + 1); if (FileBuffer == NULL) { fclose (Fptr); Error (NULL, 0, 0, InputFile, "file buffer memory allocation failure"); return STATUS_ERROR; } fread (FileBuffer, FileSize, 1, Fptr); FileBuffer[FileSize] = '\0'; fclose (Fptr); // // Walk the entire file, replacing $(MACRO_NAME). // Fptr = NULL; FromPtr = FileBuffer; SaveStart = FromPtr; while (*FromPtr) { if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) { FromPtr += 2; for (ToPtr = FromPtr; *ToPtr && (*ToPtr != ')'); ToPtr++); if (*ToPtr) { // // Find an $(MACRO_NAME), replace it // *ToPtr = '\0'; Value = GetMacroValue (FromPtr); *(FromPtr-2)= '\0'; if (Fptr == NULL) { if ((Fptr = fopen (OutputFile, "w")) == NULL) { free (FileBuffer); Error (NULL, 0, 0, OutputFile, "can't open output file"); return STATUS_ERROR; } } if (Value != NULL) { fprintf (Fptr, "%s%s", SaveStart, Value); } else { fprintf (Fptr, "%s", SaveStart); } // // Continue macro replacement for the remaining string line // FromPtr = ToPtr+1; SaveStart = FromPtr; continue; } else { break; } } else { FromPtr++; } } if (Fptr != NULL) { fprintf (Fptr, "%s", SaveStart); } free (FileBuffer); if (Fptr != NULL) { fclose (Fptr); return STATUS_SUCCESS; } else { return STATUS_WARNING; } }