1 /*++ 2 3 Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 HiiPack.c 15 16 Abstract: 17 18 Process HII package files to generate HII package list binary file or PE/COFF 19 resource script file (i.e. .rc file). 20 21 --*/ 22 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "Tiano.h" 27 #include "EfiHii.h" 28 29 #include "EfiUtilityMsgs.h" 30 #include "ParseInf.h" 31 32 #define UTILITY_VERSION "v1.0" 33 #define UTILITY_NAME "HiiPack" 34 #define MAX_PATH 260 35 36 // 37 // Define HII resource section type and name 38 // 39 #define HII_RESOURCE_TYPE "HII" 40 #define HII_RESOURCE_NAME 1 41 42 // 43 // We'll store lists of file names from the command line in 44 // a linked list of these 45 // 46 typedef struct _FILE_NAME_LIST { 47 struct _FILE_NAME_LIST *Next; 48 UINT8 FileName[MAX_PATH]; 49 UINT32 PackageType; 50 UINT32 Length; 51 UINT8 *Data; 52 } FILE_NAME_LIST; 53 54 // 55 // Create some defines for the different operation modes supported by this utility 56 // 57 #define MODE_CREATE_HII_RESOURCE_FILE 0x0001 58 #define MODE_CREATE_HII_PACKAGE_LIST 0x0002 59 60 // 61 // Here's all our globals. 62 // 63 static struct { 64 FILE_NAME_LIST *PackageFile; // all include paths to search 65 FILE_NAME_LIST *LastPackageFile; 66 UINT8 PackageListFileName[MAX_PATH]; // Output package list file name 67 UINT8 ResourceFileName[MAX_PATH]; // Output HII resource file name 68 EFI_GUID Guid; // Guid specified on command line 69 BOOLEAN GuidSpecified; 70 BOOLEAN Verbose; 71 UINT32 Mode; // Mode this utility is operating in 72 } mGlobals; 73 74 static 75 void 76 Usage ( 77 VOID 78 ); 79 80 static 81 STATUS 82 ProcessArgs ( 83 int Argc, 84 char *Argv[] 85 ); 86 87 static 88 void 89 FreeGlobals ( 90 VOID 91 ); 92 93 static 94 void 95 DumpRawBytes ( 96 FILE *OutFptr, 97 UINT8 *Buffer, 98 int Count, 99 int Indent 100 ); 101 102 static 103 STATUS 104 CreateResourceScript ( 105 char *OutputFileName, 106 EFI_GUID *PackageListGuid, 107 FILE_NAME_LIST *PackageFiles 108 ); 109 110 static 111 STATUS 112 CreatePackageList ( 113 char *OutputFileName, 114 EFI_GUID *PackageListGuid, 115 FILE_NAME_LIST *PackageFiles 116 ); 117 118 int 119 main ( 120 int Argc, 121 char *Argv[] 122 ) 123 /*++ 124 125 Routine Description: 126 127 Call the routine to parse the command-line options, then process the file. 128 129 Arguments: 130 131 Standard C main() argc and argv. 132 133 Returns: 134 135 0 if successful 136 nonzero otherwise 137 138 --*/ 139 { 140 STATUS Status; 141 142 // 143 // Set the utility name for error reporting purposes 144 // 145 SetUtilityName (UTILITY_NAME); 146 147 // 148 // Process the command-line arguments 149 // 150 Status = ProcessArgs (Argc, Argv); 151 if (Status != STATUS_SUCCESS) { 152 return Status; 153 } 154 155 // 156 // Switch based on args 157 // 158 if (mGlobals.Mode & MODE_CREATE_HII_RESOURCE_FILE) { 159 CreateResourceScript (mGlobals.ResourceFileName, &mGlobals.Guid, mGlobals.PackageFile); 160 } 161 162 if (mGlobals.Mode & MODE_CREATE_HII_PACKAGE_LIST) { 163 CreatePackageList (mGlobals.PackageListFileName, &mGlobals.Guid, mGlobals.PackageFile); 164 } 165 166 FreeGlobals (); 167 168 return GetUtilityStatus (); 169 } 170 171 /******************************************************************************/ 172 static const char *gRcFileHeader[] = { 173 "//", 174 "// DO NOT EDIT -- auto-generated file", 175 "//", 176 "// This file is generated by the hiipack utility", 177 "//", 178 NULL 179 }; 180 181 static 182 STATUS 183 CreateResourceScript ( 184 char *OutputFileName, 185 EFI_GUID *PackageListGuid, 186 FILE_NAME_LIST *PackageFiles 187 ) 188 /*++ 189 190 Routine Description: 191 192 Given a linked list of HII package files, walk the list to 193 process them and create a single HII resource script file. 194 195 Arguments: 196 197 OutputFileName - name of output HII resource script file to create 198 PackageListGuid - the specified package list GUID 199 PackageFiles - linked list of HII package files to process 200 201 Returns: 202 203 STATUS_SUCCESS - if successful 204 STATUS_ERROR - otherwise 205 206 --*/ 207 { 208 STATUS Status; 209 UINT8 *PackageList; 210 UINT8 *Buffer; 211 UINT32 PackageListLen; 212 FILE *OutFptr; 213 UINTN Index; 214 FILE_NAME_LIST *Package; 215 216 // 217 // If no input HII pack files, then why are we here? Should have been caught when 218 // args were processed though. 219 // 220 if (PackageFiles == NULL) { 221 Error (NULL, 0, 0, "no input package file(s) specified", NULL); 222 return STATUS_ERROR; 223 } 224 225 OutFptr = NULL; 226 Status = STATUS_ERROR; 227 228 // 229 // Open the output file for writing 230 // 231 if ((OutFptr = fopen (OutputFileName, "w")) == NULL) { 232 Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); 233 goto Done; 234 } 235 236 // 237 // Write file header 238 // 239 for (Index = 0; gRcFileHeader[Index] != NULL; Index++) { 240 fprintf (OutFptr, "%s\n", gRcFileHeader[Index]); 241 } 242 243 // 244 // Write nameID and typeID 245 // 246 fprintf (OutFptr, "\n"); 247 fprintf (OutFptr, "%d %s\n", HII_RESOURCE_NAME, HII_RESOURCE_TYPE); 248 fprintf (OutFptr, "{\n"); 249 250 // 251 // Prepare package list 252 // 253 PackageListLen = sizeof (EFI_HII_PACKAGE_LIST_HEADER); 254 Package = PackageFiles; 255 while (Package != NULL) { 256 PackageListLen += Package->Length; 257 Package = Package->Next; 258 } 259 // 260 // Inlucde the length of EFI_HII_PACKAGE_END 261 // 262 PackageListLen += sizeof (EFI_HII_PACKAGE_HEADER); 263 264 Buffer = (UINT8 *) malloc (PackageListLen); 265 if (Buffer == NULL) { 266 Error (NULL, 0, 0, "memory allocation failure", NULL); 267 goto Done; 268 } 269 PackageList = Buffer; 270 271 memcpy (Buffer, PackageListGuid, sizeof (EFI_GUID)); 272 Buffer += sizeof (EFI_GUID); 273 memcpy (Buffer, &PackageListLen, sizeof (UINT32)); 274 Buffer += sizeof (UINT32); 275 276 Package = PackageFiles; 277 while (Package != NULL) { 278 memcpy (Buffer, Package->Data, Package->Length); 279 Buffer += Package->Length; 280 Package = Package->Next; 281 } 282 // 283 // Append EFI_HII_PACKAGE_END 284 // 285 ((EFI_HII_PACKAGE_HEADER *) Buffer)->Type = EFI_HII_PACKAGE_END; 286 ((EFI_HII_PACKAGE_HEADER *) Buffer)->Length = sizeof (EFI_HII_PACKAGE_HEADER); 287 288 // 289 // Dump package list 290 // 291 DumpRawBytes (OutFptr, PackageList, PackageListLen, 2); 292 293 // 294 // Write file tail 295 // 296 fprintf (OutFptr, "}\n"); 297 298 Status = STATUS_SUCCESS; 299 300 Done: 301 if (OutFptr != NULL) { 302 fclose (OutFptr); 303 } 304 305 return Status; 306 } 307 308 static 309 STATUS 310 CreatePackageList ( 311 char *OutputFileName, 312 EFI_GUID *PackageListGuid, 313 FILE_NAME_LIST *PackageFiles 314 ) 315 /*++ 316 317 Routine Description: 318 319 Given a linked list of HII package files, walk the list to 320 process them and create a binary HII package list file. 321 322 Arguments: 323 324 OutputFileName - name of output HII package list file to create 325 PackageListGuid - the specified package list GUID 326 PackageFiles - linked list of HII package files to process 327 328 Returns: 329 330 STATUS_SUCCESS - if successful 331 STATUS_ERROR - otherwise 332 333 --*/ 334 { 335 FILE *OutFptr; 336 UINT32 PackageListLen; 337 FILE_NAME_LIST *Package; 338 339 if (OutputFileName == NULL || PackageListGuid == NULL || PackageFiles == NULL) { 340 return STATUS_ERROR; 341 } 342 343 // 344 // Open the output file for writing 345 // 346 if ((OutFptr = fopen (OutputFileName, "wb")) == NULL) { 347 Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); 348 goto Done; 349 } 350 351 // 352 // Write package list header 353 // 354 PackageListLen = sizeof (EFI_HII_PACKAGE_LIST_HEADER); 355 Package = PackageFiles; 356 while (Package != NULL) { 357 PackageListLen += Package->Length; 358 Package = Package->Next; 359 } 360 fwrite (PackageListGuid, sizeof (UINT8), sizeof (EFI_GUID), OutFptr); 361 fwrite (&PackageListLen, sizeof (UINT8), sizeof (UINT32), OutFptr); 362 363 // 364 // Write packages 365 // 366 Package = PackageFiles; 367 while (Package != NULL) { 368 fwrite (Package->Data, sizeof (UINT8), Package->Length, OutFptr); 369 Package = Package->Next; 370 } 371 372 Done: 373 if (OutFptr != NULL) { 374 fclose (OutFptr); 375 } 376 377 return STATUS_SUCCESS; 378 } 379 380 static 381 void 382 FreeGlobals ( 383 VOID 384 ) 385 /*++ 386 387 Routine Description: 388 389 Free up an memory we allocated so we can exit cleanly 390 391 Arguments: 392 393 Returns: NA 394 395 --*/ 396 { 397 FILE_NAME_LIST *Next; 398 399 // 400 // Free up input package file names 401 // 402 while (mGlobals.PackageFile != NULL) { 403 Next = mGlobals.PackageFile->Next; 404 if (mGlobals.PackageFile->Data != NULL) { 405 free (mGlobals.PackageFile->Data); 406 } 407 free (mGlobals.PackageFile); 408 mGlobals.PackageFile = Next; 409 } 410 } 411 412 static 413 void 414 DumpRawBytes ( 415 FILE *OutFptr, 416 UINT8 *Buffer, 417 int Count, 418 int Indent 419 ) 420 /*++ 421 422 Routine Description: 423 424 Dump buffer data into output file. 425 426 Arguments: 427 428 OutFptr - FILE pointer to output file. 429 Buffer - the buffer to dump 430 Count - number of bytes to dump 431 Indent - indent at each line start 432 433 Returns: 434 435 Nothing. 436 437 --*/ 438 { 439 int Counter; 440 int Count2; 441 UINT16 *Ptr16; 442 443 Ptr16 = (UINT16 *) Buffer; 444 Count2 = Count - (Count & 0x1); 445 446 for (Counter = 0; Counter < Count2; Counter += 2) { 447 if ((Counter & 0xF) == 0) { 448 if (Counter == 0) { 449 fprintf (OutFptr, "%*c", Indent, ' '); 450 } else { 451 fprintf (OutFptr, "\n%*c", Indent, ' '); 452 } 453 } 454 455 fprintf (OutFptr, "0x%04X, ", (unsigned int) *Ptr16); 456 Ptr16++; 457 } 458 459 // 460 // Handle the last byte 461 // 462 if ((Count & 0x1) != 0) { 463 if ((Counter & 0xF) == 0) { 464 if (Counter == 0) { 465 fprintf (OutFptr, "%*c", Indent, ' '); 466 } else { 467 fprintf (OutFptr, "\n%*c", Indent, ' '); 468 } 469 } 470 471 fprintf (OutFptr, "0x%04X, ", (unsigned int) (*Ptr16 & 0xff)); 472 } 473 474 fprintf (OutFptr, "\n"); 475 } 476 477 static 478 STATUS 479 LoadPackage ( 480 FILE_NAME_LIST *NameList 481 ) 482 /*++ 483 484 Routine Description: 485 486 Process the command line arguments 487 488 Arguments: 489 490 NameList - the FILE_NAME_LIST linked list node 491 492 Returns: 493 494 STATUS_SUCCESS - if successful 495 STATUS_ERROR - otherwise 496 497 --*/ 498 { 499 STATUS Status; 500 FILE *InFptr; 501 UINT32 BufferSize; 502 UINT8 *Buffer; 503 EFI_HII_PACKAGE_HEADER *PackageHeader; 504 EFI_IFR_FORM_SET *FormSet; 505 506 Status = STATUS_SUCCESS; 507 if (NameList == NULL) { 508 return STATUS_ERROR; 509 } 510 511 // 512 // Try to open the package file 513 // 514 if ((InFptr = fopen (NameList->FileName, "rb")) == NULL) { 515 Error (NULL, 0, 0, NameList->FileName, "failed to open input file for read"); 516 return STATUS_ERROR; 517 } 518 519 // 520 // Get the file size, then allocate a buffer and read in the file contents. 521 // 522 fseek (InFptr, 0, SEEK_END); 523 BufferSize = (UINT32) ftell (InFptr); 524 fseek (InFptr, 0, SEEK_SET); 525 Buffer = (UINT8 *) malloc (BufferSize); 526 if (Buffer == NULL) { 527 Error (NULL, 0, 0, "memory allocation failure", NULL); 528 goto Done; 529 } 530 531 if (fread (Buffer, sizeof (UINT8), BufferSize, InFptr) != BufferSize) { 532 Error (NULL, 0, 0, NameList->FileName, "error reading file contents"); 533 Status = STATUS_ERROR; 534 goto Done; 535 } 536 537 NameList->Length = BufferSize; 538 NameList->Data = Buffer; 539 540 PackageHeader = (EFI_HII_PACKAGE_HEADER *) Buffer; 541 NameList->PackageType = PackageHeader->Type; 542 543 if (!mGlobals.GuidSpecified && NameList->PackageType == EFI_HII_PACKAGE_FORMS) { 544 FormSet = (EFI_IFR_FORM_SET *) (Buffer + sizeof (EFI_HII_PACKAGE_HEADER)); 545 memcpy (&mGlobals.Guid, &FormSet->Guid, sizeof (EFI_GUID)); 546 mGlobals.GuidSpecified = TRUE; 547 } 548 549 Done: 550 fclose (InFptr); 551 552 return Status; 553 } 554 555 556 static 557 STATUS 558 ProcessArgs ( 559 int Argc, 560 char *Argv[] 561 ) 562 /*++ 563 564 Routine Description: 565 566 Process the command line arguments 567 568 Arguments: 569 570 As per standard C main() 571 572 Returns: 573 574 STATUS_SUCCESS - if successful 575 STATUS_ERROR - otherwise 576 577 --*/ 578 { 579 FILE_NAME_LIST *NewList; 580 STATUS Status; 581 582 Status = STATUS_SUCCESS; 583 memset ((void *) &mGlobals, 0, sizeof (mGlobals)); 584 585 // 586 // Skip program name 587 // 588 Argc--; 589 Argv++; 590 591 if (Argc == 0) { 592 Usage (); 593 return STATUS_ERROR; 594 } 595 596 if (_stricmp (Argv[0], "-h") == 0 || _stricmp (Argv[0], "-?") == 0) { 597 Usage (); 598 return STATUS_ERROR; 599 } 600 601 // 602 // Process until no more args. 603 // 604 while (Argc > 0) { 605 if (_stricmp (Argv[0], "-rc") == 0) { 606 Argc--; 607 Argv++; 608 609 if (Argc == 0) { 610 Error (UTILITY_NAME, 0, 0, "mising HII resource file name", NULL); 611 Status = STATUS_ERROR; 612 goto Done; 613 } 614 615 strcpy (mGlobals.ResourceFileName, Argv[0]); 616 mGlobals.Mode |= MODE_CREATE_HII_RESOURCE_FILE; 617 618 } else if (_stricmp (Argv[0], "-hii") == 0) { 619 Argc--; 620 Argv++; 621 622 if (Argc == 0) { 623 Error (UTILITY_NAME, 0, 0, "mising HII package list file name", NULL); 624 Status = STATUS_ERROR; 625 goto Done; 626 } 627 628 strcpy (mGlobals.PackageListFileName, Argv[0]); 629 mGlobals.Mode |= MODE_CREATE_HII_PACKAGE_LIST; 630 631 } else if (_stricmp (Argv[0], "-g") == 0) { 632 Argc--; 633 Argv++; 634 635 if (Argc == 0) { 636 Error (UTILITY_NAME, 0, 0, "mising package list GUID", NULL); 637 Status = STATUS_ERROR; 638 goto Done; 639 } 640 641 Status = StringToGuid (Argv[0], &mGlobals.Guid); 642 if (Status != STATUS_SUCCESS) { 643 goto Done; 644 } 645 mGlobals.GuidSpecified = TRUE; 646 647 } else { 648 // 649 // This is a package file 650 // 651 NewList = malloc (sizeof (FILE_NAME_LIST)); 652 if (NewList == NULL) { 653 Error (UTILITY_NAME, 0, 0, "memory allocation failure", NULL); 654 Status = STATUS_ERROR; 655 goto Done; 656 } 657 658 memset (NewList, 0, sizeof (FILE_NAME_LIST)); 659 strcpy (NewList->FileName, Argv[0]); 660 661 if (mGlobals.PackageFile == NULL) { 662 mGlobals.PackageFile = NewList; 663 } else { 664 mGlobals.LastPackageFile->Next = NewList; 665 } 666 mGlobals.LastPackageFile = NewList; 667 668 Status = LoadPackage (NewList); 669 if (Status != STATUS_SUCCESS) { 670 goto Done; 671 } 672 } 673 674 Argc--; 675 Argv++; 676 } 677 678 if (!mGlobals.GuidSpecified) { 679 Error (UTILITY_NAME, 0, 0, "please specify HII pakcage list GUID", NULL); 680 Status = STATUS_ERROR; 681 } 682 683 Done: 684 if (Status != STATUS_SUCCESS) { 685 FreeGlobals (); 686 } 687 688 return Status; 689 } 690 691 static 692 void 693 Usage ( 694 VOID 695 ) 696 /*++ 697 698 Routine Description: 699 700 Print usage information for this utility. 701 702 Arguments: 703 704 None. 705 706 Returns: 707 708 Nothing. 709 710 --*/ 711 { 712 int i; 713 const char *Str[] = { 714 UTILITY_NAME" "UTILITY_VERSION" - UEFI HII Package List Utility", 715 " Copyright (C), 2008 Intel Corporation", 716 717 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) ) 718 " Built from "UTILITY_BUILD", project of "UTILITY_VENDOR, 719 #endif 720 "", 721 "Usage:", 722 " "UTILITY_NAME" [OPTION] PACKAGE [PACKAGE [...]]", 723 "Description:", 724 " Merge HII package files into a single HII Package List.", 725 "Options:", 726 " -rc FileName write output to PE/COFF Resource Script file", 727 " -hii FileName write output to binary Package List file", 728 " -g GUID use GUID for the HII Package List Guid", 729 "", 730 "PACKAGE is the raw binary HII package file generated by StrGather or", 731 "VfrCompiler which named as *.hpk. For example, merge a Form package and", 732 "a String package into one HII package list:", 733 " \""UTILITY_NAME" -rc Sample.rc -hii Sample.hii \\", 734 " -g 12345678-1234-1234-1234-123456789abc Vfr.hpk Strings.hpk\"", 735 NULL 736 }; 737 for (i = 0; Str[i] != NULL; i++) { 738 fprintf (stdout, "%s\n", Str[i]); 739 } 740 } 741