git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1676 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2760 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2760 lines
		
	
	
		
			80 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2004, Intel Corporation                                                         
 | 
						|
All rights reserved. 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:
 | 
						|
 | 
						|
  StringDB.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
  String database implementation
 | 
						|
  
 | 
						|
--*/
 | 
						|
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <ctype.h>  // for tolower()
 | 
						|
 | 
						|
#include <Common/UefiBaseTypes.h>
 | 
						|
#include <Common/MultiPhase.h>
 | 
						|
#include <Common/InternalFormRepresentation.h>
 | 
						|
#include <Protocol/UgaDraw.h>  // for EFI_UGA_PIXEL definition
 | 
						|
#include <Protocol/Hii.h>
 | 
						|
 | 
						|
#include "EfiUtilityMsgs.h"
 | 
						|
#include "StrGather.h"
 | 
						|
#include "StringDB.h"
 | 
						|
 | 
						|
 | 
						|
#define STRING_OFFSET RELOFST
 | 
						|
 | 
						|
#define STRING_DB_KEY (('S' << 24) | ('D' << 16) | ('B' << 8) | 'K')
 | 
						|
//
 | 
						|
// Version supported by this tool
 | 
						|
//
 | 
						|
#define STRING_DB_VERSION             0x00010000
 | 
						|
 | 
						|
#define STRING_DB_MAJOR_VERSION_MASK  0xFFFF0000
 | 
						|
#define STRING_DB_MINOR_VERSION_MASK  0x0000FFFF
 | 
						|
 | 
						|
#define DEFINE_STR                    L"// #define"
 | 
						|
 | 
						|
#define LANGUAGE_CODE_WIDTH           4
 | 
						|
//
 | 
						|
// This is the header that gets written to the top of the
 | 
						|
// output binary database file.
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  UINT32  Key;
 | 
						|
  UINT32  HeaderSize;
 | 
						|
  UINT32  Version;
 | 
						|
  UINT32  NumStringIdenfiers;
 | 
						|
  UINT32  StringIdentifiersSize;
 | 
						|
  UINT32  NumLanguages;
 | 
						|
} STRING_DB_HEADER;
 | 
						|
 | 
						|
//
 | 
						|
// When we write out data to the database, we have a UINT16 identifier, which
 | 
						|
// indicates what follows, followed by the data. Here's the structure.
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  UINT16  DataType;
 | 
						|
  UINT16  Reserved;
 | 
						|
} DB_DATA_ITEM_HEADER;
 | 
						|
 | 
						|
#define DB_DATA_TYPE_INVALID              0x0000
 | 
						|
#define DB_DATA_TYPE_STRING_IDENTIFIER    0x0001
 | 
						|
#define DB_DATA_TYPE_LANGUAGE_DEFINITION  0x0002
 | 
						|
#define DB_DATA_TYPE_STRING_DEFINITION    0x0003
 | 
						|
#define DB_DATA_TYPE_LAST                 DB_DATA_TYPE_STRING_DEFINITION
 | 
						|
 | 
						|
//
 | 
						|
// We have to keep track of a list of languages, each of which has its own
 | 
						|
// list of strings. Define a structure to keep track of all languages and
 | 
						|
// their list of strings.
 | 
						|
//
 | 
						|
typedef struct _STRING_LIST {
 | 
						|
  struct _STRING_LIST *Next;
 | 
						|
  UINT32              Size;         // number of bytes in string, including null terminator
 | 
						|
  WCHAR               *LanguageName;
 | 
						|
  WCHAR               *StringName;  // for example STR_ID_TEXT1
 | 
						|
  WCHAR               *Scope;       //
 | 
						|
  WCHAR               *Str;         // the actual string
 | 
						|
  UINT16              Flags;        // properties of this string (used, undefined)
 | 
						|
} STRING_LIST;
 | 
						|
 | 
						|
typedef struct _LANGUAGE_LIST {
 | 
						|
  struct _LANGUAGE_LIST *Next;
 | 
						|
  WCHAR                 LanguageName[4];
 | 
						|
  WCHAR                 *PrintableLanguageName;
 | 
						|
  STRING_LIST           *String;
 | 
						|
  STRING_LIST           *LastString;
 | 
						|
} LANGUAGE_LIST;
 | 
						|
 | 
						|
//
 | 
						|
// We also keep track of all the string identifier names, which we assign unique
 | 
						|
// values to. Create a structure to keep track of them all.
 | 
						|
//
 | 
						|
typedef struct _STRING_IDENTIFIER {
 | 
						|
  struct _STRING_IDENTIFIER *Next;
 | 
						|
  UINT32                    Index;  // only need 16 bits, but makes it easier with UINT32
 | 
						|
  WCHAR                     *StringName;
 | 
						|
  UINT16                    Flags;  // if someone referenced it via STRING_TOKEN()
 | 
						|
} STRING_IDENTIFIER;
 | 
						|
//
 | 
						|
// Keep our globals in this structure to be as modular as possible.
 | 
						|
//
 | 
						|
typedef struct {
 | 
						|
  FILE              *StringDBFptr;
 | 
						|
  LANGUAGE_LIST     *LanguageList;
 | 
						|
  LANGUAGE_LIST     *LastLanguageList;
 | 
						|
  LANGUAGE_LIST     *CurrentLanguage;         // keep track of the last language they used
 | 
						|
  STRING_IDENTIFIER *StringIdentifier;
 | 
						|
  STRING_IDENTIFIER *LastStringIdentifier;
 | 
						|
  UINT8             *StringDBFileName;
 | 
						|
  UINT32            NumStringIdentifiers;
 | 
						|
  UINT32            NumStringIdentifiersReferenced;
 | 
						|
  STRING_IDENTIFIER *CurrentStringIdentifier; // keep track of the last string identifier they added
 | 
						|
  WCHAR             *CurrentScope;
 | 
						|
} STRING_DB_DATA;
 | 
						|
 | 
						|
static STRING_DB_DATA mDBData;
 | 
						|
 | 
						|
static const char     *mSourceFileHeader[] = {
 | 
						|
  "//",
 | 
						|
  "//  DO NOT EDIT -- auto-generated file",
 | 
						|
  "//",
 | 
						|
  "//  This file is generated by the string gather utility",
 | 
						|
  "//",
 | 
						|
  NULL
 | 
						|
};
 | 
						|
 | 
						|
static
 | 
						|
STRING_LIST           *
 | 
						|
