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