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