StringDBFindString (
 | 
						|
  WCHAR                       *LanguageName,
 | 
						|
  WCHAR                       *StringName,
 | 
						|
  WCHAR                       *Scope,
 | 
						|
  WCHAR_STRING_LIST           *LanguagesOfInterest,
 | 
						|
  WCHAR_MATCHING_STRING_LIST  *IndirectionList
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STRING_IDENTIFIER     *
 | 
						|
StringDBFindStringIdentifierByName (
 | 
						|
  WCHAR *Name
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STRING_IDENTIFIER     *
 | 
						|
StringDBFindStringIdentifierByIndex (
 | 
						|
  UINT32    Index
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
LANGUAGE_LIST         *
 | 
						|
StringDBFindLanguageList (
 | 
						|
  WCHAR *LanguageName
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
StringDBWriteStandardFileHeader (
 | 
						|
  FILE *OutFptr
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
WCHAR                 *
 | 
						|
AsciiToWchar (
 | 
						|
  CHAR8 *Str
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
WCHAR                 *
 | 
						|
DuplicateString (
 | 
						|
  WCHAR   *Str
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteStringIdentifier (
 | 
						|
  FILE                *DBFptr,
 | 
						|
  UINT16              StringId,
 | 
						|
  UINT16              Flags,
 | 
						|
  WCHAR               *IdentifierName
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadStringIdentifier (
 | 
						|
  FILE                *DBFptr
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteLanguageDefinition (
 | 
						|
  FILE            *DBFptr,
 | 
						|
  WCHAR           *LanguageName,
 | 
						|
  WCHAR           *PrintableLanguageName
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadLanguageDefinition (
 | 
						|
  FILE            *DBFptr
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteString (
 | 
						|
  FILE            *DBFptr,
 | 
						|
  UINT16          Flags,
 | 
						|
  WCHAR           *Language,
 | 
						|
  WCHAR           *StringName,
 | 
						|
  WCHAR           *Scope,
 | 
						|
  WCHAR           *Str
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadString (
 | 
						|
  FILE            *DBFptr
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadGenericString (
 | 
						|
  FILE      *DBFptr,
 | 
						|
  UINT16    *Size,
 | 
						|
  WCHAR     **Str
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteGenericString (
 | 
						|
  FILE      *DBFptr,
 | 
						|
  WCHAR     *Str
 | 
						|
  );
 | 
						|
 | 
						|
static
 | 
						|
void
 | 
						|
StringDBAssignStringIndexes (
 | 
						|
  VOID
 | 
						|
  );
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  Constructor function for the string database handler.
 | 
						|
 | 
						|
Arguments:
 | 
						|
  None.
 | 
						|
 | 
						|
Returns:
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
void
 | 
						|
StringDBConstructor (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  memset ((char *) &mDBData, 0, sizeof (STRING_DB_DATA));
 | 
						|
  mDBData.CurrentScope = DuplicateString (L"NULL");
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  Destructor function for the string database handler.
 | 
						|
 | 
						|
Arguments:
 | 
						|
  None.
 | 
						|
 | 
						|
Returns:
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
void
 | 
						|
StringDBDestructor (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST     *NextLang;
 | 
						|
  STRING_LIST       *NextStr;
 | 
						|
  STRING_IDENTIFIER *NextIdentifier;
 | 
						|
  //
 | 
						|
  // Close the database file if it's open
 | 
						|
  //
 | 
						|
  if (mDBData.StringDBFptr != NULL) {
 | 
						|
    fclose (mDBData.StringDBFptr);
 | 
						|
    mDBData.StringDBFptr = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If we've allocated any strings/languages, free them up
 | 
						|
  //
 | 
						|
  while (mDBData.LanguageList != NULL) {
 | 
						|
    NextLang = mDBData.LanguageList->Next;
 | 
						|
    //
 | 
						|
    // Free up all strings for this language
 | 
						|
    //
 | 
						|
    while (mDBData.LanguageList->String != NULL) {
 | 
						|
      NextStr = mDBData.LanguageList->String->Next;
 | 
						|
      FREE (mDBData.LanguageList->String->Str);
 | 
						|
      FREE (mDBData.LanguageList->String);
 | 
						|
      mDBData.LanguageList->String = NextStr;
 | 
						|
    }
 | 
						|
 | 
						|
    FREE (mDBData.LanguageList->PrintableLanguageName);
 | 
						|
    FREE (mDBData.LanguageList);
 | 
						|
    mDBData.LanguageList = NextLang;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Free up string identifiers
 | 
						|
  //
 | 
						|
  while (mDBData.StringIdentifier != NULL) {
 | 
						|
    NextIdentifier = mDBData.StringIdentifier->Next;
 | 
						|
    FREE (mDBData.StringIdentifier->StringName);
 | 
						|
    FREE (mDBData.StringIdentifier);
 | 
						|
    mDBData.StringIdentifier = NextIdentifier;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Free the filename
 | 
						|
  //
 | 
						|
  if (mDBData.StringDBFileName != NULL) {
 | 
						|
    FREE (mDBData.StringDBFileName);
 | 
						|
    mDBData.StringDBFileName = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // We save a copy of the scope, so free it up if we
 | 
						|
  // have one.
 | 
						|
  //
 | 
						|
  if (mDBData.CurrentScope != NULL) {
 | 
						|
    FREE (mDBData.CurrentScope);
 | 
						|
    mDBData.CurrentScope = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Dump the contents of a database to an output C file.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  FileName        - name of the output file to write 
 | 
						|
  BaseName        - used for the name of the C array defined
 | 
						|
  Languages       - list of languages of interest
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
Notes:
 | 
						|
 | 
						|
  Languages is a pointer to a linked list of languages specified on
 | 
						|
  the command line. Format is "eng" and "spa+cat". For this, print
 | 
						|
  the strings for eng. Print the strings for spa too, but if one is
 | 
						|
  missing look for a cat string and print if it it exists.
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBDumpCStrings (
 | 
						|
  CHAR8                       *FileName,
 | 
						|
  CHAR8                       *BaseName,
 | 
						|
  WCHAR_STRING_LIST           *LanguagesOfInterest,
 | 
						|
  WCHAR_MATCHING_STRING_LIST  *IndirectionList
 | 
						|
  )
 | 
						|
{
 | 
						|
  FILE                        *Fptr;
 | 
						|
  LANGUAGE_LIST               *Lang;
 | 
						|
  STRING_LIST                 *CurrString;
 | 
						|
  STRING_LIST                 EmptyString;
 | 
						|
  UINT32                      Offset;
 | 
						|
  UINT32                      StringIndex;
 | 
						|
  UINT32                      TempIndex;
 | 
						|
  UINT32                      BytesThisLine;
 | 
						|
  EFI_HII_STRING_PACK         StringPack;
 | 
						|
  UINT8                       *Ptr;
 | 
						|
  UINT32                      Len;
 | 
						|
  WCHAR                       ZeroString[1];
 | 
						|
  WCHAR_STRING_LIST           *LOIPtr;
 | 
						|
  BOOLEAN                     LanguageOk;
 | 
						|
  WCHAR                       *TempStringPtr;
 | 
						|
  WCHAR                       *LangName;
 | 
						|
  STRING_IDENTIFIER           *StringIdentifier;
 | 
						|
  WCHAR                       Line[200];
 | 
						|
 | 
						|
  if ((Fptr = fopen (FileName, "w")) == NULL) {
 | 
						|
    Error (NULL, 0, 0, FileName, "failed to open output C string file");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Assign index values to the string identifiers
 | 
						|
  //
 | 
						|
  StringDBAssignStringIndexes ();
 | 
						|
  //
 | 
						|
  // Write the standard header to the output file, then the structure
 | 
						|
  // definition header.
 | 
						|
  //
 | 
						|
  StringDBWriteStandardFileHeader (Fptr);
 | 
						|
  fprintf (Fptr, "\nunsigned char %s[] = {\n", BaseName);
 | 
						|
  //
 | 
						|
  // If a given string is not defined, then we'll use this one.
 | 
						|
  //
 | 
						|
  memset (&EmptyString, 0, sizeof (EmptyString));
 | 
						|
  EmptyString.Size  = sizeof (ZeroString);
 | 
						|
  EmptyString.Str   = ZeroString;
 | 
						|
  //
 | 
						|
  // Process each language, then each string for each langage
 | 
						|
  //
 | 
						|
  ZeroString[0] = 0;
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    //
 | 
						|
    // If we have a language list, then make sure this language is in that
 | 
						|
    // list.
 | 
						|
    //
 | 
						|
    LanguageOk  = TRUE;
 | 
						|
    LangName    = Lang->LanguageName;
 | 
						|
    if (LanguagesOfInterest != NULL) {
 | 
						|
      LanguageOk = FALSE;
 | 
						|
      for (LOIPtr = LanguagesOfInterest; LOIPtr != NULL; LOIPtr = LOIPtr->Next) {
 | 
						|
        if (StrnCmp (LOIPtr->Str, Lang->LanguageName, LANGUAGE_IDENTIFIER_NAME_LEN) == 0) {
 | 
						|
          LangName    = LOIPtr->Str;
 | 
						|
          LanguageOk  = TRUE;
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!LanguageOk) {
 | 
						|
      continue;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Process each string for this language. We have to make 3 passes on the strings:
 | 
						|
    //   Pass1: computes sizes and fill in the string pack header
 | 
						|
    //   Pass2: write the array of offsets
 | 
						|
    //   Pass3: write the strings
 | 
						|
    //
 | 
						|
    //
 | 
						|
    // PASS 1: Fill in and print the HII string pack header
 | 
						|
    //
 | 
						|
    // Compute the size for this language package and write
 | 
						|
    // the header out. Each string package contains:
 | 
						|
    //   Header
 | 
						|
    //   Offset[]  -- an array of offsets to strings, of type RELOFST each
 | 
						|
    //   String[]  -- the actual strings themselves
 | 
						|
    //
 | 
						|
    AsciiSPrint ( Line, sizeof(Line),
 | 
						|
      "\n//******************************************************************************"
 | 
						|
      "\n// Start of string definitions for %s/%s",
 | 
						|
      Lang->LanguageName,
 | 
						|
      Lang->PrintableLanguageName
 | 
						|
      );
 | 
						|
    fprintf (Fptr, "%s", Line);
 | 
						|
    memset ((char *) &StringPack, 0, sizeof (EFI_HII_STRING_PACK));
 | 
						|
    StringPack.Header.Type        = EFI_HII_STRING;
 | 
						|
    StringPack.NumStringPointers  = (UINT16) mDBData.NumStringIdentifiersReferenced;
 | 
						|
    //
 | 
						|
    // First string is the language name. If we're printing all languages, then
 | 
						|
    // it's just the "spa". If we were given a list of languages to print, then it's
 | 
						|
    // the "spacat" string. Compute its offset and fill in
 | 
						|
    // the info in the header. Since we know the language name string's length,
 | 
						|
    // and the printable language name follows it, use that info to fill in the
 | 
						|
    // entry for the printable language name as well.
 | 
						|
    //
 | 
						|
    StringPack.LanguageNameString = (STRING_OFFSET) (sizeof (EFI_HII_STRING_PACK) + (mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET)));
 | 
						|
    StringPack.PrintableLanguageName = (STRING_OFFSET) (StringPack.LanguageNameString + (StrLen (LangName) + 1) * sizeof (WCHAR));
 | 
						|
    //
 | 
						|
    // Add up the size of all strings so we can fill in our header.
 | 
						|
    //
 | 
						|
    Len = 0;
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        Len += (StrLen (LangName) + 1) * sizeof (WCHAR);
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a string with this language.stringname
 | 
						|
        //
 | 
						|
        StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
        if (StringIdentifier == NULL) {
 | 
						|
          Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
          return STATUS_ERROR;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Find a matching string if this string identifier was referenced
 | 
						|
        //
 | 
						|
        EmptyString.Flags = STRING_FLAGS_UNDEFINED;
 | 
						|
        CurrString        = NULL;
 | 
						|
        if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        Lang->LanguageName,
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL,
 | 
						|
                        LanguagesOfInterest,
 | 
						|
                        IndirectionList
 | 
						|
                        );
 | 
						|
          if (NULL == CurrString) {
 | 
						|
            //
 | 
						|
            // If string for Lang->LanguageName is not found, try to get an English version
 | 
						|
            //
 | 
						|
            CurrString = StringDBFindString (
 | 
						|
                          L"eng",
 | 
						|
                          StringIdentifier->StringName,
 | 
						|
                          NULL,
 | 
						|
                          LanguagesOfInterest,
 | 
						|
                          IndirectionList
 | 
						|
                          );
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString = &EmptyString;
 | 
						|
          EmptyString.Flags |= StringIdentifier->Flags;
 | 
						|
        }
 | 
						|
 | 
						|
        Len += CurrString->Size;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    StringPack.Header.Length =    sizeof (EFI_HII_STRING_PACK) 
 | 
						|
                                + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET) 
 | 
						|
                                + Len;
 | 
						|
    //
 | 
						|
    // Write out the header one byte at a time
 | 
						|
    //
 | 
						|
    Ptr = (UINT8 *) &StringPack;
 | 
						|
    for (TempIndex = 0; TempIndex < sizeof (EFI_HII_STRING_PACK); TempIndex++, Ptr++) {
 | 
						|
      if ((TempIndex & 0x07) == 0) {
 | 
						|
        fprintf (Fptr, "\n  ");
 | 
						|
      }
 | 
						|
 | 
						|
      fprintf (Fptr, "0x%02X, ", (UINT32) *Ptr);
 | 
						|
    }
 | 
						|
 | 
						|
    fprintf (Fptr, "\n  // offset 0x%X\n", sizeof (StringPack));
 | 
						|
    //
 | 
						|
    // PASS2 : write the offsets
 | 
						|
    //
 | 
						|
    // Traverse the list of strings again and write the array of offsets. The
 | 
						|
    // offset to the first string is the size of the string pack header
 | 
						|
    // plus the size of the offsets array. The other strings follow it.
 | 
						|
    //
 | 
						|
    StringIndex = 0;
 | 
						|
    Offset      = sizeof (StringPack) + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET);
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      //
 | 
						|
      // Write the offset, followed by a useful comment
 | 
						|
      //
 | 
						|
      fprintf (Fptr, "  ");
 | 
						|
      Ptr = (UINT8 *) &Offset;
 | 
						|
      for (TempIndex = 0; TempIndex < sizeof (STRING_OFFSET); TempIndex++) {
 | 
						|
        fprintf (Fptr, "0x%02X, ", (UINT32) Ptr[TempIndex]);
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Find the string name
 | 
						|
      //
 | 
						|
      StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
      if (StringIdentifier == NULL) {
 | 
						|
        Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      AsciiSPrint (Line, sizeof(Line) , " // offset to string %s (0x%04X)", StringIdentifier->StringName, StringIndex);
 | 
						|
      fprintf (Fptr, "%s", Line);
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        Offset += (StrLen (LangName) + 1) * sizeof (WCHAR);
 | 
						|
        CurrString = StringDBFindString (
 | 
						|
                      Lang->LanguageName,
 | 
						|
                      StringIdentifier->StringName,
 | 
						|
                      NULL, // scope
 | 
						|
                      NULL,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a matching string
 | 
						|
        //
 | 
						|
        CurrString = StringDBFindString (
 | 
						|
                      Lang->LanguageName,
 | 
						|
                      StringIdentifier->StringName,
 | 
						|
                      NULL,   // scope
 | 
						|
                      LanguagesOfInterest,
 | 
						|
                      IndirectionList
 | 
						|
                      );
 | 
						|
 | 
						|
        if (NULL == CurrString) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        L"eng",
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL, // scope
 | 
						|
                        LanguagesOfInterest,
 | 
						|
                        IndirectionList
 | 
						|
                        );
 | 
						|
        }
 | 
						|
 | 
						|
        EmptyString.LanguageName = Lang->LanguageName;
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString        = &EmptyString;
 | 
						|
          EmptyString.Flags = STRING_FLAGS_UNDEFINED;
 | 
						|
        } else if ((StringIdentifier->Flags & STRING_FLAGS_REFERENCED) == 0) {
 | 
						|
          CurrString        = &EmptyString;
 | 
						|
          EmptyString.Flags = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        Offset += CurrString->Size;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Print useful info about this string
 | 
						|
      //
 | 
						|
      if ((StringIdentifier->Flags & STRING_FLAGS_REFERENCED) == 0) {
 | 
						|
        fprintf (Fptr, " - not referenced");
 | 
						|
      }
 | 
						|
 | 
						|
      if (CurrString->Flags & STRING_FLAGS_UNDEFINED) {
 | 
						|
        fprintf (Fptr, " - not defined for this language");
 | 
						|
      } else if (StrCmp (CurrString->LanguageName, Lang->LanguageName) != 0) {
 | 
						|
        AsciiSPrint (
 | 
						|
          Line, sizeof(Line),
 | 
						|
          " - not defined for this language -- using secondary language %s definition",
 | 
						|
          CurrString->LanguageName
 | 
						|
          );
 | 
						|
        fprintf ( Fptr, "%s", Line);
 | 
						|
      }
 | 
						|
 | 
						|
      fprintf (Fptr, "\n");
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // For unreferenced string identifiers, print a message that they are not referenced anywhere
 | 
						|
    //
 | 
						|
    while (StringIndex < mDBData.NumStringIdentifiers) {
 | 
						|
      StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
      if (StringIdentifier != NULL) {
 | 
						|
        AsciiSPrint (Line, sizeof(Line), "  // %s not referenced\n", StringIdentifier->StringName);
 | 
						|
        fprintf (Fptr, "%s", Line);
 | 
						|
      }
 | 
						|
 | 
						|
      StringIndex++;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // PASS 3: write the strings themselves.
 | 
						|
    // Keep track of how many bytes we write per line because some editors
 | 
						|
    // (Visual Studio for instance) can't handle too long of lines.
 | 
						|
    //
 | 
						|
    Offset = sizeof (StringPack) + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET);
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
      if (StringIdentifier == NULL) {
 | 
						|
        Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
 | 
						|
      AsciiSPrint (Line, sizeof(Line), "  // string %s offset 0x%08X\n  ", StringIdentifier->StringName, Offset);
 | 
						|
      fprintf (Fptr, "%s", Line);
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        TempStringPtr = LangName;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a matching string if this string identifier was referenced
 | 
						|
        //
 | 
						|
        CurrString = NULL;
 | 
						|
        if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        Lang->LanguageName,
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL,   // scope
 | 
						|
                        LanguagesOfInterest,
 | 
						|
                        IndirectionList
 | 
						|
                        );
 | 
						|
          if (NULL == CurrString) {
 | 
						|
            CurrString = StringDBFindString (
 | 
						|
                          L"eng",
 | 
						|
                          StringIdentifier->StringName,
 | 
						|
                          NULL, // scope
 | 
						|
                          LanguagesOfInterest,
 | 
						|
                          IndirectionList
 | 
						|
                          );
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString = &EmptyString;
 | 
						|
        }
 | 
						|
 | 
						|
        TempStringPtr = CurrString->Str;
 | 
						|
      }
 | 
						|
 | 
						|
      BytesThisLine = 0;
 | 
						|
      for (TempIndex = 0; TempStringPtr[TempIndex] != 0; TempIndex++) {
 | 
						|
        fprintf (
 | 
						|
          Fptr,
 | 
						|
          "0x%02X, 0x%02X, ",
 | 
						|
          (UINT32) TempStringPtr[TempIndex] & 0xFF,
 | 
						|
          (UINT32) ((TempStringPtr[TempIndex] >> 8) & 0xFF)
 | 
						|
          );
 | 
						|
        BytesThisLine += 2;
 | 
						|
        Offset += 2;
 | 
						|
        //
 | 
						|
        // Let's say we only allow 14 per line
 | 
						|
        //
 | 
						|
        if (BytesThisLine > 14) {
 | 
						|
          fprintf (Fptr, "\n  ");
 | 
						|
          BytesThisLine = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Print NULL WCHAR at the end of this string.
 | 
						|
      //
 | 
						|
      fprintf (Fptr, "0x00, 0x00,\n");
 | 
						|
      Offset += 2;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Sanity check the offset. Make sure our running offset is what we put in the
 | 
						|
    // string pack header.
 | 
						|
    //
 | 
						|
    if (StringPack.Header.Length != Offset) {
 | 
						|
      Error (
 | 
						|
        __FILE__,
 | 
						|
        __LINE__,
 | 
						|
        0,
 | 
						|
        "application error",
 | 
						|
        "stringpack size 0x%X does not match final size 0x%X",
 | 
						|
        StringPack.Header.Length,
 | 
						|
        Offset
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Print terminator string pack, closing brace and close the file.
 | 
						|
  // The size of 0 triggers to the consumer that this is the end.
 | 
						|
  //
 | 
						|
  memset ((char *) &StringPack, 0, sizeof (EFI_HII_STRING_PACK));
 | 
						|
  StringPack.Header.Type  = EFI_HII_STRING;
 | 
						|
  Ptr                     = (UINT8 *) &StringPack;
 | 
						|
  fprintf (Fptr, "\n  // strings terminator pack");
 | 
						|
  for (TempIndex = 0; TempIndex < sizeof (StringPack); TempIndex++, Ptr++) {
 | 
						|
    if ((TempIndex & 0x0F) == 0) {
 | 
						|
      fprintf (Fptr, "\n  ");
 | 
						|
    }
 | 
						|
 | 
						|
    fprintf (Fptr, "0x%02X, ", (UINT32) *Ptr);
 | 
						|
  }
 | 
						|
 | 
						|
  fprintf (Fptr, "\n};\n");
 | 
						|
  fclose (Fptr);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Dump the #define string names
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  FileName        - name of the output file to write 
 | 
						|
  BaseName        - used for the protection #ifndef/#endif 
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBDumpStringDefines (
 | 
						|
  CHAR8 *FileName,
 | 
						|
  CHAR8 *BaseName
 | 
						|
  )
 | 
						|
{
 | 
						|
  FILE              *Fptr;
 | 
						|
  STRING_IDENTIFIER *Identifier;
 | 
						|
  CHAR8             CopyBaseName[100];
 | 
						|
  WCHAR             Line[200];
 | 
						|
  UINT32            Index;
 | 
						|
  const CHAR8       *StrDefHeader[] = {
 | 
						|
    "#ifndef _%s_STRINGS_DEFINE_H_\n",
 | 
						|
    "#define _%s_STRINGS_DEFINE_H_\n\n",
 | 
						|
    NULL
 | 
						|
  };
 | 
						|
 | 
						|
  if ((Fptr = fopen (FileName, "w")) == NULL) {
 | 
						|
    Error (NULL, 0, 0, FileName, "failed to open output string defines file");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get the base source filename and convert to uppercase.
 | 
						|
  //
 | 
						|
  if (sizeof (CopyBaseName) <= strlen (BaseName) + 1) {
 | 
						|
    Error (NULL, 0, 0, "application error", "StringDBDumpStringDefines() string length insufficient");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  strcpy (CopyBaseName, BaseName);
 | 
						|
  for (Index = 0; CopyBaseName[Index] != 0; Index++) {
 | 
						|
    if (islower (CopyBaseName[Index])) {
 | 
						|
      CopyBaseName[Index] = (INT8) toupper (CopyBaseName[Index]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Assign index values to the string identifiers
 | 
						|
  //
 | 
						|
  StringDBAssignStringIndexes ();
 | 
						|
  //
 | 
						|
  // Write the standard header to the output file, and then the
 | 
						|
  // protective #ifndef.
 | 
						|
  //
 | 
						|
  StringDBWriteStandardFileHeader (Fptr);
 | 
						|
  for (Index = 0; StrDefHeader[Index] != NULL; Index++) {
 | 
						|
    fprintf (Fptr, StrDefHeader[Index], CopyBaseName);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Print all the #defines for the string identifiers. Print identifiers
 | 
						|
  // whose names start with '$' as comments. Add comments for string
 | 
						|
  // identifiers not used as well.
 | 
						|
  //
 | 
						|
  Identifier = mDBData.StringIdentifier;
 | 
						|
  while (Identifier != NULL) {
 | 
						|
    if (Identifier->StringName[0] == L'$') {
 | 
						|
      fprintf (Fptr, "// ");
 | 
						|
    }
 | 
						|
 | 
						|
    if (Identifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
      AsciiSPrint (Line, sizeof(Line), "#define %-40s 0x%04X\n", Identifier->StringName, Identifier->Index);
 | 
						|
      fprintf (Fptr, "%s", Line);
 | 
						|
    } else {
 | 
						|
      AsciiSPrint (Line, sizeof(Line), "//#define %-40s 0x%04X // not referenced\n", Identifier->StringName, Identifier->Index);
 | 
						|
      fprintf (Fptr, "%s", Line);
 | 
						|
    }
 | 
						|
 | 
						|
    Identifier = Identifier->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  fprintf (Fptr, "\n#endif\n");
 | 
						|
  fclose (Fptr);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Add a string identifier to the database.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  StringName      - name of the string identifier. For example "STR_MY_STRING"
 | 
						|
  NewId           - if an ID has been assigned
 | 
						|
  Flags           - characteristics for the identifier
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBAddStringIdentifier (
 | 
						|
  WCHAR     *StringName,
 | 
						|
  UINT16    *NewId,
 | 
						|
  UINT16    Flags
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_IDENTIFIER *StringIdentifier;
 | 
						|
  STATUS            Status;
 | 
						|
  //
 | 
						|
  // If it was already used for some other language, then we don't
 | 
						|
  // need to add it. But set it to the current string identifier.
 | 
						|
  // The referenced bit is sticky.
 | 
						|
  //
 | 
						|
  Status            = STATUS_SUCCESS;
 | 
						|
  StringIdentifier  = StringDBFindStringIdentifierByName (StringName);
 | 
						|
  if (StringIdentifier != NULL) {
 | 
						|
    if (Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
      StringIdentifier->Flags |= STRING_FLAGS_REFERENCED;
 | 
						|
    }
 | 
						|
 | 
						|
    mDBData.CurrentStringIdentifier = StringIdentifier;
 | 
						|
    *NewId                          = (UINT16) StringIdentifier->Index;
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  StringIdentifier = (STRING_IDENTIFIER *) MALLOC (sizeof (STRING_IDENTIFIER));
 | 
						|
  if (StringIdentifier == NULL) {
 | 
						|
    Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  memset ((char *) StringIdentifier, 0, sizeof (STRING_IDENTIFIER));
 | 
						|
  StringIdentifier->StringName = (WCHAR *) malloc ((StrLen (StringName) + 1) * sizeof (WCHAR));
 | 
						|
  if (StringIdentifier->StringName == NULL) {
 | 
						|
    Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  StrCpy (StringIdentifier->StringName, StringName);
 | 
						|
  if (*NewId != STRING_ID_INVALID) {
 | 
						|
    StringIdentifier->Index = *NewId;
 | 
						|
    StringIdentifier->Flags |= STRING_FLAGS_INDEX_ASSIGNED;
 | 
						|
    if (mDBData.NumStringIdentifiers <= StringIdentifier->Index) {
 | 
						|
      mDBData.NumStringIdentifiers = StringIdentifier->Index + 1;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    StringIdentifier->Index = mDBData.NumStringIdentifiers++;
 | 
						|
  }
 | 
						|
 | 
						|
  StringIdentifier->Flags |= Flags;
 | 
						|
  //
 | 
						|
  // Add it to our list of string identifiers
 | 
						|
  //
 | 
						|
  if (mDBData.StringIdentifier == NULL) {
 | 
						|
    mDBData.StringIdentifier = StringIdentifier;
 | 
						|
  } else {
 | 
						|
    mDBData.LastStringIdentifier->Next = StringIdentifier;
 | 
						|
  }
 | 
						|
 | 
						|
  mDBData.LastStringIdentifier    = StringIdentifier;
 | 
						|
  mDBData.CurrentStringIdentifier = StringIdentifier;
 | 
						|
  *NewId                          = (UINT16) StringIdentifier->Index;
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Add a new string to the database.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  LanguageName    - "eng" or "spa" language name
 | 
						|
  StringName      - "STR_MY_TEXT" string name
 | 
						|
  Scope           - from the #scope statements in the string file
 | 
						|
  Format          - if we should format the string
 | 
						|
  Flags           - characteristic flags for the string
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
Notes:
 | 
						|
 | 
						|
  Several of the fields can be "inherited" from the previous calls to
 | 
						|
  our database functions. For example, if scope is NULL here, then
 | 
						|
  we'll use the previous setting.
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBAddString (
 | 
						|
  WCHAR   *LanguageName,
 | 
						|
  WCHAR   *StringName,
 | 
						|
  WCHAR   *Scope,
 | 
						|
  WCHAR   *String,
 | 
						|
  BOOLEAN Format,
 | 
						|
  UINT16  Flags
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST     *Lang;
 | 
						|
  UINT32            Size;
 | 
						|
  STRING_LIST       *Str;
 | 
						|
  UINT16            StringIndex;
 | 
						|
  WCHAR             TempLangName[4];
 | 
						|
  STRING_IDENTIFIER *StringIdentifier;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check that language name is exactly 3 characters, or emit an error.
 | 
						|
  // Truncate at 3 if it's longer, or make it 3 if it's shorter.
 | 
						|
  //
 | 
						|
  if (LanguageName != NULL) {
 | 
						|
    Size = StrLen (LanguageName);
 | 
						|
    if (Size != 3) {
 | 
						|
      ParserError (0, "invalid length for language name", "%S", LanguageName);
 | 
						|
      if (Size > 3) {
 | 
						|
        LanguageName[3] = 0;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Make a local copy of the language name string, and extend to
 | 
						|
        // 3 characters since we make assumptions elsewhere in this program
 | 
						|
        // on the length.
 | 
						|
        //
 | 
						|
        StrCpy (TempLangName, LanguageName);
 | 
						|
        for (; Size < 3; Size++) {
 | 
						|
          TempLangName[Size] = L'?';
 | 
						|
        }
 | 
						|
 | 
						|
        TempLangName[4] = 0;
 | 
						|
        LanguageName    = TempLangName;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If they specified a language, make sure they've defined it already
 | 
						|
  // via a #langdef statement. Otherwise use the current default language.
 | 
						|
  //
 | 
						|
  if (LanguageName != NULL) {
 | 
						|
    Lang = StringDBFindLanguageList (LanguageName);
 | 
						|
    if (Lang == NULL) {
 | 
						|
      ParserError (0, "language not defined", "%S", LanguageName);
 | 
						|
      return STATUS_ERROR;
 | 
						|
    } else {
 | 
						|
      StringDBSetCurrentLanguage (LanguageName);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Lang = mDBData.CurrentLanguage;
 | 
						|
    if (Lang == NULL) {
 | 
						|
      //
 | 
						|
      // Have to call SetLanguage() first
 | 
						|
      //
 | 
						|
      ParserError (0, "no language defined", "%S", StringName);
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If they didn't define a string identifier, use the last string identifier
 | 
						|
  // added.
 | 
						|
  //
 | 
						|
  if (StringName == NULL) {
 | 
						|
    StringName = mDBData.CurrentStringIdentifier->StringName;
 | 
						|
    if (StringName == NULL) {
 | 
						|
      ParserError (0, "no string identifier previously specified", NULL);
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If scope was not specified, use the default setting
 | 
						|
  //
 | 
						|
  if (Scope != NULL) {
 | 
						|
    Scope = DuplicateString (Scope);
 | 
						|
  } else {
 | 
						|
    Scope = DuplicateString (mDBData.CurrentScope);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // printf ("Adding string: %S.%S.%S\n", Lang->LanguageName, StringName, Scope);
 | 
						|
  //
 | 
						|
  // Check for duplicates for this Language.StringName.Scope. Allow multiple
 | 
						|
  // definitions of the language name and printable language name, since the
 | 
						|
  // user does not specifically define them.
 | 
						|
  //
 | 
						|
  if (StringDBFindString (Lang->LanguageName, StringName, Scope, NULL, NULL) != NULL) {
 | 
						|
    if ((StrCmp (StringName, LANGUAGE_NAME_STRING_NAME) == 0) &&
 | 
						|
        (StrCmp (StringName, PRINTABLE_LANGUAGE_NAME_STRING_NAME) == 0)
 | 
						|
        ) {
 | 
						|
      ParserError (
 | 
						|
        0,
 | 
						|
        "string multiply defined",
 | 
						|
        "Language.Name.Scope = %S.%S.%S",
 | 
						|
        Lang->LanguageName,
 | 
						|
        StringName,
 | 
						|
        Scope
 | 
						|
        );
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  StringIndex = STRING_ID_INVALID;
 | 
						|
  if (StringDBAddStringIdentifier (StringName, &StringIndex, Flags) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  StringIdentifier = StringDBFindStringIdentifierByName (StringName);
 | 
						|
  //
 | 
						|
  // Add this string to the end of the strings for this language.
 | 
						|
  //
 | 
						|
  Str = (STRING_LIST *) malloc (sizeof (STRING_LIST));
 | 
						|
  if (Str == NULL) {
 | 
						|
    Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  memset ((char *) Str, 0, sizeof (STRING_LIST));
 | 
						|
  Size              = (StrLen (String) + 1) * sizeof (WCHAR);
 | 
						|
  Str->Flags        = Flags;
 | 
						|
  Str->Scope        = Scope;
 | 
						|
  Str->StringName   = StringIdentifier->StringName;
 | 
						|
  Str->LanguageName = DuplicateString (LanguageName);
 | 
						|
  Str->Str          = (WCHAR *) MALLOC (Size);
 | 
						|
  if (Str->Str == NULL) {
 | 
						|
    Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If not formatting, just copy the string.
 | 
						|
  //
 | 
						|
  StrCpy (Str->Str, String);
 | 
						|
  if (Format) {
 | 
						|
    StringDBFormatString (Str->Str);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Size may change after formatting. We set the size to
 | 
						|
  // the actual size of the string, including the null for
 | 
						|
  // easier processing later.
 | 
						|
  //
 | 
						|
  Str->Size = (StrLen (Str->Str) + 1) * sizeof (WCHAR);
 | 
						|
  if (Lang->String == NULL) {
 | 
						|
    Lang->String = Str;
 | 
						|
  } else {
 | 
						|
    Lang->LastString->Next = Str;
 | 
						|
  }
 | 
						|
 | 
						|
  Lang->LastString = Str;
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Given a language name, see if a language list for it has been defined
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  LanguageName    - like "eng"
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  A pointer to the language list
 | 
						|
 | 
						|
--*/
 | 
						|
static
 | 
						|
LANGUAGE_LIST *
 | 
						|
StringDBFindLanguageList (
 | 
						|
  WCHAR *LanguageName
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST *Lang;
 | 
						|
 | 
						|
  Lang = mDBData.LanguageList;
 | 
						|
  while (Lang != NULL) {
 | 
						|
    if (StrCmp (LanguageName, Lang->LanguageName) == 0) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    Lang = Lang->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return Lang;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
STATUS
 | 
						|
StringDBSetCurrentLanguage (
 | 
						|
  WCHAR *LanguageName
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST *Lang;
 | 
						|
 | 
						|
  Lang = StringDBFindLanguageList (LanguageName);
 | 
						|
  if (Lang == NULL) {
 | 
						|
    ParserError (0, "language not previously defined", "%S", LanguageName);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  mDBData.CurrentLanguage = Lang;
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
STATUS
 | 
						|
StringDBAddLanguage (
 | 
						|
  WCHAR *LanguageName,
 | 
						|
  WCHAR *PrintableLanguageName
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST *Lang;
 | 
						|
  //
 | 
						|
  // Check for redefinitions
 | 
						|
  //
 | 
						|
  Lang = StringDBFindLanguageList (LanguageName);
 | 
						|
  if (Lang != NULL) {
 | 
						|
    //
 | 
						|
    // Better be the same printable name
 | 
						|
    //
 | 
						|
    if (StrCmp (PrintableLanguageName, Lang->PrintableLanguageName) != 0) {
 | 
						|
      ParserError (
 | 
						|
        0,
 | 
						|
        "language redefinition",
 | 
						|
        "%S:%S != %S:%S",
 | 
						|
        Lang->LanguageName,
 | 
						|
        Lang->PrintableLanguageName,
 | 
						|
        LanguageName,
 | 
						|
        PrintableLanguageName
 | 
						|
        );
 | 
						|
      return STATUS_ERROR;
 | 
						|
      //
 | 
						|
      //    } else {
 | 
						|
      //      ParserWarning (0, "benign language redefinition", "%S", PrintableLanguageName);
 | 
						|
      //      return STATUS_WARNING;
 | 
						|
      //
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Allocate memory to keep track of this new language
 | 
						|
    //
 | 
						|
    Lang = (LANGUAGE_LIST *) malloc (sizeof (LANGUAGE_LIST));
 | 
						|
    if (Lang == NULL) {
 | 
						|
      Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    memset ((char *) Lang, 0, sizeof (LANGUAGE_LIST));
 | 
						|
    //
 | 
						|
    // Save the language name, then allocate memory to save the
 | 
						|
    // printable language name
 | 
						|
    //
 | 
						|
    StrCpy (Lang->LanguageName, LanguageName);
 | 
						|
    Lang->PrintableLanguageName = (WCHAR *) malloc ((StrLen (PrintableLanguageName) + 1) * sizeof (WCHAR));
 | 
						|
    if (Lang->PrintableLanguageName == NULL) {
 | 
						|
      Error (NULL, 0, 0, NULL, "memory allocation error");
 | 
						|
      return STATUS_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    StrCpy (Lang->PrintableLanguageName, PrintableLanguageName);
 | 
						|
 | 
						|
    if (mDBData.LanguageList == NULL) {
 | 
						|
      mDBData.LanguageList = Lang;
 | 
						|
    } else {
 | 
						|
      mDBData.LastLanguageList->Next = Lang;
 | 
						|
    }
 | 
						|
 | 
						|
    mDBData.LastLanguageList = Lang;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Default is to make our active language this new one
 | 
						|
  //
 | 
						|
  StringDBSetCurrentLanguage (LanguageName);
 | 
						|
  //
 | 
						|
  // The first two strings for any language are the language name,
 | 
						|
  // followed by the printable language name. Add them and set them
 | 
						|
  // to referenced so they never get stripped out.
 | 
						|
  //
 | 
						|
  StringDBAddString (
 | 
						|
    LanguageName,
 | 
						|
    LANGUAGE_NAME_STRING_NAME,
 | 
						|
    NULL,
 | 
						|
    LanguageName,
 | 
						|
    FALSE,
 | 
						|
    STRING_FLAGS_REFERENCED
 | 
						|
    );
 | 
						|
  StringDBAddString (
 | 
						|
    LanguageName,
 | 
						|
    PRINTABLE_LANGUAGE_NAME_STRING_NAME,
 | 
						|
    NULL,
 | 
						|
    PrintableLanguageName,
 | 
						|
    FALSE,
 | 
						|
    STRING_FLAGS_REFERENCED
 | 
						|
    );
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
static
 | 
						|
STRING_IDENTIFIER *
 | 
						|
StringDBFindStringIdentifierByName (
 | 
						|
  WCHAR *StringName
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_IDENTIFIER *Identifier;
 | 
						|
 | 
						|
  Identifier = mDBData.StringIdentifier;
 | 
						|
  while (Identifier != NULL) {
 | 
						|
    if (StrCmp (StringName, Identifier->StringName) == 0) {
 | 
						|
      return Identifier;
 | 
						|
    }
 | 
						|
 | 
						|
    Identifier = Identifier->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STRING_IDENTIFIER *
 | 
						|
StringDBFindStringIdentifierByIndex (
 | 
						|
  UINT32    StringIndex
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_IDENTIFIER *Identifier;
 | 
						|
 | 
						|
  Identifier = mDBData.StringIdentifier;
 | 
						|
  while (Identifier != NULL) {
 | 
						|
    if (Identifier->Index == StringIndex) {
 | 
						|
      return Identifier;
 | 
						|
    }
 | 
						|
 | 
						|
    Identifier = Identifier->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
static
 | 
						|
void
 | 
						|
StringDBWriteStandardFileHeader (
 | 
						|
  FILE *OutFptr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  TempIndex;
 | 
						|
  for (TempIndex = 0; mSourceFileHeader[TempIndex] != NULL; TempIndex++) {
 | 
						|
    fprintf (OutFptr, "%s\n", mSourceFileHeader[TempIndex]);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  
 | 
						|
  Given a Unicode string from an input file, reformat the string to replace
 | 
						|
  backslash control sequences with the appropriate encoding.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  String        - pointer to string to reformat
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  Nothing
 | 
						|
 | 
						|
--*/
 | 
						|
void
 | 
						|
StringDBFormatString (
 | 
						|
  WCHAR   *String
 | 
						|
  )
 | 
						|
{
 | 
						|
  WCHAR *From;
 | 
						|
  WCHAR *To;
 | 
						|
  int   HexNibbles;
 | 
						|
  WCHAR HexValue;
 | 
						|
  //
 | 
						|
  // Go through the string and process any formatting characters
 | 
						|
  //
 | 
						|
  From  = String;
 | 
						|
  To    = String;
 | 
						|
  while (*From) {
 | 
						|
    if (*From == UNICODE_BACKSLASH) {
 | 
						|
      //
 | 
						|
      // First look for \wide and replace with the appropriate control character. Note that
 | 
						|
      // when you have "define STR L"ABC"", then sizeof(ABC) is 8 because the null char is
 | 
						|
      // counted. Make adjustments for this. We advance From below, so subtract 2 each time.
 | 
						|
      //
 | 
						|
      if (StrnCmp (From, UNICODE_WIDE_STRING, sizeof (UNICODE_WIDE_STRING) / sizeof (WCHAR) - 1) == 0) {
 | 
						|
        *To = WIDE_CHAR;
 | 
						|
        From += sizeof (UNICODE_WIDE_STRING) / sizeof (WCHAR) - 2;
 | 
						|
      } else if (StrnCmp (From, UNICODE_NARROW_STRING, sizeof (UNICODE_NARROW_STRING) / sizeof (WCHAR) - 1) == 0) {
 | 
						|
        //
 | 
						|
        // Found: \narrow
 | 
						|
        //
 | 
						|
        *To = NARROW_CHAR;
 | 
						|
        From += sizeof (UNICODE_NARROW_STRING) / sizeof (WCHAR) - 2;
 | 
						|
      } else if (StrnCmp (From, UNICODE_NBR_STRING, sizeof (UNICODE_NBR_STRING) / sizeof (WCHAR) - 1) == 0) {
 | 
						|
        //
 | 
						|
        // Found: \nbr
 | 
						|
        //
 | 
						|
        *To = NON_BREAKING_CHAR;
 | 
						|
        From += sizeof (UNICODE_NBR_STRING) / sizeof (WCHAR) - 2;
 | 
						|
      } else if (StrnCmp (From, UNICODE_BR_STRING, sizeof (UNICODE_BR_STRING) / sizeof (WCHAR) - 1) == 0) {
 | 
						|
        //
 | 
						|
        // Found: \br -- pass through untouched
 | 
						|
        //
 | 
						|
        *To = *From;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Standard one-character control sequences such as \n, \r, \\, or \x
 | 
						|
        //
 | 
						|
        From++;
 | 
						|
        switch (*From) {
 | 
						|
        case ASCII_TO_UNICODE ('n'):
 | 
						|
          *To = UNICODE_CR;
 | 
						|
          To++;
 | 
						|
          *To = UNICODE_LF;
 | 
						|
          break;
 | 
						|
 | 
						|
        //
 | 
						|
        // carriage return
 | 
						|
        //
 | 
						|
        case ASCII_TO_UNICODE ('r'):
 | 
						|
          *To = UNICODE_CR;
 | 
						|
          break;
 | 
						|
 | 
						|
        //
 | 
						|
        // backslash
 | 
						|
        //
 | 
						|
        case UNICODE_BACKSLASH:
 | 
						|
          *To = UNICODE_BACKSLASH;
 | 
						|
          break;
 | 
						|
 | 
						|
        //
 | 
						|
        // Tab
 | 
						|
        //
 | 
						|
        case ASCII_TO_UNICODE ('t'):
 | 
						|
          *To = UNICODE_TAB;
 | 
						|
          break;
 | 
						|
 | 
						|
        //
 | 
						|
        // embedded double-quote
 | 
						|
        //
 | 
						|
        case UNICODE_DOUBLE_QUOTE:
 | 
						|
          *To = UNICODE_DOUBLE_QUOTE;
 | 
						|
          break;
 | 
						|
 | 
						|
        //
 | 
						|
        // Hex Unicode character \x1234. We'll process up to 4 hex characters
 | 
						|
        //
 | 
						|
        case ASCII_TO_UNICODE ('x'):
 | 
						|
          HexValue = 0;
 | 
						|
          for (HexNibbles = 0; HexNibbles < 4; HexNibbles++) {
 | 
						|
            if ((From[1] >= UNICODE_0) && (From[1] <= UNICODE_9)) {
 | 
						|
              HexValue = (HexValue << 4) | (From[1] - UNICODE_0);
 | 
						|
            } else if ((From[1] >= UNICODE_a) && (From[1] <= UNICODE_f)) {
 | 
						|
              HexValue = (HexValue << 4) | (10 + From[1] - UNICODE_a);
 | 
						|
            } else if ((From[1] >= UNICODE_A) && (From[1] <= UNICODE_F)) {
 | 
						|
              HexValue = (HexValue << 4) | (10 + From[1] - UNICODE_A);
 | 
						|
            } else {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
 | 
						|
            From++;
 | 
						|
          }
 | 
						|
 | 
						|
          if (HexNibbles == 0) {
 | 
						|
            ParserWarning (
 | 
						|
              0,
 | 
						|
              "expected at least one valid hex digit with \\x escaped character in string",
 | 
						|
              "\\%C",
 | 
						|
              *From
 | 
						|
              );
 | 
						|
          } else {
 | 
						|
            *To = HexValue;
 | 
						|
          }
 | 
						|
          break;
 | 
						|
 | 
						|
        default:
 | 
						|
          *To = UNICODE_SPACE;
 | 
						|
          ParserWarning (0, "invalid escaped character in string", "\\%C", *From);
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      *To = *From;
 | 
						|
    }
 | 
						|
 | 
						|
    From++;
 | 
						|
    To++;
 | 
						|
  }
 | 
						|
 | 
						|
  *To = 0;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
STATUS
 | 
						|
StringDBReadDatabase (
 | 
						|
  CHAR8   *DBFileName,
 | 
						|
  BOOLEAN IgnoreIfNotExist,
 | 
						|
  BOOLEAN Verbose
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_DB_HEADER    DbHeader;
 | 
						|
  STATUS              Status;
 | 
						|
  FILE                *DBFptr;
 | 
						|
  DB_DATA_ITEM_HEADER DataItemHeader;
 | 
						|
 | 
						|
  Status  = STATUS_SUCCESS;
 | 
						|
  DBFptr  = NULL;
 | 
						|
  //
 | 
						|
  //  if (Verbose) {
 | 
						|
  //    fprintf (stdout, "Reading database file %s\n", DBFileName);
 | 
						|
  //  }
 | 
						|
  //
 | 
						|
  // Try to open the input file
 | 
						|
  //
 | 
						|
  if ((DBFptr = fopen (DBFileName, "rb")) == NULL) {
 | 
						|
    if (IgnoreIfNotExist) {
 | 
						|
      return STATUS_SUCCESS;
 | 
						|
    }
 | 
						|
 | 
						|
    Error (NULL, 0, 0, DBFileName, "failed to open input database file for reading");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Read and verify the database header
 | 
						|
  //
 | 
						|
  if (fread ((void *) &DbHeader, sizeof (STRING_DB_HEADER), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, DBFileName, "failed to read header from database file");
 | 
						|
    Status = STATUS_ERROR;
 | 
						|
    goto Finish;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DbHeader.Key != STRING_DB_KEY) {
 | 
						|
    Error (NULL, 0, 0, DBFileName, "invalid header in database file");
 | 
						|
    Status = STATUS_ERROR;
 | 
						|
    goto Finish;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DbHeader.Version & STRING_DB_MAJOR_VERSION_MASK) != (STRING_DB_VERSION & STRING_DB_MAJOR_VERSION_MASK)) {
 | 
						|
    Error (NULL, 0, 0, DBFileName, "incompatible database file version -- rebuild clean");
 | 
						|
    Status = STATUS_ERROR;
 | 
						|
    goto Finish;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Read remaining items
 | 
						|
  //
 | 
						|
  while (fread (&DataItemHeader, sizeof (DataItemHeader), 1, DBFptr) == 1) {
 | 
						|
    switch (DataItemHeader.DataType) {
 | 
						|
    case DB_DATA_TYPE_STRING_IDENTIFIER:
 | 
						|
      StringDBReadStringIdentifier (DBFptr);
 | 
						|
      break;
 | 
						|
 | 
						|
    case DB_DATA_TYPE_LANGUAGE_DEFINITION:
 | 
						|
      StringDBReadLanguageDefinition (DBFptr);
 | 
						|
      break;
 | 
						|
 | 
						|
    case DB_DATA_TYPE_STRING_DEFINITION:
 | 
						|
      StringDBReadString (DBFptr);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Error (
 | 
						|
        NULL,
 | 
						|
        0,
 | 
						|
        0,
 | 
						|
        "database corrupted",
 | 
						|
        "invalid data item type 0x%X at offset 0x%X",
 | 
						|
        (UINT32) DataItemHeader.DataType,
 | 
						|
        ftell (DBFptr) - sizeof (DataItemHeader)
 | 
						|
        );
 | 
						|
      Status = STATUS_ERROR;
 | 
						|
      goto Finish;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
Finish:
 | 
						|
  if (DBFptr != NULL) {
 | 
						|
    fclose (DBFptr);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
  
 | 
						|
  Write everything we know to the output database file. Write:
 | 
						|
 | 
						|
  Database header
 | 
						|
  String identifiers[]
 | 
						|
  StringPacks[]
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  DBFileName    - name of the file to write to
 | 
						|
  Verbose       - for debug purposes, print info messages along the way.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBWriteDatabase (
 | 
						|
  CHAR8   *DBFileName,
 | 
						|
  BOOLEAN Verbose
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_DB_HEADER  DbHeader;
 | 
						|
  UINT32            Counter;
 | 
						|
  UINT32            StrLength;
 | 
						|
  LANGUAGE_LIST     *Lang;
 | 
						|
  STRING_IDENTIFIER *StringIdentifier;
 | 
						|
  STRING_LIST       *StrList;
 | 
						|
  FILE              *DBFptr;
 | 
						|
 | 
						|
  if (Verbose) {
 | 
						|
    fprintf (stdout, "Writing database %s\n", DBFileName);
 | 
						|
  }
 | 
						|
 | 
						|
  if ((DBFptr = fopen (DBFileName, "wb")) == NULL) {
 | 
						|
    Error (NULL, 0, 0, DBFileName, "failed to open output database file for writing");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Fill in and write the database header
 | 
						|
  //
 | 
						|
  memset (&DbHeader, 0, sizeof (STRING_DB_HEADER));
 | 
						|
  DbHeader.HeaderSize = sizeof (STRING_DB_HEADER);
 | 
						|
  DbHeader.Key        = STRING_DB_KEY;
 | 
						|
  DbHeader.Version    = STRING_DB_VERSION;
 | 
						|
  //
 | 
						|
  // Count the number of languages we have
 | 
						|
  //
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    DbHeader.NumLanguages++;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Count up how many string identifiers we have, and total up the
 | 
						|
  // size of the names plus the size of the flags field we will
 | 
						|
  // write out too.
 | 
						|
  //
 | 
						|
  DbHeader.NumStringIdenfiers = mDBData.NumStringIdentifiers;
 | 
						|
  StringIdentifier            = mDBData.StringIdentifier;
 | 
						|
  for (Counter = 0; Counter < mDBData.NumStringIdentifiers; Counter++) {
 | 
						|
    StrLength = StrLen (StringIdentifier->StringName) + 1;
 | 
						|
    DbHeader.StringIdentifiersSize += StrLength * sizeof (WCHAR) + sizeof (StringIdentifier->Flags);
 | 
						|
    StringIdentifier = StringIdentifier->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Write the header
 | 
						|
  //
 | 
						|
  fwrite (&DbHeader, sizeof (STRING_DB_HEADER), 1, DBFptr);
 | 
						|
  if (Verbose) {
 | 
						|
    fprintf (stdout, "  Number of string identifiers  0x%04X\n", DbHeader.NumStringIdenfiers);
 | 
						|
    fprintf (stdout, "  Number of languages           %d\n", DbHeader.NumLanguages);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Write the string identifiers
 | 
						|
  //
 | 
						|
  for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) {
 | 
						|
    StringDBWriteStringIdentifier (
 | 
						|
      DBFptr,
 | 
						|
      (UINT16) StringIdentifier->Index,
 | 
						|
      StringIdentifier->Flags,
 | 
						|
      StringIdentifier->StringName
 | 
						|
      );
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Now write all the strings for each language
 | 
						|
  //
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    StringDBWriteLanguageDefinition (DBFptr, Lang->LanguageName, Lang->PrintableLanguageName);
 | 
						|
    for (StrList = Lang->String; StrList != NULL; StrList = StrList->Next) {
 | 
						|
      StringDBWriteString (
 | 
						|
        DBFptr,
 | 
						|
        StrList->Flags,
 | 
						|
        Lang->LanguageName,
 | 
						|
        StrList->StringName,
 | 
						|
        StrList->Scope,
 | 
						|
        StrList->Str
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  fclose (DBFptr);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
STATUS
 | 
						|
StringDBSetStringReferenced (
 | 
						|
  CHAR8     *StringIdentifierName,
 | 
						|
  BOOLEAN   IgnoreNotFound
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_IDENTIFIER *Id;
 | 
						|
  WCHAR             *WName;
 | 
						|
  STATUS            Status;
 | 
						|
  //
 | 
						|
  // See if it's already been defined.
 | 
						|
  //
 | 
						|
  Status  = STATUS_SUCCESS;
 | 
						|
  WName   = (WCHAR *) malloc ((strlen (StringIdentifierName) + 1) * sizeof (WCHAR));
 | 
						|
  UnicodeSPrint (WName, (strlen (StringIdentifierName) + 1) * sizeof (WCHAR), L"%a", StringIdentifierName);
 | 
						|
  Id = StringDBFindStringIdentifierByName (WName);
 | 
						|
  if (Id != NULL) {
 | 
						|
    Id->Flags |= STRING_FLAGS_REFERENCED;
 | 
						|
  } else {
 | 
						|
    if (IgnoreNotFound == 0) {
 | 
						|
      ParserWarning (0, StringIdentifierName, "string identifier not found in database");
 | 
						|
      Status = STATUS_WARNING;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  free (WName);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Dump the contents of a database to an output unicode file.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  DBFileName        - name of the pre-existing database file to read
 | 
						|
  OutputFileName    - name of the file to dump the database contents to
 | 
						|
  Verbose           - for printing of additional info useful for debugging
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
Notes:
 | 
						|
 | 
						|
  There's some issue with the unicode printing routines. Therefore to 
 | 
						|
  write to the output file properly, open it as binary and use fwrite.
 | 
						|
  Ideally we could open it with just L"w" and use fwprintf().
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBDumpDatabase (
 | 
						|
  CHAR8               *DBFileName,
 | 
						|
  CHAR8               *OutputFileName,
 | 
						|
  BOOLEAN             Verbose
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST     *Lang;
 | 
						|
  STRING_IDENTIFIER *StringIdentifier;
 | 
						|
  STRING_LIST       *StrList;
 | 
						|
  FILE              *OutFptr;
 | 
						|
  WCHAR             WChar;
 | 
						|
  WCHAR             CrLf[2];
 | 
						|
  WCHAR             Line[200];
 | 
						|
  WCHAR             *Scope;
 | 
						|
  //
 | 
						|
  // This function assumes the database has already been read, and
 | 
						|
  // we're just dumping our internal data structures to a unicode file.
 | 
						|
  //
 | 
						|
  if (Verbose) {
 | 
						|
    fprintf (stdout, "Dumping database file %s\n", DBFileName);
 | 
						|
  }
 | 
						|
 | 
						|
  OutFptr         = fopen (OutputFileName, "wb");
 | 
						|
  if (OutFptr == NULL) {
 | 
						|
    Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  WChar = UNICODE_FILE_START;
 | 
						|
  fwrite (&WChar, sizeof (WCHAR), 1, OutFptr);
 | 
						|
  CrLf[1] = UNICODE_LF;
 | 
						|
  CrLf[0] = UNICODE_CR;
 | 
						|
  //
 | 
						|
  // The default control character is '/'. Make it '#' by writing
 | 
						|
  // "/=#" to the output file.
 | 
						|
  //
 | 
						|
  UnicodeSPrint (Line, sizeof(Line), L"/=#");
 | 
						|
  fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
  fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
  fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
  //
 | 
						|
  // Dump all the string identifiers and their values
 | 
						|
  //
 | 
						|
  StringDBAssignStringIndexes ();
 | 
						|
  for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) {
 | 
						|
    //
 | 
						|
    // Write the "#define " string
 | 
						|
    //
 | 
						|
    if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
      UnicodeSPrint (
 | 
						|
        Line,
 | 
						|
        sizeof(Line), L"%s %-60.60s 0x%04X",
 | 
						|
        DEFINE_STR,
 | 
						|
        StringIdentifier->StringName,
 | 
						|
        StringIdentifier->Index
 | 
						|
        );
 | 
						|
    } else {
 | 
						|
      UnicodeSPrint (
 | 
						|
        Line,
 | 
						|
        sizeof(Line), L"%s %-60.60s 0x%04X  // NOT REFERENCED",
 | 
						|
        DEFINE_STR,
 | 
						|
        StringIdentifier->StringName,
 | 
						|
        StringIdentifier->Index
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
    fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
  }
 | 
						|
 | 
						|
  fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
  //
 | 
						|
  // Now write all the strings for each language.
 | 
						|
  //
 | 
						|
  WChar = UNICODE_DOUBLE_QUOTE;
 | 
						|
  Scope = NULL;
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
    UnicodeSPrint (Line, sizeof(Line), L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName);
 | 
						|
    fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
    fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
    fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
    //
 | 
						|
    // Now the strings (in double-quotes) for this language. Write
 | 
						|
    // #string STR_NAME  #language eng "string"
 | 
						|
    //
 | 
						|
    for (StrList = Lang->String; StrList != NULL; StrList = StrList->Next) {
 | 
						|
      //
 | 
						|
      // Print the internal flags for debug
 | 
						|
      //
 | 
						|
      UnicodeSPrint (Line, sizeof(Line), L"// flags=0x%02X", (UINT32) StrList->Flags);
 | 
						|
      fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
      fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
      //
 | 
						|
      // Print the scope if changed
 | 
						|
      //
 | 
						|
      if ((Scope == NULL) || (StrCmp (Scope, StrList->Scope) != 0)) {
 | 
						|
        UnicodeSPrint (Line, sizeof(Line), L"#scope %s", StrList->Scope);
 | 
						|
        fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
        fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
        Scope = StrList->Scope;
 | 
						|
      }
 | 
						|
 | 
						|
      UnicodeSPrint (
 | 
						|
        Line,
 | 
						|
        sizeof(Line), L"#string %-50.50s #language %s \"",
 | 
						|
        StrList->StringName,
 | 
						|
        Lang->LanguageName
 | 
						|
        );
 | 
						|
      fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
      fwrite (StrList->Str, StrList->Size - sizeof (WCHAR), 1, OutFptr);
 | 
						|
      UnicodeSPrint (Line, sizeof(Line), L"\"");
 | 
						|
      fwrite (Line, StrLen (Line) * sizeof (WCHAR), 1, OutFptr);
 | 
						|
      fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  fclose (OutFptr);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Given a primary language, a string identifier number, and a list of
 | 
						|
  languages, find a secondary string.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  LanguageName      - primary language, like "spa"
 | 
						|
  StringId          - string index value
 | 
						|
  LanguageList      - linked list of "eng", "spa+cat",...
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  Pointer to a secondary string if found. NULL otherwise.
 | 
						|
 | 
						|
Notes:
 | 
						|
 
 | 
						|
  Given: LanguageName "spa"   and  LanguageList "spa+cat", match the
 | 
						|
  "spa" and extract the "cat" and see if there is a string defined
 | 
						|
  for "cat".StringId.
 | 
						|
 | 
						|
--*/
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteStringIdentifier (
 | 
						|
  FILE                *DBFptr,
 | 
						|
  UINT16              StringId,
 | 
						|
  UINT16              Flags,
 | 
						|
  WCHAR               *IdentifierName
 | 
						|
  )
 | 
						|
{
 | 
						|
  DB_DATA_ITEM_HEADER Hdr;
 | 
						|
  memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER));
 | 
						|
  Hdr.DataType = DB_DATA_TYPE_STRING_IDENTIFIER;
 | 
						|
  if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string to output database file", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (&StringId, sizeof (StringId), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write StringId to output database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (&Flags, sizeof (Flags), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write StringId flags to output database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, IdentifierName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadStringIdentifier (
 | 
						|
  FILE                *DBFptr
 | 
						|
  )
 | 
						|
{
 | 
						|
  WCHAR   *IdentifierName;
 | 
						|
  UINT16  Flags;
 | 
						|
  UINT16  StringId;
 | 
						|
  UINT16  Size;
 | 
						|
 | 
						|
  if (fread (&StringId, sizeof (StringId), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to read StringId from database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fread (&Flags, sizeof (Flags), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to read StringId flags from database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &IdentifierName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  StringDBAddStringIdentifier (IdentifierName, &StringId, Flags);
 | 
						|
  //
 | 
						|
  // printf ("STRID:  0x%04X %S\n", (UINT32)StringId, IdentifierName);
 | 
						|
  //
 | 
						|
  FREE (IdentifierName);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteString (
 | 
						|
  FILE            *DBFptr,
 | 
						|
  UINT16          Flags,
 | 
						|
  WCHAR           *Language,
 | 
						|
  WCHAR           *StringName,
 | 
						|
  WCHAR           *Scope,
 | 
						|
  WCHAR           *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  DB_DATA_ITEM_HEADER Hdr;
 | 
						|
  memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER));
 | 
						|
  Hdr.DataType = DB_DATA_TYPE_STRING_DEFINITION;
 | 
						|
  if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string header to output database file", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (&Flags, sizeof (Flags), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string flags to output database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, Language) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, StringName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, Scope) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, Str) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // printf ("DBWriteString: %S.%S.%S\n", Language, StringName, Scope);
 | 
						|
  //
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadString (
 | 
						|
  FILE            *DBFptr
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Flags;
 | 
						|
  UINT16  Size;
 | 
						|
  WCHAR   *Language;
 | 
						|
  WCHAR   *StringName;
 | 
						|
  WCHAR   *Scope;
 | 
						|
  WCHAR   *Str;
 | 
						|
 | 
						|
  if (fread (&Flags, sizeof (Flags), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to read string flags from database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &Language) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &StringName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &Scope) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &Str) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If the first or second string (language name and printable language name),
 | 
						|
  // then skip them. They're added via language definitions data items in
 | 
						|
  // the database.
 | 
						|
  //
 | 
						|
  if (StringName[0] != L'$') {
 | 
						|
    StringDBAddString (Language, StringName, Scope, Str, FALSE, Flags);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // printf ("DBReadString: %S.%S.%S\n", Language, StringName, Scope);
 | 
						|
  //
 | 
						|
  FREE (Language);
 | 
						|
  FREE (StringName);
 | 
						|
  if (Str != NULL) {
 | 
						|
    FREE (Str);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Scope != NULL) {
 | 
						|
    FREE (Scope);
 | 
						|
  }
 | 
						|
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteLanguageDefinition (
 | 
						|
  FILE            *DBFptr,
 | 
						|
  WCHAR           *LanguageName,
 | 
						|
  WCHAR           *PrintableLanguageName
 | 
						|
  )
 | 
						|
{
 | 
						|
  DB_DATA_ITEM_HEADER Hdr;
 | 
						|
  memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER));
 | 
						|
  Hdr.DataType = DB_DATA_TYPE_LANGUAGE_DEFINITION;
 | 
						|
  if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string to output database file", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, LanguageName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBWriteGenericString (DBFptr, PrintableLanguageName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadLanguageDefinition (
 | 
						|
  FILE            *DBFptr
 | 
						|
  )
 | 
						|
{
 | 
						|
  WCHAR   *LanguageName;
 | 
						|
  WCHAR   *PrintableLanguageName;
 | 
						|
  UINT16  Size;
 | 
						|
  STATUS  Status;
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &LanguageName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (StringDBReadGenericString (DBFptr, &Size, &PrintableLanguageName) != STATUS_SUCCESS) {
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);
 | 
						|
  //
 | 
						|
  Status = StringDBAddLanguage (LanguageName, PrintableLanguageName);
 | 
						|
  FREE (LanguageName);
 | 
						|
  FREE (PrintableLanguageName);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
//
 | 
						|
// All unicode strings in the database consist of a UINT16 length
 | 
						|
// field, followed by the string itself. This routine reads one
 | 
						|
// of those and returns the info.
 | 
						|
//
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBReadGenericString (
 | 
						|
  FILE      *DBFptr,
 | 
						|
  UINT16    *Size,
 | 
						|
  WCHAR     **Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  LSize;
 | 
						|
  UINT16  Flags;
 | 
						|
  WCHAR   *LStr;
 | 
						|
 | 
						|
  if (fread (&LSize, sizeof (UINT16), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to read a string length field from the database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fread (&Flags, sizeof (UINT16), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to read a string flags field from the database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  LStr = MALLOC (LSize);
 | 
						|
  if (LStr == NULL) {
 | 
						|
    Error (__FILE__, __LINE__, 0, "memory allocation failed reading the database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fread (LStr, sizeof (WCHAR), (UINT32) LSize / sizeof (WCHAR), DBFptr) != (UINT32) LSize / sizeof (WCHAR)) {
 | 
						|
    Error (NULL, 0, 0, "failed to read string from database", NULL);
 | 
						|
    Error (NULL, 0, 0, "database read failure", "offset 0x%X", ftell (DBFptr));
 | 
						|
    free (LStr);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // printf ("DBR: %S\n", LStr);
 | 
						|
  //
 | 
						|
  // If the flags field indicated we were asked to write a NULL string, then
 | 
						|
  // return them a NULL pointer.
 | 
						|
  //
 | 
						|
  if (Flags & STRING_FLAGS_UNDEFINED) {
 | 
						|
    *Size = 0;
 | 
						|
    *Str  = NULL;
 | 
						|
  } else {
 | 
						|
    *Size = LSize;
 | 
						|
    *Str  = LStr;
 | 
						|
  }
 | 
						|
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STATUS
 | 
						|
StringDBWriteGenericString (
 | 
						|
  FILE      *DBFptr,
 | 
						|
  WCHAR     *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT16  Size;
 | 
						|
  UINT16  Flags;
 | 
						|
  WCHAR   ZeroString[1];
 | 
						|
  //
 | 
						|
  // Strings in the database consist of a size UINT16 followed
 | 
						|
  // by the string itself.
 | 
						|
  //
 | 
						|
  if (Str == NULL) {
 | 
						|
    ZeroString[0] = 0;
 | 
						|
    Str           = ZeroString;
 | 
						|
    Size          = sizeof (ZeroString);
 | 
						|
    Flags         = STRING_FLAGS_UNDEFINED;
 | 
						|
  } else {
 | 
						|
    Flags = 0;
 | 
						|
    Size  = (UINT16) ((StrLen (Str) + 1) * sizeof (WCHAR));
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (&Size, sizeof (UINT16), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string size to database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (&Flags, sizeof (UINT16), 1, DBFptr) != 1) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string flags to database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (fwrite (Str, sizeof (WCHAR), Size / sizeof (WCHAR), DBFptr) != Size / sizeof (WCHAR)) {
 | 
						|
    Error (NULL, 0, 0, "failed to write string to database", NULL);
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
STRING_LIST *
 | 
						|
StringDBFindString (
 | 
						|
  WCHAR                       *LanguageName,
 | 
						|
  WCHAR                       *StringName,
 | 
						|
  WCHAR                       *Scope,
 | 
						|
  WCHAR_STRING_LIST           *LanguagesOfInterest,
 | 
						|
  WCHAR_MATCHING_STRING_LIST  *IndirectionList
 | 
						|
  )
 | 
						|
{
 | 
						|
  LANGUAGE_LIST               *Lang;
 | 
						|
  STRING_LIST                 *CurrString;
 | 
						|
  WCHAR_MATCHING_STRING_LIST  *IndListPtr;
 | 
						|
  WCHAR                       TempLangName[LANGUAGE_IDENTIFIER_NAME_LEN + 1];
 | 
						|
  WCHAR                       *WCharPtr;
 | 
						|
 | 
						|
  //
 | 
						|
  // If we were given an indirection list, then see if one was specified for this
 | 
						|
  // string identifier. That is to say, if the indirection says "STR_ID_MY_FAVORITE MyScope",
 | 
						|
  // then if this string name matches one in the list, then do a lookup with the
 | 
						|
  // specified scope and return that value.
 | 
						|
  //
 | 
						|
  if (IndirectionList != NULL) {
 | 
						|
    for (IndListPtr = IndirectionList; IndListPtr != NULL; IndListPtr = IndListPtr->Next) {
 | 
						|
      if (StrCmp (StringName, IndListPtr->Str1) == 0) {
 | 
						|
        CurrString = StringDBFindString (LanguageName, StringName, IndListPtr->Str2, LanguagesOfInterest, NULL);
 | 
						|
        if (CurrString != NULL) {
 | 
						|
          return CurrString;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // First look for exact match language.stringname
 | 
						|
  //
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    if (StrCmp (LanguageName, Lang->LanguageName) == 0) {
 | 
						|
      //
 | 
						|
      // Found language match. Try to find string name match
 | 
						|
      //
 | 
						|
      for (CurrString = Lang->String; CurrString != NULL; CurrString = CurrString->Next) {
 | 
						|
        if (StrCmp (StringName, CurrString->StringName) == 0) {
 | 
						|
          //
 | 
						|
          // Found a string name match. See if we're supposed to find
 | 
						|
          // a scope match.
 | 
						|
          //
 | 
						|
          if (Scope != NULL) {
 | 
						|
            if (StrCmp (CurrString->Scope, Scope) == 0) {
 | 
						|
              return CurrString;
 | 
						|
            }
 | 
						|
          } else {
 | 
						|
            return CurrString;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // If we got here, then we didn't find a match. Look for secondary string
 | 
						|
  // matches. That is to say, if we're processing "spa", and they requested
 | 
						|
  // "spa+cat", then recursively call with "cat"
 | 
						|
  //
 | 
						|
  while (LanguagesOfInterest != NULL) {
 | 
						|
    //
 | 
						|
    // If this is the language we're looking for, then process the
 | 
						|
    // languages of interest list for it.
 | 
						|
    //
 | 
						|
    if (StrnCmp (LanguageName, LanguagesOfInterest->Str, LANGUAGE_IDENTIFIER_NAME_LEN) == 0) {
 | 
						|
      WCharPtr = LanguagesOfInterest->Str + LANGUAGE_IDENTIFIER_NAME_LEN;
 | 
						|
      while (*WCharPtr) {
 | 
						|
        //
 | 
						|
        // Double-check the length, though it should have been checked on the
 | 
						|
        // command line.
 | 
						|
        //
 | 
						|
        if (StrLen (WCharPtr) < LANGUAGE_IDENTIFIER_NAME_LEN) {
 | 
						|
          Error (NULL, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest->Str);
 | 
						|
          return NULL;
 | 
						|
        }
 | 
						|
 | 
						|
        StrnCpy (TempLangName, WCharPtr, LANGUAGE_IDENTIFIER_NAME_LEN);
 | 
						|
        TempLangName[LANGUAGE_IDENTIFIER_NAME_LEN]  = 0;
 | 
						|
        CurrString = StringDBFindString (TempLangName, StringName, NULL, NULL, IndirectionList);
 | 
						|
        if (CurrString != NULL) {
 | 
						|
          return CurrString;
 | 
						|
        }
 | 
						|
 | 
						|
        WCharPtr += LANGUAGE_IDENTIFIER_NAME_LEN;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    LanguagesOfInterest = LanguagesOfInterest->Next;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
STATUS
 | 
						|
StringDBSetScope (
 | 
						|
  WCHAR   *Scope
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // Free up existing scope memory.
 | 
						|
  //
 | 
						|
  if (mDBData.CurrentScope != NULL) {
 | 
						|
    FREE (mDBData.CurrentScope);
 | 
						|
  }
 | 
						|
 | 
						|
  mDBData.CurrentScope = DuplicateString (Scope);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 | 
						|
//
 | 
						|
// We typically don't assign index values to string identifiers
 | 
						|
// until we're ready to write out files. To reduce the size of
 | 
						|
// the output file, re-order the string identifiers to move any
 | 
						|
// unreferenced ones to the end. Then we'll walk the list
 | 
						|
// again to assign string indexes, keeping track of the last
 | 
						|
// one referenced.
 | 
						|
//
 | 
						|
static
 | 
						|
void
 | 
						|
StringDBAssignStringIndexes (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  STRING_IDENTIFIER *StrId;
 | 
						|
  STRING_IDENTIFIER *FirstUsed;
 | 
						|
  STRING_IDENTIFIER *LastUsed;
 | 
						|
  STRING_IDENTIFIER *FirstUnused;
 | 
						|
  STRING_IDENTIFIER *LastUnused;
 | 
						|
  UINT32            Index;
 | 
						|
  UINT32            MaxReferenced;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create two lists -- used and unused. Then put them together with
 | 
						|
  // the unused ones on the end.
 | 
						|
  //
 | 
						|
  FirstUsed   = NULL;
 | 
						|
  LastUsed    = NULL;
 | 
						|
  FirstUnused = NULL;
 | 
						|
  LastUnused  = NULL;
 | 
						|
  StrId       = mDBData.StringIdentifier;
 | 
						|
  while (StrId != NULL) {
 | 
						|
    if ((StrId->Flags & STRING_FLAGS_REFERENCED) == 0) {
 | 
						|
      //
 | 
						|
      // Put it on the unused list
 | 
						|
      //
 | 
						|
      if (FirstUnused == NULL) {
 | 
						|
        FirstUnused = StrId;
 | 
						|
      } else {
 | 
						|
        LastUnused->Next = StrId;
 | 
						|
      }
 | 
						|
 | 
						|
      LastUnused        = StrId;
 | 
						|
      StrId             = StrId->Next;
 | 
						|
      LastUnused->Next  = NULL;
 | 
						|
    } else {
 | 
						|
      //
 | 
						|
      // Put it on the used list
 | 
						|
      //
 | 
						|
      if (FirstUsed == NULL) {
 | 
						|
        FirstUsed = StrId;
 | 
						|
      } else {
 | 
						|
        LastUsed->Next = StrId;
 | 
						|
      }
 | 
						|
 | 
						|
      LastUsed        = StrId;
 | 
						|
      StrId           = StrId->Next;
 | 
						|
      LastUsed->Next  = NULL;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Join the lists
 | 
						|
  //
 | 
						|
  if (FirstUsed != NULL) {
 | 
						|
    mDBData.StringIdentifier  = FirstUsed;
 | 
						|
    LastUsed->Next            = FirstUnused;
 | 
						|
  } else {
 | 
						|
    mDBData.StringIdentifier = FirstUnused;
 | 
						|
  }
 | 
						|
 | 
						|
  MaxReferenced = 0;
 | 
						|
  Index         = 0;
 | 
						|
  for (StrId = mDBData.StringIdentifier; StrId != NULL; StrId = StrId->Next) {
 | 
						|
    StrId->Index = Index;
 | 
						|
    Index++;
 | 
						|
    if (StrId->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
      mDBData.NumStringIdentifiersReferenced = Index;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mDBData.NumStringIdentifiers = Index;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
WCHAR *
 | 
						|
DuplicateString (
 | 
						|
  WCHAR   *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  WCHAR *NewStr;
 | 
						|
  if (Str == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  NewStr = MALLOC ((StrLen (Str) + 1) * sizeof (WCHAR));
 | 
						|
  if (NewStr == NULL) {
 | 
						|
    Error (NULL, 0, 0, "memory allocation failure", NULL);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  StrCpy (NewStr, Str);
 | 
						|
  return NewStr;
 | 
						|
}
 | 
						|
 | 
						|
static
 | 
						|
WCHAR *
 | 
						|
AsciiToWchar (
 | 
						|
  CHAR8 *Str
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32  Len;
 | 
						|
  WCHAR   *NewStr;
 | 
						|
  WCHAR   *Ptr;
 | 
						|
 | 
						|
  Len     = strlen (Str) + 1;
 | 
						|
  NewStr  = (WCHAR *) malloc (Len * sizeof (WCHAR));
 | 
						|
  for (Ptr = NewStr; *Str != 0; Str++, Ptr++) {
 | 
						|
    *Ptr = (UINT16) (UINT8) *Str;
 | 
						|
  }
 | 
						|
 | 
						|
  *Ptr = 0;
 | 
						|
  return NewStr;
 | 
						|
}
 | 
						|
 | 
						|
/*****************************************************************************/
 | 
						|
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create an HII export string pack for the strings in our database.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  FileName        - name of the output file to write 
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  STATUS
 | 
						|
 | 
						|
 | 
						|
--*/
 | 
						|
STATUS
 | 
						|
StringDBCreateHiiExportPack (
 | 
						|
  CHAR8                       *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  FILE                        *Fptr;
 | 
						|
  LANGUAGE_LIST               *Lang;
 | 
						|
  STRING_LIST                 *CurrString;
 | 
						|
  STRING_LIST                 EmptyString;
 | 
						|
  UINT32                      Offset;
 | 
						|
  UINT32                      StringIndex;
 | 
						|
  UINT32                      TempIndex;
 | 
						|
  EFI_HII_STRING_PACK         StringPack;
 | 
						|
  UINT32                      Len;
 | 
						|
  WCHAR                       ZeroString[1];
 | 
						|
  WCHAR                       *TempStringPtr;
 | 
						|
  WCHAR                       *LangName;
 | 
						|
  STRING_IDENTIFIER           *StringIdentifier;
 | 
						|
 | 
						|
  if ((Fptr = fopen (FileName, "wb")) == NULL) {
 | 
						|
    Error (NULL, 0, 0, FileName, "failed to open output HII export file");
 | 
						|
    return STATUS_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Assign index values to the string identifiers
 | 
						|
  //
 | 
						|
  StringDBAssignStringIndexes ();
 | 
						|
  //
 | 
						|
  // If a given string is not defined, then we'll use this one.
 | 
						|
  //
 | 
						|
  memset (&EmptyString, 0, sizeof (EmptyString));
 | 
						|
  EmptyString.Size  = sizeof (ZeroString);
 | 
						|
  EmptyString.Str   = ZeroString;
 | 
						|
  //
 | 
						|
  // Process each language, then each string for each langage
 | 
						|
  //
 | 
						|
  ZeroString[0] = 0;
 | 
						|
  for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
 | 
						|
    //
 | 
						|
    // Process each string for this language. We have to make 3 passes on the strings:
 | 
						|
    //   Pass1: computes sizes and fill in the string pack header
 | 
						|
    //   Pass2: write the array of offsets
 | 
						|
    //   Pass3: write the strings
 | 
						|
    //
 | 
						|
    //
 | 
						|
    // PASS 1: Fill in and print the HII string pack header
 | 
						|
    //
 | 
						|
    // Compute the size for this language package and write
 | 
						|
    // the header out. Each string package contains:
 | 
						|
    //   Header
 | 
						|
    //   Offset[]  -- an array of offsets to strings, of type RELOFST each
 | 
						|
    //   String[]  -- the actual strings themselves
 | 
						|
    //
 | 
						|
    memset ((char *) &StringPack, 0, sizeof (EFI_HII_STRING_PACK));
 | 
						|
    StringPack.Header.Type        = EFI_HII_STRING;
 | 
						|
    StringPack.NumStringPointers  = (UINT16) mDBData.NumStringIdentifiersReferenced;
 | 
						|
    LangName                      = Lang->LanguageName;
 | 
						|
    //
 | 
						|
    // First string is the language name. If we're printing all languages, then
 | 
						|
    // it's just the "spa". If we were given a list of languages to print, then it's
 | 
						|
    // the "spacat" string. Compute its offset and fill in
 | 
						|
    // the info in the header. Since we know the language name string's length,
 | 
						|
    // and the printable language name follows it, use that info to fill in the
 | 
						|
    // entry for the printable language name as well.
 | 
						|
    //
 | 
						|
    StringPack.LanguageNameString = (STRING_OFFSET) (sizeof (EFI_HII_STRING_PACK) + (mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET)));
 | 
						|
    StringPack.PrintableLanguageName = (STRING_OFFSET) (StringPack.LanguageNameString + (StrLen (LangName) + 1) * sizeof (WCHAR));
 | 
						|
    //
 | 
						|
    // Add up the size of all strings so we can fill in our header.
 | 
						|
    //
 | 
						|
    Len = 0;
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        Len += (StrLen (LangName) + 1) * sizeof (WCHAR);
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a string with this language.stringname
 | 
						|
        //
 | 
						|
        StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
        if (StringIdentifier == NULL) {
 | 
						|
          Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
          return STATUS_ERROR;
 | 
						|
        }
 | 
						|
        //
 | 
						|
        // Find a matching string if this string identifier was referenced
 | 
						|
        //
 | 
						|
        EmptyString.Flags = STRING_FLAGS_UNDEFINED;
 | 
						|
        CurrString        = NULL;
 | 
						|
        if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        Lang->LanguageName,
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL,
 | 
						|
                        NULL, // LanguagesOfInterest,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
          //
 | 
						|
          // IndirectionList);
 | 
						|
          //
 | 
						|
          if (NULL == CurrString) {
 | 
						|
            //
 | 
						|
            // If string for Lang->LanguageName is not found, try to get an English version
 | 
						|
            //
 | 
						|
            CurrString = StringDBFindString (
 | 
						|
                          L"eng",
 | 
						|
                          StringIdentifier->StringName,
 | 
						|
                          NULL,
 | 
						|
                          NULL, // LanguagesOfInterest,
 | 
						|
                          NULL
 | 
						|
                          );
 | 
						|
            //
 | 
						|
            // IndirectionList);
 | 
						|
            //
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString = &EmptyString;
 | 
						|
          EmptyString.Flags |= StringIdentifier->Flags;
 | 
						|
        }
 | 
						|
 | 
						|
        Len += CurrString->Size;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    StringPack.Header.Length =    sizeof (EFI_HII_STRING_PACK) 
 | 
						|
                                + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET) 
 | 
						|
                                + Len;
 | 
						|
    //
 | 
						|
    // Write out the string pack header
 | 
						|
    //
 | 
						|
    fwrite ((void *) &StringPack, sizeof (StringPack), 1, Fptr);
 | 
						|
    //
 | 
						|
    // PASS2 : write the offsets
 | 
						|
    //
 | 
						|
    // Traverse the list of strings again and write the array of offsets. The
 | 
						|
    // offset to the first string is the size of the string pack header
 | 
						|
    // plus the size of the offsets array. The other strings follow it.
 | 
						|
    //
 | 
						|
    StringIndex = 0;
 | 
						|
    Offset      = sizeof (StringPack) + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET);
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      //
 | 
						|
      // Write the offset
 | 
						|
      //
 | 
						|
      fwrite (&Offset, sizeof (STRING_OFFSET), 1, Fptr);
 | 
						|
      //
 | 
						|
      // Find the string name
 | 
						|
      //
 | 
						|
      StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
      if (StringIdentifier == NULL) {
 | 
						|
        Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        Offset += (StrLen (LangName) + 1) * sizeof (WCHAR);
 | 
						|
        CurrString = StringDBFindString (
 | 
						|
                      Lang->LanguageName,
 | 
						|
                      StringIdentifier->StringName,
 | 
						|
                      NULL, // scope
 | 
						|
                      NULL,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a matching string
 | 
						|
        //
 | 
						|
        CurrString = StringDBFindString (
 | 
						|
                      Lang->LanguageName,
 | 
						|
                      StringIdentifier->StringName,
 | 
						|
                      NULL, // scope
 | 
						|
                      NULL, // LanguagesOfInterest,
 | 
						|
                      NULL
 | 
						|
                      );
 | 
						|
        //
 | 
						|
        // IndirectionList);
 | 
						|
        //
 | 
						|
        if (NULL == CurrString) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        L"eng",
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL, // scope
 | 
						|
                        NULL, // LanguagesOfInterest,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
          //
 | 
						|
          // IndirectionList);
 | 
						|
          //
 | 
						|
        }
 | 
						|
 | 
						|
        EmptyString.LanguageName = Lang->LanguageName;
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString        = &EmptyString;
 | 
						|
          EmptyString.Flags = STRING_FLAGS_UNDEFINED;
 | 
						|
        } else if ((StringIdentifier->Flags & STRING_FLAGS_REFERENCED) == 0) {
 | 
						|
          CurrString        = &EmptyString;
 | 
						|
          EmptyString.Flags = 0;
 | 
						|
        }
 | 
						|
 | 
						|
        Offset += CurrString->Size;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // PASS 3: write the strings themselves.
 | 
						|
    //
 | 
						|
    Offset = sizeof (StringPack) + mDBData.NumStringIdentifiersReferenced * sizeof (STRING_OFFSET);
 | 
						|
    for (StringIndex = 0; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
 | 
						|
      StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex);
 | 
						|
      if (StringIdentifier == NULL) {
 | 
						|
        Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
 | 
						|
        return STATUS_ERROR;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // For the first string (language name), we print out the "spacat" if they
 | 
						|
      // requested it. We set LangName to point to the proper language name string above.
 | 
						|
      //
 | 
						|
      if (StringIndex == STRING_ID_LANGUAGE_NAME) {
 | 
						|
        TempStringPtr = LangName;
 | 
						|
      } else {
 | 
						|
        //
 | 
						|
        // Find a matching string if this string identifier was referenced
 | 
						|
        //
 | 
						|
        CurrString = NULL;
 | 
						|
        if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
 | 
						|
          CurrString = StringDBFindString (
 | 
						|
                        Lang->LanguageName,
 | 
						|
                        StringIdentifier->StringName,
 | 
						|
                        NULL, // scope
 | 
						|
                        NULL, // LanguagesOfInterest,
 | 
						|
                        NULL
 | 
						|
                        );
 | 
						|
          //
 | 
						|
          // IndirectionList);
 | 
						|
          //
 | 
						|
          if (NULL == CurrString) {
 | 
						|
            CurrString = StringDBFindString (
 | 
						|
                          L"eng",
 | 
						|
                          StringIdentifier->StringName,
 | 
						|
                          NULL, // scope
 | 
						|
                          NULL, // LanguagesOfInterest,
 | 
						|
                          NULL
 | 
						|
                          );
 | 
						|
            //
 | 
						|
            // IndirectionList);
 | 
						|
            //
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        if (CurrString == NULL) {
 | 
						|
          CurrString = &EmptyString;
 | 
						|
        }
 | 
						|
 | 
						|
        TempStringPtr = CurrString->Str;
 | 
						|
      }
 | 
						|
 | 
						|
      for (TempIndex = 0; TempStringPtr[TempIndex] != 0; TempIndex++) {
 | 
						|
        fwrite (&TempStringPtr[TempIndex], sizeof (CHAR16), 1, Fptr);
 | 
						|
        Offset += 2;
 | 
						|
      }
 | 
						|
      //
 | 
						|
      // Print NULL WCHAR at the end of this string.
 | 
						|
      //
 | 
						|
      TempIndex = 0;
 | 
						|
      fwrite (&TempIndex, sizeof (CHAR16), 1, Fptr);
 | 
						|
      Offset += 2;
 | 
						|
    }
 | 
						|
    //
 | 
						|
    // Sanity check the offset. Make sure our running offset is what we put in the
 | 
						|
    // string pack header.
 | 
						|
    //
 | 
						|
    if (StringPack.Header.Length != Offset) {
 | 
						|
      Error (
 | 
						|
        __FILE__,
 | 
						|
        __LINE__,
 | 
						|
        0,
 | 
						|
        "application error",
 | 
						|
        "stringpack size 0x%X does not match final size 0x%X",
 | 
						|
        StringPack.Header.Length,
 | 
						|
        Offset
 | 
						|
        );
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Print terminator string pack, closing brace and close the file.
 | 
						|
  // The size of 0 triggers to the consumer that this is the end.
 | 
						|
  //
 | 
						|
  memset ((char *) &StringPack, 0, sizeof (EFI_HII_STRING_PACK));
 | 
						|
  StringPack.Header.Type = EFI_HII_STRING;
 | 
						|
  fwrite ((void *) &StringPack, sizeof (StringPack), 1, Fptr);
 | 
						|
  fclose (Fptr);
 | 
						|
  return STATUS_SUCCESS;
 | 
						|
}
 |