]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/CodeTools/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c
Restructuring for better separation of Tool packages.
[mirror_edk2.git] / Tools / CodeTools / TianoTools / GenCapsuleHdr / GenCapsuleHdr.c
diff --git a/Tools/CodeTools/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c b/Tools/CodeTools/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c
new file mode 100644 (file)
index 0000000..d1f55b9
--- /dev/null
@@ -0,0 +1,2674 @@
+/*++\r
+\r
+Copyright (c)  2002-2006 Intel Corporation. All rights reserved\r
+This program and the accompanying materials are licensed and made available \r
+under the terms and conditions of the BSD License which accompanies this \r
+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
+\r
+Module Name:\r
+\r
+  GenCapsuleHdr.c  \r
+\r
+Abstract:\r
+\r
+  Generate a capsule header for a file, and optionally prepend the\r
+  header to a file or list of files.\r
+\r
+--*/\r
+\r
+#define _UNICODE\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+\r
+#include <Common/UefiBaseTypes.h>\r
+#include <Common/MultiPhase.h>\r
+#include <Common/Capsule.h>\r
+#include <Common/FirmwareVolumeImageFormat.h>\r
+#include <Common/FirmwareVolumeHeader.h>\r
+#include <Common/FirmwareFileSystem.h>  // for FV header GUID\r
+#include <Guid/Capsule.h>\r
+#include <Guid/FirmwareFileSystem.h>  // for FV header GUID\r
+\r
+#include "CommonLib.h"\r
+#include "EfiUtilityMsgs.h"\r
+\r
+#define MAX_PATH                  256\r
+#define PROGRAM_NAME              "GenCapsuleHdr"\r
+\r
+#define UNICODE_BACKSLASH         L'\\'\r
+#define UNICODE_FILE_START        0xFEFF\r
+#define UNICODE_CR                0x000D\r
+#define UNICODE_LF                0x000A\r
+#define UNICODE_NULL              0x0000\r
+#define UNICODE_SPACE             L' '\r
+#define UNICODE_SLASH             L'/'\r
+#define UNICODE_DOUBLE_QUOTE      L'"'\r
+#define UNICODE_A                 L'A'\r
+#define UNICODE_F                 L'F'\r
+#define UNICODE_Z                 L'Z'\r
+#define UNICODE_a                 L'a'\r
+#define UNICODE_f                 L'f'\r
+#define UNICODE_z                 L'z'\r
+#define UNICODE_0                 L'0'\r
+#define UNICODE_9                 L'9'\r
+#define UNICODE_TAB               L'\t'\r
+\r
+#define OEM_HEADER_STRING         L"OemHeader"\r
+#define AUTHOR_INFO_STRING        L"AuthorInfo"\r
+#define REVISION_INFO_STRING      L"RevisionInfo"\r
+#define SHORT_DESCRIPTION_STRING  L"ShortDescription"\r
+#define LONG_DESCRIPTION_STRING   L"LongDescription"\r
+#define EQUAL_STRING              L"="\r
+#define OPEN_BRACE_STRING         L"{"\r
+#define CLOSE_BRACE_STRING        L"}"\r
+#define GUID_STRING               L"GUID"\r
+#define DATA_STRING               L"DATA"\r
+\r
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
+#define UEFI_CAPSULE_HEADER_NO_FALAGS      0\r
+#define UEFI_CAPSULE_HEADER_RESET_FALAGS   CAPSULE_FLAGS_PERSIST_ACROSS_RESET\r
+#define UEFI_CAPSULE_HEADER_ALL_FALAGS     (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)\r
+#endif\r
+\r
+typedef wchar_t WCHAR;\r
+\r
+typedef struct _FILE_LIST {\r
+  struct _FILE_LIST *Next;\r
+  INT8              FileName[MAX_PATH];\r
+} FILE_LIST;\r
+\r
+typedef struct _SIZE_LIST {\r
+  struct _SIZE_LIST *Next;\r
+  UINT32            Size;\r
+} SIZE_LIST;\r
+\r
+typedef struct {\r
+  INT8    FileName[MAX_PATH];\r
+  WCHAR   *FileBuffer;\r
+  WCHAR   *FileBufferPtr;\r
+  UINT32  FileSize;\r
+  FILE    *FilePtr;\r
+  BOOLEAN EndOfFile;\r
+  UINT32  LineNum;\r
+} SOURCE_FILE;\r
+\r
+//\r
+// Here's all our globals.\r
+//\r
+static struct {\r
+  BOOLEAN   Dump;\r
+  BOOLEAN   Verbose;\r
+  BOOLEAN   JoinMode;\r
+  INT8      ScriptFileName[MAX_PATH];\r
+  INT8      OutputFileName[MAX_PATH];\r
+  FILE_LIST *FileList;\r
+  FILE      *OutFptr;\r
+  SIZE_LIST *SizeList;\r
+  SIZE_LIST *LastSize;\r
+  SIZE_LIST *CurrentSize;\r
+} mOptions;\r
+\r
+static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;\r
+\r
+void\r
+CreateGuid (\r
+  EFI_GUID *Guid\r
+  );\r
+\r
+static\r
+STATUS\r
+ProcessArgs (\r
+  int   Argc,\r
+  char  *Argv[]\r
+  );\r
+\r
+static\r
+void\r
+SkipWhiteSpace (\r
+  SOURCE_FILE *SourceFile\r
+  );\r
+\r
+static\r
+STATUS\r
+GetHexValue (\r
+  SOURCE_FILE  *SourceFile,\r
+  UINT32       *Value,\r
+  UINT32       NumDigits\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+GetSplitFileName (\r
+  INT8    *BaseFileName,\r
+  INT8    *NewFileName,\r
+  UINT32  SequenceNumber\r
+  );\r
+\r
+static\r
+STATUS\r
+SplitCapsule (\r
+  INT8 *CapsuleFileName\r
+  );\r
+\r
+static\r
+void\r
+Usage (\r
+  VOID\r
+  );\r
+\r
+static\r
+void\r
+DumpCapsule (\r
+  VOID\r
+  );\r
+\r
+static\r
+STATUS\r
+JoinCapsule (\r
+  VOID\r
+  );\r
+\r
+static\r
+STATUS\r
+DumpCapsuleHeaderStrings (\r
+  UINT8   *SectionName,\r
+  WCHAR   *Buffer\r
+  );\r
+\r
+static\r
+STATUS\r
+CheckFirmwareVolumeHeader (\r
+  INT8    *FileName,\r
+  INT8    *Buffer,\r
+  UINT32  BufferSize\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+IsToken (\r
+  SOURCE_FILE *File,\r
+  WCHAR       *Token\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+GetNumber (\r
+  INT8    *Str,\r
+  UINT32  *Value\r
+  );\r
+\r
+static\r
+STATUS\r
+ProcessScriptFile (\r
+  INT8                *ScriptFileName,\r
+  FILE                *OutFptr,\r
+  EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  );\r
+\r
+static\r
+STATUS\r
+ParseCapsuleInfo (\r
+  SOURCE_FILE       *SourceFile,\r
+  FILE              *OutFptr,\r
+  WCHAR             *SectionName\r
+  );\r
+\r
+static\r
+STATUS\r
+CreateCapsule (\r
+  VOID\r
+  );\r
+\r
+static\r
+STATUS\r
+ParseOemInfo (\r
+  SOURCE_FILE       *SourceFile,\r
+  FILE              *OutFptr\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+IsWhiteSpace (\r
+  WCHAR Char\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+EndOfFile (\r
+  SOURCE_FILE *File\r
+  );\r
+\r
+int\r
+main (\r
+  int   Argc,\r
+  char  *Argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Call the routine to process the command-line arguments, then\r
+  dispatch to the appropriate function.\r
+  \r
+Arguments:\r
+  Standard C main() argc and argv.\r
+\r
+Returns:\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
+  FILE_LIST *NextFile;\r
+  //\r
+  // Specify our program name to the error printing routines.\r
+  //\r
+  SetUtilityName (PROGRAM_NAME);\r
+  //\r
+  // Process the command-line arguments\r
+  //\r
+  Status = ProcessArgs (Argc, Argv);\r
+  if (Status == STATUS_SUCCESS) {\r
+    if (mOptions.Dump) {\r
+      DumpCapsule ();\r
+    } else if (mOptions.JoinMode) {\r
+      JoinCapsule ();\r
+    } else {\r
+      CreateCapsule ();\r
+    }\r
+  }\r
+  //\r
+  // Cleanup\r
+  //\r
+  while (mOptions.FileList != NULL) {\r
+    NextFile = mOptions.FileList->Next;\r
+    free (mOptions.FileList);\r
+    mOptions.FileList = NextFile;\r
+  }\r
+\r
+  while (mOptions.SizeList != NULL) {\r
+    mOptions.CurrentSize = mOptions.SizeList->Next;\r
+    free (mOptions.SizeList);\r
+    mOptions.SizeList = mOptions.CurrentSize;\r
+  }\r
+\r
+  return GetUtilityStatus ();\r
+}\r
+\r
+static\r
+STATUS\r
+CreateCapsule (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  FILE                        *InFptr;\r
+  FILE_LIST                   *FileList;\r
+  INT8                        *Buffer;\r
+  UINT32                      Size;\r
+  EFI_CAPSULE_HEADER          CapsuleHeader;\r
+  UINT8                       Zero;\r
+  UINT8                       FirstFile;\r
+  UINT32                      CapsuleHeaderSize;\r
+  long                        InsertedBlockMapEntryOffset;\r
+  EFI_FV_BLOCK_MAP_ENTRY      InsertedBlockMapEntry;\r
+  UINT64                      FirmwareVolumeSize;\r
+  long                        FileSize;\r
+  EFI_FIRMWARE_VOLUME_HEADER  FVHeader;\r
+\r
+  Buffer                      = NULL;\r
+  InFptr                      = NULL;\r
+  FirmwareVolumeSize          = 0;\r
+  CapsuleHeaderSize           = 0;\r
+  InsertedBlockMapEntryOffset = 0;\r
+  memset (&InsertedBlockMapEntry, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
+  memset (&FVHeader, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
+\r
+  if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
+    Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  memset ((char *) &CapsuleHeader, 0, sizeof (CapsuleHeader));\r
+  memcpy ((void *) &CapsuleHeader.CapsuleGuid, (void *) &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID));\r
+  CapsuleHeader.HeaderSize        = sizeof (EFI_CAPSULE_HEADER);\r
+  CapsuleHeader.CapsuleImageSize  = sizeof (EFI_CAPSULE_HEADER);\r
+  if (mOptions.ScriptFileName[0] != 0) {\r
+    if (ProcessScriptFile (mOptions.ScriptFileName, mOptions.OutFptr, &CapsuleHeader) != STATUS_SUCCESS) {\r
+      goto Done;\r
+    }\r
+  } else {\r
+    //\r
+    // Insert a default capsule header\r
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
+    CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
+    CapsuleHeader.Flags   = UEFI_CAPSULE_HEADER_ALL_FALAGS;\r
+#endif\r
+    CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER);\r
+\r
+   if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
+     Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+     goto Done;\r
+   }\r
+ }\r
+\r
+  CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody;\r
+  //\r
+  // Now copy the contents of any other files specified on the command\r
+  // line to the output file. Files must be FFS files, which are aligned\r
+  // on 8-byte boundaries. Don't align the first file, since it's the start\r
+  // of the image once the capsule header has been removed.\r
+  //\r
+  FileList  = mOptions.FileList;\r
+  FirstFile = 1;\r
+  Zero      = 0;\r
+  while (FileList != NULL) {\r
+    if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+      goto Done;\r
+    }\r
+    //\r
+    // Allocate a buffer into which we can read the file.\r
+    //\r
+    fseek (InFptr, 0, SEEK_END);\r
+    Size = ftell (InFptr);\r
+    rewind (InFptr);\r
+    Buffer = (char *) malloc (Size);\r
+    if (Buffer == NULL) {\r
+      Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
+      goto Done;\r
+    }\r
+\r
+    if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
+      goto Done;\r
+    }\r
+\r
+    if (Size > 0) {\r
+      //\r
+      // Align the write of the first bytes from the file if not the first file\r
+      //\r
+      if (FirstFile) {\r
+        //\r
+        // First file must be a firmware volume. Double-check, and then insert\r
+        // an additional block map entry so we can add more files from the command line\r
+        //\r
+        if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) {\r
+          goto Done;\r
+        }\r
+        //\r
+        // Save a copy of the firmware volume header for later\r
+        //\r
+        memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
+        FirmwareVolumeSize = FVHeader.FvLength;\r
+        if (FileList->Next != NULL) {\r
+          //\r
+          // Copy the firmware volume header\r
+          //\r
+          InsertedBlockMapEntryOffset = CapsuleHeaderSize + FVHeader.HeaderLength;\r
+          if (fwrite (Buffer, FVHeader.HeaderLength, 1, mOptions.OutFptr) != 1) {\r
+            Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+            goto Done;\r
+          }\r
+\r
+          if (fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr) != 1) {\r
+            Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+            goto Done;\r
+          }\r
+\r
+          if (fwrite (\r
+                Buffer + FVHeader.HeaderLength,\r
+                Size - FVHeader.HeaderLength,\r
+                1,\r
+                mOptions.OutFptr\r
+                ) != 1) {\r
+            Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+            goto Done;\r
+          }\r
+        } else {\r
+          //\r
+          // Copy the file contents as-is\r
+          //\r
+          if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
+            Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+            goto Done;\r
+          }\r
+        }\r
+      } else {\r
+        while ((ftell (mOptions.OutFptr) - CapsuleHeaderSize) & 0x07) {\r
+          if (fwrite ((void *) &Zero, 1, 1, mOptions.OutFptr) != 1) {\r
+            Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+            goto Done;\r
+          }\r
+        }\r
+\r
+        if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
+          Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      FirstFile = 0;\r
+    }\r
+\r
+    free (Buffer);\r
+    Buffer = NULL;\r
+    fclose (InFptr);\r
+    InFptr    = NULL;\r
+    FileList  = FileList->Next;\r
+  }\r
+\r
+Done:\r
+  if (Buffer != NULL) {\r
+    free (Buffer);\r
+  }\r
+\r
+  if (InFptr != NULL) {\r
+    fclose (InFptr);\r
+  }\r
+  //\r
+  // If we inserted an additional block map entry, then fix it up. Fix up the\r
+  // FV header as well to reflect our new size.\r
+  //\r
+  if (InsertedBlockMapEntryOffset != 0) {\r
+    FileSize                        = ftell (mOptions.OutFptr);\r
+    InsertedBlockMapEntry.NumBlocks = 1;\r
+    InsertedBlockMapEntry.BlockLength = (UINT32) ((UINT64) FileSize - (UINT64) CapsuleHeaderSize - FirmwareVolumeSize - sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
+    fseek (mOptions.OutFptr, InsertedBlockMapEntryOffset, SEEK_SET);\r
+    fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
+    //\r
+    // Fix up the firmware volume header and write it out\r
+    //\r
+    fseek (mOptions.OutFptr, CapsuleHeaderSize, SEEK_SET);\r
+    FVHeader.FvLength = FileSize - CapsuleHeaderSize;\r
+    FVHeader.HeaderLength += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
+    fwrite (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
+    //\r
+    // Reposition to the end of the file\r
+    //\r
+  }\r
+  //\r
+  // Close files and free the global string lists we allocated memory for\r
+  //\r
+  if (mOptions.OutFptr != NULL) {\r
+    //\r
+    // We should now know the full capsule image size. Update the header and write it again.\r
+    //\r
+    fseek (mOptions.OutFptr, 0, SEEK_END);\r
+    Size  = ftell (mOptions.OutFptr);\r
+    CapsuleHeader.CapsuleImageSize = Size;\r
+    fseek (mOptions.OutFptr, 0, SEEK_SET);\r
+    if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
+      Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+    }\r
+\r
+    fseek (mOptions.OutFptr, 0, SEEK_END);\r
+    fclose (mOptions.OutFptr);\r
+    mOptions.OutFptr = NULL;\r
+  }\r
+  //\r
+  // If they are doing split capsule output, then split it up now.\r
+  //\r
+  if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) {\r
+    SplitCapsule (mOptions.OutputFileName);\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+ProcessScriptFile (\r
+  INT8                *ScriptFileName,\r
+  FILE                *OutFptr,\r
+  EFI_CAPSULE_HEADER  *CapsuleHeader\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Parse a capsule header script file.\r
+\r
+Arguments:\r
+  ScriptFileName    - name of script file to parse\r
+  OutFptr           - output to dump binary data\r
+  CapsuleHeader     - capsule header to update with size info\r
+                      of parsed fields in the script file\r
+\r
+Returns:\r
+  STATUS_SUCCESS - if all went well\r
+\r
+--*/\r
+{\r
+#if 0\r
+  STATUS      Status;\r
+  SOURCE_FILE SourceFile;\r
+  WCHAR       *WScriptFileName;\r
+  BOOLEAN     InComment;\r
+\r
+  if (fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr) != 1) {\r
+    Error (NULL, 0, 0, "failed to write capsule header to output file", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  memset (&SourceFile, 0, sizeof (SOURCE_FILE));\r
+  strcpy (SourceFile.FileName, ScriptFileName);\r
+\r
+  Status = STATUS_ERROR;\r
+  //\r
+  // Open the input unicode script file and read it into a buffer\r
+  //\r
+  WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR));\r
+  if (WScriptFileName == NULL) {\r
+    Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  swprintf (WScriptFileName, L"%S", ScriptFileName);\r
+  if ((SourceFile.FilePtr = _wfopen (WScriptFileName, L"r")) == NULL) {\r
+    free (WScriptFileName);\r
+    Error (NULL, 0, 0, ScriptFileName, "failed to open script file for reading");\r
+    goto Done;\r
+  }\r
+\r
+  free (WScriptFileName);\r
+  fseek (SourceFile.FilePtr, 0, SEEK_END);\r
+  SourceFile.FileSize = ftell (SourceFile.FilePtr);\r
+  rewind (SourceFile.FilePtr);\r
+  SourceFile.FileBuffer = (WCHAR *) malloc (SourceFile.FileSize + sizeof (WCHAR));\r
+  if (SourceFile.FileBuffer == NULL) {\r
+    Error (__FILE__, __LINE__, 0, ScriptFileName, "failed to allocate memory to read in file contents");\r
+    goto Done;\r
+  }\r
+\r
+  if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) {\r
+    Error (NULL, 0, 0, ScriptFileName, "failed to read file contents");\r
+    goto Done;\r
+  }\r
+\r
+  SourceFile.FileBufferPtr  = SourceFile.FileBuffer;\r
+  SourceFile.LineNum        = 1;\r
+  if (SourceFile.FileBuffer[0] != UNICODE_FILE_START) {\r
+    Error (ScriptFileName, 1, 0, "file does not appear to be a unicode file", NULL);\r
+    goto Done;\r
+  }\r
+\r
+  SourceFile.FileBufferPtr++;\r
+  SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0;\r
+  //\r
+  // Walk the source file buffer and replace all carriage returns with 0 so\r
+  // we can print from the file contents on parse errors.\r
+  //\r
+  InComment = 0;\r
+  while (!EndOfFile (&SourceFile)) {\r
+    if (SourceFile.FileBufferPtr[0] == UNICODE_CR) {\r
+      SourceFile.FileBufferPtr[0] = 0;\r
+      InComment                   = 0;\r
+    } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) {\r
+      InComment = 0;\r
+    } else if (InComment) {\r
+      SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
+    } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) {\r
+      InComment                   = 1;\r
+      SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
+    }\r
+\r
+    SourceFile.FileBufferPtr++;\r
+  }\r
+  //\r
+  // Reposition to the start of the file, but skip over the unicode file start\r
+  //\r
+  SourceFile.FileBufferPtr = SourceFile.FileBuffer;\r
+  SourceFile.FileBufferPtr++;\r
+  SourceFile.EndOfFile                    = 0;\r
+  CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr);\r
+  //\r
+  // Parse the OEM bytes\r
+  //\r
+  if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Parse the author information\r
+  //\r
+  CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr);\r
+  if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Parse the revision information\r
+  //\r
+  CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr);\r
+  if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Parse the short description\r
+  //\r
+  CapsuleHeader->OffsetToShortDescription = ftell (OutFptr);\r
+  if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Parse the long description\r
+  //\r
+  CapsuleHeader->OffsetToLongDescription = ftell (OutFptr);\r
+  if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
+    goto Done;\r
+  }\r
+  //\r
+  // Better be end of contents\r
+  //\r
+  SkipWhiteSpace (&SourceFile);\r
+  if (!EndOfFile (&SourceFile)) {\r
+    Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr);\r
+    goto Done;\r
+  }\r
+\r
+  CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr);\r
+  rewind (OutFptr);\r
+  fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr);\r
+  fseek (OutFptr, 0, SEEK_END);\r
+  Status = STATUS_SUCCESS;\r
+Done:\r
+  if (SourceFile.FilePtr != NULL) {\r
+    fclose (SourceFile.FilePtr);\r
+  }\r
+\r
+  if (SourceFile.FileBuffer != NULL) {\r
+    free (SourceFile.FileBuffer);\r
+  }\r
+\r
+  return Status;\r
+\r
+#endif\r
+  return STATUS_SUCCESS;\r
+}\r
+//\r
+// Parse the OEM data of format:\r
+//      OemInfo {\r
+//            GUID = 12345676-1234-1234-123456789ABC\r
+//            DATA = 0x01, 0x02, 0x03...\r
+//      }\r
+//\r
+static\r
+STATUS\r
+ParseOemInfo (\r
+  SOURCE_FILE       *SourceFile,\r
+  FILE              *OutFptr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  SourceFile  - GC_TODO: add argument description\r
+  OutFptr     - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  long                    OemHeaderOffset;\r
+  UINT32                  Data;\r
+  EFI_CAPSULE_OEM_HEADER  OemHeader;\r
+  STATUS                  Status;\r
+  UINT32                  DigitCount;\r
+  WCHAR                   *SaveFilePos;\r
+  UINT8                   ByteData;\r
+\r
+  Status = STATUS_ERROR;\r
+  memset (&OemHeader, 0, sizeof (EFI_CAPSULE_OEM_HEADER));\r
+  OemHeaderOffset       = ftell (OutFptr);\r
+  OemHeader.HeaderSize  = sizeof (EFI_CAPSULE_OEM_HEADER);\r
+  if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
+    Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, OEM_HEADER_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      OEM_HEADER_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      EQUAL_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      OPEN_BRACE_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+  //\r
+  // Look for:  GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx\r
+  //\r
+  if (!IsToken (SourceFile, GUID_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      GUID_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      EQUAL_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+  //\r
+  // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID\r
+  //\r
+  SkipWhiteSpace (SourceFile);\r
+  if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) {\r
+    Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+    goto Done;\r
+  }\r
+\r
+  OemHeader.OemGuid.Data1 = Data;\r
+  if (!IsToken (SourceFile, L"-")) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected dash in GUID, not %S",\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+  //\r
+  // Get 3 word values\r
+  //\r
+  for (DigitCount = 0; DigitCount < 3; DigitCount++) {\r
+    if (GetHexValue (SourceFile, &Data, 4) != STATUS_SUCCESS) {\r
+      Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    switch (DigitCount) {\r
+    case 0:\r
+      OemHeader.OemGuid.Data2 = (UINT16) Data;\r
+      break;\r
+\r
+    case 1:\r
+      OemHeader.OemGuid.Data3 = (UINT16) Data;\r
+      break;\r
+\r
+    case 2:\r
+      OemHeader.OemGuid.Data4[1]  = (UINT8) Data;\r
+      OemHeader.OemGuid.Data4[0]  = (UINT8) (Data >> 8);\r
+      break;\r
+    }\r
+\r
+    if (!IsToken (SourceFile, L"-")) {\r
+      Error (\r
+        SourceFile->FileName,\r
+        SourceFile->LineNum,\r
+        0,\r
+        NULL,\r
+        "expected dash in GUID, not %S",\r
+        SourceFile->FileBufferPtr\r
+        );\r
+      goto Done;\r
+    }\r
+  }\r
+  //\r
+  // Pick up the last 6 bytes of the GUID\r
+  //\r
+  SaveFilePos = SourceFile->FileBufferPtr;\r
+  for (DigitCount = 0; DigitCount < 6; DigitCount++) {\r
+    if (GetHexValue (SourceFile, &Data, 2) != STATUS_SUCCESS) {\r
+      Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data;\r
+  }\r
+  //\r
+  // Now read raw OEM data bytes. May or may not be present.\r
+  //    DATA = 0x01, 0x02, 0x02...\r
+  //\r
+  if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+    Status = STATUS_SUCCESS;\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, DATA_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      DATA_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      EQUAL_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  while (!EndOfFile (SourceFile)) {\r
+    if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+      Status = STATUS_SUCCESS;\r
+      goto Done;\r
+    }\r
+\r
+    if (IsToken (SourceFile, L"0x")) {\r
+      if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) {\r
+        Error (\r
+          SourceFile->FileName,\r
+          SourceFile->LineNum,\r
+          0,\r
+          NULL,\r
+          "expected hex byte value, not %.20S",\r
+          SourceFile->FileBufferPtr\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      if (Data &~0xFF) {\r
+        Error (\r
+          SourceFile->FileName,\r
+          SourceFile->LineNum,\r
+          0,\r
+          NULL,\r
+          "expected byte hex byte value at %.20S",\r
+          SourceFile->FileBufferPtr\r
+          );\r
+        goto Done;\r
+      }\r
+      //\r
+      // Skip over the hex digits, then write the data\r
+      //\r
+      while (iswxdigit (SourceFile->FileBufferPtr[0])) {\r
+        SourceFile->FileBufferPtr++;\r
+      }\r
+\r
+      ByteData = (UINT8) Data;\r
+      if (fwrite (&ByteData, 1, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, "failed to write OEM data to output file", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      OemHeader.HeaderSize++;\r
+      //\r
+      // Optional comma\r
+      //\r
+      IsToken (SourceFile, L",");\r
+    } else {\r
+      Error (\r
+        SourceFile->FileName,\r
+        SourceFile->LineNum,\r
+        0,\r
+        NULL,\r
+        "expected hex OEM data, not %.20S",\r
+        SourceFile->FileBufferPtr\r
+        );\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+  if (EndOfFile (SourceFile)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S close to OEM header data",\r
+      CLOSE_BRACE_STRING\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  Status = STATUS_SUCCESS;\r
+Done:\r
+  //\r
+  // re-write the oem header if no errors\r
+  //\r
+  if (Status == STATUS_SUCCESS) {\r
+    fseek (OutFptr, OemHeaderOffset, SEEK_SET);\r
+    if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
+      Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    fseek (OutFptr, 0, SEEK_END);\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+ParseCapsuleInfo (\r
+  SOURCE_FILE       *SourceFile,\r
+  FILE              *OutFptr,\r
+  WCHAR             *SectionName\r
+  )\r
+// GC_TODO: function comment should start with '/*++'\r
+//\r
+// GC_TODO: function comment is missing 'Routine Description:'\r
+// GC_TODO: function comment is missing 'Arguments:'\r
+// GC_TODO: function comment is missing 'Returns:'\r
+// GC_TODO:    SourceFile - add argument and description to function comment\r
+// GC_TODO:    OutFptr - add argument and description to function comment\r
+// GC_TODO:    SectionName - add argument and description to function comment\r
+// Parse:  eng "string " "parts"\r
+//          spa "string " "parts"\r
+// Write out: "eng string parts\0spa string parts\0\0\r
+//\r
+{\r
+  STATUS  Status;\r
+  int     StringCount;\r
+  WCHAR   Zero;\r
+  WCHAR   Spacebar;\r
+\r
+  Status    = STATUS_ERROR;\r
+  Zero      = 0;\r
+  Spacebar  = UNICODE_SPACE;\r
+\r
+  if (!IsToken (SourceFile, SectionName)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      SectionName,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      EQUAL_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
+    Error (\r
+      SourceFile->FileName,\r
+      SourceFile->LineNum,\r
+      0,\r
+      NULL,\r
+      "expected %S, not %.20S",\r
+      OPEN_BRACE_STRING,\r
+      SourceFile->FileBufferPtr\r
+      );\r
+    goto Done;\r
+  }\r
+\r
+  while (!EndOfFile (SourceFile)) {\r
+    if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+      break;\r
+    }\r
+    //\r
+    // Look for language identifier (3 lowercase chars)\r
+    //\r
+    if ((SourceFile->FileBufferPtr[0] >= UNICODE_a) &&\r
+        (SourceFile->FileBufferPtr[0] <= UNICODE_z) &&\r
+        (SourceFile->FileBufferPtr[1] >= UNICODE_a) &&\r
+        (SourceFile->FileBufferPtr[1] <= UNICODE_z) &&\r
+        (SourceFile->FileBufferPtr[2] >= UNICODE_a) &&\r
+        (SourceFile->FileBufferPtr[2] <= UNICODE_z) &&\r
+        IsWhiteSpace (SourceFile->FileBufferPtr[3])\r
+          ) {\r
+      //\r
+      // Write the 3 chars followed by a spacebar, and then look for opening quote\r
+      //\r
+      fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+      SourceFile->FileBufferPtr++;\r
+      fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+      SourceFile->FileBufferPtr++;\r
+      fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+      SourceFile->FileBufferPtr++;\r
+      fwrite (&Spacebar, sizeof (WCHAR), 1, OutFptr);\r
+      StringCount = 0;\r
+      while (IsToken (SourceFile, L"\"")) {\r
+        StringCount++;\r
+        while (!EndOfFile (SourceFile)) {\r
+          if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
+            SourceFile->FileBufferPtr++;\r
+            break;\r
+          } else if ((SourceFile->FileBufferPtr[0] == UNICODE_LF) || (SourceFile->FileBufferPtr[0] == 0)) {\r
+            Error (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", NULL);\r
+            goto Done;\r
+          } else {\r
+            fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+            SourceFile->FileBufferPtr++;\r
+          }\r
+        }\r
+      }\r
+\r
+      if (StringCount == 0) {\r
+        Error (\r
+          SourceFile->FileName,\r
+          SourceFile->LineNum,\r
+          0,\r
+          NULL,\r
+          "expected quoted string, not %.20S",\r
+          SourceFile->FileBufferPtr\r
+          );\r
+        goto Done;\r
+      }\r
+      //\r
+      // This string's null terminator\r
+      //\r
+      fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
+    } else {\r
+      Error (\r
+        SourceFile->FileName,\r
+        SourceFile->LineNum,\r
+        0,\r
+        NULL,\r
+        "expected valid language identifer, not %.20S",\r
+        SourceFile->FileBufferPtr\r
+        );\r
+      goto Done;\r
+    }\r
+  }\r
+  //\r
+  // Double null terminator\r
+  //\r
+  fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
+  Status = STATUS_SUCCESS;\r
+Done:\r
+  return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+SplitCapsule (\r
+  INT8    *CapsuleFileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  We've created an entire capsule image. Now split it up into the \r
+  size pieces they requested.\r
+\r
+Arguments:\r
+  CapsuleFileName  - name of an existing capsule file on disk\r
+\r
+Returns:\r
+  STATUS_SUCCESS - if no problems\r
+\r
+Notes:\r
+  This implementation reads in the entire capsule image from\r
+  disk, then overwrites the original file with the first\r
+  in the series.\r
+\r
+--*/\r
+{\r
+#if 0\r
+  EFI_CAPSULE_HEADER  *CapHdr;\r
+\r
+  EFI_CAPSULE_HEADER  Hdr;\r
+  FILE                *CapFptr;\r
+  FILE                *OutFptr;\r
+  UINT32              SizeLeft;\r
+  UINT32              CurrentSize;\r
+  UINT32              DataSize;\r
+  UINT32              SequenceNumber;\r
+  INT8                *Buffer;\r
+  INT8                FileName[MAX_PATH];\r
+  STATUS              Status;\r
+  UINT32              FileSize;\r
+  //\r
+  // Figure out the total size, then rewind the input file and\r
+  // read the entire thing in\r
+  //\r
+  if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) {\r
+    Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  OutFptr = NULL;\r
+  Status  = STATUS_SUCCESS;\r
+  fseek (CapFptr, 0, SEEK_END);\r
+  SizeLeft = ftell (CapFptr);\r
+  fseek (CapFptr, 0, SEEK_SET);\r
+  CapHdr = (EFI_CAPSULE_HEADER *) malloc (SizeLeft);\r
+  if (CapHdr == NULL) {\r
+    Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+    goto FailDone;\r
+  }\r
+\r
+  if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) {\r
+    Error (NULL, 0, 0, "failed to read capsule contents", "split failed");\r
+    goto FailDone;\r
+  }\r
+\r
+  fclose (CapFptr);\r
+  CapFptr = NULL;\r
+  //\r
+  // Get a GUID to fill in the InstanceId GUID in the header\r
+  //\r
+  CreateGuid (&CapHdr->InstanceId);\r
+  SequenceNumber = 0;\r
+  //\r
+  // If the split size is larger than the original capsule image, then\r
+  // we're done.\r
+  //\r
+  if (mOptions.SizeList->Size >= SizeLeft) {\r
+    mOptions.SizeList->Size = SizeLeft;\r
+    goto Done;\r
+  }\r
+  //\r
+  // First size has to be big enough for the original header\r
+  //\r
+  if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) {\r
+    Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL);\r
+    goto FailDone;\r
+  }\r
+  //\r
+  // Initialize the header we'll use on all but the first part\r
+  //\r
+  memset (&Hdr, 0, sizeof (Hdr));\r
+  Hdr.CapsuleGuid         = CapHdr->CapsuleGuid;\r
+  Hdr.HeaderSize          = sizeof (Hdr);\r
+  Hdr.Flags               = CapHdr->Flags;\r
+  Hdr.InstanceId          = CapHdr->InstanceId;\r
+  Hdr.CapsuleImageSize    = CapHdr->CapsuleImageSize;\r
+  Hdr.OffsetToCapsuleBody = Hdr.HeaderSize;\r
+  Hdr.SequenceNumber      = 1;\r
+  //\r
+  // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);\r
+  //\r
+  Buffer = (UINT8 *) CapHdr;\r
+  //\r
+  // Walk the list of sizes and write out a capsule header, and\r
+  // then the raw capsule data.\r
+  //\r
+  //  SizeLeft -= mOptions.SizeList->Size;\r
+  //\r
+  mOptions.CurrentSize = mOptions.SizeList;\r
+  while (SizeLeft) {\r
+    CurrentSize = mOptions.CurrentSize->Size;\r
+    GetSplitFileName (mOptions.OutputFileName, FileName, SequenceNumber);\r
+    if ((OutFptr = fopen (FileName, "wb")) == NULL) {\r
+      Error (NULL, 0, 0, FileName, "failed to open split file for writing");\r
+      goto FailDone;\r
+    }\r
+\r
+    if (Buffer == (UINT8 *) CapHdr) {\r
+      //\r
+      // First part -- write out original header and data\r
+      //\r
+      if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, FileName, "failed to write to split image file");\r
+        goto FailDone;\r
+      }\r
+\r
+      SizeLeft -= CurrentSize;\r
+      Buffer += CurrentSize;\r
+      DataSize  = CurrentSize;\r
+      FileSize  = CurrentSize;\r
+    } else {\r
+      //\r
+      // Not the first part. Write the default header, and then the raw bytes from the\r
+      // original image.\r
+      //\r
+      if (CurrentSize <= sizeof (Hdr)) {\r
+        Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize);\r
+        goto FailDone;\r
+      }\r
+\r
+      DataSize = CurrentSize - sizeof (Hdr);\r
+      if (DataSize > SizeLeft) {\r
+        DataSize = SizeLeft;\r
+      }\r
+\r
+      if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, FileName, "failed to write capsule header to output file");\r
+        fclose (OutFptr);\r
+        goto FailDone;\r
+      }\r
+\r
+      if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, FileName, "failed to write capsule data to output file");\r
+        fclose (OutFptr);\r
+        goto FailDone;\r
+      }\r
+\r
+      Hdr.SequenceNumber++;\r
+      Buffer += DataSize;\r
+      SizeLeft -= DataSize;\r
+      FileSize = DataSize + sizeof (Hdr);\r
+    }\r
+    //\r
+    // Next size in list if there is one\r
+    //\r
+    if (mOptions.CurrentSize->Next != NULL) {\r
+      mOptions.CurrentSize = mOptions.CurrentSize->Next;\r
+    }\r
+\r
+    SequenceNumber++;\r
+    fclose (OutFptr);\r
+    OutFptr = NULL;\r
+    printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize);\r
+  }\r
+\r
+  goto Done;\r
+FailDone:\r
+  Status = STATUS_ERROR;\r
+Done:\r
+  if (CapHdr != NULL) {\r
+    free (CapHdr);\r
+  }\r
+\r
+  if (CapFptr != NULL) {\r
+    fclose (CapFptr);\r
+  }\r
+\r
+  if (OutFptr != NULL) {\r
+    fclose (OutFptr);\r
+  }\r
+\r
+  return Status;\r
+\r
+#endif\r
+   return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+BOOLEAN\r
+GetSplitFileName (\r
+  INT8    *BaseFileName,\r
+  INT8    *NewFileName,\r
+  UINT32  SequenceNumber\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  BaseFileName    - GC_TODO: add argument description\r
+  NewFileName     - GC_TODO: add argument description\r
+  SequenceNumber  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  /*++\r
+\r
+Routine Description:\r
+  Given an initial split capsule file name and a sequence number,\r
+  create an appropriate file name for this split of a capsule image.\r
+\r
+Arguments:\r
+  BaseFileName   - name of of the first split file in the series\r
+  NewFileName    - output name of the split file\r
+  SequenceNumber - 0-based sequence number of split images\r
+\r
+Returns:\r
+  TRUE   - name created successfully\r
+  FALSE  - otherwise\r
+\r
+--*/\r
+  INT8    *Ptr;\r
+  INT8    *Part2Start;\r
+  UINT32  Digits;\r
+  UINT32  Len;\r
+  UINT32  BaseOffset;\r
+  //\r
+  // Work back from the end of the file name and see if there is a number somewhere\r
+  //\r
+  for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--)\r
+    ;\r
+  if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) {\r
+    //\r
+    // Found no number, so just add it to the end\r
+    //\r
+    sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber);\r
+    return TRUE;\r
+  } else {\r
+    //\r
+    // Found a number. Look back to find the first digit.\r
+    //\r
+    Part2Start = Ptr + 1;\r
+    for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++)\r
+      ;\r
+    if (!isdigit (*Ptr)) {\r
+      Ptr++;\r
+      Digits--;\r
+    }\r
+\r
+    BaseOffset      = atoi (Ptr);\r
+    SequenceNumber  = SequenceNumber + BaseOffset;\r
+    if (Digits > 1) {\r
+      //\r
+      // Copy the first part of the original file name to the new filename\r
+      // This is the path for filenames with format path\name001.cap\r
+      //\r
+      Len = (UINT32) Ptr - (UINT32) BaseFileName;\r
+      strncpy (NewFileName, BaseFileName, Len);\r
+      sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber);\r
+      strcat (NewFileName, Part2Start);\r
+      return TRUE;\r
+    } else {\r
+      //\r
+      // Only one digit found. This is the path for filenames with\r
+      // format path\name1.cap\r
+      //\r
+      Len = (UINT32) Ptr - (UINT32) BaseFileName + 1;\r
+      strncpy (NewFileName, BaseFileName, Len);\r
+      sprintf (NewFileName + Len - 1, "%d", SequenceNumber);\r
+      strcat (NewFileName, Part2Start);\r
+      return TRUE;\r
+    }\r
+  }\r
+}\r
+\r
+static\r
+BOOLEAN\r
+IsWhiteSpace (\r
+  WCHAR  Char\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Char  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  switch (Char) {\r
+  case UNICODE_SPACE:\r
+  case UNICODE_TAB:\r
+  case UNICODE_NULL:\r
+  case UNICODE_CR:\r
+  case UNICODE_LF:\r
+    return TRUE;\r
+\r
+  default:\r
+    return FALSE;\r
+  }\r
+}\r
+\r
+static\r
+BOOLEAN\r
+IsToken (\r
+  SOURCE_FILE *File,\r
+  WCHAR       *Token\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  File  - GC_TODO: add argument description\r
+  Token - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  SkipWhiteSpace (File);\r
+  if (EndOfFile (File)) {\r
+    return FALSE;\r
+  }\r
+\r
+  if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) {\r
+    File->FileBufferPtr += wcslen (Token);\r
+    return TRUE;\r
+  }\r
+\r
+  return FALSE;\r
+}\r
+\r
+static\r
+STATUS\r
+CheckFirmwareVolumeHeader (\r
+  INT8    *FileName,\r
+  INT8    *Buffer,\r
+  UINT32  BufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  FileName    - 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_FIRMWARE_VOLUME_HEADER  *Hdr;\r
+  EFI_GUID                    FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;\r
+\r
+  Hdr           = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
+  if (Hdr->Signature != EFI_FVH_SIGNATURE) {\r
+    Error (NULL, 0, 0, FileName, "file does not appear to be a firmware volume (bad signature)");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if (Hdr->Revision != EFI_FVH_REVISION) {\r
+    Error (NULL, 0, 0, FileName, "unsupported firmware volume header version");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if (Hdr->FvLength > BufferSize) {\r
+    Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if (memcmp (&Hdr->FileSystemGuid, &FVHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+    Error (NULL, 0, 0, FileName, "invalid FFS GUID in firmware volume header");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+void\r
+DumpCapsule (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+#if 0\r
+  FILE                        *InFptr;\r
+  FILE_LIST                   *FileList;\r
+  EFI_CAPSULE_HEADER          CapsuleHeader;\r
+  EFI_FIRMWARE_VOLUME_HEADER  FVHeader;\r
+  EFI_CAPSULE_OEM_HEADER      *OemHeader;\r
+  UINT8                       *BPtr;\r
+  UINT32                      FileSize;\r
+  UINT32                      CapsuleHeaderDataSize;\r
+  UINT8                       ByteCount;\r
+  UINT8                       *CapsuleHeaderData;\r
+  BOOLEAN                     SplitImage;\r
+\r
+  InFptr            = NULL;\r
+  CapsuleHeaderData = NULL;\r
+  FileList          = mOptions.FileList;\r
+  while (FileList != NULL) {\r
+    if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+      goto Done;\r
+    }\r
+\r
+    if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header");\r
+      goto Done;\r
+    }\r
+\r
+    fseek (InFptr, 0, SEEK_END);\r
+    FileSize = ftell (InFptr);\r
+    if (CapsuleHeader.CapsuleImageSize > FileSize) {\r
+      SplitImage = TRUE;\r
+    } else {\r
+      SplitImage = FALSE;\r
+    }\r
+\r
+    printf (\r
+      "Capsule %s Size=0x%X CargoSize=0x%X\n",\r
+      FileList->FileName,\r
+      FileSize,\r
+      FileSize - CapsuleHeader.OffsetToCapsuleBody\r
+      );\r
+    printf (\r
+      "  GUID                  %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
+      CapsuleHeader.CapsuleGuid.Data1,\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data2,\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data3,\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[0],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[1],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[2],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[3],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[4],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[5],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[6],\r
+      (UINT32) CapsuleHeader.CapsuleGuid.Data4[7]\r
+      );\r
+    if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+      printf ("  INVALID GUID");\r
+    }\r
+\r
+    printf ("\n");\r
+    printf ("  Header size           0x%08X\n", CapsuleHeader.HeaderSize);\r
+    printf ("  Flags                 0x%08X\n", CapsuleHeader.Flags);\r
+    if (!SplitImage) {\r
+      printf ("  Capsule image size    0x%08X\n", CapsuleHeader.CapsuleImageSize);\r
+    } else {\r
+      printf ("  Capsule image size    0x%08X (split)\n", CapsuleHeader.CapsuleImageSize);\r
+    }\r
+\r
+    printf ("  Sequence number       %d\n", CapsuleHeader.SequenceNumber);\r
+    printf (\r
+      "  InstanceId            %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
+      CapsuleHeader.InstanceId.Data1,\r
+      (UINT32) CapsuleHeader.InstanceId.Data2,\r
+      (UINT32) CapsuleHeader.InstanceId.Data3,\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[0],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[1],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[2],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[3],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[4],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[5],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[6],\r
+      (UINT32) CapsuleHeader.InstanceId.Data4[7]\r
+      );\r
+    printf ("  Offset to capsule     0x%X\n", CapsuleHeader.OffsetToCapsuleBody);\r
+    //\r
+    // Dump header data if there\r
+    //\r
+    CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize;\r
+    if (CapsuleHeaderDataSize != 0) {\r
+      CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize);\r
+      if (CapsuleHeaderData == NULL) {\r
+        Error (\r
+          NULL,\r
+          0,\r
+          0,\r
+          "failed to allocate memory to read in capsule header data",\r
+          "0x%X bytes",\r
+          CapsuleHeaderDataSize\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET);\r
+      if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) {\r
+        Error (\r
+          NULL,\r
+          0,\r
+          0,\r
+          "failed to read capsule header data contents from file",\r
+          "0x%X bytes",\r
+          CapsuleHeaderDataSize\r
+          );\r
+        goto Done;\r
+      }\r
+      //\r
+      // ************************************************************************\r
+      //\r
+      // OEM HEADER\r
+      //\r
+      // ************************************************************************\r
+      //\r
+      if (CapsuleHeader.OffsetToOemDefinedHeader != 0) {\r
+        OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize);\r
+        printf ("  OEM Header\n");\r
+        printf (\r
+          "    GUID                %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
+          OemHeader->OemGuid.Data1,\r
+          (UINT32) OemHeader->OemGuid.Data2,\r
+          (UINT32) OemHeader->OemGuid.Data3,\r
+          (UINT32) OemHeader->OemGuid.Data4[0],\r
+          (UINT32) OemHeader->OemGuid.Data4[1],\r
+          (UINT32) OemHeader->OemGuid.Data4[2],\r
+          (UINT32) OemHeader->OemGuid.Data4[3],\r
+          (UINT32) OemHeader->OemGuid.Data4[4],\r
+          (UINT32) OemHeader->OemGuid.Data4[5],\r
+          (UINT32) OemHeader->OemGuid.Data4[6],\r
+          (UINT32) OemHeader->OemGuid.Data4[7]\r
+          );\r
+        printf ("    Header size:        0x%X\n", OemHeader->HeaderSize);\r
+        printf ("    OEM data");\r
+        BPtr = (UINT8 *) (OemHeader + 1);\r
+        for (ByteCount = 0; ByteCount < OemHeader->HeaderSize - sizeof (EFI_CAPSULE_OEM_HEADER); ByteCount++) {\r
+          if ((ByteCount & 0x7) == 0) {\r
+            printf ("\n      ");\r
+          }\r
+\r
+          printf ("%02X ", (UINT32) *BPtr);\r
+          BPtr++;\r
+        }\r
+\r
+        printf ("\n");\r
+      }\r
+      //\r
+      // ************************************************************************\r
+      //\r
+      // Author, revision, short description, and long description information\r
+      //\r
+      // ************************************************************************\r
+      //\r
+      if (CapsuleHeader.OffsetToAuthorInformation != 0) {\r
+        if (DumpCapsuleHeaderStrings (\r
+              "Author information",\r
+              (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize)\r
+              ) != STATUS_SUCCESS) {\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      if (CapsuleHeader.OffsetToRevisionInformation != 0) {\r
+        if (DumpCapsuleHeaderStrings (\r
+              "Revision information",\r
+              (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize)\r
+              ) != STATUS_SUCCESS) {\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      if (CapsuleHeader.OffsetToShortDescription != 0) {\r
+        if (DumpCapsuleHeaderStrings (\r
+              "Short description",\r
+              (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize)\r
+              ) != STATUS_SUCCESS) {\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      if (CapsuleHeader.OffsetToLongDescription != 0) {\r
+        if (DumpCapsuleHeaderStrings (\r
+              "Long description",\r
+              (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize)\r
+              ) != STATUS_SUCCESS) {\r
+          goto Done;\r
+        }\r
+      }\r
+    }\r
+    //\r
+    // If it's not a split image, or it is a split image and this is the first in the series, then\r
+    // dump the cargo volume.\r
+    //\r
+    if ((!SplitImage) || (CapsuleHeader.SequenceNumber == 0)) {\r
+      printf ("  Cargo FV dump\n");\r
+      fseek (InFptr, CapsuleHeader.OffsetToCapsuleBody, SEEK_SET);\r
+      if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) != 1) {\r
+        Error (NULL, 0, 0, FileList->FileName, "failed to read cargo FV header");\r
+        goto Done;\r
+      }\r
+\r
+      printf ("    FV length           0x%X", FVHeader.FvLength);\r
+      if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) {\r
+        if (!SplitImage) {\r
+          printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody);\r
+        }\r
+      }\r
+\r
+      printf ("\n");\r
+      printf ("    Signature           0x%X ", FVHeader.Signature);\r
+      if (FVHeader.Signature == EFI_FVH_SIGNATURE) {\r
+        printf ("_FVH\n");\r
+      } else {\r
+        printf ("INVALID\n");\r
+      }\r
+\r
+      printf ("    FV header length    0x%X\n", (UINT32) FVHeader.HeaderLength);\r
+      printf ("    Revision            0x%X\n", (UINT32) FVHeader.Revision);\r
+      printf ("\n");\r
+    }\r
+\r
+    FileList = FileList->Next;\r
+  }\r
+\r
+Done:\r
+  if (InFptr != NULL) {\r
+    fclose (InFptr);\r
+  }\r
+\r
+  if (CapsuleHeaderData != NULL) {\r
+    free (CapsuleHeaderData);\r
+  }\r
+#endif\r
+}\r
+\r
+static\r
+STATUS\r
+JoinCapsule (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Join split capsule images into a single image. This is the\r
+  support function for the -j command-line option.\r
+\r
+Arguments:\r
+  None.\r
+\r
+Returns:\r
+  STATUS_SUCCESS - no problems encountered\r
+\r
+--*/\r
+{\r
+#if 0\r
+  UINT32              Size;\r
+  FILE                *InFptr;\r
+  FILE                *OutFptr;\r
+  INT8                *Buffer;\r
+  FILE_LIST           *FileList;\r
+  STATUS              Status;\r
+  EFI_CAPSULE_HEADER  CapHdr;\r
+  EFI_CAPSULE_HEADER  *CapHdrPtr;\r
+  UINT32              SizeLeft;\r
+  UINT32              SequenceNumber;\r
+  //\r
+  // Must have at least two files for join mode\r
+  //\r
+  if ((mOptions.FileList == NULL) || (mOptions.FileList->Next == NULL)) {\r
+    Error (NULL, 0, 0, "must specify at least two file names to join", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Open the output file\r
+  //\r
+  if ((OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
+    Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  FileList        = mOptions.FileList;\r
+  Buffer          = NULL;\r
+  SequenceNumber  = 0;\r
+  InFptr          = NULL;\r
+  SizeLeft        = 0;\r
+  while (FileList != NULL) {\r
+    if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+      goto FailDone;\r
+    }\r
+    //\r
+    // Allocate a buffer into which we can read the file.\r
+    //\r
+    fseek (InFptr, 0, SEEK_END);\r
+    Size = ftell (InFptr);\r
+    rewind (InFptr);\r
+    Buffer = (char *) malloc (Size);\r
+    if (Buffer == NULL) {\r
+      Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
+      goto FailDone;\r
+    }\r
+\r
+    CapHdrPtr = (EFI_CAPSULE_HEADER *) Buffer;\r
+    if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
+      Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
+      goto FailDone;\r
+    }\r
+    //\r
+    // Check the header for validity. Check size first.\r
+    //\r
+    if (Size < sizeof (EFI_CAPSULE_HEADER)) {\r
+      Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header");\r
+      goto FailDone;\r
+    }\r
+    //\r
+    // Check GUID\r
+    //\r
+    if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+      Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID");\r
+      goto FailDone;\r
+    }\r
+    //\r
+    // Check sequence number\r
+    //\r
+    if (CapHdrPtr->SequenceNumber != SequenceNumber) {\r
+      Error (\r
+        NULL,\r
+        0,\r
+        0,\r
+        FileList->FileName,\r
+        "invalid sequence number %d (expected %d)",\r
+        CapHdrPtr->SequenceNumber,\r
+        SequenceNumber\r
+        );\r
+      goto FailDone;\r
+    }\r
+    //\r
+    // If the first file, read save the capsule header\r
+    //\r
+    if (SequenceNumber == 0) {\r
+      memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER));\r
+      //\r
+      // Erase the InstanceId GUID\r
+      //\r
+      memset (&CapHdrPtr->InstanceId, 0, sizeof (EFI_GUID));\r
+      if (fwrite (Buffer, Size, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, FileList->FileName, "failed to write contents to output file");\r
+        goto FailDone;\r
+      }\r
+\r
+      if (CapHdr.CapsuleImageSize < Size) {\r
+        Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size");\r
+        goto FailDone;\r
+      }\r
+\r
+      SizeLeft = CapHdr.CapsuleImageSize - Size;\r
+    } else {\r
+      //\r
+      // Check the GUID against the first file's GUID\r
+      //\r
+      if (memcmp (&CapHdr.CapsuleGuid, &CapHdrPtr->CapsuleGuid, sizeof (EFI_GUID)) != 0) {\r
+        Error (NULL, 0, 0, FileList->FileName, "GUID does not match first file's GUID");\r
+        goto FailDone;\r
+      }\r
+      //\r
+      // Make sure we're not throwing out any header info\r
+      //\r
+      if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) {\r
+        //\r
+        // Could be the split information, so just emit a warning\r
+        //\r
+        Warning (\r
+          NULL,\r
+          0,\r
+          0,\r
+          FileList->FileName,\r
+          "image appears to have additional capsule header information -- ignoring"\r
+          );\r
+      } else if (CapHdrPtr->OffsetToCapsuleBody < sizeof (EFI_CAPSULE_HEADER)) {\r
+        Error (NULL, 0, 0, FileList->FileName, "offset to capsule body in capsule header is insufficient");\r
+        goto FailDone;\r
+      }\r
+\r
+      if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+        goto FailDone;\r
+      }\r
+\r
+      if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) {\r
+        Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL);\r
+        goto FailDone;\r
+      }\r
+      //\r
+      // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);\r
+      //\r
+      SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody);\r
+    }\r
+    //\r
+    // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);\r
+    //\r
+    fclose (InFptr);\r
+    InFptr = NULL;\r
+    free (Buffer);\r
+    Buffer    = NULL;\r
+    FileList  = FileList->Next;\r
+    SequenceNumber++;\r
+  }\r
+\r
+  if (SizeLeft) {\r
+    Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft);\r
+    goto FailDone;\r
+  }\r
+\r
+  Status = STATUS_SUCCESS;\r
+  goto Done;\r
+FailDone:\r
+  Status = STATUS_ERROR;\r
+Done:\r
+  if (InFptr != NULL) {\r
+    fclose (InFptr);\r
+  }\r
+\r
+  if (OutFptr != NULL) {\r
+    fclose (OutFptr);\r
+  }\r
+\r
+  if (Buffer != NULL) {\r
+    free (Buffer);\r
+  }\r
+\r
+  return Status;\r
+\r
+#endif\r
+return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+DumpCapsuleHeaderStrings (\r
+  UINT8   *SectionName,\r
+  WCHAR   *Buffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Given a pointer to string data from a capsule header, dump\r
+  the strings.\r
+\r
+Arguments:\r
+  SectionName  - name of the capsule header section to which\r
+                 the string data pertains\r
+  Buffer       - pointer to string data from a capsule header\r
+\r
+Returns:\r
+  STATUS_SUCCESS - all went well\r
+\r
+--*/\r
+{\r
+  printf ("  %s\n", SectionName);\r
+  while (*Buffer) {\r
+    printf ("    Language: %S\n", Buffer);\r
+    while (*Buffer) {\r
+      Buffer++;\r
+    }\r
+\r
+    Buffer++;\r
+    while (*Buffer) {\r
+      if (wcslen (Buffer) > 60) {\r
+        printf ("      %.60S\n", Buffer);\r
+        Buffer += 60;\r
+      } else {\r
+        printf ("      %S\n", Buffer);\r
+        Buffer += wcslen (Buffer);\r
+      }\r
+    }\r
+\r
+    Buffer++;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+GetHexValue (\r
+  SOURCE_FILE  *SourceFile,\r
+  UINT32       *Value,\r
+  UINT32       NumDigits\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Scan a hex value from the input stream.\r
+  \r
+Arguments:\r
+  SourceFile   - input file contents\r
+  Value        - returned value\r
+  NumDigits    - number of digits to read\r
+\r
+Returns:\r
+  STATUS_SUCCESS - if NumDigits were read from the file\r
+  STATUS_ERROR   - otherwise\r
+\r
+  \r
+--*/\r
+{\r
+  WCHAR   *SaveFilePos;\r
+  UINT32  Digits;\r
+  WCHAR   Nibble;\r
+\r
+  SaveFilePos = SourceFile->FileBufferPtr;\r
+  *Value      = 0;\r
+  Digits      = NumDigits;\r
+  while (Digits > 0) {\r
+    Nibble = SourceFile->FileBufferPtr[0];\r
+    if ((Nibble >= UNICODE_0) && (Nibble <= UNICODE_9)) {\r
+      *Value = (*Value << 4) | (Nibble - UNICODE_0);\r
+    } else if ((Nibble >= UNICODE_A) && (Nibble <= UNICODE_F)) {\r
+      *Value = (*Value << 4) | (Nibble - UNICODE_A + 0x10);\r
+    } else if ((Nibble >= UNICODE_a) && (Nibble <= UNICODE_f)) {\r
+      *Value = (*Value << 4) | (Nibble - UNICODE_a + 0x10);\r
+    } else {\r
+      Error (\r
+        SourceFile->FileName,\r
+        SourceFile->LineNum,\r
+        0,\r
+        NULL,\r
+        "expected %d valid hex nibbles at %.20S",\r
+        NumDigits,\r
+        SaveFilePos\r
+        );\r
+      return STATUS_ERROR;\r
+    }\r
+\r
+    SourceFile->FileBufferPtr++;\r
+    Digits--;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+BOOLEAN\r
+EndOfFile (\r
+  SOURCE_FILE *File\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  File  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) {\r
+    File->EndOfFile = TRUE;\r
+  }\r
+  //\r
+  // Reposition to the end of the file if we went beyond\r
+  //\r
+  if (File->EndOfFile) {\r
+    File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR);\r
+  }\r
+\r
+  return File->EndOfFile;\r
+}\r
+\r
+static\r
+void\r
+SkipWhiteSpace (\r
+  SOURCE_FILE *SourceFile\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  SourceFile  - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  while (!EndOfFile (SourceFile)) {\r
+    switch (*SourceFile->FileBufferPtr) {\r
+    case UNICODE_NULL:\r
+    case UNICODE_CR:\r
+    case UNICODE_SPACE:\r
+    case UNICODE_TAB:\r
+      SourceFile->FileBufferPtr++;\r
+      break;\r
+\r
+    case UNICODE_LF:\r
+      SourceFile->FileBufferPtr++;\r
+      SourceFile->LineNum++;\r
+      break;\r
+\r
+    default:\r
+      return ;\r
+    }\r
+  }\r
+}\r
+//\r
+// Parse a number. Possible format:\r
+//   1234\r
+//   1234k\r
+//   1234K\r
+//   1M\r
+//   1m\r
+//   0x100\r
+//\r
+static\r
+BOOLEAN\r
+GetNumber (\r
+  INT8    *Str,\r
+  UINT32  *Value\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+  Str   - GC_TODO: add argument description\r
+  Value - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+  GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+  UINT32  LValue;\r
+\r
+  *Value  = 0;\r
+  LValue  = 0;\r
+  if (!isdigit (Str[0])) {\r
+    return FALSE;\r
+  }\r
+  //\r
+  // Look for hex number\r
+  //\r
+  if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) {\r
+    Str += 2;\r
+    if (Str[0] == 0) {\r
+      return FALSE;\r
+    }\r
+\r
+    while (Str[0]) {\r
+      if ((Str[0] >= '0') && (Str[0] <= '9')) {\r
+        LValue = (LValue << 4) | (Str[0] - '0');\r
+      } else if ((Str[0] >= 'A') && (Str[0] <= 'F')) {\r
+        LValue = (LValue << 4) | (Str[0] - 'A' + 0x10);\r
+      } else if ((Str[0] >= 'a') && (Str[0] <= 'f')) {\r
+        LValue = (LValue << 4) | (Str[0] - 'a' + 0x10);\r
+      } else {\r
+        break;\r
+      }\r
+\r
+      Str++;\r
+    }\r
+  } else {\r
+    LValue = atoi (Str);\r
+    while (isdigit (*Str)) {\r
+      Str++;\r
+    }\r
+  }\r
+  //\r
+  // If string left over, better be one character we recognize\r
+  //\r
+  if (Str[0]) {\r
+    if (Str[1]) {\r
+      return FALSE;\r
+    }\r
+\r
+    switch (Str[0]) {\r
+    case 'k':\r
+    case 'K':\r
+      LValue *= 1024;\r
+      break;\r
+\r
+    case 'm':\r
+    case 'M':\r
+      LValue *= 1024 * 1024;\r
+      break;\r
+\r
+    default:\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  *Value = LValue;\r
+  return TRUE;\r
+}\r
+//\r
+// Process the command-line arguments\r
+//\r
+static\r
+STATUS\r
+ProcessArgs (\r
+  int   Argc,\r
+  char  *Argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Processes command line arguments.\r
+\r
+Arguments:\r
+\r
+  Argc   - Number of command line arguments\r
+  Argv[] - Array of files input on command line  \r
+\r
+Returns:\r
+\r
+  STATUS_ERROR    - Function exited with an error\r
+  STATUS_SUCCESS  - Function executed successfully\r
+\r
+--*/\r
+{\r
+  FILE_LIST *NewFile;\r
+\r
+  FILE_LIST *LastFile;\r
+  SIZE_LIST *NewSize;\r
+  \r
+  NewFile = NULL;\r
+  NewSize = NULL;\r
+  \r
+  //\r
+  // Clear our globals\r
+  //\r
+  memset ((char *) &mOptions, 0, sizeof (mOptions));\r
+\r
+  //\r
+  // Skip program name\r
+  //\r
+  Argc--;\r
+  Argv++;\r
+\r
+  if (Argc == 0) {\r
+    Usage ();\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Process until no more options\r
+  //\r
+  while ((Argc > 0) && (Argv[0][0] == '-')) {\r
+    if (stricmp (Argv[0], "-script") == 0) {\r
+      //\r
+      // Check for one more arg\r
+      //\r
+      if (Argc > 1) {\r
+        //\r
+        // Save the file name\r
+        //\r
+        if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) {\r
+          Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size");\r
+          \r
+          if (NewFile != NULL) {\r
+            free (NewFile);\r
+          }\r
+          if (NewSize != NULL) {\r
+            free (NewSize);\r
+          }\r
+          \r
+          return STATUS_ERROR;\r
+        }\r
+\r
+        strcpy (mOptions.ScriptFileName, Argv[1]);\r
+      } else {\r
+        Error (NULL, 0, 0, Argv[0], "missing script file name with option");\r
+        Usage ();\r
+        \r
+        if (NewFile != NULL) {\r
+          free (NewFile);\r
+        }\r
+        if (NewSize != NULL) {\r
+          free (NewSize);\r
+        }       \r
+\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      Argc--;\r
+      Argv++;\r
+      //\r
+      // -o outfilename -- specify output file name (required)\r
+      //\r
+    } else if (stricmp (Argv[0], "-o") == 0) {\r
+      //\r
+      // check for one more arg\r
+      //\r
+      if (Argc > 1) {\r
+        //\r
+        // Try to open the file\r
+        //\r
+        // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {\r
+        //  Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");\r
+        //  return STATUS_ERROR;\r
+        // }\r
+        //\r
+        strcpy (mOptions.OutputFileName, Argv[1]);\r
+      } else {\r
+        Error (NULL, 0, 0, Argv[0], "missing output filename with option");\r
+        Usage ();\r
+        \r
+        if (NewFile != NULL) {\r
+          free (NewFile);\r
+        }\r
+        if (NewSize != NULL) {\r
+          free (NewSize);\r
+        }\r
+                \r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      Argc--;\r
+      Argv++;\r
+    } else if (stricmp (Argv[0], "-j") == 0) {\r
+      mOptions.JoinMode = TRUE;\r
+      //\r
+      // -split <size> option (multiple allowed)\r
+      //\r
+    } else if (stricmp (Argv[0], "-split") == 0) {\r
+      if (Argc > 1) {\r
+        NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST));\r
+        if (NewSize == NULL) {\r
+          Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+\r
+          if (NewFile != NULL) {\r
+            free (NewFile);\r
+          }\r
+          if (NewSize != NULL) {\r
+            free (NewSize);\r
+          }\r
+          \r
+          return STATUS_ERROR;\r
+        }\r
+\r
+        memset (NewSize, 0, sizeof (SIZE_LIST));\r
+        //\r
+        // Get the size from the next arg, and then add this size\r
+        // to our size list\r
+        //\r
+        if (!GetNumber (Argv[1], &NewSize->Size)) {\r
+          Error (NULL, 0, 0, Argv[1], "invalid split size argument");\r
+\r
+          if (NewFile != NULL) {\r
+            free (NewFile);\r
+          }\r
+          if (NewSize != NULL) {\r
+            free (NewSize);\r
+          }       \r
+          \r
+          return STATUS_ERROR;\r
+        }\r
+\r
+        if (mOptions.SizeList == NULL) {\r
+          mOptions.SizeList     = NewSize;\r
+          mOptions.CurrentSize  = NewSize;\r
+        } else {\r
+          mOptions.LastSize->Next = NewSize;\r
+        }\r
+\r
+        mOptions.LastSize = NewSize;\r
+        free (NewSize);\r
+      } else {\r
+        Error (NULL, 0, 0, Argv[0], "missing size parameter with option");\r
+        Usage ();\r
+\r
+        if (NewFile != NULL) {\r
+          free (NewFile);\r
+        }\r
+        if (NewSize != NULL) {\r
+          free (NewSize);\r
+        }\r
+        \r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      Argc--;\r
+      Argv++;      \r
+    } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
+      Usage ();\r
+      \r
+      if (NewFile != NULL) {\r
+        free (NewFile);\r
+      }\r
+      if (NewSize != NULL) {\r
+        free (NewSize);\r
+      }\r
+      \r
+      return STATUS_ERROR;\r
+      //\r
+      // Default minimum header\r
+      //\r
+    } else if (stricmp (Argv[0], "-dump") == 0) {\r
+      mOptions.Dump = TRUE;\r
+    } else if (stricmp (Argv[0], "-v") == 0) {\r
+      mOptions.Verbose = TRUE;\r
+    } else {\r
+      Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
+      Usage ();\r
+      \r
+      if (NewFile != NULL) {\r
+        free (NewFile);\r
+      }\r
+      if (NewSize != NULL) {\r
+        free (NewSize);\r
+      }\r
+      \r
+      return STATUS_ERROR;\r
+    }\r
+\r
+    Argc--;\r
+    Argv++;\r
+  }\r
+  //\r
+  // Can't -j join files and -s split output capsule\r
+  //\r
+  if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) {\r
+    Error (NULL, 0, 0, "cannot specify both -j and -size", NULL);\r
+    \r
+    if (NewFile != NULL) {\r
+      free (NewFile);\r
+    }\r
+    if (NewSize != NULL) {\r
+      free (NewSize);\r
+    }\r
+    \r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Must have specified an output file name if not -dump\r
+  //\r
+  if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) {\r
+    Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified");\r
+    Usage ();\r
+    \r
+    if (NewFile != NULL) {\r
+      free (NewFile);\r
+    }\r
+    if (NewSize != NULL) {\r
+      free (NewSize);\r
+    }\r
+    \r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Rest of arguments are input files. The first one is a firmware\r
+  // volume image, and the rest are FFS files that are to be inserted\r
+  // into the firmware volume.\r
+  //\r
+  LastFile = NULL;\r
+  while (Argc > 0) {\r
+    NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
+    if (NewFile == NULL) {\r
+      Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+\r
+      if (NewFile != NULL) {\r
+        free (NewFile);\r
+      }\r
+      if (NewSize != NULL) {\r
+        free (NewSize);\r
+      }\r
+    \r
+      return STATUS_ERROR;\r
+    }\r
+\r
+    memset ((char *) NewFile, 0, sizeof (FILE_LIST));\r
+    strcpy (NewFile->FileName, Argv[0]);\r
+    if (mOptions.FileList == NULL) {\r
+      mOptions.FileList = NewFile;\r
+    } else {\r
+      if (LastFile == NULL) {\r
+        LastFile = NewFile;\r
+      } else {\r
+        LastFile->Next = NewFile;\r
+      }      \r
+    }\r
+\r
+    LastFile = NewFile;\r
+    Argc--;\r
+    Argv++;\r
+  }\r
+\r
+  //\r
+  // Must have provided at least one file name\r
+  //\r
+  if (mOptions.FileList == NULL) {\r
+    Error (NULL, 0, 0, "must specify at least one file name", NULL);\r
+    Usage ();\r
+    \r
+    if (NewFile != NULL) {\r
+      free (NewFile);\r
+    }\r
+    if (NewSize != NULL) {\r
+      free (NewSize);\r
+    }\r
+    \r
+    return STATUS_ERROR;\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
+  static const char *Str[] = {\r
+    PROGRAM_NAME " -- create a capsule header",\r
+    "  Usage: "PROGRAM_NAME " {options} [CapsuleFV]",\r
+    //\r
+    // {FfsFileNames}",\r
+    //\r
+    "    Options include:",\r
+    "      -h or -?         for this help information",\r
+    "      -script fname    to take capsule header info from unicode script",\r
+    "                       file fname",\r
+    "      -o fname         write output to file fname (required)",\r
+    "      -split size      split capsule image into multiple output files",\r
+    "      -dump            to dump a capsule header",\r
+    "      -v               for verbose output\n",\r
+    "      -j               to join split capsule images into a single image",\r
+    "",\r
+    "    CapsuleFV is the name of an existing well-formed Tiano firmware",\r
+    "    volume file.",\r
+    //\r
+    // FfsFileNames are the names of one or more Tiano FFS files to",\r
+    // "    insert into the output capsule image.",\r
+    //\r
+    NULL\r
+  };\r
+  for (Index = 0; Str[Index] != NULL; Index++) {\r
+    fprintf (stdout, "%s\n", Str[Index]);\r
+  }\r
+}\r