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