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
25 #include <ctype.h> // for tolower()
27 #include "EfiUtilityMsgs.h"
28 #include "StrGather.h"
30 #include "EfiInternalFormRepresentation.h"
32 #include EFI_PROTOCOL_DEFINITION (Hii)
35 #define STRING_OFFSET RELOFST
37 #define STRING_DB_KEY (('S' << 24) | ('D' << 16) | ('B' << 8) | 'K')
39 // Version supported by this tool
41 #define STRING_DB_VERSION 0x00010000
43 #define STRING_DB_MAJOR_VERSION_MASK 0xFFFF0000
44 #define STRING_DB_MINOR_VERSION_MASK 0x0000FFFF
46 #define DEFINE_STR L"// #define"
48 #define LANGUAGE_CODE_WIDTH 4
50 // This is the header that gets written to the top of the
51 // output binary database file.
57 UINT32 NumStringIdenfiers
;
58 UINT32 StringIdentifiersSize
;
63 // When we write out data to the database, we have a UINT16 identifier, which
64 // indicates what follows, followed by the data. Here's the structure.
69 } DB_DATA_ITEM_HEADER
;
71 #define DB_DATA_TYPE_INVALID 0x0000
72 #define DB_DATA_TYPE_STRING_IDENTIFIER 0x0001
73 #define DB_DATA_TYPE_LANGUAGE_DEFINITION 0x0002
74 #define DB_DATA_TYPE_STRING_DEFINITION 0x0003
75 #define DB_DATA_TYPE_LAST DB_DATA_TYPE_STRING_DEFINITION
78 // We have to keep track of a list of languages, each of which has its own
79 // list of strings. Define a structure to keep track of all languages and
80 // their list of strings.
82 typedef struct _STRING_LIST
{
83 struct _STRING_LIST
*Next
;
84 UINT32 Size
; // number of bytes in string, including null terminator
86 WCHAR
*StringName
; // for example STR_ID_TEXT1
88 WCHAR
*Str
; // the actual string
89 UINT16 Flags
; // properties of this string (used, undefined)
92 typedef struct _LANGUAGE_LIST
{
93 struct _LANGUAGE_LIST
*Next
;
94 WCHAR LanguageName
[4];
95 WCHAR
*PrintableLanguageName
;
97 STRING_LIST
*LastString
;
101 // We also keep track of all the string identifier names, which we assign unique
102 // values to. Create a structure to keep track of them all.
104 typedef struct _STRING_IDENTIFIER
{
105 struct _STRING_IDENTIFIER
*Next
;
106 UINT32 Index
; // only need 16 bits, but makes it easier with UINT32
108 UINT16 Flags
; // if someone referenced it via STRING_TOKEN()
111 // Keep our globals in this structure to be as modular as possible.
115 LANGUAGE_LIST
*LanguageList
;
116 LANGUAGE_LIST
*LastLanguageList
;
117 LANGUAGE_LIST
*CurrentLanguage
; // keep track of the last language they used
118 STRING_IDENTIFIER
*StringIdentifier
;
119 STRING_IDENTIFIER
*LastStringIdentifier
;
120 UINT8
*StringDBFileName
;
121 UINT32 NumStringIdentifiers
;
122 UINT32 NumStringIdentifiersReferenced
;
123 STRING_IDENTIFIER
*CurrentStringIdentifier
; // keep track of the last string identifier they added
127 static STRING_DB_DATA mDBData
;
129 static const char *mSourceFileHeader
[] = {
131 "// DO NOT EDIT -- auto-generated file",
133 "// This file is generated by the string gather utility",
144 WCHAR_STRING_LIST
*LanguagesOfInterest
,
145 WCHAR_MATCHING_STRING_LIST
*IndirectionList
150 StringDBFindStringIdentifierByName (
156 StringDBFindStringIdentifierByIndex (
162 StringDBFindLanguageList (
168 StringDBWriteStandardFileHeader (
186 StringDBWriteStringIdentifier (
190 WCHAR
*IdentifierName
195 StringDBReadStringIdentifier (
201 StringDBWriteLanguageDefinition (
204 WCHAR
*PrintableLanguageName
209 StringDBReadLanguageDefinition (
215 StringDBWriteString (
232 StringDBReadGenericString (
240 StringDBWriteGenericString (
247 StringDBAssignStringIndexes (
251 /*****************************************************************************/
256 Constructor function for the string database handler.
266 StringDBConstructor (
270 memset ((char *) &mDBData
, 0, sizeof (STRING_DB_DATA
));
271 mDBData
.CurrentScope
= DuplicateString (L
"NULL");
274 /*****************************************************************************/
279 Destructor function for the string database handler.
293 LANGUAGE_LIST
*NextLang
;
294 STRING_LIST
*NextStr
;
295 STRING_IDENTIFIER
*NextIdentifier
;
297 // Close the database file if it's open
299 if (mDBData
.StringDBFptr
!= NULL
) {
300 fclose (mDBData
.StringDBFptr
);
301 mDBData
.StringDBFptr
= NULL
;
304 // If we've allocated any strings/languages, free them up
306 while (mDBData
.LanguageList
!= NULL
) {
307 NextLang
= mDBData
.LanguageList
->Next
;
309 // Free up all strings for this language
311 while (mDBData
.LanguageList
->String
!= NULL
) {
312 NextStr
= mDBData
.LanguageList
->String
->Next
;
313 FREE (mDBData
.LanguageList
->String
->Str
);
314 FREE (mDBData
.LanguageList
->String
);
315 mDBData
.LanguageList
->String
= NextStr
;
318 FREE (mDBData
.LanguageList
->PrintableLanguageName
);
319 FREE (mDBData
.LanguageList
);
320 mDBData
.LanguageList
= NextLang
;
323 // Free up string identifiers
325 while (mDBData
.StringIdentifier
!= NULL
) {
326 NextIdentifier
= mDBData
.StringIdentifier
->Next
;
327 FREE (mDBData
.StringIdentifier
->StringName
);
328 FREE (mDBData
.StringIdentifier
);
329 mDBData
.StringIdentifier
= NextIdentifier
;
334 if (mDBData
.StringDBFileName
!= NULL
) {
335 FREE (mDBData
.StringDBFileName
);
336 mDBData
.StringDBFileName
= NULL
;
339 // We save a copy of the scope, so free it up if we
342 if (mDBData
.CurrentScope
!= NULL
) {
343 FREE (mDBData
.CurrentScope
);
344 mDBData
.CurrentScope
= NULL
;
348 /*****************************************************************************/
354 Dump the contents of a database to an output C file.
358 FileName - name of the output file to write
359 BaseName - used for the name of the C array defined
360 Languages - list of languages of interest
368 Languages is a pointer to a linked list of languages specified on
369 the command line. Format is "eng" and "spa+cat". For this, print
370 the strings for eng. Print the strings for spa too, but if one is
371 missing look for a cat string and print if it it exists.
375 StringDBDumpCStrings (
378 WCHAR_STRING_LIST
*LanguagesOfInterest
,
379 WCHAR_MATCHING_STRING_LIST
*IndirectionList
384 STRING_LIST
*CurrString
;
385 STRING_LIST EmptyString
;
389 UINT32 BytesThisLine
;
390 EFI_HII_STRING_PACK_HEADER StringPack
;
394 WCHAR_STRING_LIST
*LOIPtr
;
396 WCHAR
*TempStringPtr
;
398 STRING_IDENTIFIER
*StringIdentifier
;
400 if ((Fptr
= fopen (FileName
, "w")) == NULL
) {
401 Error (NULL
, 0, 0, FileName
, "failed to open output C string file");
405 // Assign index values to the string identifiers
407 StringDBAssignStringIndexes ();
409 // Write the standard header to the output file, then the structure
410 // definition header.
412 StringDBWriteStandardFileHeader (Fptr
);
413 fprintf (Fptr
, "\nunsigned char %s[] = {\n", BaseName
);
415 // If a given string is not defined, then we'll use this one.
417 memset (&EmptyString
, 0, sizeof (EmptyString
));
418 EmptyString
.Size
= sizeof (ZeroString
);
419 EmptyString
.Str
= ZeroString
;
421 // Process each language, then each string for each langage
424 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
426 // If we have a language list, then make sure this language is in that
430 LangName
= Lang
->LanguageName
;
431 if (LanguagesOfInterest
!= NULL
) {
433 for (LOIPtr
= LanguagesOfInterest
; LOIPtr
!= NULL
; LOIPtr
= LOIPtr
->Next
) {
434 if (wcsncmp (LOIPtr
->Str
, Lang
->LanguageName
, LANGUAGE_IDENTIFIER_NAME_LEN
) == 0) {
435 LangName
= LOIPtr
->Str
;
446 // Process each string for this language. We have to make 3 passes on the strings:
447 // Pass1: computes sizes and fill in the string pack header
448 // Pass2: write the array of offsets
449 // Pass3: write the strings
452 // PASS 1: Fill in and print the HII string pack header
454 // Compute the size for this language package and write
455 // the header out. Each string package contains:
457 // Offset[] -- an array of offsets to strings, of type RELOFST each
458 // String[] -- the actual strings themselves
462 "\n//******************************************************************************"
463 "\n// Start of string definitions for %S/%S",
465 Lang
->PrintableLanguageName
467 memset ((char *) &StringPack
, 0, sizeof (EFI_HII_STRING_PACK_HEADER
));
468 StringPack
.Header
.Type
= EFI_HII_STRING
;
469 StringPack
.NumStringPointers
= (UINT16
) mDBData
.NumStringIdentifiersReferenced
;
471 // First string is the language name. If we're printing all languages, then
472 // it's just the "spa". If we were given a list of languages to print, then it's
473 // the "spacat" string. Compute its offset and fill in
474 // the info in the header. Since we know the language name string's length,
475 // and the printable language name follows it, use that info to fill in the
476 // entry for the printable language name as well.
478 StringPack
.LanguageNameString
= (STRING_OFFSET
) (sizeof (EFI_HII_STRING_PACK_HEADER
) + (mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
)));
479 StringPack
.PrintableLanguageName
= (STRING_OFFSET
) (StringPack
.LanguageNameString
+ (wcslen (LangName
) + 1) * sizeof (WCHAR
));
481 // Add up the size of all strings so we can fill in our header.
484 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
486 // For the first string (language name), we print out the "spacat" if they
487 // requested it. We set LangName to point to the proper language name string above.
489 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
490 Len
+= (wcslen (LangName
) + 1) * sizeof (WCHAR
);
493 // Find a string with this language.stringname
495 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
496 if (StringIdentifier
== NULL
) {
497 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
501 // Find a matching string if this string identifier was referenced
503 EmptyString
.Flags
= STRING_FLAGS_UNDEFINED
;
505 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
506 CurrString
= StringDBFindString (
508 StringIdentifier
->StringName
,
513 if (NULL
== CurrString
) {
515 // If string for Lang->LanguageName is not found, try to get an English version
517 CurrString
= StringDBFindString (
519 StringIdentifier
->StringName
,
527 if (CurrString
== NULL
) {
528 CurrString
= &EmptyString
;
529 EmptyString
.Flags
|= StringIdentifier
->Flags
;
532 Len
+= CurrString
->Size
;
535 StringPack
.Header
.Length
= sizeof (EFI_HII_STRING_PACK_HEADER
)
536 + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
)
539 // Write out the header one byte at a time
541 Ptr
= (UINT8
*) &StringPack
;
542 for (TempIndex
= 0; TempIndex
< sizeof (EFI_HII_STRING_PACK_HEADER
); TempIndex
++, Ptr
++) {
543 if ((TempIndex
& 0x07) == 0) {
544 fprintf (Fptr
, "\n ");
547 fprintf (Fptr
, "0x%02X, ", (UINT32
) *Ptr
);
550 fprintf (Fptr
, "\n // offset 0x%X\n", sizeof (StringPack
));
552 // PASS2 : write the offsets
554 // Traverse the list of strings again and write the array of offsets. The
555 // offset to the first string is the size of the string pack header
556 // plus the size of the offsets array. The other strings follow it.
559 Offset
= sizeof (StringPack
) + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
);
560 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
562 // Write the offset, followed by a useful comment
565 Ptr
= (UINT8
*) &Offset
;
566 for (TempIndex
= 0; TempIndex
< sizeof (STRING_OFFSET
); TempIndex
++) {
567 fprintf (Fptr
, "0x%02X, ", (UINT32
) Ptr
[TempIndex
]);
570 // Find the string name
572 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
573 if (StringIdentifier
== NULL
) {
574 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
578 fprintf (Fptr
, " // offset to string %S (0x%04X)", StringIdentifier
->StringName
, StringIndex
);
580 // For the first string (language name), we print out the "spacat" if they
581 // requested it. We set LangName to point to the proper language name string above.
583 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
584 Offset
+= (wcslen (LangName
) + 1) * sizeof (WCHAR
);
585 CurrString
= StringDBFindString (
587 StringIdentifier
->StringName
,
594 // Find a matching string
596 CurrString
= StringDBFindString (
598 StringIdentifier
->StringName
,
604 if (NULL
== CurrString
) {
605 CurrString
= StringDBFindString (
607 StringIdentifier
->StringName
,
614 EmptyString
.LanguageName
= Lang
->LanguageName
;
615 if (CurrString
== NULL
) {
616 CurrString
= &EmptyString
;
617 EmptyString
.Flags
= STRING_FLAGS_UNDEFINED
;
618 } else if ((StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) == 0) {
619 CurrString
= &EmptyString
;
620 EmptyString
.Flags
= 0;
623 Offset
+= CurrString
->Size
;
626 // Print useful info about this string
628 if ((StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) == 0) {
629 fprintf (Fptr
, " - not referenced");
632 if (CurrString
->Flags
& STRING_FLAGS_UNDEFINED
) {
633 fprintf (Fptr
, " - not defined for this language");
634 } else if (wcscmp (CurrString
->LanguageName
, Lang
->LanguageName
) != 0) {
637 " - not defined for this language -- using secondary language %S definition",
638 CurrString
->LanguageName
642 fprintf (Fptr
, "\n");
645 // For unreferenced string identifiers, print a message that they are not referenced anywhere
647 while (StringIndex
< mDBData
.NumStringIdentifiers
) {
648 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
649 if (StringIdentifier
!= NULL
) {
650 fprintf (Fptr
, " // %S not referenced\n", StringIdentifier
->StringName
);
657 // PASS 3: write the strings themselves.
658 // Keep track of how many bytes we write per line because some editors
659 // (Visual Studio for instance) can't handle too long of lines.
661 Offset
= sizeof (StringPack
) + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
);
662 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
663 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
664 if (StringIdentifier
== NULL
) {
665 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
669 fprintf (Fptr
, " // string %S offset 0x%08X\n ", StringIdentifier
->StringName
, Offset
);
671 // For the first string (language name), we print out the "spacat" if they
672 // requested it. We set LangName to point to the proper language name string above.
674 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
675 TempStringPtr
= LangName
;
678 // Find a matching string if this string identifier was referenced
681 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
682 CurrString
= StringDBFindString (
684 StringIdentifier
->StringName
,
689 if (NULL
== CurrString
) {
690 CurrString
= StringDBFindString (
692 StringIdentifier
->StringName
,
700 if (CurrString
== NULL
) {
701 CurrString
= &EmptyString
;
704 TempStringPtr
= CurrString
->Str
;
708 for (TempIndex
= 0; TempStringPtr
[TempIndex
] != 0; TempIndex
++) {
712 (UINT32
) TempStringPtr
[TempIndex
] & 0xFF,
713 (UINT32
) ((TempStringPtr
[TempIndex
] >> 8) & 0xFF)
718 // Let's say we only allow 14 per line
720 if (BytesThisLine
> 14) {
721 fprintf (Fptr
, "\n ");
726 // Print NULL WCHAR at the end of this string.
728 fprintf (Fptr
, "0x00, 0x00,\n");
732 // Sanity check the offset. Make sure our running offset is what we put in the
733 // string pack header.
735 if (StringPack
.Header
.Length
!= Offset
) {
741 "stringpack size 0x%X does not match final size 0x%X",
742 StringPack
.Header
.Length
,
748 // Print terminator string pack, closing brace and close the file.
749 // The size of 0 triggers to the consumer that this is the end.
751 memset ((char *) &StringPack
, 0, sizeof (EFI_HII_STRING_PACK_HEADER
));
752 StringPack
.Header
.Type
= EFI_HII_STRING
;
753 Ptr
= (UINT8
*) &StringPack
;
754 fprintf (Fptr
, "\n // strings terminator pack");
755 for (TempIndex
= 0; TempIndex
< sizeof (StringPack
); TempIndex
++, Ptr
++) {
756 if ((TempIndex
& 0x0F) == 0) {
757 fprintf (Fptr
, "\n ");
760 fprintf (Fptr
, "0x%02X, ", (UINT32
) *Ptr
);
763 fprintf (Fptr
, "\n};\n");
765 return STATUS_SUCCESS
;
768 /*****************************************************************************/
774 Dump the #define string names
778 FileName - name of the output file to write
779 BaseName - used for the protection #ifndef/#endif
787 StringDBDumpStringDefines (
793 STRING_IDENTIFIER
*Identifier
;
794 INT8 CopyBaseName
[100];
796 const INT8
*StrDefHeader
[] = {
797 "#ifndef _%s_STRINGS_DEFINE_H_\n",
798 "#define _%s_STRINGS_DEFINE_H_\n\n",
802 if ((Fptr
= fopen (FileName
, "w")) == NULL
) {
803 Error (NULL
, 0, 0, FileName
, "failed to open output string defines file");
807 // Get the base source filename and convert to uppercase.
809 if (sizeof (CopyBaseName
) <= strlen (BaseName
) + 1) {
810 Error (NULL
, 0, 0, "application error", "StringDBDumpStringDefines() string length insufficient");
814 strcpy (CopyBaseName
, BaseName
);
815 for (Index
= 0; CopyBaseName
[Index
] != 0; Index
++) {
816 if (islower (CopyBaseName
[Index
])) {
817 CopyBaseName
[Index
] = (INT8
) toupper (CopyBaseName
[Index
]);
821 // Assign index values to the string identifiers
823 StringDBAssignStringIndexes ();
825 // Write the standard header to the output file, and then the
826 // protective #ifndef.
828 StringDBWriteStandardFileHeader (Fptr
);
829 for (Index
= 0; StrDefHeader
[Index
] != NULL
; Index
++) {
830 fprintf (Fptr
, StrDefHeader
[Index
], CopyBaseName
);
833 // Print all the #defines for the string identifiers. Print identifiers
834 // whose names start with '$' as comments. Add comments for string
835 // identifiers not used as well.
837 Identifier
= mDBData
.StringIdentifier
;
838 while (Identifier
!= NULL
) {
839 if (Identifier
->StringName
[0] == L
'$') {
840 fprintf (Fptr
, "// ");
843 if (Identifier
->Flags
& STRING_FLAGS_REFERENCED
) {
844 fprintf (Fptr
, "#define %-40S 0x%04X\n", Identifier
->StringName
, Identifier
->Index
);
846 fprintf (Fptr
, "//#define %-40S 0x%04X // not referenced\n", Identifier
->StringName
, Identifier
->Index
);
849 Identifier
= Identifier
->Next
;
852 fprintf (Fptr
, "\n#endif\n");
854 return STATUS_SUCCESS
;
857 /*****************************************************************************/
863 Add a string identifier to the database.
867 StringName - name of the string identifier. For example "STR_MY_STRING"
868 NewId - if an ID has been assigned
869 Flags - characteristics for the identifier
877 StringDBAddStringIdentifier (
883 STRING_IDENTIFIER
*StringIdentifier
;
886 // If it was already used for some other language, then we don't
887 // need to add it. But set it to the current string identifier.
888 // The referenced bit is sticky.
890 Status
= STATUS_SUCCESS
;
891 StringIdentifier
= StringDBFindStringIdentifierByName (StringName
);
892 if (StringIdentifier
!= NULL
) {
893 if (Flags
& STRING_FLAGS_REFERENCED
) {
894 StringIdentifier
->Flags
|= STRING_FLAGS_REFERENCED
;
897 mDBData
.CurrentStringIdentifier
= StringIdentifier
;
898 *NewId
= (UINT16
) StringIdentifier
->Index
;
902 StringIdentifier
= (STRING_IDENTIFIER
*) MALLOC (sizeof (STRING_IDENTIFIER
));
903 if (StringIdentifier
== NULL
) {
904 Error (NULL
, 0, 0, NULL
, "memory allocation error");
908 memset ((char *) StringIdentifier
, 0, sizeof (STRING_IDENTIFIER
));
909 StringIdentifier
->StringName
= (WCHAR
*) malloc ((wcslen (StringName
) + 1) * sizeof (WCHAR
));
910 if (StringIdentifier
->StringName
== NULL
) {
911 Error (NULL
, 0, 0, NULL
, "memory allocation error");
915 wcscpy (StringIdentifier
->StringName
, StringName
);
916 if (*NewId
!= STRING_ID_INVALID
) {
917 StringIdentifier
->Index
= *NewId
;
918 StringIdentifier
->Flags
|= STRING_FLAGS_INDEX_ASSIGNED
;
919 if (mDBData
.NumStringIdentifiers
<= StringIdentifier
->Index
) {
920 mDBData
.NumStringIdentifiers
= StringIdentifier
->Index
+ 1;
923 StringIdentifier
->Index
= mDBData
.NumStringIdentifiers
++;
926 StringIdentifier
->Flags
|= Flags
;
928 // Add it to our list of string identifiers
930 if (mDBData
.StringIdentifier
== NULL
) {
931 mDBData
.StringIdentifier
= StringIdentifier
;
933 mDBData
.LastStringIdentifier
->Next
= StringIdentifier
;
936 mDBData
.LastStringIdentifier
= StringIdentifier
;
937 mDBData
.CurrentStringIdentifier
= StringIdentifier
;
938 *NewId
= (UINT16
) StringIdentifier
->Index
;
942 /*****************************************************************************/
948 Add a new string to the database.
952 LanguageName - "eng" or "spa" language name
953 StringName - "STR_MY_TEXT" string name
954 Scope - from the #scope statements in the string file
955 Format - if we should format the string
956 Flags - characteristic flags for the string
964 Several of the fields can be "inherited" from the previous calls to
965 our database functions. For example, if scope is NULL here, then
966 we'll use the previous setting.
983 WCHAR TempLangName
[4];
984 STRING_IDENTIFIER
*StringIdentifier
;
987 // Check that language name is exactly 3 characters, or emit an error.
988 // Truncate at 3 if it's longer, or make it 3 if it's shorter.
990 if (LanguageName
!= NULL
) {
991 Size
= wcslen (LanguageName
);
993 ParserError (0, "invalid length for language name", "%S", LanguageName
);
998 // Make a local copy of the language name string, and extend to
999 // 3 characters since we make assumptions elsewhere in this program
1002 wcscpy (TempLangName
, LanguageName
);
1003 for (; Size
< 3; Size
++) {
1004 TempLangName
[Size
] = L
'?';
1007 TempLangName
[3] = 0;
1008 LanguageName
= TempLangName
;
1013 // If they specified a language, make sure they've defined it already
1014 // via a #langdef statement. Otherwise use the current default language.
1016 if (LanguageName
!= NULL
) {
1017 Lang
= StringDBFindLanguageList (LanguageName
);
1019 ParserError (0, "language not defined", "%S", LanguageName
);
1020 return STATUS_ERROR
;
1022 StringDBSetCurrentLanguage (LanguageName
);
1025 Lang
= mDBData
.CurrentLanguage
;
1028 // Have to call SetLanguage() first
1030 ParserError (0, "no language defined", "%S", StringName
);
1031 return STATUS_ERROR
;
1035 // If they didn't define a string identifier, use the last string identifier
1038 if (StringName
== NULL
) {
1039 StringName
= mDBData
.CurrentStringIdentifier
->StringName
;
1040 if (StringName
== NULL
) {
1041 ParserError (0, "no string identifier previously specified", NULL
);
1042 return STATUS_ERROR
;
1046 // If scope was not specified, use the default setting
1048 if (Scope
!= NULL
) {
1049 Scope
= DuplicateString (Scope
);
1051 Scope
= DuplicateString (mDBData
.CurrentScope
);
1054 // printf ("Adding string: %S.%S.%S\n", Lang->LanguageName, StringName, Scope);
1056 // Check for duplicates for this Language.StringName.Scope. Allow multiple
1057 // definitions of the language name and printable language name, since the
1058 // user does not specifically define them.
1060 if (StringDBFindString (Lang
->LanguageName
, StringName
, Scope
, NULL
, NULL
) != NULL
) {
1061 if ((wcscmp (StringName
, LANGUAGE_NAME_STRING_NAME
) == 0) &&
1062 (wcscmp (StringName
, PRINTABLE_LANGUAGE_NAME_STRING_NAME
) == 0)
1066 "string multiply defined",
1067 "Language.Name.Scope = %S.%S.%S",
1072 return STATUS_ERROR
;
1076 StringIndex
= STRING_ID_INVALID
;
1077 if (StringDBAddStringIdentifier (StringName
, &StringIndex
, Flags
) != STATUS_SUCCESS
) {
1078 return STATUS_ERROR
;
1081 StringIdentifier
= StringDBFindStringIdentifierByName (StringName
);
1083 // Add this string to the end of the strings for this language.
1085 Str
= (STRING_LIST
*) malloc (sizeof (STRING_LIST
));
1087 Error (NULL
, 0, 0, NULL
, "memory allocation error");
1088 return STATUS_ERROR
;
1091 memset ((char *) Str
, 0, sizeof (STRING_LIST
));
1092 Size
= (wcslen (String
) + 1) * sizeof (WCHAR
);
1095 Str
->StringName
= StringIdentifier
->StringName
;
1096 Str
->LanguageName
= DuplicateString (LanguageName
);
1097 Str
->Str
= (WCHAR
*) MALLOC (Size
);
1098 if (Str
->Str
== NULL
) {
1099 Error (NULL
, 0, 0, NULL
, "memory allocation error");
1100 return STATUS_ERROR
;
1103 // If not formatting, just copy the string.
1105 wcscpy (Str
->Str
, String
);
1107 StringDBFormatString (Str
->Str
);
1110 // Size may change after formatting. We set the size to
1111 // the actual size of the string, including the null for
1112 // easier processing later.
1114 Str
->Size
= (wcslen (Str
->Str
) + 1) * sizeof (WCHAR
);
1115 if (Lang
->String
== NULL
) {
1118 Lang
->LastString
->Next
= Str
;
1121 Lang
->LastString
= Str
;
1122 return STATUS_SUCCESS
;
1125 /*****************************************************************************/
1129 Routine Description:
1131 Given a language name, see if a language list for it has been defined
1135 LanguageName - like "eng"
1139 A pointer to the language list
1144 StringDBFindLanguageList (
1148 LANGUAGE_LIST
*Lang
;
1150 Lang
= mDBData
.LanguageList
;
1151 while (Lang
!= NULL
) {
1152 if (wcscmp (LanguageName
, Lang
->LanguageName
) == 0) {
1162 /*****************************************************************************/
1164 StringDBSetCurrentLanguage (
1168 LANGUAGE_LIST
*Lang
;
1170 Lang
= StringDBFindLanguageList (LanguageName
);
1172 ParserError (0, "language not previously defined", "%S", LanguageName
);
1173 return STATUS_ERROR
;
1176 mDBData
.CurrentLanguage
= Lang
;
1177 return STATUS_SUCCESS
;
1180 /*****************************************************************************/
1182 StringDBAddLanguage (
1183 WCHAR
*LanguageName
,
1184 WCHAR
*PrintableLanguageName
1187 LANGUAGE_LIST
*Lang
;
1189 // Check for redefinitions
1191 Lang
= StringDBFindLanguageList (LanguageName
);
1194 // Better be the same printable name
1196 if (wcscmp (PrintableLanguageName
, Lang
->PrintableLanguageName
) != 0) {
1199 "language redefinition",
1202 Lang
->PrintableLanguageName
,
1204 PrintableLanguageName
1206 return STATUS_ERROR
;
1209 // ParserWarning (0, "benign language redefinition", "%S", PrintableLanguageName);
1210 // return STATUS_WARNING;
1215 // Allocate memory to keep track of this new language
1217 Lang
= (LANGUAGE_LIST
*) malloc (sizeof (LANGUAGE_LIST
));
1219 Error (NULL
, 0, 0, NULL
, "memory allocation error");
1220 return STATUS_ERROR
;
1223 memset ((char *) Lang
, 0, sizeof (LANGUAGE_LIST
));
1225 // Save the language name, then allocate memory to save the
1226 // printable language name
1228 Lang
->LanguageName
[3] = 0;
1229 wcsncpy (Lang
->LanguageName
, LanguageName
, 3);
1230 Lang
->PrintableLanguageName
= (WCHAR
*) malloc ((wcslen (PrintableLanguageName
) + 1) * sizeof (WCHAR
));
1231 if (Lang
->PrintableLanguageName
== NULL
) {
1232 Error (NULL
, 0, 0, NULL
, "memory allocation error");
1233 return STATUS_ERROR
;
1236 wcscpy (Lang
->PrintableLanguageName
, PrintableLanguageName
);
1238 if (mDBData
.LanguageList
== NULL
) {
1239 mDBData
.LanguageList
= Lang
;
1241 mDBData
.LastLanguageList
->Next
= Lang
;
1244 mDBData
.LastLanguageList
= Lang
;
1247 // Default is to make our active language this new one
1249 StringDBSetCurrentLanguage (LanguageName
);
1251 // The first two strings for any language are the language name,
1252 // followed by the printable language name. Add them and set them
1253 // to referenced so they never get stripped out.
1257 LANGUAGE_NAME_STRING_NAME
,
1261 STRING_FLAGS_REFERENCED
1265 PRINTABLE_LANGUAGE_NAME_STRING_NAME
,
1267 PrintableLanguageName
,
1269 STRING_FLAGS_REFERENCED
1271 return STATUS_SUCCESS
;
1274 /*****************************************************************************/
1277 StringDBFindStringIdentifierByName (
1281 STRING_IDENTIFIER
*Identifier
;
1283 Identifier
= mDBData
.StringIdentifier
;
1284 while (Identifier
!= NULL
) {
1285 if (wcscmp (StringName
, Identifier
->StringName
) == 0) {
1289 Identifier
= Identifier
->Next
;
1297 StringDBFindStringIdentifierByIndex (
1301 STRING_IDENTIFIER
*Identifier
;
1303 Identifier
= mDBData
.StringIdentifier
;
1304 while (Identifier
!= NULL
) {
1305 if (Identifier
->Index
== StringIndex
) {
1309 Identifier
= Identifier
->Next
;
1315 /*****************************************************************************/
1318 StringDBWriteStandardFileHeader (
1323 for (TempIndex
= 0; mSourceFileHeader
[TempIndex
] != NULL
; TempIndex
++) {
1324 fprintf (OutFptr
, "%s\n", mSourceFileHeader
[TempIndex
]);
1328 /*****************************************************************************/
1332 Routine Description:
1334 Given a Unicode string from an input file, reformat the string to replace
1335 backslash control sequences with the appropriate encoding.
1339 String - pointer to string to reformat
1347 StringDBFormatString (
1356 // Go through the string and process any formatting characters
1361 if (*From
== UNICODE_BACKSLASH
) {
1363 // First look for \wide and replace with the appropriate control character. Note that
1364 // when you have "define STR L"ABC"", then sizeof(ABC) is 8 because the null char is
1365 // counted. Make adjustments for this. We advance From below, so subtract 2 each time.
1367 if (wcsncmp (From
, UNICODE_WIDE_STRING
, sizeof (UNICODE_WIDE_STRING
) / sizeof (WCHAR
) - 1) == 0) {
1369 From
+= sizeof (UNICODE_WIDE_STRING
) / sizeof (WCHAR
) - 2;
1370 } else if (wcsncmp (From
, UNICODE_NARROW_STRING
, sizeof (UNICODE_NARROW_STRING
) / sizeof (WCHAR
) - 1) == 0) {
1375 From
+= sizeof (UNICODE_NARROW_STRING
) / sizeof (WCHAR
) - 2;
1376 } else if (wcsncmp (From
, UNICODE_NBR_STRING
, sizeof (UNICODE_NBR_STRING
) / sizeof (WCHAR
) - 1) == 0) {
1380 *To
= NON_BREAKING_CHAR
;
1381 From
+= sizeof (UNICODE_NBR_STRING
) / sizeof (WCHAR
) - 2;
1382 } else if (wcsncmp (From
, UNICODE_BR_STRING
, sizeof (UNICODE_BR_STRING
) / sizeof (WCHAR
) - 1) == 0) {
1384 // Found: \br -- pass through untouched
1389 // Standard one-character control sequences such as \n, \r, \\, or \x
1393 case ASCII_TO_UNICODE ('n'):
1402 case ASCII_TO_UNICODE ('r'):
1409 case UNICODE_BACKSLASH
:
1410 *To
= UNICODE_BACKSLASH
;
1416 case ASCII_TO_UNICODE ('t'):
1421 // embedded double-quote
1423 case UNICODE_DOUBLE_QUOTE
:
1424 *To
= UNICODE_DOUBLE_QUOTE
;
1428 // Hex Unicode character \x1234. We'll process up to 4 hex characters
1430 case ASCII_TO_UNICODE ('x'):
1432 for (HexNibbles
= 0; HexNibbles
< 4; HexNibbles
++) {
1433 if ((From
[1] >= UNICODE_0
) && (From
[1] <= UNICODE_9
)) {
1434 HexValue
= (HexValue
<< 4) | (From
[1] - UNICODE_0
);
1435 } else if ((From
[1] >= UNICODE_a
) && (From
[1] <= UNICODE_f
)) {
1436 HexValue
= (HexValue
<< 4) | (10 + From
[1] - UNICODE_a
);
1437 } else if ((From
[1] >= UNICODE_A
) && (From
[1] <= UNICODE_F
)) {
1438 HexValue
= (HexValue
<< 4) | (10 + From
[1] - UNICODE_A
);
1446 if (HexNibbles
== 0) {
1449 "expected at least one valid hex digit with \\x escaped character in string",
1459 *To
= UNICODE_SPACE
;
1460 ParserWarning (0, "invalid escaped character in string", "\\%C", *From
);
1475 /*****************************************************************************/
1477 StringDBReadDatabase (
1479 BOOLEAN IgnoreIfNotExist
,
1483 STRING_DB_HEADER DbHeader
;
1486 DB_DATA_ITEM_HEADER DataItemHeader
;
1488 Status
= STATUS_SUCCESS
;
1492 // fprintf (stdout, "Reading database file %s\n", DBFileName);
1495 // Try to open the input file
1497 if ((DBFptr
= fopen (DBFileName
, "rb")) == NULL
) {
1498 if (IgnoreIfNotExist
) {
1499 return STATUS_SUCCESS
;
1502 Error (NULL
, 0, 0, DBFileName
, "failed to open input database file for reading");
1503 return STATUS_ERROR
;
1506 // Read and verify the database header
1508 if (fread ((void *) &DbHeader
, sizeof (STRING_DB_HEADER
), 1, DBFptr
) != 1) {
1509 Error (NULL
, 0, 0, DBFileName
, "failed to read header from database file");
1510 Status
= STATUS_ERROR
;
1514 if (DbHeader
.Key
!= STRING_DB_KEY
) {
1515 Error (NULL
, 0, 0, DBFileName
, "invalid header in database file");
1516 Status
= STATUS_ERROR
;
1520 if ((DbHeader
.Version
& STRING_DB_MAJOR_VERSION_MASK
) != (STRING_DB_VERSION
& STRING_DB_MAJOR_VERSION_MASK
)) {
1521 Error (NULL
, 0, 0, DBFileName
, "incompatible database file version -- rebuild clean");
1522 Status
= STATUS_ERROR
;
1526 // Read remaining items
1528 while (fread (&DataItemHeader
, sizeof (DataItemHeader
), 1, DBFptr
) == 1) {
1529 switch (DataItemHeader
.DataType
) {
1530 case DB_DATA_TYPE_STRING_IDENTIFIER
:
1531 StringDBReadStringIdentifier (DBFptr
);
1534 case DB_DATA_TYPE_LANGUAGE_DEFINITION
:
1535 StringDBReadLanguageDefinition (DBFptr
);
1538 case DB_DATA_TYPE_STRING_DEFINITION
:
1539 StringDBReadString (DBFptr
);
1547 "database corrupted",
1548 "invalid data item type 0x%X at offset 0x%X",
1549 (UINT32
) DataItemHeader
.DataType
,
1550 ftell (DBFptr
) - sizeof (DataItemHeader
)
1552 Status
= STATUS_ERROR
;
1558 if (DBFptr
!= NULL
) {
1565 /*****************************************************************************/
1569 Routine Description:
1571 Write everything we know to the output database file. Write:
1574 String identifiers[]
1579 DBFileName - name of the file to write to
1580 Verbose - for debug purposes, print info messages along the way.
1588 StringDBWriteDatabase (
1593 STRING_DB_HEADER DbHeader
;
1596 LANGUAGE_LIST
*Lang
;
1597 STRING_IDENTIFIER
*StringIdentifier
;
1598 STRING_LIST
*StrList
;
1602 fprintf (stdout
, "Writing database %s\n", DBFileName
);
1605 if ((DBFptr
= fopen (DBFileName
, "wb")) == NULL
) {
1606 Error (NULL
, 0, 0, DBFileName
, "failed to open output database file for writing");
1607 return STATUS_ERROR
;
1610 // Fill in and write the database header
1612 memset (&DbHeader
, 0, sizeof (STRING_DB_HEADER
));
1613 DbHeader
.HeaderSize
= sizeof (STRING_DB_HEADER
);
1614 DbHeader
.Key
= STRING_DB_KEY
;
1615 DbHeader
.Version
= STRING_DB_VERSION
;
1617 // Count the number of languages we have
1619 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1620 DbHeader
.NumLanguages
++;
1623 // Count up how many string identifiers we have, and total up the
1624 // size of the names plus the size of the flags field we will
1627 DbHeader
.NumStringIdenfiers
= mDBData
.NumStringIdentifiers
;
1628 StringIdentifier
= mDBData
.StringIdentifier
;
1629 for (Counter
= 0; Counter
< mDBData
.NumStringIdentifiers
; Counter
++) {
1630 StrLen
= wcslen (StringIdentifier
->StringName
) + 1;
1631 DbHeader
.StringIdentifiersSize
+= StrLen
* sizeof (WCHAR
) + sizeof (StringIdentifier
->Flags
);
1632 StringIdentifier
= StringIdentifier
->Next
;
1638 fwrite (&DbHeader
, sizeof (STRING_DB_HEADER
), 1, DBFptr
);
1640 fprintf (stdout
, " Number of string identifiers 0x%04X\n", DbHeader
.NumStringIdenfiers
);
1641 fprintf (stdout
, " Number of languages %d\n", DbHeader
.NumLanguages
);
1644 // Write the string identifiers
1646 for (StringIdentifier
= mDBData
.StringIdentifier
; StringIdentifier
!= NULL
; StringIdentifier
= StringIdentifier
->Next
) {
1647 StringDBWriteStringIdentifier (
1649 (UINT16
) StringIdentifier
->Index
,
1650 StringIdentifier
->Flags
,
1651 StringIdentifier
->StringName
1655 // Now write all the strings for each language
1657 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1658 StringDBWriteLanguageDefinition (DBFptr
, Lang
->LanguageName
, Lang
->PrintableLanguageName
);
1659 for (StrList
= Lang
->String
; StrList
!= NULL
; StrList
= StrList
->Next
) {
1660 StringDBWriteString (
1664 StrList
->StringName
,
1672 return STATUS_SUCCESS
;
1676 StringDBSetStringReferenced (
1677 INT8
*StringIdentifierName
,
1678 BOOLEAN IgnoreNotFound
1681 STRING_IDENTIFIER
*Id
;
1685 // See if it's already been defined.
1687 Status
= STATUS_SUCCESS
;
1688 WName
= (WCHAR
*) malloc ((strlen (StringIdentifierName
) + 1) * sizeof (WCHAR
));
1690 swprintf (WName
, (strlen (StringIdentifierName
) + 1) * sizeof (WCHAR
), L
"%S", StringIdentifierName
);
1692 swprintf (WName
, L
"%S", StringIdentifierName
);
1694 Id
= StringDBFindStringIdentifierByName (WName
);
1696 Id
->Flags
|= STRING_FLAGS_REFERENCED
;
1698 if (IgnoreNotFound
== 0) {
1699 ParserWarning (0, StringIdentifierName
, "string identifier not found in database");
1700 Status
= STATUS_WARNING
;
1708 /*****************************************************************************/
1712 Routine Description:
1714 Dump the contents of a database to an output unicode file.
1718 DBFileName - name of the pre-existing database file to read
1719 OutputFileName - name of the file to dump the database contents to
1720 Verbose - for printing of additional info useful for debugging
1728 There's some issue with the unicode printing routines. Therefore to
1729 write to the output file properly, open it as binary and use fwrite.
1730 Ideally we could open it with just L"w" and use fwprintf().
1734 StringDBDumpDatabase (
1736 INT8
*OutputFileName
,
1740 LANGUAGE_LIST
*Lang
;
1741 STRING_IDENTIFIER
*StringIdentifier
;
1742 STRING_LIST
*StrList
;
1745 WCHAR
*WOutputFileName
;
1750 // This function assumes the database has already been read, and
1751 // we're just dumping our internal data structures to a unicode file.
1754 fprintf (stdout
, "Dumping database file %s\n", DBFileName
);
1757 WOutputFileName
= AsciiToWchar (OutputFileName
);
1758 OutFptr
= _wfopen (WOutputFileName
, L
"wb");
1759 free (WOutputFileName
);
1760 if (OutFptr
== NULL
) {
1761 Error (NULL
, 0, 0, OutputFileName
, "failed to open output file for writing");
1762 return STATUS_ERROR
;
1765 WChar
= UNICODE_FILE_START
;
1766 fwrite (&WChar
, sizeof (WCHAR
), 1, OutFptr
);
1767 CrLf
[1] = UNICODE_LF
;
1768 CrLf
[0] = UNICODE_CR
;
1770 // The default control character is '/'. Make it '#' by writing
1771 // "/=#" to the output file.
1774 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"/=#");
1776 swprintf (Line
, L
"/=#");
1778 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1779 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1780 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1782 // Dump all the string identifiers and their values
1784 StringDBAssignStringIndexes ();
1785 for (StringIdentifier
= mDBData
.StringIdentifier
; StringIdentifier
!= NULL
; StringIdentifier
= StringIdentifier
->Next
) {
1787 // Write the "#define " string
1789 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
1793 wcslen(Line
) * sizeof (WCHAR
),
1794 L
"%s %-60.60s 0x%04X",
1796 StringIdentifier
->StringName
,
1797 StringIdentifier
->Index
1802 L
"%s %-60.60s 0x%04X",
1804 StringIdentifier
->StringName
,
1805 StringIdentifier
->Index
1812 wcslen(Line
) * sizeof (WCHAR
),
1813 L
"%s %-60.60s 0x%04X // NOT REFERENCED",
1815 StringIdentifier
->StringName
,
1816 StringIdentifier
->Index
1821 L
"%s %-60.60s 0x%04X // NOT REFERENCED",
1823 StringIdentifier
->StringName
,
1824 StringIdentifier
->Index
1829 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1830 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1833 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1835 // Now write all the strings for each language.
1837 WChar
= UNICODE_DOUBLE_QUOTE
;
1839 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
1840 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1842 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"#langdef %s \"%s\"", Lang
->LanguageName
, Lang
->PrintableLanguageName
);
1844 swprintf (Line
, L
"#langdef %s \"%s\"", Lang
->LanguageName
, Lang
->PrintableLanguageName
);
1846 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1847 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1848 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1850 // Now the strings (in double-quotes) for this language. Write
1851 // #string STR_NAME #language eng "string"
1853 for (StrList
= Lang
->String
; StrList
!= NULL
; StrList
= StrList
->Next
) {
1855 // Print the internal flags for debug
1858 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"// flags=0x%02X", (UINT32
) StrList
->Flags
);
1860 swprintf (Line
, L
"// flags=0x%02X", (UINT32
) StrList
->Flags
);
1862 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1863 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1865 // Print the scope if changed
1867 if ((Scope
== NULL
) || (wcscmp (Scope
, StrList
->Scope
) != 0)) {
1869 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"#scope %s", StrList
->Scope
);
1871 swprintf (Line
, L
"#scope %s", StrList
->Scope
);
1873 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1874 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1875 Scope
= StrList
->Scope
;
1881 wcslen(Line
) * sizeof (WCHAR
),
1882 L
"#string %-50.50s #language %s \"",
1883 StrList
->StringName
,
1889 L
"#string %-50.50s #language %s \"",
1890 StrList
->StringName
,
1894 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1895 fwrite (StrList
->Str
, StrList
->Size
- sizeof (WCHAR
), 1, OutFptr
);
1897 swprintf (Line
, wcslen(Line
) * sizeof (WCHAR
), L
"\"");
1899 swprintf (Line
, L
"\"");
1901 fwrite (Line
, wcslen (Line
) * sizeof (WCHAR
), 1, OutFptr
);
1902 fwrite (&CrLf
, sizeof (CrLf
), 1, OutFptr
);
1907 return STATUS_SUCCESS
;
1910 /*****************************************************************************/
1914 Routine Description:
1916 Given a primary language, a string identifier number, and a list of
1917 languages, find a secondary string.
1921 LanguageName - primary language, like "spa"
1922 StringId - string index value
1923 LanguageList - linked list of "eng", "spa+cat",...
1927 Pointer to a secondary string if found. NULL otherwise.
1931 Given: LanguageName "spa" and LanguageList "spa+cat", match the
1932 "spa" and extract the "cat" and see if there is a string defined
1938 StringDBWriteStringIdentifier (
1942 WCHAR
*IdentifierName
1945 DB_DATA_ITEM_HEADER Hdr
;
1946 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
1947 Hdr
.DataType
= DB_DATA_TYPE_STRING_IDENTIFIER
;
1948 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
1949 Error (NULL
, 0, 0, "failed to write string to output database file", NULL
);
1950 return STATUS_ERROR
;
1953 if (fwrite (&StringId
, sizeof (StringId
), 1, DBFptr
) != 1) {
1954 Error (NULL
, 0, 0, "failed to write StringId to output database", NULL
);
1955 return STATUS_ERROR
;
1958 if (fwrite (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1959 Error (NULL
, 0, 0, "failed to write StringId flags to output database", NULL
);
1960 return STATUS_ERROR
;
1963 if (StringDBWriteGenericString (DBFptr
, IdentifierName
) != STATUS_SUCCESS
) {
1964 return STATUS_ERROR
;
1967 return STATUS_SUCCESS
;
1972 StringDBReadStringIdentifier (
1976 WCHAR
*IdentifierName
;
1981 if (fread (&StringId
, sizeof (StringId
), 1, DBFptr
) != 1) {
1982 Error (NULL
, 0, 0, "failed to read StringId from database", NULL
);
1983 return STATUS_ERROR
;
1986 if (fread (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
1987 Error (NULL
, 0, 0, "failed to read StringId flags from database", NULL
);
1988 return STATUS_ERROR
;
1991 if (StringDBReadGenericString (DBFptr
, &Size
, &IdentifierName
) != STATUS_SUCCESS
) {
1992 return STATUS_ERROR
;
1995 StringDBAddStringIdentifier (IdentifierName
, &StringId
, Flags
);
1997 // printf ("STRID: 0x%04X %S\n", (UINT32)StringId, IdentifierName);
1999 FREE (IdentifierName
);
2000 return STATUS_SUCCESS
;
2005 StringDBWriteString (
2014 DB_DATA_ITEM_HEADER Hdr
;
2015 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
2016 Hdr
.DataType
= DB_DATA_TYPE_STRING_DEFINITION
;
2017 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
2018 Error (NULL
, 0, 0, "failed to write string header to output database file", NULL
);
2019 return STATUS_ERROR
;
2022 if (fwrite (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
2023 Error (NULL
, 0, 0, "failed to write string flags to output database", NULL
);
2024 return STATUS_ERROR
;
2027 if (StringDBWriteGenericString (DBFptr
, Language
) != STATUS_SUCCESS
) {
2028 return STATUS_ERROR
;
2031 if (StringDBWriteGenericString (DBFptr
, StringName
) != STATUS_SUCCESS
) {
2032 return STATUS_ERROR
;
2035 if (StringDBWriteGenericString (DBFptr
, Scope
) != STATUS_SUCCESS
) {
2036 return STATUS_ERROR
;
2039 if (StringDBWriteGenericString (DBFptr
, Str
) != STATUS_SUCCESS
) {
2040 return STATUS_ERROR
;
2043 // printf ("DBWriteString: %S.%S.%S\n", Language, StringName, Scope);
2045 return STATUS_SUCCESS
;
2050 StringDBReadString (
2061 if (fread (&Flags
, sizeof (Flags
), 1, DBFptr
) != 1) {
2062 Error (NULL
, 0, 0, "failed to read string flags from database", NULL
);
2063 return STATUS_ERROR
;
2066 if (StringDBReadGenericString (DBFptr
, &Size
, &Language
) != STATUS_SUCCESS
) {
2067 return STATUS_ERROR
;
2070 if (StringDBReadGenericString (DBFptr
, &Size
, &StringName
) != STATUS_SUCCESS
) {
2071 return STATUS_ERROR
;
2074 if (StringDBReadGenericString (DBFptr
, &Size
, &Scope
) != STATUS_SUCCESS
) {
2075 return STATUS_ERROR
;
2078 if (StringDBReadGenericString (DBFptr
, &Size
, &Str
) != STATUS_SUCCESS
) {
2079 return STATUS_ERROR
;
2082 // If the first or second string (language name and printable language name),
2083 // then skip them. They're added via language definitions data items in
2086 if (StringName
[0] != L
'$') {
2087 StringDBAddString (Language
, StringName
, Scope
, Str
, FALSE
, Flags
);
2090 // printf ("DBReadString: %S.%S.%S\n", Language, StringName, Scope);
2098 if (Scope
!= NULL
) {
2102 return STATUS_SUCCESS
;
2107 StringDBWriteLanguageDefinition (
2109 WCHAR
*LanguageName
,
2110 WCHAR
*PrintableLanguageName
2113 DB_DATA_ITEM_HEADER Hdr
;
2114 memset (&Hdr
, 0, sizeof (DB_DATA_ITEM_HEADER
));
2115 Hdr
.DataType
= DB_DATA_TYPE_LANGUAGE_DEFINITION
;
2116 if (fwrite (&Hdr
, sizeof (DB_DATA_ITEM_HEADER
), 1, DBFptr
) != 1) {
2117 Error (NULL
, 0, 0, "failed to write string to output database file", NULL
);
2118 return STATUS_ERROR
;
2121 if (StringDBWriteGenericString (DBFptr
, LanguageName
) != STATUS_SUCCESS
) {
2122 return STATUS_ERROR
;
2125 if (StringDBWriteGenericString (DBFptr
, PrintableLanguageName
) != STATUS_SUCCESS
) {
2126 return STATUS_ERROR
;
2129 return STATUS_SUCCESS
;
2134 StringDBReadLanguageDefinition (
2138 WCHAR
*LanguageName
;
2139 WCHAR
*PrintableLanguageName
;
2143 if (StringDBReadGenericString (DBFptr
, &Size
, &LanguageName
) != STATUS_SUCCESS
) {
2144 return STATUS_ERROR
;
2147 if (StringDBReadGenericString (DBFptr
, &Size
, &PrintableLanguageName
) != STATUS_SUCCESS
) {
2148 return STATUS_ERROR
;
2151 // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);
2153 Status
= StringDBAddLanguage (LanguageName
, PrintableLanguageName
);
2154 FREE (LanguageName
);
2155 FREE (PrintableLanguageName
);
2159 // All unicode strings in the database consist of a UINT16 length
2160 // field, followed by the string itself. This routine reads one
2161 // of those and returns the info.
2165 StringDBReadGenericString (
2175 if (fread (&LSize
, sizeof (UINT16
), 1, DBFptr
) != 1) {
2176 Error (NULL
, 0, 0, "failed to read a string length field from the database", NULL
);
2177 return STATUS_ERROR
;
2180 if (fread (&Flags
, sizeof (UINT16
), 1, DBFptr
) != 1) {
2181 Error (NULL
, 0, 0, "failed to read a string flags field from the database", NULL
);
2182 return STATUS_ERROR
;
2185 LStr
= MALLOC (LSize
);
2187 Error (__FILE__
, __LINE__
, 0, "memory allocation failed reading the database", NULL
);
2188 return STATUS_ERROR
;
2191 if (fread (LStr
, sizeof (WCHAR
), (UINT32
) LSize
/ sizeof (WCHAR
), DBFptr
) != (UINT32
) LSize
/ sizeof (WCHAR
)) {
2192 Error (NULL
, 0, 0, "failed to read string from database", NULL
);
2193 Error (NULL
, 0, 0, "database read failure", "offset 0x%X", ftell (DBFptr
));
2195 return STATUS_ERROR
;
2198 // printf ("DBR: %S\n", LStr);
2200 // If the flags field indicated we were asked to write a NULL string, then
2201 // return them a NULL pointer.
2203 if (Flags
& STRING_FLAGS_UNDEFINED
) {
2211 return STATUS_SUCCESS
;
2216 StringDBWriteGenericString (
2223 WCHAR ZeroString
[1];
2225 // Strings in the database consist of a size UINT16 followed
2226 // by the string itself.
2231 Size
= sizeof (ZeroString
);
2232 Flags
= STRING_FLAGS_UNDEFINED
;
2235 Size
= (UINT16
) ((wcslen (Str
) + 1) * sizeof (WCHAR
));
2238 if (fwrite (&Size
, sizeof (UINT16
), 1, DBFptr
) != 1) {
2239 Error (NULL
, 0, 0, "failed to write string size to database", NULL
);
2240 return STATUS_ERROR
;
2243 if (fwrite (&Flags
, sizeof (UINT16
), 1, DBFptr
) != 1) {
2244 Error (NULL
, 0, 0, "failed to write string flags to database", NULL
);
2245 return STATUS_ERROR
;
2248 if (fwrite (Str
, sizeof (WCHAR
), Size
/ sizeof (WCHAR
), DBFptr
) != Size
/ sizeof (WCHAR
)) {
2249 Error (NULL
, 0, 0, "failed to write string to database", NULL
);
2250 return STATUS_ERROR
;
2253 return STATUS_SUCCESS
;
2258 StringDBFindString (
2259 WCHAR
*LanguageName
,
2262 WCHAR_STRING_LIST
*LanguagesOfInterest
,
2263 WCHAR_MATCHING_STRING_LIST
*IndirectionList
2266 LANGUAGE_LIST
*Lang
;
2267 STRING_LIST
*CurrString
;
2268 WCHAR_MATCHING_STRING_LIST
*IndListPtr
;
2269 WCHAR TempLangName
[LANGUAGE_IDENTIFIER_NAME_LEN
+ 1];
2273 // If we were given an indirection list, then see if one was specified for this
2274 // string identifier. That is to say, if the indirection says "STR_ID_MY_FAVORITE MyScope",
2275 // then if this string name matches one in the list, then do a lookup with the
2276 // specified scope and return that value.
2278 if (IndirectionList
!= NULL
) {
2279 for (IndListPtr
= IndirectionList
; IndListPtr
!= NULL
; IndListPtr
= IndListPtr
->Next
) {
2280 if (wcscmp (StringName
, IndListPtr
->Str1
) == 0) {
2281 CurrString
= StringDBFindString (LanguageName
, StringName
, IndListPtr
->Str2
, LanguagesOfInterest
, NULL
);
2282 if (CurrString
!= NULL
) {
2289 // First look for exact match language.stringname
2291 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
2292 if (wcscmp (LanguageName
, Lang
->LanguageName
) == 0) {
2294 // Found language match. Try to find string name match
2296 for (CurrString
= Lang
->String
; CurrString
!= NULL
; CurrString
= CurrString
->Next
) {
2297 if (wcscmp (StringName
, CurrString
->StringName
) == 0) {
2299 // Found a string name match. See if we're supposed to find
2302 if (Scope
!= NULL
) {
2303 if (wcscmp (CurrString
->Scope
, Scope
) == 0) {
2314 // If we got here, then we didn't find a match. Look for secondary string
2315 // matches. That is to say, if we're processing "spa", and they requested
2316 // "spa+cat", then recursively call with "cat"
2318 while (LanguagesOfInterest
!= NULL
) {
2320 // If this is the language we're looking for, then process the
2321 // languages of interest list for it.
2323 if (wcsncmp (LanguageName
, LanguagesOfInterest
->Str
, LANGUAGE_IDENTIFIER_NAME_LEN
) == 0) {
2324 WCharPtr
= LanguagesOfInterest
->Str
+ LANGUAGE_IDENTIFIER_NAME_LEN
;
2327 // Double-check the length, though it should have been checked on the
2330 if (wcslen (WCharPtr
) < LANGUAGE_IDENTIFIER_NAME_LEN
) {
2331 Error (NULL
, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest
->Str
);
2335 wcsncpy (TempLangName
, WCharPtr
, LANGUAGE_IDENTIFIER_NAME_LEN
);
2336 TempLangName
[LANGUAGE_IDENTIFIER_NAME_LEN
] = 0;
2337 CurrString
= StringDBFindString (TempLangName
, StringName
, NULL
, NULL
, IndirectionList
);
2338 if (CurrString
!= NULL
) {
2342 WCharPtr
+= LANGUAGE_IDENTIFIER_NAME_LEN
;
2346 LanguagesOfInterest
= LanguagesOfInterest
->Next
;
2358 // Free up existing scope memory.
2360 if (mDBData
.CurrentScope
!= NULL
) {
2361 FREE (mDBData
.CurrentScope
);
2364 mDBData
.CurrentScope
= DuplicateString (Scope
);
2365 return STATUS_SUCCESS
;
2368 // We typically don't assign index values to string identifiers
2369 // until we're ready to write out files. To reduce the size of
2370 // the output file, re-order the string identifiers to move any
2371 // unreferenced ones to the end. Then we'll walk the list
2372 // again to assign string indexes, keeping track of the last
2377 StringDBAssignStringIndexes (
2381 STRING_IDENTIFIER
*StrId
;
2382 STRING_IDENTIFIER
*FirstUsed
;
2383 STRING_IDENTIFIER
*LastUsed
;
2384 STRING_IDENTIFIER
*FirstUnused
;
2385 STRING_IDENTIFIER
*LastUnused
;
2387 UINT32 MaxReferenced
;
2390 // Create two lists -- used and unused. Then put them together with
2391 // the unused ones on the end.
2397 StrId
= mDBData
.StringIdentifier
;
2398 while (StrId
!= NULL
) {
2399 if ((StrId
->Flags
& STRING_FLAGS_REFERENCED
) == 0) {
2401 // Put it on the unused list
2403 if (FirstUnused
== NULL
) {
2404 FirstUnused
= StrId
;
2406 LastUnused
->Next
= StrId
;
2410 StrId
= StrId
->Next
;
2411 LastUnused
->Next
= NULL
;
2414 // Put it on the used list
2416 if (FirstUsed
== NULL
) {
2419 LastUsed
->Next
= StrId
;
2423 StrId
= StrId
->Next
;
2424 LastUsed
->Next
= NULL
;
2430 if (FirstUsed
!= NULL
) {
2431 mDBData
.StringIdentifier
= FirstUsed
;
2432 LastUsed
->Next
= FirstUnused
;
2434 mDBData
.StringIdentifier
= FirstUnused
;
2439 for (StrId
= mDBData
.StringIdentifier
; StrId
!= NULL
; StrId
= StrId
->Next
) {
2440 StrId
->Index
= Index
;
2442 if (StrId
->Flags
& STRING_FLAGS_REFERENCED
) {
2443 mDBData
.NumStringIdentifiersReferenced
= Index
;
2447 mDBData
.NumStringIdentifiers
= Index
;
2461 NewStr
= MALLOC ((wcslen (Str
) + 1) * sizeof (WCHAR
));
2462 if (NewStr
== NULL
) {
2463 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
2467 wcscpy (NewStr
, Str
);
2481 Len
= strlen (Str
) + 1;
2482 NewStr
= (WCHAR
*) malloc (Len
* sizeof (WCHAR
));
2483 for (Ptr
= NewStr
; *Str
!= 0; Str
++, Ptr
++) {
2484 *Ptr
= (UINT16
) (UINT8
) *Str
;
2491 /*****************************************************************************/
2495 Routine Description:
2497 Create an HII export string pack for the strings in our database.
2501 FileName - name of the output file to write
2510 StringDBCreateHiiExportPack (
2512 WCHAR_STRING_LIST
*LanguagesOfInterest
2516 LANGUAGE_LIST
*Lang
;
2517 STRING_LIST
*CurrString
;
2518 STRING_LIST EmptyString
;
2522 EFI_HII_STRING_PACK_HEADER StringPack
;
2524 WCHAR ZeroString
[1];
2525 WCHAR
*TempStringPtr
;
2527 STRING_IDENTIFIER
*StringIdentifier
;
2528 WCHAR_STRING_LIST
*LOIPtr
;
2532 if ((Fptr
= fopen (FileName
, "wb")) == NULL
) {
2533 Error (NULL
, 0, 0, FileName
, "failed to open output HII export file");
2534 return STATUS_ERROR
;
2537 // Assign index values to the string identifiers
2539 StringDBAssignStringIndexes ();
2541 // If a given string is not defined, then we'll use this one.
2543 memset (&EmptyString
, 0, sizeof (EmptyString
));
2544 EmptyString
.Size
= sizeof (ZeroString
);
2545 EmptyString
.Str
= ZeroString
;
2547 // Process each language, then each string for each langage
2550 for (Lang
= mDBData
.LanguageList
; Lang
!= NULL
; Lang
= Lang
->Next
) {
2552 // If we have a language list, then make sure this language is in that
2556 if (LanguagesOfInterest
!= NULL
) {
2558 for (LOIPtr
= LanguagesOfInterest
; LOIPtr
!= NULL
; LOIPtr
= LOIPtr
->Next
) {
2559 if (wcsncmp (LOIPtr
->Str
, Lang
->LanguageName
, LANGUAGE_IDENTIFIER_NAME_LEN
) == 0) {
2571 // Process each string for this language. We have to make 3 passes on the strings:
2572 // Pass1: computes sizes and fill in the string pack header
2573 // Pass2: write the array of offsets
2574 // Pass3: write the strings
2577 // PASS 1: Fill in and print the HII string pack header
2579 // Compute the size for this language package and write
2580 // the header out. Each string package contains:
2582 // Offset[] -- an array of offsets to strings, of type RELOFST each
2583 // String[] -- the actual strings themselves
2585 memset ((char *) &StringPack
, 0, sizeof (EFI_HII_STRING_PACK_HEADER
));
2586 StringPack
.Header
.Type
= EFI_HII_STRING
;
2587 StringPack
.NumStringPointers
= (UINT16
) mDBData
.NumStringIdentifiersReferenced
;
2588 LangName
= Lang
->LanguageName
;
2590 // First string is the language name. If we're printing all languages, then
2591 // it's just the "spa". If we were given a list of languages to print, then it's
2592 // the "spacat" string. Compute its offset and fill in
2593 // the info in the header. Since we know the language name string's length,
2594 // and the printable language name follows it, use that info to fill in the
2595 // entry for the printable language name as well.
2597 StringPack
.LanguageNameString
= (STRING_OFFSET
) (sizeof (EFI_HII_STRING_PACK_HEADER
) + (mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
)));
2598 StringPack
.PrintableLanguageName
= (STRING_OFFSET
) (StringPack
.LanguageNameString
+ (wcslen (LangName
) + 1) * sizeof (WCHAR
));
2600 // Add up the size of all strings so we can fill in our header.
2603 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
2605 // For the first string (language name), we print out the "spacat" if they
2606 // requested it. We set LangName to point to the proper language name string above.
2608 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
2609 Len
+= (wcslen (LangName
) + 1) * sizeof (WCHAR
);
2612 // Find a string with this language.stringname
2614 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
2615 if (StringIdentifier
== NULL
) {
2616 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
2617 return STATUS_ERROR
;
2620 // Find a matching string if this string identifier was referenced
2622 EmptyString
.Flags
= STRING_FLAGS_UNDEFINED
;
2624 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
2625 CurrString
= StringDBFindString (
2627 StringIdentifier
->StringName
,
2629 NULL
, // LanguagesOfInterest,
2633 // IndirectionList);
2635 if (NULL
== CurrString
) {
2637 // If string for Lang->LanguageName is not found, try to get an English version
2639 CurrString
= StringDBFindString (
2641 StringIdentifier
->StringName
,
2643 NULL
, // LanguagesOfInterest,
2647 // IndirectionList);
2652 if (CurrString
== NULL
) {
2653 CurrString
= &EmptyString
;
2654 EmptyString
.Flags
|= StringIdentifier
->Flags
;
2657 Len
+= CurrString
->Size
;
2660 StringPack
.Header
.Length
= sizeof (EFI_HII_STRING_PACK_HEADER
)
2661 + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
)
2664 // Write out the string pack header
2666 fwrite ((void *) &StringPack
, sizeof (StringPack
), 1, Fptr
);
2668 // PASS2 : write the offsets
2670 // Traverse the list of strings again and write the array of offsets. The
2671 // offset to the first string is the size of the string pack header
2672 // plus the size of the offsets array. The other strings follow it.
2675 Offset
= sizeof (StringPack
) + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
);
2676 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
2680 fwrite (&Offset
, sizeof (STRING_OFFSET
), 1, Fptr
);
2682 // Find the string name
2684 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
2685 if (StringIdentifier
== NULL
) {
2686 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
2687 return STATUS_ERROR
;
2690 // For the first string (language name), we print out the "spacat" if they
2691 // requested it. We set LangName to point to the proper language name string above.
2693 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
2694 Offset
+= (wcslen (LangName
) + 1) * sizeof (WCHAR
);
2695 CurrString
= StringDBFindString (
2697 StringIdentifier
->StringName
,
2704 // Find a matching string
2706 CurrString
= StringDBFindString (
2708 StringIdentifier
->StringName
,
2710 NULL
, // LanguagesOfInterest,
2714 // IndirectionList);
2716 if (NULL
== CurrString
) {
2717 CurrString
= StringDBFindString (
2719 StringIdentifier
->StringName
,
2721 NULL
, // LanguagesOfInterest,
2725 // IndirectionList);
2729 EmptyString
.LanguageName
= Lang
->LanguageName
;
2730 if (CurrString
== NULL
) {
2731 CurrString
= &EmptyString
;
2732 EmptyString
.Flags
= STRING_FLAGS_UNDEFINED
;
2733 } else if ((StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) == 0) {
2734 CurrString
= &EmptyString
;
2735 EmptyString
.Flags
= 0;
2738 Offset
+= CurrString
->Size
;
2743 // PASS 3: write the strings themselves.
2745 Offset
= sizeof (StringPack
) + mDBData
.NumStringIdentifiersReferenced
* sizeof (STRING_OFFSET
);
2746 for (StringIndex
= 0; StringIndex
< mDBData
.NumStringIdentifiersReferenced
; StringIndex
++) {
2747 StringIdentifier
= StringDBFindStringIdentifierByIndex (StringIndex
);
2748 if (StringIdentifier
== NULL
) {
2749 Error (NULL
, 0, 0, "internal error", "invalid string index 0x%X", StringIndex
);
2750 return STATUS_ERROR
;
2753 // For the first string (language name), we print out the "spacat" if they
2754 // requested it. We set LangName to point to the proper language name string above.
2756 if (StringIndex
== STRING_ID_LANGUAGE_NAME
) {
2757 TempStringPtr
= LangName
;
2760 // Find a matching string if this string identifier was referenced
2763 if (StringIdentifier
->Flags
& STRING_FLAGS_REFERENCED
) {
2764 CurrString
= StringDBFindString (
2766 StringIdentifier
->StringName
,
2768 NULL
, // LanguagesOfInterest,
2772 // IndirectionList);
2774 if (NULL
== CurrString
) {
2775 CurrString
= StringDBFindString (
2777 StringIdentifier
->StringName
,
2779 NULL
, // LanguagesOfInterest,
2783 // IndirectionList);
2788 if (CurrString
== NULL
) {
2789 CurrString
= &EmptyString
;
2792 TempStringPtr
= CurrString
->Str
;
2795 for (TempIndex
= 0; TempStringPtr
[TempIndex
] != 0; TempIndex
++) {
2796 fwrite (&TempStringPtr
[TempIndex
], sizeof (CHAR16
), 1, Fptr
);
2800 // Print NULL WCHAR at the end of this string.
2803 fwrite (&TempIndex
, sizeof (CHAR16
), 1, Fptr
);
2807 // Sanity check the offset. Make sure our running offset is what we put in the
2808 // string pack header.
2810 if (StringPack
.Header
.Length
!= Offset
) {
2815 "application error",
2816 "stringpack size 0x%X does not match final size 0x%X",
2817 StringPack
.Header
.Length
,
2823 // Print terminator string pack, closing brace and close the file.
2824 // The size of 0 triggers to the consumer that this is the end.
2826 memset ((char *) &StringPack
, 0, sizeof (EFI_HII_STRING_PACK_HEADER
));
2827 StringPack
.Header
.Type
= EFI_HII_STRING
;
2828 fwrite ((void *) &StringPack
, sizeof (StringPack
), 1, Fptr
);
2830 return STATUS_SUCCESS
;