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
StripQuotes(IN OUT CHAR8 * String)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
PrintUsage(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
TestComment(IN CHAR8 * String,IN FILE * In)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
BreakString(IN CONST CHAR8 * Source,OUT CHAR8 * Destination,IN INTN Direction)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
GetNextLine(OUT CHAR8 * Destination,IN FILE * Package,IN OUT UINT32 * LineNumber)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
CheckSlash(IN OUT CHAR8 * String,IN FILE * In,IN OUT UINT32 * LineNumber)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
FindSectionInPackage(IN CHAR8 * BuildDirectory,IN FILE * OverridePackage,IN OUT UINT32 * LineNumber)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
GenSimpleGuidSection(IN OUT UINT8 * FileBuffer,IN OUT UINT32 * BufferSize,IN UINT32 DataSize,IN EFI_GUID SignGuid,IN UINT16 GuidedSectionAttributes)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
CompressSection(UINT8 * FileBuffer,UINT32 * BufferSize,UINT32 DataSize,CHAR8 * Type)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
StripParens(IN OUT CHAR8 * String)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
StripEqualMark(IN OUT CHAR8 * String)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
SplitAttributesField(IN CHAR8 * Buffer,IN CHAR8 * AttributesArray[],IN OUT UINT32 * NumberOfAttributes)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
GetToolArguments(CHAR8 * ToolArgumentsArray[],FILE * Package,CHAR8 ** PtrInputFileName,CHAR8 ** PtrOutputFileName,EFI_GUID * Guid,UINT16 * GuidedSectionAttributes)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
ProcessScript(IN OUT UINT8 * FileBuffer,IN FILE * Package,IN CHAR8 * BuildDirectory,IN BOOLEAN ForceUncompress)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
StringToType(IN CHAR8 * String)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
AdjustFileSize(IN UINT8 * FileBuffer,IN UINT32 FileSize)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
MainEntry(INT32 argc,CHAR8 * argv[],BOOLEAN ForceUncompress)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
main(INT32 argc,CHAR8 * argv[])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
ProcessCommandLineArgs(int Argc,char * Argv[])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
AddMacro(UINT8 * MacroString)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 *
GetMacroValue(UINT8 * MacroName)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
FreeMacros()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
ReplaceMacros(UINT8 * InputFile,UINT8 * OutputFile)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