]> git.proxmox.com Git - mirror_edk2.git/blame - Tools/CCode/Source/GenCapsuleHdr/GenCapsuleHdr.c
- Fixed EDKT513 by adding existing section files into the dependency check of genffsf...
[mirror_edk2.git] / Tools / CCode / Source / GenCapsuleHdr / GenCapsuleHdr.c
CommitLineData
d25c4bf0 1/*++\r
2\r
ad1f8df0 3Copyright (c) 2002-2006 Intel Corporation. All rights reserved\r
4This program and the accompanying materials are licensed and made available \r
5under the terms and conditions of the BSD License which accompanies this \r
6distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
d25c4bf0 11\r
12\r
13Module Name:\r
14\r
15 GenCapsuleHdr.c \r
16\r
17Abstract:\r
18\r
19 Generate a capsule header for a file, and optionally prepend the\r
20 header to a file or list of files.\r
21\r
22--*/\r
23\r
24#define _UNICODE\r
25\r
26#include <stdio.h>\r
27#include <string.h>\r
28#include <stdlib.h>\r
29#include <ctype.h>\r
30\r
ce53a8c3 31#include <Common/UefiBaseTypes.h>\r
32#include <Common/MultiPhase.h>\r
33#include <Common/Capsule.h>\r
34#include <Common/FirmwareVolumeImageFormat.h>\r
35#include <Common/FirmwareVolumeHeader.h>\r
36#include <Common/FirmwareFileSystem.h> // for FV header GUID\r
37#include <Guid/Capsule.h>\r
38#include <Guid/FirmwareFileSystem.h> // for FV header GUID\r
39\r
40#include "CommonLib.h"\r
d25c4bf0 41#include "EfiUtilityMsgs.h"\r
ce53a8c3 42\r
d25c4bf0 43#define MAX_PATH 256\r
52be9a3b 44\r
45#define UTILITY_NAME "GenCapsuleHdr"\r
46#define UTILITY_MAJOR_VERSION 1\r
47#define UTILITY_MINOR_VERSION 0\r
d25c4bf0 48\r
49#define UNICODE_BACKSLASH L'\\'\r
50#define UNICODE_FILE_START 0xFEFF\r
51#define UNICODE_CR 0x000D\r
52#define UNICODE_LF 0x000A\r
53#define UNICODE_NULL 0x0000\r
54#define UNICODE_SPACE L' '\r
55#define UNICODE_SLASH L'/'\r
56#define UNICODE_DOUBLE_QUOTE L'"'\r
57#define UNICODE_A L'A'\r
58#define UNICODE_F L'F'\r
59#define UNICODE_Z L'Z'\r
60#define UNICODE_a L'a'\r
61#define UNICODE_f L'f'\r
62#define UNICODE_z L'z'\r
63#define UNICODE_0 L'0'\r
64#define UNICODE_9 L'9'\r
65#define UNICODE_TAB L'\t'\r
66\r
67#define OEM_HEADER_STRING L"OemHeader"\r
68#define AUTHOR_INFO_STRING L"AuthorInfo"\r
69#define REVISION_INFO_STRING L"RevisionInfo"\r
70#define SHORT_DESCRIPTION_STRING L"ShortDescription"\r
71#define LONG_DESCRIPTION_STRING L"LongDescription"\r
72#define EQUAL_STRING L"="\r
73#define OPEN_BRACE_STRING L"{"\r
74#define CLOSE_BRACE_STRING L"}"\r
75#define GUID_STRING L"GUID"\r
76#define DATA_STRING L"DATA"\r
77\r
78#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
79#define UEFI_CAPSULE_HEADER_NO_FALAGS 0\r
80#define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET\r
81#define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)\r
82#endif\r
83\r
84typedef wchar_t WCHAR;\r
85\r
86typedef struct _FILE_LIST {\r
87 struct _FILE_LIST *Next;\r
88 INT8 FileName[MAX_PATH];\r
89} FILE_LIST;\r
90\r
91typedef struct _SIZE_LIST {\r
92 struct _SIZE_LIST *Next;\r
93 UINT32 Size;\r
94} SIZE_LIST;\r
95\r
96typedef struct {\r
97 INT8 FileName[MAX_PATH];\r
98 WCHAR *FileBuffer;\r
99 WCHAR *FileBufferPtr;\r
100 UINT32 FileSize;\r
101 FILE *FilePtr;\r
102 BOOLEAN EndOfFile;\r
103 UINT32 LineNum;\r
104} SOURCE_FILE;\r
105\r
106//\r
107// Here's all our globals.\r
108//\r
109static struct {\r
110 BOOLEAN Dump;\r
111 BOOLEAN Verbose;\r
112 BOOLEAN JoinMode;\r
113 INT8 ScriptFileName[MAX_PATH];\r
114 INT8 OutputFileName[MAX_PATH];\r
115 FILE_LIST *FileList;\r
116 FILE *OutFptr;\r
117 SIZE_LIST *SizeList;\r
118 SIZE_LIST *LastSize;\r
119 SIZE_LIST *CurrentSize;\r
120} mOptions;\r
121\r
122static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;\r
123\r
124void\r
125CreateGuid (\r
126 EFI_GUID *Guid\r
127 );\r
128\r
129static\r
130STATUS\r
131ProcessArgs (\r
132 int Argc,\r
133 char *Argv[]\r
134 );\r
135\r
136static\r
137void\r
138SkipWhiteSpace (\r
139 SOURCE_FILE *SourceFile\r
140 );\r
141\r
142static\r
143STATUS\r
144GetHexValue (\r
145 SOURCE_FILE *SourceFile,\r
146 UINT32 *Value,\r
147 UINT32 NumDigits\r
148 );\r
149\r
150static\r
151BOOLEAN\r
152GetSplitFileName (\r
153 INT8 *BaseFileName,\r
154 INT8 *NewFileName,\r
155 UINT32 SequenceNumber\r
156 );\r
157\r
158static\r
159STATUS\r
160SplitCapsule (\r
161 INT8 *CapsuleFileName\r
162 );\r
163\r
52be9a3b 164static\r
165void\r
166Version (\r
167 VOID\r
168 );\r
169\r
d25c4bf0 170static\r
171void\r
172Usage (\r
173 VOID\r
174 );\r
175\r
176static\r
177void\r
178DumpCapsule (\r
179 VOID\r
180 );\r
181\r
182static\r
183STATUS\r
184JoinCapsule (\r
185 VOID\r
186 );\r
187\r
188static\r
189STATUS\r
190DumpCapsuleHeaderStrings (\r
191 UINT8 *SectionName,\r
192 WCHAR *Buffer\r
193 );\r
194\r
195static\r
196STATUS\r
197CheckFirmwareVolumeHeader (\r
198 INT8 *FileName,\r
199 INT8 *Buffer,\r
200 UINT32 BufferSize\r
201 );\r
202\r
203static\r
204BOOLEAN\r
205IsToken (\r
206 SOURCE_FILE *File,\r
207 WCHAR *Token\r
208 );\r
209\r
210static\r
211BOOLEAN\r
212GetNumber (\r
213 INT8 *Str,\r
214 UINT32 *Value\r
215 );\r
216\r
217static\r
218STATUS\r
219ProcessScriptFile (\r
220 INT8 *ScriptFileName,\r
221 FILE *OutFptr,\r
222 EFI_CAPSULE_HEADER *CapsuleHeader\r
223 );\r
224\r
225static\r
226STATUS\r
227ParseCapsuleInfo (\r
228 SOURCE_FILE *SourceFile,\r
229 FILE *OutFptr,\r
230 WCHAR *SectionName\r
231 );\r
232\r
233static\r
234STATUS\r
235CreateCapsule (\r
236 VOID\r
237 );\r
238\r
239static\r
240STATUS\r
241ParseOemInfo (\r
242 SOURCE_FILE *SourceFile,\r
243 FILE *OutFptr\r
244 );\r
245\r
246static\r
247BOOLEAN\r
248IsWhiteSpace (\r
249 WCHAR Char\r
250 );\r
251\r
252static\r
253BOOLEAN\r
254EndOfFile (\r
255 SOURCE_FILE *File\r
256 );\r
257\r
258int\r
259main (\r
260 int Argc,\r
261 char *Argv[]\r
262 )\r
263/*++\r
264\r
265Routine Description:\r
266 Call the routine to process the command-line arguments, then\r
267 dispatch to the appropriate function.\r
268 \r
269Arguments:\r
270 Standard C main() argc and argv.\r
271\r
272Returns:\r
273 0 if successful\r
274 nonzero otherwise\r
275 \r
276--*/\r
277// GC_TODO: Argc - add argument and description to function comment\r
278// GC_TODO: ] - add argument and description to function comment\r
279{\r
280 STATUS Status;\r
281 FILE_LIST *NextFile;\r
282 //\r
283 // Specify our program name to the error printing routines.\r
284 //\r
52be9a3b 285 SetUtilityName (UTILITY_NAME);\r
d25c4bf0 286 //\r
287 // Process the command-line arguments\r
288 //\r
289 Status = ProcessArgs (Argc, Argv);\r
290 if (Status == STATUS_SUCCESS) {\r
291 if (mOptions.Dump) {\r
292 DumpCapsule ();\r
293 } else if (mOptions.JoinMode) {\r
294 JoinCapsule ();\r
295 } else {\r
296 CreateCapsule ();\r
297 }\r
298 }\r
299 //\r
300 // Cleanup\r
301 //\r
302 while (mOptions.FileList != NULL) {\r
303 NextFile = mOptions.FileList->Next;\r
304 free (mOptions.FileList);\r
305 mOptions.FileList = NextFile;\r
306 }\r
307\r
308 while (mOptions.SizeList != NULL) {\r
309 mOptions.CurrentSize = mOptions.SizeList->Next;\r
310 free (mOptions.SizeList);\r
311 mOptions.SizeList = mOptions.CurrentSize;\r
312 }\r
313\r
314 return GetUtilityStatus ();\r
315}\r
316\r
317static\r
318STATUS\r
319CreateCapsule (\r
320 VOID\r
321 )\r
322/*++\r
323\r
324Routine Description:\r
325\r
326 GC_TODO: Add function description\r
327\r
328Arguments:\r
329\r
330 None\r
331\r
332Returns:\r
333\r
334 GC_TODO: add return values\r
335\r
336--*/\r
337{\r
338 FILE *InFptr;\r
339 FILE_LIST *FileList;\r
340 INT8 *Buffer;\r
341 UINT32 Size;\r
342 EFI_CAPSULE_HEADER CapsuleHeader;\r
343 UINT8 Zero;\r
344 UINT8 FirstFile;\r
345 UINT32 CapsuleHeaderSize;\r
346 long InsertedBlockMapEntryOffset;\r
347 EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry;\r
348 UINT64 FirmwareVolumeSize;\r
349 long FileSize;\r
350 EFI_FIRMWARE_VOLUME_HEADER FVHeader;\r
351\r
352 Buffer = NULL;\r
353 InFptr = NULL;\r
354 FirmwareVolumeSize = 0;\r
355 CapsuleHeaderSize = 0;\r
356 InsertedBlockMapEntryOffset = 0;\r
357 memset (&InsertedBlockMapEntry, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
358 memset (&FVHeader, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
359\r
360 if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
361 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
362 return STATUS_ERROR;\r
363 }\r
364\r
365 memset ((char *) &CapsuleHeader, 0, sizeof (CapsuleHeader));\r
366 memcpy ((void *) &CapsuleHeader.CapsuleGuid, (void *) &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID));\r
367 CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
368 CapsuleHeader.CapsuleImageSize = sizeof (EFI_CAPSULE_HEADER);\r
369 if (mOptions.ScriptFileName[0] != 0) {\r
370 if (ProcessScriptFile (mOptions.ScriptFileName, mOptions.OutFptr, &CapsuleHeader) != STATUS_SUCCESS) {\r
371 goto Done;\r
372 }\r
373 } else {\r
374 //\r
375 // Insert a default capsule header\r
376#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
377 CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
378 CapsuleHeader.Flags = UEFI_CAPSULE_HEADER_ALL_FALAGS;\r
379#endif\r
380 CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER);\r
381\r
382 if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
383 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
384 goto Done;\r
385 }\r
386 }\r
387\r
388 CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody;\r
389 //\r
390 // Now copy the contents of any other files specified on the command\r
391 // line to the output file. Files must be FFS files, which are aligned\r
392 // on 8-byte boundaries. Don't align the first file, since it's the start\r
393 // of the image once the capsule header has been removed.\r
394 //\r
395 FileList = mOptions.FileList;\r
396 FirstFile = 1;\r
397 Zero = 0;\r
398 while (FileList != NULL) {\r
399 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
400 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
401 goto Done;\r
402 }\r
403 //\r
404 // Allocate a buffer into which we can read the file.\r
405 //\r
406 fseek (InFptr, 0, SEEK_END);\r
407 Size = ftell (InFptr);\r
408 rewind (InFptr);\r
409 Buffer = (char *) malloc (Size);\r
410 if (Buffer == NULL) {\r
411 Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
412 goto Done;\r
413 }\r
414\r
415 if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
416 Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
417 goto Done;\r
418 }\r
419\r
420 if (Size > 0) {\r
421 //\r
422 // Align the write of the first bytes from the file if not the first file\r
423 //\r
424 if (FirstFile) {\r
425 //\r
426 // First file must be a firmware volume. Double-check, and then insert\r
427 // an additional block map entry so we can add more files from the command line\r
428 //\r
429 if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) {\r
430 goto Done;\r
431 }\r
432 //\r
433 // Save a copy of the firmware volume header for later\r
434 //\r
435 memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
436 FirmwareVolumeSize = FVHeader.FvLength;\r
437 if (FileList->Next != NULL) {\r
438 //\r
439 // Copy the firmware volume header\r
440 //\r
441 InsertedBlockMapEntryOffset = CapsuleHeaderSize + FVHeader.HeaderLength;\r
442 if (fwrite (Buffer, FVHeader.HeaderLength, 1, mOptions.OutFptr) != 1) {\r
443 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
444 goto Done;\r
445 }\r
446\r
447 if (fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr) != 1) {\r
448 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
449 goto Done;\r
450 }\r
451\r
452 if (fwrite (\r
453 Buffer + FVHeader.HeaderLength,\r
454 Size - FVHeader.HeaderLength,\r
455 1,\r
456 mOptions.OutFptr\r
457 ) != 1) {\r
458 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
459 goto Done;\r
460 }\r
461 } else {\r
462 //\r
463 // Copy the file contents as-is\r
464 //\r
465 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
466 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
467 goto Done;\r
468 }\r
469 }\r
470 } else {\r
471 while ((ftell (mOptions.OutFptr) - CapsuleHeaderSize) & 0x07) {\r
472 if (fwrite ((void *) &Zero, 1, 1, mOptions.OutFptr) != 1) {\r
473 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
474 goto Done;\r
475 }\r
476 }\r
477\r
478 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
479 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
480 goto Done;\r
481 }\r
482 }\r
483\r
484 FirstFile = 0;\r
485 }\r
486\r
487 free (Buffer);\r
488 Buffer = NULL;\r
489 fclose (InFptr);\r
490 InFptr = NULL;\r
491 FileList = FileList->Next;\r
492 }\r
493\r
494Done:\r
495 if (Buffer != NULL) {\r
496 free (Buffer);\r
497 }\r
498\r
499 if (InFptr != NULL) {\r
500 fclose (InFptr);\r
501 }\r
502 //\r
503 // If we inserted an additional block map entry, then fix it up. Fix up the\r
504 // FV header as well to reflect our new size.\r
505 //\r
506 if (InsertedBlockMapEntryOffset != 0) {\r
507 FileSize = ftell (mOptions.OutFptr);\r
508 InsertedBlockMapEntry.NumBlocks = 1;\r
509 InsertedBlockMapEntry.BlockLength = (UINT32) ((UINT64) FileSize - (UINT64) CapsuleHeaderSize - FirmwareVolumeSize - sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
510 fseek (mOptions.OutFptr, InsertedBlockMapEntryOffset, SEEK_SET);\r
511 fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
512 //\r
513 // Fix up the firmware volume header and write it out\r
514 //\r
515 fseek (mOptions.OutFptr, CapsuleHeaderSize, SEEK_SET);\r
516 FVHeader.FvLength = FileSize - CapsuleHeaderSize;\r
517 FVHeader.HeaderLength += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
518 fwrite (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
519 //\r
520 // Reposition to the end of the file\r
521 //\r
522 }\r
523 //\r
524 // Close files and free the global string lists we allocated memory for\r
525 //\r
526 if (mOptions.OutFptr != NULL) {\r
527 //\r
528 // We should now know the full capsule image size. Update the header and write it again.\r
529 //\r
530 fseek (mOptions.OutFptr, 0, SEEK_END);\r
531 Size = ftell (mOptions.OutFptr);\r
532 CapsuleHeader.CapsuleImageSize = Size;\r
533 fseek (mOptions.OutFptr, 0, SEEK_SET);\r
534 if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
535 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
536 }\r
537\r
538 fseek (mOptions.OutFptr, 0, SEEK_END);\r
539 fclose (mOptions.OutFptr);\r
540 mOptions.OutFptr = NULL;\r
541 }\r
542 //\r
543 // If they are doing split capsule output, then split it up now.\r
544 //\r
545 if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) {\r
546 SplitCapsule (mOptions.OutputFileName);\r
547 }\r
548\r
549 return STATUS_SUCCESS;\r
550}\r
551\r
552static\r
553STATUS\r
554ProcessScriptFile (\r
555 INT8 *ScriptFileName,\r
556 FILE *OutFptr,\r
557 EFI_CAPSULE_HEADER *CapsuleHeader\r
558 )\r
559/*++\r
560\r
561Routine Description:\r
562 Parse a capsule header script file.\r
563\r
564Arguments:\r
565 ScriptFileName - name of script file to parse\r
566 OutFptr - output to dump binary data\r
567 CapsuleHeader - capsule header to update with size info\r
568 of parsed fields in the script file\r
569\r
570Returns:\r
571 STATUS_SUCCESS - if all went well\r
572\r
573--*/\r
574{\r
575#if 0\r
576 STATUS Status;\r
577 SOURCE_FILE SourceFile;\r
578 WCHAR *WScriptFileName;\r
579 BOOLEAN InComment;\r
580\r
581 if (fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr) != 1) {\r
582 Error (NULL, 0, 0, "failed to write capsule header to output file", NULL);\r
583 return STATUS_ERROR;\r
584 }\r
585\r
586 memset (&SourceFile, 0, sizeof (SOURCE_FILE));\r
587 strcpy (SourceFile.FileName, ScriptFileName);\r
588\r
589 Status = STATUS_ERROR;\r
590 //\r
591 // Open the input unicode script file and read it into a buffer\r
592 //\r
593 WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR));\r
594 if (WScriptFileName == NULL) {\r
595 Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);\r
596 return STATUS_ERROR;\r
597 }\r
598\r
599 swprintf (WScriptFileName, L"%S", ScriptFileName);\r
600 if ((SourceFile.FilePtr = _wfopen (WScriptFileName, L"r")) == NULL) {\r
601 free (WScriptFileName);\r
602 Error (NULL, 0, 0, ScriptFileName, "failed to open script file for reading");\r
603 goto Done;\r
604 }\r
605\r
606 free (WScriptFileName);\r
607 fseek (SourceFile.FilePtr, 0, SEEK_END);\r
608 SourceFile.FileSize = ftell (SourceFile.FilePtr);\r
609 rewind (SourceFile.FilePtr);\r
610 SourceFile.FileBuffer = (WCHAR *) malloc (SourceFile.FileSize + sizeof (WCHAR));\r
611 if (SourceFile.FileBuffer == NULL) {\r
612 Error (__FILE__, __LINE__, 0, ScriptFileName, "failed to allocate memory to read in file contents");\r
613 goto Done;\r
614 }\r
615\r
616 if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) {\r
617 Error (NULL, 0, 0, ScriptFileName, "failed to read file contents");\r
618 goto Done;\r
619 }\r
620\r
621 SourceFile.FileBufferPtr = SourceFile.FileBuffer;\r
622 SourceFile.LineNum = 1;\r
623 if (SourceFile.FileBuffer[0] != UNICODE_FILE_START) {\r
624 Error (ScriptFileName, 1, 0, "file does not appear to be a unicode file", NULL);\r
625 goto Done;\r
626 }\r
627\r
628 SourceFile.FileBufferPtr++;\r
629 SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0;\r
630 //\r
631 // Walk the source file buffer and replace all carriage returns with 0 so\r
632 // we can print from the file contents on parse errors.\r
633 //\r
634 InComment = 0;\r
635 while (!EndOfFile (&SourceFile)) {\r
636 if (SourceFile.FileBufferPtr[0] == UNICODE_CR) {\r
637 SourceFile.FileBufferPtr[0] = 0;\r
638 InComment = 0;\r
639 } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) {\r
640 InComment = 0;\r
641 } else if (InComment) {\r
642 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
643 } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) {\r
644 InComment = 1;\r
645 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
646 }\r
647\r
648 SourceFile.FileBufferPtr++;\r
649 }\r
650 //\r
651 // Reposition to the start of the file, but skip over the unicode file start\r
652 //\r
653 SourceFile.FileBufferPtr = SourceFile.FileBuffer;\r
654 SourceFile.FileBufferPtr++;\r
655 SourceFile.EndOfFile = 0;\r
656 CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr);\r
657 //\r
658 // Parse the OEM bytes\r
659 //\r
660 if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) {\r
661 goto Done;\r
662 }\r
663 //\r
664 // Parse the author information\r
665 //\r
666 CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr);\r
667 if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) {\r
668 goto Done;\r
669 }\r
670 //\r
671 // Parse the revision information\r
672 //\r
673 CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr);\r
674 if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) {\r
675 goto Done;\r
676 }\r
677 //\r
678 // Parse the short description\r
679 //\r
680 CapsuleHeader->OffsetToShortDescription = ftell (OutFptr);\r
681 if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
682 goto Done;\r
683 }\r
684 //\r
685 // Parse the long description\r
686 //\r
687 CapsuleHeader->OffsetToLongDescription = ftell (OutFptr);\r
688 if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
689 goto Done;\r
690 }\r
691 //\r
692 // Better be end of contents\r
693 //\r
694 SkipWhiteSpace (&SourceFile);\r
695 if (!EndOfFile (&SourceFile)) {\r
696 Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr);\r
697 goto Done;\r
698 }\r
699\r
700 CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr);\r
701 rewind (OutFptr);\r
702 fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr);\r
703 fseek (OutFptr, 0, SEEK_END);\r
704 Status = STATUS_SUCCESS;\r
705Done:\r
706 if (SourceFile.FilePtr != NULL) {\r
707 fclose (SourceFile.FilePtr);\r
708 }\r
709\r
710 if (SourceFile.FileBuffer != NULL) {\r
711 free (SourceFile.FileBuffer);\r
712 }\r
713\r
714 return Status;\r
715\r
716#endif\r
717 return STATUS_SUCCESS;\r
718}\r
719//\r
720// Parse the OEM data of format:\r
721// OemInfo {\r
722// GUID = 12345676-1234-1234-123456789ABC\r
723// DATA = 0x01, 0x02, 0x03...\r
724// }\r
725//\r
726static\r
727STATUS\r
728ParseOemInfo (\r
729 SOURCE_FILE *SourceFile,\r
730 FILE *OutFptr\r
731 )\r
732/*++\r
733\r
734Routine Description:\r
735\r
736 GC_TODO: Add function description\r
737\r
738Arguments:\r
739\r
740 SourceFile - GC_TODO: add argument description\r
741 OutFptr - GC_TODO: add argument description\r
742\r
743Returns:\r
744\r
745 GC_TODO: add return values\r
746\r
747--*/\r
748{\r
749 long OemHeaderOffset;\r
750 UINT32 Data;\r
751 EFI_CAPSULE_OEM_HEADER OemHeader;\r
752 STATUS Status;\r
753 UINT32 DigitCount;\r
754 WCHAR *SaveFilePos;\r
755 UINT8 ByteData;\r
756\r
757 Status = STATUS_ERROR;\r
758 memset (&OemHeader, 0, sizeof (EFI_CAPSULE_OEM_HEADER));\r
759 OemHeaderOffset = ftell (OutFptr);\r
760 OemHeader.HeaderSize = sizeof (EFI_CAPSULE_OEM_HEADER);\r
761 if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
762 Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
763 goto Done;\r
764 }\r
765\r
766 if (!IsToken (SourceFile, OEM_HEADER_STRING)) {\r
767 Error (\r
768 SourceFile->FileName,\r
769 SourceFile->LineNum,\r
770 0,\r
771 NULL,\r
772 "expected %S, not %.20S",\r
773 OEM_HEADER_STRING,\r
774 SourceFile->FileBufferPtr\r
775 );\r
776 goto Done;\r
777 }\r
778\r
779 if (!IsToken (SourceFile, EQUAL_STRING)) {\r
780 Error (\r
781 SourceFile->FileName,\r
782 SourceFile->LineNum,\r
783 0,\r
784 NULL,\r
785 "expected %S, not %.20S",\r
786 EQUAL_STRING,\r
787 SourceFile->FileBufferPtr\r
788 );\r
789 goto Done;\r
790 }\r
791\r
792 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
793 Error (\r
794 SourceFile->FileName,\r
795 SourceFile->LineNum,\r
796 0,\r
797 NULL,\r
798 "expected %S, not %.20S",\r
799 OPEN_BRACE_STRING,\r
800 SourceFile->FileBufferPtr\r
801 );\r
802 goto Done;\r
803 }\r
804 //\r
805 // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx\r
806 //\r
807 if (!IsToken (SourceFile, GUID_STRING)) {\r
808 Error (\r
809 SourceFile->FileName,\r
810 SourceFile->LineNum,\r
811 0,\r
812 NULL,\r
813 "expected %S, not %.20S",\r
814 GUID_STRING,\r
815 SourceFile->FileBufferPtr\r
816 );\r
817 goto Done;\r
818 }\r
819\r
820 if (!IsToken (SourceFile, EQUAL_STRING)) {\r
821 Error (\r
822 SourceFile->FileName,\r
823 SourceFile->LineNum,\r
824 0,\r
825 NULL,\r
826 "expected %S, not %.20S",\r
827 EQUAL_STRING,\r
828 SourceFile->FileBufferPtr\r
829 );\r
830 goto Done;\r
831 }\r
832 //\r
833 // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID\r
834 //\r
835 SkipWhiteSpace (SourceFile);\r
836 if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) {\r
837 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
838 goto Done;\r
839 }\r
840\r
841 OemHeader.OemGuid.Data1 = Data;\r
842 if (!IsToken (SourceFile, L"-")) {\r
843 Error (\r
844 SourceFile->FileName,\r
845 SourceFile->LineNum,\r
846 0,\r
847 NULL,\r
848 "expected dash in GUID, not %S",\r
849 SourceFile->FileBufferPtr\r
850 );\r
851 goto Done;\r
852 }\r
853 //\r
854 // Get 3 word values\r
855 //\r
856 for (DigitCount = 0; DigitCount < 3; DigitCount++) {\r
857 if (GetHexValue (SourceFile, &Data, 4) != STATUS_SUCCESS) {\r
858 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
859 goto Done;\r
860 }\r
861\r
862 switch (DigitCount) {\r
863 case 0:\r
864 OemHeader.OemGuid.Data2 = (UINT16) Data;\r
865 break;\r
866\r
867 case 1:\r
868 OemHeader.OemGuid.Data3 = (UINT16) Data;\r
869 break;\r
870\r
871 case 2:\r
872 OemHeader.OemGuid.Data4[1] = (UINT8) Data;\r
873 OemHeader.OemGuid.Data4[0] = (UINT8) (Data >> 8);\r
874 break;\r
875 }\r
876\r
877 if (!IsToken (SourceFile, L"-")) {\r
878 Error (\r
879 SourceFile->FileName,\r
880 SourceFile->LineNum,\r
881 0,\r
882 NULL,\r
883 "expected dash in GUID, not %S",\r
884 SourceFile->FileBufferPtr\r
885 );\r
886 goto Done;\r
887 }\r
888 }\r
889 //\r
890 // Pick up the last 6 bytes of the GUID\r
891 //\r
892 SaveFilePos = SourceFile->FileBufferPtr;\r
893 for (DigitCount = 0; DigitCount < 6; DigitCount++) {\r
894 if (GetHexValue (SourceFile, &Data, 2) != STATUS_SUCCESS) {\r
895 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
896 goto Done;\r
897 }\r
898\r
899 OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data;\r
900 }\r
901 //\r
902 // Now read raw OEM data bytes. May or may not be present.\r
903 // DATA = 0x01, 0x02, 0x02...\r
904 //\r
905 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
906 Status = STATUS_SUCCESS;\r
907 goto Done;\r
908 }\r
909\r
910 if (!IsToken (SourceFile, DATA_STRING)) {\r
911 Error (\r
912 SourceFile->FileName,\r
913 SourceFile->LineNum,\r
914 0,\r
915 NULL,\r
916 "expected %S, not %.20S",\r
917 DATA_STRING,\r
918 SourceFile->FileBufferPtr\r
919 );\r
920 goto Done;\r
921 }\r
922\r
923 if (!IsToken (SourceFile, EQUAL_STRING)) {\r
924 Error (\r
925 SourceFile->FileName,\r
926 SourceFile->LineNum,\r
927 0,\r
928 NULL,\r
929 "expected %S, not %.20S",\r
930 EQUAL_STRING,\r
931 SourceFile->FileBufferPtr\r
932 );\r
933 goto Done;\r
934 }\r
935\r
936 while (!EndOfFile (SourceFile)) {\r
937 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
938 Status = STATUS_SUCCESS;\r
939 goto Done;\r
940 }\r
941\r
942 if (IsToken (SourceFile, L"0x")) {\r
943 if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) {\r
944 Error (\r
945 SourceFile->FileName,\r
946 SourceFile->LineNum,\r
947 0,\r
948 NULL,\r
949 "expected hex byte value, not %.20S",\r
950 SourceFile->FileBufferPtr\r
951 );\r
952 goto Done;\r
953 }\r
954\r
955 if (Data &~0xFF) {\r
956 Error (\r
957 SourceFile->FileName,\r
958 SourceFile->LineNum,\r
959 0,\r
960 NULL,\r
961 "expected byte hex byte value at %.20S",\r
962 SourceFile->FileBufferPtr\r
963 );\r
964 goto Done;\r
965 }\r
966 //\r
967 // Skip over the hex digits, then write the data\r
968 //\r
969 while (iswxdigit (SourceFile->FileBufferPtr[0])) {\r
970 SourceFile->FileBufferPtr++;\r
971 }\r
972\r
973 ByteData = (UINT8) Data;\r
974 if (fwrite (&ByteData, 1, 1, OutFptr) != 1) {\r
975 Error (NULL, 0, 0, "failed to write OEM data to output file", NULL);\r
976 goto Done;\r
977 }\r
978\r
979 OemHeader.HeaderSize++;\r
980 //\r
981 // Optional comma\r
982 //\r
983 IsToken (SourceFile, L",");\r
984 } else {\r
985 Error (\r
986 SourceFile->FileName,\r
987 SourceFile->LineNum,\r
988 0,\r
989 NULL,\r
990 "expected hex OEM data, not %.20S",\r
991 SourceFile->FileBufferPtr\r
992 );\r
993 goto Done;\r
994 }\r
995 }\r
996\r
997 if (EndOfFile (SourceFile)) {\r
998 Error (\r
999 SourceFile->FileName,\r
1000 SourceFile->LineNum,\r
1001 0,\r
1002 NULL,\r
1003 "expected %S close to OEM header data",\r
1004 CLOSE_BRACE_STRING\r
1005 );\r
1006 goto Done;\r
1007 }\r
1008\r
1009 Status = STATUS_SUCCESS;\r
1010Done:\r
1011 //\r
1012 // re-write the oem header if no errors\r
1013 //\r
1014 if (Status == STATUS_SUCCESS) {\r
1015 fseek (OutFptr, OemHeaderOffset, SEEK_SET);\r
1016 if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
1017 Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
1018 goto Done;\r
1019 }\r
1020\r
1021 fseek (OutFptr, 0, SEEK_END);\r
1022 }\r
1023\r
1024 return Status;\r
1025}\r
1026\r
1027static\r
1028STATUS\r
1029ParseCapsuleInfo (\r
1030 SOURCE_FILE *SourceFile,\r
1031 FILE *OutFptr,\r
1032 WCHAR *SectionName\r
1033 )\r
1034// GC_TODO: function comment should start with '/*++'\r
1035//\r
1036// GC_TODO: function comment is missing 'Routine Description:'\r
1037// GC_TODO: function comment is missing 'Arguments:'\r
1038// GC_TODO: function comment is missing 'Returns:'\r
1039// GC_TODO: SourceFile - add argument and description to function comment\r
1040// GC_TODO: OutFptr - add argument and description to function comment\r
1041// GC_TODO: SectionName - add argument and description to function comment\r
1042// Parse: eng "string " "parts"\r
1043// spa "string " "parts"\r
1044// Write out: "eng string parts\0spa string parts\0\0\r
1045//\r
1046{\r
1047 STATUS Status;\r
1048 int StringCount;\r
1049 WCHAR Zero;\r
1050 WCHAR Spacebar;\r
1051\r
1052 Status = STATUS_ERROR;\r
1053 Zero = 0;\r
1054 Spacebar = UNICODE_SPACE;\r
1055\r
1056 if (!IsToken (SourceFile, SectionName)) {\r
1057 Error (\r
1058 SourceFile->FileName,\r
1059 SourceFile->LineNum,\r
1060 0,\r
1061 NULL,\r
1062 "expected %S, not %.20S",\r
1063 SectionName,\r
1064 SourceFile->FileBufferPtr\r
1065 );\r
1066 goto Done;\r
1067 }\r
1068\r
1069 if (!IsToken (SourceFile, EQUAL_STRING)) {\r
1070 Error (\r
1071 SourceFile->FileName,\r
1072 SourceFile->LineNum,\r
1073 0,\r
1074 NULL,\r
1075 "expected %S, not %.20S",\r
1076 EQUAL_STRING,\r
1077 SourceFile->FileBufferPtr\r
1078 );\r
1079 goto Done;\r
1080 }\r
1081\r
1082 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
1083 Error (\r
1084 SourceFile->FileName,\r
1085 SourceFile->LineNum,\r
1086 0,\r
1087 NULL,\r
1088 "expected %S, not %.20S",\r
1089 OPEN_BRACE_STRING,\r
1090 SourceFile->FileBufferPtr\r
1091 );\r
1092 goto Done;\r
1093 }\r
1094\r
1095 while (!EndOfFile (SourceFile)) {\r
1096 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
1097 break;\r
1098 }\r
1099 //\r
1100 // Look for language identifier (3 lowercase chars)\r
1101 //\r
1102 if ((SourceFile->FileBufferPtr[0] >= UNICODE_a) &&\r
1103 (SourceFile->FileBufferPtr[0] <= UNICODE_z) &&\r
1104 (SourceFile->FileBufferPtr[1] >= UNICODE_a) &&\r
1105 (SourceFile->FileBufferPtr[1] <= UNICODE_z) &&\r
1106 (SourceFile->FileBufferPtr[2] >= UNICODE_a) &&\r
1107 (SourceFile->FileBufferPtr[2] <= UNICODE_z) &&\r
1108 IsWhiteSpace (SourceFile->FileBufferPtr[3])\r
1109 ) {\r
1110 //\r
1111 // Write the 3 chars followed by a spacebar, and then look for opening quote\r
1112 //\r
1113 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
1114 SourceFile->FileBufferPtr++;\r
1115 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
1116 SourceFile->FileBufferPtr++;\r
1117 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
1118 SourceFile->FileBufferPtr++;\r
1119 fwrite (&Spacebar, sizeof (WCHAR), 1, OutFptr);\r
1120 StringCount = 0;\r
1121 while (IsToken (SourceFile, L"\"")) {\r
1122 StringCount++;\r
1123 while (!EndOfFile (SourceFile)) {\r
1124 if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
1125 SourceFile->FileBufferPtr++;\r
1126 break;\r
1127 } else if ((SourceFile->FileBufferPtr[0] == UNICODE_LF) || (SourceFile->FileBufferPtr[0] == 0)) {\r
1128 Error (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", NULL);\r
1129 goto Done;\r
1130 } else {\r
1131 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
1132 SourceFile->FileBufferPtr++;\r
1133 }\r
1134 }\r
1135 }\r
1136\r
1137 if (StringCount == 0) {\r
1138 Error (\r
1139 SourceFile->FileName,\r
1140 SourceFile->LineNum,\r
1141 0,\r
1142 NULL,\r
1143 "expected quoted string, not %.20S",\r
1144 SourceFile->FileBufferPtr\r
1145 );\r
1146 goto Done;\r
1147 }\r
1148 //\r
1149 // This string's null terminator\r
1150 //\r
1151 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
1152 } else {\r
1153 Error (\r
1154 SourceFile->FileName,\r
1155 SourceFile->LineNum,\r
1156 0,\r
1157 NULL,\r
1158 "expected valid language identifer, not %.20S",\r
1159 SourceFile->FileBufferPtr\r
1160 );\r
1161 goto Done;\r
1162 }\r
1163 }\r
1164 //\r
1165 // Double null terminator\r
1166 //\r
1167 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
1168 Status = STATUS_SUCCESS;\r
1169Done:\r
1170 return Status;\r
1171}\r
1172\r
1173static\r
1174STATUS\r
1175SplitCapsule (\r
1176 INT8 *CapsuleFileName\r
1177 )\r
1178/*++\r
1179\r
1180Routine Description:\r
1181 We've created an entire capsule image. Now split it up into the \r
1182 size pieces they requested.\r
1183\r
1184Arguments:\r
1185 CapsuleFileName - name of an existing capsule file on disk\r
1186\r
1187Returns:\r
1188 STATUS_SUCCESS - if no problems\r
1189\r
1190Notes:\r
1191 This implementation reads in the entire capsule image from\r
1192 disk, then overwrites the original file with the first\r
1193 in the series.\r
1194\r
1195--*/\r
1196{\r
1197#if 0\r
1198 EFI_CAPSULE_HEADER *CapHdr;\r
1199\r
1200 EFI_CAPSULE_HEADER Hdr;\r
1201 FILE *CapFptr;\r
1202 FILE *OutFptr;\r
1203 UINT32 SizeLeft;\r
1204 UINT32 CurrentSize;\r
1205 UINT32 DataSize;\r
1206 UINT32 SequenceNumber;\r
1207 INT8 *Buffer;\r
1208 INT8 FileName[MAX_PATH];\r
1209 STATUS Status;\r
1210 UINT32 FileSize;\r
1211 //\r
1212 // Figure out the total size, then rewind the input file and\r
1213 // read the entire thing in\r
1214 //\r
1215 if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) {\r
1216 Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading");\r
1217 return STATUS_ERROR;\r
1218 }\r
1219\r
1220 OutFptr = NULL;\r
1221 Status = STATUS_SUCCESS;\r
1222 fseek (CapFptr, 0, SEEK_END);\r
1223 SizeLeft = ftell (CapFptr);\r
1224 fseek (CapFptr, 0, SEEK_SET);\r
1225 CapHdr = (EFI_CAPSULE_HEADER *) malloc (SizeLeft);\r
1226 if (CapHdr == NULL) {\r
1227 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
1228 goto FailDone;\r
1229 }\r
1230\r
1231 if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) {\r
1232 Error (NULL, 0, 0, "failed to read capsule contents", "split failed");\r
1233 goto FailDone;\r
1234 }\r
1235\r
1236 fclose (CapFptr);\r
1237 CapFptr = NULL;\r
1238 //\r
1239 // Get a GUID to fill in the InstanceId GUID in the header\r
1240 //\r
1241 CreateGuid (&CapHdr->InstanceId);\r
1242 SequenceNumber = 0;\r
1243 //\r
1244 // If the split size is larger than the original capsule image, then\r
1245 // we're done.\r
1246 //\r
1247 if (mOptions.SizeList->Size >= SizeLeft) {\r
1248 mOptions.SizeList->Size = SizeLeft;\r
1249 goto Done;\r
1250 }\r
1251 //\r
1252 // First size has to be big enough for the original header\r
1253 //\r
1254 if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) {\r
1255 Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL);\r
1256 goto FailDone;\r
1257 }\r
1258 //\r
1259 // Initialize the header we'll use on all but the first part\r
1260 //\r
1261 memset (&Hdr, 0, sizeof (Hdr));\r
1262 Hdr.CapsuleGuid = CapHdr->CapsuleGuid;\r
1263 Hdr.HeaderSize = sizeof (Hdr);\r
1264 Hdr.Flags = CapHdr->Flags;\r
1265 Hdr.InstanceId = CapHdr->InstanceId;\r
1266 Hdr.CapsuleImageSize = CapHdr->CapsuleImageSize;\r
1267 Hdr.OffsetToCapsuleBody = Hdr.HeaderSize;\r
1268 Hdr.SequenceNumber = 1;\r
1269 //\r
1270 // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);\r
1271 //\r
1272 Buffer = (UINT8 *) CapHdr;\r
1273 //\r
1274 // Walk the list of sizes and write out a capsule header, and\r
1275 // then the raw capsule data.\r
1276 //\r
1277 // SizeLeft -= mOptions.SizeList->Size;\r
1278 //\r
1279 mOptions.CurrentSize = mOptions.SizeList;\r
1280 while (SizeLeft) {\r
1281 CurrentSize = mOptions.CurrentSize->Size;\r
1282 GetSplitFileName (mOptions.OutputFileName, FileName, SequenceNumber);\r
1283 if ((OutFptr = fopen (FileName, "wb")) == NULL) {\r
1284 Error (NULL, 0, 0, FileName, "failed to open split file for writing");\r
1285 goto FailDone;\r
1286 }\r
1287\r
1288 if (Buffer == (UINT8 *) CapHdr) {\r
1289 //\r
1290 // First part -- write out original header and data\r
1291 //\r
1292 if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) {\r
1293 Error (NULL, 0, 0, FileName, "failed to write to split image file");\r
1294 goto FailDone;\r
1295 }\r
1296\r
1297 SizeLeft -= CurrentSize;\r
1298 Buffer += CurrentSize;\r
1299 DataSize = CurrentSize;\r
1300 FileSize = CurrentSize;\r
1301 } else {\r
1302 //\r
1303 // Not the first part. Write the default header, and then the raw bytes from the\r
1304 // original image.\r
1305 //\r
1306 if (CurrentSize <= sizeof (Hdr)) {\r
1307 Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize);\r
1308 goto FailDone;\r
1309 }\r
1310\r
1311 DataSize = CurrentSize - sizeof (Hdr);\r
1312 if (DataSize > SizeLeft) {\r
1313 DataSize = SizeLeft;\r
1314 }\r
1315\r
1316 if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) {\r
1317 Error (NULL, 0, 0, FileName, "failed to write capsule header to output file");\r
1318 fclose (OutFptr);\r
1319 goto FailDone;\r
1320 }\r
1321\r
1322 if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) {\r
1323 Error (NULL, 0, 0, FileName, "failed to write capsule data to output file");\r
1324 fclose (OutFptr);\r
1325 goto FailDone;\r
1326 }\r
1327\r
1328 Hdr.SequenceNumber++;\r
1329 Buffer += DataSize;\r
1330 SizeLeft -= DataSize;\r
1331 FileSize = DataSize + sizeof (Hdr);\r
1332 }\r
1333 //\r
1334 // Next size in list if there is one\r
1335 //\r
1336 if (mOptions.CurrentSize->Next != NULL) {\r
1337 mOptions.CurrentSize = mOptions.CurrentSize->Next;\r
1338 }\r
1339\r
1340 SequenceNumber++;\r
1341 fclose (OutFptr);\r
1342 OutFptr = NULL;\r
1343 printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize);\r
1344 }\r
1345\r
1346 goto Done;\r
1347FailDone:\r
1348 Status = STATUS_ERROR;\r
1349Done:\r
1350 if (CapHdr != NULL) {\r
1351 free (CapHdr);\r
1352 }\r
1353\r
1354 if (CapFptr != NULL) {\r
1355 fclose (CapFptr);\r
1356 }\r
1357\r
1358 if (OutFptr != NULL) {\r
1359 fclose (OutFptr);\r
1360 }\r
1361\r
1362 return Status;\r
1363\r
1364#endif\r
1365 return STATUS_SUCCESS;\r
1366}\r
1367\r
1368static\r
1369BOOLEAN\r
1370GetSplitFileName (\r
1371 INT8 *BaseFileName,\r
1372 INT8 *NewFileName,\r
1373 UINT32 SequenceNumber\r
1374 )\r
1375/*++\r
1376\r
1377Routine Description:\r
1378\r
1379 GC_TODO: Add function description\r
1380\r
1381Arguments:\r
1382\r
1383 BaseFileName - GC_TODO: add argument description\r
1384 NewFileName - GC_TODO: add argument description\r
1385 SequenceNumber - GC_TODO: add argument description\r
1386\r
1387Returns:\r
1388\r
1389 GC_TODO: add return values\r
1390\r
1391--*/\r
1392{\r
1393 /*++\r
1394\r
1395Routine Description:\r
1396 Given an initial split capsule file name and a sequence number,\r
1397 create an appropriate file name for this split of a capsule image.\r
1398\r
1399Arguments:\r
1400 BaseFileName - name of of the first split file in the series\r
1401 NewFileName - output name of the split file\r
1402 SequenceNumber - 0-based sequence number of split images\r
1403\r
1404Returns:\r
1405 TRUE - name created successfully\r
1406 FALSE - otherwise\r
1407\r
1408--*/\r
1409 INT8 *Ptr;\r
1410 INT8 *Part2Start;\r
1411 UINT32 Digits;\r
1412 UINT32 Len;\r
1413 UINT32 BaseOffset;\r
1414 //\r
1415 // Work back from the end of the file name and see if there is a number somewhere\r
1416 //\r
1417 for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--)\r
1418 ;\r
1419 if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) {\r
1420 //\r
1421 // Found no number, so just add it to the end\r
1422 //\r
1423 sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber);\r
1424 return TRUE;\r
1425 } else {\r
1426 //\r
1427 // Found a number. Look back to find the first digit.\r
1428 //\r
1429 Part2Start = Ptr + 1;\r
1430 for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++)\r
1431 ;\r
1432 if (!isdigit (*Ptr)) {\r
1433 Ptr++;\r
1434 Digits--;\r
1435 }\r
1436\r
1437 BaseOffset = atoi (Ptr);\r
1438 SequenceNumber = SequenceNumber + BaseOffset;\r
1439 if (Digits > 1) {\r
1440 //\r
1441 // Copy the first part of the original file name to the new filename\r
1442 // This is the path for filenames with format path\name001.cap\r
1443 //\r
1444 Len = (UINT32) Ptr - (UINT32) BaseFileName;\r
1445 strncpy (NewFileName, BaseFileName, Len);\r
1446 sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber);\r
1447 strcat (NewFileName, Part2Start);\r
1448 return TRUE;\r
1449 } else {\r
1450 //\r
1451 // Only one digit found. This is the path for filenames with\r
1452 // format path\name1.cap\r
1453 //\r
1454 Len = (UINT32) Ptr - (UINT32) BaseFileName + 1;\r
1455 strncpy (NewFileName, BaseFileName, Len);\r
1456 sprintf (NewFileName + Len - 1, "%d", SequenceNumber);\r
1457 strcat (NewFileName, Part2Start);\r
1458 return TRUE;\r
1459 }\r
1460 }\r
1461}\r
1462\r
1463static\r
1464BOOLEAN\r
1465IsWhiteSpace (\r
1466 WCHAR Char\r
1467 )\r
1468/*++\r
1469\r
1470Routine Description:\r
1471\r
1472 GC_TODO: Add function description\r
1473\r
1474Arguments:\r
1475\r
1476 Char - GC_TODO: add argument description\r
1477\r
1478Returns:\r
1479\r
1480 GC_TODO: add return values\r
1481\r
1482--*/\r
1483{\r
1484 switch (Char) {\r
1485 case UNICODE_SPACE:\r
1486 case UNICODE_TAB:\r
1487 case UNICODE_NULL:\r
1488 case UNICODE_CR:\r
1489 case UNICODE_LF:\r
1490 return TRUE;\r
1491\r
1492 default:\r
1493 return FALSE;\r
1494 }\r
1495}\r
1496\r
1497static\r
1498BOOLEAN\r
1499IsToken (\r
1500 SOURCE_FILE *File,\r
1501 WCHAR *Token\r
1502 )\r
1503/*++\r
1504\r
1505Routine Description:\r
1506\r
1507 GC_TODO: Add function description\r
1508\r
1509Arguments:\r
1510\r
1511 File - GC_TODO: add argument description\r
1512 Token - GC_TODO: add argument description\r
1513\r
1514Returns:\r
1515\r
1516 GC_TODO: add return values\r
1517\r
1518--*/\r
1519{\r
1520 SkipWhiteSpace (File);\r
1521 if (EndOfFile (File)) {\r
1522 return FALSE;\r
1523 }\r
1524\r
1525 if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) {\r
1526 File->FileBufferPtr += wcslen (Token);\r
1527 return TRUE;\r
1528 }\r
1529\r
1530 return FALSE;\r
1531}\r
1532\r
1533static\r
1534STATUS\r
1535CheckFirmwareVolumeHeader (\r
1536 INT8 *FileName,\r
1537 INT8 *Buffer,\r
1538 UINT32 BufferSize\r
1539 )\r
1540/*++\r
1541\r
1542Routine Description:\r
1543\r
1544 GC_TODO: Add function description\r
1545\r
1546Arguments:\r
1547\r
1548 FileName - GC_TODO: add argument description\r
1549 Buffer - GC_TODO: add argument description\r
1550 BufferSize - GC_TODO: add argument description\r
1551\r
1552Returns:\r
1553\r
1554 GC_TODO: add return values\r
1555\r
1556--*/\r
1557{\r
1558 EFI_FIRMWARE_VOLUME_HEADER *Hdr;\r
1559 EFI_GUID FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;\r
1560\r
1561 Hdr = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
1562 if (Hdr->Signature != EFI_FVH_SIGNATURE) {\r
1563 Error (NULL, 0, 0, FileName, "file does not appear to be a firmware volume (bad signature)");\r
1564 return STATUS_ERROR;\r
1565 }\r
1566\r
1567 if (Hdr->Revision != EFI_FVH_REVISION) {\r
1568 Error (NULL, 0, 0, FileName, "unsupported firmware volume header version");\r
1569 return STATUS_ERROR;\r
1570 }\r
1571\r
1572 if (Hdr->FvLength > BufferSize) {\r
1573 Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size");\r
1574 return STATUS_ERROR;\r
1575 }\r
1576\r
1577 if (memcmp (&Hdr->FileSystemGuid, &FVHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
1578 Error (NULL, 0, 0, FileName, "invalid FFS GUID in firmware volume header");\r
1579 return STATUS_ERROR;\r
1580 }\r
1581\r
1582 return STATUS_SUCCESS;\r
1583}\r
1584\r
1585static\r
1586void\r
1587DumpCapsule (\r
1588 VOID\r
1589 )\r
1590/*++\r
1591\r
1592Routine Description:\r
1593\r
1594 GC_TODO: Add function description\r
1595\r
1596Arguments:\r
1597\r
1598 None\r
1599\r
1600Returns:\r
1601\r
1602 GC_TODO: add return values\r
1603\r
1604--*/\r
1605{\r
1606#if 0\r
1607 FILE *InFptr;\r
1608 FILE_LIST *FileList;\r
1609 EFI_CAPSULE_HEADER CapsuleHeader;\r
1610 EFI_FIRMWARE_VOLUME_HEADER FVHeader;\r
1611 EFI_CAPSULE_OEM_HEADER *OemHeader;\r
1612 UINT8 *BPtr;\r
1613 UINT32 FileSize;\r
1614 UINT32 CapsuleHeaderDataSize;\r
1615 UINT8 ByteCount;\r
1616 UINT8 *CapsuleHeaderData;\r
1617 BOOLEAN SplitImage;\r
1618\r
1619 InFptr = NULL;\r
1620 CapsuleHeaderData = NULL;\r
1621 FileList = mOptions.FileList;\r
1622 while (FileList != NULL) {\r
1623 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
1624 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
1625 goto Done;\r
1626 }\r
1627\r
1628 if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) {\r
1629 Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header");\r
1630 goto Done;\r
1631 }\r
1632\r
1633 fseek (InFptr, 0, SEEK_END);\r
1634 FileSize = ftell (InFptr);\r
1635 if (CapsuleHeader.CapsuleImageSize > FileSize) {\r
1636 SplitImage = TRUE;\r
1637 } else {\r
1638 SplitImage = FALSE;\r
1639 }\r
1640\r
1641 printf (\r
1642 "Capsule %s Size=0x%X CargoSize=0x%X\n",\r
1643 FileList->FileName,\r
1644 FileSize,\r
1645 FileSize - CapsuleHeader.OffsetToCapsuleBody\r
1646 );\r
1647 printf (\r
1648 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
1649 CapsuleHeader.CapsuleGuid.Data1,\r
1650 (UINT32) CapsuleHeader.CapsuleGuid.Data2,\r
1651 (UINT32) CapsuleHeader.CapsuleGuid.Data3,\r
1652 (UINT32) CapsuleHeader.CapsuleGuid.Data4[0],\r
1653 (UINT32) CapsuleHeader.CapsuleGuid.Data4[1],\r
1654 (UINT32) CapsuleHeader.CapsuleGuid.Data4[2],\r
1655 (UINT32) CapsuleHeader.CapsuleGuid.Data4[3],\r
1656 (UINT32) CapsuleHeader.CapsuleGuid.Data4[4],\r
1657 (UINT32) CapsuleHeader.CapsuleGuid.Data4[5],\r
1658 (UINT32) CapsuleHeader.CapsuleGuid.Data4[6],\r
1659 (UINT32) CapsuleHeader.CapsuleGuid.Data4[7]\r
1660 );\r
1661 if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
1662 printf (" INVALID GUID");\r
1663 }\r
1664\r
1665 printf ("\n");\r
1666 printf (" Header size 0x%08X\n", CapsuleHeader.HeaderSize);\r
1667 printf (" Flags 0x%08X\n", CapsuleHeader.Flags);\r
1668 if (!SplitImage) {\r
1669 printf (" Capsule image size 0x%08X\n", CapsuleHeader.CapsuleImageSize);\r
1670 } else {\r
1671 printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader.CapsuleImageSize);\r
1672 }\r
1673\r
1674 printf (" Sequence number %d\n", CapsuleHeader.SequenceNumber);\r
1675 printf (\r
1676 " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
1677 CapsuleHeader.InstanceId.Data1,\r
1678 (UINT32) CapsuleHeader.InstanceId.Data2,\r
1679 (UINT32) CapsuleHeader.InstanceId.Data3,\r
1680 (UINT32) CapsuleHeader.InstanceId.Data4[0],\r
1681 (UINT32) CapsuleHeader.InstanceId.Data4[1],\r
1682 (UINT32) CapsuleHeader.InstanceId.Data4[2],\r
1683 (UINT32) CapsuleHeader.InstanceId.Data4[3],\r
1684 (UINT32) CapsuleHeader.InstanceId.Data4[4],\r
1685 (UINT32) CapsuleHeader.InstanceId.Data4[5],\r
1686 (UINT32) CapsuleHeader.InstanceId.Data4[6],\r
1687 (UINT32) CapsuleHeader.InstanceId.Data4[7]\r
1688 );\r
1689 printf (" Offset to capsule 0x%X\n", CapsuleHeader.OffsetToCapsuleBody);\r
1690 //\r
1691 // Dump header data if there\r
1692 //\r
1693 CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize;\r
1694 if (CapsuleHeaderDataSize != 0) {\r
1695 CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize);\r
1696 if (CapsuleHeaderData == NULL) {\r
1697 Error (\r
1698 NULL,\r
1699 0,\r
1700 0,\r
1701 "failed to allocate memory to read in capsule header data",\r
1702 "0x%X bytes",\r
1703 CapsuleHeaderDataSize\r
1704 );\r
1705 goto Done;\r
1706 }\r
1707\r
1708 fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET);\r
1709 if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) {\r
1710 Error (\r
1711 NULL,\r
1712 0,\r
1713 0,\r
1714 "failed to read capsule header data contents from file",\r
1715 "0x%X bytes",\r
1716 CapsuleHeaderDataSize\r
1717 );\r
1718 goto Done;\r
1719 }\r
1720 //\r
1721 // ************************************************************************\r
1722 //\r
1723 // OEM HEADER\r
1724 //\r
1725 // ************************************************************************\r
1726 //\r
1727 if (CapsuleHeader.OffsetToOemDefinedHeader != 0) {\r
1728 OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize);\r
1729 printf (" OEM Header\n");\r
1730 printf (\r
1731 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
1732 OemHeader->OemGuid.Data1,\r
1733 (UINT32) OemHeader->OemGuid.Data2,\r
1734 (UINT32) OemHeader->OemGuid.Data3,\r
1735 (UINT32) OemHeader->OemGuid.Data4[0],\r
1736 (UINT32) OemHeader->OemGuid.Data4[1],\r
1737 (UINT32) OemHeader->OemGuid.Data4[2],\r
1738 (UINT32) OemHeader->OemGuid.Data4[3],\r
1739 (UINT32) OemHeader->OemGuid.Data4[4],\r
1740 (UINT32) OemHeader->OemGuid.Data4[5],\r
1741 (UINT32) OemHeader->OemGuid.Data4[6],\r
1742 (UINT32) OemHeader->OemGuid.Data4[7]\r
1743 );\r
1744 printf (" Header size: 0x%X\n", OemHeader->HeaderSize);\r
1745 printf (" OEM data");\r
1746 BPtr = (UINT8 *) (OemHeader + 1);\r
1747 for (ByteCount = 0; ByteCount < OemHeader->HeaderSize - sizeof (EFI_CAPSULE_OEM_HEADER); ByteCount++) {\r
1748 if ((ByteCount & 0x7) == 0) {\r
1749 printf ("\n ");\r
1750 }\r
1751\r
1752 printf ("%02X ", (UINT32) *BPtr);\r
1753 BPtr++;\r
1754 }\r
1755\r
1756 printf ("\n");\r
1757 }\r
1758 //\r
1759 // ************************************************************************\r
1760 //\r
1761 // Author, revision, short description, and long description information\r
1762 //\r
1763 // ************************************************************************\r
1764 //\r
1765 if (CapsuleHeader.OffsetToAuthorInformation != 0) {\r
1766 if (DumpCapsuleHeaderStrings (\r
1767 "Author information",\r
1768 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize)\r
1769 ) != STATUS_SUCCESS) {\r
1770 goto Done;\r
1771 }\r
1772 }\r
1773\r
1774 if (CapsuleHeader.OffsetToRevisionInformation != 0) {\r
1775 if (DumpCapsuleHeaderStrings (\r
1776 "Revision information",\r
1777 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize)\r
1778 ) != STATUS_SUCCESS) {\r
1779 goto Done;\r
1780 }\r
1781 }\r
1782\r
1783 if (CapsuleHeader.OffsetToShortDescription != 0) {\r
1784 if (DumpCapsuleHeaderStrings (\r
1785 "Short description",\r
1786 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize)\r
1787 ) != STATUS_SUCCESS) {\r
1788 goto Done;\r
1789 }\r
1790 }\r
1791\r
1792 if (CapsuleHeader.OffsetToLongDescription != 0) {\r
1793 if (DumpCapsuleHeaderStrings (\r
1794 "Long description",\r
1795 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize)\r
1796 ) != STATUS_SUCCESS) {\r
1797 goto Done;\r
1798 }\r
1799 }\r
1800 }\r
1801 //\r
1802 // If it's not a split image, or it is a split image and this is the first in the series, then\r
1803 // dump the cargo volume.\r
1804 //\r
1805 if ((!SplitImage) || (CapsuleHeader.SequenceNumber == 0)) {\r
1806 printf (" Cargo FV dump\n");\r
1807 fseek (InFptr, CapsuleHeader.OffsetToCapsuleBody, SEEK_SET);\r
1808 if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) != 1) {\r
1809 Error (NULL, 0, 0, FileList->FileName, "failed to read cargo FV header");\r
1810 goto Done;\r
1811 }\r
1812\r
1813 printf (" FV length 0x%X", FVHeader.FvLength);\r
1814 if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) {\r
1815 if (!SplitImage) {\r
1816 printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody);\r
1817 }\r
1818 }\r
1819\r
1820 printf ("\n");\r
1821 printf (" Signature 0x%X ", FVHeader.Signature);\r
1822 if (FVHeader.Signature == EFI_FVH_SIGNATURE) {\r
1823 printf ("_FVH\n");\r
1824 } else {\r
1825 printf ("INVALID\n");\r
1826 }\r
1827\r
1828 printf (" FV header length 0x%X\n", (UINT32) FVHeader.HeaderLength);\r
1829 printf (" Revision 0x%X\n", (UINT32) FVHeader.Revision);\r
1830 printf ("\n");\r
1831 }\r
1832\r
1833 FileList = FileList->Next;\r
1834 }\r
1835\r
1836Done:\r
1837 if (InFptr != NULL) {\r
1838 fclose (InFptr);\r
1839 }\r
1840\r
1841 if (CapsuleHeaderData != NULL) {\r
1842 free (CapsuleHeaderData);\r
1843 }\r
1844#endif\r
1845}\r
1846\r
1847static\r
1848STATUS\r
1849JoinCapsule (\r
1850 VOID\r
1851 )\r
1852/*++\r
1853\r
1854Routine Description:\r
1855 Join split capsule images into a single image. This is the\r
1856 support function for the -j command-line option.\r
1857\r
1858Arguments:\r
1859 None.\r
1860\r
1861Returns:\r
1862 STATUS_SUCCESS - no problems encountered\r
1863\r
1864--*/\r
1865{\r
1866#if 0\r
1867 UINT32 Size;\r
1868 FILE *InFptr;\r
1869 FILE *OutFptr;\r
1870 INT8 *Buffer;\r
1871 FILE_LIST *FileList;\r
1872 STATUS Status;\r
1873 EFI_CAPSULE_HEADER CapHdr;\r
1874 EFI_CAPSULE_HEADER *CapHdrPtr;\r
1875 UINT32 SizeLeft;\r
1876 UINT32 SequenceNumber;\r
1877 //\r
1878 // Must have at least two files for join mode\r
1879 //\r
1880 if ((mOptions.FileList == NULL) || (mOptions.FileList->Next == NULL)) {\r
1881 Error (NULL, 0, 0, "must specify at least two file names to join", NULL);\r
1882 return STATUS_ERROR;\r
1883 }\r
1884 //\r
1885 // Open the output file\r
1886 //\r
1887 if ((OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
1888 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
1889 return STATUS_ERROR;\r
1890 }\r
1891\r
1892 FileList = mOptions.FileList;\r
1893 Buffer = NULL;\r
1894 SequenceNumber = 0;\r
1895 InFptr = NULL;\r
1896 SizeLeft = 0;\r
1897 while (FileList != NULL) {\r
1898 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
1899 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
1900 goto FailDone;\r
1901 }\r
1902 //\r
1903 // Allocate a buffer into which we can read the file.\r
1904 //\r
1905 fseek (InFptr, 0, SEEK_END);\r
1906 Size = ftell (InFptr);\r
1907 rewind (InFptr);\r
1908 Buffer = (char *) malloc (Size);\r
1909 if (Buffer == NULL) {\r
1910 Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
1911 goto FailDone;\r
1912 }\r
1913\r
1914 CapHdrPtr = (EFI_CAPSULE_HEADER *) Buffer;\r
1915 if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
1916 Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
1917 goto FailDone;\r
1918 }\r
1919 //\r
1920 // Check the header for validity. Check size first.\r
1921 //\r
1922 if (Size < sizeof (EFI_CAPSULE_HEADER)) {\r
1923 Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header");\r
1924 goto FailDone;\r
1925 }\r
1926 //\r
1927 // Check GUID\r
1928 //\r
1929 if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
1930 Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID");\r
1931 goto FailDone;\r
1932 }\r
1933 //\r
1934 // Check sequence number\r
1935 //\r
1936 if (CapHdrPtr->SequenceNumber != SequenceNumber) {\r
1937 Error (\r
1938 NULL,\r
1939 0,\r
1940 0,\r
1941 FileList->FileName,\r
1942 "invalid sequence number %d (expected %d)",\r
1943 CapHdrPtr->SequenceNumber,\r
1944 SequenceNumber\r
1945 );\r
1946 goto FailDone;\r
1947 }\r
1948 //\r
1949 // If the first file, read save the capsule header\r
1950 //\r
1951 if (SequenceNumber == 0) {\r
1952 memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER));\r
1953 //\r
1954 // Erase the InstanceId GUID\r
1955 //\r
1956 memset (&CapHdrPtr->InstanceId, 0, sizeof (EFI_GUID));\r
1957 if (fwrite (Buffer, Size, 1, OutFptr) != 1) {\r
1958 Error (NULL, 0, 0, FileList->FileName, "failed to write contents to output file");\r
1959 goto FailDone;\r
1960 }\r
1961\r
1962 if (CapHdr.CapsuleImageSize < Size) {\r
1963 Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size");\r
1964 goto FailDone;\r
1965 }\r
1966\r
1967 SizeLeft = CapHdr.CapsuleImageSize - Size;\r
1968 } else {\r
1969 //\r
1970 // Check the GUID against the first file's GUID\r
1971 //\r
1972 if (memcmp (&CapHdr.CapsuleGuid, &CapHdrPtr->CapsuleGuid, sizeof (EFI_GUID)) != 0) {\r
1973 Error (NULL, 0, 0, FileList->FileName, "GUID does not match first file's GUID");\r
1974 goto FailDone;\r
1975 }\r
1976 //\r
1977 // Make sure we're not throwing out any header info\r
1978 //\r
1979 if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) {\r
1980 //\r
1981 // Could be the split information, so just emit a warning\r
1982 //\r
1983 Warning (\r
1984 NULL,\r
1985 0,\r
1986 0,\r
1987 FileList->FileName,\r
1988 "image appears to have additional capsule header information -- ignoring"\r
1989 );\r
1990 } else if (CapHdrPtr->OffsetToCapsuleBody < sizeof (EFI_CAPSULE_HEADER)) {\r
1991 Error (NULL, 0, 0, FileList->FileName, "offset to capsule body in capsule header is insufficient");\r
1992 goto FailDone;\r
1993 }\r
1994\r
1995 if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) {\r
1996 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
1997 goto FailDone;\r
1998 }\r
1999\r
2000 if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) {\r
2001 Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL);\r
2002 goto FailDone;\r
2003 }\r
2004 //\r
2005 // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);\r
2006 //\r
2007 SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody);\r
2008 }\r
2009 //\r
2010 // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);\r
2011 //\r
2012 fclose (InFptr);\r
2013 InFptr = NULL;\r
2014 free (Buffer);\r
2015 Buffer = NULL;\r
2016 FileList = FileList->Next;\r
2017 SequenceNumber++;\r
2018 }\r
2019\r
2020 if (SizeLeft) {\r
2021 Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft);\r
2022 goto FailDone;\r
2023 }\r
2024\r
2025 Status = STATUS_SUCCESS;\r
2026 goto Done;\r
2027FailDone:\r
2028 Status = STATUS_ERROR;\r
2029Done:\r
2030 if (InFptr != NULL) {\r
2031 fclose (InFptr);\r
2032 }\r
2033\r
2034 if (OutFptr != NULL) {\r
2035 fclose (OutFptr);\r
2036 }\r
2037\r
2038 if (Buffer != NULL) {\r
2039 free (Buffer);\r
2040 }\r
2041\r
2042 return Status;\r
2043\r
2044#endif\r
2045return STATUS_SUCCESS;\r
2046}\r
2047\r
2048static\r
2049STATUS\r
2050DumpCapsuleHeaderStrings (\r
2051 UINT8 *SectionName,\r
2052 WCHAR *Buffer\r
2053 )\r
2054/*++\r
2055\r
2056Routine Description:\r
2057 Given a pointer to string data from a capsule header, dump\r
2058 the strings.\r
2059\r
2060Arguments:\r
2061 SectionName - name of the capsule header section to which\r
2062 the string data pertains\r
2063 Buffer - pointer to string data from a capsule header\r
2064\r
2065Returns:\r
2066 STATUS_SUCCESS - all went well\r
2067\r
2068--*/\r
2069{\r
2070 printf (" %s\n", SectionName);\r
2071 while (*Buffer) {\r
2072 printf (" Language: %S\n", Buffer);\r
2073 while (*Buffer) {\r
2074 Buffer++;\r
2075 }\r
2076\r
2077 Buffer++;\r
2078 while (*Buffer) {\r
2079 if (wcslen (Buffer) > 60) {\r
2080 printf (" %.60S\n", Buffer);\r
2081 Buffer += 60;\r
2082 } else {\r
2083 printf (" %S\n", Buffer);\r
2084 Buffer += wcslen (Buffer);\r
2085 }\r
2086 }\r
2087\r
2088 Buffer++;\r
2089 }\r
2090\r
2091 return STATUS_SUCCESS;\r
2092}\r
2093\r
2094static\r
2095STATUS\r
2096GetHexValue (\r
2097 SOURCE_FILE *SourceFile,\r
2098 UINT32 *Value,\r
2099 UINT32 NumDigits\r
2100 )\r
2101/*++\r
2102\r
2103Routine Description:\r
2104 Scan a hex value from the input stream.\r
2105 \r
2106Arguments:\r
2107 SourceFile - input file contents\r
2108 Value - returned value\r
2109 NumDigits - number of digits to read\r
2110\r
2111Returns:\r
2112 STATUS_SUCCESS - if NumDigits were read from the file\r
2113 STATUS_ERROR - otherwise\r
2114\r
2115 \r
2116--*/\r
2117{\r
2118 WCHAR *SaveFilePos;\r
2119 UINT32 Digits;\r
2120 WCHAR Nibble;\r
2121\r
2122 SaveFilePos = SourceFile->FileBufferPtr;\r
2123 *Value = 0;\r
2124 Digits = NumDigits;\r
2125 while (Digits > 0) {\r
2126 Nibble = SourceFile->FileBufferPtr[0];\r
2127 if ((Nibble >= UNICODE_0) && (Nibble <= UNICODE_9)) {\r
2128 *Value = (*Value << 4) | (Nibble - UNICODE_0);\r
2129 } else if ((Nibble >= UNICODE_A) && (Nibble <= UNICODE_F)) {\r
2130 *Value = (*Value << 4) | (Nibble - UNICODE_A + 0x10);\r
2131 } else if ((Nibble >= UNICODE_a) && (Nibble <= UNICODE_f)) {\r
2132 *Value = (*Value << 4) | (Nibble - UNICODE_a + 0x10);\r
2133 } else {\r
2134 Error (\r
2135 SourceFile->FileName,\r
2136 SourceFile->LineNum,\r
2137 0,\r
2138 NULL,\r
2139 "expected %d valid hex nibbles at %.20S",\r
2140 NumDigits,\r
2141 SaveFilePos\r
2142 );\r
2143 return STATUS_ERROR;\r
2144 }\r
2145\r
2146 SourceFile->FileBufferPtr++;\r
2147 Digits--;\r
2148 }\r
2149\r
2150 return STATUS_SUCCESS;\r
2151}\r
2152\r
2153static\r
2154BOOLEAN\r
2155EndOfFile (\r
2156 SOURCE_FILE *File\r
2157 )\r
2158/*++\r
2159\r
2160Routine Description:\r
2161\r
2162 GC_TODO: Add function description\r
2163\r
2164Arguments:\r
2165\r
2166 File - GC_TODO: add argument description\r
2167\r
2168Returns:\r
2169\r
2170 GC_TODO: add return values\r
2171\r
2172--*/\r
2173{\r
2174 if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) {\r
2175 File->EndOfFile = TRUE;\r
2176 }\r
2177 //\r
2178 // Reposition to the end of the file if we went beyond\r
2179 //\r
2180 if (File->EndOfFile) {\r
2181 File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR);\r
2182 }\r
2183\r
2184 return File->EndOfFile;\r
2185}\r
2186\r
2187static\r
2188void\r
2189SkipWhiteSpace (\r
2190 SOURCE_FILE *SourceFile\r
2191 )\r
2192/*++\r
2193\r
2194Routine Description:\r
2195\r
2196 GC_TODO: Add function description\r
2197\r
2198Arguments:\r
2199\r
2200 SourceFile - GC_TODO: add argument description\r
2201\r
2202Returns:\r
2203\r
2204 GC_TODO: add return values\r
2205\r
2206--*/\r
2207{\r
2208 while (!EndOfFile (SourceFile)) {\r
2209 switch (*SourceFile->FileBufferPtr) {\r
2210 case UNICODE_NULL:\r
2211 case UNICODE_CR:\r
2212 case UNICODE_SPACE:\r
2213 case UNICODE_TAB:\r
2214 SourceFile->FileBufferPtr++;\r
2215 break;\r
2216\r
2217 case UNICODE_LF:\r
2218 SourceFile->FileBufferPtr++;\r
2219 SourceFile->LineNum++;\r
2220 break;\r
2221\r
2222 default:\r
2223 return ;\r
2224 }\r
2225 }\r
2226}\r
2227//\r
2228// Parse a number. Possible format:\r
2229// 1234\r
2230// 1234k\r
2231// 1234K\r
2232// 1M\r
2233// 1m\r
2234// 0x100\r
2235//\r
2236static\r
2237BOOLEAN\r
2238GetNumber (\r
2239 INT8 *Str,\r
2240 UINT32 *Value\r
2241 )\r
2242/*++\r
2243\r
2244Routine Description:\r
2245\r
2246 GC_TODO: Add function description\r
2247\r
2248Arguments:\r
2249\r
2250 Str - GC_TODO: add argument description\r
2251 Value - GC_TODO: add argument description\r
2252\r
2253Returns:\r
2254\r
2255 GC_TODO: add return values\r
2256\r
2257--*/\r
2258{\r
2259 UINT32 LValue;\r
2260\r
2261 *Value = 0;\r
2262 LValue = 0;\r
2263 if (!isdigit (Str[0])) {\r
2264 return FALSE;\r
2265 }\r
2266 //\r
2267 // Look for hex number\r
2268 //\r
2269 if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) {\r
2270 Str += 2;\r
2271 if (Str[0] == 0) {\r
2272 return FALSE;\r
2273 }\r
2274\r
2275 while (Str[0]) {\r
2276 if ((Str[0] >= '0') && (Str[0] <= '9')) {\r
2277 LValue = (LValue << 4) | (Str[0] - '0');\r
2278 } else if ((Str[0] >= 'A') && (Str[0] <= 'F')) {\r
2279 LValue = (LValue << 4) | (Str[0] - 'A' + 0x10);\r
2280 } else if ((Str[0] >= 'a') && (Str[0] <= 'f')) {\r
2281 LValue = (LValue << 4) | (Str[0] - 'a' + 0x10);\r
2282 } else {\r
2283 break;\r
2284 }\r
2285\r
2286 Str++;\r
2287 }\r
2288 } else {\r
2289 LValue = atoi (Str);\r
2290 while (isdigit (*Str)) {\r
2291 Str++;\r
2292 }\r
2293 }\r
2294 //\r
2295 // If string left over, better be one character we recognize\r
2296 //\r
2297 if (Str[0]) {\r
2298 if (Str[1]) {\r
2299 return FALSE;\r
2300 }\r
2301\r
2302 switch (Str[0]) {\r
2303 case 'k':\r
2304 case 'K':\r
2305 LValue *= 1024;\r
2306 break;\r
2307\r
2308 case 'm':\r
2309 case 'M':\r
2310 LValue *= 1024 * 1024;\r
2311 break;\r
2312\r
2313 default:\r
2314 return FALSE;\r
2315 }\r
2316 }\r
2317\r
2318 *Value = LValue;\r
2319 return TRUE;\r
2320}\r
2321//\r
2322// Process the command-line arguments\r
2323//\r
2324static\r
2325STATUS\r
2326ProcessArgs (\r
2327 int Argc,\r
2328 char *Argv[]\r
2329 )\r
2330/*++\r
2331\r
2332Routine Description:\r
2333\r
2334 Processes command line arguments.\r
2335\r
2336Arguments:\r
2337\r
2338 Argc - Number of command line arguments\r
2339 Argv[] - Array of files input on command line \r
2340\r
2341Returns:\r
2342\r
2343 STATUS_ERROR - Function exited with an error\r
2344 STATUS_SUCCESS - Function executed successfully\r
2345\r
2346--*/\r
2347{\r
2348 FILE_LIST *NewFile;\r
2349\r
2350 FILE_LIST *LastFile;\r
2351 SIZE_LIST *NewSize;\r
2352 \r
2353 NewFile = NULL;\r
2354 NewSize = NULL;\r
2355 \r
2356 //\r
2357 // Clear our globals\r
2358 //\r
2359 memset ((char *) &mOptions, 0, sizeof (mOptions));\r
2360\r
2361 //\r
2362 // Skip program name\r
2363 //\r
2364 Argc--;\r
2365 Argv++;\r
2366\r
60db81c1 2367 if (Argc == 0) {\r
d25c4bf0 2368 Usage ();\r
2369 return STATUS_ERROR;\r
2370 }\r
52be9a3b 2371 \r
2372 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||\r
2373 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {\r
2374 Usage();\r
2375 return STATUS_ERROR;\r
2376 }\r
2377 \r
2378 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {\r
2379 Version();\r
2380 return STATUS_ERROR;\r
2381 }\r
db608e6b 2382 \r
2383 if (Argc == 1) {\r
2384 Usage ();\r
2385 return STATUS_ERROR;\r
2386 }\r
52be9a3b 2387 \r
d25c4bf0 2388 //\r
2389 // Process until no more options\r
2390 //\r
2391 while ((Argc > 0) && (Argv[0][0] == '-')) {\r
2392 if (stricmp (Argv[0], "-script") == 0) {\r
2393 //\r
2394 // Check for one more arg\r
2395 //\r
2396 if (Argc > 1) {\r
2397 //\r
2398 // Save the file name\r
2399 //\r
2400 if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) {\r
2401 Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size");\r
2402 \r
2403 if (NewFile != NULL) {\r
2404 free (NewFile);\r
2405 }\r
2406 if (NewSize != NULL) {\r
2407 free (NewSize);\r
2408 }\r
2409 \r
2410 return STATUS_ERROR;\r
2411 }\r
2412\r
2413 strcpy (mOptions.ScriptFileName, Argv[1]);\r
2414 } else {\r
2415 Error (NULL, 0, 0, Argv[0], "missing script file name with option");\r
2416 Usage ();\r
2417 \r
2418 if (NewFile != NULL) {\r
2419 free (NewFile);\r
2420 }\r
2421 if (NewSize != NULL) {\r
2422 free (NewSize);\r
2423 } \r
2424\r
2425 return STATUS_ERROR;\r
2426 }\r
2427\r
2428 Argc--;\r
2429 Argv++;\r
2430 //\r
2431 // -o outfilename -- specify output file name (required)\r
2432 //\r
2433 } else if (stricmp (Argv[0], "-o") == 0) {\r
2434 //\r
2435 // check for one more arg\r
2436 //\r
2437 if (Argc > 1) {\r
2438 //\r
2439 // Try to open the file\r
2440 //\r
2441 // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {\r
2442 // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");\r
2443 // return STATUS_ERROR;\r
2444 // }\r
2445 //\r
2446 strcpy (mOptions.OutputFileName, Argv[1]);\r
2447 } else {\r
2448 Error (NULL, 0, 0, Argv[0], "missing output filename with option");\r
2449 Usage ();\r
2450 \r
2451 if (NewFile != NULL) {\r
2452 free (NewFile);\r
2453 }\r
2454 if (NewSize != NULL) {\r
2455 free (NewSize);\r
2456 }\r
2457 \r
2458 return STATUS_ERROR;\r
2459 }\r
2460\r
2461 Argc--;\r
2462 Argv++;\r
2463 } else if (stricmp (Argv[0], "-j") == 0) {\r
2464 mOptions.JoinMode = TRUE;\r
2465 //\r
2466 // -split <size> option (multiple allowed)\r
2467 //\r
2468 } else if (stricmp (Argv[0], "-split") == 0) {\r
2469 if (Argc > 1) {\r
2470 NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST));\r
2471 if (NewSize == NULL) {\r
2472 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
2473\r
2474 if (NewFile != NULL) {\r
2475 free (NewFile);\r
2476 }\r
2477 if (NewSize != NULL) {\r
2478 free (NewSize);\r
2479 }\r
2480 \r
2481 return STATUS_ERROR;\r
2482 }\r
2483\r
2484 memset (NewSize, 0, sizeof (SIZE_LIST));\r
2485 //\r
2486 // Get the size from the next arg, and then add this size\r
2487 // to our size list\r
2488 //\r
2489 if (!GetNumber (Argv[1], &NewSize->Size)) {\r
2490 Error (NULL, 0, 0, Argv[1], "invalid split size argument");\r
2491\r
2492 if (NewFile != NULL) {\r
2493 free (NewFile);\r
2494 }\r
2495 if (NewSize != NULL) {\r
2496 free (NewSize);\r
2497 } \r
2498 \r
2499 return STATUS_ERROR;\r
2500 }\r
2501\r
2502 if (mOptions.SizeList == NULL) {\r
2503 mOptions.SizeList = NewSize;\r
2504 mOptions.CurrentSize = NewSize;\r
2505 } else {\r
2506 mOptions.LastSize->Next = NewSize;\r
2507 }\r
2508\r
2509 mOptions.LastSize = NewSize;\r
2510 free (NewSize);\r
2511 } else {\r
2512 Error (NULL, 0, 0, Argv[0], "missing size parameter with option");\r
2513 Usage ();\r
2514\r
2515 if (NewFile != NULL) {\r
2516 free (NewFile);\r
2517 }\r
2518 if (NewSize != NULL) {\r
2519 free (NewSize);\r
2520 }\r
2521 \r
2522 return STATUS_ERROR;\r
2523 }\r
2524\r
2525 Argc--;\r
2526 Argv++; \r
2527 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
2528 Usage ();\r
2529 \r
2530 if (NewFile != NULL) {\r
2531 free (NewFile);\r
2532 }\r
2533 if (NewSize != NULL) {\r
2534 free (NewSize);\r
2535 }\r
2536 \r
2537 return STATUS_ERROR;\r
2538 //\r
2539 // Default minimum header\r
2540 //\r
2541 } else if (stricmp (Argv[0], "-dump") == 0) {\r
2542 mOptions.Dump = TRUE;\r
2543 } else if (stricmp (Argv[0], "-v") == 0) {\r
2544 mOptions.Verbose = TRUE;\r
2545 } else {\r
2546 Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
2547 Usage ();\r
2548 \r
2549 if (NewFile != NULL) {\r
2550 free (NewFile);\r
2551 }\r
2552 if (NewSize != NULL) {\r
2553 free (NewSize);\r
2554 }\r
2555 \r
2556 return STATUS_ERROR;\r
2557 }\r
2558\r
2559 Argc--;\r
2560 Argv++;\r
2561 }\r
2562 //\r
2563 // Can't -j join files and -s split output capsule\r
2564 //\r
2565 if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) {\r
2566 Error (NULL, 0, 0, "cannot specify both -j and -size", NULL);\r
2567 \r
2568 if (NewFile != NULL) {\r
2569 free (NewFile);\r
2570 }\r
2571 if (NewSize != NULL) {\r
2572 free (NewSize);\r
2573 }\r
2574 \r
2575 return STATUS_ERROR;\r
2576 }\r
2577 //\r
2578 // Must have specified an output file name if not -dump\r
2579 //\r
2580 if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) {\r
2581 Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified");\r
2582 Usage ();\r
2583 \r
2584 if (NewFile != NULL) {\r
2585 free (NewFile);\r
2586 }\r
2587 if (NewSize != NULL) {\r
2588 free (NewSize);\r
2589 }\r
2590 \r
2591 return STATUS_ERROR;\r
2592 }\r
2593 //\r
2594 // Rest of arguments are input files. The first one is a firmware\r
2595 // volume image, and the rest are FFS files that are to be inserted\r
2596 // into the firmware volume.\r
2597 //\r
2598 LastFile = NULL;\r
2599 while (Argc > 0) {\r
2600 NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
2601 if (NewFile == NULL) {\r
2602 Error (NULL, 0, 0, "memory allocation failure", NULL);\r
2603\r
2604 if (NewFile != NULL) {\r
2605 free (NewFile);\r
2606 }\r
2607 if (NewSize != NULL) {\r
2608 free (NewSize);\r
2609 }\r
2610 \r
2611 return STATUS_ERROR;\r
2612 }\r
2613\r
2614 memset ((char *) NewFile, 0, sizeof (FILE_LIST));\r
2615 strcpy (NewFile->FileName, Argv[0]);\r
2616 if (mOptions.FileList == NULL) {\r
2617 mOptions.FileList = NewFile;\r
2618 } else {\r
2619 if (LastFile == NULL) {\r
2620 LastFile = NewFile;\r
2621 } else {\r
2622 LastFile->Next = NewFile;\r
2623 } \r
2624 }\r
2625\r
2626 LastFile = NewFile;\r
2627 Argc--;\r
2628 Argv++;\r
2629 }\r
2630\r
2631 //\r
2632 // Must have provided at least one file name\r
2633 //\r
2634 if (mOptions.FileList == NULL) {\r
2635 Error (NULL, 0, 0, "must specify at least one file name", NULL);\r
2636 Usage ();\r
2637 \r
2638 if (NewFile != NULL) {\r
2639 free (NewFile);\r
2640 }\r
2641 if (NewSize != NULL) {\r
2642 free (NewSize);\r
2643 }\r
2644 \r
2645 return STATUS_ERROR;\r
2646 }\r
2647\r
2648 return STATUS_SUCCESS;\r
2649}\r
2650\r
52be9a3b 2651static\r
2652void \r
2653Version(\r
2654 void\r
2655 )\r
2656/*++\r
2657\r
2658Routine Description:\r
2659\r
2660 Print out version information for this utility.\r
2661\r
2662Arguments:\r
2663\r
2664 None\r
2665 \r
2666Returns:\r
2667\r
2668 None\r
2669 \r
2670--*/ \r
2671{\r
2672 printf ("%s v%d.%d -EDK utility to create a capsule header.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
2673 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");\r
2674}\r
2675\r
d25c4bf0 2676static\r
2677void\r
2678Usage (\r
2679 VOID\r
2680 )\r
2681/*++\r
2682\r
2683Routine Description:\r
2684\r
2685 Print usage information for this utility.\r
2686 \r
2687Arguments:\r
2688\r
2689 None.\r
2690\r
2691Returns:\r
2692\r
2693 Nothing.\r
2694 \r
2695--*/\r
2696{\r
2697 int Index;\r
2698 static const char *Str[] = {\r
52be9a3b 2699 "\nUsage: "UTILITY_NAME " {options} [CapsuleFV]",\r
d25c4bf0 2700 //\r
2701 // {FfsFileNames}",\r
2702 //\r
2703 " Options include:",\r
52be9a3b 2704 " -h,--help,-?,/? to display help messages",\r
2705 " -V,--version to display version information",\r
d25c4bf0 2706 " -script fname to take capsule header info from unicode script",\r
2707 " file fname",\r
2708 " -o fname write output to file fname (required)",\r
2709 " -split size split capsule image into multiple output files",\r
2710 " -dump to dump a capsule header",\r
2711 " -v for verbose output\n",\r
2712 " -j to join split capsule images into a single image",\r
2713 "",\r
2714 " CapsuleFV is the name of an existing well-formed Tiano firmware",\r
2715 " volume file.",\r
2716 //\r
2717 // FfsFileNames are the names of one or more Tiano FFS files to",\r
2718 // " insert into the output capsule image.",\r
2719 //\r
2720 NULL\r
2721 };\r
52be9a3b 2722 \r
2723 Version();\r
2724 \r
d25c4bf0 2725 for (Index = 0; Str[Index] != NULL; Index++) {\r
2726 fprintf (stdout, "%s\n", Str[Index]);\r
2727 }\r
2728}\r