]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Sample/Tools/Source/GenFfsFile/GenFfsFile.c
Add in the 1st version of ECP.
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / GenFfsFile / GenFfsFile.c
diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/GenFfsFile/GenFfsFile.c b/EdkCompatibilityPkg/Sample/Tools/Source/GenFfsFile/GenFfsFile.c
new file mode 100644 (file)
index 0000000..188ca77
--- /dev/null
@@ -0,0 +1,2681 @@
+/*++\r
+\r
+Copyright (c) 2004 - 2007, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  GenFfsFile.c\r
+\r
+Abstract:\r
+\r
+  This file contains functions required to generate a Firmware File System\r
+  file.\r
+\r
+--*/\r
+\r
+#include "TianoCommon.h"\r
+#include "EfiFirmwareFileSystem.h"\r
+#include "EfiFirmwareVolumeHeader.h"\r
+#include "EfiImageFormat.h"\r
+#include "ParseInf.h"\r
+#include "Compress.h"\r
+#include "EfiCustomizedCompress.h"\r
+#include "crc32.h"\r
+#include "GenFfsFile.h"\r
+#include <stdio.h>\r
+#include <ctype.h>  // for isalpha()\r
+//\r
+// include file for _spawnv\r
+//\r
+#include <process.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include "CommonLib.h"\r
+#include "EfiUtilityMsgs.h"\r
+#include "SimpleFileParsing.h"\r
+\r
+#define UTILITY_NAME    "GenFfsFile"\r
+#define TOOLVERSION     "0.32"\r
+#define MAX_ARRAY_SIZE  100\r
+\r
+static\r
+INT32\r
+GetNextLine (\r
+  OUT CHAR8       *Destination,\r
+  IN FILE         *Package,\r
+  IN OUT UINT32   *LineNumber\r
+  );\r
+\r
+static\r
+void\r
+CheckSlash (\r
+  IN OUT CHAR8  *String,\r
+  IN FILE       *In,\r
+  IN OUT UINT32 *LineNumber\r
+  );\r
+\r
+static\r
+INT32\r
+FindSectionInPackage (\r
+  IN CHAR8        *BuildDirectory,\r
+  IN FILE         *OverridePackage,\r
+  IN OUT UINT32   *LineNumber\r
+  );\r
+\r
+static\r
+STATUS\r
+ProcessCommandLineArgs (\r
+  int     Argc,\r
+  char    *Argv[]\r
+  );\r
+\r
+static\r
+void\r
+PrintUsage (\r
+  void\r
+  );\r
+\r
+//\r
+// Keep globals in this structure\r
+//\r
+static struct {\r
+  UINT8   BuildDirectory[_MAX_PATH];\r
+  UINT8   PrimaryPackagePath[_MAX_PATH];\r
+  UINT8   OverridePackagePath[_MAX_PATH];\r
+  BOOLEAN Verbose;\r
+} mGlobals;\r
+\r
+static EFI_GUID mZeroGuid = { 0 };\r
+\r
+static\r
+void\r
+StripQuotes (\r
+  IN OUT CHAR8 *String\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Removes quotes and/or whitespace from around a string\r
+\r
+Arguments:\r
+\r
+ String    - String to remove quotes from\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+  UINTN Index2;\r
+  UINTN StrLen;\r
+\r
+  Index2  = strspn (String, "\" \t\n");\r
+  StrLen  = strlen (String);\r
+\r
+  for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) {\r
+    String[Index - Index2] = String[Index];\r
+  }\r
+\r
+  String[Index - Index2] = 0;\r
+}\r
+\r
+static\r
+void\r
+PrintUsage (\r
+  void\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Print Error / Help message.\r
+\r
+Arguments:\r
+\r
+  void\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  printf ("Usage:\n");\r
+  printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n");\r
+  printf ("   -b \"build directory\":\n ");\r
+  printf ("       specifies the full path to the component build directory.\n");\r
+  printf ("   -p1 \"P1_path\":\n");\r
+  printf ("       specifies fully qualified file name to the primary package file.\n");\r
+  printf ("       This file will normally exist in the same directory as the makefile\n");\r
+  printf ("       for the component. Required.\n");\r
+  printf ("   -p2 \"P2_path\":\n");\r
+  printf ("       specifies fully qualified file name to the override package file.\n");\r
+  printf ("       This file will normally exist in the build tip. Optional.\n");\r
+}\r
+\r
+static\r
+INT32\r
+TestComment (\r
+  IN CHAR8  *String,\r
+  IN FILE   *In\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Tests input string to see if it is a comment, and if so goes to the next line in the file that is not a comment\r
+\r
+Arguments:\r
+\r
+  String      - String to test\r
+\r
+  In          - Open file to move pointer within\r
+\r
+Returns:\r
+\r
+  -1          - End of file reached\r
+   0          - Not a comment\r
+   1          - Comment bypassed\r
+\r
+--*/\r
+{\r
+  CHAR8 CharBuffer;\r
+\r
+  CharBuffer = 0;\r
+  if ((String[0] == '/') && (String[1] == '/')) {\r
+    while (CharBuffer != '\n') {\r
+      fscanf (In, "%c", &CharBuffer);\r
+      if (feof (In)) {\r
+        return -1;\r
+      }\r
+    }\r
+  } else {\r
+    return 0;\r
+  }\r
+\r
+  return 1;\r
+}\r
+\r
+static\r
+void\r
+BreakString (\r
+  IN CONST CHAR8 *Source,\r
+  OUT CHAR8      *Destination,\r
+  IN INTN        Direction\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Takes an input string and returns either the part before the =, or the part after the =, depending on direction\r
+\r
+Arguments:\r
+\r
+  Source      - String to break\r
+\r
+  Destination - Buffer to place new string in\r
+\r
+  Direction   - 0 to return all of source string before =\r
+                1 to return all of source string after =\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+  UINTN Index2;\r
+\r
+  Index   = 0;\r
+  Index2  = 0;\r
+\r
+  if (strchr (Source, '=') == NULL) {\r
+    strcpy (Destination, Source);\r
+\r
+    return ;\r
+  }\r
+\r
+  if (Direction == 0) {\r
+    //\r
+    // return part of string before =\r
+    //\r
+    while (Source[Index] != '=') {\r
+      Destination[Index] = Source[Index++];\r
+    }\r
+\r
+    Destination[Index] = 0;\r
+  } else {\r
+    //\r
+    // return part of string after =\r
+    //\r
+    strcpy (Destination, strchr (Source, '=') + 1);\r
+  }\r
+}\r
+\r
+static\r
+INT32\r
+GetNextLine (\r
+  OUT CHAR8       *Destination,\r
+  IN FILE         *Package,\r
+  IN OUT UINT32   *LineNumber\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Gets the next non-commented line from the file\r
+\r
+Arguments:\r
+\r
+  Destination - Where to put string\r
+\r
+  Package     - Package to get string from\r
+  \r
+  LineNumber  - The actual line number.\r
+\r
+Returns:\r
+\r
+  -1          - End of file reached\r
+   0          - Success\r
+\r
+--*/\r
+{\r
+  CHAR8 String[_MAX_PATH];\r
+  fscanf (Package, "%s", &String);\r
+  if (feof (Package)) {\r
+    return -1;\r
+  }\r
+\r
+  while (TestComment (String, Package) == 1) {\r
+    fscanf (Package, "%s", &String);\r
+    if (feof (Package)) {\r
+      return -1;\r
+    }\r
+  }\r
+\r
+  strcpy (Destination, String);\r
+  return 0;\r
+}\r
+\r
+static\r
+VOID\r
+CheckSlash (\r
+  IN OUT CHAR8  *String,\r
+  IN FILE       *In,\r
+  IN OUT UINT32 *LineNumber\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Checks to see if string is line continuation character, if so goes to next valid line\r
+\r
+Arguments:\r
+\r
+  String      - String to test\r
+\r
+  In          - Open file to move pointer within\r
+  \r
+  LineNumber  - The line number.\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  CHAR8 ByteBuffer;\r
+  ByteBuffer = 0;\r
+\r
+  switch (String[0]) {\r
+\r
+  case '\\':\r
+    while (String[0] == '\\') {\r
+      while (ByteBuffer != '\n') {\r
+        fscanf (In, "%c", &ByteBuffer);\r
+      }\r
+      (*LineNumber)++;\r
+      if (GetNextLine (String, In, LineNumber) == -1) {\r
+        return ;\r
+      }\r
+    }\r
+    break;\r
+\r
+  case '\n':\r
+    (*LineNumber)++;\r
+    while (String[0] == '\n') {\r
+      if (GetNextLine (String, In, LineNumber) == -1) {\r
+        return ;\r
+      }\r
+    }\r
+    break;\r
+\r
+  default:\r
+    break;\r
+\r
+  }\r
+\r
+}\r
+\r
+static\r
+INT32\r
+FindSectionInPackage (\r
+  IN CHAR8        *BuildDirectory,\r
+  IN FILE         *OverridePackage,\r
+  IN OUT UINT32   *LineNumber\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Finds the matching section within the package\r
+\r
+Arguments:\r
+\r
+  BuildDirectory  - name of section to find\r
+\r
+  OverridePackage - Package file to search within\r
+  \r
+  LineNumber      - The line number.\r
+\r
+Returns:\r
+\r
+  -1          - End of file reached\r
+   0          - Success\r
+\r
+--*/\r
+{\r
+  CHAR8 String[_MAX_PATH];\r
+  CHAR8 NewString[_MAX_PATH];\r
+  String[0] = 0;\r
+\r
+  while (strcmp (BuildDirectory, String) != 0) {\r
+    if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) {\r
+      return -1;\r
+    }\r
+\r
+    if (NewString[0] == '[') {\r
+      if (NewString[strlen (NewString) - 1] != ']') {\r
+        //\r
+        // have to construct string.\r
+        //\r
+        strcpy (String, NewString + 1);\r
+\r
+        while (1) {\r
+          fscanf (OverridePackage, "%s", &NewString);\r
+          if (feof (OverridePackage)) {\r
+            return -1;\r
+          }\r
+\r
+          if (NewString[0] != ']') {\r
+            if (strlen (String) != 0) {\r
+              strcat (String, " ");\r
+            }\r
+\r
+            strcat (String, NewString);\r
+            if (String[strlen (String) - 1] == ']') {\r
+              String[strlen (String) - 1] = 0;\r
+              break;\r
+            }\r
+          } else {\r
+            break;\r
+          }\r
+        }\r
+      } else {\r
+        NewString[strlen (NewString) - 1] = 0;\r
+        strcpy (String, NewString + 1);\r
+      }\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+static\r
+EFI_STATUS\r
+GenSimpleGuidSection (\r
+  IN OUT UINT8  *FileBuffer,\r
+  IN OUT UINT32 *BufferSize,\r
+  IN UINT32     DataSize,\r
+  IN EFI_GUID   SignGuid,\r
+  IN UINT16     GuidedSectionAttributes\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  add GUIDed section header for the data buffer.\r
+  data stays in same location (overwrites source data).\r
+\r
+Arguments:\r
+\r
+  FileBuffer  - Buffer containing data to sign\r
+\r
+  BufferSize  - On input, the size of FileBuffer. On output, the size of\r
+                actual section data (including added section header).\r
+\r
+  DataSize    - Length of data to Sign\r
+\r
+  SignGuid    - Guid to be add.\r
+  \r
+  GuidedSectionAttributes - The section attribute.\r
+\r
+Returns:\r
+\r
+  EFI_SUCCESS           - Successful\r
+  EFI_OUT_OF_RESOURCES  - Not enough resource.\r
+\r
+--*/\r
+{\r
+  UINT32                    TotalSize;\r
+\r
+  EFI_GUID_DEFINED_SECTION  GuidSectionHeader;\r
+  UINT8                     *SwapBuffer;\r
+\r
+  SwapBuffer = NULL;\r
+\r
+  if (DataSize == 0) {\r
+    *BufferSize = 0;\r
+\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION);\r
+  GuidSectionHeader.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;\r
+  GuidSectionHeader.CommonHeader.Size[0]  = (UINT8) (TotalSize & 0xff);\r
+  GuidSectionHeader.CommonHeader.Size[1]  = (UINT8) ((TotalSize & 0xff00) >> 8);\r
+  GuidSectionHeader.CommonHeader.Size[2]  = (UINT8) ((TotalSize & 0xff0000) >> 16);\r
+  memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID));\r
+  GuidSectionHeader.Attributes  = GuidedSectionAttributes;\r
+  GuidSectionHeader.DataOffset  = sizeof (EFI_GUID_DEFINED_SECTION);\r
+\r
+  SwapBuffer                    = (UINT8 *) malloc (DataSize);\r
+  if (SwapBuffer == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  memcpy (SwapBuffer, FileBuffer, DataSize);\r
+  memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION));\r
+  memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize);\r
+\r
+  //\r
+  // Make sure section ends on a DWORD boundary\r
+  //\r
+  while ((TotalSize & 0x03) != 0) {\r
+    FileBuffer[TotalSize] = 0;\r
+    TotalSize++;\r
+  }\r
+\r
+  *BufferSize = TotalSize;\r
+\r
+  if (SwapBuffer != NULL) {\r
+    free (SwapBuffer);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+static\r
+EFI_STATUS\r
+CompressSection (\r
+  UINT8  *FileBuffer,\r
+  UINT32 *BufferSize,\r
+  UINT32 DataSize,\r
+  CHAR8  *Type\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Compress the data and add section header for the compressed data.\r
+  Compressed data (with section header) stays in same location as the source\r
+  (overwrites source data).\r
+\r
+Arguments:\r
+\r
+  FileBuffer  - Buffer containing data to Compress\r
+\r
+  BufferSize  - On input, the size of FileBuffer. On output, the size of\r
+                actual compressed data (including added section header).\r
+                When buffer is too small, this value indicates the size needed.\r
+\r
+  DataSize    - The size of data to compress\r
+\r
+  Type        - The compression type (not used currently).\r
+                Assume EFI_HEAVY_COMPRESSION.\r
+\r
+Returns:\r
+\r
+  EFI_BUFFER_TOO_SMALL - Buffer size is too small.\r
+  EFI_UNSUPPORTED      - Compress type can not be supported.\r
+  EFI_SUCCESS          - Successful\r
+  EFI_OUT_OF_RESOURCES - Not enough resource.\r
+\r
+--*/\r
+{\r
+  EFI_STATUS              Status;\r
+  UINT8                   *CompData;\r
+  UINT32                  CompSize;\r
+  UINT32                  TotalSize;\r
+  EFI_COMPRESSION_SECTION CompressionSet;\r
+  UINT8                   CompressionType;\r
+  COMPRESS_FUNCTION       CompressFunction;\r
+\r
+  Status            = EFI_SUCCESS;\r
+  CompData          = NULL;\r
+  CompSize          = 0;\r
+  TotalSize         = 0;\r
+  CompressFunction  = NULL;\r
+\r
+  //\r
+  // Get the compress type\r
+  //\r
+  if (_strcmpi (Type, "Dummy") == 0) {\r
+    //\r
+    // Added "Dummy" to keep backward compatibility.\r
+    //\r
+    CompressionType   = EFI_STANDARD_COMPRESSION;\r
+    CompressFunction  = (COMPRESS_FUNCTION) TianoCompress;\r
+\r
+  } else if (_strcmpi (Type, "LZH") == 0) {\r
+    //\r
+    // EFI stardard compression (LZH)\r
+    //\r
+    CompressionType   = EFI_STANDARD_COMPRESSION;\r
+    CompressFunction  = (COMPRESS_FUNCTION) TianoCompress;\r
+\r
+  } else {\r
+    //\r
+    // Customized compression\r
+    //\r
+    Status = SetCustomizedCompressionType (Type);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    CompressionType   = EFI_CUSTOMIZED_COMPRESSION;\r
+    CompressFunction  = (COMPRESS_FUNCTION) CustomizedCompress;\r
+  }\r
+  //\r
+  // Compress the raw data\r
+  //\r
+  Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);\r
+  if (Status == EFI_BUFFER_TOO_SMALL) {\r
+    CompData = malloc (CompSize);\r
+    if (!CompData) {\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    if (CompData != NULL) {\r
+      free (CompData);\r
+    }\r
+\r
+    return Status;\r
+  }\r
+\r
+  TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION);\r
+\r
+  //\r
+  // Buffer too small?\r
+  //\r
+  if (TotalSize > *BufferSize) {\r
+    *BufferSize = TotalSize;\r
+    if (CompData != NULL) {\r
+      free (CompData);\r
+    }\r
+\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+  //\r
+  // Add the section header for the compressed data\r
+  //\r
+  CompressionSet.CommonHeader.Type    = EFI_SECTION_COMPRESSION;\r
+  CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff);\r
+  CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8);\r
+  CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16);\r
+  CompressionSet.CompressionType      = CompressionType;\r
+  CompressionSet.UncompressedLength   = DataSize;\r
+\r
+  //\r
+  // Copy header and data to the buffer\r
+  //\r
+  memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION));\r
+  memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize);\r
+\r
+  //\r
+  // Make sure section ends on a DWORD boundary\r
+  //\r
+  while ((TotalSize & 0x03) != 0) {\r
+    FileBuffer[TotalSize] = 0;\r
+    TotalSize++;\r
+  }\r
+\r
+  *BufferSize = TotalSize;\r
+\r
+  if (CompData != NULL) {\r
+    free (CompData);\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+static\r
+void\r
+StripParens (\r
+  IN OUT CHAR8 *String\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Removes Parenthesis from around a string\r
+\r
+Arguments:\r
+\r
+ String    - String to remove parens from\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  INT32 Index;\r
+\r
+  if (String[0] != '(') {\r
+    return ;\r
+  }\r
+\r
+  for (Index = 1; String[Index] != ')'; Index++) {\r
+    String[Index - 1] = String[Index];\r
+    if (String[Index] == 0) {\r
+      return ;\r
+    }\r
+  }\r
+\r
+  String[Index - 1] = 0;\r
+\r
+  return ;\r
+}\r
+\r
+static\r
+void\r
+StripEqualMark (\r
+  IN OUT CHAR8 *String\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Removes Equal Mark from around a string\r
+\r
+Arguments:\r
+\r
+ String    - String to remove equal mark from\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  INT32 Index;\r
+\r
+  if (String[0] != '=' && String[strlen (String) - 1] != '=') {\r
+    return ;\r
+  }\r
+\r
+  if (String[0] == '=') {\r
+\r
+    for (Index = 1; String[Index] != 0; Index++) {\r
+      String[Index - 1] = String[Index];\r
+    }\r
+\r
+    String[Index - 1] = 0;\r
+  }\r
+\r
+  if (String[strlen (String) - 1] == '=') {\r
+    String[strlen (String) - 1] = 0;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+static\r
+INT32\r
+ProcessEnvironmentVariable (\r
+  IN CHAR8  *Buffer,\r
+  OUT CHAR8 *NewBuffer\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Converts environment variables to values\r
+\r
+Arguments:\r
+\r
+  Buffer      - Buffer containing Environment Variable String\r
+\r
+  NewBuffer   - Buffer containing value of environment variable\r
+\r
+\r
+Returns:\r
+\r
+  Number of characters from Buffer used\r
+\r
+--*/\r
+{\r
+  INT32 Index;\r
+  INT32 Index2;\r
+  CHAR8 VariableBuffer[_MAX_PATH];\r
+\r
+  Index   = 2;\r
+  Index2  = 0;\r
+\r
+  while (Buffer[Index] != ')') {\r
+    VariableBuffer[Index - 2] = Buffer[Index++];\r
+  }\r
+\r
+  VariableBuffer[Index - 2] = 0;\r
+  Index++;\r
+\r
+  if (getenv (VariableBuffer) != NULL) {\r
+    strcpy (NewBuffer, getenv (VariableBuffer));\r
+  } else {\r
+    printf ("Environment variable %s not found!\n", VariableBuffer);\r
+  }\r
+\r
+  return Index;\r
+}\r
+\r
+static\r
+void\r
+SplitAttributesField (\r
+  IN CHAR8       *Buffer,\r
+  IN CHAR8       *AttributesArray[],\r
+  IN OUT UINT32  *NumberOfAttributes\r
+  )\r
+/*\r
+  NumberOfAttributes: on input, it specifies the current number of attributes\r
+                      stored in AttributeArray.\r
+                      on output, it is updated to the latest number of attributes\r
+                      stored in AttributesArray.\r
+*/\r
+{\r
+  UINT32  Index;\r
+  UINT32  Index2;\r
+  UINT32  z;\r
+  CHAR8   *CharBuffer;\r
+\r
+  CharBuffer  = NULL;\r
+  CharBuffer  = (CHAR8 *) malloc (_MAX_PATH);\r
+  ZeroMem (CharBuffer, _MAX_PATH);\r
+\r
+  for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) {\r
+\r
+    if (Buffer[Index] != '|') {\r
+      CharBuffer[z] = Buffer[Index];\r
+      z++;\r
+    } else {\r
+\r
+      CharBuffer[z] = 0;\r
+      AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;\r
+      Index2++;\r
+\r
+      //\r
+      // allocate new char buffer for the next attributes string\r
+      //\r
+      CharBuffer = (CHAR8 *) malloc (_MAX_PATH);\r
+      ZeroMem (CharBuffer, _MAX_PATH);\r
+      z = 0;\r
+    }\r
+  }\r
+\r
+  CharBuffer[z] = 0;\r
+  //\r
+  // record the last attributes string in the Buffer\r
+  //\r
+  AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;\r
+  Index2++;\r
+\r
+  *NumberOfAttributes += Index2;\r
+\r
+  return ;\r
+}\r
+\r
+static\r
+INT32\r
+GetToolArguments (\r
+  CHAR8       *ToolArgumentsArray[],\r
+  FILE        *Package,\r
+  CHAR8       **PtrInputFileName,\r
+  CHAR8       **PtrOutputFileName,\r
+  EFI_GUID    *Guid,\r
+  UINT16      *GuidedSectionAttributes\r
+  )\r
+{\r
+  CHAR8       Buffer[_MAX_PATH];\r
+  BOOLEAN     ArgumentsFlag;\r
+  BOOLEAN     InputFlag;\r
+  BOOLEAN     OutputFlag;\r
+  BOOLEAN     GuidFlag;\r
+  BOOLEAN     AttributesFlag;\r
+  UINT32      argc;\r
+  UINT32      Index2;\r
+  UINT32      z;\r
+  CHAR8       *CharBuffer;\r
+  INT32       Index;\r
+  INT32       ReturnValue;\r
+  EFI_STATUS  Status;\r
+\r
+  CHAR8       *AttributesArray[MAX_ARRAY_SIZE];\r
+  UINT32      NumberOfAttributes;\r
+  CHAR8       *InputFileName;\r
+  CHAR8       *OutputFileName;\r
+  UINT32      LineNumber;\r
+  Buffer[_MAX_PATH];\r
+\r
+  ArgumentsFlag   = FALSE;\r
+  InputFlag       = FALSE;\r
+  OutputFlag      = FALSE;\r
+  GuidFlag        = FALSE;\r
+  AttributesFlag  = FALSE;\r
+  //\r
+  // Start at 1, since ToolArgumentsArray[0]\r
+  // is the program name.\r
+  //\r
+  argc            = 1;\r
+  Index2              = 0;\r
+\r
+  z                   = 0;\r
+  ReturnValue         = 0;\r
+  NumberOfAttributes  = 0;\r
+  InputFileName       = NULL;\r
+  OutputFileName      = NULL;\r
+\r
+  ZeroMem (Buffer, _MAX_PATH);\r
+  ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);\r
+  LineNumber = 0;\r
+  while (Buffer[0] != ')') {\r
+\r
+    if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+      CheckSlash (Buffer, Package, &LineNumber);\r
+      StripEqualMark (Buffer);\r
+    } else {\r
+      Error (NULL, 0, 0, "failed to get next line from package file", NULL);\r
+      return -1;\r
+    }\r
+\r
+    if (Buffer[0] == ')') {\r
+      break;\r
+    } else if (_strcmpi (Buffer, "ARGS") == 0) {\r
+\r
+      ArgumentsFlag   = TRUE;\r
+      AttributesFlag  = FALSE;\r
+      continue;\r
+\r
+    } else if (_strcmpi (Buffer, "INPUT") == 0) {\r
+\r
+      InputFlag       = TRUE;\r
+      ArgumentsFlag   = FALSE;\r
+      AttributesFlag  = FALSE;\r
+      continue;\r
+\r
+    } else if (_strcmpi (Buffer, "OUTPUT") == 0) {\r
+\r
+      OutputFlag      = TRUE;\r
+      ArgumentsFlag   = FALSE;\r
+      AttributesFlag  = FALSE;\r
+      continue;\r
+\r
+    } else if (_strcmpi (Buffer, "GUID") == 0) {\r
+\r
+      GuidFlag        = TRUE;\r
+      ArgumentsFlag   = FALSE;\r
+      AttributesFlag  = FALSE;\r
+      //\r
+      // fetch the GUID for the section\r
+      //\r
+      continue;\r
+\r
+    } else if (_strcmpi (Buffer, "ATTRIBUTES") == 0) {\r
+\r
+      AttributesFlag  = TRUE;\r
+      ArgumentsFlag   = FALSE;\r
+      //\r
+      // fetch the GUIDed Section's Attributes\r
+      //\r
+      continue;\r
+\r
+    } else if (_strcmpi (Buffer, "") == 0) {\r
+      continue;\r
+    }\r
+    //\r
+    // get all command arguments into ToolArgumentsArray\r
+    //\r
+    if (ArgumentsFlag) {\r
+\r
+      StripEqualMark (Buffer);\r
+\r
+      CharBuffer = (CHAR8 *) malloc (_MAX_PATH);\r
+      if (CharBuffer == NULL) {\r
+        goto ErrorExit;\r
+      }\r
+\r
+      ZeroMem (CharBuffer, sizeof (_MAX_PATH));\r
+\r
+      ToolArgumentsArray[argc] = CharBuffer;\r
+\r
+      if (Buffer[0] == '$') {\r
+        Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]);\r
+        //\r
+        // if there is string after the environment variable, cat it.\r
+        //\r
+        if ((UINT32) Index < strlen (Buffer)) {\r
+          strcat (ToolArgumentsArray[argc], &Buffer[Index]);\r
+        }\r
+      } else {\r
+        strcpy (ToolArgumentsArray[argc], Buffer);\r
+      }\r
+\r
+      argc += 1;\r
+      ToolArgumentsArray[argc] = NULL;\r
+      continue;\r
+    }\r
+\r
+    if (InputFlag) {\r
+\r
+      StripEqualMark (Buffer);\r
+\r
+      InputFileName = (CHAR8 *) malloc (_MAX_PATH);\r
+      if (InputFileName == NULL) {\r
+        goto ErrorExit;\r
+      }\r
+\r
+      ZeroMem (InputFileName, sizeof (_MAX_PATH));\r
+\r
+      if (Buffer[0] == '$') {\r
+        Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName);\r
+        //\r
+        // if there is string after the environment variable, cat it.\r
+        //\r
+        if ((UINT32) Index < strlen (Buffer)) {\r
+          strcat (InputFileName, &Buffer[Index]);\r
+        }\r
+      } else {\r
+        strcpy (InputFileName, Buffer);\r
+      }\r
+\r
+      InputFlag = FALSE;\r
+      continue;\r
+    }\r
+\r
+    if (OutputFlag) {\r
+\r
+      StripEqualMark (Buffer);\r
+\r
+      OutputFileName = (CHAR8 *) malloc (_MAX_PATH);\r
+      if (OutputFileName == NULL) {\r
+        goto ErrorExit;\r
+      }\r
+\r
+      ZeroMem (OutputFileName, sizeof (_MAX_PATH));\r
+\r
+      if (Buffer[0] == '$') {\r
+        Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName);\r
+        //\r
+        // if there is string after the environment variable, cat it.\r
+        //\r
+        if ((UINT32) Index < strlen (Buffer)) {\r
+          strcat (OutputFileName, &Buffer[Index]);\r
+        }\r
+      } else {\r
+        strcpy (OutputFileName, Buffer);\r
+      }\r
+\r
+      OutputFlag = FALSE;\r
+      continue;\r
+    }\r
+\r
+    if (GuidFlag) {\r
+\r
+      StripEqualMark (Buffer);\r
+\r
+      Status = StringToGuid (Buffer, Guid);\r
+      if (EFI_ERROR (Status)) {\r
+        ReturnValue = -1;\r
+        goto ErrorExit;\r
+      }\r
+\r
+      GuidFlag = FALSE;\r
+    }\r
+\r
+    if (AttributesFlag) {\r
+\r
+      StripEqualMark (Buffer);\r
+\r
+      //\r
+      // there might be no space between each attribute in the statement,\r
+      // split them aside and return each attribute string\r
+      // in the AttributesArray\r
+      //\r
+      SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes);\r
+    }\r
+  }\r
+  //\r
+  // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j);\r
+  // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1);\r
+  //\r
+  for (z = 0; z < NumberOfAttributes; z++) {\r
+    if (_strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) {\r
+      *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;\r
+    } else if (_strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) {\r
+      *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;\r
+    }\r
+  }\r
+\r
+ErrorExit:\r
+\r
+  for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) {\r
+    if (AttributesArray[Index2] == NULL) {\r
+      break;\r
+    }\r
+\r
+    free (AttributesArray[Index2]);\r
+  }\r
+\r
+  *PtrInputFileName   = InputFileName;\r
+  *PtrOutputFileName  = OutputFileName;\r
+\r
+  return ReturnValue;\r
+}\r
+\r
+static\r
+INT32\r
+ProcessScript (\r
+  IN OUT UINT8   *FileBuffer,\r
+  IN FILE        *Package,\r
+  IN CHAR8       *BuildDirectory,\r
+  IN BOOLEAN     ForceUncompress\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Signs the section, data stays in same location\r
+\r
+Arguments:\r
+\r
+  FileBuffer  - Data Buffer\r
+\r
+  Package     - Points to curly brace in Image Script\r
+\r
+  BuildDirectory     - Name of the source directory parameter\r
+  \r
+  ForceUncompress   - Whether to force uncompress.\r
+\r
+Returns:\r
+\r
+  Number of bytes added to file buffer\r
+  -1 on error\r
+\r
+--*/\r
+{\r
+  EFI_STATUS  Status;\r
+  UINT32      Size;\r
+  CHAR8       Buffer[_MAX_PATH];\r
+  CHAR8       Type[_MAX_PATH];\r
+  CHAR8       FileName[_MAX_PATH];\r
+  CHAR8       NewBuffer[_MAX_PATH];\r
+  INT32       Index3;\r
+  INT32       Index2;\r
+  UINT32      ReturnValue;\r
+  UINT8       ByteBuffer;\r
+  FILE        *InFile;\r
+  UINT32      SourceDataSize;\r
+  CHAR8       *ToolArgumentsArray[MAX_ARRAY_SIZE];\r
+  CHAR8       *OutputFileName;\r
+  CHAR8       *InputFileName;\r
+  CHAR8       ToolName[_MAX_PATH];\r
+  FILE        *OutputFile;\r
+  FILE        *InputFile;\r
+  UINT8       Temp;\r
+  int         returnint;\r
+  INT32       Index;\r
+  UINT32      LineNumber;\r
+  BOOLEAN     IsError;\r
+  EFI_GUID    SignGuid;\r
+  UINT16      GuidedSectionAttributes;\r
+  UINT8       *TargetFileBuffer;\r
+\r
+  OutputFileName          = NULL;\r
+  InputFileName           = NULL;\r
+  OutputFile              = NULL;\r
+  InputFile               = NULL;\r
+  IsError                 = FALSE;\r
+  GuidedSectionAttributes = 0;\r
+  TargetFileBuffer        = NULL;\r
+\r
+  Size                    = 0;\r
+  LineNumber              = 0;\r
+  Buffer[0]               = 0;\r
+  for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) {\r
+    ToolArgumentsArray[Index3] = NULL;\r
+  }\r
+\r
+  while (Buffer[0] != '}') {\r
+    if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+      CheckSlash (Buffer, Package, &LineNumber);\r
+    } else {\r
+      printf ("ERROR in IMAGE SCRIPT!\n");\r
+      IsError = TRUE;\r
+      goto Done;\r
+    }\r
+\r
+    if (_strcmpi (Buffer, "Compress") == 0) {\r
+      //\r
+      // Handle compress\r
+      //\r
+      //\r
+      // read compression type\r
+      //\r
+      if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+        CheckSlash (Buffer, Package, &LineNumber);\r
+      }\r
+\r
+      StripParens (Buffer);\r
+      if (Buffer[0] == '$') {\r
+        ProcessEnvironmentVariable (&Buffer[0], Type);\r
+      } else {\r
+        strcpy (Type, Buffer);\r
+      }\r
+      //\r
+      // build buffer\r
+      //\r
+      while (Buffer[0] != '{') {\r
+        if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+          CheckSlash (Buffer, Package, &LineNumber);\r
+        }\r
+      }\r
+\r
+      ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress);\r
+      if (ReturnValue == -1) {\r
+        IsError = TRUE;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Call compress routine on buffer.\r
+      // Occasionally, compressed data + section header would\r
+      // be largere than the source and EFI_BUFFER_TOO_SMALL is\r
+      // returned from CompressSection()\r
+      //\r
+      SourceDataSize = ReturnValue;\r
+\r
+      if (!ForceUncompress) {\r
+\r
+        Status = CompressSection (\r
+                  &FileBuffer[Size],\r
+                  &ReturnValue,\r
+                  SourceDataSize,\r
+                  Type\r
+                  );\r
+\r
+        if (Status == EFI_BUFFER_TOO_SMALL) {\r
+          Status = CompressSection (\r
+                    &FileBuffer[Size],\r
+                    &ReturnValue,\r
+                    SourceDataSize,\r
+                    Type\r
+                    );\r
+        }\r
+\r
+        if (EFI_ERROR (Status)) {\r
+          IsError = TRUE;\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      Size += ReturnValue;\r
+\r
+    } else if (_strcmpi (Buffer, "Tool") == 0) {\r
+\r
+      ZeroMem (ToolName, _MAX_PATH);\r
+      ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);\r
+      ZeroMem (&SignGuid, sizeof (EFI_GUID));\r
+\r
+      //\r
+      // handle signing Tool\r
+      //\r
+      while (Buffer[0] != '(') {\r
+        if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+          CheckSlash (Buffer, Package, &LineNumber);\r
+        }\r
+      }\r
+\r
+      if (_strcmpi (Buffer, "(") == 0) {\r
+        if (GetNextLine (Buffer, Package, &LineNumber) != -1) {\r
+          CheckSlash (Buffer, Package, &LineNumber);\r
+        }\r
+      }\r
+\r
+      StripParens (Buffer);\r
+\r
+      if (Buffer[0] == '$') {\r
+        Index = ProcessEnvironmentVariable (&Buffer[0], ToolName);\r
+        //\r
+        // if there is string after the environment variable, cat it.\r
+        //\r
+        if ((UINT32) Index < strlen (Buffer)) {\r
+          strcat (ToolName, &Buffer[Index]);\r
+        }\r
+      } else {\r
+        strcpy (ToolName, Buffer);\r
+      }\r
+\r
+      ToolArgumentsArray[0] = ToolName;\r
+\r
+      //\r
+      // read ARGS\r
+      //\r
+      if (GetToolArguments (\r
+            ToolArgumentsArray,\r
+            Package,\r
+            &InputFileName,\r
+            &OutputFileName,\r
+            &SignGuid,\r
+            &GuidedSectionAttributes\r
+            ) == -1) {\r
+        IsError = TRUE;\r
+        goto Done;\r
+      }\r
+      //\r
+      // if the tool need input file,\r
+      // dump the file buffer to the specified input file.\r
+      //\r
+      if (InputFileName != NULL) {\r
+        InputFile = fopen (InputFileName, "wb");\r
+        if (InputFile == NULL) {\r
+          Error (NULL, 0, 0, InputFileName, "failed to open output file for writing");\r
+          IsError = TRUE;\r
+          goto Done;\r
+        }\r
+\r
+        fwrite (FileBuffer, sizeof (UINT8), Size, InputFile);\r
+        fclose (InputFile);\r
+        InputFile = NULL;\r
+        free (InputFileName);\r
+        InputFileName = NULL;\r
+      }\r
+      //\r
+      // dispatch signing tool\r
+      //\r
+      returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray);\r
+      if (returnint != 0) {\r
+        Error (NULL, 0, 0, ToolName, "external tool failed");\r
+        IsError = TRUE;\r
+        goto Done;\r
+      }\r
+      //\r
+      // if the tool has output file,\r
+      // dump the output file to the file buffer\r
+      //\r
+      if (OutputFileName != NULL) {\r
+\r
+        OutputFile = fopen (OutputFileName, "rb");\r
+        if (OutputFile == NULL) {\r
+          Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");\r
+          IsError = TRUE;\r
+          goto Done;\r
+        }\r
+\r
+        TargetFileBuffer  = &FileBuffer[Size];\r
+        SourceDataSize    = Size;\r
+\r
+        fread (&Temp, sizeof (UINT8), 1, OutputFile);\r
+        while (!feof (OutputFile)) {\r
+          FileBuffer[Size++] = Temp;\r
+          fread (&Temp, sizeof (UINT8), 1, OutputFile);\r
+        }\r
+\r
+        while ((Size & 0x03) != 0) {\r
+          FileBuffer[Size] = 0;\r
+          Size++;\r
+        }\r
+\r
+        SourceDataSize = Size - SourceDataSize;\r
+\r
+        fclose (OutputFile);\r
+        OutputFile = NULL;\r
+        free (OutputFileName);\r
+        OutputFileName = NULL;\r
+\r
+        if (CompareGuid (&SignGuid, &mZeroGuid) != 0) {\r
+          ReturnValue = SourceDataSize;\r
+          Status = GenSimpleGuidSection (\r
+                    TargetFileBuffer,\r
+                    &ReturnValue,\r
+                    SourceDataSize,\r
+                    SignGuid,\r
+                    GuidedSectionAttributes\r
+                    );\r
+          if (EFI_ERROR (Status)) {\r
+            IsError = TRUE;\r
+            goto Done;\r
+          }\r
+\r
+          Size = ReturnValue;\r
+        }\r
+      }\r
+\r
+    } else if (Buffer[0] != '}') {\r
+      //\r
+      // if we are here, we should see either a file name,\r
+      // or a }.\r
+      //\r
+      Index3      = 0;\r
+      FileName[0] = 0;\r
+      //\r
+      // Prepend the build directory to the file name if the\r
+      // file name does not already contain a full path.\r
+      //\r
+      if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {\r
+        sprintf (FileName, "%s\\", BuildDirectory);\r
+      }\r
+\r
+      while (Buffer[Index3] != '\n') {\r
+        if (Buffer[Index3] == '$') {\r
+          Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer);\r
+          strcat (FileName, NewBuffer);\r
+        }\r
+\r
+        if (Buffer[Index3] == 0) {\r
+          break;\r
+        } else {\r
+          Index2              = strlen (FileName);\r
+          FileName[Index2++]  = Buffer[Index3++];\r
+          FileName[Index2]    = 0;\r
+        }\r
+      }\r
+\r
+      InFile = fopen (FileName, "rb");\r
+      if (InFile == NULL) {\r
+        Error (NULL, 0, 0, FileName, "failed to open file for reading");\r
+        IsError = TRUE;\r
+        goto Done;\r
+      }\r
+\r
+      fread (&ByteBuffer, sizeof (UINT8), 1, InFile);\r
+      while (!feof (InFile)) {\r
+        FileBuffer[Size++] = ByteBuffer;\r
+        fread (&ByteBuffer, sizeof (UINT8), 1, InFile);\r
+      }\r
+\r
+      fclose (InFile);\r
+      InFile = NULL;\r
+\r
+      //\r
+      // Make sure section ends on a DWORD boundary\r
+      //\r
+      while ((Size & 0x03) != 0) {\r
+        FileBuffer[Size] = 0;\r
+        Size++;\r
+      }\r
+\r
+    }\r
+  }\r
+\r
+Done:\r
+  for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) {\r
+    if (ToolArgumentsArray[Index3] == NULL) {\r
+      break;\r
+    }\r
+\r
+    free (ToolArgumentsArray[Index3]);\r
+  }\r
+\r
+  if (IsError) {\r
+    return -1;\r
+  }\r
+\r
+  return Size;\r
+\r
+}\r
+\r
+static\r
+UINT8\r
+StringToType (\r
+  IN CHAR8 *String\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Converts File Type String to value.  EFI_FV_FILETYPE_ALL indicates that an\r
+  unrecognized file type was specified.\r
+\r
+Arguments:\r
+\r
+  String    - File type string\r
+\r
+Returns:\r
+\r
+  File Type Value\r
+\r
+--*/\r
+{\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) {\r
+    return EFI_FV_FILETYPE_RAW;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) {\r
+    return EFI_FV_FILETYPE_FREEFORM;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) {\r
+    return EFI_FV_FILETYPE_SECURITY_CORE;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) {\r
+    return EFI_FV_FILETYPE_PEI_CORE;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) {\r
+    return EFI_FV_FILETYPE_DXE_CORE;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) {\r
+    return EFI_FV_FILETYPE_PEIM;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) {\r
+    return EFI_FV_FILETYPE_DRIVER;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) {\r
+    return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) {\r
+    return EFI_FV_FILETYPE_APPLICATION;\r
+  }\r
+\r
+  if (_strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) {\r
+    return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;\r
+  }\r
+\r
+  return EFI_FV_FILETYPE_ALL;\r
+}\r
+\r
+static\r
+UINT32\r
+AdjustFileSize (\r
+  IN UINT8  *FileBuffer,\r
+  IN UINT32 FileSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Adjusts file size to insure sectioned file is exactly the right length such\r
+  that it ends on exactly the last byte of the last section.  ProcessScript()\r
+  may have padded beyond the end of the last section out to a 4 byte boundary.\r
+  This padding is stripped.\r
+\r
+Arguments:\r
+  FileBuffer  - Data Buffer - contains a section stream\r
+  FileSize    - Size of FileBuffer as returned from ProcessScript()\r
+\r
+Returns:\r
+  Corrected size of file.\r
+\r
+--*/\r
+{\r
+  UINT32                    TotalLength;\r
+  UINT32                    CurrentLength;\r
+  UINT32                    SectionLength;\r
+  UINT32                    SectionStreamLength;\r
+  EFI_COMMON_SECTION_HEADER *SectionHeader;\r
+  EFI_COMMON_SECTION_HEADER *NextSectionHeader;\r
+\r
+  TotalLength         = 0;\r
+  CurrentLength       = 0;\r
+  SectionStreamLength = FileSize;\r
+\r
+  SectionHeader       = (EFI_COMMON_SECTION_HEADER *) FileBuffer;\r
+\r
+  while (TotalLength < SectionStreamLength) {\r
+    SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff;\r
+    TotalLength += SectionLength;\r
+\r
+    if (TotalLength == SectionStreamLength) {\r
+      return TotalLength;\r
+    }\r
+    //\r
+    // Move to the next byte following the section...\r
+    //\r
+    SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);\r
+    CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer;\r
+\r
+    //\r
+    // Figure out where the next section begins\r
+    //\r
+    NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3);\r
+    NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3);\r
+    TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;\r
+    SectionHeader = NextSectionHeader;\r
+  }\r
+\r
+  return CurrentLength;\r
+}\r
+\r
+static\r
+INT32\r
+MainEntry (\r
+  INT32     argc,\r
+  CHAR8     *argv[],\r
+  BOOLEAN   ForceUncompress\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  MainEntry function.\r
+\r
+Arguments:\r
+\r
+  argc            - Number of command line parameters.\r
+  argv            - Array of pointers to command line parameter strings.\r
+  ForceUncompress - If TRUE, force to do not compress the sections even if compression\r
+                    is specified in the script. Otherwise, FALSE.\r
+\r
+Returns:\r
+  STATUS_SUCCESS  - Function exits successfully.\r
+  STATUS_ERROR    - Some error occurred during execution.\r
+\r
+--*/\r
+{\r
+  FILE                    *PrimaryPackage;\r
+  FILE                    *OverridePackage;\r
+  FILE                    *Out;\r
+  CHAR8                   BaseName[_MAX_PATH];\r
+  EFI_GUID                FfsGuid;\r
+  CHAR8                   GuidString[_MAX_PATH];\r
+  EFI_FFS_FILE_HEADER     FileHeader;\r
+  CHAR8                   FileType[_MAX_PATH];\r
+  EFI_FFS_FILE_ATTRIBUTES FfsAttrib;\r
+  EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined;\r
+  UINT64                  FfsAlignment;\r
+  UINT32                  FfsAlignment32;\r
+  CHAR8                   InputString[_MAX_PATH];\r
+  BOOLEAN                 ImageScriptInOveride;\r
+  UINT32                  FileSize;\r
+  UINT8                   *FileBuffer;\r
+  EFI_STATUS              Status;\r
+  UINT32                  LineNumber;\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)  \r
+  EFI_FFS_FILE_TAIL       TailValue;\r
+#endif\r
+  BaseName[0]       = 0;\r
+  FileType[0]       = 0;\r
+  FfsAttrib         = 0;\r
+  FfsAttribDefined  = 0;\r
+  FfsAlignment      = 0;\r
+  FfsAlignment32    = 0;\r
+  PrimaryPackage    = NULL;\r
+  Out               = NULL;\r
+  OverridePackage   = NULL;\r
+  FileBuffer        = NULL;\r
+\r
+  strcpy (GuidString, "00000000-0000-0000-0000-000000000000");\r
+  Status = StringToGuid (GuidString, &FfsGuid);\r
+  if (Status != 0) {\r
+    Error (NULL, 0, 0, GuidString, "error parsing GUID string");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  GuidString[0]         = 0;\r
+  ImageScriptInOveride  = FALSE;\r
+  //\r
+  // Initialize the simple file parsing routines. Then open\r
+  // the primary package file for parsing.\r
+  //\r
+  SFPInit ();\r
+  if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) {\r
+    Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");\r
+    goto Done;\r
+  }\r
+  //\r
+  // First token in the file must be "PACKAGE.INF"\r
+  //\r
+  if (!SFPIsToken ("PACKAGE.INF")) {\r
+    Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL);\r
+    goto Done;\r
+  }\r
+  //\r
+  // Find the [.] section\r
+  //\r
+  if (!SFPSkipToToken ("[.]")) {\r
+    Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL);\r
+    goto Done;\r
+  }\r
+  //\r
+  // Start parsing the data. The algorithm is essentially the same for each keyword:\r
+  //   1. Identify the keyword\r
+  //   2. Verify that the keyword/value pair has not already been defined\r
+  //   3. Set some flag indicating that the keyword/value pair has been defined\r
+  //   4. Skip over the "="\r
+  //   5. Get the value, which may be a number, TRUE, FALSE, or a string.\r
+  //\r
+  while (1) {\r
+    if (SFPIsToken ("BASE_NAME")) {\r
+      //\r
+      // Found BASE_NAME, format:\r
+      //   BASE_NAME = MyBaseName\r
+      //\r
+      if (BaseName[0] != 0) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPGetNextToken (BaseName, sizeof (BaseName))) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL);\r
+        goto Done;\r
+      }\r
+    } else if (SFPIsToken ("IMAGE_SCRIPT")) {\r
+      //\r
+      // Found IMAGE_SCRIPT. Break out and process below.\r
+      //\r
+      break;\r
+    } else if (SFPIsToken ("FFS_FILEGUID")) {\r
+      //\r
+      // found FILEGUID, format:\r
+      //   FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A\r
+      //\r
+      if (GuidString[0] != 0) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      Status = StringToGuid (GuidString, &FfsGuid);\r
+      if (Status != 0) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL);\r
+        goto Done;\r
+      }\r
+    } else if (SFPIsToken ("FFS_FILETYPE")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found FFS_FILETYPE, format:\r
+      //  FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION\r
+      //\r
+      if (FileType[0] != 0) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPGetNextToken (FileType, sizeof (FileType))) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL);\r
+        goto Done;\r
+      }\r
+    }\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)    \r
+    else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE\r
+      // Spec says the bit is for future expansion, and must be false.\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) {\r
+        Error (\r
+          mGlobals.PrimaryPackagePath,\r
+          SFPGetLineNumber (),\r
+          0,\r
+          "FFS_ATTRIB_HEADER_EXTENSION previously defined",\r
+          NULL\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPIsToken ("TRUE")) {\r
+        Error (\r
+          mGlobals.PrimaryPackagePath,\r
+          SFPGetLineNumber (),\r
+          0,\r
+          "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported",\r
+          NULL\r
+          );\r
+        goto Done;\r
+      } else if (SFPIsToken ("FALSE")) {\r
+        //\r
+        // Default is FALSE\r
+        //\r
+      } else {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL);\r
+        goto Done;\r
+      }\r
+    }\r
+#else\r
+    else if (SFPIsToken ("FFS_ATTRIB_FIXED")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found: FFS_ATTRIB_FIXED = TRUE | FALSE\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_FIXED) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_FIXED previously defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_FIXED;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPIsToken ("TRUE")) {\r
+        FfsAttrib |= FFS_ATTRIB_FIXED;\r
+      } else if (SFPIsToken ("FALSE")) {\r
+        //\r
+        // Default is FALSE\r
+        //\r
+      } else {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+        goto Done;\r
+      }\r
+    } \r
+#endif\r
+    else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPIsToken ("TRUE")) {\r
+        FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT;\r
+      } else if (SFPIsToken ("FALSE")) {\r
+        //\r
+        // Default is FALSE\r
+        //\r
+      } else {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+        goto Done;\r
+      }\r
+    } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_RECOVERY;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPIsToken ("TRUE")) {\r
+        FfsAttrib |= FFS_ATTRIB_RECOVERY;\r
+      } else if (SFPIsToken ("FALSE")) {\r
+        //\r
+        // Default is FALSE\r
+        //\r
+      } else {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+        goto Done;\r
+      }\r
+    } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_CHECKSUM;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (SFPIsToken ("TRUE")) {\r
+        FfsAttrib |= FFS_ATTRIB_CHECKSUM;\r
+      } else if (SFPIsToken ("FALSE")) {\r
+        //\r
+        // Default is FALSE\r
+        //\r
+      } else {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+        goto Done;\r
+      }\r
+    } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) {\r
+      //\r
+      // ***********************************************************************\r
+      //\r
+      // Found FFS_ALIGNMENT, formats:\r
+      //   FFS_ALIGNMENT = 0-7\r
+      //   FFS_ATTRIB_DATA_ALIGNMENT = 0-7\r
+      //\r
+      if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) {\r
+        Error (\r
+          mGlobals.PrimaryPackagePath,\r
+          SFPGetLineNumber (),\r
+          0,\r
+          "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined",\r
+          NULL\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT;\r
+      if (!SFPIsToken ("=")) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPGetNumber (&FfsAlignment32)) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      if (FfsAlignment32 > 7) {\r
+        Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL);\r
+        goto Done;\r
+      }\r
+\r
+      FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3);\r
+    } else {\r
+      SFPGetNextToken (InputString, sizeof (InputString));\r
+      Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token");\r
+      goto Done;\r
+    }\r
+  }\r
+  //\r
+  // Close the primary package file\r
+  //\r
+  SFPCloseFile ();\r
+  //\r
+  // TODO: replace code below with basically a copy of the code above. Don't\r
+  // forget to reset the FfsAttribDefined variable first. Also, you'll need\r
+  // to somehow keep track of whether or not the basename is defined multiple\r
+  // times in the override package. Ditto on the file GUID.\r
+  //\r
+  if (mGlobals.OverridePackagePath[0] != 0) {\r
+    OverridePackage = fopen (mGlobals.OverridePackagePath, "r");\r
+    //\r
+    // NOTE: For package override to work correctly, the code below must be modified to\r
+    //       SET or CLEAR bits properly. For example, if the primary package set\r
+    //       FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then\r
+    //       we'd need to clear the bit below. Since this is not happening, I'm guessing that\r
+    //       the override functionality is not being used, so should be made obsolete. If I'm\r
+    //       wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is\r
+    //       used, and we'll address it then.  4/10/2003\r
+    //\r
+    Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL);\r
+    goto Done;\r
+  } else {\r
+    OverridePackage = NULL;\r
+  }\r
+\r
+#ifdef OVERRIDE_SUPPORTED\r
+  if (OverridePackage != NULL) {\r
+    //\r
+    // Parse override package file\r
+    //\r
+    fscanf (OverridePackage, "%s", &InputString);\r
+    if (_strcmpi (InputString, "PACKAGE.INF") != 0) {\r
+      Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'");\r
+      goto Done;\r
+    }\r
+    //\r
+    // Match [dir] to Build Directory\r
+    //\r
+    if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) {\r
+      Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file");\r
+      goto Done;\r
+    }\r
+\r
+    InputString[0] = 0;\r
+    while ((InputString[0] != '[') && (!feof (OverridePackage))) {\r
+      if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) {\r
+        if (InputString[0] != '[') {\r
+here:\r
+          if (_strcmpi (InputString, "BASE_NAME") == 0) {\r
+            //\r
+            // found BASE_NAME, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+              strcpy (BaseName, InputString);\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+              strcpy (BaseName, InputString);\r
+            }\r
+          } else if (_strcmpi (InputString, "IMAGE_SCRIPT") == 0) {\r
+            //\r
+            // found IMAGE_SCRIPT, come back later to process it\r
+            //\r
+            ImageScriptInOveride = TRUE;\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+          } else if (_strcmpi (InputString, "FFS_FILEGUID") == 0) {\r
+            //\r
+            // found FILEGUID, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+              Status = StringToGuid (InputString, &FfsGuid);\r
+              if (Status != 0) {\r
+                Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");\r
+                goto Done;\r
+              }\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+              Status = StringToGuid (InputString, &FfsGuid);\r
+              if (Status != 0) {\r
+                Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");\r
+                goto Done;\r
+              }\r
+            }\r
+          } else if (_strcmpi (InputString, "FFS_FILETYPE") == 0) {\r
+            //\r
+            // found FILETYPE, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+              strcpy (FileType, InputString);\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+              strcpy (FileType, InputString);\r
+            }\r
+\r
+          } else if (_strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) {\r
+            //\r
+            // found FFS_ATTRIB_RECOVERY, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+              if (_strcmpi (InputString, "TRUE") == 0) {\r
+                FfsAttrib |= FFS_ATTRIB_RECOVERY;\r
+              }\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+              if (_strcmpi (InputString, "TRUE") == 0) {\r
+                FfsAttrib |= FFS_ATTRIB_RECOVERY;\r
+              }\r
+            }\r
+          } else if (_strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) {\r
+            //\r
+            // found FFS_ATTRIB_CHECKSUM, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+              if (_strcmpi (InputString, "TRUE") == 0) {\r
+                FfsAttrib |= FFS_ATTRIB_CHECKSUM;\r
+              }\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+              if (_strcmpi (InputString, "TRUE") == 0) {\r
+                FfsAttrib |= FFS_ATTRIB_CHECKSUM;\r
+              }\r
+            }\r
+          } else if (_strcmpi (InputString, "FFS_ALIGNMENT") == 0) {\r
+            //\r
+            // found FFS_ALIGNMENT, next is = and string.\r
+            //\r
+            fscanf (OverridePackage, "%s", &InputString);\r
+            CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            if (strlen (InputString) == 1) {\r
+              //\r
+              // string is just =\r
+              //\r
+              fscanf (OverridePackage, "%s", &InputString);\r
+              CheckSlash (InputString, OverridePackage, &LineNumber);\r
+            } else {\r
+              BreakString (InputString, InputString, 1);\r
+            }\r
+\r
+            AsciiStringToUint64 (InputString, FALSE, &FfsAlignment);\r
+            if (FfsAlignment > 7) {\r
+              Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value");\r
+              goto Done;\r
+            }\r
+\r
+            FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3);\r
+          } else if (strchr (InputString, '=') != NULL) {\r
+            BreakString (InputString, String, 1);\r
+            fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR);\r
+            BreakString (InputString, InputString, 0);\r
+            goto here;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+#endif // #ifdef OVERRIDE_SUPPORTED\r
+  //\r
+  // Require that they specified a file GUID at least, since that's how we're\r
+  // naming the file.\r
+  //\r
+  if (GuidString[0] == 0) {\r
+    Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Build Header and process image script\r
+  //\r
+  FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8));\r
+  if (FileBuffer == NULL) {\r
+    Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);\r
+    goto Done;\r
+  }\r
+\r
+  FileSize = 0;\r
+  if (ImageScriptInOveride) {\r
+#ifdef OVERRIDE_SUPPORTED\r
+    rewind (OverridePackage);\r
+    LineNumber = 0;\r
+    FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber);\r
+    while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) {\r
+      GetNextLine (InputString, OverridePackage, &LineNumber);\r
+      CheckSlash (InputString, OverridePackage, &LineNumber);\r
+      if (strchr (InputString, '=') != NULL) {\r
+        BreakString (InputString, InputString, 0);\r
+      }\r
+    }\r
+\r
+    while (InputString[0] != '{') {\r
+      GetNextLine (InputString, OverridePackage, &LineNumber);\r
+      CheckSlash (InputString, OverridePackage, &LineNumber);\r
+    }\r
+    //\r
+    // Found start of image script, process it\r
+    //\r
+    FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress);\r
+    if (FileSize == -1) {\r
+      Error (NULL, 0, 0, "failed to process script", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {\r
+      FileSize = AdjustFileSize (FileBuffer, FileSize);\r
+    }\r
+\r
+    if (BaseName[0] == '\"') {\r
+      StripQuotes (BaseName);\r
+    }\r
+\r
+    if (BaseName[0] != 0) {\r
+      sprintf (InputString, "%s-%s", GuidString, BaseName);\r
+    } else {\r
+      strcpy (InputString, GuidString);\r
+    }\r
+\r
+    switch (StringToType (FileType)) {\r
+\r
+    case EFI_FV_FILETYPE_SECURITY_CORE:\r
+      strcat (InputString, ".SEC");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_PEIM:\r
+    case EFI_FV_FILETYPE_PEI_CORE:\r
+    case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
+      strcat (InputString, ".PEI");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_DRIVER:\r
+    case EFI_FV_FILETYPE_DXE_CORE:\r
+      strcat (InputString, ".DXE");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_APPLICATION:\r
+      strcat (InputString, ".APP");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
+      strcat (InputString, ".FVI");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_RAW:\r
+      strcat (InputString, ".RAW");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_ALL:\r
+      Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL);\r
+      goto Done;\r
+\r
+    default:\r
+      strcat (InputString, ".FFS");\r
+      break;\r
+    }\r
+\r
+    if (ForceUncompress) {\r
+      strcat (InputString, ".ORG");\r
+    }\r
+\r
+    Out = fopen (InputString, "wb");\r
+    if (Out == NULL) {\r
+      Error (NULL, 0, 0, InputString, "could not open output file for writing");\r
+      goto Done;\r
+    }\r
+    //\r
+    // create ffs header\r
+    //\r
+    memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
+    memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
+    FileHeader.Type       = StringToType (FileType);\r
+    FileHeader.Attributes = FfsAttrib;\r
+    //\r
+    // Now FileSize includes the EFI_FFS_FILE_HEADER\r
+    //\r
+    FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
+    FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);\r
+    FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);\r
+    FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
+    //\r
+    // Fill in checksums and state, these must be zero for checksumming\r
+    //\r
+    // FileHeader.IntegrityCheck.Checksum.Header = 0;\r
+    // FileHeader.IntegrityCheck.Checksum.File = 0;\r
+    // FileHeader.State = 0;\r
+    //\r
+    FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
+                                                  (UINT8 *) &FileHeader,\r
+                                                  sizeof (EFI_FFS_FILE_HEADER)\r
+                                                  );\r
+    if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
+      FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize);\r
+    } else {\r
+      FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+    }\r
+\r
+    FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
+    //\r
+    // write header\r
+    //\r
+    if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {\r
+      Error (NULL, 0, 0, "failed to write file header to output file", NULL);\r
+      goto Done;\r
+    }\r
+    //\r
+    // write data\r
+    //\r
+    if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {\r
+      Error (NULL, 0, 0, "failed to write all bytes to output file", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    fclose (Out);\r
+    Out = NULL;\r
+#endif // #ifdef OVERRIDE_SUPPORTED\r
+  } else {\r
+    //\r
+    // Open primary package file and process the IMAGE_SCRIPT section\r
+    //\r
+    PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r");\r
+    if (PrimaryPackage == NULL) {\r
+      Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");\r
+      goto Done;\r
+    }\r
+\r
+    LineNumber = 1;\r
+    FindSectionInPackage (".", PrimaryPackage, &LineNumber);\r
+    while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) {\r
+      GetNextLine (InputString, PrimaryPackage, &LineNumber);\r
+      CheckSlash (InputString, PrimaryPackage, &LineNumber);\r
+      if (strchr (InputString, '=') != NULL) {\r
+        BreakString (InputString, InputString, 0);\r
+      }\r
+    }\r
+\r
+    while (InputString[0] != '{') {\r
+      GetNextLine (InputString, PrimaryPackage, &LineNumber);\r
+      CheckSlash (InputString, PrimaryPackage, &LineNumber);\r
+    }\r
+    //\r
+    // Found start of image script, process it\r
+    //\r
+    FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress);\r
+    if (FileSize == -1) {\r
+      Error (NULL, 0, 0, "failed to process script", NULL);\r
+      goto Done;\r
+    }\r
+\r
+    if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {\r
+      FileSize = AdjustFileSize (FileBuffer, FileSize);\r
+    }\r
+\r
+    if (BaseName[0] == '\"') {\r
+      StripQuotes (BaseName);\r
+    }\r
+\r
+    if (BaseName[0] != 0) {\r
+      sprintf (InputString, "%s-%s", GuidString, BaseName);\r
+    } else {\r
+      strcpy (InputString, GuidString);\r
+    }\r
+\r
+    switch (StringToType (FileType)) {\r
+\r
+    case EFI_FV_FILETYPE_SECURITY_CORE:\r
+      strcat (InputString, ".SEC");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_PEIM:\r
+    case EFI_FV_FILETYPE_PEI_CORE:\r
+    case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:\r
+      strcat (InputString, ".PEI");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_DRIVER:\r
+    case EFI_FV_FILETYPE_DXE_CORE:\r
+      strcat (InputString, ".DXE");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_APPLICATION:\r
+      strcat (InputString, ".APP");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:\r
+      strcat (InputString, ".FVI");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_RAW:\r
+      strcat (InputString, ".RAW");\r
+      break;\r
+\r
+    case EFI_FV_FILETYPE_ALL:\r
+      Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL);\r
+      goto Done;\r
+\r
+    default:\r
+      strcat (InputString, ".FFS");\r
+      break;\r
+    }\r
+\r
+    if (ForceUncompress) {\r
+      strcat (InputString, ".ORG");\r
+    }\r
+\r
+    Out = fopen (InputString, "wb");\r
+    if (Out == NULL) {\r
+      Error (NULL, 0, 0, InputString, "failed to open output file for writing");\r
+      goto Done;\r
+    }\r
+    //\r
+    // Initialize the FFS file header\r
+    //\r
+    memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
+    memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));\r
+    FileHeader.Type       = StringToType (FileType);\r
+    FileHeader.Attributes = FfsAttrib;\r
+    //\r
+    // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER\r
+    //\r
+    FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
+    //\r
+    // If using a tail, then it adds two bytes\r
+    //\r
+    if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      //\r
+      // Tail is not allowed for pad and 0-length files\r
+      //\r
+      if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) {\r
+        Error (\r
+          mGlobals.PrimaryPackagePath,\r
+          1,\r
+          0,\r
+          "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files",\r
+          NULL\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      FileSize += sizeof (EFI_FFS_FILE_TAIL);\r
+    }\r
+\r
+    FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);\r
+    FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);\r
+    FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
+    //\r
+    // Fill in checksums and state, they must be 0 for checksumming.\r
+    //\r
+    // FileHeader.IntegrityCheck.Checksum.Header = 0;\r
+    // FileHeader.IntegrityCheck.Checksum.File = 0;\r
+    // FileHeader.State = 0;\r
+    //\r
+    FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
+                                                  (UINT8 *) &FileHeader,\r
+                                                  sizeof (EFI_FFS_FILE_HEADER)\r
+                                                  );\r
+    if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
+      //\r
+      // Cheating here.  Since the header checksums, just calculate the checksum of the body.\r
+      // Checksum does not include the tail\r
+      //\r
+      if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+        FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
+                                                    FileBuffer,\r
+                                                    FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL)\r
+                                                    );\r
+      } else {\r
+        FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
+                                                    FileBuffer,\r
+                                                    FileSize - sizeof (EFI_FFS_FILE_HEADER)\r
+                                                    );\r
+      }\r
+    } else {\r
+      FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
+    }\r
+    //\r
+    // Set the state now. Spec says the checksum assumes the state is 0\r
+    //\r
+    FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
+\r
+#if (PI_SPECIFICATION_VERSION < 0x00010000)\r
+\r
+    //\r
+    // If there is a tail, then set it\r
+    //\r
+    if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {\r
+      TailValue = FileHeader.IntegrityCheck.TailReference;\r
+      TailValue = (UINT16) (~TailValue);\r
+      memcpy (\r
+        (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL),\r
+        &TailValue,\r
+        sizeof (TailValue)\r
+        );\r
+    }\r
+#endif    \r
+    //\r
+    // Write the FFS file header\r
+    //\r
+    if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {\r
+      Error (NULL, 0, 0, "failed to write file header contents", NULL);\r
+      goto Done;\r
+    }\r
+    //\r
+    // Write data\r
+    //\r
+    if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {\r
+      Error (NULL, 0, 0, "failed to write file contents", NULL);\r
+      goto Done;\r
+    }\r
+  }\r
+\r
+Done:\r
+  SFPCloseFile ();\r
+  if (Out != NULL) {\r
+    fclose (Out);\r
+  }\r
+\r
+  if (PrimaryPackage != NULL) {\r
+    fclose (PrimaryPackage);\r
+  }\r
+\r
+  if (FileBuffer != NULL) {\r
+    free (FileBuffer);\r
+  }\r
+\r
+  if (OverridePackage != NULL) {\r
+    fclose (OverridePackage);\r
+  }\r
+\r
+  return GetUtilityStatus ();\r
+}\r
+\r
+int\r
+main (\r
+  INT32 argc,\r
+  CHAR8 *argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Main function.\r
+\r
+Arguments:\r
+\r
+  argc - Number of command line parameters.\r
+  argv - Array of pointers to parameter strings.\r
+\r
+Returns:\r
+  STATUS_SUCCESS - Utility exits successfully.\r
+  STATUS_ERROR   - Some error occurred during execution.\r
+\r
+--*/\r
+{\r
+  STATUS  Status;\r
+  //\r
+  // Set the name of our utility for error reporting purposes.\r
+  //\r
+  SetUtilityName (UTILITY_NAME);\r
+  Status = ProcessCommandLineArgs (argc, argv);\r
+  if (Status != STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  Status = MainEntry (argc, argv, TRUE);\r
+  if (Status == STATUS_SUCCESS) {\r
+    MainEntry (argc, argv, FALSE);\r
+  }\r
+  //\r
+  // If any errors were reported via the standard error reporting\r
+  // routines, then the status has been saved. Get the value and\r
+  // return it to the caller.\r
+  //\r
+  return GetUtilityStatus ();\r
+}\r
+\r
+static\r
+STATUS\r
+ProcessCommandLineArgs (\r
+  int     Argc,\r
+  char    *Argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Process the command line arguments.\r
+\r
+Arguments:\r
+  Argc - as passed in to main()\r
+  Argv - as passed in to main()\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - arguments all ok\r
+  STATUS_ERROR      - problem with args, so caller should exit\r
+\r
+--*/\r
+{\r
+  //\r
+  // If no args, then print usage instructions and return an error\r
+  //\r
+  if (Argc == 1) {\r
+    PrintUsage ();\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  memset (&mGlobals, 0, sizeof (mGlobals));\r
+  Argc--;\r
+  Argv++;\r
+  while (Argc > 0) {\r
+    if (_strcmpi (Argv[0], "-b") == 0) {\r
+      //\r
+      // OPTION: -b BuildDirectory\r
+      // Make sure there is another argument, then save it to our globals.\r
+      //\r
+      if (Argc < 2) {\r
+        Error (NULL, 0, 0, "-b option requires the build directory name", NULL);\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      if (mGlobals.BuildDirectory[0]) {\r
+        Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      strcpy (mGlobals.BuildDirectory, Argv[1]);\r
+      Argc--;\r
+      Argv++;\r
+    } else if (_strcmpi (Argv[0], "-p1") == 0) {\r
+      //\r
+      // OPTION: -p1 PrimaryPackageFile\r
+      // Make sure there is another argument, then save it to our globals.\r
+      //\r
+      if (Argc < 2) {\r
+        Error (NULL, 0, 0, Argv[0], "option requires the primary package file name");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      if (mGlobals.PrimaryPackagePath[0]) {\r
+        Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      strcpy (mGlobals.PrimaryPackagePath, Argv[1]);\r
+      Argc--;\r
+      Argv++;\r
+    } else if (_strcmpi (Argv[0], "-p2") == 0) {\r
+      //\r
+      // OPTION: -p2 OverridePackageFile\r
+      // Make sure there is another argument, then save it to our globals.\r
+      //\r
+      if (Argc < 2) {\r
+        Error (NULL, 0, 0, Argv[0], "option requires the override package file name");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      if (mGlobals.OverridePackagePath[0]) {\r
+        Error (NULL, 0, 0, Argv[0], "option can only be specified once");\r
+        return STATUS_ERROR;\r
+      }\r
+\r
+      strcpy (mGlobals.OverridePackagePath, Argv[1]);\r
+      Argc--;\r
+      Argv++;\r
+    } else if (_strcmpi (Argv[0], "-v") == 0) {\r
+      //\r
+      // OPTION: -v       verbose\r
+      //\r
+      mGlobals.Verbose = TRUE;\r
+    } else if (_strcmpi (Argv[0], "-h") == 0) {\r
+      //\r
+      // OPTION: -h      help\r
+      //\r
+      PrintUsage ();\r
+      return STATUS_ERROR;\r
+    } else if (_strcmpi (Argv[0], "-?") == 0) {\r
+      //\r
+      // OPTION:  -?      help\r
+      //\r
+      PrintUsage ();\r
+      return STATUS_ERROR;\r
+    } else {\r
+      Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
+      PrintUsage ();\r
+      return STATUS_ERROR;\r
+    }\r
+\r
+    Argv++;\r
+    Argc--;\r
+  }\r
+  //\r
+  // Must have at least specified the package file name\r
+  //\r
+  if (mGlobals.PrimaryPackagePath[0] == 0) {\r
+    Error (NULL, 0, 0, "must specify primary package file", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r