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