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