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