| /*++ | |
| Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| HiiPack.c | |
| Abstract: | |
| Process HII export and pack files and create HII export files, | |
| dumps, or variable defaults packs. | |
| --*/ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <stdlib.h> | |
| #include <ctype.h> | |
| #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]); | |
| } | |
| } |