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