/*++ 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: HiiPack.c Abstract: Process HII export and pack files and create HII export files, dumps, or variable defaults packs. --*/ #include #include #include #include #include "Tiano.h" #include "EfiUtilityMsgs.h" #include "ParseInf.h" #include "EfiInternalFormRepresentation.h" #include "HiiPack.h" #include "Hii.h" #include "IfrParse.h" #include "StringParse.h" #define UTILITY_VERSION "v1.0" #define UTILITY_NAME "HiiPack" #define MAX_PATH 260 // // We may have to create an empty IFR formset to provide a GUID for an HII // export pack. Create a structure definition to make it easier. // #pragma pack(1) typedef struct { EFI_HII_IFR_PACK PackHeader; EFI_IFR_FORM_SET Formset; EFI_IFR_END_FORM_SET EndFormset; } EMPTY_FORMSET_PACK; #pragma pack() // // We'll store lists of file names from the command line in // a linked list of these // typedef struct _FILE_NAME_LIST { struct _FILE_NAME_LIST *Next; UINT8 FileName[MAX_PATH]; int Tag; // used for whatever } FILE_NAME_LIST; // // When merging HII export packs, we save HII data table headers in a linked // list of these. // typedef struct _DATA_TABLE_HEADER_LIST { struct _DATA_TABLE_HEADER_LIST *Next; EFI_HII_DATA_TABLE DataTableHeader; } DATA_TABLE_HEADER_LIST; // // Create some defines for the different operation modes supported by this utility // #define MODE_CREATE_HII_EXPORT 1 #define MODE_MERGE_HII_EXPORTS 2 #define MODE_EMIT_DEFAULTS 3 #define MODE_DUMP_HII_EXPORT 4 // // Here's all our globals. // static struct { FILE_NAME_LIST *PackFileNames; // Input HII pack file names FILE_NAME_LIST *HiiExportFileNames; // Input files when merging CHAR8 OutputFileName[MAX_PATH]; // Output dump file BOOLEAN MfgFlag; // From -mfg command line arg BOOLEAN NoEmptyVarPacks; // From -noemptyvarpacks command line arg BOOLEAN NoVarPacks; // From -novarpacks command line arg EFI_GUID Guid; // Guid specified on command line BOOLEAN GuidSpecified; BOOLEAN DumpStrings; // In dump mode, dump string data int Verbose; int Mode; // Mode this utility is operating in } mGlobals; static void Usage ( VOID ); static STATUS ProcessArgs ( int Argc, char *Argv[] ); static STATUS DumpHiiExportFile ( char *HiiExportFileName, char *OutputFileName ); static void DumpString ( FILE *OutFptr, int StringIndex, CHAR16 *Str, int Indent ); static void DumpStringPack ( FILE *OutFptr, EFI_HII_STRING_PACK *Pack, int BaseOffset, int Indent ); static void DumpVariablePacks ( FILE *OutFptr, EFI_HII_VARIABLE_PACK *Pack, int NumPacks, int BaseOffset, int Indent ); static void TestDumpHiiPack ( FILE *OutFptr, char *BufferStart, int BufferSize ); static void DumpRawBytes ( FILE *OutFptr, char *Buffer, int Count, int BaseOffset, int Indent ); static void DumpIfrPack ( FILE *OutFptr, EFI_HII_IFR_PACK *Pack, int BaseOffset, int Indent ); static void FreeGlobals ( VOID ); static STATUS AddStringPack ( EFI_HII_STRING_PACK *PackHeader ); static STATUS ProcessHiiExportFile ( char *FileName, int MfgDefaults ); static STATUS ProcessIfrFiles ( FILE_NAME_LIST *FileName ); static STATUS EmitDefaults ( FILE_NAME_LIST *HiiExportFiles, int MfgDefaults, int NoEmptyVarPacks ); static STATUS MergeHiiExports ( FILE_NAME_LIST *HiiExportFiles, char *OutputFileName, int MfgDefaults, int NoEmptyVarPacks ); void GuidToString ( EFI_GUID *Guid, char *Str ); static CHAR16 * AsciiToWchar ( CHAR8 *Str ); static STATUS CreateHiiExport ( char *OutputFileName, EFI_GUID *DummyFormsetGuid, FILE_NAME_LIST *PackFiles, int MfgDefaults ); int main ( int Argc, char *Argv[] ) /*++ Routine Description: Call the routine to parse the command-line options, then process the file. Arguments: Standard C main() argc and argv. Returns: 0 if successful nonzero otherwise --*/ // GC_TODO: Argc - add argument and description to function comment // GC_TODO: ] - add argument and description to function comment { STATUS Status; // // Set the utility name for error reporting purposes // SetUtilityName (UTILITY_NAME); // // Process the command-line arguments // Status = ProcessArgs (Argc, Argv); if (Status != STATUS_SUCCESS) { return Status; } // // Switch based on whether we're dumping, merging, etc. // if (mGlobals.Mode == MODE_DUMP_HII_EXPORT) { if (mGlobals.Verbose) { fprintf (stdout, "Dumping HII export file %s => %s\n", mGlobals.HiiExportFileNames, mGlobals.OutputFileName); } DumpHiiExportFile (mGlobals.HiiExportFileNames->FileName, mGlobals.OutputFileName); } else if (mGlobals.Mode == MODE_CREATE_HII_EXPORT) { CreateHiiExport (mGlobals.OutputFileName, &mGlobals.Guid, mGlobals.PackFileNames, mGlobals.MfgFlag); } else if (mGlobals.Mode == MODE_MERGE_HII_EXPORTS) { MergeHiiExports (mGlobals.HiiExportFileNames, mGlobals.OutputFileName, mGlobals.MfgFlag, mGlobals.NoEmptyVarPacks); } else if (mGlobals.Mode == MODE_EMIT_DEFAULTS) { EmitDefaults (mGlobals.HiiExportFileNames, mGlobals.MfgFlag, mGlobals.NoEmptyVarPacks); } // // FreeGlobals (); IfrParseEnd (); StringEnd (); return GetUtilityStatus (); } /******************************************************************************/ static STATUS MergeHiiExports ( FILE_NAME_LIST *HiiExportFiles, char *OutputFileName, int MfgDefaults, int NoEmptyVarPacks ) /*++ Routine Description: Given a linked list of input HII export pack files, read in the contents of each and create a single HII export pack that contains the contents of all the input files. Arguments: HiiExportFiles - pointer to linked list of input HII export pack file names OutputFileName - name of output (merged) HII export file MfgDefaults - non-zero to emit manufacturing defaults in output file NoEmptyVarPacks - non-zero to not emit 0-length variable packs to the output file Returns: STATUS_SUCCESS - if successful STATUS_ERROR - otherwise --*/ { EFI_HII_HANDLE HiiHandle; FILE *OutFptr; FILE *InFptr; STATUS Status; CHAR8 *Buffer; int FileSize; int DataTableIndex; int Count; int NumDataTables; EFI_HII_EXPORT_TABLE *HiiExportTableHeader; EFI_HII_EXPORT_TABLE TempHiiExportTableHeader; EFI_HII_DATA_TABLE *DataTableHeader; EFI_HII_STRING_PACK *StringPack; EFI_HII_VARIABLE_PACK *VarPack; EFI_HII_IFR_PACK *IfrPack; EFI_GUID HiiExportRevisionGuid = EFI_HII_PROTOCOL_GUID; EFI_GUID PackageGuid; EFI_GUID FormsetGuid; long DataTableHeaderOffset; DATA_TABLE_HEADER_LIST *DataTableList; DATA_TABLE_HEADER_LIST *LastDataTable; DATA_TABLE_HEADER_LIST *TempDataTable; // // Init locals // HiiHandle = FIRST_HII_PACK_HANDLE; Buffer = NULL; InFptr = NULL; OutFptr = NULL; Status = STATUS_ERROR; DataTableList = NULL; LastDataTable = NULL; // // Initialize our IFR parser and string routines // IfrParseInit (); StringInit (); // // Process each input HII export file // NumDataTables = 0; while (HiiExportFiles != NULL) { if (mGlobals.Verbose) { fprintf (stdout, "Processing file %s\n", HiiExportFiles->FileName); } // // Read in the entire file contents // if ((InFptr = fopen (HiiExportFiles->FileName, "rb")) == NULL) { Error (NULL, 0, 0, HiiExportFiles->FileName, "failed to open HII export file for reading"); goto Done; } fseek (InFptr, 0, SEEK_END); FileSize = (int) ftell (InFptr); fseek (InFptr, 0, SEEK_SET); Buffer = (CHAR8 *) malloc (FileSize); if (Buffer == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); goto Done; } if (fread (Buffer, FileSize, 1, InFptr) != 1) { Error (NULL, 0, 0, HiiExportFiles->FileName, "failed to read file contents"); goto Done; } fclose (InFptr); InFptr = NULL; HiiExportTableHeader = (EFI_HII_EXPORT_TABLE *) Buffer; // // Walk all the data tables // DataTableHeader = (EFI_HII_DATA_TABLE *) (HiiExportTableHeader + 1); for (DataTableIndex = 0; DataTableIndex < (int) HiiExportTableHeader->NumberOfHiiDataTables; DataTableIndex++) { NumDataTables++; // // Make sure we're still pointing into our buffer // if (((char *) DataTableHeader < Buffer) || ((char *) DataTableHeader > Buffer + FileSize)) { Error (NULL, 0, 0, "bad data table size in input file", NULL); goto Done; } // // Save a copy of the data table header // TempDataTable = (DATA_TABLE_HEADER_LIST *) malloc (sizeof (DATA_TABLE_HEADER_LIST)); if (TempDataTable == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); goto Done; } memset ((void *) TempDataTable, 0, sizeof (DATA_TABLE_HEADER_LIST)); memcpy (&TempDataTable->DataTableHeader, DataTableHeader, sizeof (EFI_HII_DATA_TABLE)); if (DataTableList == NULL) { DataTableList = TempDataTable; } else { LastDataTable->Next = TempDataTable; } LastDataTable = TempDataTable; // // If there is an IFR pack, parse it // if (DataTableHeader->IfrDataOffset != 0) { if (IfrParsePack ( HiiHandle, (EFI_HII_IFR_PACK *) ((char *) DataTableHeader + DataTableHeader->IfrDataOffset), &DataTableHeader->PackageGuid ) != STATUS_SUCCESS ) { goto Done; } } // // If there is string data, save it // if (DataTableHeader->StringDataOffset != 0) { Status = StringParsePack ( HiiHandle, (EFI_HII_STRING_PACK *) ((char *) DataTableHeader + DataTableHeader->StringDataOffset), NULL, &DataTableHeader->PackageGuid ); if (Status != STATUS_SUCCESS) { goto Done; } } // // If there is device path data, process it // if (DataTableHeader->DevicePathOffset != 0) { Error (NULL, 0, 0, "application error", "%s contains unsupported device path data", HiiExportFiles->FileName); goto Done; } // // Next data pack // DataTableHeader = (EFI_HII_DATA_TABLE *) ((char *) DataTableHeader + DataTableHeader->DataTableSize); HiiHandle++; } free (Buffer); Buffer = NULL; // // Next input file // HiiExportFiles = HiiExportFiles->Next; } // // Now create defaults // if (IfrSetDefaults (MfgDefaults) != STATUS_SUCCESS) { goto Done; } // // Create and write the output HII export header // if ((OutFptr = fopen (OutputFileName, "wb")) == NULL) { Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); goto Done; } memset ((void *) &TempHiiExportTableHeader, 0, sizeof (EFI_HII_EXPORT_TABLE)); TempHiiExportTableHeader.NumberOfHiiDataTables = HiiHandle - FIRST_HII_PACK_HANDLE; memcpy (&TempHiiExportTableHeader.Revision, &HiiExportRevisionGuid, sizeof (EFI_GUID)); if (fwrite ((void *) &TempHiiExportTableHeader, sizeof (EFI_HII_EXPORT_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write HII export table header to output file"); goto Done; } // // Now go back through all the handles and create new data packs for each, writing out // the contents as we go. // HiiHandle = FIRST_HII_PACK_HANDLE; for (TempDataTable = DataTableList; TempDataTable != NULL; TempDataTable = TempDataTable->Next) { // // Write a data table header to the output file. We'll rewind the file and // write an updated one when we're done with this data set // DataTableHeaderOffset = ftell (OutFptr); TempDataTable->DataTableHeader.HiiHandle = HiiHandle; TempDataTable->DataTableHeader.DataTableSize = sizeof (EFI_HII_DATA_TABLE); // // We may change the number of variable data when merging export files, so init to 0 // TempDataTable->DataTableHeader.NumberOfVariableData = 0; if (fwrite ((void *) &TempDataTable->DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write HII data table header to output file"); goto Done; } // // Get the string pack if any // Status = StringGetPack (HiiHandle, &StringPack, &FileSize, &Count, &FormsetGuid, &PackageGuid); if (Status == STATUS_SUCCESS) { TempDataTable->DataTableHeader.StringDataOffset = TempDataTable->DataTableHeader.DataTableSize; TempDataTable->DataTableHeader.DataTableSize += FileSize; // // TempDataTable->DataTableHeader.NumberOfLanguages should be unchanged // if (fwrite ((void *) StringPack, FileSize, 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write string pack to output file", NULL); goto Done; } } // // Get the IFR pack // Status = IfrGetIfrPack (HiiHandle, &IfrPack, &FormsetGuid); if (Status == STATUS_SUCCESS) { // // Write the IFR pack, followed by the variable packs // TempDataTable->DataTableHeader.IfrDataOffset = TempDataTable->DataTableHeader.DataTableSize; TempDataTable->DataTableHeader.DataTableSize += IfrPack->Header.Length; if (fwrite ((void *) IfrPack, IfrPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write IFR pack to output file", NULL); goto Done; } // // If this is just a formset stub, then don't write the variable packs // if (IfrPack->Header.Length != sizeof (EMPTY_FORMSET_PACK)) { // // Go through all the variable packs and see if they're referenced by this IFR // Count = 0; do { Status = IfrGetVarPack (Count, &VarPack); if (Status == STATUS_SUCCESS) { // // Check for variable data length of 0 // if ((NoEmptyVarPacks == 0) || ((VarPack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - VarPack->VariableNameLength) != 0) ) { // // See if it's referenced by this IFR // if (IfrReferencesVarPack (HiiHandle, VarPack) == STATUS_SUCCESS) { if (TempDataTable->DataTableHeader.VariableDataOffset == 0) { TempDataTable->DataTableHeader.VariableDataOffset = TempDataTable->DataTableHeader.DataTableSize; } TempDataTable->DataTableHeader.DataTableSize += VarPack->Header.Length; TempDataTable->DataTableHeader.NumberOfVariableData++; if (fwrite ((void *) VarPack, VarPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write variable pack to output file", NULL); goto Done; } } } } Count++; } while (Status == STATUS_SUCCESS); } Status = STATUS_SUCCESS; } // // Get the device path pack // // // Rewind the file and write the updated data table header. // fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); if (fwrite ((void *) &TempDataTable->DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write HII data table header to output file"); goto Done; } fseek (OutFptr, 0, SEEK_END); HiiHandle++; } Status = STATUS_SUCCESS; Done: IfrParseEnd (); StringEnd (); if (Buffer != NULL) { free (Buffer); } if (InFptr != NULL) { fclose (InFptr); } if (OutFptr != NULL) { fclose (OutFptr); } while (DataTableList != NULL) { TempDataTable = DataTableList->Next; free (DataTableList); DataTableList = TempDataTable; } return Status; } /******************************************************************************/ static STATUS CreateHiiExport ( char *OutputFileName, EFI_GUID *DummyFormsetGuid, FILE_NAME_LIST *PackFiles, int MfgDefaults ) /*++ Routine Description: Given a linked list of HII pack file names, walk the list to process them and create a single HII export file. Arguments: OutputFileName - name of output HII export file to create DummyFormsetGuid - IFR formsets contain a GUID which is used in many places while processing data tables. If we were not given an IFR pack, then we'll create a stub IFR pack using this GUID as the formset GUID. PackFiles - linked list of HII pack files to process MfgDefaults - when creating variable packs (via IFR pack processing), use manufacturing defaults rather than standard defaults Returns: STATUS_SUCCESS - if successful STATUS_ERROR - otherwise --*/ { STATUS Status; EMPTY_FORMSET_PACK EmptyFormset; EFI_HII_DATA_TABLE DataTableHeader; EFI_HII_EXPORT_TABLE ExportTableHeader; long DataTableHeaderOffset; long FileSize; FILE *OutFptr; FILE *InFptr; FILE_NAME_LIST *TempFile; EFI_GUID HiiExportRevisionGuid = EFI_HII_PROTOCOL_GUID; EFI_GUID TempGuid; EFI_GUID PackageGuid; char *Buffer; EFI_HII_VARIABLE_PACK *VarPack; EFI_HII_IFR_PACK *IfrPack; EFI_HII_STRING_PACK_HEADER *StringPack; EFI_HII_STRING_PACK_HEADER TerminatorStringPack; int NumIfr; int NumStrings; int Index; int VarPackIndex; // // If no input HII pack files, then why are we here? Should have been caught when // args were processed though. // if (PackFiles == NULL) { Error (NULL, 0, 0, "no input pack files specified", NULL); return STATUS_ERROR; } InFptr = NULL; Status = STATUS_ERROR; Buffer = NULL; // // Open the output file for writing // if ((OutFptr = fopen (OutputFileName, "wb")) == NULL) { Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); goto Done; } // // Figure out how many data tables we are going to need. We'll create one // data table if no more than one IFR, or we'll create one data table per IFR, // and then one for strings if multiple IFR // NumIfr = 0; NumStrings = 0; for (TempFile = PackFiles; TempFile != NULL; TempFile = TempFile->Next) { if (TempFile->Tag == EFI_HII_IFR) { NumIfr++; } else if (TempFile->Tag == EFI_HII_STRING) { NumStrings++; } } // // Three possibilities: // 1) No IFR, so create one data table that contains only strings and an empty formset // 2) Only 1 IFR, so create an export table with one data table that contains the IFR // and all the strings // 3) Multiple IFR, so create a data table for each IFR and another data table with // all the strings. // // Initialize the export table header and write it out // memset ((void *) &ExportTableHeader, 0, sizeof (EFI_HII_EXPORT_TABLE)); if (NumIfr < 2) { ExportTableHeader.NumberOfHiiDataTables = 1; } else { // // One data table per IFR, plus one for strings (if any). // ExportTableHeader.NumberOfHiiDataTables = (UINT16) NumIfr; if (NumStrings != 0) { ExportTableHeader.NumberOfHiiDataTables++; } } // // Init the GUID in the HII export table header // memcpy (&ExportTableHeader.Revision, &HiiExportRevisionGuid, sizeof (EFI_GUID)); if (fwrite ((void *) &ExportTableHeader, sizeof (EFI_HII_EXPORT_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write HII export table header to output file"); goto Done; } // // ***************************************************************************************** // // CASE 1 - No IFR => one data table that contains only strings and an empty formset. // No variable data. // // CASE 2 - Only 1 IFR => create an export table with one data table that contains the IFR // and all the strings plus variable data // // CASE 3 - Multiple IFR => create a data table for each IFR and another data table with // all the strings. Each IFR data table has variable data if applicable. // // ***************************************************************************************** // // If the user did not give us an IFR file, then we'll have to create an empty formset // and emit it to the output file. In this case, we need a formset GUID on the command // line. // if ((NumIfr == 0) && (mGlobals.GuidSpecified == 0)) { // // Warning (NULL, 0, 0, "using NULL GUID for empty formset", "specify -g GUID on the command line if desired"); // memset ((void *) &PackageGuid, 0, sizeof (EFI_GUID)); } else if (mGlobals.GuidSpecified) { // // Use it for the package GUID // memcpy (&PackageGuid, &mGlobals.Guid, sizeof (EFI_GUID)); } // // Init the data table header. // Write out the blank data table header. Save the offset so we can // write an updated version at the end of processing. // memset ((void *) &DataTableHeader, 0, sizeof (EFI_HII_DATA_TABLE)); DataTableHeaderOffset = ftell (OutFptr); DataTableHeader.HiiHandle = FIRST_HII_PACK_HANDLE; if (mGlobals.Verbose) { fprintf (stdout, "writing data table (first time) to offset 0x%X\n", ftell (OutFptr)); } if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } // // Set the data table size, then write out all the string packs // DataTableHeader.DataTableSize = sizeof (EFI_HII_DATA_TABLE); // // Write out the string files to a single data record // for (TempFile = PackFiles; TempFile != NULL; TempFile = TempFile->Next) { // // Continue to next file if it's not a string pack file // if (TempFile->Tag != EFI_HII_STRING) { continue; } // // Set the offset in the header if this is the first string pack // if (DataTableHeader.StringDataOffset == 0) { DataTableHeader.StringDataOffset = DataTableHeader.DataTableSize; } if ((InFptr = fopen (TempFile->FileName, "rb")) == NULL) { Error (NULL, 0, 0, TempFile->FileName, "failed to open input string pack file for reading"); goto Done; } // // Get the file size, then read it into a buffer // fseek (InFptr, 0, SEEK_END); FileSize = ftell (InFptr); fseek (InFptr, 0, SEEK_SET); Buffer = (char *) malloc (FileSize); if (Buffer == NULL) { Error (NULL, 0, 0, TempFile->FileName, "memory allocation failure reading in file contents"); goto Done; } if (fread (Buffer, FileSize, 1, InFptr) != 1) { Error (NULL, 0, 0, TempFile->FileName, "failed to read file contents"); goto Done; } fclose (InFptr); InFptr = NULL; // // Verify that it's actually a string pack // StringPack = (EFI_HII_STRING_PACK_HEADER *) Buffer; while ((char *) StringPack < Buffer + FileSize) { if (StringPack->Header.Type != EFI_HII_STRING) { Error (NULL, 0, 0, TempFile->FileName, "file does not consist entirely of string packs"); goto Done; } if (StringPack->Header.Length == 0) { break; } DataTableHeader.NumberOfLanguages++; DataTableHeader.DataTableSize += StringPack->Header.Length; // // Write the string pack to the output file // if (mGlobals.Verbose) { fprintf (stdout, "writing string pack to offset 0x%X\n", ftell (OutFptr)); } if (fwrite (StringPack, StringPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, TempFile->FileName, "failed to write string pack to output file"); goto Done; } // // Sanity check that adding the length advances us (no wrap) // if ((char *) StringPack + StringPack->Header.Length <= (char *) StringPack) { Error (NULL, 0, 0, TempFile->FileName, "invalid pack size in file"); goto Done; } StringPack = (EFI_HII_STRING_PACK_HEADER *) ((char *) StringPack + StringPack->Header.Length); } // // Free up buffer, go to next input string pack file // free (Buffer); Buffer = NULL; } // // Write a null-terminator string pack if we had any string packs at all // if (DataTableHeader.StringDataOffset != 0) { memset (&TerminatorStringPack, 0, sizeof (EFI_HII_STRING_PACK_HEADER)); TerminatorStringPack.Header.Length = 0; TerminatorStringPack.Header.Type = EFI_HII_STRING; if (mGlobals.Verbose) { fprintf (stdout, "writing terminator string pack to offset 0x%X\n", ftell (OutFptr)); } if (fwrite (&TerminatorStringPack, sizeof (EFI_HII_STRING_PACK_HEADER), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write string pack terminator to output file", NULL); goto Done; } DataTableHeader.DataTableSize += sizeof (EFI_HII_STRING_PACK_HEADER); } // // Parse all the IFR packs, then get the GUID from the first // one so we can use it for the package GUID if necessary. // memcpy (&PackageGuid, &mGlobals.Guid, sizeof (EFI_GUID)); if (NumIfr != 0) { IfrParseInit (); if (ProcessIfrFiles (PackFiles) != STATUS_SUCCESS) { goto Done; } // // Set variable defaults in all variable packs // IfrSetDefaults (MfgDefaults); // // Get the GUID from the first IFR pack if the user did not specify a GUID on // the command line. // if (mGlobals.GuidSpecified == 0) { if (IfrGetIfrPack (FIRST_HII_PACK_HANDLE, &IfrPack, &PackageGuid) != STATUS_SUCCESS) { Error (NULL, 0, 0, "internal application error", "failed to retrieve IFR pack after parsing"); goto Done; } } } // // Set the package GUID in the data table header. // memcpy (&DataTableHeader.PackageGuid, &PackageGuid, sizeof (EFI_GUID)); // // If no IFR, then create and write the empty formset. Otherwise // parse the IFR and emit it and the variable data for it. // if (NumIfr == 0) { memset ((void *) &EmptyFormset, 0, sizeof (EMPTY_FORMSET_PACK)); EmptyFormset.PackHeader.Header.Type = EFI_HII_IFR; EmptyFormset.PackHeader.Header.Length = sizeof (EMPTY_FORMSET_PACK); // // Formset Opcode // EmptyFormset.Formset.Header.OpCode = EFI_IFR_FORM_SET_OP; EmptyFormset.Formset.Header.Length = (UINT8) sizeof (EFI_IFR_FORM_SET); memcpy (&EmptyFormset.Formset.Guid, &PackageGuid, sizeof (EFI_GUID)); // // EndFormset Opcode // EmptyFormset.EndFormset.Header.OpCode = EFI_IFR_END_FORM_SET_OP; EmptyFormset.EndFormset.Header.Length = (UINT8) sizeof (EFI_IFR_END_FORM_SET); DataTableHeader.IfrDataOffset = DataTableHeader.DataTableSize; if (mGlobals.Verbose) { fprintf (stdout, "writing stub IFR formset to to offset 0x%X\n", ftell (OutFptr)); } if (fwrite (&EmptyFormset, sizeof (EMPTY_FORMSET_PACK), 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write formset stub to output file"); goto Done; } DataTableHeader.DataTableSize += sizeof (EMPTY_FORMSET_PACK); // // Go back and re-write the data table header, reposition to the end, then return. // fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); if (mGlobals.Verbose) { fprintf (stdout, "writing data table (second time) to offset 0x%X\n", ftell (OutFptr)); } if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } fseek (OutFptr, 0, SEEK_END); if (mGlobals.Verbose) { fprintf ( stdout, "final file offset=0x%X DataTableHeader.DataTableSize=0x%X\n", ftell (OutFptr), DataTableHeader.DataTableSize ); } } else if (NumIfr == 1) { // // They gave us one input IFR file. We parsed it above, so get each one // and emit the IFR and each variable pack it references. // Update the data pack header for the IFR pack, then write the IFR pack data // DataTableHeader.IfrDataOffset = DataTableHeader.DataTableSize; if (IfrGetIfrPack (FIRST_HII_PACK_HANDLE, &IfrPack, &TempGuid) != STATUS_SUCCESS) { Error (NULL, 0, 0, "internal application error", "failed to retrieve IFR pack after parsing"); goto Done; } if (mGlobals.Verbose) { fprintf (stdout, "writing IFR pack to 0x%X\n", ftell (OutFptr)); } if (fwrite (IfrPack, IfrPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write IFR pack to output file"); goto Done; } DataTableHeader.DataTableSize += IfrPack->Header.Length; // // Now go through all the variable packs discovered during IFR processing // and write them to the output file // if (mGlobals.NoVarPacks == 0) { Index = 0; do { Status = IfrGetVarPack (Index, &VarPack); if (Status == STATUS_SUCCESS) { // // If this is the first variable pack, then update the "offset // to variable data" in the data table header // if (Index == 0) { DataTableHeader.VariableDataOffset = DataTableHeader.DataTableSize; } DataTableHeader.DataTableSize += VarPack->Header.Length; DataTableHeader.NumberOfVariableData++; if (fwrite ((void *) VarPack, VarPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write variable pack to output file"); goto Done; } Index++; } } while (Status == STATUS_SUCCESS); } // // Reposition in the output file and write the updated data table header // fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } fseek (OutFptr, 0, SEEK_END); } else { // // Multiple IFR input files. Close out the current data table (strings) // if applicable. Then retrieve each parsed IFR pack and create a data pack // that contains the IFR (one per data set) and the variable packs that // the given IFR form references. // if (NumStrings != 0) { fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } fseek (OutFptr, 0, SEEK_END); } else { // // No strings, so back up over the data table header we wrote because we assumed // at least one string pack. // fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); } // // Now go through all the IFR packs and write them out, along with variable // data referenced by each. Note that multiple IFR forms can refer to the // same variables, so the same variable data could be duplicated in multiple // data packs. // Index = FIRST_HII_PACK_HANDLE; while (IfrGetIfrPack (Index, &IfrPack, &TempGuid) == STATUS_SUCCESS) { // // Initialize the data table header // memset (&DataTableHeader, 0, sizeof (EFI_HII_DATA_TABLE)); memcpy (&DataTableHeader.PackageGuid, &PackageGuid, sizeof (EFI_GUID)); // // If we didn't have strings, then the HiiHandle should be just Index, // rather than Index+1. But since the HiiHandle is not required to start // with 1, we'll let it be Index+1. // DataTableHeader.HiiHandle = (EFI_HII_HANDLE) (Index + 1); DataTableHeader.DataTableSize = sizeof (EFI_HII_DATA_TABLE); // // Save the file offset of the data table header so we can write an updated // version later. // DataTableHeaderOffset = ftell (OutFptr); if (mGlobals.Verbose) { fprintf (stdout, "writing data table header to 0x%X\n", ftell (OutFptr)); } if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } DataTableHeader.IfrDataOffset = DataTableHeader.DataTableSize; if (fwrite (IfrPack, IfrPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write IFR pack to output file"); goto Done; } DataTableHeader.DataTableSize += IfrPack->Header.Length; // // Go through all the variable packs and see if this IFR references each. If the // IFR does reference it, then add the variable pack to the output. // if (mGlobals.NoVarPacks == 0) { VarPackIndex = 0; while (IfrGetVarPack (VarPackIndex, &VarPack) == STATUS_SUCCESS) { // // See if the IFR references this variable pack // if (IfrReferencesVarPack (Index, VarPack) == STATUS_SUCCESS) { // // If this is the first variable pack, then set the offset in // the data table header. // if (DataTableHeader.VariableDataOffset == 0) { DataTableHeader.VariableDataOffset = DataTableHeader.DataTableSize; } // // Write the variable pack // if (fwrite (VarPack, VarPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, OutputFileName, "failed to write variable pack to output file"); goto Done; } DataTableHeader.NumberOfVariableData++; DataTableHeader.DataTableSize += VarPack->Header.Length; } VarPackIndex++; } } // // Write the updated data table header // fseek (OutFptr, DataTableHeaderOffset, SEEK_SET); if (fwrite ((void *) &DataTableHeader, sizeof (EFI_HII_DATA_TABLE), 1, OutFptr) != 1) { Error (NULL, 0, 0, "failed to write Data Table Header to output file", NULL); goto Done; } fseek (OutFptr, 0, SEEK_END); // // Next IFR pack // Index++; } } Status = STATUS_SUCCESS; Done: IfrParseEnd (); StringEnd (); if (Buffer != NULL) { free (Buffer); } if (InFptr != NULL) { fclose (InFptr); } if (OutFptr != NULL) { fclose (OutFptr); } return Status; } /******************************************************************************/ static STATUS ProcessIfrFiles ( FILE_NAME_LIST *FileName ) /*++ Routine Description: Given a linked list of pack file names, read in each IFR pack file and process the contents. Arguments: FileName - pointer to linked list of input pack file names Returns: STATUS_SUCCESS - if successful STATUS_ERROR - otherwise --*/ { FILE *InFptr; char *Buffer; long BufferSize; STATUS Status; STATUS IfrStatus; int Handle; EFI_GUID FormsetGuid; EFI_HII_PACK_HEADER *PackHeader; // // Process each input IFR file // Status = STATUS_ERROR; Handle = 1; InFptr = NULL; Buffer = NULL; while (FileName != NULL) { // // Only process IFR pack files // if (FileName->Tag != EFI_HII_IFR) { FileName = FileName->Next; continue; } // // Open the input file, then read the contents // if ((InFptr = fopen (FileName->FileName, "rb")) == NULL) { Error (NULL, 0, 0, FileName->FileName, "failed to open input IFR file"); goto Done; } fseek (InFptr, 0, SEEK_END); BufferSize = ftell (InFptr); fseek (InFptr, 0, SEEK_SET); Buffer = (char *) malloc (BufferSize); if (Buffer == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); goto Done; } if (fread (Buffer, BufferSize, 1, InFptr) != 1) { Error (NULL, 0, 0, FileName->FileName, "failed to read file contents"); goto Done; } fclose (InFptr); InFptr = NULL; // // Check the buffer contents -- better be an IFR pack // if (BufferSize < sizeof (EFI_HII_PACK_HEADER)) { Error (NULL, 0, 0, FileName->FileName, "file is not large enough to contain an IFR pack"); goto Done; } PackHeader = (EFI_HII_PACK_HEADER *) Buffer; if (PackHeader->Type != EFI_HII_IFR) { Error (NULL, 0, 0, FileName->FileName, "file does not appear to be an IFR pack"); goto Done; } // // Process the contents // memset ((void *) &FormsetGuid, 0, sizeof (EFI_GUID)); IfrStatus = IfrParsePack (Handle, (EFI_HII_IFR_PACK *) PackHeader, &FormsetGuid); if (IfrStatus != STATUS_SUCCESS) { goto Done; } Handle++; free (Buffer); Buffer = NULL; FileName = FileName->Next; } Status = STATUS_SUCCESS; Done: if (InFptr != NULL) { fclose (InFptr); } if (Buffer != NULL) { free (Buffer); } return Status; } static STATUS EmitDefaults ( FILE_NAME_LIST *HiiExportFiles, int MfgDefaults, int NoEmptyVarPacks ) /*++ Routine Description: Given a linked list of HII export files, read in each file, process the contents, and then emit variable packs. Arguments: HiiExportFiles - linked list of HII export files to process MfgDefaults - emit manufacturing defaults NoEmptyVarPacks - don't emit variable packs if they are 0-length Returns: STATUS_SUCCESS - if successful STATUS_ERROR - otherwise --*/ { int HiiHandle; FILE *OutFptr; FILE *InFptr; EFI_HII_VARIABLE_PACK *VarPack; CHAR8 OutFileName[MAX_PATH]; CHAR8 GuidString[100]; STATUS Status; CHAR8 *Buffer; int FileSize; int DataTableIndex; EFI_HII_EXPORT_TABLE *HiiExportTableHeader; EFI_HII_DATA_TABLE *DataTableHeader; // // Init locals // HiiHandle = FIRST_HII_PACK_HANDLE; Buffer = NULL; InFptr = NULL; OutFptr = NULL; Status = STATUS_ERROR; // // Initialize our IFR parser // IfrParseInit (); // // Process each input HII export file // while (HiiExportFiles != NULL) { if (mGlobals.Verbose) { fprintf (stdout, "Processing file %s\n", HiiExportFiles->FileName); } // // Read in the entire file contents // if ((InFptr = fopen (HiiExportFiles->FileName, "rb")) == NULL) { Error (NULL, 0, 0, HiiExportFiles->FileName, "failed to open HII export file for reading"); goto Done; } fseek (InFptr, 0, SEEK_END); FileSize = (int) ftell (InFptr); fseek (InFptr, 0, SEEK_SET); Buffer = (CHAR8 *) malloc (FileSize); if (Buffer == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); goto Done; } if (fread (Buffer, FileSize, 1, InFptr) != 1) { Error (NULL, 0, 0, HiiExportFiles->FileName, "failed to read file contents"); goto Done; } fclose (InFptr); InFptr = NULL; HiiExportTableHeader = (EFI_HII_EXPORT_TABLE *) Buffer; // // Walk all the data tables // DataTableHeader = (EFI_HII_DATA_TABLE *) (HiiExportTableHeader + 1); for (DataTableIndex = 0; DataTableIndex < (int) HiiExportTableHeader->NumberOfHiiDataTables; DataTableIndex++) { // // Make sure we're still pointing into our buffer // if (((char *) DataTableHeader < Buffer) || ((char *) DataTableHeader > Buffer + FileSize)) { Error (NULL, 0, 0, "bad data table size in input file", NULL); goto Done; } // // If there is an IFR pack, parse it // HiiHandle++; if (DataTableHeader->IfrDataOffset != 0) { if (IfrParsePack ( HiiHandle, (EFI_HII_IFR_PACK *) ((char *) DataTableHeader + DataTableHeader->IfrDataOffset), &DataTableHeader->PackageGuid ) != STATUS_SUCCESS ) { goto Done; } } // // Next data pack // DataTableHeader = (EFI_HII_DATA_TABLE *) ((char *) DataTableHeader + DataTableHeader->DataTableSize); } free (Buffer); Buffer = NULL; // // Next input file // HiiExportFiles = HiiExportFiles->Next; } // // Now create defaults // if (IfrSetDefaults (MfgDefaults) != STATUS_SUCCESS) { goto Done; } // // Now retrieve each variable pack and write it out to a GUID-VarName.hpk file // HiiHandle = 0; do { Status = IfrGetVarPack (HiiHandle, &VarPack); if (Status == STATUS_SUCCESS) { // // Check for variable data length of 0 // if ((NoEmptyVarPacks == 0) || ((VarPack->Header.Length - sizeof (EFI_HII_VARIABLE_PACK) - VarPack->VariableNameLength) != 0) ) { // // Open the output file and write the variable pack // GuidToString (&VarPack->VariableGuid, GuidString); if (MfgDefaults) { sprintf ( OutFileName, "%s-%S-MfgDefaults%s", GuidString, (CHAR16 *) (VarPack + 1), DEFAULT_HII_PACK_FILENAME_EXTENSION ); } else { sprintf ( OutFileName, "%s-%S-Defaults%s", GuidString, (CHAR16 *) (VarPack + 1), DEFAULT_HII_PACK_FILENAME_EXTENSION ); } if (mGlobals.Verbose) { fprintf ( stdout, "Creating %svariable defaults pack file %s\n", MfgDefaults ? "manufacturing " : "", OutFileName ); } if ((OutFptr = fopen (OutFileName, "wb")) == NULL) { Error (NULL, 0, 0, OutFileName, "failed to open output file for writing", NULL); goto Done; } if (fwrite ((void *) VarPack, VarPack->Header.Length, 1, OutFptr) != 1) { Error (NULL, 0, 0, OutFileName, "failed to write defaults to output file"); goto Done; } fclose (OutFptr); OutFptr = NULL; } else { // // Print a message that we skipped one if in verbose mode // if (mGlobals.Verbose) { GuidToString (&VarPack->VariableGuid, GuidString); if (MfgDefaults) { sprintf ( OutFileName, "%s-%S-MfgDefaults%s", GuidString, (CHAR16 *) (VarPack + 1), DEFAULT_HII_PACK_FILENAME_EXTENSION ); } else { sprintf ( OutFileName, "%s-%S-Defaults%s", GuidString, (CHAR16 *) (VarPack + 1), DEFAULT_HII_PACK_FILENAME_EXTENSION ); } fprintf ( stdout, "Skipping 0-length %svariable defaults pack file %s\n", MfgDefaults ? "manufacturing " : "", OutFileName ); } } } HiiHandle++; } while (Status == STATUS_SUCCESS); Status = STATUS_SUCCESS; Done: IfrParseEnd (); if (Buffer != NULL) { free (Buffer); } if (InFptr != NULL) { fclose (InFptr); } if (OutFptr != NULL) { fclose (OutFptr); } return Status; } static void FreeGlobals ( VOID ) /*++ Routine Description: Free up an memory we allocated so we can exit cleanly Arguments: Returns: NA --*/ { FILE_NAME_LIST *Next; // // Free up input pack file names // while (mGlobals.PackFileNames != NULL) { Next = mGlobals.PackFileNames->Next; free (mGlobals.PackFileNames); mGlobals.PackFileNames = Next; } // // Free up input HII export file names // while (mGlobals.HiiExportFileNames != NULL) { Next = mGlobals.HiiExportFileNames->Next; free (mGlobals.HiiExportFileNames); mGlobals.HiiExportFileNames = Next; } } static STATUS DumpHiiExportFile ( char *HiiExportFileName, char *OutputFileName ) /*++ Routine Description: Dump the contents of an HII export file for debug purposes Arguments: HiiExportFileName - name of input HII export file OutputFileName - name of output file to dump contents Returns: STATUS_SUCCESS - no problems STATUS_ERROR - problems encountered processing the file --*/ { FILE *InFptr; FILE *OutFptr; char *Buffer; char *BufferStart; char *BufferEnd; int BufferSize; STATUS Status; char GuidString[100]; int Counter; int NumberOfTables; EFI_HII_DATA_TABLE *DataTableHeader; EFI_GUID HiiExportRevisionGuid = EFI_HII_PROTOCOL_GUID; // // Init locals // InFptr = NULL; OutFptr = NULL; BufferStart = NULL; Status = STATUS_ERROR; // // Open the input file // if ((InFptr = fopen (HiiExportFileName, "rb")) == NULL) { Error (NULL, 0, 0, HiiExportFileName, "failed to open input HII export file for reading"); goto Done; } // // Open the output file // if ((OutFptr = fopen (OutputFileName, "w")) == NULL) { Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); goto Done; } // // Get the file size, then allocate a buffer and read in the file contents. // fseek (InFptr, 0, SEEK_END); BufferSize = (int) ftell (InFptr); fseek (InFptr, 0, SEEK_SET); BufferStart = (char *) malloc (BufferSize); if (BufferStart == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); goto Done; } if (fread (BufferStart, BufferSize, 1, InFptr) != 1) { Error (NULL, 0, 0, HiiExportFileName, "error reading file contents"); goto Done; } fclose (InFptr); InFptr = NULL; // // Crude check of the input data -- check the size and GUID // if (BufferSize < sizeof (EFI_HII_EXPORT_TABLE)) { Error (NULL, 0, 0, HiiExportFileName, "files not large enough to contain an HII export table header"); goto Done; } if (memcmp (&((EFI_HII_EXPORT_TABLE *) BufferStart)->Revision, &HiiExportRevisionGuid, sizeof (EFI_GUID)) != 0) { Error (NULL, 0, 0, HiiExportFileName, "invalid HII export revision GUID -- is this an HII export file?"); // // See if it's a HII pack file // TestDumpHiiPack (OutFptr, BufferStart, BufferSize); goto Done; } // // Now walk the export data // Buffer = BufferStart; BufferEnd = BufferStart + BufferSize; // // Dump the header // fprintf (OutFptr, "HII dump of file %s\n\n", HiiExportFileName); NumberOfTables = ((EFI_HII_EXPORT_TABLE *) Buffer)->NumberOfHiiDataTables; fprintf (OutFptr, "Number of data tables: %d\n", NumberOfTables); GuidToString (&((EFI_HII_EXPORT_TABLE *) Buffer)->Revision, GuidString); fprintf (OutFptr, "HII export revision: %s\n", GuidString); // // Now walk the data tables // Buffer += sizeof (EFI_HII_EXPORT_TABLE); for (Counter = 0; Counter < NumberOfTables; Counter++) { DataTableHeader = (EFI_HII_DATA_TABLE *) Buffer; fprintf (OutFptr, "----------------------------------------------------------\n"); fprintf (OutFptr, " DataTable at offset 0x%08X\n", (int) Buffer - (int) BufferStart); fprintf (OutFptr, " HII Handle: 0x%08X\n", DataTableHeader->HiiHandle); GuidToString (&DataTableHeader->PackageGuid, GuidString); fprintf (OutFptr, " Package GUID: %s\n", GuidString); fprintf (OutFptr, " Data table size: 0x%08X\n", DataTableHeader->DataTableSize); fprintf (OutFptr, " IFR data offset: 0x%08X\n", DataTableHeader->IfrDataOffset); fprintf (OutFptr, " String data offset: 0x%08X\n", DataTableHeader->StringDataOffset); fprintf (OutFptr, " Variable data offset: 0x%08X\n", DataTableHeader->VariableDataOffset); fprintf (OutFptr, " Device path offset: 0x%08X\n", DataTableHeader->DevicePathOffset); fprintf (OutFptr, " Number of variable data: 0x%08X\n", DataTableHeader->NumberOfVariableData); fprintf (OutFptr, " Number of languages: 0x%08X\n", DataTableHeader->NumberOfLanguages); // // Dump strings // if (DataTableHeader->StringDataOffset != 0) { DumpStringPack ( OutFptr, (EFI_HII_STRING_PACK *) ((char *) DataTableHeader + DataTableHeader->StringDataOffset), DataTableHeader->StringDataOffset, 6 ); } // // Dump IFR // if (DataTableHeader->IfrDataOffset != 0) { DumpIfrPack ( OutFptr, (EFI_HII_IFR_PACK *) ((char *) DataTableHeader + DataTableHeader->IfrDataOffset), DataTableHeader->IfrDataOffset, 6 ); } // // Dump variables // if (DataTableHeader->VariableDataOffset != 0) { DumpVariablePacks ( OutFptr, (EFI_HII_VARIABLE_PACK *) ((char *) DataTableHeader + DataTableHeader->VariableDataOffset), DataTableHeader->NumberOfVariableData, DataTableHeader->VariableDataOffset, 6 ); } // // Dump device path // // // Check position before advancing // if ((Buffer + DataTableHeader->DataTableSize < Buffer) || (Buffer + DataTableHeader->DataTableSize > BufferEnd)) { Error (NULL, 0, 0, HiiExportFileName, "bad data table size at offset 0x%X", (int) Buffer - (int) BufferStart); goto Done; } Buffer += DataTableHeader->DataTableSize; } Status = STATUS_SUCCESS; Done: if (OutFptr != NULL) { fclose (OutFptr); } if (InFptr != NULL) { fclose (InFptr); } if (BufferStart != NULL) { free (BufferStart); } return Status; } static void DumpIfrPack ( FILE *OutFptr, EFI_HII_IFR_PACK *Pack, int BaseOffset, int Indent ) /*++ Routine Description: Dump the contents of an IFR pack for debug purposes Arguments: OutFptr - file pointer to which to dump the output Pack - pointer to IFR pack to dump BaseOffset - offset from which Pack starts in its parent data table Indent - indent this many spaces when printing text to OutFptr Returns: NA --*/ { EFI_IFR_FORM_SET *IfrFormSet; char GuidString[100]; if (Pack->Header.Type != EFI_HII_IFR) { Error (NULL, 0, 0, "found non-IFR pack type at IFR data offset", NULL); return ; } fprintf (OutFptr, "%*cIFR pack at offset 0x%08X\n", Indent, ' ', BaseOffset); fprintf (OutFptr, "%*c Length 0x%08X\n", Indent, ' ', Pack->Header.Length); // // Get the GUID from the formset // IfrFormSet = (EFI_IFR_FORM_SET *) (Pack + 1); GuidToString (&IfrFormSet->Guid, GuidString); fprintf (OutFptr, "%*c Variable GUID %s\n", Indent, ' ', GuidString); // // Print the IFR formset size, with a note indicating if it's a min (likely stub) // formset // if (Pack->Header.Length == sizeof (EMPTY_FORMSET_PACK)) { fprintf ( OutFptr, "%*c IFR formset size 0x%08X (empty formset)\n", Indent, ' ', Pack->Header.Length - sizeof (EFI_HII_IFR_PACK) ); } else { fprintf ( OutFptr, "%*c IFR formset size 0x%08X\n", Indent, ' ', Pack->Header.Length - sizeof (EFI_HII_IFR_PACK) ); } // // Dump raw bytes -- not much use // } static void DumpVariablePacks ( FILE *OutFptr, EFI_HII_VARIABLE_PACK *Pack, int NumPacks, int BaseOffset, int Indent ) /*++ Routine Description: Dump the contents of an IFR pack for debug purposes Arguments: OutFptr - file pointer to which to dump the output Pack - pointer to variable pack to dump NumPacks - number of packs in Pack[] array BaseOffset - offset from which Pack starts in its parent data table Indent - indent this many spaces when printing text to OutFptr Returns: NA --*/ { int Count; int Len; char GuidString[100]; for (Count = 0; Count < NumPacks; Count++) { if (Pack->Header.Type != EFI_HII_VARIABLE) { Error (NULL, 0, 0, "found non-variable pack type in variable pack array", NULL); return ; } fprintf (OutFptr, "%*cVariable pack at offset 0x%08X\n", Indent, ' ', BaseOffset); fprintf (OutFptr, "%*c Length 0x%08X\n", Indent, ' ', Pack->Header.Length); GuidToString (&Pack->VariableGuid, GuidString); fprintf (OutFptr, "%*c Variable GUID %s\n", Indent, ' ', GuidString); fprintf (OutFptr, "%*c Variable Name %S\n", Indent, ' ', (CHAR16 *) (Pack + 1)); Len = sizeof (EFI_HII_VARIABLE_PACK) + Pack->VariableNameLength; fprintf (OutFptr, "%*c Variable Size 0x%08X\n", Indent, ' ', Pack->Header.Length - Len); // // Dump raw bytes // DumpRawBytes (OutFptr, (char *) Pack + Len, Pack->Header.Length - Len, Len, Indent + 2); BaseOffset += Pack->Header.Length; Pack = (EFI_HII_VARIABLE_PACK *) ((char *) Pack + Pack->Header.Length); } } static void DumpStringPack ( FILE *OutFptr, EFI_HII_STRING_PACK *Pack, int BaseOffset, int Indent ) /*++ Routine Description: Dump the contents of a string pack array for debug purposes Arguments: OutFptr - file pointer to which to dump the output Pack - pointer to string pack array to dump BaseOffset - offset from which Pack starts in its parent data table Indent - indent this many spaces when printing text to OutFptr Returns: NA --*/ { int Count; int *IndexPtr; CHAR16 *WCPtr; // // String pack array is terminated with a zero-length string pack // while (Pack->Header.Length > 0) { if (Pack->Header.Type != EFI_HII_STRING) { Error (NULL, 0, 0, "found non-string pack type in string pack array", NULL); return ; } fprintf (OutFptr, "%*cString pack at offset 0x%08X\n", Indent, ' ', BaseOffset); fprintf (OutFptr, "%*c Length 0x%08X\n", Indent, ' ', Pack->Header.Length); fprintf ( OutFptr, "%*c Language %S\n", Indent, ' ', (CHAR16 *) ((char *) Pack + Pack->LanguageNameString) ); fprintf ( OutFptr, "%*c Printable Language %S\n", Indent, ' ', (CHAR16 *) ((char *) Pack + Pack->PrintableLanguageName) ); fprintf (OutFptr, "%*c Number of strings 0x%08X\n", Indent, ' ', Pack->NumStringPointers); fprintf (OutFptr, "%*c Attributes 0x%08X\n", Indent, ' ', Pack->Attributes); IndexPtr = (int *) (Pack + 1); // // Dump string data // if (mGlobals.DumpStrings) { for (Count = 0; Count < (int) Pack->NumStringPointers; Count++) { fprintf (OutFptr, "%*c String 0x%04X: ", Indent, ' ', Count); // // Print raw hex bytes // for (WCPtr = (CHAR16 *) ((char *) Pack +*IndexPtr); *WCPtr != 0; WCPtr++) { fprintf (OutFptr, "%02X ", (unsigned int) *WCPtr); } fprintf (OutFptr, "00\n"); IndexPtr++; } } BaseOffset += Pack->Header.Length; Pack = (EFI_HII_STRING_PACK *) ((char *) Pack + Pack->Header.Length); } } static void TestDumpHiiPack ( FILE *OutFptr, char *Buffer, int BufferSize ) /*++ Routine Description: GC_TODO: Add function description Arguments: OutFptr - GC_TODO: add argument description Buffer - GC_TODO: add argument description BufferSize - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ { EFI_HII_PACK_HEADER *PackHeader; PackHeader = (EFI_HII_PACK_HEADER *) Buffer; // // Check size match // if (PackHeader->Length != (unsigned int) BufferSize) { return ; } // // Check type // switch (PackHeader->Type) { case EFI_HII_STRING: fprintf (stdout, "Dumping as string pack\n"); DumpStringPack (OutFptr, (EFI_HII_STRING_PACK *) Buffer, 0, 2); break; case EFI_HII_IFR: fprintf (stdout, "Dumping as IFR pack\n"); DumpIfrPack (OutFptr, (EFI_HII_IFR_PACK *) Buffer, 0, 2); break; case EFI_HII_VARIABLE: fprintf (stdout, "Dumping as IFR pack\n"); DumpVariablePacks (OutFptr, (EFI_HII_VARIABLE_PACK *) Buffer, 1, 0, 2); break; } } static void DumpRawBytes ( FILE *OutFptr, char *Buffer, int Count, int BaseOffset, int Indent ) /*++ Routine Description: GC_TODO: Add function description Arguments: OutFptr - GC_TODO: add argument description Buffer - GC_TODO: add argument description Count - GC_TODO: add argument description BaseOffset - GC_TODO: add argument description Indent - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ { int Counter; for (Counter = 0; Counter < Count; Counter++) { if ((Counter & 0xF) == 0) { if (Counter != 0) { fprintf (OutFptr, "\n%*c%08X ", Indent, ' ', Counter); } else { fprintf (OutFptr, "\n%*c%08X ", Indent, ' ', Counter); } } fprintf (OutFptr, "%02X ", (unsigned int) (unsigned char) *Buffer); Buffer++; } fprintf (OutFptr, "\n"); } void GuidToString ( EFI_GUID *Guid, char *Str ) /*++ Routine Description: Given a pointer to a GUID, sprint the value into a string Arguments: Guid - pointer to input GUID Str - pointer to outgoing printed GUID value Returns: NA --*/ { sprintf ( Str, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", Guid->Data1, Guid->Data2, Guid->Data3, Guid->Data4[0], Guid->Data4[1], Guid->Data4[2], Guid->Data4[3], Guid->Data4[4], Guid->Data4[5], Guid->Data4[6], Guid->Data4[7] ); } int FindFilesCallback ( char *FoundFileName ) /*++ Routine Description: Callback function used to get files matching a file mask. This function is called when the command-line arguments to this utility are parsed and the user specified "-s Path FileMask" to process all HII export files in Path and its subdirectories that match FileMask. Arguments: FoundFileName - name of file found. Returns: non-zero - caller should halt processing zero - no problems while processing FoundFileName --*/ { FILE_NAME_LIST *FileName; FILE_NAME_LIST *TempFileName; FileName = (FILE_NAME_LIST *) malloc (sizeof (FILE_NAME_LIST)); if (FileName == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); return STATUS_ERROR; } memset ((void *) FileName, 0, sizeof (FILE_NAME_LIST)); strcpy (FileName->FileName, FoundFileName); if (mGlobals.HiiExportFileNames == NULL) { mGlobals.HiiExportFileNames = FileName; } else { // // Add to the end of the list // for (TempFileName = mGlobals.HiiExportFileNames; TempFileName->Next != NULL; TempFileName = TempFileName->Next) ; TempFileName->Next = FileName; } return 0; } static STATUS ProcessArgs ( int Argc, char *Argv[] ) /*++ Routine Description: Process the command line arguments Arguments: As per standard C main() Returns: STATUS_SUCCESS - if successful STATUS_ERROR - otherwise --*/ // GC_TODO: Argc - add argument and description to function comment // GC_TODO: ] - add argument and description to function comment { FILE_NAME_LIST *FileName; FILE_NAME_LIST *TempFileName; FILE *InFptr; EFI_HII_PACK_HEADER PackHeader; memset ((void *) &mGlobals, 0, sizeof (mGlobals)); // // Skip program name // Argc--; Argv++; if (Argc == 0) { Usage (); return STATUS_ERROR; } // // First arg must be one of create, merge, defaults, or dump // if (_stricmp (Argv[0], "create") == 0) { mGlobals.Mode = MODE_CREATE_HII_EXPORT; } else if (_stricmp (Argv[0], "merge") == 0) { mGlobals.Mode = MODE_MERGE_HII_EXPORTS; } else if (_stricmp (Argv[0], "defaults") == 0) { mGlobals.Mode = MODE_EMIT_DEFAULTS; } else if (_stricmp (Argv[0], "dump") == 0) { mGlobals.Mode = MODE_DUMP_HII_EXPORT; } else if (strcmp (Argv[0], "-?") == 0) { Usage (); return STATUS_ERROR; } else { Error (NULL, 0, 0, Argv[0], "unrecognized mode"); return STATUS_ERROR; } Argv++; Argc--; // // Process until no more args. // while (Argc > 0) { if (_stricmp (Argv[0], "-o") == 0) { // // -o option to specify the output file // if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing output file name"); return STATUS_ERROR; } if (mGlobals.OutputFileName[0] == 0) { mGlobals.OutputFileName[MAX_PATH - 1] = 0; strncpy (mGlobals.OutputFileName, Argv[1], MAX_PATH - 1); } else { Error (UTILITY_NAME, 0, 0, Argv[1], "-o option already specified with '%s'", mGlobals.OutputFileName); return STATUS_ERROR; } Argv++; Argc--; } else if (_stricmp (Argv[0], "-mfg") == 0) { mGlobals.MfgFlag = 1; } else if (_stricmp (Argv[0], "-g") == 0) { // // -g option to specify the guid // if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing GUID"); return STATUS_ERROR; } StringToGuid (Argv[1], &mGlobals.Guid); mGlobals.GuidSpecified = 1; Argv++; Argc--; } else if (_stricmp (Argv[0], "-v") == 0) { mGlobals.Verbose = 1; } else if (_stricmp (Argv[0], "-p") == 0) { // // -p option to specify an input pack file. Only valid for 'create' mode // if (mGlobals.Mode != MODE_CREATE_HII_EXPORT) { Error (NULL, 0, 0, Argv[0], "option only valid in 'create' mode"); return STATUS_ERROR; } if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing pack file name"); return STATUS_ERROR; } // // Consume arguments until next -arg or end // do { Argv++; Argc--; // // Open the file, read the pack header, and figure out what type of // HII pack it is. // if ((InFptr = fopen (Argv[0], "rb")) == NULL) { Error (NULL, 0, 0, Argv[0], "failed to open input HII pack file for reading"); return STATUS_ERROR; } if (fread (&PackHeader, sizeof (EFI_HII_PACK_HEADER), 1, InFptr) != 1) { Error (NULL, 0, 0, Argv[0], "failed to read pack header from input HII pack file"); fclose (InFptr); return STATUS_ERROR; } fclose (InFptr); if ((PackHeader.Type != EFI_HII_STRING) && (PackHeader.Type != EFI_HII_IFR) && (PackHeader.Type != EFI_HII_VARIABLE) ) { Error (NULL, 0, 0, Argv[0], "unsupported HII pack type 0x%X", (unsigned int) PackHeader.Type); return STATUS_ERROR; } // // Add this file name to our list of pack files // FileName = (FILE_NAME_LIST *) malloc (sizeof (FILE_NAME_LIST)); if (FileName == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); return STATUS_ERROR; } memset ((void *) FileName, 0, sizeof (FILE_NAME_LIST)); FileName->Tag = (int) PackHeader.Type; strcpy (FileName->FileName, Argv[0]); if (mGlobals.PackFileNames == NULL) { mGlobals.PackFileNames = FileName; } else { // // Add to the end of the list // for (TempFileName = mGlobals.PackFileNames; TempFileName->Next != NULL; TempFileName = TempFileName->Next) ; TempFileName->Next = FileName; } } while ((Argc > 1) && (Argv[1][0] != '-')); } else if (_stricmp (Argv[0], "-noemptyvarpacks") == 0) { mGlobals.NoEmptyVarPacks = 1; } else if (_stricmp (Argv[0], "-novarpacks") == 0) { mGlobals.NoVarPacks = 1; } else if (_stricmp (Argv[0], "-x") == 0) { // // -x option to specify an input HII export file name. Not valid for 'create' mode // if (mGlobals.Mode == MODE_CREATE_HII_EXPORT) { Error (NULL, 0, 0, Argv[0], "option is not valid in 'create' mode"); return STATUS_ERROR; } if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing HII export input file name"); return STATUS_ERROR; } // // Consume arguments until next -arg or end // do { Argv++; Argc--; // // Add this file name to our list of export files // FileName = (FILE_NAME_LIST *) malloc (sizeof (FILE_NAME_LIST)); if (FileName == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); return STATUS_ERROR; } memset ((void *) FileName, 0, sizeof (FILE_NAME_LIST)); strcpy (FileName->FileName, Argv[0]); if (mGlobals.HiiExportFileNames == NULL) { mGlobals.HiiExportFileNames = FileName; } else { // // Add to the end of the list // for (TempFileName = mGlobals.HiiExportFileNames; TempFileName->Next != NULL; TempFileName = TempFileName->Next ) ; TempFileName->Next = FileName; } } while ((Argc > 1) && (Argv[1][0] != '-')); } else if (_stricmp (Argv[0], "-dumpstrings") == 0) { mGlobals.DumpStrings = 1; } else if (_stricmp (Argv[0], "-s") == 0) { // // -s option to specify input HII export files using a path and file mask. // Only valid in merge mode // if (mGlobals.Mode != MODE_MERGE_HII_EXPORTS) { Error (NULL, 0, 0, Argv[0], "option only valid in 'merge' mode"); return STATUS_ERROR; } if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing root directory name"); return STATUS_ERROR; } if ((Argc <= 2) || (Argv[2][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing file mask"); return STATUS_ERROR; } // // Call our function to process the directory and file mask. If // the directory does not start with c:\, then prepend cwd to it. // if (FindFiles (Argv[1], Argv[2], FindFilesCallback)) { Error (NULL, 0, 0, "failed to process matching files", "%s\\%s", Argv[1], Argv[2]); return STATUS_ERROR; } Argv += 2; Argc -= 2; } else if (_stricmp (Argv[0], "-p") == 0) { // // -p option to specify an input pack file. Only valid for 'create' mode // if (mGlobals.Mode != MODE_CREATE_HII_EXPORT) { Error (NULL, 0, 0, Argv[0], "option only valid in 'create' mode"); return STATUS_ERROR; } if ((Argc <= 1) || (Argv[1][0] == '-')) { Error (UTILITY_NAME, 0, 0, Argv[0], "missing pack file name"); return STATUS_ERROR; } // // Consume arguments until next -arg or end // do { Argv++; Argc--; // // Open the file, read the pack header, and figure out what type of // HII pack it is. // if ((InFptr = fopen (Argv[0], "rb")) == NULL) { Error (NULL, 0, 0, Argv[0], "failed to open input HII pack file for reading"); return STATUS_ERROR; } if (fread (&PackHeader, sizeof (EFI_HII_PACK_HEADER), 1, InFptr) != 1) { Error (NULL, 0, 0, Argv[0], "failed to read pack header from input HII pack file"); fclose (InFptr); return STATUS_ERROR; } fclose (InFptr); if ((PackHeader.Type != EFI_HII_STRING) && (PackHeader.Type != EFI_HII_IFR) && (PackHeader.Type != EFI_HII_VARIABLE) ) { Error (NULL, 0, 0, Argv[0], "unsupported HII pack type 0x%X", (unsigned int) PackHeader.Type); return STATUS_ERROR; } // // Add this file name to our list of pack files // FileName = (FILE_NAME_LIST *) malloc (sizeof (FILE_NAME_LIST)); if (FileName == NULL) { Error (NULL, 0, 0, "memory allocation failure", NULL); return STATUS_ERROR; } memset ((void *) FileName, 0, sizeof (FILE_NAME_LIST)); FileName->Tag = (int) PackHeader.Type; strcpy (FileName->FileName, Argv[0]); if (mGlobals.PackFileNames == NULL) { mGlobals.PackFileNames = FileName; } else { // // Add to the end of the list // for (TempFileName = mGlobals.PackFileNames; TempFileName->Next != NULL; TempFileName = TempFileName->Next) ; TempFileName->Next = FileName; } } while ((Argc > 1) && (Argv[1][0] != '-')); } else { Error (NULL, 0, 0, Argv[0], "unrecognized option"); return STATUS_ERROR; } Argv++; Argc--; } // // All modes except 'defaults' requires an output file name // if (mGlobals.Mode != MODE_EMIT_DEFAULTS) { if (mGlobals.OutputFileName[0] == 0) { Error (NULL, 0, 0, "must specify '-o OutputFileName'", NULL); return STATUS_ERROR; } // // If merging, then you have to specify at least one HII export files. // We support specifying only one file in case you want to take an export file // and emit a copy with different (for example, manufacturing) defaults. // if (mGlobals.Mode == MODE_MERGE_HII_EXPORTS) { if (mGlobals.HiiExportFileNames == NULL) { Error (NULL, 0, 0, "must specify at least one HII export file in 'merge' mode", NULL); return STATUS_ERROR; } } else if (mGlobals.Mode == MODE_CREATE_HII_EXPORT) { // // Must have specified at least one HII pack file // if (mGlobals.PackFileNames == NULL) { Error (NULL, 0, 0, "must specify at least one input HII pack file in 'create' mode", NULL); return STATUS_ERROR; } } } else { // // Must have specified an input HII export file name // if (mGlobals.HiiExportFileNames == NULL) { Error (NULL, 0, 0, "must specify at least one '-x HiiExportFileName'", NULL); return STATUS_ERROR; } } return STATUS_SUCCESS; } static void Usage ( VOID ) /*++ Routine Description: Print usage information for this utility. Arguments: None. Returns: Nothing. --*/ { int Index; const char *Str[] = { UTILITY_NAME" "UTILITY_VERSION" - Create/Dump HII Database Files Utility", " Copyright (C), 2004 - 2008 Intel Corporation", #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) ) " Built from "UTILITY_BUILD", project of "UTILITY_VENDOR, #endif "", "Usage:", " "UTILITY_NAME " [MODE] [OPTION]", "Modes:", " create create an HII export file from one or more HII pack files", " merge merge two or more HII export files into one HII export file", " defaults emit variable defaults from an input HII export file", " dump ASCII dump the contents of an HII export file", "Options for all modes:", " -o FileName write output to FileName", " -mfg use manufacturing defaults from IFR rather than standard defaults", " -g GUID use GUID for a package GUID in the data tables where applicable", " -v verbose operation", "Options for 'create' mode:", " -p PackFileName(s) include contents of HII pack file PackFileName", " in the output file", " -novarpacks don't emit variable packs to the output file", "Options for 'merge' mode:", " -x HiiExportFileName(s) include contents of HII export file", " HiiExportFileName in the output file", " -s Path FileMask include all matching HII export files in Path", " and its subdirectories in the output file.", " If Path does not begin with the form C:\\, then", " it is assumed to be relative to the current working", " directory. FileMask may contain wildcard characters.", "Options for 'defaults' mode:", " -x HiiExportFileName emit defaults from all variables referenced", " in input file HiiExportFileName", " -noemptyvarpacks don't emit variable packs for 0-length variables", "Options for 'dump' mode:", " -x HiiExportFileName dump contents of input file HiiExportFileName", " -dumpstrings dump string data", NULL }; for (Index = 0; Str[Index] != NULL; Index++) { fprintf (stdout, "%s\n", Str[Index]); } }