--- /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>\r
+#include <Tiano.h>\r
+#include <EfiUtilityMsgs.h>\r
+#include <EfiHii.h>\r
+#include "StrGather.h"\r
+#include "StringDb.h"\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
+void\r
+StringDBWriteStandardFileHeader (\r
+ FILE *OutFptr\r
+ );\r
+\r
+static\r
+WCHAR *\r
+AsciiToWchar (\r
+ INT8 *Str\r
+ );\r
+\r
+static\r
+CHAR8 *\r
+WcharToAscii (\r
+ WCHAR *Str\r
+ );\r
+\r
+static\r
+WCHAR *\r
+DuplicateString (\r
+ WCHAR *Str\r
+ );\r
+\r
+static\r
+WCHAR *\r
+WstrCatenate (\r
+ WCHAR *Dst,\r
+ WCHAR *Src\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
+ WCHAR *SecondaryLanguageList\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->SecondaryLanguageList);\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
+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
+ STRING_IDENTIFIER *StringIdentifier;\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
+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
+ WCHAR *SecondaryLanguageList\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 = (WCHAR *) malloc ((wcslen (LanguageName) + 1) * 2);\r
+ if (Lang->LanguageName == NULL) {\r
+ Error (NULL, 0, 0, NULL, "memory allocation error");\r
+ return STATUS_ERROR;\r
+ }\r
+ wcscpy (Lang->LanguageName, LanguageName);\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
+ FREE (Lang->LanguageName);\r
+ return STATUS_ERROR;\r
+ }\r
+ wcscpy (Lang->PrintableLanguageName, PrintableLanguageName);\r
+\r
+ if (SecondaryLanguageList != NULL) {\r
+ Lang->SecondaryLanguageList = (WCHAR *) malloc ((wcslen (SecondaryLanguageList) + 1) * sizeof (WCHAR));\r
+ if (Lang->SecondaryLanguageList == NULL) {\r
+ Error (NULL, 0, 0, NULL, "memory allocation error");\r
+ FREE (Lang->PrintableLanguageName);\r
+ FREE (Lang->LanguageName);\r
+ return STATUS_ERROR;\r
+ }\r
+ wcscpy (Lang->SecondaryLanguageList, SecondaryLanguageList);\r
+ } else {\r
+ Lang->SecondaryLanguageList = NULL;\r
+ }\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
+STATUS\r
+StringDBAddSecondaryLanguage (\r
+ WCHAR *LanguageName,\r
+ WCHAR *SecondaryLanguageList\r
+ )\r
+{\r
+ LANGUAGE_LIST *Lang;\r
+\r
+ Lang = StringDBFindLanguageList (LanguageName);\r
+ if (Lang == NULL) {\r
+ return STATUS_ERROR;\r
+ } else {\r
+ Lang->SecondaryLanguageList = WstrCatenate(Lang->SecondaryLanguageList, SecondaryLanguageList);\r
+ return STATUS_SUCCESS;\r
+ }\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, Lang->SecondaryLanguageList);\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
+ WCHAR *SecondaryLanguageList\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
+ if (StringDBWriteGenericString (DBFptr, SecondaryLanguageList) != 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 = NULL;\r
+ WCHAR *PrintableLanguageName = NULL;\r
+ WCHAR *SecondaryLanguageList = NULL;\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
+ if (StringDBReadGenericString (DBFptr, &Size, &SecondaryLanguageList) != STATUS_SUCCESS) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ //\r
+ // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);\r
+ //\r
+ Status = StringDBAddLanguage (LanguageName, PrintableLanguageName, SecondaryLanguageList);\r
+ FREE (LanguageName);\r
+ FREE (PrintableLanguageName);\r
+ FREE (SecondaryLanguageList);\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
+WstrCatenate (\r
+ WCHAR *Dst,\r
+ WCHAR *Src\r
+ )\r
+{\r
+ UINT32 Len = 0;\r
+ WCHAR *Bak = Dst;\r
+\r
+ if (Src == NULL) {\r
+ return Dst;\r
+ }\r
+\r
+ if (Dst != NULL) {\r
+ Len = wcslen (Dst);\r
+ }\r
+ Len += wcslen (Src);\r
+ Dst = (WCHAR *) malloc ((Len + 1) * 2);\r
+ if (Dst == NULL) {\r
+ return NULL;\r
+ }\r
+\r
+ Dst[0] = L'\0';\r
+ if (Bak != NULL) {\r
+ wcscpy (Dst, Bak);\r
+ FREE (Bak);\r
+ }\r
+ wcscat (Dst, Src);\r
+ return Dst;\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
+static\r
+CHAR8 *\r
+WcharToAscii (\r
+ WCHAR *Str\r
+ )\r
+{\r
+ UINT32 Len;\r
+ CHAR8 *NewStr;\r
+ CHAR8 *Ptr;\r
+\r
+ Len = wcslen (Str) + 1;\r
+ NewStr = (CHAR8 *) malloc (Len * sizeof (CHAR8));\r
+ for (Ptr = NewStr; *Str != L'\0'; Str++, Ptr++) {\r
+ *Ptr = (CHAR8) *Str;\r
+ }\r
+\r
+ *Ptr = '\0';\r
+ return NewStr;\r
+}\r
+\r
+/*****************************************************************************/\r
+CHAR8 *\r
+unicode2ascii (\r
+ WCHAR *UnicodeStr\r
+ )\r
+{\r
+ CHAR8 *RetStr = (CHAR8 *)UnicodeStr;\r
+ CHAR8 *AsciiStr = (CHAR8 *)UnicodeStr;\r
+\r
+ while (*UnicodeStr != '\0') {\r
+ *AsciiStr = (CHAR8) *(UnicodeStr++);\r
+ AsciiStr++;\r
+ }\r
+ *AsciiStr = '\0';\r
+\r
+ return RetStr;\r
+}\r
+\r
+STATUS\r
+BuildStringPkgHdr (\r
+ IN WCHAR *PrimaryLangName,\r
+ IN WCHAR *SecondaryLangList,\r
+ IN UINT32 Type,\r
+ IN UINT32 PkgBlkSize,\r
+ OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr\r
+ )\r
+{\r
+ UINT32 LangNameLen;\r
+\r
+ LangNameLen = wcslen (PrimaryLangName);\r
+ if (SecondaryLangList != NULL) {\r
+ LangNameLen += wcslen (SecondaryLangList) + 1;\r
+ }\r
+\r
+ *StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) malloc(sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);\r
+ if (*StrPkgHdr == NULL) {\r
+ return STATUS_ERROR;\r
+ }\r
+ memset (*StrPkgHdr, 0, sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);\r
+\r
+ (*StrPkgHdr)->Header.Type = Type;\r
+ (*StrPkgHdr)->Header.Length = PkgBlkSize + sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;\r
+ (*StrPkgHdr)->HdrSize = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;\r
+ (*StrPkgHdr)->StringInfoOffset = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen;\r
+ (*StrPkgHdr)->LanguageWindow[0] = L'\0';\r
+ (*StrPkgHdr)->LanguageName = (EFI_STRING_ID)1;\r
+\r
+ strcpy ((*StrPkgHdr)->Language, unicode2ascii(PrimaryLangName));\r
+ if (SecondaryLangList != NULL) {\r
+ strcat ((*StrPkgHdr)->Language, ";");\r
+ strcat ((*StrPkgHdr)->Language, unicode2ascii(SecondaryLangList));\r
+ }\r
+\r
+#ifdef DEBUG_STRGATHER\r
+ printf ("STR HDR\t %s\n", (*StrPkgHdr)->Language);\r
+#endif\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+BuildStringPkgUCS2Blk (\r
+ IN EFI_STRING_ID StringId,\r
+ IN WCHAR *LangName,\r
+ IN WCHAR *StrName,\r
+ OUT EFI_HII_SIBT_STRING_UCS2_BLOCK **StrBlk,\r
+ OUT UINT32 *BlkSize\r
+ )\r
+{\r
+ UINT32 StrLen = 0;\r
+ STRING_LIST *CurrString = NULL;\r
+\r
+ if ((LangName == NULL) || (StrName == NULL) || (StrBlk == NULL)) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ *StrBlk = NULL;\r
+ *BlkSize = 0;\r
+\r
+ CurrString = StringDBFindString (LangName, StrName, NULL, NULL, NULL);\r
+ if (CurrString == NULL) {\r
+ return STATUS_WARNING;\r
+ }\r
+\r
+ StrLen = wcslen (CurrString->Str);\r
+ *BlkSize = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) + StrLen * 2;\r
+ *StrBlk = (EFI_HII_SIBT_STRING_UCS2_BLOCK *) malloc (*BlkSize);\r
+ if (*StrBlk == NULL) {\r
+ *StrBlk = NULL;\r
+ *BlkSize = 0;\r
+ return STATUS_ERROR;\r
+ }\r
+ (*StrBlk)->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;\r
+ wcscpy((*StrBlk)->StringText, CurrString->Str);\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+BuildStringPkgSKIP2Blk (\r
+ IN EFI_STRING_ID SkipIdCount,\r
+ OUT EFI_HII_SIBT_SKIP2_BLOCK **StrBlk\r
+ )\r
+{\r
+ if (StrBlk == NULL) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ *StrBlk = NULL;\r
+\r
+ *StrBlk = (EFI_HII_SIBT_SKIP2_BLOCK *) malloc (sizeof (EFI_HII_SIBT_SKIP2_BLOCK));\r
+ if (*StrBlk == NULL) {\r
+ *StrBlk = NULL;\r
+ return STATUS_ERROR;\r
+ }\r
+ (*StrBlk)->Header.BlockType = EFI_HII_SIBT_SKIP2;\r
+ (*StrBlk)->SkipCount = SkipIdCount;\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+BuildStringPkgEndBlk (\r
+ OUT EFI_HII_SIBT_END_BLOCK **End\r
+ )\r
+{\r
+ *End = (EFI_HII_SIBT_END_BLOCK *) malloc (sizeof (EFI_HII_SIBT_END_BLOCK));\r
+ if (*End == NULL) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ (*End)->Header.BlockType = EFI_HII_SIBT_END;\r
+ return STATUS_SUCCESS;\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
+StrPkgBlkBufferListAddTail (\r
+ IN EFI_STRING_ID StringId,\r
+ IN WCHAR *StrName,\r
+ IN SPkgBlkBuffer **PkgBufferListHead,\r
+ IN SPkgBlkBuffer **PkgBufferListTail,\r
+ IN VOID *Buffer,\r
+ IN UINT32 Size \r
+ )\r
+{\r
+ SPkgBlkBuffer *pNew = NULL;\r
+#ifdef DEBUG_STRGATHER\r
+ EFI_HII_STRING_BLOCK *SBlk = (EFI_HII_STRING_BLOCK *)Buffer;\r
+#endif\r
+\r
+ if ((PkgBufferListHead == NULL) || (PkgBufferListTail == NULL)) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ pNew = (SPkgBlkBuffer *) malloc (sizeof (SPkgBlkBuffer));\r
+ if (pNew == NULL) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ pNew->mBlkBuffer = Buffer;\r
+ pNew->mBlkSize = Size;\r
+ if ((*PkgBufferListTail) == NULL) {\r
+ (*PkgBufferListHead) = (*PkgBufferListTail) = pNew;\r
+ } else {\r
+ (*PkgBufferListTail)->mNext = pNew;\r
+ (*PkgBufferListTail) = pNew;\r
+ pNew->mNext = NULL;\r
+ }\r
+\r
+#ifdef DEBUG_STRGATHER\r
+ switch (SBlk->BlockType) {\r
+ case EFI_HII_SIBT_STRING_UCS2 :\r
+ printf ("\tID: [%x] TYPE: [UCS2]\t NAME: %S \t STR: %S\n", StringId, StrName, ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)SBlk)->StringText);\r
+ break;\r
+ case EFI_HII_SIBT_SKIP2 :\r
+ printf ("\tID: [NULL] TYPE: [SKIP2] SKIPCOUNT: [%x]\n", ((EFI_HII_SIBT_SKIP2_BLOCK *)SBlk)->SkipCount);\r
+ break;\r
+ case EFI_HII_SIBT_END :\r
+ printf ("\tID: [%x] TYPE: [END]\n", StringId);\r
+ break;\r
+ default :\r
+ printf ("!!!!UNKNOWN STRING TYPE!!!\n");\r
+ }\r
+#endif\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+VOID\r
+StrPkgHdrFree (\r
+ IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr\r
+ )\r
+{\r
+ if (StrPkgHdr != NULL) {\r
+ free (StrPkgHdr);\r
+ }\r
+}\r
+\r
+VOID\r
+StrPkgBlkBufferListFree (\r
+ IN SPkgBlkBuffer *PkgBlkList\r
+ )\r
+{\r
+ SPkgBlkBuffer *Buffer;\r
+\r
+ while (PkgBlkList != NULL) {\r
+ Buffer = PkgBlkList;\r
+ PkgBlkList = PkgBlkList->mNext;\r
+\r
+ if (Buffer->mBlkBuffer != NULL) {\r
+ free (Buffer->mBlkBuffer);\r
+ }\r
+ free (Buffer);\r
+ }\r
+}\r
+\r
+VOID\r
+WriteBlockLine (\r
+ IN FILE *pFile,\r
+ IN UINT32 LineBytes,\r
+ IN INT8 *LineHeader,\r
+ IN INT8 *BlkBuf,\r
+ IN UINT32 BlkSize\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ if ((pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {\r
+ return;\r
+ }\r
+\r
+ for (Index = 0; Index < BlkSize; Index++) {\r
+ if ((Index % LineBytes) == 0) {\r
+ fprintf (pFile, "\n%s", LineHeader);\r
+ }\r
+ fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);\r
+ }\r
+}\r
+\r
+VOID\r
+WriteBlockEnd (\r
+ IN FILE *pFile,\r
+ IN UINT32 LineBytes,\r
+ IN INT8 *LineHeader,\r
+ IN INT8 *BlkBuf,\r
+ IN UINT32 BlkSize\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ if ((BlkSize == 0) || (pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {\r
+ return;\r
+ }\r
+\r
+ for (Index = 0; Index < BlkSize - 1; Index++) {\r
+ if ((Index % LineBytes) == 0) {\r
+ fprintf (pFile, "\n%s", LineHeader);\r
+ }\r
+ fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]);\r
+ }\r
+\r
+ if ((Index % LineBytes) == 0) {\r
+ fprintf (pFile, "\n%s", LineHeader);\r
+ }\r
+ fprintf (pFile, "0x%02X\n", (UINT8)BlkBuf[Index]);\r
+}\r
+\r
+#define BYTES_PRE_LINE 0x10\r
+\r
+VOID\r
+StrPkgWriteHdrCFile (\r
+ IN FILE *File,\r
+ IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr\r
+ )\r
+{\r
+ if (StrPkgHdr != NULL) {\r
+ fprintf (File, "\n // PACKAGE HEADER\n");\r
+ WriteBlockLine(File, BYTES_PRE_LINE, " ", (INT8 *)StrPkgHdr, StrPkgHdr->HdrSize);\r
+ }\r
+}\r
+\r
+VOID\r
+StrPkgWirteArrayLength (\r
+ IN FILE *File,\r
+ IN UINT32 PkgNumber,\r
+ IN EFI_HII_STRING_PACKAGE_HDR **PkgHdr\r
+ )\r
+{\r
+ UINT32 Index;\r
+ UINT32 ArrayLen;\r
+\r
+ ArrayLen = sizeof (UINT32);\r
+ for (Index = 0; Index < PkgNumber; Index++) {\r
+ if (PkgHdr[Index] != NULL) {\r
+ ArrayLen += PkgHdr[Index]->Header.Length;\r
+ }\r
+ }\r
+\r
+ fprintf (File, "\n // STRING ARRAY LENGTH\n");\r
+ WriteBlockLine(File, BYTES_PRE_LINE, " ", (UINT8 *)&ArrayLen, sizeof (UINT32));\r
+}\r
+\r
+VOID\r
+StrPkgWriteBlkListCFile (\r
+ IN FILE *File,\r
+ IN SPkgBlkBuffer *BlkList,\r
+ IN BOOLEAN WriteEnd\r
+ )\r
+{\r
+ SPkgBlkBuffer *Buffer;\r
+\r
+ fprintf (File, "\n\n // PACKAGE DATA\n");\r
+\r
+ while (BlkList != NULL) {\r
+ Buffer = BlkList;\r
+ BlkList = BlkList->mNext;\r
+\r
+ if ((Buffer->mNext == NULL) && (WriteEnd == TRUE)) {\r
+ if (Buffer->mBlkBuffer != NULL) {\r
+ WriteBlockEnd (File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize);\r
+ }\r
+ } else {\r
+ if (Buffer->mBlkBuffer != NULL) {\r
+ WriteBlockLine(File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize);\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+VOID\r
+StrPkgWriteHdrBinary (\r
+ IN FILE *File,\r
+ IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr\r
+ )\r
+{\r
+ fwrite (StrPkgHdr, StrPkgHdr->HdrSize, 1, File);\r
+}\r
+\r
+VOID\r
+StrPkgWriteBlkListBinary (\r
+ IN FILE *File,\r
+ IN SPkgBlkBuffer *BlkList\r
+ )\r
+{\r
+ SPkgBlkBuffer *Buffer;\r
+\r
+ while (BlkList != NULL) {\r
+ Buffer = BlkList;\r
+ BlkList = BlkList->mNext;\r
+\r
+ if (Buffer->mBlkBuffer != NULL) {\r
+ fwrite (Buffer->mBlkBuffer, Buffer->mBlkSize, 1, File);\r
+ }\r
+ }\r
+}\r
+\r
+STATUS\r
+StringDBGenStrPkgHdrAndBlkList (\r
+ IN LANGUAGE_LIST *Lang,\r
+ OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr,\r
+ OUT SPkgBlkBuffer **BlkList\r
+ )\r
+{\r
+ STATUS Status;\r
+ UINT32 StringIndex;\r
+ EFI_STRING_ID StringIdCurrent;\r
+ EFI_STRING_ID SkipIdCount;\r
+ UINT32 BlkSize = 0;\r
+ EFI_HII_SIBT_STRING_UCS2_BLOCK *StrUCS2Blk = NULL;\r
+ EFI_HII_SIBT_SKIP2_BLOCK *StrSKIP2Blk = NULL;\r
+ STRING_IDENTIFIER *StringIdentifier = NULL;\r
+ EFI_HII_SIBT_END_BLOCK *EndBlk = NULL;\r
+ UINT32 PkgBlkSize = 0;\r
+ SPkgBlkBuffer *PkgBufferListHead = NULL;\r
+ SPkgBlkBuffer *PkgBufferListTail = NULL;\r
+\r
+ if ((Lang == NULL) || (StrPkgHdr == NULL) || (BlkList == NULL)) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ //\r
+ // Assign index values to the string identifiers\r
+ //\r
+ StringDBAssignStringIndexes ();\r
+ StringIdCurrent = EFI_STRING_ID_BEGIN;\r
+ SkipIdCount = 0;\r
+\r
+ for (StringIndex = STRING_ID_PRINTABLE_LANGUAGE_NAME; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) {\r
+ if ((StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex)) == NULL) {\r
+ Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex);\r
+ goto ExportPackOut;\r
+ }\r
+\r
+ if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {\r
+ Status = BuildStringPkgUCS2Blk (StringIdCurrent, Lang->LanguageName, StringIdentifier->StringName, &StrUCS2Blk, &BlkSize);\r
+ switch (Status) {\r
+ case STATUS_ERROR: \r
+ goto ExportPackOut; \r
+ break;\r
+ case STATUS_WARNING :\r
+ SkipIdCount++;\r
+ break;\r
+ case STATUS_SUCCESS :\r
+ if (SkipIdCount == 0) {\r
+ if (StrPkgBlkBufferListAddTail (\r
+ StringIdCurrent, \r
+ StringIdentifier->StringName, \r
+ &PkgBufferListHead, \r
+ &PkgBufferListTail, \r
+ StrUCS2Blk, \r
+ BlkSize\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+ PkgBlkSize += BlkSize;\r
+ } else {\r
+ if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ } else {\r
+ if (StrPkgBlkBufferListAddTail (\r
+ StringIdCurrent, \r
+ NULL, \r
+ &PkgBufferListHead, \r
+ &PkgBufferListTail, \r
+ StrSKIP2Blk, \r
+ sizeof (EFI_HII_SIBT_SKIP2_BLOCK)\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+ PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);\r
+ SkipIdCount = 0;\r
+ }\r
+\r
+ if (StrPkgBlkBufferListAddTail (\r
+ StringIdCurrent, \r
+ StringIdentifier->StringName, \r
+ &PkgBufferListHead, \r
+ &PkgBufferListTail, \r
+ StrUCS2Blk, \r
+ BlkSize\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+ PkgBlkSize += BlkSize;\r
+ }\r
+ }\r
+ }\r
+\r
+ StringIdCurrent++;\r
+ }\r
+\r
+ if (SkipIdCount != 0) {\r
+ if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ } else {\r
+ if (StrPkgBlkBufferListAddTail (\r
+ StringIdCurrent, \r
+ NULL, \r
+ &PkgBufferListHead, \r
+ &PkgBufferListTail, \r
+ StrSKIP2Blk, \r
+ sizeof (EFI_HII_SIBT_SKIP2_BLOCK)\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+ PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);\r
+ SkipIdCount = 0;\r
+ }\r
+ }\r
+\r
+ if (BuildStringPkgEndBlk (&EndBlk) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ } else if (StrPkgBlkBufferListAddTail (\r
+ StringIdCurrent, \r
+ NULL, \r
+ &PkgBufferListHead, \r
+ &PkgBufferListTail, \r
+ EndBlk, \r
+ sizeof (EFI_HII_SIBT_END_BLOCK)\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+ StringIdCurrent++;\r
+ PkgBlkSize += sizeof (EFI_HII_SIBT_END_BLOCK);\r
+\r
+ if (BuildStringPkgHdr(\r
+ Lang->LanguageName, \r
+ Lang->SecondaryLanguageList,\r
+ EFI_HII_PACKAGE_STRINGS, \r
+ PkgBlkSize, \r
+ StrPkgHdr\r
+ ) != STATUS_SUCCESS) {\r
+ goto ExportPackOut;\r
+ }\r
+\r
+ *BlkList = PkgBufferListHead;\r
+\r
+ return STATUS_SUCCESS;\r
+\r
+ExportPackOut:\r
+ StrPkgBlkBufferListFree(PkgBufferListHead);\r
+ *BlkList = NULL;\r
+ *StrPkgHdr = NULL;\r
+ return STATUS_ERROR;\r
+}\r
+\r
+STATUS\r
+StringDBCreateHiiExportPack (\r
+ INT8 *FileName\r
+ )\r
+{\r
+ FILE *File = NULL;\r
+ LANGUAGE_LIST *Lang = NULL;\r
+ EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr = NULL;\r
+ SPkgBlkBuffer *BlkList = NULL;\r
+\r
+ if (FileName == NULL) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if ((File = fopen (FileName, "wb")) == NULL) {\r
+ Error (NULL, 0, 0, FileName, "failed to open output HII export file");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {\r
+ if (StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr, &BlkList) != STATUS_SUCCESS) {\r
+ fclose (File);\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ StrPkgWriteHdrBinary (File, StrPkgHdr);\r
+ StrPkgWriteBlkListBinary (File, BlkList);\r
+\r
+ StrPkgHdrFree (StrPkgHdr);\r
+ StrPkgBlkBufferListFree (BlkList);\r
+ }\r
+\r
+ fclose (File);\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static const char *gSourceFileHeader[] = {\r
+ "//",\r
+ "// DO NOT EDIT -- auto-generated file",\r
+ "//",\r
+ "// This file is generated by the StrGather utility",\r
+ "//",\r
+ NULL\r
+};\r
+\r
+STATUS\r
+StringDBDumpCStrings (\r
+ INT8 *BaseName,\r
+ INT8 *FileName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ FILE *File = NULL;\r
+ LANGUAGE_LIST *Lang = NULL;\r
+ EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr = NULL;\r
+ SPkgBlkBuffer **BlkList = NULL;\r
+ UINT32 Index;\r
+ UINT32 LangNumber = 0;\r
+\r
+ if ((BaseName == NULL) || (FileName == NULL)) {\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (mDBData.LanguageList == NULL) {\r
+ return STATUS_SUCCESS;\r
+ }\r
+\r
+ for (LangNumber = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, LangNumber++)\r
+ ;\r
+\r
+ StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR **) malloc (sizeof (EFI_HII_STRING_PACKAGE_HDR *) * LangNumber);\r
+ BlkList = (SPkgBlkBuffer **) malloc (sizeof (SPkgBlkBuffer *) * LangNumber);\r
+ for (Index = 0; Index < LangNumber; Index++) {\r
+ StrPkgHdr[Index] = NULL;\r
+ BlkList[Index] = NULL;\r
+ }\r
+\r
+ for (Index = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, Index++) {\r
+ Status = StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr[Index], &BlkList[Index]);\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+\r
+ if ((File = fopen (FileName, "w")) == NULL) {\r
+ Error (NULL, 0, 0, FileName, "failed to open output C file - %s", FileName);\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ for (Index = 0; gSourceFileHeader[Index] != NULL; Index++) {\r
+ fprintf (File, "%s\n", gSourceFileHeader[Index]);\r
+ }\r
+\r
+ fprintf (File, "\nunsigned char %s[] = {\n", BaseName);\r
+\r
+ //\r
+ // Save the length of the string package array.\r
+ //\r
+ StrPkgWirteArrayLength (File, LangNumber, StrPkgHdr);\r
+\r
+ for (Index = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, Index++) {\r
+ if (StrPkgHdr[Index] != NULL) {\r
+ StrPkgWriteHdrCFile (File, StrPkgHdr[Index]);\r
+ StrPkgWriteBlkListCFile (File, BlkList[Index], (Lang->Next == NULL) ? TRUE : FALSE);\r
+ }\r
+\r
+ StrPkgHdrFree (StrPkgHdr[Index]);\r
+ StrPkgBlkBufferListFree (BlkList[Index]);\r
+ }\r
+\r
+ fprintf (File, "\n};\n");\r
+\r
+ fclose (File);\r
+ return STATUS_SUCCESS;\r
+}\r