| /*++ | |
| Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| Module Name: | |
| StringDB.c | |
| Abstract: | |
| String database implementation | |
| --*/ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include <Tiano.h> | |
| #include <EfiUtilityMsgs.h> | |
| #include <EfiHii.h> | |
| #include "StrGather.h" | |
| #include "StringDb.h" | |
| static STRING_DB_DATA mDBData; | |
| static const char *mSourceFileHeader[] = { | |
| "//", | |
| "// DO NOT EDIT -- auto-generated file", | |
| "//", | |
| "// This file is generated by the string gather utility", | |
| "//", | |
| NULL | |
| }; | |
| static | |
| STRING_LIST * | |
| StringDBFindString ( | |
| WCHAR *LanguageName, | |
| WCHAR *StringName, | |
| WCHAR *Scope, | |
| WCHAR_STRING_LIST *LanguagesOfInterest, | |
| WCHAR_MATCHING_STRING_LIST *IndirectionList | |
| ); | |
| static | |
| STRING_IDENTIFIER * | |
| StringDBFindStringIdentifierByName ( | |
| WCHAR *Name | |
| ); | |
| static | |
| STRING_IDENTIFIER * | |
| StringDBFindStringIdentifierByIndex ( | |
| UINT32 Index | |
| ); | |
| static | |
| void | |
| StringDBWriteStandardFileHeader ( | |
| FILE *OutFptr | |
| ); | |
| static | |
| WCHAR * | |
| AsciiToWchar ( | |
| INT8 *Str | |
| ); | |
| static | |
| CHAR8 * | |
| WcharToAscii ( | |
| WCHAR *Str | |
| ); | |
| static | |
| WCHAR * | |
| DuplicateString ( | |
| WCHAR *Str | |
| ); | |
| static | |
| WCHAR * | |
| WstrCatenate ( | |
| WCHAR *Dst, | |
| WCHAR *Src | |
| ); | |
| static | |
| STATUS | |
| StringDBWriteStringIdentifier ( | |
| FILE *DBFptr, | |
| UINT16 StringId, | |
| UINT16 Flags, | |
| WCHAR *IdentifierName | |
| ); | |
| static | |
| STATUS | |
| StringDBReadStringIdentifier ( | |
| FILE *DBFptr | |
| ); | |
| static | |
| STATUS | |
| StringDBWriteLanguageDefinition ( | |
| FILE *DBFptr, | |
| WCHAR *LanguageName, | |
| WCHAR *PrintableLanguageName, | |
| WCHAR *SecondaryLanguageList | |
| ); | |
| static | |
| STATUS | |
| StringDBReadLanguageDefinition ( | |
| FILE *DBFptr | |
| ); | |
| static | |
| STATUS | |
| StringDBWriteString ( | |
| FILE *DBFptr, | |
| UINT16 Flags, | |
| WCHAR *Language, | |
| WCHAR *StringName, | |
| WCHAR *Scope, | |
| WCHAR *Str | |
| ); | |
| static | |
| STATUS | |
| StringDBReadString ( | |
| FILE *DBFptr | |
| ); | |
| static | |
| STATUS | |
| StringDBReadGenericString ( | |
| FILE *DBFptr, | |
| UINT16 *Size, | |
| WCHAR **Str | |
| ); | |
| static | |
| STATUS | |
| StringDBWriteGenericString ( | |
| FILE *DBFptr, | |
| WCHAR *Str | |
| ); | |
| static | |
| void | |
| StringDBAssignStringIndexes ( | |
| VOID | |
| ); | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Constructor function for the string database handler. | |
| Arguments: | |
| None. | |
| Returns: | |
| None. | |
| --*/ | |
| void | |
| StringDBConstructor ( | |
| VOID | |
| ) | |
| { | |
| memset ((char *) &mDBData, 0, sizeof (STRING_DB_DATA)); | |
| mDBData.CurrentScope = DuplicateString (L"NULL"); | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Destructor function for the string database handler. | |
| Arguments: | |
| None. | |
| Returns: | |
| None. | |
| --*/ | |
| void | |
| StringDBDestructor ( | |
| VOID | |
| ) | |
| { | |
| LANGUAGE_LIST *NextLang; | |
| STRING_LIST *NextStr; | |
| STRING_IDENTIFIER *NextIdentifier; | |
| // | |
| // Close the database file if it's open | |
| // | |
| if (mDBData.StringDBFptr != NULL) { | |
| fclose (mDBData.StringDBFptr); | |
| mDBData.StringDBFptr = NULL; | |
| } | |
| // | |
| // If we've allocated any strings/languages, free them up | |
| // | |
| while (mDBData.LanguageList != NULL) { | |
| NextLang = mDBData.LanguageList->Next; | |
| // | |
| // Free up all strings for this language | |
| // | |
| while (mDBData.LanguageList->String != NULL) { | |
| NextStr = mDBData.LanguageList->String->Next; | |
| FREE (mDBData.LanguageList->String->Str); | |
| FREE (mDBData.LanguageList->String); | |
| mDBData.LanguageList->String = NextStr; | |
| } | |
| FREE (mDBData.LanguageList->SecondaryLanguageList); | |
| FREE (mDBData.LanguageList->PrintableLanguageName); | |
| FREE (mDBData.LanguageList); | |
| mDBData.LanguageList = NextLang; | |
| } | |
| // | |
| // Free up string identifiers | |
| // | |
| while (mDBData.StringIdentifier != NULL) { | |
| NextIdentifier = mDBData.StringIdentifier->Next; | |
| FREE (mDBData.StringIdentifier->StringName); | |
| FREE (mDBData.StringIdentifier); | |
| mDBData.StringIdentifier = NextIdentifier; | |
| } | |
| // | |
| // Free the filename | |
| // | |
| if (mDBData.StringDBFileName != NULL) { | |
| FREE (mDBData.StringDBFileName); | |
| mDBData.StringDBFileName = NULL; | |
| } | |
| // | |
| // We save a copy of the scope, so free it up if we | |
| // have one. | |
| // | |
| if (mDBData.CurrentScope != NULL) { | |
| FREE (mDBData.CurrentScope); | |
| mDBData.CurrentScope = NULL; | |
| } | |
| } | |
| /*****************************************************************************/ | |
| STATUS | |
| StringDBDumpStringDefines ( | |
| INT8 *FileName, | |
| INT8 *BaseName | |
| ) | |
| { | |
| FILE *Fptr; | |
| STRING_IDENTIFIER *Identifier; | |
| INT8 CopyBaseName[100]; | |
| UINT32 Index; | |
| const INT8 *StrDefHeader[] = { | |
| "#ifndef _%s_STRINGS_DEFINE_H_\n", | |
| "#define _%s_STRINGS_DEFINE_H_\n\n", | |
| NULL | |
| }; | |
| if ((Fptr = fopen (FileName, "w")) == NULL) { | |
| Error (NULL, 0, 0, FileName, "failed to open output string defines file"); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Get the base source filename and convert to uppercase. | |
| // | |
| if (sizeof (CopyBaseName) <= strlen (BaseName) + 1) { | |
| Error (NULL, 0, 0, "application error", "StringDBDumpStringDefines() string length insufficient"); | |
| return STATUS_ERROR; | |
| } | |
| strcpy (CopyBaseName, BaseName); | |
| for (Index = 0; CopyBaseName[Index] != 0; Index++) { | |
| if (islower (CopyBaseName[Index])) { | |
| CopyBaseName[Index] = (INT8) toupper (CopyBaseName[Index]); | |
| } | |
| } | |
| // | |
| // Assign index values to the string identifiers | |
| // | |
| StringDBAssignStringIndexes (); | |
| // | |
| // Write the standard header to the output file, and then the | |
| // protective #ifndef. | |
| // | |
| StringDBWriteStandardFileHeader (Fptr); | |
| for (Index = 0; StrDefHeader[Index] != NULL; Index++) { | |
| fprintf (Fptr, StrDefHeader[Index], CopyBaseName); | |
| } | |
| // | |
| // Print all the #defines for the string identifiers. Print identifiers | |
| // whose names start with '$' as comments. Add comments for string | |
| // identifiers not used as well. | |
| // | |
| Identifier = mDBData.StringIdentifier; | |
| while (Identifier != NULL) { | |
| if (Identifier->StringName[0] == L'$') { | |
| fprintf (Fptr, "// "); | |
| } | |
| if (Identifier->Flags & STRING_FLAGS_REFERENCED) { | |
| fprintf (Fptr, "#define %-40S 0x%04X\n", Identifier->StringName, Identifier->Index); | |
| } else { | |
| fprintf (Fptr, "//#define %-40S 0x%04X // not referenced\n", Identifier->StringName, Identifier->Index); | |
| } | |
| Identifier = Identifier->Next; | |
| } | |
| fprintf (Fptr, "\n#endif\n"); | |
| fclose (Fptr); | |
| return STATUS_SUCCESS; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Add a string identifier to the database. | |
| Arguments: | |
| StringName - name of the string identifier. For example "STR_MY_STRING" | |
| NewId - if an ID has been assigned | |
| Flags - characteristics for the identifier | |
| Returns: | |
| STATUS | |
| --*/ | |
| STATUS | |
| StringDBAddStringIdentifier ( | |
| WCHAR *StringName, | |
| UINT16 *NewId, | |
| UINT16 Flags | |
| ) | |
| { | |
| STRING_IDENTIFIER *StringIdentifier; | |
| STATUS Status; | |
| // | |
| // If it was already used for some other language, then we don't | |
| // need to add it. But set it to the current string identifier. | |
| // The referenced bit is sticky. | |
| // | |
| Status = STATUS_SUCCESS; | |
| StringIdentifier = StringDBFindStringIdentifierByName (StringName); | |
| if (StringIdentifier != NULL) { | |
| if (Flags & STRING_FLAGS_REFERENCED) { | |
| StringIdentifier->Flags |= STRING_FLAGS_REFERENCED; | |
| } | |
| mDBData.CurrentStringIdentifier = StringIdentifier; | |
| *NewId = (UINT16) StringIdentifier->Index; | |
| return Status; | |
| } | |
| StringIdentifier = (STRING_IDENTIFIER *) MALLOC (sizeof (STRING_IDENTIFIER)); | |
| if (StringIdentifier == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| memset ((char *) StringIdentifier, 0, sizeof (STRING_IDENTIFIER)); | |
| StringIdentifier->StringName = (WCHAR *) malloc ((wcslen (StringName) + 1) * sizeof (WCHAR)); | |
| if (StringIdentifier->StringName == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| wcscpy (StringIdentifier->StringName, StringName); | |
| if (*NewId != STRING_ID_INVALID) { | |
| StringIdentifier->Index = *NewId; | |
| StringIdentifier->Flags |= STRING_FLAGS_INDEX_ASSIGNED; | |
| if (mDBData.NumStringIdentifiers <= StringIdentifier->Index) { | |
| mDBData.NumStringIdentifiers = StringIdentifier->Index + 1; | |
| } | |
| } else { | |
| StringIdentifier->Index = mDBData.NumStringIdentifiers++; | |
| } | |
| StringIdentifier->Flags |= Flags; | |
| // | |
| // Add it to our list of string identifiers | |
| // | |
| if (mDBData.StringIdentifier == NULL) { | |
| mDBData.StringIdentifier = StringIdentifier; | |
| } else { | |
| mDBData.LastStringIdentifier->Next = StringIdentifier; | |
| } | |
| mDBData.LastStringIdentifier = StringIdentifier; | |
| mDBData.CurrentStringIdentifier = StringIdentifier; | |
| *NewId = (UINT16) StringIdentifier->Index; | |
| return Status; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Add a new string to the database. | |
| Arguments: | |
| LanguageName - "eng" or "spa" language name | |
| StringName - "STR_MY_TEXT" string name | |
| Scope - from the #scope statements in the string file | |
| Format - if we should format the string | |
| Flags - characteristic flags for the string | |
| Returns: | |
| STATUS | |
| Notes: | |
| Several of the fields can be "inherited" from the previous calls to | |
| our database functions. For example, if scope is NULL here, then | |
| we'll use the previous setting. | |
| --*/ | |
| STATUS | |
| StringDBAddString ( | |
| WCHAR *LanguageName, | |
| WCHAR *StringName, | |
| WCHAR *Scope, | |
| WCHAR *String, | |
| BOOLEAN Format, | |
| UINT16 Flags | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| UINT32 Size; | |
| STRING_LIST *Str; | |
| UINT16 StringIndex; | |
| STRING_IDENTIFIER *StringIdentifier; | |
| // | |
| // If they specified a language, make sure they've defined it already | |
| // via a #langdef statement. Otherwise use the current default language. | |
| // | |
| if (LanguageName != NULL) { | |
| Lang = StringDBFindLanguageList (LanguageName); | |
| if (Lang == NULL) { | |
| ParserError (0, "language not defined", "%S", LanguageName); | |
| return STATUS_ERROR; | |
| } else { | |
| StringDBSetCurrentLanguage (LanguageName); | |
| } | |
| } else { | |
| Lang = mDBData.CurrentLanguage; | |
| if (Lang == NULL) { | |
| // | |
| // Have to call SetLanguage() first | |
| // | |
| ParserError (0, "no language defined", "%S", StringName); | |
| return STATUS_ERROR; | |
| } | |
| } | |
| // | |
| // If they didn't define a string identifier, use the last string identifier | |
| // added. | |
| // | |
| if (StringName == NULL) { | |
| StringName = mDBData.CurrentStringIdentifier->StringName; | |
| if (StringName == NULL) { | |
| ParserError (0, "no string identifier previously specified", NULL); | |
| return STATUS_ERROR; | |
| } | |
| } | |
| // | |
| // If scope was not specified, use the default setting | |
| // | |
| if (Scope != NULL) { | |
| Scope = DuplicateString (Scope); | |
| } else { | |
| Scope = DuplicateString (mDBData.CurrentScope); | |
| } | |
| // | |
| // printf ("Adding string: %S.%S.%S\n", Lang->LanguageName, StringName, Scope); | |
| // | |
| // Check for duplicates for this Language.StringName.Scope. Allow multiple | |
| // definitions of the language name and printable language name, since the | |
| // user does not specifically define them. | |
| // | |
| if (StringDBFindString (Lang->LanguageName, StringName, Scope, NULL, NULL) != NULL) { | |
| if ((wcscmp (StringName, LANGUAGE_NAME_STRING_NAME) == 0) && | |
| (wcscmp (StringName, PRINTABLE_LANGUAGE_NAME_STRING_NAME) == 0) | |
| ) { | |
| ParserError ( | |
| 0, | |
| "string multiply defined", | |
| "Language.Name.Scope = %S.%S.%S", | |
| Lang->LanguageName, | |
| StringName, | |
| Scope | |
| ); | |
| return STATUS_ERROR; | |
| } | |
| } | |
| StringIndex = STRING_ID_INVALID; | |
| if (StringDBAddStringIdentifier (StringName, &StringIndex, Flags) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| StringIdentifier = StringDBFindStringIdentifierByName (StringName); | |
| // | |
| // Add this string to the end of the strings for this language. | |
| // | |
| Str = (STRING_LIST *) malloc (sizeof (STRING_LIST)); | |
| if (Str == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| memset ((char *) Str, 0, sizeof (STRING_LIST)); | |
| Size = (wcslen (String) + 1) * sizeof (WCHAR); | |
| Str->Flags = Flags; | |
| Str->Scope = Scope; | |
| Str->StringName = StringIdentifier->StringName; | |
| Str->LanguageName = DuplicateString (LanguageName); | |
| Str->Str = (WCHAR *) MALLOC (Size); | |
| if (Str->Str == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // If not formatting, just copy the string. | |
| // | |
| wcscpy (Str->Str, String); | |
| if (Format) { | |
| StringDBFormatString (Str->Str); | |
| } | |
| // | |
| // Size may change after formatting. We set the size to | |
| // the actual size of the string, including the null for | |
| // easier processing later. | |
| // | |
| Str->Size = (wcslen (Str->Str) + 1) * sizeof (WCHAR); | |
| if (Lang->String == NULL) { | |
| Lang->String = Str; | |
| } else { | |
| Lang->LastString->Next = Str; | |
| } | |
| Lang->LastString = Str; | |
| return STATUS_SUCCESS; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Given a language name, see if a language list for it has been defined | |
| Arguments: | |
| LanguageName - like "eng" | |
| Returns: | |
| A pointer to the language list | |
| --*/ | |
| LANGUAGE_LIST * | |
| StringDBFindLanguageList ( | |
| WCHAR *LanguageName | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| Lang = mDBData.LanguageList; | |
| while (Lang != NULL) { | |
| if (wcscmp (LanguageName, Lang->LanguageName) == 0) { | |
| break; | |
| } | |
| Lang = Lang->Next; | |
| } | |
| return Lang; | |
| } | |
| /*****************************************************************************/ | |
| STATUS | |
| StringDBSetCurrentLanguage ( | |
| WCHAR *LanguageName | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| Lang = StringDBFindLanguageList (LanguageName); | |
| if (Lang == NULL) { | |
| ParserError (0, "language not previously defined", "%S", LanguageName); | |
| return STATUS_ERROR; | |
| } | |
| mDBData.CurrentLanguage = Lang; | |
| return STATUS_SUCCESS; | |
| } | |
| /*****************************************************************************/ | |
| STATUS | |
| StringDBAddLanguage ( | |
| WCHAR *LanguageName, | |
| WCHAR *PrintableLanguageName, | |
| WCHAR *SecondaryLanguageList | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| // | |
| // Check for redefinitions | |
| // | |
| Lang = StringDBFindLanguageList (LanguageName); | |
| if (Lang != NULL) { | |
| // | |
| // Better be the same printable name | |
| // | |
| if (wcscmp (PrintableLanguageName, Lang->PrintableLanguageName) != 0) { | |
| ParserError ( | |
| 0, | |
| "language redefinition", | |
| "%S:%S != %S:%S", | |
| Lang->LanguageName, | |
| Lang->PrintableLanguageName, | |
| LanguageName, | |
| PrintableLanguageName | |
| ); | |
| return STATUS_ERROR; | |
| // | |
| // } else { | |
| // ParserWarning (0, "benign language redefinition", "%S", PrintableLanguageName); | |
| // return STATUS_WARNING; | |
| // | |
| } | |
| } else { | |
| // | |
| // Allocate memory to keep track of this new language | |
| // | |
| Lang = (LANGUAGE_LIST *) malloc (sizeof (LANGUAGE_LIST)); | |
| if (Lang == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| memset ((char *) Lang, 0, sizeof (LANGUAGE_LIST)); | |
| // | |
| // Save the language name, then allocate memory to save the | |
| // printable language name | |
| // | |
| Lang->LanguageName = (WCHAR *) malloc ((wcslen (LanguageName) + 1) * 2); | |
| if (Lang->LanguageName == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| return STATUS_ERROR; | |
| } | |
| wcscpy (Lang->LanguageName, LanguageName); | |
| Lang->PrintableLanguageName = (WCHAR *) malloc ((wcslen (PrintableLanguageName) + 1) * sizeof (WCHAR)); | |
| if (Lang->PrintableLanguageName == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| FREE (Lang->LanguageName); | |
| return STATUS_ERROR; | |
| } | |
| wcscpy (Lang->PrintableLanguageName, PrintableLanguageName); | |
| if (SecondaryLanguageList != NULL) { | |
| Lang->SecondaryLanguageList = (WCHAR *) malloc ((wcslen (SecondaryLanguageList) + 1) * sizeof (WCHAR)); | |
| if (Lang->SecondaryLanguageList == NULL) { | |
| Error (NULL, 0, 0, NULL, "memory allocation error"); | |
| FREE (Lang->PrintableLanguageName); | |
| FREE (Lang->LanguageName); | |
| return STATUS_ERROR; | |
| } | |
| wcscpy (Lang->SecondaryLanguageList, SecondaryLanguageList); | |
| } else { | |
| Lang->SecondaryLanguageList = NULL; | |
| } | |
| if (mDBData.LanguageList == NULL) { | |
| mDBData.LanguageList = Lang; | |
| } else { | |
| mDBData.LastLanguageList->Next = Lang; | |
| } | |
| mDBData.LastLanguageList = Lang; | |
| } | |
| // | |
| // Default is to make our active language this new one | |
| // | |
| StringDBSetCurrentLanguage (LanguageName); | |
| // | |
| // The first two strings for any language are the language name, | |
| // followed by the printable language name. Add them and set them | |
| // to referenced so they never get stripped out. | |
| // | |
| StringDBAddString ( | |
| LanguageName, | |
| LANGUAGE_NAME_STRING_NAME, | |
| NULL, | |
| LanguageName, | |
| FALSE, | |
| STRING_FLAGS_REFERENCED | |
| ); | |
| StringDBAddString ( | |
| LanguageName, | |
| PRINTABLE_LANGUAGE_NAME_STRING_NAME, | |
| NULL, | |
| PrintableLanguageName, | |
| FALSE, | |
| STRING_FLAGS_REFERENCED | |
| ); | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| StringDBAddSecondaryLanguage ( | |
| WCHAR *LanguageName, | |
| WCHAR *SecondaryLanguageList | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| Lang = StringDBFindLanguageList (LanguageName); | |
| if (Lang == NULL) { | |
| return STATUS_ERROR; | |
| } else { | |
| Lang->SecondaryLanguageList = WstrCatenate(Lang->SecondaryLanguageList, SecondaryLanguageList); | |
| return STATUS_SUCCESS; | |
| } | |
| } | |
| /*****************************************************************************/ | |
| static | |
| STRING_IDENTIFIER * | |
| StringDBFindStringIdentifierByName ( | |
| WCHAR *StringName | |
| ) | |
| { | |
| STRING_IDENTIFIER *Identifier; | |
| Identifier = mDBData.StringIdentifier; | |
| while (Identifier != NULL) { | |
| if (wcscmp (StringName, Identifier->StringName) == 0) { | |
| return Identifier; | |
| } | |
| Identifier = Identifier->Next; | |
| } | |
| return NULL; | |
| } | |
| static | |
| STRING_IDENTIFIER * | |
| StringDBFindStringIdentifierByIndex ( | |
| UINT32 StringIndex | |
| ) | |
| { | |
| STRING_IDENTIFIER *Identifier; | |
| Identifier = mDBData.StringIdentifier; | |
| while (Identifier != NULL) { | |
| if (Identifier->Index == StringIndex) { | |
| return Identifier; | |
| } | |
| Identifier = Identifier->Next; | |
| } | |
| return NULL; | |
| } | |
| /*****************************************************************************/ | |
| static | |
| void | |
| StringDBWriteStandardFileHeader ( | |
| FILE *OutFptr | |
| ) | |
| { | |
| UINT32 TempIndex; | |
| for (TempIndex = 0; mSourceFileHeader[TempIndex] != NULL; TempIndex++) { | |
| fprintf (OutFptr, "%s\n", mSourceFileHeader[TempIndex]); | |
| } | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Given a Unicode string from an input file, reformat the string to replace | |
| backslash control sequences with the appropriate encoding. | |
| Arguments: | |
| String - pointer to string to reformat | |
| Returns: | |
| Nothing | |
| --*/ | |
| void | |
| StringDBFormatString ( | |
| WCHAR *String | |
| ) | |
| { | |
| WCHAR *From; | |
| WCHAR *To; | |
| int HexNibbles; | |
| WCHAR HexValue; | |
| // | |
| // Go through the string and process any formatting characters | |
| // | |
| From = String; | |
| To = String; | |
| while (*From) { | |
| if (*From == UNICODE_BACKSLASH) { | |
| // | |
| // First look for \wide and replace with the appropriate control character. Note that | |
| // when you have "define STR L"ABC"", then sizeof(ABC) is 8 because the null char is | |
| // counted. Make adjustments for this. We advance From below, so subtract 2 each time. | |
| // | |
| if (wcsncmp (From, UNICODE_WIDE_STRING, sizeof (UNICODE_WIDE_STRING) / sizeof (WCHAR) - 1) == 0) { | |
| *To = WIDE_CHAR; | |
| From += sizeof (UNICODE_WIDE_STRING) / sizeof (WCHAR) - 2; | |
| } else if (wcsncmp (From, UNICODE_NARROW_STRING, sizeof (UNICODE_NARROW_STRING) / sizeof (WCHAR) - 1) == 0) { | |
| // | |
| // Found: \narrow | |
| // | |
| *To = NARROW_CHAR; | |
| From += sizeof (UNICODE_NARROW_STRING) / sizeof (WCHAR) - 2; | |
| } else if (wcsncmp (From, UNICODE_NBR_STRING, sizeof (UNICODE_NBR_STRING) / sizeof (WCHAR) - 1) == 0) { | |
| // | |
| // Found: \nbr | |
| // | |
| *To = NON_BREAKING_CHAR; | |
| From += sizeof (UNICODE_NBR_STRING) / sizeof (WCHAR) - 2; | |
| } else if (wcsncmp (From, UNICODE_BR_STRING, sizeof (UNICODE_BR_STRING) / sizeof (WCHAR) - 1) == 0) { | |
| // | |
| // Found: \br -- pass through untouched | |
| // | |
| *To = *From; | |
| } else { | |
| // | |
| // Standard one-character control sequences such as \n, \r, \\, or \x | |
| // | |
| From++; | |
| switch (*From) { | |
| case ASCII_TO_UNICODE ('n'): | |
| *To = UNICODE_CR; | |
| To++; | |
| *To = UNICODE_LF; | |
| break; | |
| // | |
| // carriage return | |
| // | |
| case ASCII_TO_UNICODE ('r'): | |
| *To = UNICODE_CR; | |
| break; | |
| // | |
| // backslash | |
| // | |
| case UNICODE_BACKSLASH: | |
| *To = UNICODE_BACKSLASH; | |
| break; | |
| // | |
| // Tab | |
| // | |
| case ASCII_TO_UNICODE ('t'): | |
| *To = UNICODE_TAB; | |
| break; | |
| // | |
| // embedded double-quote | |
| // | |
| case UNICODE_DOUBLE_QUOTE: | |
| *To = UNICODE_DOUBLE_QUOTE; | |
| break; | |
| // | |
| // Hex Unicode character \x1234. We'll process up to 4 hex characters | |
| // | |
| case ASCII_TO_UNICODE ('x'): | |
| HexValue = 0; | |
| for (HexNibbles = 0; HexNibbles < 4; HexNibbles++) { | |
| if ((From[1] >= UNICODE_0) && (From[1] <= UNICODE_9)) { | |
| HexValue = (HexValue << 4) | (From[1] - UNICODE_0); | |
| } else if ((From[1] >= UNICODE_a) && (From[1] <= UNICODE_f)) { | |
| HexValue = (HexValue << 4) | (10 + From[1] - UNICODE_a); | |
| } else if ((From[1] >= UNICODE_A) && (From[1] <= UNICODE_F)) { | |
| HexValue = (HexValue << 4) | (10 + From[1] - UNICODE_A); | |
| } else { | |
| break; | |
| } | |
| From++; | |
| } | |
| if (HexNibbles == 0) { | |
| ParserWarning ( | |
| 0, | |
| "expected at least one valid hex digit with \\x escaped character in string", | |
| "\\%C", | |
| *From | |
| ); | |
| } else { | |
| *To = HexValue; | |
| } | |
| break; | |
| default: | |
| *To = UNICODE_SPACE; | |
| ParserWarning (0, "invalid escaped character in string", "\\%C", *From); | |
| break; | |
| } | |
| } | |
| } else { | |
| *To = *From; | |
| } | |
| From++; | |
| To++; | |
| } | |
| *To = 0; | |
| } | |
| /*****************************************************************************/ | |
| STATUS | |
| StringDBReadDatabase ( | |
| INT8 *DBFileName, | |
| BOOLEAN IgnoreIfNotExist, | |
| BOOLEAN Verbose | |
| ) | |
| { | |
| STRING_DB_HEADER DbHeader; | |
| STATUS Status; | |
| FILE *DBFptr; | |
| DB_DATA_ITEM_HEADER DataItemHeader; | |
| Status = STATUS_SUCCESS; | |
| DBFptr = NULL; | |
| // | |
| // if (Verbose) { | |
| // fprintf (stdout, "Reading database file %s\n", DBFileName); | |
| // } | |
| // | |
| // Try to open the input file | |
| // | |
| if ((DBFptr = fopen (DBFileName, "rb")) == NULL) { | |
| if (IgnoreIfNotExist) { | |
| return STATUS_SUCCESS; | |
| } | |
| Error (NULL, 0, 0, DBFileName, "failed to open input database file for reading"); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Read and verify the database header | |
| // | |
| if (fread ((void *) &DbHeader, sizeof (STRING_DB_HEADER), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, DBFileName, "failed to read header from database file"); | |
| Status = STATUS_ERROR; | |
| goto Finish; | |
| } | |
| if (DbHeader.Key != STRING_DB_KEY) { | |
| Error (NULL, 0, 0, DBFileName, "invalid header in database file"); | |
| Status = STATUS_ERROR; | |
| goto Finish; | |
| } | |
| if ((DbHeader.Version & STRING_DB_MAJOR_VERSION_MASK) != (STRING_DB_VERSION & STRING_DB_MAJOR_VERSION_MASK)) { | |
| Error (NULL, 0, 0, DBFileName, "incompatible database file version -- rebuild clean"); | |
| Status = STATUS_ERROR; | |
| goto Finish; | |
| } | |
| // | |
| // Read remaining items | |
| // | |
| while (fread (&DataItemHeader, sizeof (DataItemHeader), 1, DBFptr) == 1) { | |
| switch (DataItemHeader.DataType) { | |
| case DB_DATA_TYPE_STRING_IDENTIFIER: | |
| StringDBReadStringIdentifier (DBFptr); | |
| break; | |
| case DB_DATA_TYPE_LANGUAGE_DEFINITION: | |
| StringDBReadLanguageDefinition (DBFptr); | |
| break; | |
| case DB_DATA_TYPE_STRING_DEFINITION: | |
| StringDBReadString (DBFptr); | |
| break; | |
| default: | |
| Error ( | |
| NULL, | |
| 0, | |
| 0, | |
| "database corrupted", | |
| "invalid data item type 0x%X at offset 0x%X", | |
| (UINT32) DataItemHeader.DataType, | |
| ftell (DBFptr) - sizeof (DataItemHeader) | |
| ); | |
| Status = STATUS_ERROR; | |
| goto Finish; | |
| } | |
| } | |
| Finish: | |
| if (DBFptr != NULL) { | |
| fclose (DBFptr); | |
| } | |
| return Status; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Write everything we know to the output database file. Write: | |
| Database header | |
| String identifiers[] | |
| StringPacks[] | |
| Arguments: | |
| DBFileName - name of the file to write to | |
| Verbose - for debug purposes, print info messages along the way. | |
| Returns: | |
| STATUS | |
| --*/ | |
| STATUS | |
| StringDBWriteDatabase ( | |
| INT8 *DBFileName, | |
| BOOLEAN Verbose | |
| ) | |
| { | |
| STRING_DB_HEADER DbHeader; | |
| UINT32 Counter; | |
| UINT32 StrLen; | |
| LANGUAGE_LIST *Lang; | |
| STRING_IDENTIFIER *StringIdentifier; | |
| STRING_LIST *StrList; | |
| FILE *DBFptr; | |
| if (Verbose) { | |
| fprintf (stdout, "Writing database %s\n", DBFileName); | |
| } | |
| if ((DBFptr = fopen (DBFileName, "wb")) == NULL) { | |
| Error (NULL, 0, 0, DBFileName, "failed to open output database file for writing"); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Fill in and write the database header | |
| // | |
| memset (&DbHeader, 0, sizeof (STRING_DB_HEADER)); | |
| DbHeader.HeaderSize = sizeof (STRING_DB_HEADER); | |
| DbHeader.Key = STRING_DB_KEY; | |
| DbHeader.Version = STRING_DB_VERSION; | |
| // | |
| // Count the number of languages we have | |
| // | |
| for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| DbHeader.NumLanguages++; | |
| } | |
| // | |
| // Count up how many string identifiers we have, and total up the | |
| // size of the names plus the size of the flags field we will | |
| // write out too. | |
| // | |
| DbHeader.NumStringIdenfiers = mDBData.NumStringIdentifiers; | |
| StringIdentifier = mDBData.StringIdentifier; | |
| for (Counter = 0; Counter < mDBData.NumStringIdentifiers; Counter++) { | |
| StrLen = wcslen (StringIdentifier->StringName) + 1; | |
| DbHeader.StringIdentifiersSize += StrLen * sizeof (WCHAR) + sizeof (StringIdentifier->Flags); | |
| StringIdentifier = StringIdentifier->Next; | |
| } | |
| // | |
| // Write the header | |
| // | |
| fwrite (&DbHeader, sizeof (STRING_DB_HEADER), 1, DBFptr); | |
| if (Verbose) { | |
| fprintf (stdout, " Number of string identifiers 0x%04X\n", DbHeader.NumStringIdenfiers); | |
| fprintf (stdout, " Number of languages %d\n", DbHeader.NumLanguages); | |
| } | |
| // | |
| // Write the string identifiers | |
| // | |
| for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) { | |
| StringDBWriteStringIdentifier ( | |
| DBFptr, | |
| (UINT16) StringIdentifier->Index, | |
| StringIdentifier->Flags, | |
| StringIdentifier->StringName | |
| ); | |
| } | |
| // | |
| // Now write all the strings for each language | |
| // | |
| for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| StringDBWriteLanguageDefinition (DBFptr, Lang->LanguageName, Lang->PrintableLanguageName, Lang->SecondaryLanguageList); | |
| for (StrList = Lang->String; StrList != NULL; StrList = StrList->Next) { | |
| StringDBWriteString ( | |
| DBFptr, | |
| StrList->Flags, | |
| Lang->LanguageName, | |
| StrList->StringName, | |
| StrList->Scope, | |
| StrList->Str | |
| ); | |
| } | |
| } | |
| fclose (DBFptr); | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| StringDBSetStringReferenced ( | |
| INT8 *StringIdentifierName, | |
| BOOLEAN IgnoreNotFound | |
| ) | |
| { | |
| STRING_IDENTIFIER *Id; | |
| WCHAR *WName; | |
| STATUS Status; | |
| // | |
| // See if it's already been defined. | |
| // | |
| Status = STATUS_SUCCESS; | |
| WName = (WCHAR *) malloc ((strlen (StringIdentifierName) + 1) * sizeof (WCHAR)); | |
| #ifdef USE_VC8 | |
| swprintf (WName, (strlen (StringIdentifierName) + 1) * sizeof (WCHAR), L"%S", StringIdentifierName); | |
| #else | |
| swprintf (WName, L"%S", StringIdentifierName); | |
| #endif | |
| Id = StringDBFindStringIdentifierByName (WName); | |
| if (Id != NULL) { | |
| Id->Flags |= STRING_FLAGS_REFERENCED; | |
| } else { | |
| if (IgnoreNotFound == 0) { | |
| ParserWarning (0, StringIdentifierName, "string identifier not found in database"); | |
| Status = STATUS_WARNING; | |
| } | |
| } | |
| free (WName); | |
| return Status; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Dump the contents of a database to an output unicode file. | |
| Arguments: | |
| DBFileName - name of the pre-existing database file to read | |
| OutputFileName - name of the file to dump the database contents to | |
| Verbose - for printing of additional info useful for debugging | |
| Returns: | |
| STATUS | |
| Notes: | |
| There's some issue with the unicode printing routines. Therefore to | |
| write to the output file properly, open it as binary and use fwrite. | |
| Ideally we could open it with just L"w" and use fwprintf(). | |
| --*/ | |
| STATUS | |
| StringDBDumpDatabase ( | |
| INT8 *DBFileName, | |
| INT8 *OutputFileName, | |
| BOOLEAN Verbose | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| STRING_IDENTIFIER *StringIdentifier; | |
| STRING_LIST *StrList; | |
| FILE *OutFptr; | |
| WCHAR WChar; | |
| WCHAR *WOutputFileName; | |
| WCHAR CrLf[2]; | |
| WCHAR Line[200]; | |
| WCHAR *Scope; | |
| // | |
| // This function assumes the database has already been read, and | |
| // we're just dumping our internal data structures to a unicode file. | |
| // | |
| if (Verbose) { | |
| fprintf (stdout, "Dumping database file %s\n", DBFileName); | |
| } | |
| WOutputFileName = AsciiToWchar (OutputFileName); | |
| OutFptr = _wfopen (WOutputFileName, L"wb"); | |
| free (WOutputFileName); | |
| if (OutFptr == NULL) { | |
| Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing"); | |
| return STATUS_ERROR; | |
| } | |
| WChar = UNICODE_FILE_START; | |
| fwrite (&WChar, sizeof (WCHAR), 1, OutFptr); | |
| CrLf[1] = UNICODE_LF; | |
| CrLf[0] = UNICODE_CR; | |
| // | |
| // The default control character is '/'. Make it '#' by writing | |
| // "/=#" to the output file. | |
| // | |
| #ifdef USE_VC8 | |
| swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"/=#"); | |
| #else | |
| swprintf (Line, L"/=#"); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| // | |
| // Dump all the string identifiers and their values | |
| // | |
| StringDBAssignStringIndexes (); | |
| for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) { | |
| // | |
| // Write the "#define " string | |
| // | |
| if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) { | |
| #ifdef USE_VC8 | |
| swprintf ( | |
| Line, | |
| wcslen(Line) * sizeof (WCHAR), | |
| L"%s %-60.60s 0x%04X", | |
| DEFINE_STR, | |
| StringIdentifier->StringName, | |
| StringIdentifier->Index | |
| ); | |
| #else | |
| swprintf ( | |
| Line, | |
| L"%s %-60.60s 0x%04X", | |
| DEFINE_STR, | |
| StringIdentifier->StringName, | |
| StringIdentifier->Index | |
| ); | |
| #endif | |
| } else { | |
| #ifdef USE_VC8 | |
| swprintf ( | |
| Line, | |
| wcslen(Line) * sizeof (WCHAR), | |
| L"%s %-60.60s 0x%04X // NOT REFERENCED", | |
| DEFINE_STR, | |
| StringIdentifier->StringName, | |
| StringIdentifier->Index | |
| ); | |
| #else | |
| swprintf ( | |
| Line, | |
| L"%s %-60.60s 0x%04X // NOT REFERENCED", | |
| DEFINE_STR, | |
| StringIdentifier->StringName, | |
| StringIdentifier->Index | |
| ); | |
| #endif | |
| } | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| } | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| // | |
| // Now write all the strings for each language. | |
| // | |
| WChar = UNICODE_DOUBLE_QUOTE; | |
| Scope = NULL; | |
| for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| #ifdef USE_VC8 | |
| swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName); | |
| #else | |
| swprintf (Line, L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| // | |
| // Now the strings (in double-quotes) for this language. Write | |
| // #string STR_NAME #language eng "string" | |
| // | |
| for (StrList = Lang->String; StrList != NULL; StrList = StrList->Next) { | |
| // | |
| // Print the internal flags for debug | |
| // | |
| #ifdef USE_VC8 | |
| swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"// flags=0x%02X", (UINT32) StrList->Flags); | |
| #else | |
| swprintf (Line, L"// flags=0x%02X", (UINT32) StrList->Flags); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| // | |
| // Print the scope if changed | |
| // | |
| if ((Scope == NULL) || (wcscmp (Scope, StrList->Scope) != 0)) { | |
| #ifdef USE_VC8 | |
| swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#scope %s", StrList->Scope); | |
| #else | |
| swprintf (Line, L"#scope %s", StrList->Scope); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| Scope = StrList->Scope; | |
| } | |
| #ifdef USE_VC8 | |
| swprintf ( | |
| Line, | |
| wcslen(Line) * sizeof (WCHAR), | |
| L"#string %-50.50s #language %s \"", | |
| StrList->StringName, | |
| Lang->LanguageName | |
| ); | |
| #else | |
| swprintf ( | |
| Line, | |
| L"#string %-50.50s #language %s \"", | |
| StrList->StringName, | |
| Lang->LanguageName | |
| ); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (StrList->Str, StrList->Size - sizeof (WCHAR), 1, OutFptr); | |
| #ifdef USE_VC8 | |
| swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"\""); | |
| #else | |
| swprintf (Line, L"\""); | |
| #endif | |
| fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr); | |
| fwrite (&CrLf, sizeof (CrLf), 1, OutFptr); | |
| } | |
| } | |
| fclose (OutFptr); | |
| return STATUS_SUCCESS; | |
| } | |
| /*****************************************************************************/ | |
| /*++ | |
| Routine Description: | |
| Given a primary language, a string identifier number, and a list of | |
| languages, find a secondary string. | |
| Arguments: | |
| LanguageName - primary language, like "spa" | |
| StringId - string index value | |
| LanguageList - linked list of "eng", "spa+cat",... | |
| Returns: | |
| Pointer to a secondary string if found. NULL otherwise. | |
| Notes: | |
| Given: LanguageName "spa" and LanguageList "spa+cat", match the | |
| "spa" and extract the "cat" and see if there is a string defined | |
| for "cat".StringId. | |
| --*/ | |
| static | |
| STATUS | |
| StringDBWriteStringIdentifier ( | |
| FILE *DBFptr, | |
| UINT16 StringId, | |
| UINT16 Flags, | |
| WCHAR *IdentifierName | |
| ) | |
| { | |
| DB_DATA_ITEM_HEADER Hdr; | |
| memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER)); | |
| Hdr.DataType = DB_DATA_TYPE_STRING_IDENTIFIER; | |
| if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string to output database file", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (&StringId, sizeof (StringId), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write StringId to output database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (&Flags, sizeof (Flags), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write StringId flags to output database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, IdentifierName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBReadStringIdentifier ( | |
| FILE *DBFptr | |
| ) | |
| { | |
| WCHAR *IdentifierName; | |
| UINT16 Flags; | |
| UINT16 StringId; | |
| UINT16 Size; | |
| if (fread (&StringId, sizeof (StringId), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to read StringId from database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fread (&Flags, sizeof (Flags), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to read StringId flags from database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &IdentifierName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| StringDBAddStringIdentifier (IdentifierName, &StringId, Flags); | |
| // | |
| // printf ("STRID: 0x%04X %S\n", (UINT32)StringId, IdentifierName); | |
| // | |
| FREE (IdentifierName); | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBWriteString ( | |
| FILE *DBFptr, | |
| UINT16 Flags, | |
| WCHAR *Language, | |
| WCHAR *StringName, | |
| WCHAR *Scope, | |
| WCHAR *Str | |
| ) | |
| { | |
| DB_DATA_ITEM_HEADER Hdr; | |
| memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER)); | |
| Hdr.DataType = DB_DATA_TYPE_STRING_DEFINITION; | |
| if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string header to output database file", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (&Flags, sizeof (Flags), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string flags to output database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, Language) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, StringName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, Scope) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, Str) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // printf ("DBWriteString: %S.%S.%S\n", Language, StringName, Scope); | |
| // | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBReadString ( | |
| FILE *DBFptr | |
| ) | |
| { | |
| UINT16 Flags; | |
| UINT16 Size; | |
| WCHAR *Language; | |
| WCHAR *StringName; | |
| WCHAR *Scope; | |
| WCHAR *Str; | |
| if (fread (&Flags, sizeof (Flags), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to read string flags from database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &Language) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &StringName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &Scope) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &Str) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // If the first or second string (language name and printable language name), | |
| // then skip them. They're added via language definitions data items in | |
| // the database. | |
| // | |
| if (StringName[0] != L'$') { | |
| StringDBAddString (Language, StringName, Scope, Str, FALSE, Flags); | |
| } | |
| // | |
| // printf ("DBReadString: %S.%S.%S\n", Language, StringName, Scope); | |
| // | |
| FREE (Language); | |
| FREE (StringName); | |
| if (Str != NULL) { | |
| FREE (Str); | |
| } | |
| if (Scope != NULL) { | |
| FREE (Scope); | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBWriteLanguageDefinition ( | |
| FILE *DBFptr, | |
| WCHAR *LanguageName, | |
| WCHAR *PrintableLanguageName, | |
| WCHAR *SecondaryLanguageList | |
| ) | |
| { | |
| DB_DATA_ITEM_HEADER Hdr; | |
| memset (&Hdr, 0, sizeof (DB_DATA_ITEM_HEADER)); | |
| Hdr.DataType = DB_DATA_TYPE_LANGUAGE_DEFINITION; | |
| if (fwrite (&Hdr, sizeof (DB_DATA_ITEM_HEADER), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string to output database file", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, LanguageName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, PrintableLanguageName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBWriteGenericString (DBFptr, SecondaryLanguageList) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBReadLanguageDefinition ( | |
| FILE *DBFptr | |
| ) | |
| { | |
| WCHAR *LanguageName = NULL; | |
| WCHAR *PrintableLanguageName = NULL; | |
| WCHAR *SecondaryLanguageList = NULL; | |
| UINT16 Size; | |
| STATUS Status; | |
| if (StringDBReadGenericString (DBFptr, &Size, &LanguageName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &PrintableLanguageName) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| if (StringDBReadGenericString (DBFptr, &Size, &SecondaryLanguageList) != STATUS_SUCCESS) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName); | |
| // | |
| Status = StringDBAddLanguage (LanguageName, PrintableLanguageName, SecondaryLanguageList); | |
| FREE (LanguageName); | |
| FREE (PrintableLanguageName); | |
| FREE (SecondaryLanguageList); | |
| return Status; | |
| } | |
| // | |
| // All unicode strings in the database consist of a UINT16 length | |
| // field, followed by the string itself. This routine reads one | |
| // of those and returns the info. | |
| // | |
| static | |
| STATUS | |
| StringDBReadGenericString ( | |
| FILE *DBFptr, | |
| UINT16 *Size, | |
| WCHAR **Str | |
| ) | |
| { | |
| UINT16 LSize; | |
| UINT16 Flags; | |
| WCHAR *LStr; | |
| if (fread (&LSize, sizeof (UINT16), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to read a string length field from the database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fread (&Flags, sizeof (UINT16), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to read a string flags field from the database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| LStr = MALLOC (LSize); | |
| if (LStr == NULL) { | |
| Error (__FILE__, __LINE__, 0, "memory allocation failed reading the database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fread (LStr, sizeof (WCHAR), (UINT32) LSize / sizeof (WCHAR), DBFptr) != (UINT32) LSize / sizeof (WCHAR)) { | |
| Error (NULL, 0, 0, "failed to read string from database", NULL); | |
| Error (NULL, 0, 0, "database read failure", "offset 0x%X", ftell (DBFptr)); | |
| free (LStr); | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // printf ("DBR: %S\n", LStr); | |
| // | |
| // If the flags field indicated we were asked to write a NULL string, then | |
| // return them a NULL pointer. | |
| // | |
| if (Flags & STRING_FLAGS_UNDEFINED) { | |
| *Size = 0; | |
| *Str = NULL; | |
| } else { | |
| *Size = LSize; | |
| *Str = LStr; | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STATUS | |
| StringDBWriteGenericString ( | |
| FILE *DBFptr, | |
| WCHAR *Str | |
| ) | |
| { | |
| UINT16 Size; | |
| UINT16 Flags; | |
| WCHAR ZeroString[1]; | |
| // | |
| // Strings in the database consist of a size UINT16 followed | |
| // by the string itself. | |
| // | |
| if (Str == NULL) { | |
| ZeroString[0] = 0; | |
| Str = ZeroString; | |
| Size = sizeof (ZeroString); | |
| Flags = STRING_FLAGS_UNDEFINED; | |
| } else { | |
| Flags = 0; | |
| Size = (UINT16) ((wcslen (Str) + 1) * sizeof (WCHAR)); | |
| } | |
| if (fwrite (&Size, sizeof (UINT16), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string size to database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (&Flags, sizeof (UINT16), 1, DBFptr) != 1) { | |
| Error (NULL, 0, 0, "failed to write string flags to database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| if (fwrite (Str, sizeof (WCHAR), Size / sizeof (WCHAR), DBFptr) != Size / sizeof (WCHAR)) { | |
| Error (NULL, 0, 0, "failed to write string to database", NULL); | |
| return STATUS_ERROR; | |
| } | |
| return STATUS_SUCCESS; | |
| } | |
| static | |
| STRING_LIST * | |
| StringDBFindString ( | |
| WCHAR *LanguageName, | |
| WCHAR *StringName, | |
| WCHAR *Scope, | |
| WCHAR_STRING_LIST *LanguagesOfInterest, | |
| WCHAR_MATCHING_STRING_LIST *IndirectionList | |
| ) | |
| { | |
| LANGUAGE_LIST *Lang; | |
| STRING_LIST *CurrString; | |
| WCHAR_MATCHING_STRING_LIST *IndListPtr; | |
| WCHAR TempLangName[LANGUAGE_IDENTIFIER_NAME_LEN + 1]; | |
| WCHAR *WCharPtr; | |
| // | |
| // If we were given an indirection list, then see if one was specified for this | |
| // string identifier. That is to say, if the indirection says "STR_ID_MY_FAVORITE MyScope", | |
| // then if this string name matches one in the list, then do a lookup with the | |
| // specified scope and return that value. | |
| // | |
| if (IndirectionList != NULL) { | |
| for (IndListPtr = IndirectionList; IndListPtr != NULL; IndListPtr = IndListPtr->Next) { | |
| if (wcscmp (StringName, IndListPtr->Str1) == 0) { | |
| CurrString = StringDBFindString (LanguageName, StringName, IndListPtr->Str2, LanguagesOfInterest, NULL); | |
| if (CurrString != NULL) { | |
| return CurrString; | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // First look for exact match language.stringname | |
| // | |
| for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| if (wcscmp (LanguageName, Lang->LanguageName) == 0) { | |
| // | |
| // Found language match. Try to find string name match | |
| // | |
| for (CurrString = Lang->String; CurrString != NULL; CurrString = CurrString->Next) { | |
| if (wcscmp (StringName, CurrString->StringName) == 0) { | |
| // | |
| // Found a string name match. See if we're supposed to find | |
| // a scope match. | |
| // | |
| if (Scope != NULL) { | |
| if (wcscmp (CurrString->Scope, Scope) == 0) { | |
| return CurrString; | |
| } | |
| } else { | |
| return CurrString; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // | |
| // If we got here, then we didn't find a match. Look for secondary string | |
| // matches. That is to say, if we're processing "spa", and they requested | |
| // "spa+cat", then recursively call with "cat" | |
| // | |
| while (LanguagesOfInterest != NULL) { | |
| // | |
| // If this is the language we're looking for, then process the | |
| // languages of interest list for it. | |
| // | |
| if (wcsncmp (LanguageName, LanguagesOfInterest->Str, LANGUAGE_IDENTIFIER_NAME_LEN) == 0) { | |
| WCharPtr = LanguagesOfInterest->Str + LANGUAGE_IDENTIFIER_NAME_LEN; | |
| while (*WCharPtr) { | |
| // | |
| // Double-check the length, though it should have been checked on the | |
| // command line. | |
| // | |
| if (wcslen (WCharPtr) < LANGUAGE_IDENTIFIER_NAME_LEN) { | |
| Error (NULL, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest->Str); | |
| return NULL; | |
| } | |
| wcsncpy (TempLangName, WCharPtr, LANGUAGE_IDENTIFIER_NAME_LEN); | |
| TempLangName[LANGUAGE_IDENTIFIER_NAME_LEN] = 0; | |
| CurrString = StringDBFindString (TempLangName, StringName, NULL, NULL, IndirectionList); | |
| if (CurrString != NULL) { | |
| return CurrString; | |
| } | |
| WCharPtr += LANGUAGE_IDENTIFIER_NAME_LEN; | |
| } | |
| } | |
| LanguagesOfInterest = LanguagesOfInterest->Next; | |
| } | |
| return NULL; | |
| } | |
| STATUS | |
| StringDBSetScope ( | |
| WCHAR *Scope | |
| ) | |
| { | |
| // | |
| // Free up existing scope memory. | |
| // | |
| if (mDBData.CurrentScope != NULL) { | |
| FREE (mDBData.CurrentScope); | |
| } | |
| mDBData.CurrentScope = DuplicateString (Scope); | |
| return STATUS_SUCCESS; | |
| } | |
| // | |
| // We typically don't assign index values to string identifiers | |
| // until we're ready to write out files. To reduce the size of | |
| // the output file, re-order the string identifiers to move any | |
| // unreferenced ones to the end. Then we'll walk the list | |
| // again to assign string indexes, keeping track of the last | |
| // one referenced. | |
| // | |
| static | |
| void | |
| StringDBAssignStringIndexes ( | |
| VOID | |
| ) | |
| { | |
| STRING_IDENTIFIER *StrId; | |
| STRING_IDENTIFIER *FirstUsed; | |
| STRING_IDENTIFIER *LastUsed; | |
| STRING_IDENTIFIER *FirstUnused; | |
| STRING_IDENTIFIER *LastUnused; | |
| UINT32 Index; | |
| UINT32 MaxReferenced; | |
| // | |
| // Create two lists -- used and unused. Then put them together with | |
| // the unused ones on the end. | |
| // | |
| FirstUsed = NULL; | |
| LastUsed = NULL; | |
| FirstUnused = NULL; | |
| LastUnused = NULL; | |
| StrId = mDBData.StringIdentifier; | |
| while (StrId != NULL) { | |
| if ((StrId->Flags & STRING_FLAGS_REFERENCED) == 0) { | |
| // | |
| // Put it on the unused list | |
| // | |
| if (FirstUnused == NULL) { | |
| FirstUnused = StrId; | |
| } else { | |
| LastUnused->Next = StrId; | |
| } | |
| LastUnused = StrId; | |
| StrId = StrId->Next; | |
| LastUnused->Next = NULL; | |
| } else { | |
| // | |
| // Put it on the used list | |
| // | |
| if (FirstUsed == NULL) { | |
| FirstUsed = StrId; | |
| } else { | |
| LastUsed->Next = StrId; | |
| } | |
| LastUsed = StrId; | |
| StrId = StrId->Next; | |
| LastUsed->Next = NULL; | |
| } | |
| } | |
| // | |
| // Join the lists | |
| // | |
| if (FirstUsed != NULL) { | |
| mDBData.StringIdentifier = FirstUsed; | |
| LastUsed->Next = FirstUnused; | |
| } else { | |
| mDBData.StringIdentifier = FirstUnused; | |
| } | |
| MaxReferenced = 0; | |
| Index = 0; | |
| for (StrId = mDBData.StringIdentifier; StrId != NULL; StrId = StrId->Next) { | |
| StrId->Index = Index; | |
| Index++; | |
| if (StrId->Flags & STRING_FLAGS_REFERENCED) { | |
| mDBData.NumStringIdentifiersReferenced = Index; | |
| } | |
| } | |
| mDBData.NumStringIdentifiers = Index; | |
| } | |
| static | |
| WCHAR * | |
| DuplicateString ( | |
| WCHAR *Str | |
| ) | |
| { | |
| WCHAR *NewStr; | |
| if (Str == NULL) { | |
| return NULL; | |
| } | |
| NewStr = MALLOC ((wcslen (Str) + 1) * sizeof (WCHAR)); | |
| if (NewStr == NULL) { | |
| Error (NULL, 0, 0, "memory allocation failure", NULL); | |
| return NULL; | |
| } | |
| wcscpy (NewStr, Str); | |
| return NewStr; | |
| } | |
| static | |
| WCHAR * | |
| WstrCatenate ( | |
| WCHAR *Dst, | |
| WCHAR *Src | |
| ) | |
| { | |
| UINT32 Len = 0; | |
| WCHAR *Bak = Dst; | |
| if (Src == NULL) { | |
| return Dst; | |
| } | |
| if (Dst != NULL) { | |
| Len = wcslen (Dst); | |
| } | |
| Len += wcslen (Src); | |
| Dst = (WCHAR *) malloc ((Len + 1) * 2); | |
| if (Dst == NULL) { | |
| return NULL; | |
| } | |
| Dst[0] = L'\0'; | |
| if (Bak != NULL) { | |
| wcscpy (Dst, Bak); | |
| FREE (Bak); | |
| } | |
| wcscat (Dst, Src); | |
| return Dst; | |
| } | |
| static | |
| WCHAR * | |
| AsciiToWchar ( | |
| INT8 *Str | |
| ) | |
| { | |
| UINT32 Len; | |
| WCHAR *NewStr; | |
| WCHAR *Ptr; | |
| Len = strlen (Str) + 1; | |
| NewStr = (WCHAR *) malloc (Len * sizeof (WCHAR)); | |
| for (Ptr = NewStr; *Str != 0; Str++, Ptr++) { | |
| *Ptr = (UINT16) (UINT8) *Str; | |
| } | |
| *Ptr = 0; | |
| return NewStr; | |
| } | |
| static | |
| CHAR8 * | |
| WcharToAscii ( | |
| WCHAR *Str | |
| ) | |
| { | |
| UINT32 Len; | |
| CHAR8 *NewStr; | |
| CHAR8 *Ptr; | |
| Len = wcslen (Str) + 1; | |
| NewStr = (CHAR8 *) malloc (Len * sizeof (CHAR8)); | |
| for (Ptr = NewStr; *Str != L'\0'; Str++, Ptr++) { | |
| *Ptr = (CHAR8) *Str; | |
| } | |
| *Ptr = '\0'; | |
| return NewStr; | |
| } | |
| /*****************************************************************************/ | |
| CHAR8 * | |
| unicode2ascii ( | |
| WCHAR *UnicodeStr | |
| ) | |
| { | |
| CHAR8 *RetStr = (CHAR8 *)UnicodeStr; | |
| CHAR8 *AsciiStr = (CHAR8 *)UnicodeStr; | |
| while (*UnicodeStr != '\0') { | |
| *AsciiStr = (CHAR8) *(UnicodeStr++); | |
| AsciiStr++; | |
| } | |
| *AsciiStr = '\0'; | |
| return RetStr; | |
| } | |
| STATUS | |
| BuildStringPkgHdr ( | |
| IN WCHAR *PrimaryLangName, | |
| IN WCHAR *SecondaryLangList, | |
| IN UINT32 Type, | |
| IN UINT32 PkgBlkSize, | |
| OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr | |
| ) | |
| { | |
| UINT32 LangNameLen; | |
| LangNameLen = wcslen (PrimaryLangName); | |
| if (SecondaryLangList != NULL) { | |
| LangNameLen += wcslen (SecondaryLangList) + 1; | |
| } | |
| *StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) malloc(sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen); | |
| if (*StrPkgHdr == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| memset (*StrPkgHdr, 0, sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen); | |
| (*StrPkgHdr)->Header.Type = Type; | |
| (*StrPkgHdr)->Header.Length = PkgBlkSize + sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen; | |
| (*StrPkgHdr)->HdrSize = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen; | |
| (*StrPkgHdr)->StringInfoOffset = sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen; | |
| (*StrPkgHdr)->LanguageWindow[0] = L'\0'; | |
| (*StrPkgHdr)->LanguageName = (EFI_STRING_ID)1; | |
| strcpy ((*StrPkgHdr)->Language, unicode2ascii(PrimaryLangName)); | |
| if (SecondaryLangList != NULL) { | |
| strcat ((*StrPkgHdr)->Language, ";"); | |
| strcat ((*StrPkgHdr)->Language, unicode2ascii(SecondaryLangList)); | |
| } | |
| #ifdef DEBUG_STRGATHER | |
| printf ("STR HDR\t %s\n", (*StrPkgHdr)->Language); | |
| #endif | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| BuildStringPkgUCS2Blk ( | |
| IN EFI_STRING_ID StringId, | |
| IN WCHAR *LangName, | |
| IN WCHAR *StrName, | |
| OUT EFI_HII_SIBT_STRING_UCS2_BLOCK **StrBlk, | |
| OUT UINT32 *BlkSize | |
| ) | |
| { | |
| UINT32 StrLen = 0; | |
| STRING_LIST *CurrString = NULL; | |
| if ((LangName == NULL) || (StrName == NULL) || (StrBlk == NULL)) { | |
| return STATUS_ERROR; | |
| } | |
| *StrBlk = NULL; | |
| *BlkSize = 0; | |
| CurrString = StringDBFindString (LangName, StrName, NULL, NULL, NULL); | |
| if (CurrString == NULL) { | |
| return STATUS_WARNING; | |
| } | |
| StrLen = wcslen (CurrString->Str); | |
| *BlkSize = sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK) + StrLen * 2; | |
| *StrBlk = (EFI_HII_SIBT_STRING_UCS2_BLOCK *) malloc (*BlkSize); | |
| if (*StrBlk == NULL) { | |
| *StrBlk = NULL; | |
| *BlkSize = 0; | |
| return STATUS_ERROR; | |
| } | |
| (*StrBlk)->Header.BlockType = EFI_HII_SIBT_STRING_UCS2; | |
| wcscpy((*StrBlk)->StringText, CurrString->Str); | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| BuildStringPkgSKIP2Blk ( | |
| IN EFI_STRING_ID SkipIdCount, | |
| OUT EFI_HII_SIBT_SKIP2_BLOCK **StrBlk | |
| ) | |
| { | |
| if (StrBlk == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| *StrBlk = NULL; | |
| *StrBlk = (EFI_HII_SIBT_SKIP2_BLOCK *) malloc (sizeof (EFI_HII_SIBT_SKIP2_BLOCK)); | |
| if (*StrBlk == NULL) { | |
| *StrBlk = NULL; | |
| return STATUS_ERROR; | |
| } | |
| (*StrBlk)->Header.BlockType = EFI_HII_SIBT_SKIP2; | |
| (*StrBlk)->SkipCount = SkipIdCount; | |
| return STATUS_SUCCESS; | |
| } | |
| STATUS | |
| BuildStringPkgEndBlk ( | |
| OUT EFI_HII_SIBT_END_BLOCK **End | |
| ) | |
| { | |
| *End = (EFI_HII_SIBT_END_BLOCK *) malloc (sizeof (EFI_HII_SIBT_END_BLOCK)); | |
| if (*End == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| (*End)->Header.BlockType = EFI_HII_SIBT_END; | |
| return STATUS_SUCCESS; | |
| } | |
| /*++ | |
| Routine Description: | |
| Create an HII export string pack for the strings in our database. | |
| Arguments: | |
| FileName - name of the output file to write | |
| Returns: | |
| STATUS | |
| --*/ | |
| STATUS | |
| StrPkgBlkBufferListAddTail ( | |
| IN EFI_STRING_ID StringId, | |
| IN WCHAR *StrName, | |
| IN SPkgBlkBuffer **PkgBufferListHead, | |
| IN SPkgBlkBuffer **PkgBufferListTail, | |
| IN VOID *Buffer, | |
| IN UINT32 Size | |
| ) | |
| { | |
| SPkgBlkBuffer *pNew = NULL; | |
| #ifdef DEBUG_STRGATHER | |
| EFI_HII_STRING_BLOCK *SBlk = (EFI_HII_STRING_BLOCK *)Buffer; | |
| #endif | |
| if ((PkgBufferListHead == NULL) || (PkgBufferListTail == NULL)) { | |
| return STATUS_ERROR; | |
| } | |
| pNew = (SPkgBlkBuffer *) malloc (sizeof (SPkgBlkBuffer)); | |
| if (pNew == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| pNew->mBlkBuffer = Buffer; | |
| pNew->mBlkSize = Size; | |
| if ((*PkgBufferListTail) == NULL) { | |
| (*PkgBufferListHead) = (*PkgBufferListTail) = pNew; | |
| } else { | |
| (*PkgBufferListTail)->mNext = pNew; | |
| (*PkgBufferListTail) = pNew; | |
| pNew->mNext = NULL; | |
| } | |
| #ifdef DEBUG_STRGATHER | |
| switch (SBlk->BlockType) { | |
| case EFI_HII_SIBT_STRING_UCS2 : | |
| printf ("\tID: [%x] TYPE: [UCS2]\t NAME: %S \t STR: %S\n", StringId, StrName, ((EFI_HII_SIBT_STRING_UCS2_BLOCK *)SBlk)->StringText); | |
| break; | |
| case EFI_HII_SIBT_SKIP2 : | |
| printf ("\tID: [NULL] TYPE: [SKIP2] SKIPCOUNT: [%x]\n", ((EFI_HII_SIBT_SKIP2_BLOCK *)SBlk)->SkipCount); | |
| break; | |
| case EFI_HII_SIBT_END : | |
| printf ("\tID: [%x] TYPE: [END]\n", StringId); | |
| break; | |
| default : | |
| printf ("!!!!UNKNOWN STRING TYPE!!!\n"); | |
| } | |
| #endif | |
| return STATUS_SUCCESS; | |
| } | |
| VOID | |
| StrPkgHdrFree ( | |
| IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr | |
| ) | |
| { | |
| if (StrPkgHdr != NULL) { | |
| free (StrPkgHdr); | |
| } | |
| } | |
| VOID | |
| StrPkgBlkBufferListFree ( | |
| IN SPkgBlkBuffer *PkgBlkList | |
| ) | |
| { | |
| SPkgBlkBuffer *Buffer; | |
| while (PkgBlkList != NULL) { | |
| Buffer = PkgBlkList; | |
| PkgBlkList = PkgBlkList->mNext; | |
| if (Buffer->mBlkBuffer != NULL) { | |
| free (Buffer->mBlkBuffer); | |
| } | |
| free (Buffer); | |
| } | |
| } | |
| VOID | |
| WriteBlockLine ( | |
| IN FILE *pFile, | |
| IN UINT32 LineBytes, | |
| IN INT8 *LineHeader, | |
| IN INT8 *BlkBuf, | |
| IN UINT32 BlkSize | |
| ) | |
| { | |
| UINT32 Index; | |
| if ((pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) { | |
| return; | |
| } | |
| for (Index = 0; Index < BlkSize; Index++) { | |
| if ((Index % LineBytes) == 0) { | |
| fprintf (pFile, "\n%s", LineHeader); | |
| } | |
| fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]); | |
| } | |
| } | |
| VOID | |
| WriteBlockEnd ( | |
| IN FILE *pFile, | |
| IN UINT32 LineBytes, | |
| IN INT8 *LineHeader, | |
| IN INT8 *BlkBuf, | |
| IN UINT32 BlkSize | |
| ) | |
| { | |
| UINT32 Index; | |
| if ((BlkSize == 0) || (pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) { | |
| return; | |
| } | |
| for (Index = 0; Index < BlkSize - 1; Index++) { | |
| if ((Index % LineBytes) == 0) { | |
| fprintf (pFile, "\n%s", LineHeader); | |
| } | |
| fprintf (pFile, "0x%02X, ", (UINT8)BlkBuf[Index]); | |
| } | |
| if ((Index % LineBytes) == 0) { | |
| fprintf (pFile, "\n%s", LineHeader); | |
| } | |
| fprintf (pFile, "0x%02X\n", (UINT8)BlkBuf[Index]); | |
| } | |
| #define BYTES_PRE_LINE 0x10 | |
| VOID | |
| StrPkgWriteHdrCFile ( | |
| IN FILE *File, | |
| IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr | |
| ) | |
| { | |
| if (StrPkgHdr != NULL) { | |
| fprintf (File, "\n // PACKAGE HEADER\n"); | |
| WriteBlockLine(File, BYTES_PRE_LINE, " ", (INT8 *)StrPkgHdr, StrPkgHdr->HdrSize); | |
| } | |
| } | |
| VOID | |
| StrPkgWirteArrayLength ( | |
| IN FILE *File, | |
| IN UINT32 PkgNumber, | |
| IN EFI_HII_STRING_PACKAGE_HDR **PkgHdr | |
| ) | |
| { | |
| UINT32 Index; | |
| UINT32 ArrayLen; | |
| ArrayLen = sizeof (UINT32); | |
| for (Index = 0; Index < PkgNumber; Index++) { | |
| if (PkgHdr[Index] != NULL) { | |
| ArrayLen += PkgHdr[Index]->Header.Length; | |
| } | |
| } | |
| fprintf (File, "\n // STRING ARRAY LENGTH\n"); | |
| WriteBlockLine(File, BYTES_PRE_LINE, " ", (UINT8 *)&ArrayLen, sizeof (UINT32)); | |
| } | |
| VOID | |
| StrPkgWriteBlkListCFile ( | |
| IN FILE *File, | |
| IN SPkgBlkBuffer *BlkList, | |
| IN BOOLEAN WriteEnd | |
| ) | |
| { | |
| SPkgBlkBuffer *Buffer; | |
| fprintf (File, "\n\n // PACKAGE DATA\n"); | |
| while (BlkList != NULL) { | |
| Buffer = BlkList; | |
| BlkList = BlkList->mNext; | |
| if ((Buffer->mNext == NULL) && (WriteEnd == TRUE)) { | |
| if (Buffer->mBlkBuffer != NULL) { | |
| WriteBlockEnd (File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize); | |
| } | |
| } else { | |
| if (Buffer->mBlkBuffer != NULL) { | |
| WriteBlockLine(File, BYTES_PRE_LINE, " ", Buffer->mBlkBuffer, Buffer->mBlkSize); | |
| } | |
| } | |
| } | |
| } | |
| VOID | |
| StrPkgWriteHdrBinary ( | |
| IN FILE *File, | |
| IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr | |
| ) | |
| { | |
| fwrite (StrPkgHdr, StrPkgHdr->HdrSize, 1, File); | |
| } | |
| VOID | |
| StrPkgWriteBlkListBinary ( | |
| IN FILE *File, | |
| IN SPkgBlkBuffer *BlkList | |
| ) | |
| { | |
| SPkgBlkBuffer *Buffer; | |
| while (BlkList != NULL) { | |
| Buffer = BlkList; | |
| BlkList = BlkList->mNext; | |
| if (Buffer->mBlkBuffer != NULL) { | |
| fwrite (Buffer->mBlkBuffer, Buffer->mBlkSize, 1, File); | |
| } | |
| } | |
| } | |
| STATUS | |
| StringDBGenStrPkgHdrAndBlkList ( | |
| IN LANGUAGE_LIST *Lang, | |
| OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr, | |
| OUT SPkgBlkBuffer **BlkList | |
| ) | |
| { | |
| STATUS Status; | |
| UINT32 StringIndex; | |
| EFI_STRING_ID StringIdCurrent; | |
| EFI_STRING_ID SkipIdCount; | |
| UINT32 BlkSize = 0; | |
| EFI_HII_SIBT_STRING_UCS2_BLOCK *StrUCS2Blk = NULL; | |
| EFI_HII_SIBT_SKIP2_BLOCK *StrSKIP2Blk = NULL; | |
| STRING_IDENTIFIER *StringIdentifier = NULL; | |
| EFI_HII_SIBT_END_BLOCK *EndBlk = NULL; | |
| UINT32 PkgBlkSize = 0; | |
| SPkgBlkBuffer *PkgBufferListHead = NULL; | |
| SPkgBlkBuffer *PkgBufferListTail = NULL; | |
| if ((Lang == NULL) || (StrPkgHdr == NULL) || (BlkList == NULL)) { | |
| return STATUS_ERROR; | |
| } | |
| // | |
| // Assign index values to the string identifiers | |
| // | |
| StringDBAssignStringIndexes (); | |
| StringIdCurrent = EFI_STRING_ID_BEGIN; | |
| SkipIdCount = 0; | |
| for (StringIndex = STRING_ID_PRINTABLE_LANGUAGE_NAME; StringIndex < mDBData.NumStringIdentifiersReferenced; StringIndex++) { | |
| if ((StringIdentifier = StringDBFindStringIdentifierByIndex (StringIndex)) == NULL) { | |
| Error (NULL, 0, 0, "internal error", "invalid string index 0x%X", StringIndex); | |
| goto ExportPackOut; | |
| } | |
| if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) { | |
| Status = BuildStringPkgUCS2Blk (StringIdCurrent, Lang->LanguageName, StringIdentifier->StringName, &StrUCS2Blk, &BlkSize); | |
| switch (Status) { | |
| case STATUS_ERROR: | |
| goto ExportPackOut; | |
| break; | |
| case STATUS_WARNING : | |
| SkipIdCount++; | |
| break; | |
| case STATUS_SUCCESS : | |
| if (SkipIdCount == 0) { | |
| if (StrPkgBlkBufferListAddTail ( | |
| StringIdCurrent, | |
| StringIdentifier->StringName, | |
| &PkgBufferListHead, | |
| &PkgBufferListTail, | |
| StrUCS2Blk, | |
| BlkSize | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| PkgBlkSize += BlkSize; | |
| } else { | |
| if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } else { | |
| if (StrPkgBlkBufferListAddTail ( | |
| StringIdCurrent, | |
| NULL, | |
| &PkgBufferListHead, | |
| &PkgBufferListTail, | |
| StrSKIP2Blk, | |
| sizeof (EFI_HII_SIBT_SKIP2_BLOCK) | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); | |
| SkipIdCount = 0; | |
| } | |
| if (StrPkgBlkBufferListAddTail ( | |
| StringIdCurrent, | |
| StringIdentifier->StringName, | |
| &PkgBufferListHead, | |
| &PkgBufferListTail, | |
| StrUCS2Blk, | |
| BlkSize | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| PkgBlkSize += BlkSize; | |
| } | |
| } | |
| } | |
| StringIdCurrent++; | |
| } | |
| if (SkipIdCount != 0) { | |
| if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } else { | |
| if (StrPkgBlkBufferListAddTail ( | |
| StringIdCurrent, | |
| NULL, | |
| &PkgBufferListHead, | |
| &PkgBufferListTail, | |
| StrSKIP2Blk, | |
| sizeof (EFI_HII_SIBT_SKIP2_BLOCK) | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK); | |
| SkipIdCount = 0; | |
| } | |
| } | |
| if (BuildStringPkgEndBlk (&EndBlk) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } else if (StrPkgBlkBufferListAddTail ( | |
| StringIdCurrent, | |
| NULL, | |
| &PkgBufferListHead, | |
| &PkgBufferListTail, | |
| EndBlk, | |
| sizeof (EFI_HII_SIBT_END_BLOCK) | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| StringIdCurrent++; | |
| PkgBlkSize += sizeof (EFI_HII_SIBT_END_BLOCK); | |
| if (BuildStringPkgHdr( | |
| Lang->LanguageName, | |
| Lang->SecondaryLanguageList, | |
| EFI_HII_PACKAGE_STRINGS, | |
| PkgBlkSize, | |
| StrPkgHdr | |
| ) != STATUS_SUCCESS) { | |
| goto ExportPackOut; | |
| } | |
| *BlkList = PkgBufferListHead; | |
| return STATUS_SUCCESS; | |
| ExportPackOut: | |
| StrPkgBlkBufferListFree(PkgBufferListHead); | |
| *BlkList = NULL; | |
| *StrPkgHdr = NULL; | |
| return STATUS_ERROR; | |
| } | |
| STATUS | |
| StringDBCreateHiiExportPack ( | |
| INT8 *FileName, | |
| WCHAR_STRING_LIST *LanguagesOfInterest | |
| ) | |
| { | |
| FILE *File; | |
| LANGUAGE_LIST *Lang; | |
| EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr; | |
| SPkgBlkBuffer *BlkList; | |
| WCHAR_STRING_LIST *LOIPtr; | |
| if (FileName == NULL) { | |
| return STATUS_ERROR; | |
| } | |
| if ((File = fopen (FileName, "wb")) == NULL) { | |
| Error (NULL, 0, 0, FileName, "failed to open output HII export file"); | |
| return STATUS_ERROR; | |
| } | |
| for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| for (LOIPtr = LanguagesOfInterest; LOIPtr != NULL; LOIPtr = LOIPtr->Next) { | |
| if (wcscmp (LOIPtr->Str, Lang->LanguageName) == 0) { | |
| break; | |
| } | |
| } | |
| if ((LanguagesOfInterest == NULL) || | |
| (LanguagesOfInterest != NULL && LOIPtr != NULL)) { | |
| if (StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr, &BlkList) != STATUS_SUCCESS) { | |
| fclose (File); | |
| return STATUS_SUCCESS; | |
| } | |
| StrPkgWriteHdrBinary (File, StrPkgHdr); | |
| StrPkgWriteBlkListBinary (File, BlkList); | |
| StrPkgHdrFree (StrPkgHdr); | |
| StrPkgBlkBufferListFree (BlkList); | |
| } | |
| } | |
| fclose (File); | |
| return STATUS_SUCCESS; | |
| } | |
| static const char *gSourceFileHeader[] = { | |
| "//", | |
| "// DO NOT EDIT -- auto-generated file", | |
| "//", | |
| "// This file is generated by the StrGather utility", | |
| "//", | |
| NULL | |
| }; | |
| STATUS | |
| StringDBDumpCStrings ( | |
| INT8 *BaseName, | |
| INT8 *FileName, | |
| WCHAR_STRING_LIST *LanguagesOfInterest | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FILE *File; | |
| LANGUAGE_LIST *Lang; | |
| EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr; | |
| SPkgBlkBuffer **BlkList; | |
| UINT32 Index; | |
| UINT32 LangNumber; | |
| WCHAR_STRING_LIST *LOIPtr; | |
| if ((BaseName == NULL) || (FileName == NULL)) { | |
| return STATUS_ERROR; | |
| } | |
| if (mDBData.LanguageList == NULL) { | |
| return STATUS_SUCCESS; | |
| } | |
| for (LangNumber = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, LangNumber++) | |
| ; | |
| StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR **) malloc (sizeof (EFI_HII_STRING_PACKAGE_HDR *) * LangNumber); | |
| BlkList = (SPkgBlkBuffer **) malloc (sizeof (SPkgBlkBuffer *) * LangNumber); | |
| for (Index = 0; Index < LangNumber; Index++) { | |
| StrPkgHdr[Index] = NULL; | |
| BlkList[Index] = NULL; | |
| } | |
| for (Index = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) { | |
| for (LOIPtr = LanguagesOfInterest; LOIPtr != NULL; LOIPtr = LOIPtr->Next) { | |
| if (wcscmp (LOIPtr->Str, Lang->LanguageName) == 0) { | |
| break; | |
| } | |
| } | |
| if ((LanguagesOfInterest == NULL) || | |
| (LanguagesOfInterest != NULL && LOIPtr != NULL)) { | |
| Status = StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr[Index], &BlkList[Index]); | |
| Index++; | |
| if (EFI_ERROR(Status)) { | |
| free (StrPkgHdr); | |
| free (BlkList); | |
| return STATUS_ERROR; | |
| } | |
| } | |
| } | |
| // | |
| // Update LangNumber after filter | |
| // | |
| LangNumber = Index; | |
| if (LangNumber == 0) { | |
| free (StrPkgHdr); | |
| free (BlkList); | |
| return STATUS_SUCCESS; | |
| } | |
| if ((File = fopen (FileName, "w")) == NULL) { | |
| Error (NULL, 0, 0, FileName, "failed to open output C file - %s", FileName); | |
| return STATUS_ERROR; | |
| } | |
| for (Index = 0; gSourceFileHeader[Index] != NULL; Index++) { | |
| fprintf (File, "%s\n", gSourceFileHeader[Index]); | |
| } | |
| fprintf (File, "\nunsigned char %s[] = {\n", BaseName); | |
| // | |
| // Save the length of the string package array. | |
| // | |
| StrPkgWirteArrayLength (File, LangNumber, StrPkgHdr); | |
| for (Index = 0; Index < LangNumber; Index++) { | |
| StrPkgWriteHdrCFile (File, StrPkgHdr[Index]); | |
| StrPkgWriteBlkListCFile (File, BlkList[Index], (Index == LangNumber - 1) ? TRUE : FALSE); | |
| StrPkgHdrFree (StrPkgHdr[Index]); | |
| StrPkgBlkBufferListFree (BlkList[Index]); | |
| } | |
| fprintf (File, "\n};\n"); | |
| fclose (File); | |
| free (StrPkgHdr); | |
| free (BlkList); | |
| return STATUS_SUCCESS; | |
| } |