git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@246 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2675 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2675 lines
		
	
	
		
			68 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c)  2002 - 2005, Intel Corporation. All rights reserved
 | |
| This software and associated documentation (if any) is furnished
 | |
| under a license and may only be used or copied in accordance
 | |
| with the terms of the license. Except as permitted by such
 | |
| license, no part of this software or documentation may be
 | |
| reproduced, stored in a retrieval system, or transmitted in any
 | |
| form or by any means without the express written consent of
 | |
| Intel Corporation.
 | |
| 
 | |
| 
 | |
| 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 <UefiBaseTypes.h>
 | |
| #include <Base.h>
 | |
| #include <CommonLib.h>
 | |
| 
 | |
| #include "EfiUtilityMsgs.h"
 | |
| #include "MultiPhase.h"
 | |
| #include "Capsule.h"
 | |
| #include "Guid/Capsule.h"
 | |
| #include "FirmwareVolumeImageFormat.h"
 | |
| #include "FirmwareVolumeHeader.h"
 | |
| #include "FirmwareFileSystem.h"  // for FV header GUID
 | |
| #include "Guid/FirmwareFileSystem.h"  // for FV header GUID
 | |
| #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]);
 | |
|   }
 | |
| }
 |