3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 String database implementation
27 #include <EfiUtilityMsgs.h>
29 #include "StrGather.h"
32 static STRING_DB_DATA mDBData
;
34 static const char *mSourceFileHeader
[] = {
36 "// DO NOT EDIT -- auto-generated file",
38 "// This file is generated by the string gather utility",
49 WCHAR_STRING_LIST
*LanguagesOfInterest
,
50 WCHAR_MATCHING_STRING_LIST
*IndirectionList
55 StringDBFindStringIdentifierByName (
61 StringDBFindStringIdentifierByIndex (
67 StringDBWriteStandardFileHeader (
98 StringDBWriteStringIdentifier (
102 WCHAR
*IdentifierName
107 StringDBReadStringIdentifier (
113 StringDBWriteLanguageDefinition (
116 WCHAR
*PrintableLanguageName
,
117 WCHAR
*SecondaryLanguageList
122 StringDBReadLanguageDefinition (
128 StringDBWriteString (
145 StringDBReadGenericString (
153 StringDBWriteGenericString (
160 StringDBAssignStringIndexes (
164 /*****************************************************************************/
169 Constructor function for the string database handler.
179 StringDBConstructor (
183 memset ((char *) &mDBData
, 0, sizeof (STRING_DB_DATA
));
184 mDBData
.CurrentScope
= DuplicateString (L
"NULL");
187 /*****************************************************************************/
192 Destructor function for the string database handler.
206 LANGUAGE_LIST
*NextLang
;
207 STRING_LIST
*NextStr
;
208 STRING_IDENTIFIER
*NextIdentifier
;
210 // Close the database file if it's open
212 if (mDBData
.StringDBFptr
!= NULL
) {
213 fclose (mDBData
.StringDBFptr
);
214 mDBData
.StringDBFptr
= NULL
;
217 // If we've allocated any strings/languages, free them up
219 while (mDBData
.LanguageList
!= NULL
) {
220 NextLang
= mDBData
.LanguageList
->Next
;
222 // Free up all strings for this language
224 while (mDBData
.LanguageList
->String
!= NULL
) {
225 NextStr
= mDBData
.LanguageList
->String
->Next
;
226 FREE (mDBData
.LanguageList
->String
->Str
);
227 FREE (mDBData
.LanguageList
->String
);
228 mDBData
.LanguageList
->String
= NextStr
;
231 FREE (mDBData
.LanguageList
->SecondaryLanguageList
);
232 FREE (mDBData
.LanguageList
->PrintableLanguageName
);
233 FREE (mDBData
.LanguageList
);
234 mDBData
.LanguageList
= NextLang
;
237 // Free up string identifiers
239 while (mDBData
.StringIdentifier
!= NULL
) {
240 NextIdentifier
= mDBData
.StringIdentifier
->Next
;
241 FREE (mDBData
.StringIdentifier
->StringName
);
242 FREE (mDBData
.StringIdentifier
);
243 mDBData
.StringIdentifier
= NextIdentifier
;
248 if (mDBData
.StringDBFileName
!= NULL
) {
249 FREE (mDBData
.StringDBFileName
);
250 mDBData
.StringDBFileName
= NULL
;
253 // We save a copy of the scope, so free it up if we
256 if (mDBData
.CurrentScope
!= NULL
) {
257 FREE (mDBData
.CurrentScope
);
258 mDBData
.CurrentScope
= NULL
;
262 /*****************************************************************************/
264 StringDBDumpStringDefines (
270 STRING_IDENTIFIER
*Identifier
;
271 INT8 CopyBaseName
[100];
273 const INT8
*StrDefHeader
[] = {
274 "#ifndef _%s_STRINGS_DEFINE_H_\n",
275 "#define _%s_STRINGS_DEFINE_H_\n\n",
279 if ((Fptr
= fopen (FileName
, "w")) == NULL
) {
280 Error (NULL
, 0, 0, FileName
, "failed to open output string defines file");
284 // Get the base source filename and convert to uppercase.
286 if (sizeof (CopyBaseName
) <= strlen (BaseName
) + 1) {
287 Error (NULL
, 0, 0, "application error", "StringDBDumpStringDefines() string length insufficient");
291 strcpy (CopyBaseName
, BaseName
);
292 for (Index
= 0; CopyBaseName
[Index
] != 0; Index
++) {
293 if (islower (CopyBaseName
[Index
])) {
294 CopyBaseName
[Index
] = (INT8
) toupper (CopyBaseName
[Index
]);
298 // Assign index values to the string identifiers
300 StringDBAssignStringIndexes ();
302 // Write the standard header to the output file, and then the
303 // protective #ifndef.
305 StringDBWriteStandardFileHeader (Fptr
);
306 for (Index
= 0; StrDefHeader
[Index
] != NULL
; Index
++) {
307 fprintf (Fptr
, StrDefHeader
[Index
], CopyBaseName
);
310 // Print all the #defines for the string identifiers. Print identifiers
311 // whose names start with '$' as comments. Add comments for string
312 // identifiers not used as well.
314 Identifier
= mDBData
.StringIdentifier
;
315 while (Identifier
!= NULL
) {
316 if (Identifier
->StringName
[0] == L
'$') {
317 fprintf (Fptr
, "// ");
320 if (Identifier
->Flags
& STRING_FLAGS_REFERENCED
) {
321 fprintf (Fptr
, "#define %-40S 0x%04X\n", Identifier
->StringName
, Identifier
->Index
);
323 fprintf (Fptr
, "//#define %-40S 0x%04X // not referenced\n", Identifier
->StringName
, Identifier
->Index
);
326 Identifier
= Identifier
->Next
;
329 fprintf (Fptr
, "\n#endif\n");
331 return STATUS_SUCCESS
;
334 /*****************************************************************************/
340 Add a string identifier to the database.
344 StringName - name of the string identifier. For example "STR_MY_STRING"
345 NewId - if an ID has been assigned
346 Flags - characteristics for the identifier
354 StringDBAddStringIdentifier (
360 STRING_IDENTIFIER
*StringIdentifier
;
363 // If it was already used for some other language, then we don't
364 // need to add it. But set it to the current string identifier.
365 // The referenced bit is sticky.
367 Status
= STATUS_SUCCESS
;
368 StringIdentifier
= StringDBFindStringIdentifierByName (StringName
);
369 if (StringIdentifier
!= NULL
) {
370 if (Flags
& STRING_FLAGS_REFERENCED
) {
371 StringIdentifier
->Flags
|= STRING_FLAGS_REFERENCED
;
374 mDBData
.CurrentStringIdentifier
= StringIdentifier
;
375 *NewId
= (UINT16
) StringIdentifier
->Index
;
379 StringIdentifier
= (STRING_IDENTIFIER
*) MALLOC (sizeof (STRING_IDENTIFIER
));
380 if (StringIdentifier
== NULL
) {
381 Error (NULL
, 0, 0, NULL
, "memory allocation error");
385 memset ((char *) StringIdentifier
, 0, sizeof (STRING_IDENTIFIER
));
386 StringIdentifier
->StringName
= (WCHAR
*) malloc ((wcslen (StringName
) + 1) * sizeof (WCHAR
));
387 if (StringIdentifier
->StringName
== NULL
) {
388 Error (NULL
, 0, 0, NULL
, "memory allocation error");
392 wcscpy (StringIdentifier
->StringName
, StringName
);
393 if (*NewId
!= STRING_ID_INVALID
) {
394 StringIdentifier
->Index
= *NewId
;
395 StringIdentifier
->Flags
|= STRING_FLAGS_INDEX_ASSIGNED
;
396 if (mDBData
.NumStringIdentifiers
<= StringIdentifier
->Index
) {
397 mDBData
.NumStringIdentifiers
= StringIdentifier
->Index
+ 1;
400 StringIdentifier
->Index
= mDBData
.NumStringIdentifiers
++;
403 StringIdentifier
->Flags
|= Flags
;
405 // Add it to our list of string identifiers
407 if (mDBData
.StringIdentifier
== NULL
) {
408 mDBData
.StringIdentifier
= StringIdentifier
;
410 mDBData
.LastStringIdentifier
->Next
= StringIdentifier
;
413 mDBData
.LastStringIdentifier
= StringIdentifier
;
414 mDBData
.CurrentStringIdentifier
= StringIdentifier
;
415 *NewId
= (UINT16
) StringIdentifier
->Index
;
419 /*****************************************************************************/
425 Add a new string to the database.
429 LanguageName - "eng" or "spa" language name
430 StringName - "STR_MY_TEXT" string name
431 Scope - from the #scope statements in the string file
432 Format - if we should format the string
433 Flags - characteristic flags for the string
441 Several of the fields can be "inherited" from the previous calls to
442 our database functions. For example, if scope is NULL here, then
443 we'll use the previous setting.
460 STRING_IDENTIFIER
*StringIdentifier
;
463 // If they specified a language, make sure they've defined it already
464 // via a #langdef statement. Otherwise use the current default language.
466 if (LanguageName
!= NULL
) {
467 Lang
= StringDBFindLanguageList (LanguageName
);
469 ParserError (0, "language not defined", "%S", LanguageName
);
472 StringDBSetCurrentLanguage (LanguageName
);
475 Lang
= mDBData
.CurrentLanguage
;
478 // Have to call SetLanguage() first
480 ParserError (0, "no language defined", "%S", StringName
);
485 // If they didn't define a string identifier, use the last string identifier
488 if (StringName
== NULL
) {
489 StringName
= mDBData
.CurrentStringIdentifier
->StringName
;
490 if (StringName
== NULL
) {
491 ParserError (0, "no string identifier previously specified", NULL
);
496 // If scope was not specified, use the default setting
499 Scope
= DuplicateString (Scope
);
501 Scope
= DuplicateString (mDBData
.CurrentScope
);
504 // printf ("Adding string: %S.%S.%S\n", Lang->LanguageName, StringName, Scope);
506 // Check for duplicates for this Language.StringName.Scope. Allow multiple
507 // definitions of the language name and printable language name, since the
508 // user does not specifically define them.
510 if (StringDBFindString (Lang
->LanguageName
, StringName
, Scope
, NULL
, NULL
) != NULL
) {
511 if ((wcscmp (StringName
, LANGUAGE_NAME_STRING_NAME
) == 0) &&
512 (wcscmp (StringName
, PRINTABLE_LANGUAGE_NAME_STRING_NAME
) == 0)
516 "string multiply defined",
517 "Language.Name.Scope = %S.%S.%S",
526 StringIndex
= STRING_ID_INVALID
;
527 if (StringDBAddStringIdentifier (StringName
, &StringIndex
, Flags
) != STATUS_SUCCESS
) {
531 StringIdentifier
= StringDBFindStringIdentifierByName (StringName
);
533 // Add this string to the end of the strings for this language.
535 Str
= (STRING_LIST
*) malloc (sizeof (STRING_LIST
));
537 Error (NULL
, 0, 0, NULL
, "memory allocation error");
541 memset ((char *) Str
, 0, sizeof (STRING_LIST
));
542 Size
= (wcslen (String
) + 1) * sizeof (WCHAR
);
545 Str
->StringName
= StringIdentifier
->StringName
;
546 Str
->LanguageName
= DuplicateString (LanguageName
);
547 Str
->Str
= (WCHAR
*) MALLOC (Size
);
548 if (Str
->Str
== NULL
) {
549 Error (NULL
, 0, 0, NULL
, "memory allocation error");
553 // If not formatting, just copy the string.
555 wcscpy (Str
->Str
, String
);
557 StringDBFormatString (Str
->Str
);
560 // Size may change after formatting. We set the size to
561 // the actual size of the string, including the null for
562 // easier processing later.
564 Str
->Size
= (wcslen (Str
->Str
) + 1) * sizeof (WCHAR
);
565 if (Lang
->String
== NULL
) {
568 Lang
->LastString
->Next
= Str
;
571 Lang
->LastString
= Str
;
572 return STATUS_SUCCESS
;
575 /*****************************************************************************/
581 Given a language name, see if a language list for it has been defined
585 LanguageName - like "eng"
589 A pointer to the language list
593 StringDBFindLanguageList (
599 Lang
= mDBData
.LanguageList
;
600 while (Lang
!= NULL
) {
601 if (wcscmp (LanguageName
, Lang
->LanguageName
) == 0) {
611 /*****************************************************************************/
613 StringDBSetCurrentLanguage (
619 Lang
= StringDBFindLanguageList (LanguageName
);
621 ParserError (0, "language not previously defined", "%S", LanguageName
);
625 mDBData
.CurrentLanguage
= Lang
;
626 return STATUS_SUCCESS
;
629 /*****************************************************************************/
631 StringDBAddLanguage (
633 WCHAR
*PrintableLanguageName
,
634 WCHAR
*SecondaryLanguageList
639 // Check for redefinitions
641 Lang
= StringDBFindLanguageList (LanguageName
);
644 // Better be the same printable name
646 if (wcscmp (PrintableLanguageName
, Lang
->PrintableLanguageName
) != 0) {
649 "language redefinition",
652 Lang
->PrintableLanguageName
,
654 PrintableLanguageName
659 // ParserWarning (0, "benign language redefinition", "%S", PrintableLanguageName);
660 // return STATUS_WARNING;
665 // Allocate memory to keep track of this new language
667 Lang
= (LANGUAGE_LIST
*) malloc (sizeof (LANGUAGE_LIST
));
669 Error (NULL
, 0, 0, NULL
, "memory allocation error");
673 memset ((char *) Lang
, 0, sizeof (LANGUAGE_LIST
));
675 // Save the language name, then allocate memory to save the
676 // printable language name
678 Lang
->LanguageName
= (WCHAR
*) malloc ((wcslen (LanguageName
) + 1) * 2);
679 if (Lang
->LanguageName
== NULL
) {
680 Error (NULL
, 0, 0, NULL
, "memory allocation error");
683 wcscpy (Lang
->LanguageName
, LanguageName
);
684 Lang
->PrintableLanguageName
= (WCHAR
*) malloc ((wcslen (PrintableLanguageName
) + 1) * sizeof (WCHAR
));
685 if (Lang
->PrintableLanguageName
== NULL
) {
686 Error (NULL
, 0, 0, NULL
, "memory allocation error");
687 FREE (Lang
->LanguageName
);
690 wcscpy (Lang
->PrintableLanguageName
, PrintableLanguageName
);
692 if (SecondaryLanguageList
!= NULL
) {
693 Lang
->SecondaryLanguageList
= (WCHAR
*) malloc ((wcslen (SecondaryLanguageList
) + 1) * sizeof (WCHAR
));
694 if (Lang
->SecondaryLanguageList
== NULL
) {
695 Error (NULL
, 0, 0, NULL
, "memory allocation error");
696 FREE (Lang
->PrintableLanguageName
);
697 FREE (Lang
->LanguageName
);
700 wcscpy (Lang
->SecondaryLanguageList
, SecondaryLanguageList
);
702 Lang
->SecondaryLanguageList
= NULL
;
705 if (mDBData
.LanguageList
== NULL
) {
706 mDBData
.LanguageList
= Lang
;
708 mDBData
.LastLanguageList
->Next
= Lang
;
711 mDBData
.LastLanguageList
= Lang
;
714 // Default is to make our active language this new one
716 StringDBSetCurrentLanguage (LanguageName
);
718 // The first two strings for any language are the language name,
719 // followed by the printable language name. Add them and set them
720 // to referenced so they never get stripped out.
724 LANGUAGE_NAME_STRING_NAME
,
728 STRING_FLAGS_REFERENCED
732 PRINTABLE_LANGUAGE_NAME_STRING_NAME
,
734 PrintableLanguageName
,
736 STRING_FLAGS_REFERENCED
738 return STATUS_SUCCESS
;
742 StringDBAddSecondaryLanguage (
744 WCHAR
*SecondaryLanguageList
749 Lang
= StringDBFindLanguageList (LanguageName
);
753 Lang
->SecondaryLanguageList
= WstrCatenate(Lang
->SecondaryLanguageList
, SecondaryLanguageList
);
754 return STATUS_SUCCESS
;
758 /*****************************************************************************/
761 StringDBFindStringIdentifierByName (
765 STRING_IDENTIFIER
*Identifier
;
767 Identifier
= mDBData
.StringIdentifier
;
768 while (Identifier
!= NULL
) {
769 if (wcscmp (StringName
, Identifier
->StringName
) == 0) {
773 Identifier
= Identifier
->Next
;
781 StringDBFindStringIdentifierByIndex (
785 STRING_IDENTIFIER
*Identifier
;
787 Identifier
= mDBData
.StringIdentifier
;
788 while (Identifier
!= NULL
) {
789 if (Identifier
->Index
== StringIndex
) {
793 Identifier
= Identifier
->Next
;
799 /*****************************************************************************/
802 StringDBWriteStandardFileHeader (
807 for (TempIndex
= 0; mSourceFileHeader
[TempIndex
] != NULL
; TempIndex
++) {
808 fprintf (OutFptr
, "%s\n", mSourceFileHeader
[TempIndex
]);
812 /*****************************************************************************/
818 Given a Unicode string from an input file, reformat the string to replace
819 backslash control sequences with the appropriate encoding.
823 String - pointer to string to reformat
831 StringDBFormatString (
840 // Go through the string and process any formatting characters
845 if (*From
== UNICODE_BACKSLASH
) {
847 // First look for \wide and replace with the appropriate control character. Note that
848 // when you have "define STR L"ABC"", then sizeof(ABC) is 8 because the null char is
849 // counted. Make adjustments for this. We advance From below, so subtract 2 each time.
851 if (wcsncmp (From
, UNICODE_WIDE_STRING
, sizeof (UNICODE_WIDE_STRING
) / sizeof (WCHAR
) - 1) == 0) {
853 From
+= sizeof (UNICODE_WIDE_STRING
) / sizeof (WCHAR
) - 2;
854 } else if (wcsncmp (From
, UNICODE_NARROW_STRING
, sizeof (UNICODE_NARROW_STRING
) / sizeof (WCHAR
) - 1) == 0) {
859 From
+= sizeof (UNICODE_NARROW_STRING
) / sizeof (WCHAR
) - 2;
860 } else if (wcsncmp (From
, UNICODE_NBR_STRING
, sizeof (UNICODE_NBR_STRING
) / sizeof (WCHAR
) - 1) == 0) {
864 *To
= NON_BREAKING_CHAR
;
865 From
+= sizeof (UNICODE_NBR_STRING
) / sizeof (WCHAR
) - 2;
866 } else if (wcsncmp (From
, UNICODE_BR_STRING
, sizeof (UNICODE_BR_STRING
) / sizeof (WCHAR
) - 1) == 0) {
868 // Found: \br -- pass through untouched
873 // Standard one-character control sequences such as \n, \r, \\, or \x
877 case ASCII_TO_UNICODE ('n'):
886 case ASCII_TO_UNICODE ('r'):
893 case UNICODE_BACKSLASH
:
894 *To
= UNICODE_BACKSLASH
;
900 case ASCII_TO_UNICODE ('t'):
905 // embedded double-quote
907 case UNICODE_DOUBLE_QUOTE
:
908 *To
= UNICODE_DOUBLE_QUOTE
;
912 // Hex Unicode character \x1234. We'll process up to 4 hex characters
914 case ASCII_TO_UNICODE ('x'):
916 for (HexNibbles
= 0; HexNibbles
< 4; HexNibbles
++) {
917 if ((From
[1] >= UNICODE_0
) && (From
[1] <= UNICODE_9
)) {
918 HexValue
= (HexValue
<< 4) | (From
[1] - UNICODE_0
);
919 } else if ((From
[1] >= UNICODE_a
) && (From
[1] <= UNICODE_f
)) {
920 HexValue
= (HexValue
<< 4) | (10 + From
[1] - UNICODE_a
);
921 } else if ((From
[1] >= UNICODE_A
) && (From
[1] <= UNICODE_F
)) {
922 HexValue
= (HexValue
<< 4) | (10 + From
[1] - UNICODE_A
);
930 if (HexNibbles
== 0) {
933 "expected at least one valid hex digit with \\x escaped character in string",
944 ParserWarning (0, "invalid escaped character in string", "\\%C", *From
);
959 /*****************************************************************************/
961 StringDBReadDatabase (
963 BOOLEAN IgnoreIfNotExist
,
967 STRING_DB_HEADER DbHeader
;
970 DB_DATA_ITEM_HEADER DataItemHeader
;
972 Status
= STATUS_SUCCESS
;
976 // fprintf (stdout, "Reading database file %s\n", DBFileName);
979 // Try to open the input file
981 if ((DBFptr
= fopen (DBFileName
, "rb")) == NULL
) {
982 if (IgnoreIfNotExist
) {
983 return STATUS_SUCCESS
;
986 Error (NULL
, 0, 0, DBFileName
, "failed to open input database file for reading");
990 // Read and verify the database header
992 if (fread ((void *) &DbHeader
, sizeof (STRING_DB_HEADER
), 1, DBFptr
) != 1) {
993 Error (NULL
, 0, 0, DBFileName
, "failed to read header from database file");
994 Status
= STATUS_ERROR
;
998 if (DbHeader
.Key
!= STRING_DB_KEY
) {
999 Error (NULL
, 0, 0, DBFileName
, "invalid header in database file");
1000 Status
= STATUS_ERROR
;
1004 if ((DbHeader
.Version
& STRING_DB_MAJOR_VERSION_MASK
) != (STRING_DB_VERSION
& STRING_DB_MAJOR_VERSION_MASK
)) {
1005 Error (NULL
, 0, 0, DBFileName
, "incompatible database file version -- rebuild clean");
1006 Status
= STATUS_ERROR
;
1010 // Read remaining items
1012 while (fread (&DataItemHeader
, sizeof (DataItemHeader
), 1, DBFptr
) == 1) {
1013 switch (DataItemHeader
.DataType
) {
1014 case DB_DATA_TYPE_STRING_IDENTIFIER
:
1015 StringDBReadStringIdentifier (DBFptr
);
1018 case DB_DATA_TYPE_LANGUAGE_DEFINITION
:
1019 StringDBReadLanguageDefinition (DBFptr
);
1022 case DB_DATA_TYPE_STRING_DEFINITION
:
1023 StringDBReadString (DBFptr
);
1031 "database corrupted",
1032 "invalid data item type 0x%X at offset 0x%X",
1033 (UINT32
) DataItemHeader
.DataType
,
1034 ftell (DBFptr
) - sizeof (DataItemHeader
)
1036 Status
= STATUS_ERROR
;
1042 if (DBFptr
!= NULL
) {
1049 /*****************************************************************************/
1053 Routine Description:
1055 Write everything we know to the output database file. Write:
1058 String identifiers[]
1063 DBFileName - name of the file to write to
1064 Verbose - for debug purposes, print info messages along the way.
1072 StringDBWriteDatabase (
1077 STRING_DB_HEADER DbHeader
;
1080 LANGUAGE_LIST
*Lang
;
1081 STRING_IDENTIFIER
*StringIdentifier
;
1082 STRING_LIST
*StrList
;
1086 fprintf (stdout
, "Writing database %s\n", DBFileName
);
1089 if ((DBFptr
= fopen (DBFileName
, "wb")) == NULL
) {
1090 Error (NULL
, 0, 0, DBFileName
, "failed to open output database file for writing");
1091 return STATUS_ERROR
;
1094 // Fill in and write the database header
1096 memset (&DbHeader
, 0, sizeof (STRING_DB_HEADER
));
1097 DbHeader
.HeaderSize
= sizeof (STRING_DB_HEADER
);
1098 DbHeader
.Key
= STRING_DB_KEY
;
1099 DbHeader
.Version
= STRING_DB_VERSION
;
1101 // Count the number of languages we have
1103 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1104 DbHeader
.NumLanguages
++;
1107 // Count up how many string identifiers we have, and total up the
1108 // size of the names plus the size of the flags field we will
1111 DbHeader
.NumStringIdenfiers
= mDBData
.NumStringIdentifiers
;
1112 StringIdentifier
= mDBData
.StringIdentifier
;
1113 for (Counter
= 0; Counter
< mDBData
.NumStringIdentifiers
; Counter
++) {
1114 StrLen
= wcslen (StringIdentifier
->StringName
) + 1;
1115 DbHeader
.StringIdentifiersSize
+= StrLen
* sizeof (WCHAR
) + sizeof (StringIdentifier
->Flags
);
1116 StringIdentifier
= StringIdentifier
->Next
;
1122 fwrite (&DbHeader
, sizeof (STRING_DB_HEADER
), 1, DBFptr
);
1124 fprintf (stdout
, " Number of string identifiers 0x%04X\n", DbHeader
.NumStringIdenfiers
);
1125 fprintf (stdout
, " Number of languages %d\n", DbHeader
.NumLanguages
);
1128 // Write the string identifiers
1130 for (StringIdentifier
= mDBData
.StringIdentifier
; StringIdentifier
!= NULL
; StringIdentifier
= StringIdentifier
->Next
) {
1131 StringDBWriteStringIdentifier (
1133 (UINT16
) StringIdentifier
->Index
,
1134 StringIdentifier
->Flags
,
1135 StringIdentifier
->StringName
1139 // Now write all the strings for each language
1141 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1142 StringDBWriteLanguageDefinition (DBFptr
, Lang
->LanguageName
, Lang
->PrintableLanguageName
, Lang
->SecondaryLanguageList
);
1143 for (StrList
= Lang
->String
; StrList
!= NULL
; StrList
= StrList
->Next
) {
1144 StringDBWriteString (
1148 StrList
->StringName
,
1156 return STATUS_SUCCESS
;
1160 StringDBSetStringReferenced (
1161 INT8
*StringIdentifierName
,
1162 BOOLEAN IgnoreNotFound
1165 STRING_IDENTIFIER
*Id
;
1169 // See if it's already been defined.
1171 Status
= STATUS_SUCCESS
;
1172 WName
= (WCHAR
*) malloc ((strlen (StringIdentifierName
) + 1) * sizeof (WCHAR
));
1174 swprintf (WName
, (strlen (StringIdentifierName
) + 1) * sizeof (WCHAR
), L
"%S", StringIdentifierName
);
1176 swprintf (WName
, L
"%S", StringIdentifierName
);
1178 Id
= StringDBFindStringIdentifierByName (WName
);
1180 Id
->Flags
|= STRING_FLAGS_REFERENCED
;
1182 if (IgnoreNotFound
== 0) {
1183 ParserWarning (0, StringIdentifierName
, "string identifier not found in database");
1184 Status
= STATUS_WARNING
;
1192 /*****************************************************************************/
1196 Routine Description:
1198 Dump the contents of a database to an output unicode file.
1202 DBFileName - name of the pre-existing database file to read
1203 OutputFileName - name of the file to dump the database contents to
1204 Verbose - for printing of additional info useful for debugging
1212 There's some issue with the unicode printing routines. Therefore to
1213 write to the output file properly, open it as binary and use fwrite.
1214 Ideally we could open it with just L"w" and use fwprintf().
1218 StringDBDumpDatabase (
1220 INT8
*OutputFileName
,
1224 LANGUAGE_LIST
*Lang
;
1225 STRING_IDENTIFIER
*StringIdentifier
;
1226 STRING_LIST
*StrList
;
1229 WCHAR
*WOutputFileName
;
1234 // This function assumes the database has already been read, and
1235 // we're just dumping our internal data structures to a unicode file.
1238 fprintf (stdout
, "Dumping database file %s\n", DBFileName
);
1241 WOutputFileName
= AsciiToWchar (OutputFileName
);
1242 OutFptr
= _wfopen (WOutputFileName
, L
"wb");
1243 free (WOutputFileName
);
1244 if (OutFptr
== NULL
) {
1245 Error (NULL
, 0, 0, OutputFileName
, "failed to open output file for writing");
1246 return STATUS_ERROR
;
1249 WChar
= UNICODE_FILE_START
;
1250 fwrite (&WChar
, sizeof (WCHAR
), 1, OutFptr
);
1251 CrLf
[1] = UNICODE_LF
;
1252 CrLf
[0] = UNICODE_CR
;
1254 // The default control character is '/'. Make it '#' by writing
1255 // "/=#" to the output file.
1258 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"/=#");
1260 swprintf (Line
, L
"/=#");
1262 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1263 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1264 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1266 // Dump all the string identifiers and their values
1268 StringDBAssignStringIndexes ();
1269 for (StringIdentifier
= mDBData
.StringIdentifier
; StringIdentifier
!= NULL
; StringIdentifier
= StringIdentifier
->Next
) {
1271 // Write the "#define " string
1273 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
1277 wcslen(Line
) * sizeof (WCHAR
),
1278 L
"%s %-60.60s 0x%04X",
1280 StringIdentifier
->StringName
,
1281 StringIdentifier
->Index
1286 L
"%s %-60.60s 0x%04X",
1288 StringIdentifier
->StringName
,
1289 StringIdentifier
->Index
1296 wcslen(Line
) * sizeof (WCHAR
),
1297 L
"%s %-60.60s 0x%04X // NOT REFERENCED",
1299 StringIdentifier
->StringName
,
1300 StringIdentifier
->Index
1305 L
"%s %-60.60s 0x%04X // NOT REFERENCED",
1307 StringIdentifier
->StringName
,
1308 StringIdentifier
->Index
1313 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1314 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1317 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1319 // Now write all the strings for each language.
1321 WChar
= UNICODE_DOUBLE_QUOTE
;
1323 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1324 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1326 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"#langdef %s \"%s\"", Lang
->LanguageName
, Lang
->PrintableLanguageName
);
1328 swprintf (Line
, L
"#langdef %s \"%s\"", Lang
->LanguageName
, Lang
->PrintableLanguageName
);
1330 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1331 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1332 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1334 // Now the strings (in double-quotes) for this language. Write
1335 // #string STR_NAME #language eng "string"
1337 for (StrList
= Lang
->String
; StrList
!= NULL
; StrList
= StrList
->Next
) {
1339 // Print the internal flags for debug
1342 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"// flags=0x%02X", (UINT32
) StrList
->Flags
);
1344 swprintf (Line
, L
"// flags=0x%02X", (UINT32
) StrList
->Flags
);
1346 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1347 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1349 // Print the scope if changed
1351 if ((Scope
== NULL
) || (wcscmp (Scope
, StrList
->Scope
) != 0)) {
1353 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"#scope %s", StrList
->Scope
);
1355 swprintf (Line
, L
"#scope %s", StrList
->Scope
);
1357 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1358 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1359 Scope
= StrList
->Scope
;
1365 wcslen(Line
) * sizeof (WCHAR
),
1366 L
"#string %-50.50s #language %s \"",
1367 StrList
->StringName
,
1373 L
"#string %-50.50s #language %s \"",
1374 StrList
->StringName
,
1378 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1379 fwrite (StrList
->Str
, StrList
->Size
- sizeof (WCHAR
), 1, OutFptr
);
1381 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"\"");
1383 swprintf (Line
, L
"\"");
1385 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1386 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1391 return STATUS_SUCCESS
;
1394 /*****************************************************************************/
1398 Routine Description:
1400 Given a primary language, a string identifier number, and a list of
1401 languages, find a secondary string.
1405 LanguageName - primary language, like "spa"
1406 StringId - string index value
1407 LanguageList - linked list of "eng", "spa+cat",...
1411 Pointer to a secondary string if found. NULL otherwise.
1415 Given: LanguageName "spa" and LanguageList "spa+cat", match the
1416 "spa" and extract the "cat" and see if there is a string defined
1422 StringDBWriteStringIdentifier (
1426 WCHAR
*IdentifierName
1429 DB_DATA_ITEM_HEADER Hdr
;
1430 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
1431 Hdr
.DataType
= DB_DATA_TYPE_STRING_IDENTIFIER
;
1432 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
1433 Error (NULL
, 0, 0, "failed to write string to output database file", NULL
);
1434 return STATUS_ERROR
;
1437 if (fwrite (&StringId
, sizeof (StringId
), 1, DBFptr
) != 1) {
1438 Error (NULL
, 0, 0, "failed to write StringId to output database", NULL
);
1439 return STATUS_ERROR
;
1442 if (fwrite (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1443 Error (NULL
, 0, 0, "failed to write StringId flags to output database", NULL
);
1444 return STATUS_ERROR
;
1447 if (StringDBWriteGenericString (DBFptr
, IdentifierName
) != STATUS_SUCCESS
) {
1448 return STATUS_ERROR
;
1451 return STATUS_SUCCESS
;
1456 StringDBReadStringIdentifier (
1460 WCHAR
*IdentifierName
;
1465 if (fread (&StringId
, sizeof (StringId
), 1, DBFptr
) != 1) {
1466 Error (NULL
, 0, 0, "failed to read StringId from database", NULL
);
1467 return STATUS_ERROR
;
1470 if (fread (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1471 Error (NULL
, 0, 0, "failed to read StringId flags from database", NULL
);
1472 return STATUS_ERROR
;
1475 if (StringDBReadGenericString (DBFptr
, &Size
, &IdentifierName
) != STATUS_SUCCESS
) {
1476 return STATUS_ERROR
;
1479 StringDBAddStringIdentifier (IdentifierName
, &StringId
, Flags
);
1481 // printf ("STRID: 0x%04X %S\n", (UINT32)StringId, IdentifierName);
1483 FREE (IdentifierName
);
1484 return STATUS_SUCCESS
;
1489 StringDBWriteString (
1498 DB_DATA_ITEM_HEADER Hdr
;
1499 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
1500 Hdr
.DataType
= DB_DATA_TYPE_STRING_DEFINITION
;
1501 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
1502 Error (NULL
, 0, 0, "failed to write string header to output database file", NULL
);
1503 return STATUS_ERROR
;
1506 if (fwrite (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1507 Error (NULL
, 0, 0, "failed to write string flags to output database", NULL
);
1508 return STATUS_ERROR
;
1511 if (StringDBWriteGenericString (DBFptr
, Language
) != STATUS_SUCCESS
) {
1512 return STATUS_ERROR
;
1515 if (StringDBWriteGenericString (DBFptr
, StringName
) != STATUS_SUCCESS
) {
1516 return STATUS_ERROR
;
1519 if (StringDBWriteGenericString (DBFptr
, Scope
) != STATUS_SUCCESS
) {
1520 return STATUS_ERROR
;
1523 if (StringDBWriteGenericString (DBFptr
, Str
) != STATUS_SUCCESS
) {
1524 return STATUS_ERROR
;
1527 // printf ("DBWriteString: %S.%S.%S\n", Language, StringName, Scope);
1529 return STATUS_SUCCESS
;
1534 StringDBReadString (
1545 if (fread (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1546 Error (NULL
, 0, 0, "failed to read string flags from database", NULL
);
1547 return STATUS_ERROR
;
1550 if (StringDBReadGenericString (DBFptr
, &Size
, &Language
) != STATUS_SUCCESS
) {
1551 return STATUS_ERROR
;
1554 if (StringDBReadGenericString (DBFptr
, &Size
, &StringName
) != STATUS_SUCCESS
) {
1555 return STATUS_ERROR
;
1558 if (StringDBReadGenericString (DBFptr
, &Size
, &Scope
) != STATUS_SUCCESS
) {
1559 return STATUS_ERROR
;
1562 if (StringDBReadGenericString (DBFptr
, &Size
, &Str
) != STATUS_SUCCESS
) {
1563 return STATUS_ERROR
;
1566 // If the first or second string (language name and printable language name),
1567 // then skip them. They're added via language definitions data items in
1570 if (StringName
[0] != L
'$') {
1571 StringDBAddString (Language
, StringName
, Scope
, Str
, FALSE
, Flags
);
1574 // printf ("DBReadString: %S.%S.%S\n", Language, StringName, Scope);
1582 if (Scope
!= NULL
) {
1586 return STATUS_SUCCESS
;
1591 StringDBWriteLanguageDefinition (
1593 WCHAR
*LanguageName
,
1594 WCHAR
*PrintableLanguageName
,
1595 WCHAR
*SecondaryLanguageList
1598 DB_DATA_ITEM_HEADER Hdr
;
1599 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
1600 Hdr
.DataType
= DB_DATA_TYPE_LANGUAGE_DEFINITION
;
1601 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
1602 Error (NULL
, 0, 0, "failed to write string to output database file", NULL
);
1603 return STATUS_ERROR
;
1606 if (StringDBWriteGenericString (DBFptr
, LanguageName
) != STATUS_SUCCESS
) {
1607 return STATUS_ERROR
;
1610 if (StringDBWriteGenericString (DBFptr
, PrintableLanguageName
) != STATUS_SUCCESS
) {
1611 return STATUS_ERROR
;
1614 if (StringDBWriteGenericString (DBFptr
, SecondaryLanguageList
) != STATUS_SUCCESS
) {
1615 return STATUS_ERROR
;
1618 return STATUS_SUCCESS
;
1623 StringDBReadLanguageDefinition (
1627 WCHAR
*LanguageName
= NULL
;
1628 WCHAR
*PrintableLanguageName
= NULL
;
1629 WCHAR
*SecondaryLanguageList
= NULL
;
1633 if (StringDBReadGenericString (DBFptr
, &Size
, &LanguageName
) != STATUS_SUCCESS
) {
1634 return STATUS_ERROR
;
1637 if (StringDBReadGenericString (DBFptr
, &Size
, &PrintableLanguageName
) != STATUS_SUCCESS
) {
1638 return STATUS_ERROR
;
1641 if (StringDBReadGenericString (DBFptr
, &Size
, &SecondaryLanguageList
) != STATUS_SUCCESS
) {
1642 return STATUS_ERROR
;
1646 // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);
1648 Status
= StringDBAddLanguage (LanguageName
, PrintableLanguageName
, SecondaryLanguageList
);
1649 FREE (LanguageName
);
1650 FREE (PrintableLanguageName
);
1651 FREE (SecondaryLanguageList
);
1655 // All unicode strings in the database consist of a UINT16 length
1656 // field, followed by the string itself. This routine reads one
1657 // of those and returns the info.
1661 StringDBReadGenericString (
1671 if (fread (&LSize
, sizeof (UINT16
), 1, DBFptr
) != 1) {
1672 Error (NULL
, 0, 0, "failed to read a string length field from the database", NULL
);
1673 return STATUS_ERROR
;
1676 if (fread (&Flags
, sizeof (UINT16
), 1, DBFptr
) != 1) {
1677 Error (NULL
, 0, 0, "failed to read a string flags field from the database", NULL
);
1678 return STATUS_ERROR
;
1681 LStr
= MALLOC (LSize
);
1683 Error (__FILE__
, __LINE__
, 0, "memory allocation failed reading the database", NULL
);
1684 return STATUS_ERROR
;
1687 if (fread (LStr
, sizeof (WCHAR
), (UINT32
) LSize
/ sizeof (WCHAR
), DBFptr
) != (UINT32
) LSize
/ sizeof (WCHAR
)) {
1688 Error (NULL
, 0, 0, "failed to read string from database", NULL
);
1689 Error (NULL
, 0, 0, "database read failure", "offset 0x%X", ftell (DBFptr
));
1691 return STATUS_ERROR
;
1694 // printf ("DBR: %S\n", LStr);
1696 // If the flags field indicated we were asked to write a NULL string, then
1697 // return them a NULL pointer.
1699 if (Flags
& STRING_FLAGS_UNDEFINED
) {
1707 return STATUS_SUCCESS
;
1712 StringDBWriteGenericString (
1719 WCHAR ZeroString
[1];
1721 // Strings in the database consist of a size UINT16 followed
1722 // by the string itself.
1727 Size
= sizeof (ZeroString
);
1728 Flags
= STRING_FLAGS_UNDEFINED
;
1731 Size
= (UINT16
) ((wcslen (Str
) + 1) * sizeof (WCHAR
));
1734 if (fwrite (&Size
, sizeof (UINT16
), 1, DBFptr
) != 1) {
1735 Error (NULL
, 0, 0, "failed to write string size to database", NULL
);
1736 return STATUS_ERROR
;
1739 if (fwrite (&Flags
, sizeof (UINT16
), 1, DBFptr
) != 1) {
1740 Error (NULL
, 0, 0, "failed to write string flags to database", NULL
);
1741 return STATUS_ERROR
;
1744 if (fwrite (Str
, sizeof (WCHAR
), Size
/ sizeof (WCHAR
), DBFptr
) != Size
/ sizeof (WCHAR
)) {
1745 Error (NULL
, 0, 0, "failed to write string to database", NULL
);
1746 return STATUS_ERROR
;
1749 return STATUS_SUCCESS
;
1754 StringDBFindString (
1755 WCHAR
*LanguageName
,
1758 WCHAR_STRING_LIST
*LanguagesOfInterest
,
1759 WCHAR_MATCHING_STRING_LIST
*IndirectionList
1762 LANGUAGE_LIST
*Lang
;
1763 STRING_LIST
*CurrString
;
1764 WCHAR_MATCHING_STRING_LIST
*IndListPtr
;
1765 WCHAR TempLangName
[LANGUAGE_IDENTIFIER_NAME_LEN
+ 1];
1769 // If we were given an indirection list, then see if one was specified for this
1770 // string identifier. That is to say, if the indirection says "STR_ID_MY_FAVORITE MyScope",
1771 // then if this string name matches one in the list, then do a lookup with the
1772 // specified scope and return that value.
1774 if (IndirectionList
!= NULL
) {
1775 for (IndListPtr
= IndirectionList
; IndListPtr
!= NULL
; IndListPtr
= IndListPtr
->Next
) {
1776 if (wcscmp (StringName
, IndListPtr
->Str1
) == 0) {
1777 CurrString
= StringDBFindString (LanguageName
, StringName
, IndListPtr
->Str2
, LanguagesOfInterest
, NULL
);
1778 if (CurrString
!= NULL
) {
1785 // First look for exact match language.stringname
1787 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1788 if (wcscmp (LanguageName
, Lang
->LanguageName
) == 0) {
1790 // Found language match. Try to find string name match
1792 for (CurrString
= Lang
->String
; CurrString
!= NULL
; CurrString
= CurrString
->Next
) {
1793 if (wcscmp (StringName
, CurrString
->StringName
) == 0) {
1795 // Found a string name match. See if we're supposed to find
1798 if (Scope
!= NULL
) {
1799 if (wcscmp (CurrString
->Scope
, Scope
) == 0) {
1810 // If we got here, then we didn't find a match. Look for secondary string
1811 // matches. That is to say, if we're processing "spa", and they requested
1812 // "spa+cat", then recursively call with "cat"
1814 while (LanguagesOfInterest
!= NULL
) {
1816 // If this is the language we're looking for, then process the
1817 // languages of interest list for it.
1819 if (wcsncmp (LanguageName
, LanguagesOfInterest
->Str
, LANGUAGE_IDENTIFIER_NAME_LEN
) == 0) {
1820 WCharPtr
= LanguagesOfInterest
->Str
+ LANGUAGE_IDENTIFIER_NAME_LEN
;
1823 // Double-check the length, though it should have been checked on the
1826 if (wcslen (WCharPtr
) < LANGUAGE_IDENTIFIER_NAME_LEN
) {
1827 Error (NULL
, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest
->Str
);
1831 wcsncpy (TempLangName
, WCharPtr
, LANGUAGE_IDENTIFIER_NAME_LEN
);
1832 TempLangName
[LANGUAGE_IDENTIFIER_NAME_LEN
] = 0;
1833 CurrString
= StringDBFindString (TempLangName
, StringName
, NULL
, NULL
, IndirectionList
);
1834 if (CurrString
!= NULL
) {
1838 WCharPtr
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
1842 LanguagesOfInterest
= LanguagesOfInterest
->Next
;
1854 // Free up existing scope memory.
1856 if (mDBData
.CurrentScope
!= NULL
) {
1857 FREE (mDBData
.CurrentScope
);
1860 mDBData
.CurrentScope
= DuplicateString (Scope
);
1861 return STATUS_SUCCESS
;
1864 // We typically don't assign index values to string identifiers
1865 // until we're ready to write out files. To reduce the size of
1866 // the output file, re-order the string identifiers to move any
1867 // unreferenced ones to the end. Then we'll walk the list
1868 // again to assign string indexes, keeping track of the last
1873 StringDBAssignStringIndexes (
1877 STRING_IDENTIFIER
*StrId
;
1878 STRING_IDENTIFIER
*FirstUsed
;
1879 STRING_IDENTIFIER
*LastUsed
;
1880 STRING_IDENTIFIER
*FirstUnused
;
1881 STRING_IDENTIFIER
*LastUnused
;
1883 UINT32 MaxReferenced
;
1886 // Create two lists -- used and unused. Then put them together with
1887 // the unused ones on the end.
1893 StrId
= mDBData
.StringIdentifier
;
1894 while (StrId
!= NULL
) {
1895 if ((StrId
->Flags
& STRING_FLAGS_REFERENCED
) == 0) {
1897 // Put it on the unused list
1899 if (FirstUnused
== NULL
) {
1900 FirstUnused
= StrId
;
1902 LastUnused
->Next
= StrId
;
1906 StrId
= StrId
->Next
;
1907 LastUnused
->Next
= NULL
;
1910 // Put it on the used list
1912 if (FirstUsed
== NULL
) {
1915 LastUsed
->Next
= StrId
;
1919 StrId
= StrId
->Next
;
1920 LastUsed
->Next
= NULL
;
1926 if (FirstUsed
!= NULL
) {
1927 mDBData
.StringIdentifier
= FirstUsed
;
1928 LastUsed
->Next
= FirstUnused
;
1930 mDBData
.StringIdentifier
= FirstUnused
;
1935 for (StrId
= mDBData
.StringIdentifier
; StrId
!= NULL
; StrId
= StrId
->Next
) {
1936 StrId
->Index
= Index
;
1938 if (StrId
->Flags
& STRING_FLAGS_REFERENCED
) {
1939 mDBData
.NumStringIdentifiersReferenced
= Index
;
1943 mDBData
.NumStringIdentifiers
= Index
;
1957 NewStr
= MALLOC ((wcslen (Str
) + 1) * sizeof (WCHAR
));
1958 if (NewStr
== NULL
) {
1959 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
1963 wcscpy (NewStr
, Str
);
1984 Len
+= wcslen (Src
);
1985 Dst
= (WCHAR
*) malloc ((Len
+ 1) * 2);
2009 Len
= strlen (Str
) + 1;
2010 NewStr
= (WCHAR
*) malloc (Len
* sizeof (WCHAR
));
2011 for (Ptr
= NewStr
; *Str
!= 0; Str
++, Ptr
++) {
2012 *Ptr
= (UINT16
) (UINT8
) *Str
;
2029 Len
= wcslen (Str
) + 1;
2030 NewStr
= (CHAR8
*) malloc (Len
* sizeof (CHAR8
));
2031 for (Ptr
= NewStr
; *Str
!= L
'\0'; Str
++, Ptr
++) {
2032 *Ptr
= (CHAR8
) *Str
;
2039 /*****************************************************************************/
2045 CHAR8
*RetStr
= (CHAR8
*)UnicodeStr
;
2046 CHAR8
*AsciiStr
= (CHAR8
*)UnicodeStr
;
2048 while (*UnicodeStr
!= '\0') {
2049 *AsciiStr
= (CHAR8
) *(UnicodeStr
++);
2059 IN WCHAR
*PrimaryLangName
,
2060 IN WCHAR
*SecondaryLangList
,
2062 IN UINT32 PkgBlkSize
,
2063 OUT EFI_HII_STRING_PACKAGE_HDR
**StrPkgHdr
2068 LangNameLen
= wcslen (PrimaryLangName
);
2069 if (SecondaryLangList
!= NULL
) {
2070 LangNameLen
+= wcslen (SecondaryLangList
) + 1;
2073 *StrPkgHdr
= (EFI_HII_STRING_PACKAGE_HDR
*) malloc(sizeof (EFI_HII_STRING_PACKAGE_HDR
) + LangNameLen
);
2074 if (*StrPkgHdr
== NULL
) {
2075 return STATUS_ERROR
;
2077 memset (*StrPkgHdr
, 0, sizeof (EFI_HII_STRING_PACKAGE_HDR
) + LangNameLen
);
2079 (*StrPkgHdr
)->Header
.Type
= Type
;
2080 (*StrPkgHdr
)->Header
.Length
= PkgBlkSize
+ sizeof (EFI_HII_STRING_PACKAGE_HDR
) + LangNameLen
;
2081 (*StrPkgHdr
)->HdrSize
= sizeof (EFI_HII_STRING_PACKAGE_HDR
) + LangNameLen
;
2082 (*StrPkgHdr
)->StringInfoOffset
= sizeof (EFI_HII_STRING_PACKAGE_HDR
) + LangNameLen
;
2083 (*StrPkgHdr
)->LanguageWindow
[0] = L
'\0';
2084 (*StrPkgHdr
)->LanguageName
= (EFI_STRING_ID
)1;
2086 strcpy ((*StrPkgHdr
)->Language
, unicode2ascii(PrimaryLangName
));
2087 if (SecondaryLangList
!= NULL
) {
2088 strcat ((*StrPkgHdr
)->Language
, ";");
2089 strcat ((*StrPkgHdr
)->Language
, unicode2ascii(SecondaryLangList
));
2092 #ifdef DEBUG_STRGATHER
2093 printf ("STR HDR\t %s\n", (*StrPkgHdr
)->Language
);
2095 return STATUS_SUCCESS
;
2099 BuildStringPkgUCS2Blk (
2100 IN EFI_STRING_ID StringId
,
2103 OUT EFI_HII_SIBT_STRING_UCS2_BLOCK
**StrBlk
,
2108 STRING_LIST
*CurrString
= NULL
;
2110 if ((LangName
== NULL
) || (StrName
== NULL
) || (StrBlk
== NULL
)) {
2111 return STATUS_ERROR
;
2117 CurrString
= StringDBFindString (LangName
, StrName
, NULL
, NULL
, NULL
);
2118 if (CurrString
== NULL
) {
2119 return STATUS_WARNING
;
2122 StrLen
= wcslen (CurrString
->Str
);
2123 *BlkSize
= sizeof (EFI_HII_SIBT_STRING_UCS2_BLOCK
) + StrLen
* 2;
2124 *StrBlk
= (EFI_HII_SIBT_STRING_UCS2_BLOCK
*) malloc (*BlkSize
);
2125 if (*StrBlk
== NULL
) {
2128 return STATUS_ERROR
;
2130 (*StrBlk
)->Header
.BlockType
= EFI_HII_SIBT_STRING_UCS2
;
2131 wcscpy((*StrBlk
)->StringText
, CurrString
->Str
);
2133 return STATUS_SUCCESS
;
2137 BuildStringPkgSKIP2Blk (
2138 IN EFI_STRING_ID SkipIdCount
,
2139 OUT EFI_HII_SIBT_SKIP2_BLOCK
**StrBlk
2142 if (StrBlk
== NULL
) {
2143 return STATUS_ERROR
;
2148 *StrBlk
= (EFI_HII_SIBT_SKIP2_BLOCK
*) malloc (sizeof (EFI_HII_SIBT_SKIP2_BLOCK
));
2149 if (*StrBlk
== NULL
) {
2151 return STATUS_ERROR
;
2153 (*StrBlk
)->Header
.BlockType
= EFI_HII_SIBT_SKIP2
;
2154 (*StrBlk
)->SkipCount
= SkipIdCount
;
2156 return STATUS_SUCCESS
;
2160 BuildStringPkgEndBlk (
2161 OUT EFI_HII_SIBT_END_BLOCK
**End
2164 *End
= (EFI_HII_SIBT_END_BLOCK
*) malloc (sizeof (EFI_HII_SIBT_END_BLOCK
));
2166 return STATUS_ERROR
;
2169 (*End
)->Header
.BlockType
= EFI_HII_SIBT_END
;
2170 return STATUS_SUCCESS
;
2175 Routine Description:
2177 Create an HII export string pack for the strings in our database.
2181 FileName - name of the output file to write
2190 StrPkgBlkBufferListAddTail (
2191 IN EFI_STRING_ID StringId
,
2193 IN SPkgBlkBuffer
**PkgBufferListHead
,
2194 IN SPkgBlkBuffer
**PkgBufferListTail
,
2199 SPkgBlkBuffer
*pNew
= NULL
;
2200 #ifdef DEBUG_STRGATHER
2201 EFI_HII_STRING_BLOCK
*SBlk
= (EFI_HII_STRING_BLOCK
*)Buffer
;
2204 if ((PkgBufferListHead
== NULL
) || (PkgBufferListTail
== NULL
)) {
2205 return STATUS_ERROR
;
2208 pNew
= (SPkgBlkBuffer
*) malloc (sizeof (SPkgBlkBuffer
));
2210 return STATUS_ERROR
;
2213 pNew
->mBlkBuffer
= Buffer
;
2214 pNew
->mBlkSize
= Size
;
2215 if ((*PkgBufferListTail
) == NULL
) {
2216 (*PkgBufferListHead
) = (*PkgBufferListTail
) = pNew
;
2218 (*PkgBufferListTail
)->mNext
= pNew
;
2219 (*PkgBufferListTail
) = pNew
;
2223 #ifdef DEBUG_STRGATHER
2224 switch (SBlk
->BlockType
) {
2225 case EFI_HII_SIBT_STRING_UCS2
:
2226 printf ("\tID: [%x] TYPE: [UCS2]\t NAME: %S \t STR: %S\n", StringId
, StrName
, ((EFI_HII_SIBT_STRING_UCS2_BLOCK
*)SBlk
)->StringText
);
2228 case EFI_HII_SIBT_SKIP2
:
2229 printf ("\tID: [NULL] TYPE: [SKIP2] SKIPCOUNT: [%x]\n", ((EFI_HII_SIBT_SKIP2_BLOCK
*)SBlk
)->SkipCount
);
2231 case EFI_HII_SIBT_END
:
2232 printf ("\tID: [%x] TYPE: [END]\n", StringId
);
2235 printf ("!!!!UNKNOWN STRING TYPE!!!\n");
2239 return STATUS_SUCCESS
;
2244 IN EFI_HII_STRING_PACKAGE_HDR
*StrPkgHdr
2247 if (StrPkgHdr
!= NULL
) {
2253 StrPkgBlkBufferListFree (
2254 IN SPkgBlkBuffer
*PkgBlkList
2257 SPkgBlkBuffer
*Buffer
;
2259 while (PkgBlkList
!= NULL
) {
2260 Buffer
= PkgBlkList
;
2261 PkgBlkList
= PkgBlkList
->mNext
;
2263 if (Buffer
->mBlkBuffer
!= NULL
) {
2264 free (Buffer
->mBlkBuffer
);
2273 IN UINT32 LineBytes
,
2274 IN INT8
*LineHeader
,
2281 if ((pFile
== NULL
) || (LineHeader
== NULL
) || (BlkBuf
== NULL
)) {
2285 for (Index
= 0; Index
< BlkSize
; Index
++) {
2286 if ((Index
% LineBytes
) == 0) {
2287 fprintf (pFile
, "\n%s", LineHeader
);
2289 fprintf (pFile
, "0x%02X, ", (UINT8
)BlkBuf
[Index
]);
2296 IN UINT32 LineBytes
,
2297 IN INT8
*LineHeader
,
2304 if ((BlkSize
== 0) || (pFile
== NULL
) || (LineHeader
== NULL
) || (BlkBuf
== NULL
)) {
2308 for (Index
= 0; Index
< BlkSize
- 1; Index
++) {
2309 if ((Index
% LineBytes
) == 0) {
2310 fprintf (pFile
, "\n%s", LineHeader
);
2312 fprintf (pFile
, "0x%02X, ", (UINT8
)BlkBuf
[Index
]);
2315 if ((Index
% LineBytes
) == 0) {
2316 fprintf (pFile
, "\n%s", LineHeader
);
2318 fprintf (pFile
, "0x%02X\n", (UINT8
)BlkBuf
[Index
]);
2321 #define BYTES_PRE_LINE 0x10
2324 StrPkgWriteHdrCFile (
2326 IN EFI_HII_STRING_PACKAGE_HDR
*StrPkgHdr
2329 if (StrPkgHdr
!= NULL
) {
2330 fprintf (File
, "\n // PACKAGE HEADER\n");
2331 WriteBlockLine(File
, BYTES_PRE_LINE
, " ", (INT8
*)StrPkgHdr
, StrPkgHdr
->HdrSize
);
2336 StrPkgWirteArrayLength (
2338 IN UINT32 PkgNumber
,
2339 IN EFI_HII_STRING_PACKAGE_HDR
**PkgHdr
2345 ArrayLen
= sizeof (UINT32
);
2346 for (Index
= 0; Index
< PkgNumber
; Index
++) {
2347 if (PkgHdr
[Index
] != NULL
) {
2348 ArrayLen
+= PkgHdr
[Index
]->Header
.Length
;
2352 fprintf (File
, "\n // STRING ARRAY LENGTH\n");
2353 WriteBlockLine(File
, BYTES_PRE_LINE
, " ", (UINT8
*)&ArrayLen
, sizeof (UINT32
));
2357 StrPkgWriteBlkListCFile (
2359 IN SPkgBlkBuffer
*BlkList
,
2363 SPkgBlkBuffer
*Buffer
;
2365 fprintf (File
, "\n\n // PACKAGE DATA\n");
2367 while (BlkList
!= NULL
) {
2369 BlkList
= BlkList
->mNext
;
2371 if ((Buffer
->mNext
== NULL
) && (WriteEnd
== TRUE
)) {
2372 if (Buffer
->mBlkBuffer
!= NULL
) {
2373 WriteBlockEnd (File
, BYTES_PRE_LINE
, " ", Buffer
->mBlkBuffer
, Buffer
->mBlkSize
);
2376 if (Buffer
->mBlkBuffer
!= NULL
) {
2377 WriteBlockLine(File
, BYTES_PRE_LINE
, " ", Buffer
->mBlkBuffer
, Buffer
->mBlkSize
);
2384 StrPkgWriteHdrBinary (
2386 IN EFI_HII_STRING_PACKAGE_HDR
*StrPkgHdr
2389 fwrite (StrPkgHdr
, StrPkgHdr
->HdrSize
, 1, File
);
2393 StrPkgWriteBlkListBinary (
2395 IN SPkgBlkBuffer
*BlkList
2398 SPkgBlkBuffer
*Buffer
;
2400 while (BlkList
!= NULL
) {
2402 BlkList
= BlkList
->mNext
;
2404 if (Buffer
->mBlkBuffer
!= NULL
) {
2405 fwrite (Buffer
->mBlkBuffer
, Buffer
->mBlkSize
, 1, File
);
2411 StringDBGenStrPkgHdrAndBlkList (
2412 IN LANGUAGE_LIST
*Lang
,
2413 OUT EFI_HII_STRING_PACKAGE_HDR
**StrPkgHdr
,
2414 OUT SPkgBlkBuffer
**BlkList
2419 EFI_STRING_ID StringIdCurrent
;
2420 EFI_STRING_ID SkipIdCount
;
2422 EFI_HII_SIBT_STRING_UCS2_BLOCK
*StrUCS2Blk
= NULL
;
2423 EFI_HII_SIBT_SKIP2_BLOCK
*StrSKIP2Blk
= NULL
;
2424 STRING_IDENTIFIER
*StringIdentifier
= NULL
;
2425 EFI_HII_SIBT_END_BLOCK
*EndBlk
= NULL
;
2426 UINT32 PkgBlkSize
= 0;
2427 SPkgBlkBuffer
*PkgBufferListHead
= NULL
;
2428 SPkgBlkBuffer
*PkgBufferListTail
= NULL
;
2430 if ((Lang
== NULL
) || (StrPkgHdr
== NULL
) || (BlkList
== NULL
)) {
2431 return STATUS_ERROR
;
2435 // Assign index values to the string identifiers
2437 StringDBAssignStringIndexes ();
2438 StringIdCurrent
= EFI_STRING_ID_BEGIN
;
2441 for (StringIndex
= STRING_ID_PRINTABLE_LANGUAGE_NAME
; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
2442 if ((StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
)) == NULL
) {
2443 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
2447 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
2448 Status
= BuildStringPkgUCS2Blk (StringIdCurrent
, Lang
->LanguageName
, StringIdentifier
->StringName
, &StrUCS2Blk
, &BlkSize
);
2453 case STATUS_WARNING
:
2456 case STATUS_SUCCESS
:
2457 if (SkipIdCount
== 0) {
2458 if (StrPkgBlkBufferListAddTail (
2460 StringIdentifier
->StringName
,
2465 ) != STATUS_SUCCESS
) {
2468 PkgBlkSize
+= BlkSize
;
2470 if (BuildStringPkgSKIP2Blk (SkipIdCount
, &StrSKIP2Blk
) != STATUS_SUCCESS
) {
2473 if (StrPkgBlkBufferListAddTail (
2479 sizeof (EFI_HII_SIBT_SKIP2_BLOCK
)
2480 ) != STATUS_SUCCESS
) {
2483 PkgBlkSize
+= sizeof (EFI_HII_SIBT_SKIP2_BLOCK
);
2487 if (StrPkgBlkBufferListAddTail (
2489 StringIdentifier
->StringName
,
2494 ) != STATUS_SUCCESS
) {
2497 PkgBlkSize
+= BlkSize
;
2505 if (SkipIdCount
!= 0) {
2506 if (BuildStringPkgSKIP2Blk (SkipIdCount
, &StrSKIP2Blk
) != STATUS_SUCCESS
) {
2509 if (StrPkgBlkBufferListAddTail (
2515 sizeof (EFI_HII_SIBT_SKIP2_BLOCK
)
2516 ) != STATUS_SUCCESS
) {
2519 PkgBlkSize
+= sizeof (EFI_HII_SIBT_SKIP2_BLOCK
);
2524 if (BuildStringPkgEndBlk (&EndBlk
) != STATUS_SUCCESS
) {
2526 } else if (StrPkgBlkBufferListAddTail (
2532 sizeof (EFI_HII_SIBT_END_BLOCK
)
2533 ) != STATUS_SUCCESS
) {
2537 PkgBlkSize
+= sizeof (EFI_HII_SIBT_END_BLOCK
);
2539 if (BuildStringPkgHdr(
2541 Lang
->SecondaryLanguageList
,
2542 EFI_HII_PACKAGE_STRINGS
,
2545 ) != STATUS_SUCCESS
) {
2549 *BlkList
= PkgBufferListHead
;
2551 return STATUS_SUCCESS
;
2554 StrPkgBlkBufferListFree(PkgBufferListHead
);
2557 return STATUS_ERROR
;
2561 StringDBCreateHiiExportPack (
2563 WCHAR_STRING_LIST
*LanguagesOfInterest
2567 LANGUAGE_LIST
*Lang
;
2568 EFI_HII_STRING_PACKAGE_HDR
*StrPkgHdr
;
2569 SPkgBlkBuffer
*BlkList
;
2570 WCHAR_STRING_LIST
*LOIPtr
;
2572 if (FileName
== NULL
) {
2573 return STATUS_ERROR
;
2576 if ((File
= fopen (FileName
, "wb")) == NULL
) {
2577 Error (NULL
, 0, 0, FileName
, "failed to open output HII export file");
2578 return STATUS_ERROR
;
2581 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
2582 for (LOIPtr
= LanguagesOfInterest
; LOIPtr
!= NULL
; LOIPtr
= LOIPtr
->Next
) {
2583 if (wcscmp (LOIPtr
->Str
, Lang
->LanguageName
) == 0) {
2588 if ((LanguagesOfInterest
== NULL
) ||
2589 (LanguagesOfInterest
!= NULL
&& LOIPtr
!= NULL
)) {
2590 if (StringDBGenStrPkgHdrAndBlkList(Lang
, &StrPkgHdr
, &BlkList
) != STATUS_SUCCESS
) {
2592 return STATUS_SUCCESS
;
2595 StrPkgWriteHdrBinary (File
, StrPkgHdr
);
2596 StrPkgWriteBlkListBinary (File
, BlkList
);
2598 StrPkgHdrFree (StrPkgHdr
);
2599 StrPkgBlkBufferListFree (BlkList
);
2603 return STATUS_SUCCESS
;
2606 static const char *gSourceFileHeader
[] = {
2608 "// DO NOT EDIT -- auto-generated file",
2610 "// This file is generated by the StrGather utility",
2616 StringDBDumpCStrings (
2619 WCHAR_STRING_LIST
*LanguagesOfInterest
2624 LANGUAGE_LIST
*Lang
;
2625 EFI_HII_STRING_PACKAGE_HDR
**StrPkgHdr
;
2626 SPkgBlkBuffer
**BlkList
;
2629 WCHAR_STRING_LIST
*LOIPtr
;
2631 if ((BaseName
== NULL
) || (FileName
== NULL
)) {
2632 return STATUS_ERROR
;
2635 if (mDBData
.LanguageList
== NULL
) {
2636 return STATUS_SUCCESS
;
2639 for (LangNumber
= 0, Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
, LangNumber
++)
2642 StrPkgHdr
= (EFI_HII_STRING_PACKAGE_HDR
**) malloc (sizeof (EFI_HII_STRING_PACKAGE_HDR
*) * LangNumber
);
2643 BlkList
= (SPkgBlkBuffer
**) malloc (sizeof (SPkgBlkBuffer
*) * LangNumber
);
2644 for (Index
= 0; Index
< LangNumber
; Index
++) {
2645 StrPkgHdr
[Index
] = NULL
;
2646 BlkList
[Index
] = NULL
;
2649 for (Index
= 0, Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
2650 for (LOIPtr
= LanguagesOfInterest
; LOIPtr
!= NULL
; LOIPtr
= LOIPtr
->Next
) {
2651 if (wcscmp (LOIPtr
->Str
, Lang
->LanguageName
) == 0) {
2655 if ((LanguagesOfInterest
== NULL
) ||
2656 (LanguagesOfInterest
!= NULL
&& LOIPtr
!= NULL
)) {
2657 Status
= StringDBGenStrPkgHdrAndBlkList(Lang
, &StrPkgHdr
[Index
], &BlkList
[Index
]);
2659 if (EFI_ERROR(Status
)) {
2662 return STATUS_ERROR
;
2668 // Update LangNumber after filter
2672 if (LangNumber
== 0) {
2675 return STATUS_SUCCESS
;
2678 if ((File
= fopen (FileName
, "w")) == NULL
) {
2679 Error (NULL
, 0, 0, FileName
, "failed to open output C file - %s", FileName
);
2680 return STATUS_ERROR
;
2683 for (Index
= 0; gSourceFileHeader
[Index
] != NULL
; Index
++) {
2684 fprintf (File
, "%s\n", gSourceFileHeader
[Index
]);
2687 fprintf (File
, "\nunsigned char %s[] = {\n", BaseName
);
2690 // Save the length of the string package array.
2692 StrPkgWirteArrayLength (File
, LangNumber
, StrPkgHdr
);
2694 for (Index
= 0; Index
< LangNumber
; Index
++) {
2695 StrPkgWriteHdrCFile (File
, StrPkgHdr
[Index
]);
2696 StrPkgWriteBlkListCFile (File
, BlkList
[Index
], (Index
== LangNumber
- 1) ? TRUE
: FALSE
);
2698 StrPkgHdrFree (StrPkgHdr
[Index
]);
2699 StrPkgBlkBufferListFree (BlkList
[Index
]);
2702 fprintf (File
, "\n};\n");
2707 return STATUS_SUCCESS
;