audk/EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c

2675 lines
69 KiB
C
Raw Normal View History

/*++
Copyright (c) 2004 - 2007, 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>
#include <Tiano.h>
#include <EfiUtilityMsgs.h>
#include <EfiHii.h>
#include "StrGather.h"
#include "StringDb.h"
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
void
StringDBWriteStandardFileHeader (
FILE *OutFptr
);
static
WCHAR *
AsciiToWchar (
INT8 *Str
);
static
CHAR8 *
WcharToAscii (
WCHAR *Str
);
static
WCHAR *
DuplicateString (
WCHAR *Str
);
static
WCHAR *
WstrCatenate (
WCHAR *Dst,
WCHAR *Src
);
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,
WCHAR *SecondaryLanguageList
);
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->SecondaryLanguageList);
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;
}
}
/*****************************************************************************/
STATUS
StringDBDumpStringDefines (
INT8 *FileName,
INT8 *BaseName
)
{
FILE *Fptr;
STRING_IDENTIFIER *Identifier;
INT8 CopyBaseName[100];
UINT32 Index;
const INT8 *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) {
fprintf (Fptr, "#define %-40S 0x%04X\n", Identifier->StringName, Identifier->Index);
} else {
fprintf (Fptr, "//#define %-40S 0x%04X // not referenced\n", Identifier->StringName, Identifier->Index);
}
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 ((wcslen (StringName) + 1) * sizeof (WCHAR));
if (StringIdentifier->StringName == NULL) {
Error (NULL, 0, 0, NULL, "memory allocation error");
return STATUS_ERROR;
}
wcscpy (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;
STRING_IDENTIFIER *StringIdentifier;
//
// 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 ((wcscmp (StringName, LANGUAGE_NAME_STRING_NAME) == 0) &&
(wcscmp (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 = (wcslen (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.
//
wcscpy (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 = (wcslen (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
--*/
LANGUAGE_LIST *
StringDBFindLanguageList (
WCHAR *LanguageName
)
{
LANGUAGE_LIST *Lang;
Lang = mDBData.LanguageList;
while (Lang != NULL) {
if (wcscmp (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,
WCHAR *SecondaryLanguageList
)
{
LANGUAGE_LIST *Lang;
//
// Check for redefinitions
//
Lang = StringDBFindLanguageList (LanguageName);
if (Lang != NULL) {
//
// Better be the same printable name
//
if (wcscmp (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
//
Lang->LanguageName = (WCHAR *) malloc ((wcslen (LanguageName) + 1) * 2);
if (Lang->LanguageName == NULL) {
Error (NULL, 0, 0, NULL, "memory allocation error");
return STATUS_ERROR;
}
wcscpy (Lang->LanguageName, LanguageName);
Lang->PrintableLanguageName = (WCHAR *) malloc ((wcslen (PrintableLanguageName) + 1) * sizeof (WCHAR));
if (Lang->PrintableLanguageName == NULL) {
Error (NULL, 0, 0, NULL, "memory allocation error");
FREE (Lang->LanguageName);
return STATUS_ERROR;
}
wcscpy (Lang->PrintableLanguageName, PrintableLanguageName);
if (SecondaryLanguageList != NULL) {
Lang->SecondaryLanguageList = (WCHAR *) malloc ((wcslen (SecondaryLanguageList) + 1) * sizeof (WCHAR));
if (Lang->SecondaryLanguageList == NULL) {
Error (NULL, 0, 0, NULL, "memory allocation error");
FREE (Lang->PrintableLanguageName);
FREE (Lang->LanguageName);
return STATUS_ERROR;
}
wcscpy (Lang->SecondaryLanguageList, SecondaryLanguageList);
} else {
Lang->SecondaryLanguageList = NULL;
}
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;
}
STATUS
StringDBAddSecondaryLanguage (
WCHAR *LanguageName,
WCHAR *SecondaryLanguageList
)
{
LANGUAGE_LIST *Lang;
Lang = StringDBFindLanguageList (LanguageName);
if (Lang == NULL) {
return STATUS_ERROR;
} else {
Lang->SecondaryLanguageList = WstrCatenate(Lang->SecondaryLanguageList, SecondaryLanguageList);
return STATUS_SUCCESS;
}
}
/*****************************************************************************/
static
STRING_IDENTIFIER *
StringDBFindStringIdentifierByName (
WCHAR *StringName
)
{
STRING_IDENTIFIER *Identifier;
Identifier = mDBData.StringIdentifier;
while (Identifier != NULL) {
if (wcscmp (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 (wcsncmp (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 (wcsncmp (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 (wcsncmp (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 (wcsncmp (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 (
INT8 *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 (
INT8 *DBFileName,
BOOLEAN Verbose
)
{
STRING_DB_HEADER DbHeader;
UINT32 Counter;
UINT32 StrLen;
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++) {
StrLen = wcslen (StringIdentifier->StringName) + 1;
DbHeader.StringIdentifiersSize += StrLen * 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, Lang->SecondaryLanguageList);
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 (
INT8 *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));
#ifdef USE_VC8
swprintf (WName, (strlen (StringIdentifierName) + 1) * sizeof (WCHAR), L"%S", StringIdentifierName);
#else
swprintf (WName, L"%S", StringIdentifierName);
#endif
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 (
INT8 *DBFileName,
INT8 *OutputFileName,
BOOLEAN Verbose
)
{
LANGUAGE_LIST *Lang;
STRING_IDENTIFIER *StringIdentifier;
STRING_LIST *StrList;
FILE *OutFptr;
WCHAR WChar;
WCHAR *WOutputFileName;
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);
}
WOutputFileName = AsciiToWchar (OutputFileName);
OutFptr = _wfopen (WOutputFileName, L"wb");
free (WOutputFileName);
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.
//
#ifdef USE_VC8
swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"/=#");
#else
swprintf (Line, L"/=#");
#endif
fwrite (Line, wcslen (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) {
#ifdef USE_VC8
swprintf (
Line,
wcslen(Line) * sizeof (WCHAR),
L"%s %-60.60s 0x%04X",
DEFINE_STR,
StringIdentifier->StringName,
StringIdentifier->Index
);
#else
swprintf (
Line,
L"%s %-60.60s 0x%04X",
DEFINE_STR,
StringIdentifier->StringName,
StringIdentifier->Index
);
#endif
} else {
#ifdef USE_VC8
swprintf (
Line,
wcslen(Line) * sizeof (WCHAR),
L"%s %-60.60s 0x%04X // NOT REFERENCED",
DEFINE_STR,
StringIdentifier->StringName,
StringIdentifier->Index
);
#else
swprintf (
Line,
L"%s %-60.60s 0x%04X // NOT REFERENCED",
DEFINE_STR,
StringIdentifier->StringName,
StringIdentifier->Index
);
#endif
}
fwrite (Line, wcslen (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);
#ifdef USE_VC8
swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName);
#else
swprintf (Line, L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName);
#endif
fwrite (Line, wcslen (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
//
#ifdef USE_VC8
swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"// flags=0x%02X", (UINT32) StrList->Flags);
#else
swprintf (Line, L"// flags=0x%02X", (UINT32) StrList->Flags);
#endif
fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
//
// Print the scope if changed
//
if ((Scope == NULL) || (wcscmp (Scope, StrList->Scope) != 0)) {
#ifdef USE_VC8
swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#scope %s", StrList->Scope);
#else
swprintf (Line, L"#scope %s", StrList->Scope);
#endif
fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
Scope = StrList->Scope;
}
#ifdef USE_VC8
swprintf (
Line,
wcslen(Line) * sizeof (WCHAR),
L"#string %-50.50s #language %s \"",
StrList->StringName,
Lang->LanguageName
);
#else
swprintf (
Line,
L"#string %-50.50s #language %s \"",
StrList->StringName,
Lang->LanguageName
);
#endif
fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
fwrite (StrList->Str, StrList->Size - sizeof (WCHAR), 1, OutFptr);
#ifdef USE_VC8
swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"\"");
#else
swprintf (Line, L"\"");
#endif
fwrite (Line, wcslen (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,
WCHAR *SecondaryLanguageList
)
{
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;
}
if (StringDBWriteGenericString (DBFptr, SecondaryLanguageList) != STATUS_SUCCESS) {
return STATUS_ERROR;
}
return STATUS_SUCCESS;
}
static
STATUS
StringDBReadLanguageDefinition (
FILE *DBFptr
)
{
WCHAR *LanguageName = NULL;
WCHAR *PrintableLanguageName = NULL;
WCHAR *SecondaryLanguageList = NULL;
UINT16 Size;
STATUS Status;
if (StringDBReadGenericString (DBFptr, &Size, &LanguageName) != STATUS_SUCCESS) {
return STATUS_ERROR;
}
if (StringDBReadGenericString (DBFptr, &Size, &PrintableLanguageName) != STATUS_SUCCESS) {
return STATUS_ERROR;
}
if (StringDBReadGenericString (DBFptr, &Size, &SecondaryLanguageList) != STATUS_SUCCESS) {
return STATUS_ERROR;
}
//
// printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);
//
Status = StringDBAddLanguage (LanguageName, PrintableLanguageName, SecondaryLanguageList);
FREE (LanguageName);
FREE (PrintableLanguageName);
FREE (SecondaryLanguageList);
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) ((wcslen (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 (wcscmp (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 (wcscmp (LanguageName, Lang->LanguageName) == 0) {
//
// Found language match. Try to find string name match
//
for (CurrString = Lang->String; CurrString != NULL; CurrString = CurrString->Next) {
if (wcscmp (StringName, CurrString->StringName) == 0) {
//
// Found a string name match. See if we're supposed to find
// a scope match.
//
if (Scope != NULL) {
if (wcscmp (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 (wcsncmp (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 (wcslen (WCharPtr) < LANGUAGE_IDENTIFIER_NAME_LEN) {
Error (NULL, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest->Str);
return NULL;
}
wcsncpy (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 ((wcslen (Str) + 1) * sizeof (WCHAR));
if (NewStr == NULL) {
Error (NULL, 0, 0, "memory allocation failure", NULL);
return NULL;
}
wcscpy (NewStr, Str);
return NewStr;
}
static
WCHAR *
WstrCatenate (
WCHAR *Dst,
WCHAR *Src
)
{
UINT32 Len = 0;
WCHAR *Bak = Dst;
if (Src == NULL) {
return Dst;
}
if (Dst != NULL) {
Len = wcslen (Dst);
}
Len += wcslen (Src);
Dst = (WCHAR *) malloc ((Len + 1) * 2);
if (Dst == NULL) {
return NULL;
}
Dst[0] = L'\0';
if (Bak != NULL) {
wcscpy (Dst, Bak);
FREE (Bak);
}
wcscat (Dst, Src);
return Dst;
}
static
WCHAR *
AsciiToWchar (
INT8 *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;
}
static
CHAR8 *
WcharToAscii (
WCHAR *Str
)
{
UINT32 Len;
CHAR8 *NewStr;
CHAR8 *Ptr;
Len = wcslen (Str) + 1;
NewStr = (CHAR8 *) malloc (Len * sizeof (CHAR8));
for (Ptr = NewStr; *Str != L'\0'; Str++, Ptr++) {
*Ptr = (CHAR8) *Str;
}
*Ptr = '\0';
return NewStr;
}
/*****************************************************************************/
CHAR8 *
unicode2ascii (
WCHAR *UnicodeStr
)
{
CHAR8 *RetStr = (CHAR8 *)UnicodeStr;
CHAR8 *AsciiStr = (CHAR8 *)UnicodeStr;
while (*UnicodeStr != '\0') {
*AsciiStr = (CHAR8) *(UnicodeStr++);
AsciiStr++;
}
*AsciiStr = '\0';
return RetStr;
}
STATUS
BuildStringPkgHdr (
IN WCHAR *PrimaryLangName,
IN WCHAR *SecondaryLangList,
IN UINT32 Type,
IN UINT32 PkgBlkSize,
OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr
)
{
UINT32 LangNameLen;
LangNameLen = wcslen (PrimaryLangName);
if (SecondaryLangList != NULL) {
LangNameLen += wcslen (SecondaryLangList) + 1;
}
*StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) malloc(sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);
if (*StrPkgHdr == NULL) {
return STATUS_ERROR;
}
memset (*StrPkgHdr, 0, sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);
(*StrPkgHdr)->Header.Type = Type;
(*StrPkgHdr)->Header.Length = PkgBlkSize + sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;
(*StrPkgHdr)->HdrSize = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;
(*StrPkgHdr)->StringInfoOffset = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;
(*StrPkgHdr)->LanguageWindow[0] = L'\0';
(*StrPkgHdr)->LanguageName = (EFI_STRING_ID)1;
strcpy ((*StrPkgHdr)->Language, unicode2ascii(PrimaryLangName));
if (SecondaryLangList != NULL) {
strcat ((*StrPkgHdr)->Language, ";");
strcat ((*StrPkgHdr)->Language, unicode2ascii(SecondaryLangList));
}
#ifdef DEBUG_STRGATHER
printf ("STR HDR\t %s\n", (*StrPkgHdr)->Language);
#endif
return STATUS_SUCCESS;
}
STATUS
BuildStringPkgUCS2Blk (
IN EFI_STRING_ID StringId,
IN WCHAR *LangName,
IN WCHAR *StrName,
OUT EFI_HII_SIBT_STRING_UCS2_BLOCK **StrBlk,
OUT UINT32 *BlkSize
)
{
UINT32 StrLen = 0;
STRING_LIST *CurrString = NULL;
if ((LangName == NULL) || (StrName == NULL) || (StrBlk == NULL)) {
return STATUS_ERROR;
}
*StrBlk = NULL;
*BlkSize = 0;
CurrString = StringDBFindString (LangName, StrName, NULL, NULL, NULL);
if (CurrString == NULL) {
return STATUS_WARNING;
}
StrLen = wcslen (CurrString->Str);
*BlkSize = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) + StrLen * 2;
*StrBlk = (EFI_HII_SIBT_STRING_UCS2_BLOCK *) malloc (*BlkSize);
if (*StrBlk == NULL) {
*StrBlk = NULL;
*BlkSize = 0;
return STATUS_ERROR;
}
(*StrBlk)->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
wcscpy((*StrBlk)->StringText, CurrString->Str);
return STATUS_SUCCESS;
}
STATUS
BuildStringPkgSKIP2Blk (
IN EFI_STRING_ID SkipIdCount,
OUT EFI_HII_SIBT_SKIP2_BLOCK **StrBlk
)
{
if (StrBlk == NULL) {
return STATUS_ERROR;
}
*StrBlk = NULL;
*StrBlk = (EFI_HII_SIBT_SKIP2_BLOCK *) malloc (sizeof (EFI_HII_SIBT_SKIP2_BLOCK));
if (*StrBlk == NULL) {
*StrBlk = NULL;
return STATUS_ERROR;
}
(*StrBlk)->Header.BlockType = EFI_HII_SIBT_SKIP2;
(*StrBlk)->SkipCount = SkipIdCount;
return STATUS_SUCCESS;
}
STATUS
BuildStringPkgEndBlk (
OUT EFI_HII_SIBT_END_BLOCK **End
)
{
*End = (EFI_HII_SIBT_END_BLOCK *) malloc (sizeof (EFI_HII_SIBT_END_BLOCK));
if (*End == NULL) {
return STATUS_ERROR;
}
(*End)->Header.BlockType = EFI_HII_SIBT_END;
return STATUS_SUCCESS;
}
/*++
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
StrPkgBlkBufferListAddTail (
IN EFI_STRING_ID StringId,
IN WCHAR *StrName,
IN SPkgBlkBuffer **PkgBufferListHead,
IN SPkgBlkBuffer **PkgBufferListTail,
IN VOID *Buffer,
IN UINT32 Size
)
{
SPkgBlkBuffer *pNew = NULL;
#ifdef DEBUG_STRGATHER
EFI_HII_STRING_BLOCK *SBlk = (EFI_HII_STRING_BLOCK *)Buffer;
#endif
if ((PkgBufferListHead == NULL) || (PkgBufferListTail == NULL)) {
return STATUS_ERROR;
}
pNew = (SPkgBlkBuffer *) malloc (sizeof (SPkgBlkBuffer));
if (pNew == NULL) {
return STATUS_ERROR;
}
pNew->mBlkBuffer = Buffer;
pNew->mBlkSize = Size;
if ((*PkgBufferListTail) == NULL) {
(*PkgBufferListHead) = (*PkgBufferListTail) = pNew;
} else {
(*PkgBufferListTail)->mNext = pNew;
(*PkgBufferListTail) = pNew;
pNew->mNext = NULL;
}
#ifdef DEBUG_STRGATHER
switch (SBlk->BlockType) {
case EFI_HII_SIBT_STRING_UCS2 :
printf ("\tID: [%x] TYPE: [UCS2]\t NAME: %S \t STR: %S\n", StringId, StrName, ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)SBlk)->StringText);
break;
case EFI_HII_SIBT_SKIP2 :
printf ("\tID: [NULL] TYPE: [SKIP2] SKIPCOUNT: [%x]\n", ((EFI_HII_SIBT_SKIP2_BLOCK *)SBlk)->SkipCount);
break;
case EFI_HII_SIBT_END :
printf ("\tID: [%x] TYPE: [END]\n", StringId);
break;
default :
printf ("!!!!UNKNOWN STRING TYPE!!!\n");
}
#endif
return STATUS_SUCCESS;
}
VOID
StrPkgHdrFree (
IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
)
{
if (StrPkgHdr != NULL) {
free (StrPkgHdr);
}
}
VOID
StrPkgBlkBufferListFree (
IN SPkgBlkBuffer *PkgBlkList
)
{
SPkgBlkBuffer *Buffer;
while (PkgBlkList != NULL) {
Buffer = PkgBlkList;
PkgBlkList = PkgBlkList->mNext;
if (Buffer->mBlkBuffer != NULL) {
free (Buffer->mBlkBuffer);
}
free (Buffer);
}
}
VOID
WriteBlockLine (
IN FILE *pFile,
IN UINT32 LineBytes,
IN INT8 *LineHeader,
IN INT8 *BlkBuf,
IN UINT32 BlkSize
)
{
UINT32 Index;
if ((pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
return;
}
for (Index = 0; Index < BlkSize; Index++) {
if ((Index % LineBytes) == 0) {
fprintf (pFile, "\n%s", LineHeader);
}
fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);
}
}
VOID
WriteBlockEnd (
IN FILE *pFile,
IN UINT32 LineBytes,
IN INT8 *LineHeader,
IN INT8 *BlkBuf,
IN UINT32 BlkSize
)
{
UINT32 Index;
if ((BlkSize == 0) || (pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
return;
}
for (Index = 0; Index < BlkSize - 1; Index++) {
if ((Index % LineBytes) == 0) {
fprintf (pFile, "\n%s", LineHeader);
}
fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);
}
if ((Index % LineBytes) == 0) {
fprintf (pFile, "\n%s", LineHeader);
}
fprintf (pFile, "0x%02X\n", (UINT8)BlkBuf[Index]);
}
#define BYTES_PRE_LINE 0x10
VOID
StrPkgWriteHdrCFile (
IN FILE *File,
IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
)
{
if (StrPkgHdr != NULL) {
fprintf (File, "\n // PACKAGE HEADER\n");
WriteBlockLine(File, BYTES_PRE_LINE, " ", (INT8 *)StrPkgHdr, StrPkgHdr->HdrSize);
}
}
VOID
StrPkgWirteArrayLength (
IN FILE *File,
IN UINT32 PkgNumber,
IN EFI_HII_STRING_PACKAGE_HDR **PkgHdr
)
{
UINT32 Index;
UINT32 ArrayLen;
ArrayLen = sizeof (UINT32);
for (Index = 0; Index < PkgNumber; Index++) {
if (PkgHdr[Index] != NULL) {
ArrayLen += PkgHdr[Index]->Header.Length;
}
}
fprintf (File, "\n // STRING ARRAY LENGTH\n");
WriteBlockLine(File, BYTES_PRE_LINE, " ", (UINT8 *)&ArrayLen, sizeof (UINT32));
}
VOID
StrPkgWriteBlkListCFile (
IN FILE *File,
IN SPkgBlkBuffer *BlkList,
IN BOOLEAN WriteEnd
)
{
SPkgBlkBuffer *Buffer;
fprintf (File, "\n\n // PACKAGE DATA\n");
while (BlkList != NULL) {
Buffer = BlkList;
BlkList = BlkList->mNext;
if ((Buffer->mNext == NULL) && (WriteEnd == TRUE)) {
if (Buffer->mBlkBuffer != NULL) {
WriteBlockEnd (File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize);
}
} else {
if (Buffer->mBlkBuffer != NULL) {
WriteBlockLine(File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize);
}
}
}
}
VOID
StrPkgWriteHdrBinary (
IN FILE *File,
IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
)
{
fwrite (StrPkgHdr, StrPkgHdr->HdrSize, 1, File);
}
VOID
StrPkgWriteBlkListBinary (
IN FILE *File,
IN SPkgBlkBuffer *BlkList
)
{
SPkgBlkBuffer *Buffer;
while (BlkList != NULL) {
Buffer = BlkList;
BlkList = BlkList->mNext;
if (Buffer->mBlkBuffer != NULL) {
fwrite (Buffer->mBlkBuffer, Buffer->mBlkSize, 1, File);
}
}
}
STATUS
StringDBGenStrPkgHdrAndBlkList (
IN LANGUAGE_LIST *Lang,
OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr,
OUT SPkgBlkBuffer **BlkList
)
{
STATUS Status;
UINT32 StringIndex;
EFI_STRING_ID StringIdCurrent;
EFI_STRING_ID SkipIdCount;
UINT32 BlkSize = 0;
EFI_HII_SIBT_STRING_UCS2_BLOCK *StrUCS2Blk = NULL;
EFI_HII_SIBT_SKIP2_BLOCK *StrSKIP2Blk = NULL;
STRING_IDENTIFIER *StringIdentifier = NULL;
EFI_HII_SIBT_END_BLOCK *EndBlk = NULL;
UINT32 PkgBlkSize = 0;
SPkgBlkBuffer *PkgBufferListHead = NULL;
SPkgBlkBuffer *PkgBufferListTail = NULL;
if ((Lang == NULL) || (StrPkgHdr == NULL) || (BlkList == NULL)) {
return STATUS_ERROR;
}
//
// Assign index values to the string identifiers
//
StringDBAssignStringIndexes ();
StringIdCurrent = EFI_STRING_ID_BEGIN;
SkipIdCount = 0;
for (StringIndex = STRING_ID_PRINTABLE_LANGUAGE_NAME; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {
if ((StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex)) == NULL) {
Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);
goto ExportPackOut;
}
if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
Status = BuildStringPkgUCS2Blk (StringIdCurrent, Lang->LanguageName, StringIdentifier->StringName, &StrUCS2Blk, &BlkSize);
switch (Status) {
case STATUS_ERROR:
goto ExportPackOut;
break;
case STATUS_WARNING :
SkipIdCount++;
break;
case STATUS_SUCCESS :
if (SkipIdCount == 0) {
if (StrPkgBlkBufferListAddTail (
StringIdCurrent,
StringIdentifier->StringName,
&PkgBufferListHead,
&PkgBufferListTail,
StrUCS2Blk,
BlkSize
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
PkgBlkSize += BlkSize;
} else {
if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {
goto ExportPackOut;
} else {
if (StrPkgBlkBufferListAddTail (
StringIdCurrent,
NULL,
&PkgBufferListHead,
&PkgBufferListTail,
StrSKIP2Blk,
sizeof (EFI_HII_SIBT_SKIP2_BLOCK)
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
SkipIdCount = 0;
}
if (StrPkgBlkBufferListAddTail (
StringIdCurrent,
StringIdentifier->StringName,
&PkgBufferListHead,
&PkgBufferListTail,
StrUCS2Blk,
BlkSize
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
PkgBlkSize += BlkSize;
}
}
}
StringIdCurrent++;
}
if (SkipIdCount != 0) {
if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {
goto ExportPackOut;
} else {
if (StrPkgBlkBufferListAddTail (
StringIdCurrent,
NULL,
&PkgBufferListHead,
&PkgBufferListTail,
StrSKIP2Blk,
sizeof (EFI_HII_SIBT_SKIP2_BLOCK)
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
SkipIdCount = 0;
}
}
if (BuildStringPkgEndBlk (&EndBlk) != STATUS_SUCCESS) {
goto ExportPackOut;
} else if (StrPkgBlkBufferListAddTail (
StringIdCurrent,
NULL,
&PkgBufferListHead,
&PkgBufferListTail,
EndBlk,
sizeof (EFI_HII_SIBT_END_BLOCK)
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
StringIdCurrent++;
PkgBlkSize += sizeof (EFI_HII_SIBT_END_BLOCK);
if (BuildStringPkgHdr(
Lang->LanguageName,
Lang->SecondaryLanguageList,
EFI_HII_PACKAGE_STRINGS,
PkgBlkSize,
StrPkgHdr
) != STATUS_SUCCESS) {
goto ExportPackOut;
}
*BlkList = PkgBufferListHead;
return STATUS_SUCCESS;
ExportPackOut:
StrPkgBlkBufferListFree(PkgBufferListHead);
*BlkList = NULL;
*StrPkgHdr = NULL;
return STATUS_ERROR;
}
STATUS
StringDBCreateHiiExportPack (
INT8 *FileName
)
{
FILE *File = NULL;
LANGUAGE_LIST *Lang = NULL;
EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr = NULL;
SPkgBlkBuffer *BlkList = NULL;
if (FileName == NULL) {
return STATUS_ERROR;
}
if ((File = fopen (FileName, "wb")) == NULL) {
Error (NULL, 0, 0, FileName, "failed to open output HII export file");
return STATUS_ERROR;
}
for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
if (StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr, &BlkList) != STATUS_SUCCESS) {
fclose (File);
return STATUS_SUCCESS;
}
StrPkgWriteHdrBinary (File, StrPkgHdr);
StrPkgWriteBlkListBinary (File, BlkList);
StrPkgHdrFree (StrPkgHdr);
StrPkgBlkBufferListFree (BlkList);
}
fclose (File);
return STATUS_SUCCESS;
}
static const char *gSourceFileHeader[] = {
"//",
"// DO NOT EDIT -- auto-generated file",
"//",
"// This file is generated by the StrGather utility",
"//",
NULL
};
STATUS
StringDBDumpCStrings (
INT8 *BaseName,
INT8 *FileName
)
{
EFI_STATUS Status;
FILE *File = NULL;
LANGUAGE_LIST *Lang = NULL;
EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr = NULL;
SPkgBlkBuffer **BlkList = NULL;
UINT32 Index;
UINT32 LangNumber = 0;
if ((BaseName == NULL) || (FileName == NULL)) {
return STATUS_ERROR;
}
if (mDBData.LanguageList == NULL) {
return STATUS_SUCCESS;
}
for (LangNumber = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, LangNumber++)
;
StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR **) malloc (sizeof (EFI_HII_STRING_PACKAGE_HDR *) * LangNumber);
BlkList = (SPkgBlkBuffer **) malloc (sizeof (SPkgBlkBuffer *) * LangNumber);
for (Index = 0; Index < LangNumber; Index++) {
StrPkgHdr[Index] = NULL;
BlkList[Index] = NULL;
}
for (Index = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, Index++) {
Status = StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr[Index], &BlkList[Index]);
if (EFI_ERROR(Status)) {
return Status;
}
}
if ((File = fopen (FileName, "w")) == NULL) {
Error (NULL, 0, 0, FileName, "failed to open output C file - %s", FileName);
return STATUS_ERROR;
}
for (Index = 0; gSourceFileHeader[Index] != NULL; Index++) {
fprintf (File, "%s\n", gSourceFileHeader[Index]);
}
fprintf (File, "\nunsigned char %s[] = {\n", BaseName);
//
// Save the length of the string package array.
//
StrPkgWirteArrayLength (File, LangNumber, StrPkgHdr);
for (Index = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, Index++) {
if (StrPkgHdr[Index] != NULL) {
StrPkgWriteHdrCFile (File, StrPkgHdr[Index]);
StrPkgWriteBlkListCFile (File, BlkList[Index], (Lang->Next == NULL) ? TRUE : FALSE);
}
StrPkgHdrFree (StrPkgHdr[Index]);
StrPkgBlkBufferListFree (BlkList[Index]);
}
fprintf (File, "\n};\n");
fclose (File);
return STATUS_SUCCESS;
}