Home | History | Annotate | Download | only in GenFfsFile
      1 /*++
      2 
      3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
      4 This program and the accompanying materials
      5 are licensed and made available under the terms and conditions of the BSD License
      6 which accompanies this distribution.  The full text of the license may be found at
      7 http://opensource.org/licenses/bsd-license.php
      8 
      9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12 Module Name:
     13 
     14   GenFfsFile.c
     15 
     16 Abstract:
     17 
     18   This file contains functions required to generate a Firmware File System
     19   file.
     20 
     21 --*/
     22 
     23 #include "TianoCommon.h"
     24 #include "EfiFirmwareFileSystem.h"
     25 #include "EfiFirmwareVolumeHeader.h"
     26 #include "EfiImageFormat.h"
     27 #include "EfiImage.h"
     28 #include "ParseInf.h"
     29 #include "Compress.h"
     30 #include "EfiCustomizedCompress.h"
     31 #include "crc32.h"
     32 #include "GenFfsFile.h"
     33 #include <stdio.h>
     34 #include <ctype.h>  // for isalpha()
     35 //
     36 // include file for _spawnv
     37 //
     38 #include <process.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include "CommonLib.h"
     42 #include "EfiUtilityMsgs.h"
     43 #include "SimpleFileParsing.h"
     44 
     45 #define UTILITY_NAME    "GenFfsFile"
     46 #define UTILITY_VERSION "v1.1"
     47 #define MAX_ARRAY_SIZE  100
     48 
     49 static
     50 INT32
     51 GetNextLine (
     52   OUT CHAR8       *Destination,
     53   IN FILE         *Package,
     54   IN OUT UINT32   *LineNumber
     55   );
     56 
     57 static
     58 void
     59 CheckSlash (
     60   IN OUT CHAR8  *String,
     61   IN FILE       *In,
     62   IN OUT UINT32 *LineNumber
     63   );
     64 
     65 static
     66 INT32
     67 FindSectionInPackage (
     68   IN CHAR8        *BuildDirectory,
     69   IN FILE         *OverridePackage,
     70   IN OUT UINT32   *LineNumber
     71   );
     72 
     73 static
     74 STATUS
     75 ProcessCommandLineArgs (
     76   int     Argc,
     77   char    *Argv[]
     78   );
     79 
     80 static
     81 void
     82 PrintUsage (
     83   void
     84   );
     85 
     86 static
     87 void
     88 AddMacro (
     89   UINT8   *MacroString
     90   );
     91 
     92 static
     93 UINT8 *
     94 GetMacroValue (
     95   UINT8   *MacroName
     96   );
     97 
     98 static
     99 void
    100 FreeMacros (
    101   );
    102 
    103 static
    104 STATUS
    105 ReplaceMacros (
    106   UINT8   *InputFile,
    107   UINT8   *OutputFile
    108   );
    109 
    110 //
    111 // Linked list to keep track of all macros
    112 //
    113 typedef struct _MACRO {
    114   struct _MACRO   *Next;
    115   UINT8           *Name;
    116   UINT8           *Value;
    117 } MACRO;
    118 
    119 //
    120 // Keep globals in this structure
    121 //
    122 static struct {
    123   UINT8   BuildDirectory[_MAX_PATH];
    124   UINT8   PrimaryPackagePath[_MAX_PATH];
    125   UINT8   OverridePackagePath[_MAX_PATH];
    126   UINT8   OutputFilePath[_MAX_PATH];
    127   BOOLEAN Verbose;
    128   MACRO   *MacroList;
    129 } mGlobals;
    130 
    131 static EFI_GUID mZeroGuid = { 0 };
    132 
    133 static UINT8  MinFfsDataAlignOverride = 0;
    134 
    135 static
    136 void
    137 StripQuotes (
    138   IN OUT CHAR8 *String
    139   )
    140 /*++
    141 
    142 Routine Description:
    143 
    144   Removes quotes and/or whitespace from around a string
    145 
    146 Arguments:
    147 
    148  String    - String to remove quotes from
    149 
    150 Returns:
    151 
    152   None
    153 
    154 --*/
    155 {
    156   UINTN Index;
    157   UINTN Index2;
    158   UINTN StrLen;
    159 
    160   Index2  = strspn (String, "\" \t\n");
    161   StrLen  = strlen (String);
    162 
    163   for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) {
    164     String[Index - Index2] = String[Index];
    165   }
    166 
    167   String[Index - Index2] = 0;
    168 }
    169 
    170 static
    171 void
    172 PrintUsage (
    173   void
    174   )
    175 /*++
    176 
    177 Routine Description:
    178 
    179   Print Error / Help message.
    180 
    181 Arguments:
    182 
    183   void
    184 
    185 Returns:
    186 
    187   None
    188 
    189 --*/
    190 {
    191   int         Index;
    192   const char  *Str[] = {
    193     UTILITY_NAME" "UTILITY_VERSION" - Intel Generate FFS File Utility",
    194     "  Copyright (C), 2004 - 2009 Intel Corporation",
    195 
    196 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
    197     "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
    198 #endif
    199     "",
    200     "Usage:",
    201     "  "UTILITY_NAME" [OPTION]...",
    202     "Options:",
    203     "  -b BuildDirectory  Specifies the full path to the component build directory",
    204     "  -p1 P1Path         Specifies fully qualified file name to the primary package",
    205     "                     file. This file will normally exist in the same directory",
    206     "                     as the makefile for the component. Required.",
    207     "  -p2 P2Path         Specifies fully qualified file name to the override",
    208     "                     package. This file will normally exist in the build tip.",
    209     "                     Optional.",
    210     "  -d Name=Value      Add a macro definition for the package file. Optional.",
    211     "  -o OutputFile      Specifies the file name of output file. Optional.",
    212     "  -v                 Verbose. Optional.",
    213     NULL
    214   };
    215   for (Index = 0; Str[Index] != NULL; Index++) {
    216     fprintf (stdout, "%s\n", Str[Index]);
    217   }
    218 }
    219 
    220 static
    221 INT32
    222 TestComment (
    223   IN CHAR8  *String,
    224   IN FILE   *In
    225   )
    226 /*++
    227 
    228 Routine Description:
    229 
    230   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
    231 
    232 Arguments:
    233 
    234   String      - String to test
    235 
    236   In          - Open file to move pointer within
    237 
    238 Returns:
    239 
    240   -1          - End of file reached
    241    0          - Not a comment
    242    1          - Comment bypassed
    243 
    244 --*/
    245 {
    246   CHAR8 CharBuffer;
    247 
    248   CharBuffer = 0;
    249   if ((String[0] == '/') && (String[1] == '/')) {
    250     while (CharBuffer != '\n') {
    251       fscanf (In, "%c", &CharBuffer);
    252       if (feof (In)) {
    253         return -1;
    254       }
    255     }
    256   } else {
    257     return 0;
    258   }
    259 
    260   return 1;
    261 }
    262 
    263 static
    264 void
    265 BreakString (
    266   IN CONST CHAR8 *Source,
    267   OUT CHAR8      *Destination,
    268   IN INTN        Direction
    269   )
    270 /*++
    271 
    272 Routine Description:
    273 
    274   Takes an input string and returns either the part before the =, or the part after the =, depending on direction
    275 
    276 Arguments:
    277 
    278   Source      - String to break
    279 
    280   Destination - Buffer to place new string in
    281 
    282   Direction   - 0 to return all of source string before =
    283                 1 to return all of source string after =
    284 
    285 Returns:
    286 
    287   None
    288 
    289 --*/
    290 {
    291   UINTN Index;
    292   UINTN Index2;
    293 
    294   Index   = 0;
    295   Index2  = 0;
    296 
    297   if (strchr (Source, '=') == NULL) {
    298     strcpy (Destination, Source);
    299 
    300     return ;
    301   }
    302 
    303   if (Direction == 0) {
    304     //
    305     // return part of string before =
    306     //
    307     while (Source[Index] != '=') {
    308       Destination[Index] = Source[Index++];
    309     }
    310 
    311     Destination[Index] = 0;
    312   } else {
    313     //
    314     // return part of string after =
    315     //
    316     strcpy (Destination, strchr (Source, '=') + 1);
    317   }
    318 }
    319 
    320 static
    321 INT32
    322 GetNextLine (
    323   OUT CHAR8       *Destination,
    324   IN FILE         *Package,
    325   IN OUT UINT32   *LineNumber
    326   )
    327 /*++
    328 
    329 Routine Description:
    330 
    331   Gets the next non-commented line from the file
    332 
    333 Arguments:
    334 
    335   Destination - Where to put string
    336 
    337   Package     - Package to get string from
    338 
    339   LineNumber  - The actual line number.
    340 
    341 Returns:
    342 
    343   -1          - End of file reached
    344    0          - Success
    345 
    346 --*/
    347 {
    348   CHAR8 String[_MAX_PATH];
    349   fscanf (Package, "%s", &String);
    350   if (feof (Package)) {
    351     return -1;
    352   }
    353 
    354   while (TestComment (String, Package) == 1) {
    355     fscanf (Package, "%s", &String);
    356     if (feof (Package)) {
    357       return -1;
    358     }
    359   }
    360 
    361   strcpy (Destination, String);
    362   return 0;
    363 }
    364 
    365 static
    366 VOID
    367 CheckSlash (
    368   IN OUT CHAR8  *String,
    369   IN FILE       *In,
    370   IN OUT UINT32 *LineNumber
    371   )
    372 /*++
    373 
    374 Routine Description:
    375 
    376   Checks to see if string is line continuation character, if so goes to next valid line
    377 
    378 Arguments:
    379 
    380   String      - String to test
    381 
    382   In          - Open file to move pointer within
    383 
    384   LineNumber  - The line number.
    385 
    386 Returns:
    387 
    388   None
    389 
    390 --*/
    391 {
    392   CHAR8 ByteBuffer;
    393   ByteBuffer = 0;
    394 
    395   switch (String[0]) {
    396 
    397   case '\\':
    398     while (String[0] == '\\') {
    399       while (ByteBuffer != '\n') {
    400         fscanf (In, "%c", &ByteBuffer);
    401       }
    402       (*LineNumber)++;
    403       if (GetNextLine (String, In, LineNumber) == -1) {
    404         return ;
    405       }
    406     }
    407     break;
    408 
    409   case '\n':
    410     (*LineNumber)++;
    411     while (String[0] == '\n') {
    412       if (GetNextLine (String, In, LineNumber) == -1) {
    413         return ;
    414       }
    415     }
    416     break;
    417 
    418   default:
    419     break;
    420 
    421   }
    422 
    423 }
    424 
    425 static
    426 INT32
    427 FindSectionInPackage (
    428   IN CHAR8        *BuildDirectory,
    429   IN FILE         *OverridePackage,
    430   IN OUT UINT32   *LineNumber
    431   )
    432 /*++
    433 
    434 Routine Description:
    435 
    436   Finds the matching section within the package
    437 
    438 Arguments:
    439 
    440   BuildDirectory  - name of section to find
    441 
    442   OverridePackage - Package file to search within
    443 
    444   LineNumber      - The line number.
    445 
    446 Returns:
    447 
    448   -1          - End of file reached
    449    0          - Success
    450 
    451 --*/
    452 {
    453   CHAR8 String[_MAX_PATH];
    454   CHAR8 NewString[_MAX_PATH];
    455   String[0] = 0;
    456 
    457   while (strcmp (BuildDirectory, String) != 0) {
    458     if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) {
    459       return -1;
    460     }
    461 
    462     if (NewString[0] == '[') {
    463       if (NewString[strlen (NewString) - 1] != ']') {
    464         //
    465         // have to construct string.
    466         //
    467         strcpy (String, NewString + 1);
    468 
    469         while (1) {
    470           fscanf (OverridePackage, "%s", &NewString);
    471           if (feof (OverridePackage)) {
    472             return -1;
    473           }
    474 
    475           if (NewString[0] != ']') {
    476             if (strlen (String) != 0) {
    477               strcat (String, " ");
    478             }
    479 
    480             strcat (String, NewString);
    481             if (String[strlen (String) - 1] == ']') {
    482               String[strlen (String) - 1] = 0;
    483               break;
    484             }
    485           } else {
    486             break;
    487           }
    488         }
    489       } else {
    490         NewString[strlen (NewString) - 1] = 0;
    491         strcpy (String, NewString + 1);
    492       }
    493     }
    494   }
    495 
    496   return 0;
    497 }
    498 
    499 static
    500 EFI_STATUS
    501 GenSimpleGuidSection (
    502   IN OUT UINT8  *FileBuffer,
    503   IN OUT UINT32 *BufferSize,
    504   IN UINT32     DataSize,
    505   IN EFI_GUID   SignGuid,
    506   IN UINT16     GuidedSectionAttributes
    507   )
    508 /*++
    509 
    510 Routine Description:
    511 
    512   add GUIDed section header for the data buffer.
    513   data stays in same location (overwrites source data).
    514 
    515 Arguments:
    516 
    517   FileBuffer  - Buffer containing data to sign
    518 
    519   BufferSize  - On input, the size of FileBuffer. On output, the size of
    520                 actual section data (including added section header).
    521 
    522   DataSize    - Length of data to Sign
    523 
    524   SignGuid    - Guid to be add.
    525 
    526   GuidedSectionAttributes - The section attribute.
    527 
    528 Returns:
    529 
    530   EFI_SUCCESS           - Successful
    531   EFI_OUT_OF_RESOURCES  - Not enough resource.
    532 
    533 --*/
    534 {
    535   UINT32                    TotalSize;
    536 
    537   EFI_GUID_DEFINED_SECTION  GuidSectionHeader;
    538   UINT8                     *SwapBuffer;
    539 
    540   SwapBuffer = NULL;
    541 
    542   if (DataSize == 0) {
    543     *BufferSize = 0;
    544 
    545     return EFI_SUCCESS;
    546   }
    547 
    548   TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION);
    549   GuidSectionHeader.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;
    550   GuidSectionHeader.CommonHeader.Size[0]  = (UINT8) (TotalSize & 0xff);
    551   GuidSectionHeader.CommonHeader.Size[1]  = (UINT8) ((TotalSize & 0xff00) >> 8);
    552   GuidSectionHeader.CommonHeader.Size[2]  = (UINT8) ((TotalSize & 0xff0000) >> 16);
    553   memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID));
    554   GuidSectionHeader.Attributes  = GuidedSectionAttributes;
    555   GuidSectionHeader.DataOffset  = sizeof (EFI_GUID_DEFINED_SECTION);
    556 
    557   SwapBuffer                    = (UINT8 *) malloc (DataSize);
    558   if (SwapBuffer == NULL) {
    559     return EFI_OUT_OF_RESOURCES;
    560   }
    561 
    562   memcpy (SwapBuffer, FileBuffer, DataSize);
    563   memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION));
    564   memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize);
    565 
    566   //
    567   // Make sure section ends on a DWORD boundary
    568   //
    569   while ((TotalSize & 0x03) != 0) {
    570     FileBuffer[TotalSize] = 0;
    571     TotalSize++;
    572   }
    573 
    574   *BufferSize = TotalSize;
    575 
    576   if (SwapBuffer != NULL) {
    577     free (SwapBuffer);
    578   }
    579 
    580   return EFI_SUCCESS;
    581 }
    582 
    583 static
    584 EFI_STATUS
    585 CompressSection (
    586   UINT8  *FileBuffer,
    587   UINT32 *BufferSize,
    588   UINT32 DataSize,
    589   CHAR8  *Type
    590   )
    591 /*++
    592 
    593 Routine Description:
    594 
    595   Compress the data and add section header for the compressed data.
    596   Compressed data (with section header) stays in same location as the source
    597   (overwrites source data).
    598 
    599 Arguments:
    600 
    601   FileBuffer  - Buffer containing data to Compress
    602 
    603   BufferSize  - On input, the size of FileBuffer. On output, the size of
    604                 actual compressed data (including added section header).
    605                 When buffer is too small, this value indicates the size needed.
    606 
    607   DataSize    - The size of data to compress
    608 
    609   Type        - The compression type (not used currently).
    610                 Assume EFI_HEAVY_COMPRESSION.
    611 
    612 Returns:
    613 
    614   EFI_BUFFER_TOO_SMALL - Buffer size is too small.
    615   EFI_UNSUPPORTED      - Compress type can not be supported.
    616   EFI_SUCCESS          - Successful
    617   EFI_OUT_OF_RESOURCES - Not enough resource.
    618 
    619 --*/
    620 {
    621   EFI_STATUS              Status;
    622   UINT8                   *CompData;
    623   UINT32                  CompSize;
    624   UINT32                  TotalSize;
    625   EFI_COMPRESSION_SECTION CompressionSet;
    626   UINT8                   CompressionType;
    627   COMPRESS_FUNCTION       CompressFunction;
    628 
    629   Status            = EFI_SUCCESS;
    630   CompData          = NULL;
    631   CompSize          = 0;
    632   TotalSize         = 0;
    633   CompressFunction  = NULL;
    634 
    635   //
    636   // Get the compress type
    637   //
    638   if (_strcmpi (Type, "Dummy") == 0) {
    639     //
    640     // Added "Dummy" to keep backward compatibility.
    641     //
    642     CompressionType   = EFI_STANDARD_COMPRESSION;
    643     CompressFunction  = (COMPRESS_FUNCTION) TianoCompress;
    644 
    645   } else if (_strcmpi (Type, "LZH") == 0) {
    646     //
    647     // EFI stardard compression (LZH)
    648     //
    649     CompressionType   = EFI_STANDARD_COMPRESSION;
    650     CompressFunction  = (COMPRESS_FUNCTION) TianoCompress;
    651 
    652   } else {
    653     //
    654     // Customized compression
    655     //
    656     Status = SetCustomizedCompressionType (Type);
    657     if (EFI_ERROR (Status)) {
    658       return Status;
    659     }
    660 
    661     CompressionType   = EFI_CUSTOMIZED_COMPRESSION;
    662     CompressFunction  = (COMPRESS_FUNCTION) CustomizedCompress;
    663   }
    664   //
    665   // Compress the raw data
    666   //
    667   Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
    668   if (Status == EFI_BUFFER_TOO_SMALL) {
    669     CompData = malloc (CompSize);
    670     if (!CompData) {
    671       return EFI_OUT_OF_RESOURCES;
    672     }
    673 
    674     Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
    675   }
    676 
    677   if (EFI_ERROR (Status)) {
    678     if (CompData != NULL) {
    679       free (CompData);
    680     }
    681 
    682     return Status;
    683   }
    684 
    685   TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION);
    686 
    687   //
    688   // Buffer too small?
    689   //
    690   if (TotalSize > *BufferSize) {
    691     *BufferSize = TotalSize;
    692     if (CompData != NULL) {
    693       free (CompData);
    694     }
    695 
    696     return EFI_BUFFER_TOO_SMALL;
    697   }
    698   //
    699   // Add the section header for the compressed data
    700   //
    701   CompressionSet.CommonHeader.Type    = EFI_SECTION_COMPRESSION;
    702   CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff);
    703   CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8);
    704   CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16);
    705   CompressionSet.CompressionType      = CompressionType;
    706   CompressionSet.UncompressedLength   = DataSize;
    707 
    708   //
    709   // Copy header and data to the buffer
    710   //
    711   memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION));
    712   memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize);
    713 
    714   //
    715   // Make sure section ends on a DWORD boundary
    716   //
    717   while ((TotalSize & 0x03) != 0) {
    718     FileBuffer[TotalSize] = 0;
    719     TotalSize++;
    720   }
    721 
    722   *BufferSize = TotalSize;
    723 
    724   if (CompData != NULL) {
    725     free (CompData);
    726   }
    727 
    728   return EFI_SUCCESS;
    729 }
    730 
    731 static
    732 void
    733 StripParens (
    734   IN OUT CHAR8 *String
    735   )
    736 /*++
    737 
    738 Routine Description:
    739 
    740   Removes Parenthesis from around a string
    741 
    742 Arguments:
    743 
    744  String    - String to remove parens from
    745 
    746 Returns:
    747 
    748   None
    749 
    750 --*/
    751 {
    752   INT32 Index;
    753 
    754   if (String[0] != '(') {
    755     return ;
    756   }
    757 
    758   for (Index = 1; String[Index] != ')'; Index++) {
    759     String[Index - 1] = String[Index];
    760     if (String[Index] == 0) {
    761       return ;
    762     }
    763   }
    764 
    765   String[Index - 1] = 0;
    766 
    767   return ;
    768 }
    769 
    770 static
    771 void
    772 StripEqualMark (
    773   IN OUT CHAR8 *String
    774   )
    775 /*++
    776 
    777 Routine Description:
    778 
    779   Removes Equal Mark from around a string
    780 
    781 Arguments:
    782 
    783  String    - String to remove equal mark from
    784 
    785 Returns:
    786 
    787   None
    788 
    789 --*/
    790 {
    791   INT32 Index;
    792 
    793   if (String[0] != '=' && String[strlen (String) - 1] != '=') {
    794     return ;
    795   }
    796 
    797   if (String[0] == '=') {
    798 
    799     for (Index = 1; String[Index] != 0; Index++) {
    800       String[Index - 1] = String[Index];
    801     }
    802 
    803     String[Index - 1] = 0;
    804   }
    805 
    806   if (String[strlen (String) - 1] == '=') {
    807     String[strlen (String) - 1] = 0;
    808   }
    809 
    810   return ;
    811 }
    812 
    813 static
    814 void
    815 SplitAttributesField (
    816   IN CHAR8       *Buffer,
    817   IN CHAR8       *AttributesArray[],
    818   IN OUT UINT32  *NumberOfAttributes
    819   )
    820 /*
    821   NumberOfAttributes: on input, it specifies the current number of attributes
    822                       stored in AttributeArray.
    823                       on output, it is updated to the latest number of attributes
    824                       stored in AttributesArray.
    825 */
    826 {
    827   UINT32  Index;
    828   UINT32  Index2;
    829   UINT32  z;
    830   CHAR8   *CharBuffer;
    831 
    832   CharBuffer  = NULL;
    833   CharBuffer  = (CHAR8 *) malloc (_MAX_PATH);
    834   ZeroMem (CharBuffer, _MAX_PATH);
    835 
    836   for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) {
    837 
    838     if (Buffer[Index] != '|') {
    839       CharBuffer[z] = Buffer[Index];
    840       z++;
    841     } else {
    842 
    843       CharBuffer[z] = 0;
    844       AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
    845       Index2++;
    846 
    847       //
    848       // allocate new char buffer for the next attributes string
    849       //
    850       CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
    851       ZeroMem (CharBuffer, _MAX_PATH);
    852       z = 0;
    853     }
    854   }
    855 
    856   CharBuffer[z] = 0;
    857   //
    858   // record the last attributes string in the Buffer
    859   //
    860   AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
    861   Index2++;
    862 
    863   *NumberOfAttributes += Index2;
    864 
    865   return ;
    866 }
    867 
    868 static
    869 INT32
    870 GetToolArguments (
    871   CHAR8       *ToolArgumentsArray[],
    872   FILE        *Package,
    873   CHAR8       **PtrInputFileName,
    874   CHAR8       **PtrOutputFileName,
    875   EFI_GUID    *Guid,
    876   UINT16      *GuidedSectionAttributes
    877   )
    878 {
    879   CHAR8       Buffer[_MAX_PATH];
    880   BOOLEAN     ArgumentsFlag;
    881   BOOLEAN     InputFlag;
    882   BOOLEAN     OutputFlag;
    883   BOOLEAN     GuidFlag;
    884   BOOLEAN     AttributesFlag;
    885   UINT32      argc;
    886   UINT32      Index2;
    887   UINT32      z;
    888   CHAR8       *CharBuffer;
    889   INT32       ReturnValue;
    890   EFI_STATUS  Status;
    891 
    892   CHAR8       *AttributesArray[MAX_ARRAY_SIZE];
    893   UINT32      NumberOfAttributes;
    894   CHAR8       *InputFileName;
    895   CHAR8       *OutputFileName;
    896   UINT32      LineNumber;
    897   Buffer[_MAX_PATH];
    898 
    899   ArgumentsFlag   = FALSE;
    900   InputFlag       = FALSE;
    901   OutputFlag      = FALSE;
    902   GuidFlag        = FALSE;
    903   AttributesFlag  = FALSE;
    904   //
    905   // Start at 1, since ToolArgumentsArray[0]
    906   // is the program name.
    907   //
    908   argc            = 1;
    909   Index2              = 0;
    910 
    911   z                   = 0;
    912   ReturnValue         = 0;
    913   NumberOfAttributes  = 0;
    914   InputFileName       = NULL;
    915   OutputFileName      = NULL;
    916 
    917   ZeroMem (Buffer, _MAX_PATH);
    918   ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
    919   LineNumber = 0;
    920   while (Buffer[0] != ')') {
    921 
    922     if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
    923       CheckSlash (Buffer, Package, &LineNumber);
    924       StripEqualMark (Buffer);
    925     } else {
    926       Error (NULL, 0, 0, "failed to get next line from package file", NULL);
    927       return -1;
    928     }
    929 
    930     if (Buffer[0] == ')') {
    931       break;
    932     } else if (_strcmpi (Buffer, "ARGS") == 0) {
    933 
    934       ArgumentsFlag   = TRUE;
    935       AttributesFlag  = FALSE;
    936       continue;
    937 
    938     } else if (_strcmpi (Buffer, "INPUT") == 0) {
    939 
    940       InputFlag       = TRUE;
    941       ArgumentsFlag   = FALSE;
    942       AttributesFlag  = FALSE;
    943       continue;
    944 
    945     } else if (_strcmpi (Buffer, "OUTPUT") == 0) {
    946 
    947       OutputFlag      = TRUE;
    948       ArgumentsFlag   = FALSE;
    949       AttributesFlag  = FALSE;
    950       continue;
    951 
    952     } else if (_strcmpi (Buffer, "GUID") == 0) {
    953 
    954       GuidFlag        = TRUE;
    955       ArgumentsFlag   = FALSE;
    956       AttributesFlag  = FALSE;
    957       //
    958       // fetch the GUID for the section
    959       //
    960       continue;
    961 
    962     } else if (_strcmpi (Buffer, "ATTRIBUTES") == 0) {
    963 
    964       AttributesFlag  = TRUE;
    965       ArgumentsFlag   = FALSE;
    966       //
    967       // fetch the GUIDed Section's Attributes
    968       //
    969       continue;
    970 
    971     } else if (_strcmpi (Buffer, "") == 0) {
    972       continue;
    973     }
    974     //
    975     // get all command arguments into ToolArgumentsArray
    976     //
    977     if (ArgumentsFlag) {
    978 
    979       StripEqualMark (Buffer);
    980 
    981       CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
    982       if (CharBuffer == NULL) {
    983         goto ErrorExit;
    984       }
    985 
    986       ZeroMem (CharBuffer, sizeof (_MAX_PATH));
    987 
    988       ToolArgumentsArray[argc] = CharBuffer;
    989 
    990       strcpy (ToolArgumentsArray[argc], Buffer);
    991 
    992       argc += 1;
    993       ToolArgumentsArray[argc] = NULL;
    994       continue;
    995     }
    996 
    997     if (InputFlag) {
    998 
    999       StripEqualMark (Buffer);
   1000 
   1001       InputFileName = (CHAR8 *) malloc (_MAX_PATH);
   1002       if (InputFileName == NULL) {
   1003         goto ErrorExit;
   1004       }
   1005 
   1006       ZeroMem (InputFileName, sizeof (_MAX_PATH));
   1007 
   1008       strcpy (InputFileName, Buffer);
   1009 
   1010       InputFlag = FALSE;
   1011       continue;
   1012     }
   1013 
   1014     if (OutputFlag) {
   1015 
   1016       StripEqualMark (Buffer);
   1017 
   1018       OutputFileName = (CHAR8 *) malloc (_MAX_PATH);
   1019       if (OutputFileName == NULL) {
   1020         goto ErrorExit;
   1021       }
   1022 
   1023       ZeroMem (OutputFileName, sizeof (_MAX_PATH));
   1024 
   1025       strcpy (OutputFileName, Buffer);
   1026 
   1027       OutputFlag = FALSE;
   1028       continue;
   1029     }
   1030 
   1031     if (GuidFlag) {
   1032 
   1033       StripEqualMark (Buffer);
   1034 
   1035       Status = StringToGuid (Buffer, Guid);
   1036       if (EFI_ERROR (Status)) {
   1037         ReturnValue = -1;
   1038         goto ErrorExit;
   1039       }
   1040 
   1041       GuidFlag = FALSE;
   1042     }
   1043 
   1044     if (AttributesFlag) {
   1045 
   1046       StripEqualMark (Buffer);
   1047 
   1048       //
   1049       // there might be no space between each attribute in the statement,
   1050       // split them aside and return each attribute string
   1051       // in the AttributesArray
   1052       //
   1053       SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes);
   1054     }
   1055   }
   1056   //
   1057   // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j);
   1058   // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1);
   1059   //
   1060   for (z = 0; z < NumberOfAttributes; z++) {
   1061     if (_strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) {
   1062       *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
   1063     } else if (_strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) {
   1064       *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
   1065     }
   1066   }
   1067 
   1068 ErrorExit:
   1069 
   1070   for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) {
   1071     if (AttributesArray[Index2] == NULL) {
   1072       break;
   1073     }
   1074 
   1075     free (AttributesArray[Index2]);
   1076   }
   1077 
   1078   *PtrInputFileName   = InputFileName;
   1079   *PtrOutputFileName  = OutputFileName;
   1080 
   1081   return ReturnValue;
   1082 }
   1083 
   1084 static
   1085 INT32
   1086 ProcessScript (
   1087   IN OUT UINT8   *FileBuffer,
   1088   IN FILE        *Package,
   1089   IN CHAR8       *BuildDirectory,
   1090   IN BOOLEAN     ForceUncompress
   1091   )
   1092 /*++
   1093 
   1094 Routine Description:
   1095 
   1096   Signs the section, data stays in same location
   1097 
   1098 Arguments:
   1099 
   1100   FileBuffer  - Data Buffer
   1101 
   1102   Package     - Points to curly brace in Image Script
   1103 
   1104   BuildDirectory     - Name of the source directory parameter
   1105 
   1106   ForceUncompress   - Whether to force uncompress.
   1107 
   1108 Returns:
   1109 
   1110   Number of bytes added to file buffer
   1111   -1 on error
   1112 
   1113 --*/
   1114 {
   1115   EFI_STATUS  Status;
   1116   UINT32      Size;
   1117   UINT32      OldSize;
   1118   UINT32      Adjust;
   1119   UINT16      TeStrippedSize;
   1120   CHAR8       Buffer[_MAX_PATH];
   1121   CHAR8       Type[_MAX_PATH];
   1122   CHAR8       FileName[_MAX_PATH];
   1123   INT32       Index3;
   1124   INT32       Index2;
   1125   UINT32      ReturnValue;
   1126   UINT8       ByteBuffer;
   1127   FILE        *InFile;
   1128   UINT32      SourceDataSize;
   1129   CHAR8       *ToolArgumentsArray[MAX_ARRAY_SIZE];
   1130   CHAR8       *OutputFileName;
   1131   CHAR8       *InputFileName;
   1132   CHAR8       ToolName[_MAX_PATH];
   1133   FILE        *OutputFile;
   1134   FILE        *InputFile;
   1135   UINT8       Temp;
   1136   int         returnint;
   1137   UINT32      LineNumber;
   1138   BOOLEAN     IsError;
   1139   EFI_GUID    SignGuid;
   1140   UINT16      GuidedSectionAttributes;
   1141   UINT8       *TargetFileBuffer;
   1142 
   1143   OutputFileName          = NULL;
   1144   InputFileName           = NULL;
   1145   OutputFile              = NULL;
   1146   InputFile               = NULL;
   1147   IsError                 = FALSE;
   1148   GuidedSectionAttributes = 0;
   1149   TargetFileBuffer        = NULL;
   1150 
   1151   Size                    = 0;
   1152   LineNumber              = 0;
   1153   Buffer[0]               = 0;
   1154   for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) {
   1155     ToolArgumentsArray[Index3] = NULL;
   1156   }
   1157 
   1158   while (Buffer[0] != '}') {
   1159     if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
   1160       CheckSlash (Buffer, Package, &LineNumber);
   1161     } else {
   1162       printf ("ERROR in IMAGE SCRIPT!\n");
   1163       IsError = TRUE;
   1164       goto Done;
   1165     }
   1166 
   1167     if (_strcmpi (Buffer, "Compress") == 0) {
   1168       //
   1169       // Handle compress
   1170       //
   1171       //
   1172       // read compression type
   1173       //
   1174       if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
   1175         CheckSlash (Buffer, Package, &LineNumber);
   1176       }
   1177 
   1178       StripParens (Buffer);
   1179       strcpy (Type, Buffer);
   1180       //
   1181       // build buffer
   1182       //
   1183       while (Buffer[0] != '{') {
   1184         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
   1185           CheckSlash (Buffer, Package, &LineNumber);
   1186         }
   1187       }
   1188 
   1189       ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress);
   1190       if (ReturnValue == -1) {
   1191         IsError = TRUE;
   1192         goto Done;
   1193       }
   1194       //
   1195       // Call compress routine on buffer.
   1196       // Occasionally, compressed data + section header would
   1197       // be largere than the source and EFI_BUFFER_TOO_SMALL is
   1198       // returned from CompressSection()
   1199       //
   1200       SourceDataSize = ReturnValue;
   1201 
   1202       if (!ForceUncompress) {
   1203 
   1204         Status = CompressSection (
   1205                   &FileBuffer[Size],
   1206                   &ReturnValue,
   1207                   SourceDataSize,
   1208                   Type
   1209                   );
   1210 
   1211         if (Status == EFI_BUFFER_TOO_SMALL) {
   1212           Status = CompressSection (
   1213                     &FileBuffer[Size],
   1214                     &ReturnValue,
   1215                     SourceDataSize,
   1216                     Type
   1217                     );
   1218         }
   1219 
   1220         if (EFI_ERROR (Status)) {
   1221           IsError = TRUE;
   1222           goto Done;
   1223         }
   1224       }
   1225 
   1226       Size += ReturnValue;
   1227 
   1228     } else if (_strcmpi (Buffer, "Tool") == 0) {
   1229 
   1230       ZeroMem (ToolName, _MAX_PATH);
   1231       ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
   1232       ZeroMem (&SignGuid, sizeof (EFI_GUID));
   1233 
   1234       //
   1235       // handle signing Tool
   1236       //
   1237       while (Buffer[0] != '(') {
   1238         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
   1239           CheckSlash (Buffer, Package, &LineNumber);
   1240         }
   1241       }
   1242 
   1243       if (_strcmpi (Buffer, "(") == 0) {
   1244         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
   1245           CheckSlash (Buffer, Package, &LineNumber);
   1246         }
   1247       }
   1248 
   1249       StripParens (Buffer);
   1250       strcpy (ToolName, Buffer);
   1251       ToolArgumentsArray[0] = ToolName;
   1252 
   1253       //
   1254       // read ARGS
   1255       //
   1256       if (GetToolArguments (
   1257             ToolArgumentsArray,
   1258             Package,
   1259             &InputFileName,
   1260             &OutputFileName,
   1261             &SignGuid,
   1262             &GuidedSectionAttributes
   1263             ) == -1) {
   1264         IsError = TRUE;
   1265         goto Done;
   1266       }
   1267       //
   1268       // if the tool need input file,
   1269       // dump the file buffer to the specified input file.
   1270       //
   1271       if (InputFileName != NULL) {
   1272         InputFile = fopen (InputFileName, "wb");
   1273         if (InputFile == NULL) {
   1274           Error (NULL, 0, 0, InputFileName, "failed to open output file for writing");
   1275           IsError = TRUE;
   1276           goto Done;
   1277         }
   1278 
   1279         fwrite (FileBuffer, sizeof (UINT8), Size, InputFile);
   1280         fclose (InputFile);
   1281         InputFile = NULL;
   1282         free (InputFileName);
   1283         InputFileName = NULL;
   1284       }
   1285       //
   1286       // dispatch signing tool
   1287       //
   1288       returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray);
   1289       if (returnint != 0) {
   1290         Error (NULL, 0, 0, ToolName, "external tool failed");
   1291         IsError = TRUE;
   1292         goto Done;
   1293       }
   1294       //
   1295       // if the tool has output file,
   1296       // dump the output file to the file buffer
   1297       //
   1298       if (OutputFileName != NULL) {
   1299 
   1300         OutputFile = fopen (OutputFileName, "rb");
   1301         if (OutputFile == NULL) {
   1302           Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");
   1303           IsError = TRUE;
   1304           goto Done;
   1305         }
   1306 
   1307         TargetFileBuffer  = &FileBuffer[Size];
   1308         SourceDataSize    = Size;
   1309 
   1310         fread (&Temp, sizeof (UINT8), 1, OutputFile);
   1311         while (!feof (OutputFile)) {
   1312           FileBuffer[Size++] = Temp;
   1313           fread (&Temp, sizeof (UINT8), 1, OutputFile);
   1314         }
   1315 
   1316         while ((Size & 0x03) != 0) {
   1317           FileBuffer[Size] = 0;
   1318           Size++;
   1319         }
   1320 
   1321         SourceDataSize = Size - SourceDataSize;
   1322 
   1323         fclose (OutputFile);
   1324         OutputFile = NULL;
   1325         free (OutputFileName);
   1326         OutputFileName = NULL;
   1327 
   1328         if (CompareGuid (&SignGuid, &mZeroGuid) != 0) {
   1329           ReturnValue = SourceDataSize;
   1330           Status = GenSimpleGuidSection (
   1331                     TargetFileBuffer,
   1332                     &ReturnValue,
   1333                     SourceDataSize,
   1334                     SignGuid,
   1335                     GuidedSectionAttributes
   1336                     );
   1337           if (EFI_ERROR (Status)) {
   1338             IsError = TRUE;
   1339             goto Done;
   1340           }
   1341 
   1342           Size = ReturnValue;
   1343         }
   1344       }
   1345 
   1346     } else if (Buffer[0] != '}') {
   1347       //
   1348       // if we are here, we should see either a file name,
   1349       // or a }.
   1350       //
   1351       Index3      = 0;
   1352       FileName[0] = 0;
   1353       //
   1354       // Prepend the build directory to the file name if the
   1355       // file name does not already contain a full path.
   1356       //
   1357       if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {
   1358         sprintf (FileName, "%s\\", BuildDirectory);
   1359       }
   1360 
   1361       while (Buffer[Index3] != '\n') {
   1362         if (Buffer[Index3] == 0) {
   1363           break;
   1364         } else {
   1365           Index2              = strlen (FileName);
   1366           FileName[Index2++]  = Buffer[Index3++];
   1367           FileName[Index2]    = 0;
   1368         }
   1369       }
   1370 
   1371       InFile = fopen (FileName, "rb");
   1372       if (InFile == NULL) {
   1373         Error (NULL, 0, 0, FileName, "failed to open file for reading");
   1374         IsError = TRUE;
   1375         goto Done;
   1376       }
   1377 
   1378       OldSize = Size;
   1379       fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
   1380       while (!feof (InFile)) {
   1381         FileBuffer[Size++] = ByteBuffer;
   1382         fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
   1383       }
   1384 
   1385       fclose (InFile);
   1386       InFile = NULL;
   1387 
   1388       //
   1389       // Adjust the TE Section for IPF so that the function entries are 16-byte aligned.
   1390       //
   1391       if (Size - OldSize >= sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER) &&
   1392           ((EFI_COMMON_SECTION_HEADER *) &FileBuffer[OldSize])->Type == EFI_SECTION_TE        &&
   1393           ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->Machine == EFI_IMAGE_MACHINE_IA64) {
   1394         TeStrippedSize = ((EFI_TE_IMAGE_HEADER *) &FileBuffer[OldSize + 4])->StrippedSize;
   1395         Adjust = TeStrippedSize - (OldSize + sizeof (EFI_COMMON_SECTION_HEADER) + sizeof (EFI_TE_IMAGE_HEADER));
   1396         Adjust &= 15;
   1397         if (Adjust > 0) {
   1398           memmove (&FileBuffer[OldSize + Adjust], &FileBuffer[OldSize], Size - OldSize);
   1399           //
   1400           // Pad with RAW Section type
   1401           //
   1402           *(UINT32 *)&FileBuffer[OldSize] = 0x19000000 | Adjust;
   1403           Size += Adjust;
   1404           //
   1405           // Make sure the Data alignment in FFS header is no less than 1 (16-byte aligned)
   1406           //
   1407           MinFfsDataAlignOverride = 1;
   1408         }
   1409       }
   1410 
   1411       //
   1412       // Make sure section ends on a DWORD boundary
   1413       //
   1414       while ((Size & 0x03) != 0) {
   1415         FileBuffer[Size] = 0;
   1416         Size++;
   1417       }
   1418 
   1419     }
   1420   }
   1421 
   1422 Done:
   1423   for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) {
   1424     if (ToolArgumentsArray[Index3] == NULL) {
   1425       break;
   1426     }
   1427 
   1428     free (ToolArgumentsArray[Index3]);
   1429   }
   1430 
   1431   if (IsError) {
   1432     return -1;
   1433   }
   1434 
   1435   return Size;
   1436 
   1437 }
   1438 
   1439 static
   1440 UINT8
   1441 StringToType (
   1442   IN CHAR8 *String
   1443   )
   1444 /*++
   1445 
   1446 Routine Description:
   1447 
   1448   Converts File Type String to value.  EFI_FV_FILETYPE_ALL indicates that an
   1449   unrecognized file type was specified.
   1450 
   1451 Arguments:
   1452 
   1453   String    - File type string
   1454 
   1455 Returns:
   1456 
   1457   File Type Value
   1458 
   1459 --*/
   1460 {
   1461   if (_strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) {
   1462     return EFI_FV_FILETYPE_RAW;
   1463   }
   1464 
   1465   if (_strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) {
   1466     return EFI_FV_FILETYPE_FREEFORM;
   1467   }
   1468 
   1469   if (_strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) {
   1470     return EFI_FV_FILETYPE_SECURITY_CORE;
   1471   }
   1472 
   1473   if (_strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) {
   1474     return EFI_FV_FILETYPE_PEI_CORE;
   1475   }
   1476 
   1477   if (_strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) {
   1478     return EFI_FV_FILETYPE_DXE_CORE;
   1479   }
   1480 
   1481   if (_strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) {
   1482     return EFI_FV_FILETYPE_PEIM;
   1483   }
   1484 
   1485   if (_strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) {
   1486     return EFI_FV_FILETYPE_DRIVER;
   1487   }
   1488 
   1489   if (_strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) {
   1490     return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER;
   1491   }
   1492 
   1493   if (_strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) {
   1494     return EFI_FV_FILETYPE_APPLICATION;
   1495   }
   1496 
   1497   if (_strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) {
   1498     return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;
   1499   }
   1500 
   1501   return EFI_FV_FILETYPE_ALL;
   1502 }
   1503 
   1504 static
   1505 UINT32
   1506 AdjustFileSize (
   1507   IN UINT8  *FileBuffer,
   1508   IN UINT32 FileSize
   1509   )
   1510 /*++
   1511 
   1512 Routine Description:
   1513   Adjusts file size to insure sectioned file is exactly the right length such
   1514   that it ends on exactly the last byte of the last section.  ProcessScript()
   1515   may have padded beyond the end of the last section out to a 4 byte boundary.
   1516   This padding is stripped.
   1517 
   1518 Arguments:
   1519   FileBuffer  - Data Buffer - contains a section stream
   1520   FileSize    - Size of FileBuffer as returned from ProcessScript()
   1521 
   1522 Returns:
   1523   Corrected size of file.
   1524 
   1525 --*/
   1526 {
   1527   UINT32                    TotalLength;
   1528   UINT32                    CurrentLength;
   1529   UINT32                    SectionLength;
   1530   UINT32                    SectionStreamLength;
   1531   EFI_COMMON_SECTION_HEADER *SectionHeader;
   1532   EFI_COMMON_SECTION_HEADER *NextSectionHeader;
   1533 
   1534   TotalLength         = 0;
   1535   CurrentLength       = 0;
   1536   SectionStreamLength = FileSize;
   1537 
   1538   SectionHeader       = (EFI_COMMON_SECTION_HEADER *) FileBuffer;
   1539 
   1540   while (TotalLength < SectionStreamLength) {
   1541     SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff;
   1542     TotalLength += SectionLength;
   1543 
   1544     if (TotalLength == SectionStreamLength) {
   1545       return TotalLength;
   1546     }
   1547     //
   1548     // Move to the next byte following the section...
   1549     //
   1550     SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
   1551     CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer;
   1552 
   1553     //
   1554     // Figure out where the next section begins
   1555     //
   1556     NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3);
   1557     NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3);
   1558     TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
   1559     SectionHeader = NextSectionHeader;
   1560   }
   1561 
   1562   return CurrentLength;
   1563 }
   1564 
   1565 static
   1566 INT32
   1567 MainEntry (
   1568   INT32     argc,
   1569   CHAR8     *argv[],
   1570   BOOLEAN   ForceUncompress
   1571   )
   1572 /*++
   1573 
   1574 Routine Description:
   1575 
   1576   MainEntry function.
   1577 
   1578 Arguments:
   1579 
   1580   argc            - Number of command line parameters.
   1581   argv            - Array of pointers to command line parameter strings.
   1582   ForceUncompress - If TRUE, force to do not compress the sections even if compression
   1583                     is specified in the script. Otherwise, FALSE.
   1584 
   1585 Returns:
   1586   STATUS_SUCCESS  - Function exits successfully.
   1587   STATUS_ERROR    - Some error occurred during execution.
   1588 
   1589 --*/
   1590 {
   1591   FILE                    *PrimaryPackage;
   1592   FILE                    *OverridePackage;
   1593   FILE                    *Out;
   1594   CHAR8                   BaseName[_MAX_PATH];
   1595   EFI_GUID                FfsGuid;
   1596   CHAR8                   GuidString[_MAX_PATH];
   1597   EFI_FFS_FILE_HEADER     FileHeader;
   1598   CHAR8                   FileType[_MAX_PATH];
   1599   EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
   1600   EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined;
   1601   UINT64                  FfsAlignment;
   1602   UINT32                  FfsAlignment32;
   1603   CHAR8                   InputString[_MAX_PATH];
   1604   BOOLEAN                 ImageScriptInOveride;
   1605   UINT32                  FileSize;
   1606   UINT8                   *FileBuffer;
   1607   EFI_STATUS              Status;
   1608   UINT32                  LineNumber;
   1609 #if (PI_SPECIFICATION_VERSION < 0x00010000)
   1610   EFI_FFS_FILE_TAIL       TailValue;
   1611 #endif
   1612   BaseName[0]       = 0;
   1613   FileType[0]       = 0;
   1614   FfsAttrib         = 0;
   1615   FfsAttribDefined  = 0;
   1616   FfsAlignment      = 0;
   1617   FfsAlignment32    = 0;
   1618   PrimaryPackage    = NULL;
   1619   Out               = NULL;
   1620   OverridePackage   = NULL;
   1621   FileBuffer        = NULL;
   1622 
   1623   strcpy (GuidString, "00000000-0000-0000-0000-000000000000");
   1624   Status = StringToGuid (GuidString, &FfsGuid);
   1625   if (Status != 0) {
   1626     Error (NULL, 0, 0, GuidString, "error parsing GUID string");
   1627     return STATUS_ERROR;
   1628   }
   1629 
   1630   GuidString[0]         = 0;
   1631   ImageScriptInOveride  = FALSE;
   1632   //
   1633   // Initialize the simple file parsing routines. Then open
   1634   // the primary package file for parsing.
   1635   //
   1636   SFPInit ();
   1637   if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) {
   1638     Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
   1639     goto Done;
   1640   }
   1641   //
   1642   // First token in the file must be "PACKAGE.INF"
   1643   //
   1644   if (!SFPIsToken ("PACKAGE.INF")) {
   1645     Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL);
   1646     goto Done;
   1647   }
   1648   //
   1649   // Find the [.] section
   1650   //
   1651   if (!SFPSkipToToken ("[.]")) {
   1652     Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL);
   1653     goto Done;
   1654   }
   1655   //
   1656   // Start parsing the data. The algorithm is essentially the same for each keyword:
   1657   //   1. Identify the keyword
   1658   //   2. Verify that the keyword/value pair has not already been defined
   1659   //   3. Set some flag indicating that the keyword/value pair has been defined
   1660   //   4. Skip over the "="
   1661   //   5. Get the value, which may be a number, TRUE, FALSE, or a string.
   1662   //
   1663   while (1) {
   1664     if (SFPIsToken ("BASE_NAME")) {
   1665       //
   1666       // Found BASE_NAME, format:
   1667       //   BASE_NAME = MyBaseName
   1668       //
   1669       if (BaseName[0] != 0) {
   1670         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL);
   1671         goto Done;
   1672       }
   1673 
   1674       if (!SFPIsToken ("=")) {
   1675         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1676         goto Done;
   1677       }
   1678 
   1679       if (!SFPGetNextToken (BaseName, sizeof (BaseName))) {
   1680         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL);
   1681         goto Done;
   1682       }
   1683     } else if (SFPIsToken ("IMAGE_SCRIPT")) {
   1684       //
   1685       // Found IMAGE_SCRIPT. Break out and process below.
   1686       //
   1687       break;
   1688     } else if (SFPIsToken ("FFS_FILEGUID")) {
   1689       //
   1690       // found FILEGUID, format:
   1691       //   FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A
   1692       //
   1693       if (GuidString[0] != 0) {
   1694         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL);
   1695         goto Done;
   1696       }
   1697 
   1698       if (!SFPIsToken ("=")) {
   1699         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1700         goto Done;
   1701       }
   1702 
   1703       if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) {
   1704         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL);
   1705         goto Done;
   1706       }
   1707 
   1708       Status = StringToGuid (GuidString, &FfsGuid);
   1709       if (Status != 0) {
   1710         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL);
   1711         goto Done;
   1712       }
   1713     } else if (SFPIsToken ("FFS_FILETYPE")) {
   1714       //
   1715       // ***********************************************************************
   1716       //
   1717       // Found FFS_FILETYPE, format:
   1718       //  FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION
   1719       //
   1720       if (FileType[0] != 0) {
   1721         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL);
   1722         goto Done;
   1723       }
   1724 
   1725       if (!SFPIsToken ("=")) {
   1726         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1727         goto Done;
   1728       }
   1729 
   1730       if (!SFPGetNextToken (FileType, sizeof (FileType))) {
   1731         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL);
   1732         goto Done;
   1733       }
   1734     }
   1735 #if (PI_SPECIFICATION_VERSION < 0x00010000)
   1736     else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) {
   1737       //
   1738       // ***********************************************************************
   1739       //
   1740       // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE
   1741       // Spec says the bit is for future expansion, and must be false.
   1742       //
   1743       if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) {
   1744         Error (
   1745           mGlobals.PrimaryPackagePath,
   1746           SFPGetLineNumber (),
   1747           0,
   1748           "FFS_ATTRIB_HEADER_EXTENSION previously defined",
   1749           NULL
   1750           );
   1751         goto Done;
   1752       }
   1753 
   1754       FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION;
   1755       if (!SFPIsToken ("=")) {
   1756         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1757         goto Done;
   1758       }
   1759 
   1760       if (SFPIsToken ("TRUE")) {
   1761         Error (
   1762           mGlobals.PrimaryPackagePath,
   1763           SFPGetLineNumber (),
   1764           0,
   1765           "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported",
   1766           NULL
   1767           );
   1768         goto Done;
   1769       } else if (SFPIsToken ("FALSE")) {
   1770         //
   1771         // Default is FALSE
   1772         //
   1773       } else {
   1774         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL);
   1775         goto Done;
   1776       }
   1777     }
   1778 #else
   1779     else if (SFPIsToken ("FFS_ATTRIB_FIXED")) {
   1780       //
   1781       // ***********************************************************************
   1782       //
   1783       // Found: FFS_ATTRIB_FIXED = TRUE | FALSE
   1784       //
   1785       if (FfsAttribDefined & FFS_ATTRIB_FIXED) {
   1786         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_FIXED previously defined", NULL);
   1787         goto Done;
   1788       }
   1789 
   1790       FfsAttribDefined |= FFS_ATTRIB_FIXED;
   1791       if (!SFPIsToken ("=")) {
   1792         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1793         goto Done;
   1794       }
   1795 
   1796       if (SFPIsToken ("TRUE")) {
   1797         FfsAttrib |= FFS_ATTRIB_FIXED;
   1798       } else if (SFPIsToken ("FALSE")) {
   1799         //
   1800         // Default is FALSE
   1801         //
   1802       } else {
   1803         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
   1804         goto Done;
   1805       }
   1806     }
   1807 #endif
   1808     else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) {
   1809       //
   1810       // ***********************************************************************
   1811       //
   1812       // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE
   1813       //
   1814       if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) {
   1815         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL);
   1816         goto Done;
   1817       }
   1818 
   1819       FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT;
   1820       if (!SFPIsToken ("=")) {
   1821         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1822         goto Done;
   1823       }
   1824 
   1825       if (SFPIsToken ("TRUE")) {
   1826         FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT;
   1827       } else if (SFPIsToken ("FALSE")) {
   1828         //
   1829         // Default is FALSE
   1830         //
   1831       } else {
   1832         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
   1833         goto Done;
   1834       }
   1835     } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) {
   1836       //
   1837       // ***********************************************************************
   1838       //
   1839       // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE
   1840       //
   1841       if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) {
   1842         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL);
   1843         goto Done;
   1844       }
   1845 
   1846       FfsAttribDefined |= FFS_ATTRIB_RECOVERY;
   1847       if (!SFPIsToken ("=")) {
   1848         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1849         goto Done;
   1850       }
   1851 
   1852       if (SFPIsToken ("TRUE")) {
   1853         FfsAttrib |= FFS_ATTRIB_RECOVERY;
   1854       } else if (SFPIsToken ("FALSE")) {
   1855         //
   1856         // Default is FALSE
   1857         //
   1858       } else {
   1859         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
   1860         goto Done;
   1861       }
   1862     } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) {
   1863       //
   1864       // ***********************************************************************
   1865       //
   1866       // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE
   1867       //
   1868       if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) {
   1869         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL);
   1870         goto Done;
   1871       }
   1872 
   1873       FfsAttribDefined |= FFS_ATTRIB_CHECKSUM;
   1874       if (!SFPIsToken ("=")) {
   1875         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1876         goto Done;
   1877       }
   1878 
   1879       if (SFPIsToken ("TRUE")) {
   1880         FfsAttrib |= FFS_ATTRIB_CHECKSUM;
   1881       } else if (SFPIsToken ("FALSE")) {
   1882         //
   1883         // Default is FALSE
   1884         //
   1885       } else {
   1886         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
   1887         goto Done;
   1888       }
   1889     } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) {
   1890       //
   1891       // ***********************************************************************
   1892       //
   1893       // Found FFS_ALIGNMENT, formats:
   1894       //   FFS_ALIGNMENT = 0-7
   1895       //   FFS_ATTRIB_DATA_ALIGNMENT = 0-7
   1896       //
   1897       if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) {
   1898         Error (
   1899           mGlobals.PrimaryPackagePath,
   1900           SFPGetLineNumber (),
   1901           0,
   1902           "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined",
   1903           NULL
   1904           );
   1905         goto Done;
   1906       }
   1907 
   1908       FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT;
   1909       if (!SFPIsToken ("=")) {
   1910         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
   1911         goto Done;
   1912       }
   1913 
   1914       if (!SFPGetNumber (&FfsAlignment32)) {
   1915         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL);
   1916         goto Done;
   1917       }
   1918 
   1919       if (FfsAlignment32 > 7) {
   1920         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL);
   1921         goto Done;
   1922       }
   1923 
   1924       FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3);
   1925     } else {
   1926       SFPGetNextToken (InputString, sizeof (InputString));
   1927       Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token");
   1928       goto Done;
   1929     }
   1930   }
   1931   //
   1932   // Close the primary package file
   1933   //
   1934   SFPCloseFile ();
   1935   //
   1936   // TODO: replace code below with basically a copy of the code above. Don't
   1937   // forget to reset the FfsAttribDefined variable first. Also, you'll need
   1938   // to somehow keep track of whether or not the basename is defined multiple
   1939   // times in the override package. Ditto on the file GUID.
   1940   //
   1941   if (mGlobals.OverridePackagePath[0] != 0) {
   1942     OverridePackage = fopen (mGlobals.OverridePackagePath, "r");
   1943     //
   1944     // NOTE: For package override to work correctly, the code below must be modified to
   1945     //       SET or CLEAR bits properly. For example, if the primary package set
   1946     //       FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then
   1947     //       we'd need to clear the bit below. Since this is not happening, I'm guessing that
   1948     //       the override functionality is not being used, so should be made obsolete. If I'm
   1949     //       wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is
   1950     //       used, and we'll address it then.  4/10/2003
   1951     //
   1952     Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL);
   1953     goto Done;
   1954   } else {
   1955     OverridePackage = NULL;
   1956   }
   1957 
   1958 #ifdef OVERRIDE_SUPPORTED
   1959   if (OverridePackage != NULL) {
   1960     //
   1961     // Parse override package file
   1962     //
   1963     fscanf (OverridePackage, "%s", &InputString);
   1964     if (_strcmpi (InputString, "PACKAGE.INF") != 0) {
   1965       Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'");
   1966       goto Done;
   1967     }
   1968     //
   1969     // Match [dir] to Build Directory
   1970     //
   1971     if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) {
   1972       Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file");
   1973       goto Done;
   1974     }
   1975 
   1976     InputString[0] = 0;
   1977     while ((InputString[0] != '[') && (!feof (OverridePackage))) {
   1978       if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) {
   1979         if (InputString[0] != '[') {
   1980 here:
   1981           if (_strcmpi (InputString, "BASE_NAME") == 0) {
   1982             //
   1983             // found BASE_NAME, next is = and string.
   1984             //
   1985             fscanf (OverridePackage, "%s", &InputString);
   1986             CheckSlash (InputString, OverridePackage, &LineNumber);
   1987             if (strlen (InputString) == 1) {
   1988               //
   1989               // string is just =
   1990               //
   1991               fscanf (OverridePackage, "%s", &InputString);
   1992               CheckSlash (InputString, OverridePackage, &LineNumber);
   1993               strcpy (BaseName, InputString);
   1994             } else {
   1995               BreakString (InputString, InputString, 1);
   1996               strcpy (BaseName, InputString);
   1997             }
   1998           } else if (_strcmpi (InputString, "IMAGE_SCRIPT") == 0) {
   1999             //
   2000             // found IMAGE_SCRIPT, come back later to process it
   2001             //
   2002             ImageScriptInOveride = TRUE;
   2003             fscanf (OverridePackage, "%s", &InputString);
   2004           } else if (_strcmpi (InputString, "FFS_FILEGUID") == 0) {
   2005             //
   2006             // found FILEGUID, next is = and string.
   2007             //
   2008             fscanf (OverridePackage, "%s", &InputString);
   2009             CheckSlash (InputString, OverridePackage, &LineNumber);
   2010             if (strlen (InputString) == 1) {
   2011               //
   2012               // string is just =
   2013               //
   2014               fscanf (OverridePackage, "%s", &InputString);
   2015               CheckSlash (InputString, OverridePackage, &LineNumber);
   2016               Status = StringToGuid (InputString, &FfsGuid);
   2017               if (Status != 0) {
   2018                 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
   2019                 goto Done;
   2020               }
   2021             } else {
   2022               BreakString (InputString, InputString, 1);
   2023               Status = StringToGuid (InputString, &FfsGuid);
   2024               if (Status != 0) {
   2025                 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
   2026                 goto Done;
   2027               }
   2028             }
   2029           } else if (_strcmpi (InputString, "FFS_FILETYPE") == 0) {
   2030             //
   2031             // found FILETYPE, next is = and string.
   2032             //
   2033             fscanf (OverridePackage, "%s", &InputString);
   2034             CheckSlash (InputString, OverridePackage, &LineNumber);
   2035             if (strlen (InputString) == 1) {
   2036               //
   2037               // string is just =
   2038               //
   2039               fscanf (OverridePackage, "%s", &InputString);
   2040               CheckSlash (InputString, OverridePackage, &LineNumber);
   2041               strcpy (FileType, InputString);
   2042             } else {
   2043               BreakString (InputString, InputString, 1);
   2044               strcpy (FileType, InputString);
   2045             }
   2046 
   2047           } else if (_strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) {
   2048             //
   2049             // found FFS_ATTRIB_RECOVERY, next is = and string.
   2050             //
   2051             fscanf (OverridePackage, "%s", &InputString);
   2052             CheckSlash (InputString, OverridePackage, &LineNumber);
   2053             if (strlen (InputString) == 1) {
   2054               //
   2055               // string is just =
   2056               //
   2057               fscanf (OverridePackage, "%s", &InputString);
   2058               CheckSlash (InputString, OverridePackage, &LineNumber);
   2059               if (_strcmpi (InputString, "TRUE") == 0) {
   2060                 FfsAttrib |= FFS_ATTRIB_RECOVERY;
   2061               }
   2062             } else {
   2063               BreakString (InputString, InputString, 1);
   2064               if (_strcmpi (InputString, "TRUE") == 0) {
   2065                 FfsAttrib |= FFS_ATTRIB_RECOVERY;
   2066               }
   2067             }
   2068           } else if (_strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) {
   2069             //
   2070             // found FFS_ATTRIB_CHECKSUM, next is = and string.
   2071             //
   2072             fscanf (OverridePackage, "%s", &InputString);
   2073             CheckSlash (InputString, OverridePackage, &LineNumber);
   2074             if (strlen (InputString) == 1) {
   2075               //
   2076               // string is just =
   2077               //
   2078               fscanf (OverridePackage, "%s", &InputString);
   2079               CheckSlash (InputString, OverridePackage, &LineNumber);
   2080               if (_strcmpi (InputString, "TRUE") == 0) {
   2081                 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
   2082               }
   2083             } else {
   2084               BreakString (InputString, InputString, 1);
   2085               if (_strcmpi (InputString, "TRUE") == 0) {
   2086                 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
   2087               }
   2088             }
   2089           } else if (_strcmpi (InputString, "FFS_ALIGNMENT") == 0) {
   2090             //
   2091             // found FFS_ALIGNMENT, next is = and string.
   2092             //
   2093             fscanf (OverridePackage, "%s", &InputString);
   2094             CheckSlash (InputString, OverridePackage, &LineNumber);
   2095             if (strlen (InputString) == 1) {
   2096               //
   2097               // string is just =
   2098               //
   2099               fscanf (OverridePackage, "%s", &InputString);
   2100               CheckSlash (InputString, OverridePackage, &LineNumber);
   2101             } else {
   2102               BreakString (InputString, InputString, 1);
   2103             }
   2104 
   2105             AsciiStringToUint64 (InputString, FALSE, &FfsAlignment);
   2106             if (FfsAlignment > 7) {
   2107               Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value");
   2108               goto Done;
   2109             }
   2110 
   2111             FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3);
   2112           } else if (strchr (InputString, '=') != NULL) {
   2113             BreakString (InputString, String, 1);
   2114             fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR);
   2115             BreakString (InputString, InputString, 0);
   2116             goto here;
   2117           }
   2118         }
   2119       }
   2120     }
   2121   }
   2122 #endif // #ifdef OVERRIDE_SUPPORTED
   2123   //
   2124   // Require that they specified a file GUID at least, since that's how we're
   2125   // naming the file.
   2126   //
   2127   if (GuidString[0] == 0) {
   2128     Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL);
   2129     return STATUS_ERROR;
   2130   }
   2131   //
   2132   // Build Header and process image script
   2133   //
   2134   FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8));
   2135   if (FileBuffer == NULL) {
   2136     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
   2137     goto Done;
   2138   }
   2139 
   2140   FileSize = 0;
   2141   if (ImageScriptInOveride) {
   2142 #ifdef OVERRIDE_SUPPORTED
   2143     rewind (OverridePackage);
   2144     LineNumber = 0;
   2145     FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber);
   2146     while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
   2147       GetNextLine (InputString, OverridePackage, &LineNumber);
   2148       CheckSlash (InputString, OverridePackage, &LineNumber);
   2149       if (strchr (InputString, '=') != NULL) {
   2150         BreakString (InputString, InputString, 0);
   2151       }
   2152     }
   2153 
   2154     while (InputString[0] != '{') {
   2155       GetNextLine (InputString, OverridePackage, &LineNumber);
   2156       CheckSlash (InputString, OverridePackage, &LineNumber);
   2157     }
   2158     //
   2159     // Found start of image script, process it
   2160     //
   2161     FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress);
   2162     if (FileSize == -1) {
   2163       Error (NULL, 0, 0, "failed to process script", NULL);
   2164       goto Done;
   2165     }
   2166 
   2167     if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
   2168       FileSize = AdjustFileSize (FileBuffer, FileSize);
   2169     }
   2170 
   2171     if (BaseName[0] == '\"') {
   2172       StripQuotes (BaseName);
   2173     }
   2174 
   2175     if (mGlobals.OutputFilePath[0]) {
   2176       //
   2177       // Use user specified output file name
   2178       //
   2179       strcpy (InputString, mGlobals.OutputFilePath);
   2180     } else {
   2181       //
   2182       // Construct the output file name according to FileType
   2183       //
   2184       if (BaseName[0] != 0) {
   2185         sprintf (InputString, "%s-%s", GuidString, BaseName);
   2186       } else {
   2187         strcpy (InputString, GuidString);
   2188       }
   2189 
   2190       switch (StringToType (FileType)) {
   2191 
   2192       case EFI_FV_FILETYPE_SECURITY_CORE:
   2193         strcat (InputString, ".SEC");
   2194         break;
   2195 
   2196       case EFI_FV_FILETYPE_PEIM:
   2197       case EFI_FV_FILETYPE_PEI_CORE:
   2198       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
   2199         strcat (InputString, ".PEI");
   2200         break;
   2201 
   2202       case EFI_FV_FILETYPE_DRIVER:
   2203       case EFI_FV_FILETYPE_DXE_CORE:
   2204         strcat (InputString, ".DXE");
   2205         break;
   2206 
   2207       case EFI_FV_FILETYPE_APPLICATION:
   2208         strcat (InputString, ".APP");
   2209         break;
   2210 
   2211       case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
   2212         strcat (InputString, ".FVI");
   2213         break;
   2214 
   2215       case EFI_FV_FILETYPE_RAW:
   2216         strcat (InputString, ".RAW");
   2217         break;
   2218 
   2219       case EFI_FV_FILETYPE_ALL:
   2220         Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
   2221         goto Done;
   2222 
   2223       default:
   2224         strcat (InputString, ".FFS");
   2225         break;
   2226       }
   2227     }
   2228 
   2229     if (ForceUncompress) {
   2230       strcat (InputString, ".ORG");
   2231     }
   2232 
   2233     Out = fopen (InputString, "wb");
   2234     if (Out == NULL) {
   2235       Error (NULL, 0, 0, InputString, "could not open output file for writing");
   2236       goto Done;
   2237     }
   2238     //
   2239     // create ffs header
   2240     //
   2241     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
   2242     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
   2243     FileHeader.Type       = StringToType (FileType);
   2244     if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {
   2245       FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);
   2246     }
   2247     FileHeader.Attributes = FfsAttrib;
   2248     //
   2249     // Now FileSize includes the EFI_FFS_FILE_HEADER
   2250     //
   2251     FileSize += sizeof (EFI_FFS_FILE_HEADER);
   2252     FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
   2253     FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
   2254     FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
   2255     //
   2256     // Fill in checksums and state, these must be zero for checksumming
   2257     //
   2258     // FileHeader.IntegrityCheck.Checksum.Header = 0;
   2259     // FileHeader.IntegrityCheck.Checksum.File = 0;
   2260     // FileHeader.State = 0;
   2261     //
   2262     FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
   2263                                                   (UINT8 *) &FileHeader,
   2264                                                   sizeof (EFI_FFS_FILE_HEADER)
   2265                                                   );
   2266     if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
   2267 #if (PI_SPECIFICATION_VERSION < 0x00010000)
   2268       FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize);
   2269 #else
   2270       FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) ((UINTN)&FileHeader + sizeof (EFI_FFS_FILE_HEADER)), FileSize - sizeof (EFI_FFS_FILE_HEADER));
   2271 #endif
   2272     } else {
   2273       FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
   2274     }
   2275 
   2276     FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
   2277     //
   2278     // write header
   2279     //
   2280     if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
   2281       Error (NULL, 0, 0, "failed to write file header to output file", NULL);
   2282       goto Done;
   2283     }
   2284     //
   2285     // write data
   2286     //
   2287     if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
   2288       Error (NULL, 0, 0, "failed to write all bytes to output file", NULL);
   2289       goto Done;
   2290     }
   2291 
   2292     fclose (Out);
   2293     Out = NULL;
   2294 #endif // #ifdef OVERRIDE_SUPPORTED
   2295   } else {
   2296     //
   2297     // Open primary package file and process the IMAGE_SCRIPT section
   2298     //
   2299     PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r");
   2300     if (PrimaryPackage == NULL) {
   2301       Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
   2302       goto Done;
   2303     }
   2304 
   2305     LineNumber = 1;
   2306     FindSectionInPackage (".", PrimaryPackage, &LineNumber);
   2307     while (_strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
   2308       GetNextLine (InputString, PrimaryPackage, &LineNumber);
   2309       CheckSlash (InputString, PrimaryPackage, &LineNumber);
   2310       if (strchr (InputString, '=') != NULL) {
   2311         BreakString (InputString, InputString, 0);
   2312       }
   2313     }
   2314 
   2315     while (InputString[0] != '{') {
   2316       GetNextLine (InputString, PrimaryPackage, &LineNumber);
   2317       CheckSlash (InputString, PrimaryPackage, &LineNumber);
   2318     }
   2319     //
   2320     // Found start of image script, process it
   2321     //
   2322     FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress);
   2323     if (FileSize == -1) {
   2324       Error (NULL, 0, 0, "failed to process script", NULL);
   2325       goto Done;
   2326     }
   2327 
   2328     if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
   2329       FileSize = AdjustFileSize (FileBuffer, FileSize);
   2330     }
   2331 
   2332     if (BaseName[0] == '\"') {
   2333       StripQuotes (BaseName);
   2334     }
   2335 
   2336     if (mGlobals.OutputFilePath[0]) {
   2337       //
   2338       // Use user specified output file name
   2339       //
   2340       strcpy (InputString, mGlobals.OutputFilePath);
   2341     } else {
   2342       //
   2343       // Construct the output file name according to FileType
   2344       //
   2345       if (BaseName[0] != 0) {
   2346         sprintf (InputString, "%s-%s", GuidString, BaseName);
   2347       } else {
   2348         strcpy (InputString, GuidString);
   2349       }
   2350 
   2351       switch (StringToType (FileType)) {
   2352 
   2353       case EFI_FV_FILETYPE_SECURITY_CORE:
   2354         strcat (InputString, ".SEC");
   2355         break;
   2356 
   2357       case EFI_FV_FILETYPE_PEIM:
   2358       case EFI_FV_FILETYPE_PEI_CORE:
   2359       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
   2360         strcat (InputString, ".PEI");
   2361         break;
   2362 
   2363       case EFI_FV_FILETYPE_DRIVER:
   2364       case EFI_FV_FILETYPE_DXE_CORE:
   2365         strcat (InputString, ".DXE");
   2366         break;
   2367 
   2368       case EFI_FV_FILETYPE_APPLICATION:
   2369         strcat (InputString, ".APP");
   2370         break;
   2371 
   2372       case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
   2373         strcat (InputString, ".FVI");
   2374         break;
   2375 
   2376       case EFI_FV_FILETYPE_RAW:
   2377         strcat (InputString, ".RAW");
   2378         break;
   2379 
   2380       case EFI_FV_FILETYPE_ALL:
   2381         Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
   2382         goto Done;
   2383 
   2384       default:
   2385         strcat (InputString, ".FFS");
   2386         break;
   2387       }
   2388     }
   2389 
   2390     if (ForceUncompress) {
   2391       strcat (InputString, ".ORG");
   2392     }
   2393 
   2394     Out = fopen (InputString, "wb");
   2395     if (Out == NULL) {
   2396       Error (NULL, 0, 0, InputString, "failed to open output file for writing");
   2397       goto Done;
   2398     }
   2399     //
   2400     // Initialize the FFS file header
   2401     //
   2402     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
   2403     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
   2404     FileHeader.Type       = StringToType (FileType);
   2405     if (((FfsAttrib & FFS_ATTRIB_DATA_ALIGNMENT) >> 3) < MinFfsDataAlignOverride) {
   2406       FfsAttrib = (FfsAttrib & ~FFS_ATTRIB_DATA_ALIGNMENT) | (MinFfsDataAlignOverride << 3);
   2407     }
   2408     FileHeader.Attributes = FfsAttrib;
   2409     //
   2410     // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER
   2411     //
   2412     FileSize += sizeof (EFI_FFS_FILE_HEADER);
   2413     //
   2414     // If using a tail, then it adds two bytes
   2415     //
   2416     if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
   2417       //
   2418       // Tail is not allowed for pad and 0-length files
   2419       //
   2420       if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) {
   2421         Error (
   2422           mGlobals.PrimaryPackagePath,
   2423           1,
   2424           0,
   2425           "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files",
   2426           NULL
   2427           );
   2428         goto Done;
   2429       }
   2430 
   2431       FileSize += sizeof (EFI_FFS_FILE_TAIL);
   2432     }
   2433 
   2434     FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
   2435     FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
   2436     FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
   2437     //
   2438     // Fill in checksums and state, they must be 0 for checksumming.
   2439     //
   2440     // FileHeader.IntegrityCheck.Checksum.Header = 0;
   2441     // FileHeader.IntegrityCheck.Checksum.File = 0;
   2442     // FileHeader.State = 0;
   2443     //
   2444     FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
   2445                                                   (UINT8 *) &FileHeader,
   2446                                                   sizeof (EFI_FFS_FILE_HEADER)
   2447                                                   );
   2448     if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
   2449       //
   2450       // Cheating here.  Since the header checksums, just calculate the checksum of the body.
   2451       // Checksum does not include the tail
   2452       //
   2453       if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
   2454         FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
   2455                                                     FileBuffer,
   2456                                                     FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL)
   2457                                                     );
   2458       } else {
   2459         FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
   2460                                                     FileBuffer,
   2461                                                     FileSize - sizeof (EFI_FFS_FILE_HEADER)
   2462                                                     );
   2463       }
   2464     } else {
   2465       FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
   2466     }
   2467     //
   2468     // Set the state now. Spec says the checksum assumes the state is 0
   2469     //
   2470     FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
   2471 
   2472 #if (PI_SPECIFICATION_VERSION < 0x00010000)
   2473 
   2474     //
   2475     // If there is a tail, then set it
   2476     //
   2477     if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
   2478       TailValue = FileHeader.IntegrityCheck.TailReference;
   2479       TailValue = (UINT16) (~TailValue);
   2480       memcpy (
   2481         (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL),
   2482         &TailValue,
   2483         sizeof (TailValue)
   2484         );
   2485     }
   2486 #endif
   2487     //
   2488     // Write the FFS file header
   2489     //
   2490     if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
   2491       Error (NULL, 0, 0, "failed to write file header contents", NULL);
   2492       goto Done;
   2493     }
   2494     //
   2495     // Write data
   2496     //
   2497     if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
   2498       Error (NULL, 0, 0, "failed to write file contents", NULL);
   2499       goto Done;
   2500     }
   2501   }
   2502 
   2503 Done:
   2504   SFPCloseFile ();
   2505   if (Out != NULL) {
   2506     fclose (Out);
   2507   }
   2508 
   2509   if (PrimaryPackage != NULL) {
   2510     fclose (PrimaryPackage);
   2511   }
   2512 
   2513   if (FileBuffer != NULL) {
   2514     free (FileBuffer);
   2515   }
   2516 
   2517   if (OverridePackage != NULL) {
   2518     fclose (OverridePackage);
   2519   }
   2520 
   2521   return GetUtilityStatus ();
   2522 }
   2523 
   2524 int
   2525 main (
   2526   INT32 argc,
   2527   CHAR8 *argv[]
   2528   )
   2529 /*++
   2530 
   2531 Routine Description:
   2532 
   2533   Main function.
   2534 
   2535 Arguments:
   2536 
   2537   argc - Number of command line parameters.
   2538   argv - Array of pointers to parameter strings.
   2539 
   2540 Returns:
   2541   STATUS_SUCCESS - Utility exits successfully.
   2542   STATUS_ERROR   - Some error occurred during execution.
   2543 
   2544 --*/
   2545 {
   2546   STATUS  Status;
   2547   //
   2548   // Set the name of our utility for error reporting purposes.
   2549   //
   2550   SetUtilityName (UTILITY_NAME);
   2551   Status = ProcessCommandLineArgs (argc, argv);
   2552   FreeMacros ();
   2553   if (Status != STATUS_SUCCESS) {
   2554     return Status;
   2555   }
   2556 
   2557   Status = MainEntry (argc, argv, TRUE);
   2558   if (Status == STATUS_SUCCESS) {
   2559     MainEntry (argc, argv, FALSE);
   2560   }
   2561   //
   2562   // If any errors were reported via the standard error reporting
   2563   // routines, then the status has been saved. Get the value and
   2564   // return it to the caller.
   2565   //
   2566   return GetUtilityStatus ();
   2567 }
   2568 
   2569 static
   2570 STATUS
   2571 ProcessCommandLineArgs (
   2572   int     Argc,
   2573   char    *Argv[]
   2574   )
   2575 /*++
   2576 
   2577 Routine Description:
   2578   Process the command line arguments.
   2579 
   2580 Arguments:
   2581   Argc - as passed in to main()
   2582   Argv - as passed in to main()
   2583 
   2584 Returns:
   2585   STATUS_SUCCESS    - arguments all ok
   2586   STATUS_ERROR      - problem with args, so caller should exit
   2587 
   2588 --*/
   2589 {
   2590   STATUS       Status;
   2591   UINT8        *OriginalPrimaryPackagePath;
   2592   UINT8        *OriginalOverridePackagePath;
   2593   UINT8        *PackageName;
   2594 
   2595   //
   2596   // If no args, then print usage instructions and return an error
   2597   //
   2598   if (Argc == 1) {
   2599     PrintUsage ();
   2600     return STATUS_ERROR;
   2601   }
   2602 
   2603   OriginalPrimaryPackagePath = NULL;
   2604   OriginalOverridePackagePath = NULL;
   2605   memset (&mGlobals, 0, sizeof (mGlobals));
   2606   Argc--;
   2607   Argv++;
   2608   while (Argc > 0) {
   2609     if (_strcmpi (Argv[0], "-b") == 0) {
   2610       //
   2611       // OPTION: -b BuildDirectory
   2612       // Make sure there is another argument, then save it to our globals.
   2613       //
   2614       if (Argc < 2) {
   2615         Error (NULL, 0, 0, "-b option requires the build directory name", NULL);
   2616         return STATUS_ERROR;
   2617       }
   2618 
   2619       if (mGlobals.BuildDirectory[0]) {
   2620         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
   2621         return STATUS_ERROR;
   2622       }
   2623 
   2624       strcpy (mGlobals.BuildDirectory, Argv[1]);
   2625       Argc--;
   2626       Argv++;
   2627     } else if (_strcmpi (Argv[0], "-p1") == 0) {
   2628       //
   2629       // OPTION: -p1 PrimaryPackageFile
   2630       // Make sure there is another argument, then save it to our globals.
   2631       //
   2632       if (Argc < 2) {
   2633         Error (NULL, 0, 0, Argv[0], "option requires the primary package file name");
   2634         return STATUS_ERROR;
   2635       }
   2636 
   2637       if (OriginalPrimaryPackagePath) {
   2638         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
   2639         return STATUS_ERROR;
   2640       }
   2641 
   2642       OriginalPrimaryPackagePath = Argv[1];
   2643       Argc--;
   2644       Argv++;
   2645     } else if (_strcmpi (Argv[0], "-p2") == 0) {
   2646       //
   2647       // OPTION: -p2 OverridePackageFile
   2648       // Make sure there is another argument, then save it to our globals.
   2649       //
   2650       if (Argc < 2) {
   2651         Error (NULL, 0, 0, Argv[0], "option requires the override package file name");
   2652         return STATUS_ERROR;
   2653       }
   2654 
   2655       if (OriginalOverridePackagePath) {
   2656         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
   2657         return STATUS_ERROR;
   2658       }
   2659 
   2660       OriginalOverridePackagePath = Argv[1];
   2661       Argc--;
   2662       Argv++;
   2663     } else if (_strcmpi (Argv[0], "-o") == 0) {
   2664       //
   2665       // OPTION: -o OutputFilePath
   2666       // Make sure there is another argument, then save it to out globals.
   2667       //
   2668       if (Argc < 2) {
   2669         Error (NULL, 0, 0, Argv[0], "option requires the output file name");
   2670         return STATUS_ERROR;
   2671       }
   2672       if (mGlobals.OutputFilePath[0]) {
   2673         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
   2674         return STATUS_ERROR;
   2675       }
   2676 
   2677       strcpy (mGlobals.OutputFilePath, Argv[1]);
   2678       Argc--;
   2679       Argv++;
   2680     } else if (_strcmpi (Argv[0], "-v") == 0) {
   2681       //
   2682       // OPTION: -v       verbose
   2683       //
   2684       mGlobals.Verbose = TRUE;
   2685     } else if (_strcmpi (Argv[0], "-d") == 0) {
   2686       //
   2687       // OPTION: -d  name=value
   2688       // Make sure there is another argument, then add it to our macro list.
   2689       //
   2690       if (Argc < 2) {
   2691         Error (NULL, 0, 0, Argv[0], "option requires the macro definition");
   2692         return STATUS_ERROR;
   2693       }
   2694 
   2695       AddMacro (Argv[1]);
   2696       Argc--;
   2697       Argv++;
   2698     } else if (_strcmpi (Argv[0], "-h") == 0) {
   2699       //
   2700       // OPTION: -h      help
   2701       //
   2702       PrintUsage ();
   2703       return STATUS_ERROR;
   2704     } else if (_strcmpi (Argv[0], "-?") == 0) {
   2705       //
   2706       // OPTION:  -?      help
   2707       //
   2708       PrintUsage ();
   2709       return STATUS_ERROR;
   2710     } else {
   2711       Error (NULL, 0, 0, Argv[0], "unrecognized option");
   2712       PrintUsage ();
   2713       return STATUS_ERROR;
   2714     }
   2715 
   2716     Argv++;
   2717     Argc--;
   2718   }
   2719 
   2720   //
   2721   // Must have at least specified the build directory
   2722   //
   2723   if (!mGlobals.BuildDirectory[0]) {
   2724     Error (NULL, 0, 0, "must specify build directory", NULL);
   2725     return STATUS_ERROR;
   2726   }
   2727 
   2728   //
   2729   // Must have at least specified the package file name
   2730   //
   2731   if (OriginalPrimaryPackagePath == NULL) {
   2732     Error (NULL, 0, 0, "must specify primary package file", NULL);
   2733     return STATUS_ERROR;
   2734   }
   2735 
   2736   PackageName = OriginalPrimaryPackagePath + strlen (OriginalPrimaryPackagePath);
   2737   while ((*PackageName != '\\') && (*PackageName != '/') &&
   2738          (PackageName != OriginalPrimaryPackagePath)) {
   2739     PackageName--;
   2740   }
   2741   //
   2742   // Skip the '\' or '/'
   2743   //
   2744   if (PackageName != OriginalPrimaryPackagePath) {
   2745     PackageName++;
   2746   }
   2747   sprintf (mGlobals.PrimaryPackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);
   2748   Status = ReplaceMacros (OriginalPrimaryPackagePath, mGlobals.PrimaryPackagePath);
   2749   if (Status == STATUS_WARNING) {
   2750     //
   2751     // No macro replacement, use the previous package file
   2752     //
   2753     strcpy (mGlobals.PrimaryPackagePath, OriginalPrimaryPackagePath);
   2754   } else if (Status != STATUS_SUCCESS) {
   2755     return Status;
   2756   }
   2757 
   2758   if (OriginalOverridePackagePath != NULL) {
   2759     PackageName = OriginalOverridePackagePath + strlen (OriginalOverridePackagePath);
   2760     while ((*PackageName != '\\') && (*PackageName != '/') &&
   2761            (PackageName != OriginalOverridePackagePath)) {
   2762       PackageName--;
   2763     }
   2764     //
   2765     // Skip the '\' or '/'
   2766     //
   2767     if (PackageName != OriginalOverridePackagePath) {
   2768       PackageName++;
   2769     }
   2770     sprintf (mGlobals.OverridePackagePath, "%s\\%s.new", mGlobals.BuildDirectory, PackageName);
   2771     Status = ReplaceMacros (OriginalOverridePackagePath, mGlobals.OverridePackagePath);
   2772     if (Status == STATUS_WARNING) {
   2773       //
   2774       // No macro replacement, use the previous package file
   2775       //
   2776       strcpy (mGlobals.OverridePackagePath, OriginalOverridePackagePath);
   2777     } else if (Status != STATUS_SUCCESS) {
   2778         return Status;
   2779     }
   2780   }
   2781 
   2782   return STATUS_SUCCESS;
   2783 }
   2784 
   2785 static
   2786 void
   2787 AddMacro (
   2788   UINT8   *MacroString
   2789   )
   2790 /*++
   2791 
   2792 Routine Description:
   2793 
   2794   Add or override a macro definition.
   2795 
   2796 Arguments:
   2797 
   2798   MacroString  - macro definition string: name=value
   2799 
   2800 Returns:
   2801 
   2802   None
   2803 
   2804 --*/
   2805 {
   2806   MACRO    *Macro;
   2807   MACRO    *NewMacro;
   2808   UINT8    *Value;
   2809 
   2810   //
   2811   // Seperate macro name and value by '\0'
   2812   //
   2813   for (Value = MacroString; *Value && (*Value != '='); Value++);
   2814 
   2815   if (*Value == '=') {
   2816     *Value = '\0';
   2817     Value ++;
   2818   }
   2819 
   2820   //
   2821   // We now have a macro name and value.
   2822   // Look for an existing macro and overwrite it.
   2823   //
   2824   Macro = mGlobals.MacroList;
   2825   while (Macro) {
   2826     if (_strcmpi (MacroString, Macro->Name) == 0) {
   2827       Macro->Value = Value;
   2828       return;
   2829     }
   2830 
   2831     Macro = Macro->Next;
   2832   }
   2833 
   2834   //
   2835   // Does not exist, create a new one
   2836   //
   2837   NewMacro = (MACRO *) malloc (sizeof (MACRO));
   2838   memset ((UINT8 *) NewMacro, 0, sizeof (MACRO));
   2839   NewMacro->Name   = MacroString;
   2840   NewMacro->Value  = Value;
   2841 
   2842   //
   2843   // Add it to the head of the list.
   2844   //
   2845   NewMacro->Next = mGlobals.MacroList;
   2846   mGlobals.MacroList = NewMacro;
   2847 
   2848   return;
   2849 }
   2850 
   2851 static
   2852 UINT8 *
   2853 GetMacroValue (
   2854   UINT8   *MacroName
   2855   )
   2856 /*++
   2857 
   2858 Routine Description:
   2859 
   2860   Look up a macro.
   2861 
   2862 Arguments:
   2863 
   2864   MacroName  - The name of macro
   2865 
   2866 Returns:
   2867 
   2868   Pointer to the value of the macro if found
   2869   NULL if the macro is not found
   2870 
   2871 --*/
   2872 {
   2873 
   2874   MACRO  *Macro;
   2875   UINT8  *Value;
   2876 
   2877   //
   2878   // Scan for macro
   2879   //
   2880   Macro = mGlobals.MacroList;
   2881   while (Macro) {
   2882     if (_strcmpi (MacroName, Macro->Name) == 0) {
   2883       return Macro->Value;
   2884     }
   2885     Macro = Macro->Next;
   2886   }
   2887 
   2888   //
   2889   // Try environment variable
   2890   //
   2891   Value = getenv (MacroName);
   2892   if (Value == NULL) {
   2893     printf ("Environment variable %s not found!\n", MacroName);
   2894   }
   2895   return Value;
   2896 }
   2897 
   2898 static
   2899 void
   2900 FreeMacros (
   2901   )
   2902 /*++
   2903 
   2904 Routine Description:
   2905 
   2906   Free the macro list.
   2907 
   2908 Arguments:
   2909 
   2910   None
   2911 
   2912 Returns:
   2913 
   2914   None
   2915 
   2916 --*/
   2917 {
   2918   MACRO    *Macro;
   2919   MACRO    *NextMacro;
   2920 
   2921   Macro = mGlobals.MacroList;
   2922   while (Macro) {
   2923     NextMacro = Macro->Next;
   2924     free (Macro);
   2925     Macro = NextMacro;
   2926   }
   2927   mGlobals.MacroList = NULL;
   2928 
   2929   return;
   2930 }
   2931 
   2932 static
   2933 STATUS
   2934 ReplaceMacros (
   2935   UINT8   *InputFile,
   2936   UINT8   *OutputFile
   2937   )
   2938 /*++
   2939 
   2940 Routine Description:
   2941 
   2942   Replace all the macros in InputFile to create the OutputFile.
   2943 
   2944 Arguments:
   2945 
   2946   InputFile         - Input package file for macro replacement
   2947   OutputFile        - Output package file after macro replacement
   2948 
   2949 Returns:
   2950 
   2951   STATUS_SUCCESS    - Output package file is created successfully after the macro replacement.
   2952   STATUS_WARNING    - Output package file is not created because of no macro replacement.
   2953   STATUS_ERROR      - Some error occurred during execution.
   2954 
   2955 --*/
   2956 {
   2957   FILE   *Fptr;
   2958   UINT8  *SaveStart;
   2959   UINT8  *FromPtr;
   2960   UINT8  *ToPtr;
   2961   UINT8  *Value;
   2962   UINT8  *FileBuffer;
   2963   UINTN  FileSize;
   2964 
   2965   //
   2966   // Get the file size, and then read the entire thing into memory.
   2967   // Allocate extra space for a terminator character.
   2968   //
   2969   if ((Fptr = fopen (InputFile, "r")) == NULL) {
   2970     Error (NULL, 0, 0, InputFile, "can't open input file");
   2971     return STATUS_ERROR;
   2972   }
   2973   fseek (Fptr, 0, SEEK_END);
   2974   FileSize = ftell (Fptr);
   2975   fseek (Fptr, 0, SEEK_SET);
   2976   FileBuffer = malloc (FileSize + 1);
   2977   if (FileBuffer == NULL) {
   2978     fclose (Fptr);
   2979     Error (NULL, 0, 0, InputFile, "file buffer memory allocation failure");
   2980     return STATUS_ERROR;
   2981   }
   2982   fread (FileBuffer, FileSize, 1, Fptr);
   2983   FileBuffer[FileSize] = '\0';
   2984   fclose (Fptr);
   2985 
   2986   //
   2987   // Walk the entire file, replacing $(MACRO_NAME).
   2988   //
   2989   Fptr = NULL;
   2990   FromPtr = FileBuffer;
   2991   SaveStart = FromPtr;
   2992   while (*FromPtr) {
   2993     if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) {
   2994       FromPtr += 2;
   2995       for (ToPtr = FromPtr; *ToPtr && (*ToPtr != ')'); ToPtr++);
   2996       if (*ToPtr) {
   2997         //
   2998         // Find an $(MACRO_NAME), replace it
   2999         //
   3000         *ToPtr = '\0';
   3001         Value = GetMacroValue (FromPtr);
   3002         *(FromPtr-2)= '\0';
   3003         if (Fptr == NULL) {
   3004           if ((Fptr = fopen (OutputFile, "w")) == NULL) {
   3005             free (FileBuffer);
   3006             Error (NULL, 0, 0, OutputFile, "can't open output file");
   3007             return STATUS_ERROR;
   3008           }
   3009         }
   3010         if (Value != NULL) {
   3011           fprintf (Fptr, "%s%s", SaveStart, Value);
   3012         } else {
   3013           fprintf (Fptr, "%s", SaveStart);
   3014         }
   3015         //
   3016         // Continue macro replacement for the remaining string line
   3017         //
   3018         FromPtr = ToPtr+1;
   3019         SaveStart = FromPtr;
   3020         continue;
   3021       } else {
   3022         break;
   3023       }
   3024     } else {
   3025       FromPtr++;
   3026     }
   3027   }
   3028   if (Fptr != NULL) {
   3029     fprintf (Fptr, "%s", SaveStart);
   3030   }
   3031 
   3032   free (FileBuffer);
   3033   if (Fptr != NULL) {
   3034     fclose (Fptr);
   3035     return STATUS_SUCCESS;
   3036   } else {
   3037     return STATUS_WARNING;
   3038   }
   3039 }
   3040