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