d25c4bf0 |
1 | /*++\r |
2 | \r |
ad1f8df0 |
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 |
d25c4bf0 |
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 |
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 |
81 | typedef wchar_t WCHAR;\r |
82 | \r |
83 | typedef struct _FILE_LIST {\r |
84 | struct _FILE_LIST *Next;\r |
85 | INT8 FileName[MAX_PATH];\r |
86 | } FILE_LIST;\r |
87 | \r |
88 | typedef struct _SIZE_LIST {\r |
89 | struct _SIZE_LIST *Next;\r |
90 | UINT32 Size;\r |
91 | } SIZE_LIST;\r |
92 | \r |
93 | typedef 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 |
106 | static 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 |
119 | static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;\r |
120 | \r |
121 | void\r |
122 | CreateGuid (\r |
123 | EFI_GUID *Guid\r |
124 | );\r |
125 | \r |
126 | static\r |
127 | STATUS\r |
128 | ProcessArgs (\r |
129 | int Argc,\r |
130 | char *Argv[]\r |
131 | );\r |
132 | \r |
133 | static\r |
134 | void\r |
135 | SkipWhiteSpace (\r |
136 | SOURCE_FILE *SourceFile\r |
137 | );\r |
138 | \r |
139 | static\r |
140 | STATUS\r |
141 | GetHexValue (\r |
142 | SOURCE_FILE *SourceFile,\r |
143 | UINT32 *Value,\r |
144 | UINT32 NumDigits\r |
145 | );\r |
146 | \r |
147 | static\r |
148 | BOOLEAN\r |
149 | GetSplitFileName (\r |
150 | INT8 *BaseFileName,\r |
151 | INT8 *NewFileName,\r |
152 | UINT32 SequenceNumber\r |
153 | );\r |
154 | \r |
155 | static\r |
156 | STATUS\r |
157 | SplitCapsule (\r |
158 | INT8 *CapsuleFileName\r |
159 | );\r |
160 | \r |
161 | static\r |
162 | void\r |
163 | Usage (\r |
164 | VOID\r |
165 | );\r |
166 | \r |
167 | static\r |
168 | void\r |
169 | DumpCapsule (\r |
170 | VOID\r |
171 | );\r |
172 | \r |
173 | static\r |
174 | STATUS\r |
175 | JoinCapsule (\r |
176 | VOID\r |
177 | );\r |
178 | \r |
179 | static\r |
180 | STATUS\r |
181 | DumpCapsuleHeaderStrings (\r |
182 | UINT8 *SectionName,\r |
183 | WCHAR *Buffer\r |
184 | );\r |
185 | \r |
186 | static\r |
187 | STATUS\r |
188 | CheckFirmwareVolumeHeader (\r |
189 | INT8 *FileName,\r |
190 | INT8 *Buffer,\r |
191 | UINT32 BufferSize\r |
192 | );\r |
193 | \r |
194 | static\r |
195 | BOOLEAN\r |
196 | IsToken (\r |
197 | SOURCE_FILE *File,\r |
198 | WCHAR *Token\r |
199 | );\r |
200 | \r |
201 | static\r |
202 | BOOLEAN\r |
203 | GetNumber (\r |
204 | INT8 *Str,\r |
205 | UINT32 *Value\r |
206 | );\r |
207 | \r |
208 | static\r |
209 | STATUS\r |
210 | ProcessScriptFile (\r |
211 | INT8 *ScriptFileName,\r |
212 | FILE *OutFptr,\r |
213 | EFI_CAPSULE_HEADER *CapsuleHeader\r |
214 | );\r |
215 | \r |
216 | static\r |
217 | STATUS\r |
218 | ParseCapsuleInfo (\r |
219 | SOURCE_FILE *SourceFile,\r |
220 | FILE *OutFptr,\r |
221 | WCHAR *SectionName\r |
222 | );\r |
223 | \r |
224 | static\r |
225 | STATUS\r |
226 | CreateCapsule (\r |
227 | VOID\r |
228 | );\r |
229 | \r |
230 | static\r |
231 | STATUS\r |
232 | ParseOemInfo (\r |
233 | SOURCE_FILE *SourceFile,\r |
234 | FILE *OutFptr\r |
235 | );\r |
236 | \r |
237 | static\r |
238 | BOOLEAN\r |
239 | IsWhiteSpace (\r |
240 | WCHAR Char\r |
241 | );\r |
242 | \r |
243 | static\r |
244 | BOOLEAN\r |
245 | EndOfFile (\r |
246 | SOURCE_FILE *File\r |
247 | );\r |
248 | \r |
249 | int\r |
250 | main (\r |
251 | int Argc,\r |
252 | char *Argv[]\r |
253 | )\r |
254 | /*++\r |
255 | \r |
256 | Routine Description:\r |
257 | Call the routine to process the command-line arguments, then\r |
258 | dispatch to the appropriate function.\r |
259 | \r |
260 | Arguments:\r |
261 | Standard C main() argc and argv.\r |
262 | \r |
263 | Returns:\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 |
308 | static\r |
309 | STATUS\r |
310 | CreateCapsule (\r |
311 | VOID\r |
312 | )\r |
313 | /*++\r |
314 | \r |
315 | Routine Description:\r |
316 | \r |
317 | GC_TODO: Add function description\r |
318 | \r |
319 | Arguments:\r |
320 | \r |
321 | None\r |
322 | \r |
323 | Returns:\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 |
485 | Done:\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 |
543 | static\r |
544 | STATUS\r |
545 | ProcessScriptFile (\r |
546 | INT8 *ScriptFileName,\r |
547 | FILE *OutFptr,\r |
548 | EFI_CAPSULE_HEADER *CapsuleHeader\r |
549 | )\r |
550 | /*++\r |
551 | \r |
552 | Routine Description:\r |
553 | Parse a capsule header script file.\r |
554 | \r |
555 | Arguments:\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 |
561 | Returns:\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 |
696 | Done:\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 |
717 | static\r |
718 | STATUS\r |
719 | ParseOemInfo (\r |
720 | SOURCE_FILE *SourceFile,\r |
721 | FILE *OutFptr\r |
722 | )\r |
723 | /*++\r |
724 | \r |
725 | Routine Description:\r |
726 | \r |
727 | GC_TODO: Add function description\r |
728 | \r |
729 | Arguments:\r |
730 | \r |
731 | SourceFile - GC_TODO: add argument description\r |
732 | OutFptr - GC_TODO: add argument description\r |
733 | \r |
734 | Returns:\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 |
1001 | Done:\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 |
1018 | static\r |
1019 | STATUS\r |
1020 | ParseCapsuleInfo (\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 |
1160 | Done:\r |
1161 | return Status;\r |
1162 | }\r |
1163 | \r |
1164 | static\r |
1165 | STATUS\r |
1166 | SplitCapsule (\r |
1167 | INT8 *CapsuleFileName\r |
1168 | )\r |
1169 | /*++\r |
1170 | \r |
1171 | Routine 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 |
1175 | Arguments:\r |
1176 | CapsuleFileName - name of an existing capsule file on disk\r |
1177 | \r |
1178 | Returns:\r |
1179 | STATUS_SUCCESS - if no problems\r |
1180 | \r |
1181 | Notes:\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 |
1338 | FailDone:\r |
1339 | Status = STATUS_ERROR;\r |
1340 | Done:\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 |
1359 | static\r |
1360 | BOOLEAN\r |
1361 | GetSplitFileName (\r |
1362 | INT8 *BaseFileName,\r |
1363 | INT8 *NewFileName,\r |
1364 | UINT32 SequenceNumber\r |
1365 | )\r |
1366 | /*++\r |
1367 | \r |
1368 | Routine Description:\r |
1369 | \r |
1370 | GC_TODO: Add function description\r |
1371 | \r |
1372 | Arguments:\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 |
1378 | Returns:\r |
1379 | \r |
1380 | GC_TODO: add return values\r |
1381 | \r |
1382 | --*/\r |
1383 | {\r |
1384 | /*++\r |
1385 | \r |
1386 | Routine 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 |
1390 | Arguments:\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 |
1395 | Returns:\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 |
1454 | static\r |
1455 | BOOLEAN\r |
1456 | IsWhiteSpace (\r |
1457 | WCHAR Char\r |
1458 | )\r |
1459 | /*++\r |
1460 | \r |
1461 | Routine Description:\r |
1462 | \r |
1463 | GC_TODO: Add function description\r |
1464 | \r |
1465 | Arguments:\r |
1466 | \r |
1467 | Char - GC_TODO: add argument description\r |
1468 | \r |
1469 | Returns:\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 |
1488 | static\r |
1489 | BOOLEAN\r |
1490 | IsToken (\r |
1491 | SOURCE_FILE *File,\r |
1492 | WCHAR *Token\r |
1493 | )\r |
1494 | /*++\r |
1495 | \r |
1496 | Routine Description:\r |
1497 | \r |
1498 | GC_TODO: Add function description\r |
1499 | \r |
1500 | Arguments:\r |
1501 | \r |
1502 | File - GC_TODO: add argument description\r |
1503 | Token - GC_TODO: add argument description\r |
1504 | \r |
1505 | Returns:\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 |
1524 | static\r |
1525 | STATUS\r |
1526 | CheckFirmwareVolumeHeader (\r |
1527 | INT8 *FileName,\r |
1528 | INT8 *Buffer,\r |
1529 | UINT32 BufferSize\r |
1530 | )\r |
1531 | /*++\r |
1532 | \r |
1533 | Routine Description:\r |
1534 | \r |
1535 | GC_TODO: Add function description\r |
1536 | \r |
1537 | Arguments:\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 |
1543 | Returns:\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 |
1576 | static\r |
1577 | void\r |
1578 | DumpCapsule (\r |
1579 | VOID\r |
1580 | )\r |
1581 | /*++\r |
1582 | \r |
1583 | Routine Description:\r |
1584 | \r |
1585 | GC_TODO: Add function description\r |
1586 | \r |
1587 | Arguments:\r |
1588 | \r |
1589 | None\r |
1590 | \r |
1591 | Returns:\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 |
1827 | Done:\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 |
1838 | static\r |
1839 | STATUS\r |
1840 | JoinCapsule (\r |
1841 | VOID\r |
1842 | )\r |
1843 | /*++\r |
1844 | \r |
1845 | Routine 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 |
1849 | Arguments:\r |
1850 | None.\r |
1851 | \r |
1852 | Returns:\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 |
2018 | FailDone:\r |
2019 | Status = STATUS_ERROR;\r |
2020 | Done:\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 |
2036 | return STATUS_SUCCESS;\r |
2037 | }\r |
2038 | \r |
2039 | static\r |
2040 | STATUS\r |
2041 | DumpCapsuleHeaderStrings (\r |
2042 | UINT8 *SectionName,\r |
2043 | WCHAR *Buffer\r |
2044 | )\r |
2045 | /*++\r |
2046 | \r |
2047 | Routine Description:\r |
2048 | Given a pointer to string data from a capsule header, dump\r |
2049 | the strings.\r |
2050 | \r |
2051 | Arguments:\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 |
2056 | Returns:\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 |
2085 | static\r |
2086 | STATUS\r |
2087 | GetHexValue (\r |
2088 | SOURCE_FILE *SourceFile,\r |
2089 | UINT32 *Value,\r |
2090 | UINT32 NumDigits\r |
2091 | )\r |
2092 | /*++\r |
2093 | \r |
2094 | Routine Description:\r |
2095 | Scan a hex value from the input stream.\r |
2096 | \r |
2097 | Arguments:\r |
2098 | SourceFile - input file contents\r |
2099 | Value - returned value\r |
2100 | NumDigits - number of digits to read\r |
2101 | \r |
2102 | Returns:\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 |
2144 | static\r |
2145 | BOOLEAN\r |
2146 | EndOfFile (\r |
2147 | SOURCE_FILE *File\r |
2148 | )\r |
2149 | /*++\r |
2150 | \r |
2151 | Routine Description:\r |
2152 | \r |
2153 | GC_TODO: Add function description\r |
2154 | \r |
2155 | Arguments:\r |
2156 | \r |
2157 | File - GC_TODO: add argument description\r |
2158 | \r |
2159 | Returns:\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 |
2178 | static\r |
2179 | void\r |
2180 | SkipWhiteSpace (\r |
2181 | SOURCE_FILE *SourceFile\r |
2182 | )\r |
2183 | /*++\r |
2184 | \r |
2185 | Routine Description:\r |
2186 | \r |
2187 | GC_TODO: Add function description\r |
2188 | \r |
2189 | Arguments:\r |
2190 | \r |
2191 | SourceFile - GC_TODO: add argument description\r |
2192 | \r |
2193 | Returns:\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 |
2227 | static\r |
2228 | BOOLEAN\r |
2229 | GetNumber (\r |
2230 | INT8 *Str,\r |
2231 | UINT32 *Value\r |
2232 | )\r |
2233 | /*++\r |
2234 | \r |
2235 | Routine Description:\r |
2236 | \r |
2237 | GC_TODO: Add function description\r |
2238 | \r |
2239 | Arguments:\r |
2240 | \r |
2241 | Str - GC_TODO: add argument description\r |
2242 | Value - GC_TODO: add argument description\r |
2243 | \r |
2244 | Returns:\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 |
2315 | static\r |
2316 | STATUS\r |
2317 | ProcessArgs (\r |
2318 | int Argc,\r |
2319 | char *Argv[]\r |
2320 | )\r |
2321 | /*++\r |
2322 | \r |
2323 | Routine Description:\r |
2324 | \r |
2325 | Processes command line arguments.\r |
2326 | \r |
2327 | Arguments:\r |
2328 | \r |
2329 | Argc - Number of command line arguments\r |
2330 | Argv[] - Array of files input on command line \r |
2331 | \r |
2332 | Returns:\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 |
2625 | static\r |
2626 | void\r |
2627 | Usage (\r |
2628 | VOID\r |
2629 | )\r |
2630 | /*++\r |
2631 | \r |
2632 | Routine Description:\r |
2633 | \r |
2634 | Print usage information for this utility.\r |
2635 | \r |
2636 | Arguments:\r |
2637 | \r |
2638 | None.\r |
2639 | \r |
2640 | Returns:\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 |