Home | History | Annotate | Download | only in UefiHiiPack
      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