]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/GenSec/GenSec.c
BaseTools: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / BaseTools / Source / C / GenSec / GenSec.c
1 /** @file
2 Creates output file that is a properly formed section per the PI spec.
3
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8 #ifndef __GNUC__
9 #include <windows.h>
10 #include <io.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #endif
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19
20 #include <Common/UefiBaseTypes.h>
21 #include <Common/PiFirmwareFile.h>
22 #include <Protocol/GuidedSectionExtraction.h>
23 #include <IndustryStandard/PeImage.h>
24
25 #include "CommonLib.h"
26 #include "Compress.h"
27 #include "Crc32.h"
28 #include "EfiUtilityMsgs.h"
29 #include "ParseInf.h"
30 #include "FvLib.h"
31 #include "PeCoffLib.h"
32
33 //
34 // GenSec Tool Information
35 //
36 #define UTILITY_NAME "GenSec"
37 #define UTILITY_MAJOR_VERSION 0
38 #define UTILITY_MINOR_VERSION 1
39
40 STATIC CHAR8 *mSectionTypeName[] = {
41 NULL, // 0x00 - reserved
42 "EFI_SECTION_COMPRESSION", // 0x01
43 "EFI_SECTION_GUID_DEFINED", // 0x02
44 NULL, // 0x03 - reserved
45 NULL, // 0x04 - reserved
46 NULL, // 0x05 - reserved
47 NULL, // 0x06 - reserved
48 NULL, // 0x07 - reserved
49 NULL, // 0x08 - reserved
50 NULL, // 0x09 - reserved
51 NULL, // 0x0A - reserved
52 NULL, // 0x0B - reserved
53 NULL, // 0x0C - reserved
54 NULL, // 0x0D - reserved
55 NULL, // 0x0E - reserved
56 NULL, // 0x0F - reserved
57 "EFI_SECTION_PE32", // 0x10
58 "EFI_SECTION_PIC", // 0x11
59 "EFI_SECTION_TE", // 0x12
60 "EFI_SECTION_DXE_DEPEX", // 0x13
61 "EFI_SECTION_VERSION", // 0x14
62 "EFI_SECTION_USER_INTERFACE", // 0x15
63 "EFI_SECTION_COMPATIBILITY16", // 0x16
64 "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // 0x17
65 "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // 0x18
66 "EFI_SECTION_RAW", // 0x19
67 NULL, // 0x1A
68 "EFI_SECTION_PEI_DEPEX", // 0x1B
69 "EFI_SECTION_SMM_DEPEX" // 0x1C
70 };
71
72 STATIC CHAR8 *mCompressionTypeName[] = { "PI_NONE", "PI_STD" };
73
74 #define EFI_GUIDED_SECTION_NONE 0x80
75 STATIC CHAR8 *mGUIDedSectionAttribue[] = { "NONE", "PROCESSING_REQUIRED", "AUTH_STATUS_VALID"};
76
77 STATIC CHAR8 *mAlignName[] = {
78 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",
79 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",
80 "512K", "1M", "2M", "4M", "8M", "16M"
81 };
82
83 //
84 // Crc32 GUID section related definitions.
85 //
86 typedef struct {
87 EFI_GUID_DEFINED_SECTION GuidSectionHeader;
88 UINT32 CRC32Checksum;
89 } CRC32_SECTION_HEADER;
90
91 typedef struct {
92 EFI_GUID_DEFINED_SECTION2 GuidSectionHeader;
93 UINT32 CRC32Checksum;
94 } CRC32_SECTION_HEADER2;
95
96 STATIC EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
97 STATIC EFI_GUID mEfiCrc32SectionGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
98
99 STATIC
100 VOID
101 Version (
102 VOID
103 )
104 /*++
105
106 Routine Description:
107
108 Print out version information for this utility.
109
110 Arguments:
111
112 None
113
114 Returns:
115
116 None
117
118 --*/
119 {
120 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
121 }
122
123 STATIC
124 VOID
125 Usage (
126 VOID
127 )
128 /*++
129
130 Routine Description:
131
132 Print Help message.
133
134 Arguments:
135
136 VOID
137
138 Returns:
139
140 None
141
142 --*/
143 {
144 //
145 // Summary usage
146 //
147 fprintf (stdout, "\nUsage: %s [options] [input_file]\n\n", UTILITY_NAME);
148
149 //
150 // Copyright declaration
151 //
152 fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
153
154 //
155 // Details Option
156 //
157 fprintf (stdout, "Options:\n");
158 fprintf (stdout, " -o FileName, --outputfile FileName\n\
159 File is the SectionFile to be created.\n");
160 fprintf (stdout, " -s [SectionType], --sectiontype [SectionType]\n\
161 SectionType defined in PI spec is one type of\n\
162 EFI_SECTION_COMPRESSION, EFI_SECTION_GUID_DEFINED,\n\
163 EFI_SECTION_PE32, EFI_SECTION_PIC, EFI_SECTION_TE,\n\
164 EFI_SECTION_DXE_DEPEX, EFI_SECTION_COMPATIBILITY16,\n\
165 EFI_SECTION_USER_INTERFACE, EFI_SECTION_VERSION,\n\
166 EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EFI_SECTION_RAW,\n\
167 EFI_SECTION_FREEFORM_SUBTYPE_GUID,\n\
168 EFI_SECTION_PEI_DEPEX, EFI_SECTION_SMM_DEPEX.\n\
169 if -s option is not given, \n\
170 EFI_SECTION_ALL is default section type.\n");
171 fprintf (stdout, " -c [Type], --compress [Type]\n\
172 Compress method type can be PI_NONE or PI_STD.\n\
173 if -c option is not given, PI_STD is default type.\n");
174 fprintf (stdout, " -g GuidValue, --vendor GuidValue\n\
175 GuidValue is one specific vendor guid value.\n\
176 Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");
177 fprintf (stdout, " -l GuidHeaderLength, --HeaderLength GuidHeaderLength\n\
178 GuidHeaderLength is the size of header of guided data\n");
179 fprintf (stdout, " -r GuidAttr, --attributes GuidAttr\n\
180 GuidAttr is guid section atttributes, which may be\n\
181 PROCESSING_REQUIRED, AUTH_STATUS_VALID and NONE. \n\
182 if -r option is not given, default PROCESSING_REQUIRED\n");
183 fprintf (stdout, " -n String, --name String\n\
184 String is a NULL terminated string used in Ui section.\n");
185 fprintf (stdout, " -j Number, --buildnumber Number\n\
186 Number is an integer value between 0 and 65535\n\
187 used in Ver section.\n");
188 fprintf (stdout, " --sectionalign SectionAlign\n\
189 SectionAlign points to section alignment, which support\n\
190 the alignment scope 0~16M. If SectionAlign is specified\n\
191 as 0, tool get alignment value from SectionFile. It is\n\
192 specified in same order that the section file is input.\n");
193 fprintf (stdout, " --dummy dummyfile\n\
194 compare dummpyfile with input_file to decide whether\n\
195 need to set PROCESSING_REQUIRED attribute.\n");
196 fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n");
197 fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n");
198 fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n");
199 fprintf (stdout, " --version Show program's version number and exit.\n");
200 fprintf (stdout, " -h, --help Show this help message and exit.\n");
201 }
202
203 VOID
204 Ascii2UnicodeString (
205 CHAR8 *String,
206 CHAR16 *UniString
207 )
208 /*++
209
210 Routine Description:
211
212 Write ascii string as unicode string format to FILE
213
214 Arguments:
215
216 String - Pointer to string that is written to FILE.
217 UniString - Pointer to unicode string
218
219 Returns:
220
221 NULL
222
223 --*/
224 {
225 while (*String != '\0') {
226 *(UniString++) = (CHAR16) *(String++);
227 }
228 //
229 // End the UniString with a NULL.
230 //
231 *UniString = '\0';
232 }
233
234 STATUS
235 GenSectionCommonLeafSection (
236 CHAR8 **InputFileName,
237 UINT32 InputFileNum,
238 UINT8 SectionType,
239 UINT8 **OutFileBuffer
240 )
241 /*++
242
243 Routine Description:
244
245 Generate a leaf section of type other than EFI_SECTION_VERSION
246 and EFI_SECTION_USER_INTERFACE. Input file must be well formed.
247 The function won't validate the input file's contents. For
248 common leaf sections, the input file may be a binary file.
249 The utility will add section header to the file.
250
251 Arguments:
252
253 InputFileName - Name of the input file.
254
255 InputFileNum - Number of input files. Should be 1 for leaf section.
256
257 SectionType - A valid section type string
258
259 OutFileBuffer - Buffer pointer to Output file contents
260
261 Returns:
262
263 STATUS_ERROR - can't continue
264 STATUS_SUCCESS - successful return
265
266 --*/
267 {
268 UINT32 InputFileLength;
269 FILE *InFile;
270 UINT8 *Buffer;
271 UINT32 TotalLength;
272 UINT32 HeaderLength;
273 EFI_COMMON_SECTION_HEADER *CommonSect;
274 STATUS Status;
275
276 if (InputFileNum > 1) {
277 Error (NULL, 0, 2000, "Invalid parameter", "more than one input file specified");
278 return STATUS_ERROR;
279 } else if (InputFileNum < 1) {
280 Error (NULL, 0, 2000, "Invalid parameter", "no input file specified");
281 return STATUS_ERROR;
282 }
283 //
284 // Open the input file
285 //
286 InFile = fopen (LongFilePath (InputFileName[0]), "rb");
287 if (InFile == NULL) {
288 Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);
289 return STATUS_ERROR;
290 }
291
292 Status = STATUS_ERROR;
293 Buffer = NULL;
294 //
295 // Seek to the end of the input file so we can determine its size
296 //
297 fseek (InFile, 0, SEEK_END);
298 InputFileLength = ftell (InFile);
299 fseek (InFile, 0, SEEK_SET);
300 DebugMsg (NULL, 0, 9, "Input file", "File name is %s and File size is %u bytes", InputFileName[0], (unsigned) InputFileLength);
301 TotalLength = sizeof (EFI_COMMON_SECTION_HEADER) + InputFileLength;
302 //
303 // Size must fit in 3 bytes
304 //
305 //if (TotalLength >= MAX_SECTION_SIZE) {
306 // Error (NULL, 0, 2000, "Invalid parameter", "%s file size (0x%X) exceeds section size limit(%uM).", InputFileName[0], (unsigned) TotalLength, MAX_SECTION_SIZE>>20);
307 // goto Done;
308 //}
309 HeaderLength = sizeof (EFI_COMMON_SECTION_HEADER);
310 if (TotalLength >= MAX_SECTION_SIZE) {
311 TotalLength = sizeof (EFI_COMMON_SECTION_HEADER2) + InputFileLength;
312 HeaderLength = sizeof (EFI_COMMON_SECTION_HEADER2);
313 }
314 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
315 //
316 // Fill in the fields in the local section header structure
317 //
318 Buffer = (UINT8 *) malloc ((size_t) TotalLength);
319 if (Buffer == NULL) {
320 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
321 goto Done;
322 }
323 CommonSect = (EFI_COMMON_SECTION_HEADER *) Buffer;
324 CommonSect->Type = SectionType;
325 if (TotalLength < MAX_SECTION_SIZE) {
326 CommonSect->Size[0] = (UINT8) (TotalLength & 0xff);
327 CommonSect->Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
328 CommonSect->Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
329 } else {
330 memset(CommonSect->Size, 0xff, sizeof(UINT8) * 3);
331 ((EFI_COMMON_SECTION_HEADER2 *)CommonSect)->ExtendedSize = TotalLength;
332 }
333
334 //
335 // read data from the input file.
336 //
337 if (InputFileLength != 0) {
338 if (fread (Buffer + HeaderLength, (size_t) InputFileLength, 1, InFile) != 1) {
339 Error (NULL, 0, 0004, "Error reading file", InputFileName[0]);
340 goto Done;
341 }
342 }
343
344 //
345 // Set OutFileBuffer
346 //
347 *OutFileBuffer = Buffer;
348 Status = STATUS_SUCCESS;
349
350 Done:
351 fclose (InFile);
352
353 return Status;
354 }
355
356 STATIC
357 EFI_STATUS
358 StringtoAlignment (
359 IN CHAR8 *AlignBuffer,
360 OUT UINT32 *AlignNumber
361 )
362 /*++
363
364 Routine Description:
365
366 Converts Align String to align value (1~16M).
367
368 Arguments:
369
370 AlignBuffer - Pointer to Align string.
371 AlignNumber - Pointer to Align value.
372
373 Returns:
374
375 EFI_SUCCESS Successfully convert align string to align value.
376 EFI_INVALID_PARAMETER Align string is invalid or align value is not in scope.
377
378 --*/
379 {
380 UINT32 Index = 0;
381 //
382 // Check AlignBuffer
383 //
384 if (AlignBuffer == NULL) {
385 return EFI_INVALID_PARAMETER;
386 }
387 for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) {
388 if (stricmp (AlignBuffer, mAlignName [Index]) == 0) {
389 *AlignNumber = 1 << Index;
390 return EFI_SUCCESS;
391 }
392 }
393 return EFI_INVALID_PARAMETER;
394 }
395
396 EFI_STATUS
397 GetSectionContents (
398 CHAR8 **InputFileName,
399 UINT32 *InputFileAlign,
400 UINT32 InputFileNum,
401 UINT8 *FileBuffer,
402 UINT32 *BufferLength
403 )
404 /*++
405
406 Routine Description:
407
408 Get the contents of all section files specified in InputFileName
409 into FileBuffer.
410
411 Arguments:
412
413 InputFileName - Name of the input file.
414
415 InputFileAlign - Alignment required by the input file data.
416
417 InputFileNum - Number of input files. Should be at least 1.
418
419 FileBuffer - Output buffer to contain data
420
421 BufferLength - On input, this is size of the FileBuffer.
422 On output, this is the actual length of the data.
423
424 Returns:
425
426 EFI_SUCCESS on successful return
427 EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL.
428 EFI_ABORTED if unable to open input file.
429 EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data.
430 --*/
431 {
432 UINT32 Size;
433 UINT32 Offset;
434 UINT32 FileSize;
435 UINT32 Index;
436 FILE *InFile;
437 EFI_COMMON_SECTION_HEADER *SectHeader;
438 EFI_COMMON_SECTION_HEADER2 TempSectHeader;
439 EFI_TE_IMAGE_HEADER TeHeader;
440 UINT32 TeOffset;
441 EFI_GUID_DEFINED_SECTION GuidSectHeader;
442 EFI_GUID_DEFINED_SECTION2 GuidSectHeader2;
443 UINT32 HeaderSize;
444
445 if (InputFileNum < 1) {
446 Error (NULL, 0, 2000, "Invalid parameter", "must specify at least one input file");
447 return EFI_INVALID_PARAMETER;
448 }
449
450 if (BufferLength == NULL) {
451 Error (NULL, 0, 2000, "Invalid parameter", "BufferLength can't be NULL");
452 return EFI_INVALID_PARAMETER;
453 }
454
455 Size = 0;
456 Offset = 0;
457 TeOffset = 0;
458 //
459 // Go through our array of file names and copy their contents
460 // to the output buffer.
461 //
462 for (Index = 0; Index < InputFileNum; Index++) {
463 //
464 // make sure section ends on a DWORD boundary
465 //
466 while ((Size & 0x03) != 0) {
467 if (FileBuffer != NULL && Size < *BufferLength) {
468 FileBuffer[Size] = 0;
469 }
470 Size++;
471 }
472
473 //
474 // Open file and read contents
475 //
476 InFile = fopen (LongFilePath (InputFileName[Index]), "rb");
477 if (InFile == NULL) {
478 Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);
479 return EFI_ABORTED;
480 }
481
482 fseek (InFile, 0, SEEK_END);
483 FileSize = ftell (InFile);
484 fseek (InFile, 0, SEEK_SET);
485 DebugMsg (NULL, 0, 9, "Input files", "the input file name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize);
486 //
487 // Adjust section buffer when section alignment is required.
488 //
489 if (InputFileAlign != NULL) {
490 //
491 // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.
492 //
493 TeOffset = 0;
494 //
495 // The section might be EFI_COMMON_SECTION_HEADER2
496 // But only Type needs to be checked
497 //
498 if (FileSize >= MAX_SECTION_SIZE) {
499 HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2);
500 } else {
501 HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);
502 }
503 fread (&TempSectHeader, 1, HeaderSize, InFile);
504 if (TempSectHeader.Type == EFI_SECTION_TE) {
505 fread (&TeHeader, 1, sizeof (TeHeader), InFile);
506 if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
507 TeOffset = TeHeader.StrippedSize - sizeof (TeHeader);
508 }
509 } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) {
510 fseek (InFile, 0, SEEK_SET);
511 if (FileSize >= MAX_SECTION_SIZE) {
512 fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile);
513 if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
514 HeaderSize = GuidSectHeader2.DataOffset;
515 }
516 } else {
517 fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);
518 if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {
519 HeaderSize = GuidSectHeader.DataOffset;
520 }
521 }
522 }
523
524 fseek (InFile, 0, SEEK_SET);
525
526 //
527 // Revert TeOffset to the converse value relative to Alignment
528 // This is to assure the original PeImage Header at Alignment.
529 //
530 if (TeOffset != 0) {
531 TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);
532 TeOffset = TeOffset % InputFileAlign [Index];
533 }
534
535 //
536 // make sure section data meet its alignment requirement by adding one raw pad section.
537 //
538 if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {
539 Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);
540 Offset = Offset - Size - HeaderSize - TeOffset;
541
542 if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {
543 //
544 // The maximal alignment is 64K, the raw section size must be less than 0xffffff
545 //
546 memset (FileBuffer + Size, 0, Offset);
547 SectHeader = (EFI_COMMON_SECTION_HEADER *) (FileBuffer + Size);
548 SectHeader->Type = EFI_SECTION_RAW;
549 SectHeader->Size[0] = (UINT8) (Offset & 0xff);
550 SectHeader->Size[1] = (UINT8) ((Offset & 0xff00) >> 8);
551 SectHeader->Size[2] = (UINT8) ((Offset & 0xff0000) >> 16);
552 }
553 DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", "Pad Raw section size is %u", (unsigned) Offset);
554
555 Size = Size + Offset;
556 }
557 }
558
559 //
560 // Now read the contents of the file into the buffer
561 // Buffer must be enough to contain the file content.
562 //
563 if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {
564 if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {
565 Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);
566 fclose (InFile);
567 return EFI_ABORTED;
568 }
569 }
570
571 fclose (InFile);
572 Size += FileSize;
573 }
574
575 //
576 // Set the real required buffer size.
577 //
578 if (Size > *BufferLength) {
579 *BufferLength = Size;
580 return EFI_BUFFER_TOO_SMALL;
581 } else {
582 *BufferLength = Size;
583 return EFI_SUCCESS;
584 }
585 }
586
587 EFI_STATUS
588 GenSectionCompressionSection (
589 CHAR8 **InputFileName,
590 UINT32 *InputFileAlign,
591 UINT32 InputFileNum,
592 UINT8 SectCompSubType,
593 UINT8 **OutFileBuffer
594 )
595 /*++
596
597 Routine Description:
598
599 Generate an encapsulating section of type EFI_SECTION_COMPRESSION
600 Input file must be already sectioned. The function won't validate
601 the input files' contents. Caller should hand in files already
602 with section header.
603
604 Arguments:
605
606 InputFileName - Name of the input file.
607
608 InputFileAlign - Alignment required by the input file data.
609
610 InputFileNum - Number of input files. Should be at least 1.
611
612 SectCompSubType - Specify the compression algorithm requested.
613
614 OutFileBuffer - Buffer pointer to Output file contents
615
616 Returns:
617
618 EFI_SUCCESS on successful return
619 EFI_INVALID_PARAMETER if InputFileNum is less than 1
620 EFI_ABORTED if unable to open input file.
621 EFI_OUT_OF_RESOURCES No resource to complete the operation.
622 --*/
623 {
624 UINT32 TotalLength;
625 UINT32 InputLength;
626 UINT32 CompressedLength;
627 UINT32 HeaderLength;
628 UINT8 *FileBuffer;
629 UINT8 *OutputBuffer;
630 EFI_STATUS Status;
631 EFI_COMPRESSION_SECTION *CompressionSect;
632 EFI_COMPRESSION_SECTION2 *CompressionSect2;
633 COMPRESS_FUNCTION CompressFunction;
634
635 InputLength = 0;
636 FileBuffer = NULL;
637 OutputBuffer = NULL;
638 CompressedLength = 0;
639 TotalLength = 0;
640 //
641 // read all input file contents into a buffer
642 // first get the size of all file contents
643 //
644 Status = GetSectionContents (
645 InputFileName,
646 InputFileAlign,
647 InputFileNum,
648 FileBuffer,
649 &InputLength
650 );
651
652 if (Status == EFI_BUFFER_TOO_SMALL) {
653 FileBuffer = (UINT8 *) malloc (InputLength);
654 if (FileBuffer == NULL) {
655 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
656 return EFI_OUT_OF_RESOURCES;
657 }
658 //
659 // read all input file contents into a buffer
660 //
661 Status = GetSectionContents (
662 InputFileName,
663 InputFileAlign,
664 InputFileNum,
665 FileBuffer,
666 &InputLength
667 );
668 }
669
670 if (EFI_ERROR (Status)) {
671 if (FileBuffer != NULL) {
672 free (FileBuffer);
673 }
674 return Status;
675 }
676
677 if (FileBuffer == NULL) {
678 return EFI_OUT_OF_RESOURCES;
679 }
680
681 CompressFunction = NULL;
682
683 //
684 // Now data is in FileBuffer, compress the data
685 //
686 switch (SectCompSubType) {
687 case EFI_NOT_COMPRESSED:
688 CompressedLength = InputLength;
689 HeaderLength = sizeof (EFI_COMPRESSION_SECTION);
690 if (CompressedLength + HeaderLength >= MAX_SECTION_SIZE) {
691 HeaderLength = sizeof (EFI_COMPRESSION_SECTION2);
692 }
693 TotalLength = CompressedLength + HeaderLength;
694 //
695 // Copy file buffer to the none compressed data.
696 //
697 OutputBuffer = malloc (TotalLength);
698 if (OutputBuffer == NULL) {
699 free (FileBuffer);
700 return EFI_OUT_OF_RESOURCES;
701 }
702 memcpy (OutputBuffer + HeaderLength, FileBuffer, CompressedLength);
703 free (FileBuffer);
704 FileBuffer = OutputBuffer;
705 break;
706
707 case EFI_STANDARD_COMPRESSION:
708 CompressFunction = (COMPRESS_FUNCTION) EfiCompress;
709 break;
710
711 default:
712 Error (NULL, 0, 2000, "Invalid parameter", "unknown compression type");
713 free (FileBuffer);
714 return EFI_ABORTED;
715 }
716
717 if (CompressFunction != NULL) {
718
719 Status = CompressFunction (FileBuffer, InputLength, OutputBuffer, &CompressedLength);
720 if (Status == EFI_BUFFER_TOO_SMALL) {
721 HeaderLength = sizeof (EFI_COMPRESSION_SECTION);
722 if (CompressedLength + HeaderLength >= MAX_SECTION_SIZE) {
723 HeaderLength = sizeof (EFI_COMPRESSION_SECTION2);
724 }
725 TotalLength = CompressedLength + HeaderLength;
726 OutputBuffer = malloc (TotalLength);
727 if (!OutputBuffer) {
728 free (FileBuffer);
729 return EFI_OUT_OF_RESOURCES;
730 }
731
732 Status = CompressFunction (FileBuffer, InputLength, OutputBuffer + HeaderLength, &CompressedLength);
733 }
734
735 free (FileBuffer);
736 FileBuffer = OutputBuffer;
737
738 if (EFI_ERROR (Status)) {
739 if (FileBuffer != NULL) {
740 free (FileBuffer);
741 }
742
743 return Status;
744 }
745
746 if (FileBuffer == NULL) {
747 return EFI_OUT_OF_RESOURCES;
748 }
749 }
750
751 DebugMsg (NULL, 0, 9, "comprss file size",
752 "the original section size is %d bytes and the compressed section size is %u bytes", (unsigned) InputLength, (unsigned) CompressedLength);
753
754 //if (TotalLength >= MAX_SECTION_SIZE) {
755 // Error (NULL, 0, 2000, "Invalid parameter", "The size of all files exceeds section size limit(%uM).", MAX_SECTION_SIZE>>20);
756 // if (FileBuffer != NULL) {
757 // free (FileBuffer);
758 // }
759 // if (OutputBuffer != NULL) {
760 // free (OutputBuffer);
761 // }
762 // return STATUS_ERROR;
763 //}
764 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
765
766 //
767 // Add the section header for the compressed data
768 //
769 if (TotalLength >= MAX_SECTION_SIZE) {
770 CompressionSect2 = (EFI_COMPRESSION_SECTION2 *)FileBuffer;
771
772 memset(CompressionSect2->CommonHeader.Size, 0xff, sizeof(UINT8) * 3);
773 CompressionSect2->CommonHeader.Type = EFI_SECTION_COMPRESSION;
774 CompressionSect2->CommonHeader.ExtendedSize = TotalLength;
775 CompressionSect2->CompressionType = SectCompSubType;
776 CompressionSect2->UncompressedLength = InputLength;
777 } else {
778 CompressionSect = (EFI_COMPRESSION_SECTION *) FileBuffer;
779
780 CompressionSect->CommonHeader.Type = EFI_SECTION_COMPRESSION;
781 CompressionSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
782 CompressionSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
783 CompressionSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
784 CompressionSect->CompressionType = SectCompSubType;
785 CompressionSect->UncompressedLength = InputLength;
786 }
787
788 //
789 // Set OutFileBuffer
790 //
791 *OutFileBuffer = FileBuffer;
792
793 return EFI_SUCCESS;
794 }
795
796 EFI_STATUS
797 GenSectionGuidDefinedSection (
798 CHAR8 **InputFileName,
799 UINT32 *InputFileAlign,
800 UINT32 InputFileNum,
801 EFI_GUID *VendorGuid,
802 UINT16 DataAttribute,
803 UINT32 DataHeaderSize,
804 UINT8 **OutFileBuffer
805 )
806 /*++
807
808 Routine Description:
809
810 Generate an encapsulating section of type EFI_SECTION_GUID_DEFINED
811 Input file must be already sectioned. The function won't validate
812 the input files' contents. Caller should hand in files already
813 with section header.
814
815 Arguments:
816
817 InputFileName - Name of the input file.
818
819 InputFileAlign - Alignment required by the input file data.
820
821 InputFileNum - Number of input files. Should be at least 1.
822
823 VendorGuid - Specify vendor guid value.
824
825 DataAttribute - Specify attribute for the vendor guid data.
826
827 DataHeaderSize- Guided Data Header Size
828
829 OutFileBuffer - Buffer pointer to Output file contents
830
831 Returns:
832
833 EFI_SUCCESS on successful return
834 EFI_INVALID_PARAMETER if InputFileNum is less than 1
835 EFI_ABORTED if unable to open input file.
836 EFI_OUT_OF_RESOURCES No resource to complete the operation.
837
838 --*/
839 {
840 UINT32 TotalLength;
841 UINT32 InputLength;
842 UINT32 Offset;
843 UINT8 *FileBuffer;
844 UINT32 Crc32Checksum;
845 EFI_STATUS Status;
846 CRC32_SECTION_HEADER *Crc32GuidSect;
847 CRC32_SECTION_HEADER2 *Crc32GuidSect2;
848 EFI_GUID_DEFINED_SECTION *VendorGuidSect;
849 EFI_GUID_DEFINED_SECTION2 *VendorGuidSect2;
850
851 InputLength = 0;
852 Offset = 0;
853 FileBuffer = NULL;
854 TotalLength = 0;
855
856 //
857 // read all input file contents into a buffer
858 // first get the size of all file contents
859 //
860 Status = GetSectionContents (
861 InputFileName,
862 InputFileAlign,
863 InputFileNum,
864 FileBuffer,
865 &InputLength
866 );
867
868 if (Status == EFI_BUFFER_TOO_SMALL) {
869 if (CompareGuid (VendorGuid, &mZeroGuid) == 0) {
870 Offset = sizeof (CRC32_SECTION_HEADER);
871 if (InputLength + Offset >= MAX_SECTION_SIZE) {
872 Offset = sizeof (CRC32_SECTION_HEADER2);
873 }
874 } else {
875 Offset = sizeof (EFI_GUID_DEFINED_SECTION);
876 if (InputLength + Offset >= MAX_SECTION_SIZE) {
877 Offset = sizeof (EFI_GUID_DEFINED_SECTION2);
878 }
879 }
880 TotalLength = InputLength + Offset;
881
882 FileBuffer = (UINT8 *) malloc (InputLength + Offset);
883 if (FileBuffer == NULL) {
884 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
885 return EFI_OUT_OF_RESOURCES;
886 }
887 //
888 // read all input file contents into a buffer
889 //
890 Status = GetSectionContents (
891 InputFileName,
892 InputFileAlign,
893 InputFileNum,
894 FileBuffer + Offset,
895 &InputLength
896 );
897 }
898
899 if (EFI_ERROR (Status)) {
900 if (FileBuffer != NULL) {
901 free (FileBuffer);
902 }
903 Error (NULL, 0, 0001, "Error opening file for reading", InputFileName[0]);
904 return Status;
905 }
906
907 if (InputLength == 0) {
908 if (FileBuffer != NULL) {
909 free (FileBuffer);
910 }
911 Error (NULL, 0, 2000, "Invalid parameter", "the size of input file %s can't be zero", InputFileName);
912 return EFI_NOT_FOUND;
913 }
914
915 //
916 // InputLength != 0, but FileBuffer == NULL means out of resources.
917 //
918 if (FileBuffer == NULL) {
919 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
920 return EFI_OUT_OF_RESOURCES;
921 }
922
923 //
924 // Now data is in FileBuffer + Offset
925 //
926 if (CompareGuid (VendorGuid, &mZeroGuid) == 0) {
927 //
928 // Default Guid section is CRC32.
929 //
930 Crc32Checksum = 0;
931 CalculateCrc32 (FileBuffer + Offset, InputLength, &Crc32Checksum);
932
933 if (TotalLength >= MAX_SECTION_SIZE) {
934 Crc32GuidSect2 = (CRC32_SECTION_HEADER2 *) FileBuffer;
935 Crc32GuidSect2->GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
936 Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[0] = (UINT8) 0xff;
937 Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[1] = (UINT8) 0xff;
938 Crc32GuidSect2->GuidSectionHeader.CommonHeader.Size[2] = (UINT8) 0xff;
939 Crc32GuidSect2->GuidSectionHeader.CommonHeader.ExtendedSize = TotalLength;
940 memcpy (&(Crc32GuidSect2->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
941 Crc32GuidSect2->GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
942 Crc32GuidSect2->GuidSectionHeader.DataOffset = sizeof (CRC32_SECTION_HEADER2);
943 Crc32GuidSect2->CRC32Checksum = Crc32Checksum;
944 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect2->GuidSectionHeader.DataOffset);
945 } else {
946 Crc32GuidSect = (CRC32_SECTION_HEADER *) FileBuffer;
947 Crc32GuidSect->GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
948 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
949 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
950 Crc32GuidSect->GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
951 memcpy (&(Crc32GuidSect->GuidSectionHeader.SectionDefinitionGuid), &mEfiCrc32SectionGuid, sizeof (EFI_GUID));
952 Crc32GuidSect->GuidSectionHeader.Attributes = EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
953 Crc32GuidSect->GuidSectionHeader.DataOffset = sizeof (CRC32_SECTION_HEADER);
954 Crc32GuidSect->CRC32Checksum = Crc32Checksum;
955 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", Crc32GuidSect->GuidSectionHeader.DataOffset);
956 }
957 } else {
958 if (TotalLength >= MAX_SECTION_SIZE) {
959 VendorGuidSect2 = (EFI_GUID_DEFINED_SECTION2 *) FileBuffer;
960 VendorGuidSect2->CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
961 VendorGuidSect2->CommonHeader.Size[0] = (UINT8) 0xff;
962 VendorGuidSect2->CommonHeader.Size[1] = (UINT8) 0xff;
963 VendorGuidSect2->CommonHeader.Size[2] = (UINT8) 0xff;
964 VendorGuidSect2->CommonHeader.ExtendedSize = InputLength + sizeof (EFI_GUID_DEFINED_SECTION2);
965 memcpy (&(VendorGuidSect2->SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));
966 VendorGuidSect2->Attributes = DataAttribute;
967 VendorGuidSect2->DataOffset = (UINT16) (sizeof (EFI_GUID_DEFINED_SECTION2) + DataHeaderSize);
968 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", VendorGuidSect2->DataOffset);
969 } else {
970 VendorGuidSect = (EFI_GUID_DEFINED_SECTION *) FileBuffer;
971 VendorGuidSect->CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
972 VendorGuidSect->CommonHeader.Size[0] = (UINT8) (TotalLength & 0xff);
973 VendorGuidSect->CommonHeader.Size[1] = (UINT8) ((TotalLength & 0xff00) >> 8);
974 VendorGuidSect->CommonHeader.Size[2] = (UINT8) ((TotalLength & 0xff0000) >> 16);
975 memcpy (&(VendorGuidSect->SectionDefinitionGuid), VendorGuid, sizeof (EFI_GUID));
976 VendorGuidSect->Attributes = DataAttribute;
977 VendorGuidSect->DataOffset = (UINT16) (sizeof (EFI_GUID_DEFINED_SECTION) + DataHeaderSize);
978 DebugMsg (NULL, 0, 9, "Guided section", "Data offset is %u", VendorGuidSect->DataOffset);
979 }
980 }
981 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) TotalLength);
982
983 //
984 // Set OutFileBuffer
985 //
986 *OutFileBuffer = FileBuffer;
987
988 return EFI_SUCCESS;
989 }
990
991 EFI_STATUS
992 FfsRebaseImageRead (
993 IN VOID *FileHandle,
994 IN UINTN FileOffset,
995 IN OUT UINT32 *ReadSize,
996 OUT VOID *Buffer
997 )
998 /*++
999
1000 Routine Description:
1001
1002 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
1003
1004 Arguments:
1005
1006 FileHandle - The handle to the PE/COFF file
1007
1008 FileOffset - The offset, in bytes, into the file to read
1009
1010 ReadSize - The number of bytes to read from the file starting at FileOffset
1011
1012 Buffer - A pointer to the buffer to read the data into.
1013
1014 Returns:
1015
1016 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
1017
1018 --*/
1019 {
1020 CHAR8 *Destination8;
1021 CHAR8 *Source8;
1022 UINT32 Length;
1023
1024 Destination8 = Buffer;
1025 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
1026 Length = *ReadSize;
1027 while (Length--) {
1028 *(Destination8++) = *(Source8++);
1029 }
1030
1031 return EFI_SUCCESS;
1032 }
1033
1034 STATIC
1035 EFI_STATUS
1036 GetAlignmentFromFile(char *InFile, UINT32 *Alignment)
1037 /*
1038 InFile is input file for getting alignment
1039 return the alignment
1040 */
1041 {
1042 FILE *InFileHandle;
1043 UINT8 *PeFileBuffer;
1044 UINTN PeFileSize;
1045 UINT32 CurSecHdrSize;
1046 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
1047 EFI_COMMON_SECTION_HEADER *CommonHeader;
1048 EFI_STATUS Status;
1049
1050 InFileHandle = NULL;
1051 PeFileBuffer = NULL;
1052 *Alignment = 0;
1053
1054 memset (&ImageContext, 0, sizeof (ImageContext));
1055
1056 InFileHandle = fopen(LongFilePath(InFile), "rb");
1057 if (InFileHandle == NULL){
1058 Error (NULL, 0, 0001, "Error opening file", InFile);
1059 return EFI_ABORTED;
1060 }
1061 PeFileSize = _filelength (fileno(InFileHandle));
1062 PeFileBuffer = (UINT8 *) malloc (PeFileSize);
1063 if (PeFileBuffer == NULL) {
1064 fclose (InFileHandle);
1065 Error(NULL, 0, 4001, "Resource", "memory cannot be allocated of %s", InFileHandle);
1066 return EFI_OUT_OF_RESOURCES;
1067 }
1068 fread (PeFileBuffer, sizeof (UINT8), PeFileSize, InFileHandle);
1069 fclose (InFileHandle);
1070 CommonHeader = (EFI_COMMON_SECTION_HEADER *) PeFileBuffer;
1071 CurSecHdrSize = GetSectionHeaderLength(CommonHeader);
1072 ImageContext.Handle = (VOID *) ((UINTN)PeFileBuffer + CurSecHdrSize);
1073 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)FfsRebaseImageRead;
1074 Status = PeCoffLoaderGetImageInfo(&ImageContext);
1075 if (EFI_ERROR (Status)) {
1076 Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and return status is %x", InFile, (int) Status);
1077 return Status;
1078 }
1079 *Alignment = ImageContext.SectionAlignment;
1080 // Free the allocated memory resource
1081 if (PeFileBuffer != NULL) {
1082 free (PeFileBuffer);
1083 PeFileBuffer = NULL;
1084 }
1085 return EFI_SUCCESS;
1086 }
1087
1088 int
1089 main (
1090 int argc,
1091 char *argv[]
1092 )
1093 /*++
1094
1095 Routine Description:
1096
1097 Main
1098
1099 Arguments:
1100
1101 command line parameters
1102
1103 Returns:
1104
1105 EFI_SUCCESS Section header successfully generated and section concatenated.
1106 EFI_ABORTED Could not generate the section
1107 EFI_OUT_OF_RESOURCES No resource to complete the operation.
1108
1109 --*/
1110 {
1111 UINT32 Index;
1112 UINT32 InputFileNum;
1113 FILE *OutFile;
1114 CHAR8 **InputFileName;
1115 CHAR8 *OutputFileName;
1116 CHAR8 *SectionName;
1117 CHAR8 *CompressionName;
1118 CHAR8 *StringBuffer;
1119 EFI_GUID VendorGuid = mZeroGuid;
1120 int VersionNumber;
1121 UINT8 SectType;
1122 UINT8 SectCompSubType;
1123 UINT16 SectGuidAttribute;
1124 UINT64 SectGuidHeaderLength;
1125 EFI_VERSION_SECTION *VersionSect;
1126 EFI_USER_INTERFACE_SECTION *UiSect;
1127 UINT32 InputLength;
1128 UINT8 *OutFileBuffer;
1129 EFI_STATUS Status;
1130 UINT64 LogLevel;
1131 UINT32 *InputFileAlign;
1132 UINT32 InputFileAlignNum;
1133 EFI_COMMON_SECTION_HEADER *SectionHeader;
1134 CHAR8 *DummyFileName;
1135 FILE *DummyFile;
1136 UINTN DummyFileSize;
1137 UINT8 *DummyFileBuffer;
1138 FILE *InFile;
1139 UINT8 *InFileBuffer;
1140 UINTN InFileSize;
1141
1142 InputFileAlign = NULL;
1143 InputFileAlignNum = 0;
1144 InputFileName = NULL;
1145 OutputFileName = NULL;
1146 SectionName = NULL;
1147 CompressionName = NULL;
1148 StringBuffer = "";
1149 OutFile = NULL;
1150 VersionNumber = 0;
1151 InputFileNum = 0;
1152 SectType = EFI_SECTION_ALL;
1153 SectCompSubType = 0;
1154 SectGuidAttribute = EFI_GUIDED_SECTION_NONE;
1155 OutFileBuffer = NULL;
1156 InputLength = 0;
1157 Status = STATUS_SUCCESS;
1158 LogLevel = 0;
1159 SectGuidHeaderLength = 0;
1160 VersionSect = NULL;
1161 UiSect = NULL;
1162 DummyFileSize = 0;
1163 DummyFileName = NULL;
1164 DummyFile = NULL;
1165 DummyFileBuffer = NULL;
1166 InFile = NULL;
1167 InFileSize = 0;
1168 InFileBuffer = NULL;
1169
1170 SetUtilityName (UTILITY_NAME);
1171
1172 if (argc == 1) {
1173 Error (NULL, 0, 1001, "Missing options", "No options input");
1174 Usage ();
1175 return STATUS_ERROR;
1176 }
1177
1178 //
1179 // Parse command line
1180 //
1181 argc --;
1182 argv ++;
1183
1184 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
1185 Version ();
1186 Usage ();
1187 return STATUS_SUCCESS;
1188 }
1189
1190 if (stricmp (argv[0], "--version") == 0) {
1191 Version ();
1192 return STATUS_SUCCESS;
1193 }
1194
1195 while (argc > 0) {
1196 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--SectionType") == 0)) {
1197 SectionName = argv[1];
1198 if (SectionName == NULL) {
1199 Error (NULL, 0, 1003, "Invalid option value", "Section Type can't be NULL");
1200 goto Finish;
1201 }
1202 argc -= 2;
1203 argv += 2;
1204 continue;
1205 }
1206
1207 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {
1208 OutputFileName = argv[1];
1209 if (OutputFileName == NULL) {
1210 Error (NULL, 0, 1003, "Invalid option value", "Output file can't be NULL");
1211 goto Finish;
1212 }
1213 argc -= 2;
1214 argv += 2;
1215 continue;
1216 }
1217
1218 if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--compress") == 0)) {
1219 CompressionName = argv[1];
1220 if (CompressionName == NULL) {
1221 Error (NULL, 0, 1003, "Invalid option value", "Compression Type can't be NULL");
1222 goto Finish;
1223 }
1224 argc -= 2;
1225 argv += 2;
1226 continue;
1227 }
1228
1229 if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--vendor") == 0)) {
1230 Status = StringToGuid (argv[1], &VendorGuid);
1231 if (EFI_ERROR (Status)) {
1232 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1233 goto Finish;
1234 }
1235 argc -= 2;
1236 argv += 2;
1237 continue;
1238 }
1239 if (stricmp (argv[0], "--dummy") == 0) {
1240 DummyFileName = argv[1];
1241 if (DummyFileName == NULL) {
1242 Error (NULL, 0, 1003, "Invalid option value", "Dummy file can't be NULL");
1243 goto Finish;
1244 }
1245 argc -= 2;
1246 argv += 2;
1247 continue;
1248 }
1249
1250 if ((stricmp (argv[0], "-r") == 0) || (stricmp (argv[0], "--attributes") == 0)) {
1251 if (argv[1] == NULL) {
1252 Error (NULL, 0, 1003, "Invalid option value", "Guid section attributes can't be NULL");
1253 goto Finish;
1254 }
1255 if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]) == 0) {
1256 SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
1257 } else if (stricmp (argv[1], mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]) == 0) {
1258 SectGuidAttribute |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
1259 } else if (stricmp (argv[1], mGUIDedSectionAttribue[0]) == 0) {
1260 //
1261 // NONE attribute
1262 //
1263 SectGuidAttribute |= EFI_GUIDED_SECTION_NONE;
1264 } else {
1265 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1266 goto Finish;
1267 }
1268 argc -= 2;
1269 argv += 2;
1270 continue;
1271 }
1272
1273 if ((stricmp (argv[0], "-l") == 0) || (stricmp (argv[0], "--HeaderLength") == 0)) {
1274 Status = AsciiStringToUint64 (argv[1], FALSE, &SectGuidHeaderLength);
1275 if (EFI_ERROR (Status)) {
1276 Error (NULL, 0, 1003, "Invalid option value for GuidHeaderLength", "%s = %s", argv[0], argv[1]);
1277 goto Finish;
1278 }
1279 argc -= 2;
1280 argv += 2;
1281 continue;
1282 }
1283
1284 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--name") == 0)) {
1285 StringBuffer = argv[1];
1286 if (StringBuffer == NULL) {
1287 Error (NULL, 0, 1003, "Invalid option value", "Name can't be NULL");
1288 goto Finish;
1289 }
1290 argc -= 2;
1291 argv += 2;
1292 continue;
1293 }
1294
1295 if ((stricmp (argv[0], "-j") == 0) || (stricmp (argv[0], "--buildnumber") == 0)) {
1296 if (argv[1] == NULL) {
1297 Error (NULL, 0, 1003, "Invalid option value", "build number can't be NULL");
1298 goto Finish;
1299 }
1300 //
1301 // Verify string is a integrator number
1302 //
1303 for (Index = 0; Index < strlen (argv[1]); Index++) {
1304 if ((argv[1][Index] != '-') && (isdigit ((int)argv[1][Index]) == 0)) {
1305 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1306 goto Finish;
1307 }
1308 }
1309
1310 sscanf (argv[1], "%d", &VersionNumber);
1311 argc -= 2;
1312 argv += 2;
1313 continue;
1314 }
1315
1316 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {
1317 SetPrintLevel (VERBOSE_LOG_LEVEL);
1318 VerboseMsg ("Verbose output Mode Set!");
1319 argc --;
1320 argv ++;
1321 continue;
1322 }
1323
1324 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
1325 SetPrintLevel (KEY_LOG_LEVEL);
1326 KeyMsg ("Quiet output Mode Set!");
1327 argc --;
1328 argv ++;
1329 continue;
1330 }
1331
1332 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {
1333 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);
1334 if (EFI_ERROR (Status)) {
1335 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1336 goto Finish;
1337 }
1338 if (LogLevel > 9) {
1339 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0~9, current input level is %d", (int) LogLevel);
1340 goto Finish;
1341 }
1342 SetPrintLevel (LogLevel);
1343 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);
1344 argc -= 2;
1345 argv += 2;
1346 continue;
1347 }
1348
1349 //
1350 // Section File alignment requirement
1351 //
1352 if (stricmp (argv[0], "--sectionalign") == 0) {
1353 if (InputFileAlignNum == 0) {
1354 InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
1355 if (InputFileAlign == NULL) {
1356 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1357 goto Finish;
1358 }
1359 memset (InputFileAlign, 1, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));
1360 } else if (InputFileAlignNum % MAXIMUM_INPUT_FILE_NUM == 0) {
1361 InputFileAlign = (UINT32 *) realloc (
1362 InputFileAlign,
1363 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)
1364 );
1365
1366 if (InputFileAlign == NULL) {
1367 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
1368 goto Finish;
1369 }
1370 memset (&(InputFileAlign[InputFileNum]), 1, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));
1371 }
1372 if (stricmp(argv[1], "0") == 0) {
1373 InputFileAlign[InputFileAlignNum] = 0;
1374 } else {
1375 Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileAlignNum]));
1376 if (EFI_ERROR (Status)) {
1377 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);
1378 goto Finish;
1379 }
1380 }
1381 argc -= 2;
1382 argv += 2;
1383 InputFileAlignNum ++;
1384 continue;
1385 }
1386
1387 //
1388 // Get Input file name
1389 //
1390 if ((InputFileNum == 0) && (InputFileName == NULL)) {
1391 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));
1392 if (InputFileName == NULL) {
1393 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1394 goto Finish;
1395 }
1396 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
1397 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {
1398 //
1399 // InputFileName buffer too small, need to realloc
1400 //
1401 InputFileName = (CHAR8 **) realloc (
1402 InputFileName,
1403 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)
1404 );
1405
1406 if (InputFileName == NULL) {
1407 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1408 goto Finish;
1409 }
1410 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));
1411 }
1412
1413 InputFileName[InputFileNum++] = argv[0];
1414 argc --;
1415 argv ++;
1416 }
1417
1418 if (InputFileAlignNum > 0 && InputFileAlignNum != InputFileNum) {
1419 Error (NULL, 0, 1003, "Invalid option", "section alignment must be set for each section");
1420 goto Finish;
1421 }
1422 for (Index = 0; Index < InputFileAlignNum; Index++)
1423 {
1424 if (InputFileAlign[Index] == 0) {
1425 Status = GetAlignmentFromFile(InputFileName[Index], &(InputFileAlign[Index]));
1426 if (EFI_ERROR(Status)) {
1427 Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);
1428 goto Finish;
1429 }
1430 }
1431 }
1432
1433 VerboseMsg ("%s tool start.", UTILITY_NAME);
1434
1435 if (DummyFileName != NULL) {
1436 //
1437 // Open file and read contents
1438 //
1439 DummyFile = fopen (LongFilePath (DummyFileName), "rb");
1440 if (DummyFile == NULL) {
1441 Error (NULL, 0, 0001, "Error opening file", DummyFileName);
1442 goto Finish;
1443 }
1444
1445 fseek (DummyFile, 0, SEEK_END);
1446 DummyFileSize = ftell (DummyFile);
1447 fseek (DummyFile, 0, SEEK_SET);
1448 DummyFileBuffer = (UINT8 *) malloc (DummyFileSize);
1449 if (DummyFileBuffer == NULL) {
1450 fclose(DummyFile);
1451 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1452 goto Finish;
1453 }
1454
1455 fread(DummyFileBuffer, 1, DummyFileSize, DummyFile);
1456 fclose(DummyFile);
1457 DebugMsg (NULL, 0, 9, "Dummy files", "the dummy file name is %s and the size is %u bytes", DummyFileName, (unsigned) DummyFileSize);
1458
1459 if (InputFileName == NULL) {
1460 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1461 goto Finish;
1462 }
1463 InFile = fopen(LongFilePath(InputFileName[0]), "rb");
1464 if (InFile == NULL) {
1465 Error (NULL, 0, 0001, "Error opening file", InputFileName[0]);
1466 goto Finish;
1467 }
1468
1469 fseek (InFile, 0, SEEK_END);
1470 InFileSize = ftell (InFile);
1471 fseek (InFile, 0, SEEK_SET);
1472 InFileBuffer = (UINT8 *) malloc (InFileSize);
1473 if (InFileBuffer == NULL) {
1474 fclose(InFile);
1475 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1476 goto Finish;
1477 }
1478
1479 fread(InFileBuffer, 1, InFileSize, InFile);
1480 fclose(InFile);
1481 DebugMsg (NULL, 0, 9, "Input files", "the input file name is %s and the size is %u bytes", InputFileName[0], (unsigned) InFileSize);
1482 if (InFileSize > DummyFileSize){
1483 if (stricmp((CHAR8 *)DummyFileBuffer, (CHAR8 *)(InFileBuffer + (InFileSize - DummyFileSize))) == 0){
1484 SectGuidHeaderLength = InFileSize - DummyFileSize;
1485 }
1486 }
1487 if (SectGuidHeaderLength == 0) {
1488 SectGuidAttribute |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
1489 }
1490 if (DummyFileBuffer != NULL) {
1491 free (DummyFileBuffer);
1492 DummyFileBuffer = NULL;
1493 }
1494 if (InFileBuffer != NULL) {
1495 free (InFileBuffer);
1496 }
1497 }
1498
1499 //
1500 // Parse all command line parameters to get the corresponding section type.
1501 //
1502 VerboseMsg ("Section type is %s", SectionName);
1503 if (SectionName == NULL) {
1504 //
1505 // No specified Section type, default is SECTION_ALL.
1506 //
1507 SectType = EFI_SECTION_ALL;
1508 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPRESSION]) == 0) {
1509 SectType = EFI_SECTION_COMPRESSION;
1510 if (CompressionName == NULL) {
1511 //
1512 // Default is PI_STD compression algorithm.
1513 //
1514 SectCompSubType = EFI_STANDARD_COMPRESSION;
1515 } else if (stricmp (CompressionName, mCompressionTypeName[EFI_NOT_COMPRESSED]) == 0) {
1516 SectCompSubType = EFI_NOT_COMPRESSED;
1517 } else if (stricmp (CompressionName, mCompressionTypeName[EFI_STANDARD_COMPRESSION]) == 0) {
1518 SectCompSubType = EFI_STANDARD_COMPRESSION;
1519 } else {
1520 Error (NULL, 0, 1003, "Invalid option value", "--compress = %s", CompressionName);
1521 goto Finish;
1522 }
1523 VerboseMsg ("Compress method is %s", mCompressionTypeName [SectCompSubType]);
1524 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_GUID_DEFINED]) == 0) {
1525 SectType = EFI_SECTION_GUID_DEFINED;
1526
1527 if ((SectGuidAttribute & EFI_GUIDED_SECTION_NONE) != 0) {
1528 //
1529 // NONE attribute, clear attribute value.
1530 //
1531 SectGuidAttribute = SectGuidAttribute & ~EFI_GUIDED_SECTION_NONE;
1532 }
1533 VerboseMsg ("Vendor Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1534 (unsigned) VendorGuid.Data1,
1535 VendorGuid.Data2,
1536 VendorGuid.Data3,
1537 VendorGuid.Data4[0],
1538 VendorGuid.Data4[1],
1539 VendorGuid.Data4[2],
1540 VendorGuid.Data4[3],
1541 VendorGuid.Data4[4],
1542 VendorGuid.Data4[5],
1543 VendorGuid.Data4[6],
1544 VendorGuid.Data4[7]);
1545 if ((SectGuidAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) {
1546 VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_PROCESSING_REQUIRED]);
1547 }
1548 if ((SectGuidAttribute & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) != 0) {
1549 VerboseMsg ("Guid Attribute is %s", mGUIDedSectionAttribue[EFI_GUIDED_SECTION_AUTH_STATUS_VALID]);
1550 }
1551 if (SectGuidHeaderLength != 0) {
1552 VerboseMsg ("Guid Data Header size is 0x%llx", (unsigned long long) SectGuidHeaderLength);
1553 }
1554 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PE32]) == 0) {
1555 SectType = EFI_SECTION_PE32;
1556 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PIC]) == 0) {
1557 SectType = EFI_SECTION_PIC;
1558 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_TE]) == 0) {
1559 SectType = EFI_SECTION_TE;
1560 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_DXE_DEPEX]) == 0) {
1561 SectType = EFI_SECTION_DXE_DEPEX;
1562 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_SMM_DEPEX]) == 0) {
1563 SectType = EFI_SECTION_SMM_DEPEX;
1564 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_VERSION]) == 0) {
1565 SectType = EFI_SECTION_VERSION;
1566 if (VersionNumber < 0 || VersionNumber > 65535) {
1567 Error (NULL, 0, 1003, "Invalid option value", "%d is not in 0~65535", VersionNumber);
1568 goto Finish;
1569 }
1570 VerboseMsg ("Version section number is %d", VersionNumber);
1571 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_USER_INTERFACE]) == 0) {
1572 SectType = EFI_SECTION_USER_INTERFACE;
1573 if (StringBuffer[0] == '\0') {
1574 Error (NULL, 0, 1001, "Missing option", "user interface string");
1575 goto Finish;
1576 }
1577 VerboseMsg ("UI section string name is %s", StringBuffer);
1578 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_COMPATIBILITY16]) == 0) {
1579 SectType = EFI_SECTION_COMPATIBILITY16;
1580 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FIRMWARE_VOLUME_IMAGE]) == 0) {
1581 SectType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
1582 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_FREEFORM_SUBTYPE_GUID]) == 0) {
1583 SectType = EFI_SECTION_FREEFORM_SUBTYPE_GUID;
1584 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_RAW]) == 0) {
1585 SectType = EFI_SECTION_RAW;
1586 } else if (stricmp (SectionName, mSectionTypeName[EFI_SECTION_PEI_DEPEX]) == 0) {
1587 SectType = EFI_SECTION_PEI_DEPEX;
1588 } else {
1589 Error (NULL, 0, 1003, "Invalid option value", "SectionType = %s", SectionName);
1590 goto Finish;
1591 }
1592
1593 //
1594 // GuidValue is only required by Guided section.
1595 //
1596 if ((SectType != EFI_SECTION_GUID_DEFINED) &&
1597 (SectionName != NULL) &&
1598 (CompareGuid (&VendorGuid, &mZeroGuid) != 0)) {
1599 fprintf (stdout, "Warning: the input guid value is not required for this section type %s\n", SectionName);
1600 }
1601
1602 //
1603 // Check whether there is input file
1604 //
1605 if ((SectType != EFI_SECTION_VERSION) && (SectType != EFI_SECTION_USER_INTERFACE)) {
1606 //
1607 // The input file are required for other section type.
1608 //
1609 if (InputFileNum == 0) {
1610 Error (NULL, 0, 1001, "Missing options", "Input files");
1611 goto Finish;
1612 }
1613 }
1614 //
1615 // Check whether there is output file
1616 //
1617 for (Index = 0; Index < InputFileNum; Index ++) {
1618 VerboseMsg ("the %uth input file name is %s", (unsigned) Index, InputFileName[Index]);
1619 }
1620 if (OutputFileName == NULL) {
1621 Error (NULL, 0, 1001, "Missing options", "Output file");
1622 goto Finish;
1623 // OutFile = stdout;
1624 }
1625 VerboseMsg ("Output file name is %s", OutputFileName);
1626
1627 //
1628 // At this point, we've fully validated the command line, and opened appropriate
1629 // files, so let's go and do what we've been asked to do...
1630 //
1631 //
1632 // Within this switch, build and write out the section header including any
1633 // section type specific pieces. If there's an input file, it's tacked on later
1634 //
1635 switch (SectType) {
1636 case EFI_SECTION_COMPRESSION:
1637 if (InputFileAlign != NULL) {
1638 free (InputFileAlign);
1639 InputFileAlign = NULL;
1640 }
1641 Status = GenSectionCompressionSection (
1642 InputFileName,
1643 InputFileAlign,
1644 InputFileNum,
1645 SectCompSubType,
1646 &OutFileBuffer
1647 );
1648 break;
1649
1650 case EFI_SECTION_GUID_DEFINED:
1651 if (InputFileAlign != NULL && (CompareGuid (&VendorGuid, &mZeroGuid) != 0)) {
1652 //
1653 // Only process alignment for the default known CRC32 guided section.
1654 // For the unknown guided section, the alignment is processed when the dummy all section (EFI_SECTION_ALL) is generated.
1655 //
1656 free (InputFileAlign);
1657 InputFileAlign = NULL;
1658 }
1659 Status = GenSectionGuidDefinedSection (
1660 InputFileName,
1661 InputFileAlign,
1662 InputFileNum,
1663 &VendorGuid,
1664 SectGuidAttribute,
1665 (UINT32) SectGuidHeaderLength,
1666 &OutFileBuffer
1667 );
1668 break;
1669
1670 case EFI_SECTION_VERSION:
1671 Index = sizeof (EFI_COMMON_SECTION_HEADER);
1672 //
1673 // 2 bytes for the build number UINT16
1674 //
1675 Index += 2;
1676 //
1677 // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
1678 //
1679 Index += (strlen (StringBuffer) * 2) + 2;
1680 OutFileBuffer = (UINT8 *) malloc (Index);
1681 if (OutFileBuffer == NULL) {
1682 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1683 goto Finish;
1684 }
1685 VersionSect = (EFI_VERSION_SECTION *) OutFileBuffer;
1686 VersionSect->CommonHeader.Type = SectType;
1687 VersionSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
1688 VersionSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
1689 VersionSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
1690 VersionSect->BuildNumber = (UINT16) VersionNumber;
1691 Ascii2UnicodeString (StringBuffer, VersionSect->VersionString);
1692 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
1693 break;
1694
1695 case EFI_SECTION_USER_INTERFACE:
1696 Index = sizeof (EFI_COMMON_SECTION_HEADER);
1697 //
1698 // StringBuffer is ascii.. unicode is 2X + 2 bytes for terminating unicode null.
1699 //
1700 Index += (strlen (StringBuffer) * 2) + 2;
1701 OutFileBuffer = (UINT8 *) malloc (Index);
1702 if (OutFileBuffer == NULL) {
1703 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1704 goto Finish;
1705 }
1706 UiSect = (EFI_USER_INTERFACE_SECTION *) OutFileBuffer;
1707 UiSect->CommonHeader.Type = SectType;
1708 UiSect->CommonHeader.Size[0] = (UINT8) (Index & 0xff);
1709 UiSect->CommonHeader.Size[1] = (UINT8) ((Index & 0xff00) >> 8);
1710 UiSect->CommonHeader.Size[2] = (UINT8) ((Index & 0xff0000) >> 16);
1711 Ascii2UnicodeString (StringBuffer, UiSect->FileNameString);
1712 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) Index);
1713 break;
1714
1715 case EFI_SECTION_ALL:
1716 //
1717 // read all input file contents into a buffer
1718 // first get the size of all file contents
1719 //
1720 Status = GetSectionContents (
1721 InputFileName,
1722 InputFileAlign,
1723 InputFileNum,
1724 OutFileBuffer,
1725 &InputLength
1726 );
1727
1728 if (Status == EFI_BUFFER_TOO_SMALL) {
1729 OutFileBuffer = (UINT8 *) malloc (InputLength);
1730 if (OutFileBuffer == NULL) {
1731 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated");
1732 goto Finish;
1733 }
1734 //
1735 // read all input file contents into a buffer
1736 //
1737 Status = GetSectionContents (
1738 InputFileName,
1739 InputFileAlign,
1740 InputFileNum,
1741 OutFileBuffer,
1742 &InputLength
1743 );
1744 }
1745 VerboseMsg ("the size of the created section file is %u bytes", (unsigned) InputLength);
1746 break;
1747 default:
1748 //
1749 // All other section types are caught by default (they're all the same)
1750 //
1751 Status = GenSectionCommonLeafSection (
1752 InputFileName,
1753 InputFileNum,
1754 SectType,
1755 &OutFileBuffer
1756 );
1757 break;
1758 }
1759
1760 if (Status != EFI_SUCCESS || OutFileBuffer == NULL) {
1761 Error (NULL, 0, 2000, "Status is not successful", "Status value is 0x%X", (int) Status);
1762 goto Finish;
1763 }
1764
1765 //
1766 // Get output file length
1767 //
1768 if (SectType != EFI_SECTION_ALL) {
1769 SectionHeader = (EFI_COMMON_SECTION_HEADER *)OutFileBuffer;
1770 InputLength = *(UINT32 *)SectionHeader->Size & 0x00ffffff;
1771 if (InputLength == 0xffffff) {
1772 InputLength = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
1773 }
1774 }
1775
1776 //
1777 // Write the output file
1778 //
1779 OutFile = fopen (LongFilePath (OutputFileName), "wb");
1780 if (OutFile == NULL) {
1781 Error (NULL, 0, 0001, "Error opening file for writing", OutputFileName);
1782 goto Finish;
1783 }
1784
1785 fwrite (OutFileBuffer, InputLength, 1, OutFile);
1786
1787 Finish:
1788 if (InputFileName != NULL) {
1789 free (InputFileName);
1790 }
1791
1792 if (InputFileAlign != NULL) {
1793 free (InputFileAlign);
1794 }
1795
1796 if (OutFileBuffer != NULL) {
1797 free (OutFileBuffer);
1798 }
1799
1800 if (OutFile != NULL) {
1801 fclose (OutFile);
1802 }
1803
1804 if (DummyFileBuffer != NULL) {
1805 free (DummyFileBuffer);
1806 }
1807
1808 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());
1809
1810 return GetUtilityStatus ();
1811 }