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