summaryrefslogtreecommitdiff
path: root/EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c')
-rw-r--r--EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c2674
1 files changed, 2674 insertions, 0 deletions
diff --git a/EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c b/EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c
new file mode 100644
index 0000000000..ac6fef8577
--- /dev/null
+++ b/EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c
@@ -0,0 +1,2674 @@
+/*++
+
+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;
+}