]>
Commit | Line | Data |
---|---|---|
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 |