| /*++ | |
| Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| HiiPack.c | |
| Abstract: | |
| Process HII package files to generate HII package list binary file or PE/COFF | |
| resource script file (i.e. .rc file). | |
| --*/ | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "Tiano.h" | |
| #include "EfiHii.h" | |
| #include "EfiUtilityMsgs.h" | |
| #include "ParseInf.h" | |
| #define UTILITY_VERSION "v1.0" | |
| #define UTILITY_NAME "HiiPack" | |
| #define MAX_PATH 260 | |
| // | |
| // Define HII resource section type and name | |
| // | |
| #define HII_RESOURCE_TYPE "HII" | |
| #define HII_RESOURCE_NAME 1 | |
| // | |
| // We'll store lists of file names from the command line in | |
| // a linked list of these | |
| // | |
| typedef struct _FILE_NAME_LIST { | |
| struct _FILE_NAME_LIST *Next; | |
| UINT8 FileName[MAX_PATH]; | |
| UINT32 PackageType; | |
| UINT32 Length; | |
| UINT8 *Data; | |
| } FILE_NAME_LIST; | |
| // | |
| // Create some defines for the different operation modes supported by this utility | |
| // | |
| #define MODE_CREATE_HII_RESOURCE_FILE 0x0001 | |
| #define MODE_CREATE_HII_PACKAGE_LIST 0x0002 | |
| // | |
| // Here's all our globals. | |
| // | |
| static struct { | |
| FILE_NAME_LIST *PackageFile; // all include paths to search | |
| FILE_NAME_LIST *LastPackageFile; | |
| UINT8 PackageListFileName[MAX_PATH]; // Output package list file name | |
| UINT8 ResourceFileName[MAX_PATH]; // Output HII resource file name | |
| EFI_GUID Guid; // Guid specified on command line | |
| BOOLEAN GuidSpecified; | |
| BOOLEAN Verbose; | |
| UINT32 Mode; // Mode this utility is operating in | |
| } mGlobals; | |
| static | |
| void | |
| Usage ( | |
| VOID | |
| ); | |
| static | |
| STATUS | |
| ProcessArgs ( | |
| int Argc, | |
| char *Argv[] | |
| ); | |
| static | |
| void | |
| FreeGlobals ( | |
| VOID | |
| ); | |
| static | |
| void | |
| DumpRawBytes ( | |
| FILE *OutFptr, | |
| UINT8 *Buffer, | |
| int Count, | |
| int Indent | |
| ); | |
| static | |
| STATUS | |
| CreateResourceScript ( | |
| char *OutputFileName, | |
| EFI_GUID *PackageListGuid, | |
| FILE_NAME_LIST *PackageFiles | |
| ); | |
| static | |
| STATUS | |
| CreatePackageList ( | |
| char *OutputFileName, | |
| EFI_GUID *PackageListGuid, | |
| FILE_NAME_LIST *PackageFiles | |
| ); | |
| int | |
| main ( | |
| int Argc, | |
| char *Argv[] | |
| ) | |
| /*++ | |
| Routine Description: | |
| Call the routine to parse the command-line options, then process the file. | |
| Arguments: | |
| Standard C main() argc and argv. | |
| Returns: | |
| 0 if successful | |
| nonzero otherwise | |
| --*/ | |
| { | |
| STATUS Status; | |
| // | |
| // Set the utility name for error reporting purposes | |
| // | |
| SetUtilityName (UTILITY_NAME); | |
| // | |
| // Process the command-line arguments | |
| // | |
| Status = ProcessArgs (Argc, Argv); | |
| if (Status != STATUS_SUCCESS) { | |
| return Status; | |
| } | |
| // | |
| // Switch based on args | |
| // | |
| if (mGlobals.Mode & MODE_CREATE_HII_RESOURCE_FILE) { | |
| CreateResourceScript (mGlobals.ResourceFileName, &mGlobals.Guid, mGlobals.PackageFile); | |
| } | |
| if (mGlobals.Mode & MODE_CREATE_HII_PACKAGE_LIST) { | |
| CreatePackageList (mGlobals.PackageListFileName, &mGlobals.Guid, mGlobals.PackageFile); | |
| } | |
| FreeGlobals (); | |
| return GetUtilityStatus (); | |
| } | |
| /******************************************************************************/ | |
| static const char *gRcFileHeader[] = { | |
| "//", | |
| "// DO NOT EDIT -- auto-generated file", | |
| "//", | |
| "// This file is generated by the hiipack utility", | |
| "//", | |
| NULL | |
| }; | |
| static | |
| STATUS | |
| CreateResourceScript ( | |
| char *OutputFileName, | |
| EFI_GUID *PackageListGuid, | |
| FILE_NAME_LIST *PackageFiles | |
| ) | |
| /*++ | |
| Routine Description: | |
| Given a linked list of HII package files, walk the list to | |
| process them and create a single HII resource script file. | |
| Arguments: | |
| OutputFileName - name of output HII resource script file to create | |
| PackageListGuid - the specified package list GUID | |
| PackageFiles - linked list of HII package files to process | |
| Returns: | |
| STATUS_SUCCESS - if successful | |
| STATUS_ERROR - otherwise | |
| --*/ | |
| { | |
| STATUS Status; | |
| UINT8 *PackageList; | |
| UINT8 *Buffer; | |
| UINT32 PackageListLen; | |
| FILE *OutFptr; | |
| UINTN Index; | |
| FILE_NAME_LIST *Package; | |
| // | |
| // If no input HII pack files, then why are we here? Should have been caught when | |
| // args were processed though. | |
| // | |
| if (PackageFiles == NULL) { | |
| Error (NULL, 0, 0, "no input package file(s) specified", NULL); | |
| return STATUS_ERROR; | |
| } | |
| OutFptr = NULL; | |
| Status = STATUS_ERROR; | |
| // | |
| // Open the output file for writing | |
| // | |
| if ((OutFptr = fopen (OutputFileName, "w")) == NULL) { | |
| Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); | |
| goto Done; | |
| } | |
| // | |
| // Write file header | |
| // | |
| for (Index = 0; gRcFileHeader[Index] != NULL; Index++) { | |
| fprintf (OutFptr, "%s\n", gRcFileHeader[Index]); | |
| } | |
| // | |
| // Write nameID and typeID | |
| // | |
| fprintf (OutFptr, "\n"); | |
| fprintf (OutFptr, "%d %s\n", HII_RESOURCE_NAME, HII_RESOURCE_TYPE); | |
| fprintf (OutFptr, "{\n"); | |
| // | |
| // Prepare package list | |
| // | |
| PackageListLen = sizeof (EFI_HII_PACKAGE_LIST_HEADER); | |
| Package = PackageFiles; | |
| while (Package != NULL) { | |
| PackageListLen += Package->Length; | |
| Package = Package->Next; | |
| } | |
| // | |
| // Inlucde the length of EFI_HII_PACKAGE_END | |
| // | |
| PackageListLen += sizeof (EFI_HII_PACKAGE_HEADER); | |
| Buffer = (UINT8 *) malloc (PackageListLen); | |
| if (Buffer == NULL) { | |
| Error (NULL, 0, 0, "memory allocation failure", NULL); | |
| goto Done; | |
| } | |
| PackageList = Buffer; | |
| memcpy (Buffer, PackageListGuid, sizeof (EFI_GUID)); | |
| Buffer += sizeof (EFI_GUID); | |
| memcpy (Buffer, &PackageListLen, sizeof (UINT32)); | |
| Buffer += sizeof (UINT32); | |
| Package = PackageFiles; | |
| while (Package != NULL) { | |
| memcpy (Buffer, Package->Data, Package->Length); | |
| Buffer += Package->Length; | |
| Package = Package->Next; | |
| } | |
| // | |
| // Append EFI_HII_PACKAGE_END | |
| // | |
| ((EFI_HII_PACKAGE_HEADER *) Buffer)->Type = EFI_HII_PACKAGE_END; | |
| ((EFI_HII_PACKAGE_HEADER *) Buffer)->Length = sizeof (EFI_HII_PACKAGE_HEADER); | |
| // | |
| // Dump package list | |
| // | |
| DumpRawBytes (OutFptr, PackageList, PackageListLen, 2); | |
| // | |
| // Write file tail | |
| // | |
| fprintf (OutFptr, "}\n"); | |
| Status = STATUS_SUCCESS; | |
| Done: | |
| if (OutFptr != NULL) { | |
| fclose (OutFptr); | |
| } | |
| return Status; | |
| } | |
| static | |
| STATUS | |
| CreatePackageList ( | |
| char *OutputFileName, | |
| EFI_GUID *PackageListGuid, | |
| FILE_NAME_LIST *PackageFiles | |
| ) | |
| /*++ | |
| Routine Description: | |
| Given a linked list of HII package files, walk the list to | |
| process them and create a binary HII package list file. | |
| Arguments: | |
| OutputFileName - name of output HII package list file to create | |
| PackageListGuid - the specified package list GUID | |
| PackageFiles - linked list of HII package files to process | |
| Returns: | |
| STATUS_SUCCESS - if successful | |
| STATUS_ERROR - otherwise | |
| --*/ | |
| { | |
| FILE *OutFptr; | |
| UINT32 PackageListLen; | |
| FILE_NAME_LIST *Package; | |
| if (OutputFileName == NULL || PackageListGuid == NULL || PackageFiles == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Open the output file for writing | |
| // | |
| if ((OutFptr = fopen (OutputFileName, "wb")) == NULL) { | |
| Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); | |
| goto Done; | |
| } | |
| // | |
| // Write package list header | |
| // | |
| PackageListLen = sizeof (EFI_HII_PACKAGE_LIST_HEADER); | |
| Package = PackageFiles; | |
| while (Package != NULL) { | |
| PackageListLen += Package->Length; | |
| Package = Package->Next; | |
| } | |
| fwrite (PackageListGuid, sizeof (UINT8), sizeof (EFI_GUID), OutFptr); | |
| fwrite (&PackageListLen, sizeof (UINT8), sizeof (UINT32), OutFptr); | |
| // | |
| // Write packages | |
| // | |
| Package = PackageFiles; | |
| while (Package != NULL) { | |
| fwrite (Package->Data, sizeof (UINT8), Package->Length, OutFptr); | |
| Package = Package->Next; | |
| } | |
| Done: | |
| if (OutFptr != NULL) { | |
| fclose (OutFptr); | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| void | |
| FreeGlobals ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Free up an memory we allocated so we can exit cleanly | |
| Arguments: | |
| Returns: NA | |
| --*/ | |
| { | |
| FILE_NAME_LIST *Next; | |
| // | |
| // Free up input package file names | |
| // | |
| while (mGlobals.PackageFile != NULL) { | |
| Next = mGlobals.PackageFile->Next; | |
| if (mGlobals.PackageFile->Data != NULL) { | |
| free (mGlobals.PackageFile->Data); | |
| } | |
| free (mGlobals.PackageFile); | |
| mGlobals.PackageFile = Next; | |
| } | |
| } | |
| static | |
| void | |
| DumpRawBytes ( | |
| FILE *OutFptr, | |
| UINT8 *Buffer, | |
| int Count, | |
| int Indent | |
| ) | |
| /*++ | |
| Routine Description: | |
| Dump buffer data into output file. | |
| Arguments: | |
| OutFptr - FILE pointer to output file. | |
| Buffer - the buffer to dump | |
| Count - number of bytes to dump | |
| Indent - indent at each line start | |
| Returns: | |
| Nothing. | |
| --*/ | |
| { | |
| int Counter; | |
| int Count2; | |
| UINT16 *Ptr16; | |
| Ptr16 = (UINT16 *) Buffer; | |
| Count2 = Count - (Count & 0x1); | |
| for (Counter = 0; Counter < Count2; Counter += 2) { | |
| if ((Counter & 0xF) == 0) { | |
| if (Counter == 0) { | |
| fprintf (OutFptr, "%*c", Indent, ' '); | |
| } else { | |
| fprintf (OutFptr, "\n%*c", Indent, ' '); | |
| } | |
| } | |
| fprintf (OutFptr, "0x%04X, ", (unsigned int) *Ptr16); | |
| Ptr16++; | |
| } | |
| // | |
| // Handle the last byte | |
| // | |
| if ((Count & 0x1) != 0) { | |
| if ((Counter & 0xF) == 0) { | |
| if (Counter == 0) { | |
| fprintf (OutFptr, "%*c", Indent, ' '); | |
| } else { | |
| fprintf (OutFptr, "\n%*c", Indent, ' '); | |
| } | |
| } | |
| fprintf (OutFptr, "0x%04X, ", (unsigned int) (*Ptr16 & 0xff)); | |
| } | |
| fprintf (OutFptr, "\n"); | |
| } | |
| static | |
| STATUS | |
| LoadPackage ( | |
| FILE_NAME_LIST *NameList | |
| ) | |
| /*++ | |
| Routine Description: | |
| Process the command line arguments | |
| Arguments: | |
| NameList - the FILE_NAME_LIST linked list node | |
| Returns: | |
| STATUS_SUCCESS - if successful | |
| STATUS_ERROR - otherwise | |
| --*/ | |
| { | |
| STATUS Status; | |
| FILE *InFptr; | |
| UINT32 BufferSize; | |
| UINT8 *Buffer; | |
| EFI_HII_PACKAGE_HEADER *PackageHeader; | |
| EFI_IFR_FORM_SET *FormSet; | |
| Status = STATUS_SUCCESS; | |
| if (NameList == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Try to open the package file | |
| // | |
| if ((InFptr = fopen (NameList->FileName, "rb")) == NULL) { | |
| Error (NULL, 0, 0, NameList->FileName, "failed to open input file for read"); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Get the file size, then allocate a buffer and read in the file contents. | |
| // | |
| fseek (InFptr, 0, SEEK_END); | |
| BufferSize = (UINT32) ftell (InFptr); | |
| fseek (InFptr, 0, SEEK_SET); | |
| Buffer = (UINT8 *) malloc (BufferSize); | |
| if (Buffer == NULL) { | |
| Error (NULL, 0, 0, "memory allocation failure", NULL); | |
| goto Done; | |
| } | |
| if (fread (Buffer, sizeof (UINT8), BufferSize, InFptr) != BufferSize) { | |
| Error (NULL, 0, 0, NameList->FileName, "error reading file contents"); | |
| Status = STATUS_ERROR; | |
| goto Done; | |
| } | |
| NameList->Length = BufferSize; | |
| NameList->Data = Buffer; | |
| PackageHeader = (EFI_HII_PACKAGE_HEADER *) Buffer; | |
| NameList->PackageType = PackageHeader->Type; | |
| if (!mGlobals.GuidSpecified && NameList->PackageType == EFI_HII_PACKAGE_FORMS) { | |
| FormSet = (EFI_IFR_FORM_SET *) (Buffer + sizeof (EFI_HII_PACKAGE_HEADER)); | |
| memcpy (&mGlobals.Guid, &FormSet->Guid, sizeof (EFI_GUID)); | |
| mGlobals.GuidSpecified = TRUE; | |
| } | |
| Done: | |
| fclose (InFptr); | |
| return Status; | |
| } | |
| static | |
| STATUS | |
| ProcessArgs ( | |
| int Argc, | |
| char *Argv[] | |
| ) | |
| /*++ | |
| Routine Description: | |
| Process the command line arguments | |
| Arguments: | |
| As per standard C main() | |
| Returns: | |
| STATUS_SUCCESS - if successful | |
| STATUS_ERROR - otherwise | |
| --*/ | |
| { | |
| FILE_NAME_LIST *NewList; | |
| STATUS Status; | |
| Status = STATUS_SUCCESS; | |
| memset ((void *) &mGlobals, 0, sizeof (mGlobals)); | |
| // | |
| // Skip program name | |
| // | |
| Argc--; | |
| Argv++; | |
| if (Argc == 0) { | |
| Usage (); | |
| return STATUS_ERROR; | |
| } | |
| if (_stricmp (Argv[0], "-h") == 0 || _stricmp (Argv[0], "-?") == 0) { | |
| Usage (); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Process until no more args. | |
| // | |
| while (Argc > 0) { | |
| if (_stricmp (Argv[0], "-rc") == 0) { | |
| Argc--; | |
| Argv++; | |
| if (Argc == 0) { | |
| Error (UTILITY_NAME, 0, 0, "mising HII resource file name", NULL); | |
| Status = STATUS_ERROR; | |
| goto Done; | |
| } | |
| strcpy (mGlobals.ResourceFileName, Argv[0]); | |
| mGlobals.Mode |= MODE_CREATE_HII_RESOURCE_FILE; | |
| } else if (_stricmp (Argv[0], "-hii") == 0) { | |
| Argc--; | |
| Argv++; | |
| if (Argc == 0) { | |
| Error (UTILITY_NAME, 0, 0, "mising HII package list file name", NULL); | |
| Status = STATUS_ERROR; | |
| goto Done; | |
| } | |
| strcpy (mGlobals.PackageListFileName, Argv[0]); | |
| mGlobals.Mode |= MODE_CREATE_HII_PACKAGE_LIST; | |
| } else if (_stricmp (Argv[0], "-g") == 0) { | |
| Argc--; | |
| Argv++; | |
| if (Argc == 0) { | |
| Error (UTILITY_NAME, 0, 0, "mising package list GUID", NULL); | |
| Status = STATUS_ERROR; | |
| goto Done; | |
| } | |
| Status = StringToGuid (Argv[0], &mGlobals.Guid); | |
| if (Status != STATUS_SUCCESS) { | |
| goto Done; | |
| } | |
| mGlobals.GuidSpecified = TRUE; | |
| } else { | |
| // | |
| // This is a package file | |
| // | |
| NewList = malloc (sizeof (FILE_NAME_LIST)); | |
| if (NewList == NULL) { | |
| Error (UTILITY_NAME, 0, 0, "memory allocation failure", NULL); | |
| Status = STATUS_ERROR; | |
| goto Done; | |
| } | |
| memset (NewList, 0, sizeof (FILE_NAME_LIST)); | |
| strcpy (NewList->FileName, Argv[0]); | |
| if (mGlobals.PackageFile == NULL) { | |
| mGlobals.PackageFile = NewList; | |
| } else { | |
| mGlobals.LastPackageFile->Next = NewList; | |
| } | |
| mGlobals.LastPackageFile = NewList; | |
| Status = LoadPackage (NewList); | |
| if (Status != STATUS_SUCCESS) { | |
| goto Done; | |
| } | |
| } | |
| Argc--; | |
| Argv++; | |
| } | |
| if (!mGlobals.GuidSpecified) { | |
| Error (UTILITY_NAME, 0, 0, "please specify HII pakcage list GUID", NULL); | |
| Status = STATUS_ERROR; | |
| } | |
| Done: | |
| if (Status != STATUS_SUCCESS) { | |
| FreeGlobals (); | |
| } | |
| return Status; | |
| } | |
| static | |
| void | |
| Usage ( | |
| VOID | |
| ) | |
| /*++ | |
| Routine Description: | |
| Print usage information for this utility. | |
| Arguments: | |
| None. | |
| Returns: | |
| Nothing. | |
| --*/ | |
| { | |
| int i; | |
| const char *Str[] = { | |
| UTILITY_NAME" "UTILITY_VERSION" - UEFI HII Package List Utility", | |
| " Copyright (C), 2008 Intel Corporation", | |
| #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) ) | |
| " Built from "UTILITY_BUILD", project of "UTILITY_VENDOR, | |
| #endif | |
| "", | |
| "Usage:", | |
| " "UTILITY_NAME" [OPTION] PACKAGE [PACKAGE [...]]", | |
| "Description:", | |
| " Merge HII package files into a single HII Package List.", | |
| "Options:", | |
| " -rc FileName write output to PE/COFF Resource Script file", | |
| " -hii FileName write output to binary Package List file", | |
| " -g GUID use GUID for the HII Package List Guid", | |
| "", | |
| "PACKAGE is the raw binary HII package file generated by StrGather or", | |
| "VfrCompiler which named as *.hpk. For example, merge a Form package and", | |
| "a String package into one HII package list:", | |
| " \""UTILITY_NAME" -rc Sample.rc -hii Sample.hii \\", | |
| " -g 12345678-1234-1234-1234-123456789abc Vfr.hpk Strings.hpk\"", | |
| NULL | |
| }; | |
| for (i = 0; Str[i] != NULL; i++) { | |
| fprintf (stdout, "%s\n", Str[i]); | |
| } | |
| } |