1 /*++
2 
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
8 
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.
11 
12 Module Name:
13 
14   StringDB.c
15 
16 Abstract:
17 
18   String database implementation
19 
20 --*/
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26 #include <Tiano.h>
27 #include <EfiUtilityMsgs.h>
28 #include <EfiHii.h>
29 #include "StrGather.h"
30 #include "StringDb.h"
31 
32 static STRING_DB_DATA mDBData;
33 
34 static const char     *mSourceFileHeader[] = {
35   "//",
36   "//  DO NOT EDIT -- auto-generated file",
37   "//",
38   "//  This file is generated by the string gather utility",
39   "//",
40   NULL
41 };
42 
43 static
44 STRING_LIST           *
45 StringDBFindString (
46   WCHAR                       *LanguageName,
47   WCHAR                       *StringName,
48   WCHAR                       *Scope,
49   WCHAR_STRING_LIST           *LanguagesOfInterest,
50   WCHAR_MATCHING_STRING_LIST  *IndirectionList
51   );
52 
53 static
54 STRING_IDENTIFIER     *
55 StringDBFindStringIdentifierByName (
56   WCHAR *Name
57   );
58 
59 static
60 STRING_IDENTIFIER     *
61 StringDBFindStringIdentifierByIndex (
62   UINT32    Index
63   );
64 
65 static
66 void
67 StringDBWriteStandardFileHeader (
68   FILE *OutFptr
69   );
70 
71 static
72 WCHAR                 *
73 AsciiToWchar (
74   INT8 *Str
75   );
76 
77 static
78 CHAR8 *
79 WcharToAscii (
80   WCHAR *Str
81   );
82 
83 static
84 WCHAR                 *
85 DuplicateString (
86   WCHAR   *Str
87   );
88 
89 static
90 WCHAR *
91 WstrCatenate (
92   WCHAR *Dst,
93   WCHAR *Src
94   );
95 
96 static
97 STATUS
98 StringDBWriteStringIdentifier (
99   FILE                *DBFptr,
100   UINT16              StringId,
101   UINT16              Flags,
102   WCHAR               *IdentifierName
103   );
104 
105 static
106 STATUS
107 StringDBReadStringIdentifier (
108   FILE                *DBFptr
109   );
110 
111 static
112 STATUS
113 StringDBWriteLanguageDefinition (
114   FILE            *DBFptr,
115   WCHAR           *LanguageName,
116   WCHAR           *PrintableLanguageName,
117   WCHAR           *SecondaryLanguageList
118   );
119 
120 static
121 STATUS
122 StringDBReadLanguageDefinition (
123   FILE            *DBFptr
124   );
125 
126 static
127 STATUS
128 StringDBWriteString (
129   FILE            *DBFptr,
130   UINT16          Flags,
131   WCHAR           *Language,
132   WCHAR           *StringName,
133   WCHAR           *Scope,
134   WCHAR           *Str
135   );
136 
137 static
138 STATUS
139 StringDBReadString (
140   FILE            *DBFptr
141   );
142 
143 static
144 STATUS
145 StringDBReadGenericString (
146   FILE      *DBFptr,
147   UINT16    *Size,
148   WCHAR     **Str
149   );
150 
151 static
152 STATUS
153 StringDBWriteGenericString (
154   FILE      *DBFptr,
155   WCHAR     *Str
156   );
157 
158 static
159 void
160 StringDBAssignStringIndexes (
161   VOID
162   );
163 
164 /*****************************************************************************/
165 
166 /*++
167 
168 Routine Description:
169   Constructor function for the string database handler.
170 
171 Arguments:
172   None.
173 
174 Returns:
175   None.
176 
177 --*/
178 void
StringDBConstructor(VOID)179 StringDBConstructor (
180   VOID
181   )
182 {
183   memset ((char *) &mDBData, 0, sizeof (STRING_DB_DATA));
184   mDBData.CurrentScope = DuplicateString (L"NULL");
185 }
186 
187 /*****************************************************************************/
188 
189 /*++
190 
191 Routine Description:
192   Destructor function for the string database handler.
193 
194 Arguments:
195   None.
196 
197 Returns:
198   None.
199 
200 --*/
201 void
StringDBDestructor(VOID)202 StringDBDestructor (
203   VOID
204   )
205 {
206   LANGUAGE_LIST     *NextLang;
207   STRING_LIST       *NextStr;
208   STRING_IDENTIFIER *NextIdentifier;
209   //
210   // Close the database file if it's open
211   //
212   if (mDBData.StringDBFptr != NULL) {
213     fclose (mDBData.StringDBFptr);
214     mDBData.StringDBFptr = NULL;
215   }
216   //
217   // If we've allocated any strings/languages, free them up
218   //
219   while (mDBData.LanguageList != NULL) {
220     NextLang = mDBData.LanguageList->Next;
221     //
222     // Free up all strings for this language
223     //
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;
229     }
230 
231     FREE (mDBData.LanguageList->SecondaryLanguageList);
232     FREE (mDBData.LanguageList->PrintableLanguageName);
233     FREE (mDBData.LanguageList);
234     mDBData.LanguageList = NextLang;
235   }
236   //
237   // Free up string identifiers
238   //
239   while (mDBData.StringIdentifier != NULL) {
240     NextIdentifier = mDBData.StringIdentifier->Next;
241     FREE (mDBData.StringIdentifier->StringName);
242     FREE (mDBData.StringIdentifier);
243     mDBData.StringIdentifier = NextIdentifier;
244   }
245   //
246   // Free the filename
247   //
248   if (mDBData.StringDBFileName != NULL) {
249     FREE (mDBData.StringDBFileName);
250     mDBData.StringDBFileName = NULL;
251   }
252   //
253   // We save a copy of the scope, so free it up if we
254   // have one.
255   //
256   if (mDBData.CurrentScope != NULL) {
257     FREE (mDBData.CurrentScope);
258     mDBData.CurrentScope = NULL;
259   }
260 }
261 
262 /*****************************************************************************/
263 STATUS
StringDBDumpStringDefines(INT8 * FileName,INT8 * BaseName)264 StringDBDumpStringDefines (
265   INT8 *FileName,
266   INT8 *BaseName
267   )
268 {
269   FILE              *Fptr;
270   STRING_IDENTIFIER *Identifier;
271   INT8              CopyBaseName[100];
272   UINT32            Index;
273   const INT8        *StrDefHeader[] = {
274     "#ifndef _%s_STRINGS_DEFINE_H_\n",
275     "#define _%s_STRINGS_DEFINE_H_\n\n",
276     NULL
277   };
278 
279   if ((Fptr = fopen (FileName, "w")) == NULL) {
280     Error (NULL, 0, 0, FileName, "failed to open output string defines file");
281     return STATUS_ERROR;
282   }
283   //
284   // Get the base source filename and convert to uppercase.
285   //
286   if (sizeof (CopyBaseName) <= strlen (BaseName) + 1) {
287     Error (NULL, 0, 0, "application error", "StringDBDumpStringDefines() string length insufficient");
288     return STATUS_ERROR;
289   }
290 
291   strcpy (CopyBaseName, BaseName);
292   for (Index = 0; CopyBaseName[Index] != 0; Index++) {
293     if (islower (CopyBaseName[Index])) {
294       CopyBaseName[Index] = (INT8) toupper (CopyBaseName[Index]);
295     }
296   }
297   //
298   // Assign index values to the string identifiers
299   //
300   StringDBAssignStringIndexes ();
301   //
302   // Write the standard header to the output file, and then the
303   // protective #ifndef.
304   //
305   StringDBWriteStandardFileHeader (Fptr);
306   for (Index = 0; StrDefHeader[Index] != NULL; Index++) {
307     fprintf (Fptr, StrDefHeader[Index], CopyBaseName);
308   }
309   //
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.
313   //
314   Identifier = mDBData.StringIdentifier;
315   while (Identifier != NULL) {
316     if (Identifier->StringName[0] == L'$') {
317       fprintf (Fptr, "// ");
318     }
319 
320     if (Identifier->Flags & STRING_FLAGS_REFERENCED) {
321       fprintf (Fptr, "#define %-40S 0x%04X\n", Identifier->StringName, Identifier->Index);
322     } else {
323       fprintf (Fptr, "//#define %-40S 0x%04X // not referenced\n", Identifier->StringName, Identifier->Index);
324     }
325 
326     Identifier = Identifier->Next;
327   }
328 
329   fprintf (Fptr, "\n#endif\n");
330   fclose (Fptr);
331   return STATUS_SUCCESS;
332 }
333 
334 /*****************************************************************************/
335 
336 /*++
337 
338 Routine Description:
339 
340   Add a string identifier to the database.
341 
342 Arguments:
343 
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
347 
348 Returns:
349 
350   STATUS
351 
352 --*/
353 STATUS
StringDBAddStringIdentifier(WCHAR * StringName,UINT16 * NewId,UINT16 Flags)354 StringDBAddStringIdentifier (
355   WCHAR     *StringName,
356   UINT16    *NewId,
357   UINT16    Flags
358   )
359 {
360   STRING_IDENTIFIER *StringIdentifier;
361   STATUS            Status;
362   //
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.
366   //
367   Status            = STATUS_SUCCESS;
368   StringIdentifier  = StringDBFindStringIdentifierByName (StringName);
369   if (StringIdentifier != NULL) {
370     if (Flags & STRING_FLAGS_REFERENCED) {
371       StringIdentifier->Flags |= STRING_FLAGS_REFERENCED;
372     }
373 
374     mDBData.CurrentStringIdentifier = StringIdentifier;
375     *NewId                          = (UINT16) StringIdentifier->Index;
376     return Status;
377   }
378 
379   StringIdentifier = (STRING_IDENTIFIER *) MALLOC (sizeof (STRING_IDENTIFIER));
380   if (StringIdentifier == NULL) {
381     Error (NULL, 0, 0, NULL, "memory allocation error");
382     return STATUS_ERROR;
383   }
384 
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");
389     return STATUS_ERROR;
390   }
391 
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;
398     }
399   } else {
400     StringIdentifier->Index = mDBData.NumStringIdentifiers++;
401   }
402 
403   StringIdentifier->Flags |= Flags;
404   //
405   // Add it to our list of string identifiers
406   //
407   if (mDBData.StringIdentifier == NULL) {
408     mDBData.StringIdentifier = StringIdentifier;
409   } else {
410     mDBData.LastStringIdentifier->Next = StringIdentifier;
411   }
412 
413   mDBData.LastStringIdentifier    = StringIdentifier;
414   mDBData.CurrentStringIdentifier = StringIdentifier;
415   *NewId                          = (UINT16) StringIdentifier->Index;
416   return Status;
417 }
418 
419 /*****************************************************************************/
420 
421 /*++
422 
423 Routine Description:
424 
425   Add a new string to the database.
426 
427 Arguments:
428 
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
434 
435 Returns:
436 
437   STATUS
438 
439 Notes:
440 
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.
444 
445 --*/
446 STATUS
StringDBAddString(WCHAR * LanguageName,WCHAR * StringName,WCHAR * Scope,WCHAR * String,BOOLEAN Format,UINT16 Flags)447 StringDBAddString (
448   WCHAR   *LanguageName,
449   WCHAR   *StringName,
450   WCHAR   *Scope,
451   WCHAR   *String,
452   BOOLEAN Format,
453   UINT16  Flags
454   )
455 {
456   LANGUAGE_LIST     *Lang;
457   UINT32            Size;
458   STRING_LIST       *Str;
459   UINT16            StringIndex;
460   STRING_IDENTIFIER *StringIdentifier;
461 
462   //
463   // If they specified a language, make sure they've defined it already
464   // via a #langdef statement. Otherwise use the current default language.
465   //
466   if (LanguageName != NULL) {
467     Lang = StringDBFindLanguageList (LanguageName);
468     if (Lang == NULL) {
469       ParserError (0, "language not defined", "%S", LanguageName);
470       return STATUS_ERROR;
471     } else {
472       StringDBSetCurrentLanguage (LanguageName);
473     }
474   } else {
475     Lang = mDBData.CurrentLanguage;
476     if (Lang == NULL) {
477       //
478       // Have to call SetLanguage() first
479       //
480       ParserError (0, "no language defined", "%S", StringName);
481       return STATUS_ERROR;
482     }
483   }
484   //
485   // If they didn't define a string identifier, use the last string identifier
486   // added.
487   //
488   if (StringName == NULL) {
489     StringName = mDBData.CurrentStringIdentifier->StringName;
490     if (StringName == NULL) {
491       ParserError (0, "no string identifier previously specified", NULL);
492       return STATUS_ERROR;
493     }
494   }
495   //
496   // If scope was not specified, use the default setting
497   //
498   if (Scope != NULL) {
499     Scope = DuplicateString (Scope);
500   } else {
501     Scope = DuplicateString (mDBData.CurrentScope);
502   }
503   //
504   // printf ("Adding string: %S.%S.%S\n", Lang->LanguageName, StringName, Scope);
505   //
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.
509   //
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)
513         ) {
514       ParserError (
515         0,
516         "string multiply defined",
517         "Language.Name.Scope = %S.%S.%S",
518         Lang->LanguageName,
519         StringName,
520         Scope
521         );
522       return STATUS_ERROR;
523     }
524   }
525 
526   StringIndex = STRING_ID_INVALID;
527   if (StringDBAddStringIdentifier (StringName, &StringIndex, Flags) != STATUS_SUCCESS) {
528     return STATUS_ERROR;
529   }
530 
531   StringIdentifier = StringDBFindStringIdentifierByName (StringName);
532   //
533   // Add this string to the end of the strings for this language.
534   //
535   Str = (STRING_LIST *) malloc (sizeof (STRING_LIST));
536   if (Str == NULL) {
537     Error (NULL, 0, 0, NULL, "memory allocation error");
538     return STATUS_ERROR;
539   }
540 
541   memset ((char *) Str, 0, sizeof (STRING_LIST));
542   Size              = (wcslen (String) + 1) * sizeof (WCHAR);
543   Str->Flags        = Flags;
544   Str->Scope        = Scope;
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");
550     return STATUS_ERROR;
551   }
552   //
553   // If not formatting, just copy the string.
554   //
555   wcscpy (Str->Str, String);
556   if (Format) {
557     StringDBFormatString (Str->Str);
558   }
559   //
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.
563   //
564   Str->Size = (wcslen (Str->Str) + 1) * sizeof (WCHAR);
565   if (Lang->String == NULL) {
566     Lang->String = Str;
567   } else {
568     Lang->LastString->Next = Str;
569   }
570 
571   Lang->LastString = Str;
572   return STATUS_SUCCESS;
573 }
574 
575 /*****************************************************************************/
576 
577 /*++
578 
579 Routine Description:
580 
581   Given a language name, see if a language list for it has been defined
582 
583 Arguments:
584 
585   LanguageName    - like "eng"
586 
587 Returns:
588 
589   A pointer to the language list
590 
591 --*/
592 LANGUAGE_LIST *
StringDBFindLanguageList(WCHAR * LanguageName)593 StringDBFindLanguageList (
594   WCHAR *LanguageName
595   )
596 {
597   LANGUAGE_LIST *Lang;
598 
599   Lang = mDBData.LanguageList;
600   while (Lang != NULL) {
601     if (wcscmp (LanguageName, Lang->LanguageName) == 0) {
602       break;
603     }
604 
605     Lang = Lang->Next;
606   }
607 
608   return Lang;
609 }
610 
611 /*****************************************************************************/
612 STATUS
StringDBSetCurrentLanguage(WCHAR * LanguageName)613 StringDBSetCurrentLanguage (
614   WCHAR *LanguageName
615   )
616 {
617   LANGUAGE_LIST *Lang;
618 
619   Lang = StringDBFindLanguageList (LanguageName);
620   if (Lang == NULL) {
621     ParserError (0, "language not previously defined", "%S", LanguageName);
622     return STATUS_ERROR;
623   }
624 
625   mDBData.CurrentLanguage = Lang;
626   return STATUS_SUCCESS;
627 }
628 
629 /*****************************************************************************/
630 STATUS
StringDBAddLanguage(WCHAR * LanguageName,WCHAR * PrintableLanguageName,WCHAR * SecondaryLanguageList)631 StringDBAddLanguage (
632   WCHAR *LanguageName,
633   WCHAR *PrintableLanguageName,
634   WCHAR *SecondaryLanguageList
635   )
636 {
637   LANGUAGE_LIST *Lang;
638   //
639   // Check for redefinitions
640   //
641   Lang = StringDBFindLanguageList (LanguageName);
642   if (Lang != NULL) {
643     //
644     // Better be the same printable name
645     //
646     if (wcscmp (PrintableLanguageName, Lang->PrintableLanguageName) != 0) {
647       ParserError (
648         0,
649         "language redefinition",
650         "%S:%S != %S:%S",
651         Lang->LanguageName,
652         Lang->PrintableLanguageName,
653         LanguageName,
654         PrintableLanguageName
655         );
656       return STATUS_ERROR;
657       //
658       //    } else {
659       //      ParserWarning (0, "benign language redefinition", "%S", PrintableLanguageName);
660       //      return STATUS_WARNING;
661       //
662     }
663   } else {
664     //
665     // Allocate memory to keep track of this new language
666     //
667     Lang = (LANGUAGE_LIST *) malloc (sizeof (LANGUAGE_LIST));
668     if (Lang == NULL) {
669       Error (NULL, 0, 0, NULL, "memory allocation error");
670       return STATUS_ERROR;
671     }
672 
673     memset ((char *) Lang, 0, sizeof (LANGUAGE_LIST));
674     //
675     // Save the language name, then allocate memory to save the
676     // printable language name
677     //
678     Lang->LanguageName = (WCHAR *) malloc ((wcslen (LanguageName) + 1) * 2);
679 	if (Lang->LanguageName == NULL) {
680       Error (NULL, 0, 0, NULL, "memory allocation error");
681       return STATUS_ERROR;
682     }
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);
688       return STATUS_ERROR;
689     }
690     wcscpy (Lang->PrintableLanguageName, PrintableLanguageName);
691 
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);
698         return STATUS_ERROR;
699       }
700       wcscpy (Lang->SecondaryLanguageList, SecondaryLanguageList);
701 	} else {
702       Lang->SecondaryLanguageList = NULL;
703 	}
704 
705     if (mDBData.LanguageList == NULL) {
706       mDBData.LanguageList = Lang;
707     } else {
708       mDBData.LastLanguageList->Next = Lang;
709     }
710 
711     mDBData.LastLanguageList = Lang;
712   }
713   //
714   // Default is to make our active language this new one
715   //
716   StringDBSetCurrentLanguage (LanguageName);
717   //
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.
721   //
722   StringDBAddString (
723     LanguageName,
724     LANGUAGE_NAME_STRING_NAME,
725     NULL,
726     LanguageName,
727     FALSE,
728     STRING_FLAGS_REFERENCED
729     );
730   StringDBAddString (
731     LanguageName,
732     PRINTABLE_LANGUAGE_NAME_STRING_NAME,
733     NULL,
734     PrintableLanguageName,
735     FALSE,
736     STRING_FLAGS_REFERENCED
737     );
738   return STATUS_SUCCESS;
739 }
740 
741 STATUS
StringDBAddSecondaryLanguage(WCHAR * LanguageName,WCHAR * SecondaryLanguageList)742 StringDBAddSecondaryLanguage (
743   WCHAR *LanguageName,
744   WCHAR *SecondaryLanguageList
745   )
746 {
747   LANGUAGE_LIST *Lang;
748 
749   Lang = StringDBFindLanguageList (LanguageName);
750   if (Lang == NULL) {
751     return STATUS_ERROR;
752   } else {
753     Lang->SecondaryLanguageList = WstrCatenate(Lang->SecondaryLanguageList, SecondaryLanguageList);
754     return STATUS_SUCCESS;
755   }
756 }
757 
758 /*****************************************************************************/
759 static
760 STRING_IDENTIFIER *
StringDBFindStringIdentifierByName(WCHAR * StringName)761 StringDBFindStringIdentifierByName (
762   WCHAR *StringName
763   )
764 {
765   STRING_IDENTIFIER *Identifier;
766 
767   Identifier = mDBData.StringIdentifier;
768   while (Identifier != NULL) {
769     if (wcscmp (StringName, Identifier->StringName) == 0) {
770       return Identifier;
771     }
772 
773     Identifier = Identifier->Next;
774   }
775 
776   return NULL;
777 }
778 
779 static
780 STRING_IDENTIFIER *
StringDBFindStringIdentifierByIndex(UINT32 StringIndex)781 StringDBFindStringIdentifierByIndex (
782   UINT32    StringIndex
783   )
784 {
785   STRING_IDENTIFIER *Identifier;
786 
787   Identifier = mDBData.StringIdentifier;
788   while (Identifier != NULL) {
789     if (Identifier->Index == StringIndex) {
790       return Identifier;
791     }
792 
793     Identifier = Identifier->Next;
794   }
795 
796   return NULL;
797 }
798 
799 /*****************************************************************************/
800 static
801 void
StringDBWriteStandardFileHeader(FILE * OutFptr)802 StringDBWriteStandardFileHeader (
803   FILE *OutFptr
804   )
805 {
806   UINT32  TempIndex;
807   for (TempIndex = 0; mSourceFileHeader[TempIndex] != NULL; TempIndex++) {
808     fprintf (OutFptr, "%s\n", mSourceFileHeader[TempIndex]);
809   }
810 }
811 
812 /*****************************************************************************/
813 
814 /*++
815 
816 Routine Description:
817 
818   Given a Unicode string from an input file, reformat the string to replace
819   backslash control sequences with the appropriate encoding.
820 
821 Arguments:
822 
823   String        - pointer to string to reformat
824 
825 Returns:
826 
827   Nothing
828 
829 --*/
830 void
StringDBFormatString(WCHAR * String)831 StringDBFormatString (
832   WCHAR   *String
833   )
834 {
835   WCHAR *From;
836   WCHAR *To;
837   int   HexNibbles;
838   WCHAR HexValue;
839   //
840   // Go through the string and process any formatting characters
841   //
842   From  = String;
843   To    = String;
844   while (*From) {
845     if (*From == UNICODE_BACKSLASH) {
846       //
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.
850       //
851       if (wcsncmp (From, UNICODE_WIDE_STRING, sizeof (UNICODE_WIDE_STRING) / sizeof (WCHAR) - 1) == 0) {
852         *To = WIDE_CHAR;
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) {
855         //
856         // Found: \narrow
857         //
858         *To = NARROW_CHAR;
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) {
861         //
862         // Found: \nbr
863         //
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) {
867         //
868         // Found: \br -- pass through untouched
869         //
870         *To = *From;
871       } else {
872         //
873         // Standard one-character control sequences such as \n, \r, \\, or \x
874         //
875         From++;
876         switch (*From) {
877         case ASCII_TO_UNICODE ('n'):
878           *To = UNICODE_CR;
879           To++;
880           *To = UNICODE_LF;
881           break;
882 
883         //
884         // carriage return
885         //
886         case ASCII_TO_UNICODE ('r'):
887           *To = UNICODE_CR;
888           break;
889 
890         //
891         // backslash
892         //
893         case UNICODE_BACKSLASH:
894           *To = UNICODE_BACKSLASH;
895           break;
896 
897         //
898         // Tab
899         //
900         case ASCII_TO_UNICODE ('t'):
901           *To = UNICODE_TAB;
902           break;
903 
904         //
905         // embedded double-quote
906         //
907         case UNICODE_DOUBLE_QUOTE:
908           *To = UNICODE_DOUBLE_QUOTE;
909           break;
910 
911         //
912         // Hex Unicode character \x1234. We'll process up to 4 hex characters
913         //
914         case ASCII_TO_UNICODE ('x'):
915           HexValue = 0;
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);
923             } else {
924               break;
925             }
926 
927             From++;
928           }
929 
930           if (HexNibbles == 0) {
931             ParserWarning (
932               0,
933               "expected at least one valid hex digit with \\x escaped character in string",
934               "\\%C",
935               *From
936               );
937           } else {
938             *To = HexValue;
939           }
940           break;
941 
942         default:
943           *To = UNICODE_SPACE;
944           ParserWarning (0, "invalid escaped character in string", "\\%C", *From);
945           break;
946         }
947       }
948     } else {
949       *To = *From;
950     }
951 
952     From++;
953     To++;
954   }
955 
956   *To = 0;
957 }
958 
959 /*****************************************************************************/
960 STATUS
StringDBReadDatabase(INT8 * DBFileName,BOOLEAN IgnoreIfNotExist,BOOLEAN Verbose)961 StringDBReadDatabase (
962   INT8    *DBFileName,
963   BOOLEAN IgnoreIfNotExist,
964   BOOLEAN Verbose
965   )
966 {
967   STRING_DB_HEADER    DbHeader;
968   STATUS              Status;
969   FILE                *DBFptr;
970   DB_DATA_ITEM_HEADER DataItemHeader;
971 
972   Status  = STATUS_SUCCESS;
973   DBFptr  = NULL;
974   //
975   //  if (Verbose) {
976   //    fprintf (stdout, "Reading database file %s\n", DBFileName);
977   //  }
978   //
979   // Try to open the input file
980   //
981   if ((DBFptr = fopen (DBFileName, "rb")) == NULL) {
982     if (IgnoreIfNotExist) {
983       return STATUS_SUCCESS;
984     }
985 
986     Error (NULL, 0, 0, DBFileName, "failed to open input database file for reading");
987     return STATUS_ERROR;
988   }
989   //
990   // Read and verify the database header
991   //
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;
995     goto Finish;
996   }
997 
998   if (DbHeader.Key != STRING_DB_KEY) {
999     Error (NULL, 0, 0, DBFileName, "invalid header in database file");
1000     Status = STATUS_ERROR;
1001     goto Finish;
1002   }
1003 
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;
1007     goto Finish;
1008   }
1009   //
1010   // Read remaining items
1011   //
1012   while (fread (&DataItemHeader, sizeof (DataItemHeader), 1, DBFptr) == 1) {
1013     switch (DataItemHeader.DataType) {
1014     case DB_DATA_TYPE_STRING_IDENTIFIER:
1015       StringDBReadStringIdentifier (DBFptr);
1016       break;
1017 
1018     case DB_DATA_TYPE_LANGUAGE_DEFINITION:
1019       StringDBReadLanguageDefinition (DBFptr);
1020       break;
1021 
1022     case DB_DATA_TYPE_STRING_DEFINITION:
1023       StringDBReadString (DBFptr);
1024       break;
1025 
1026     default:
1027       Error (
1028         NULL,
1029         0,
1030         0,
1031         "database corrupted",
1032         "invalid data item type 0x%X at offset 0x%X",
1033         (UINT32) DataItemHeader.DataType,
1034         ftell (DBFptr) - sizeof (DataItemHeader)
1035         );
1036       Status = STATUS_ERROR;
1037       goto Finish;
1038     }
1039   }
1040 
1041 Finish:
1042   if (DBFptr != NULL) {
1043     fclose (DBFptr);
1044   }
1045 
1046   return Status;
1047 }
1048 
1049 /*****************************************************************************/
1050 
1051 /*++
1052 
1053 Routine Description:
1054 
1055   Write everything we know to the output database file. Write:
1056 
1057   Database header
1058   String identifiers[]
1059   StringPacks[]
1060 
1061 Arguments:
1062 
1063   DBFileName    - name of the file to write to
1064   Verbose       - for debug purposes, print info messages along the way.
1065 
1066 Returns:
1067 
1068   STATUS
1069 
1070 --*/
1071 STATUS
StringDBWriteDatabase(INT8 * DBFileName,BOOLEAN Verbose)1072 StringDBWriteDatabase (
1073   INT8    *DBFileName,
1074   BOOLEAN Verbose
1075   )
1076 {
1077   STRING_DB_HEADER  DbHeader;
1078   UINT32            Counter;
1079   UINT32            StrLen;
1080   LANGUAGE_LIST     *Lang;
1081   STRING_IDENTIFIER *StringIdentifier;
1082   STRING_LIST       *StrList;
1083   FILE              *DBFptr;
1084 
1085   if (Verbose) {
1086     fprintf (stdout, "Writing database %s\n", DBFileName);
1087   }
1088 
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;
1092   }
1093   //
1094   // Fill in and write the database header
1095   //
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;
1100   //
1101   // Count the number of languages we have
1102   //
1103   for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
1104     DbHeader.NumLanguages++;
1105   }
1106   //
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
1109   // write out too.
1110   //
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;
1117   }
1118 
1119   //
1120   // Write the header
1121   //
1122   fwrite (&DbHeader, sizeof (STRING_DB_HEADER), 1, DBFptr);
1123   if (Verbose) {
1124     fprintf (stdout, "  Number of string identifiers  0x%04X\n", DbHeader.NumStringIdenfiers);
1125     fprintf (stdout, "  Number of languages           %d\n", DbHeader.NumLanguages);
1126   }
1127   //
1128   // Write the string identifiers
1129   //
1130   for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) {
1131     StringDBWriteStringIdentifier (
1132       DBFptr,
1133       (UINT16) StringIdentifier->Index,
1134       StringIdentifier->Flags,
1135       StringIdentifier->StringName
1136       );
1137   }
1138   //
1139   // Now write all the strings for each language
1140   //
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 (
1145         DBFptr,
1146         StrList->Flags,
1147         Lang->LanguageName,
1148         StrList->StringName,
1149         StrList->Scope,
1150         StrList->Str
1151         );
1152     }
1153   }
1154 
1155   fclose (DBFptr);
1156   return STATUS_SUCCESS;
1157 }
1158 
1159 STATUS
StringDBSetStringReferenced(INT8 * StringIdentifierName,BOOLEAN IgnoreNotFound)1160 StringDBSetStringReferenced (
1161   INT8      *StringIdentifierName,
1162   BOOLEAN   IgnoreNotFound
1163   )
1164 {
1165   STRING_IDENTIFIER *Id;
1166   WCHAR             *WName;
1167   STATUS            Status;
1168   //
1169   // See if it's already been defined.
1170   //
1171   Status  = STATUS_SUCCESS;
1172   WName   = (WCHAR *) malloc ((strlen (StringIdentifierName) + 1) * sizeof (WCHAR));
1173 #ifdef USE_VC8
1174   swprintf (WName, (strlen (StringIdentifierName) + 1) * sizeof (WCHAR), L"%S", StringIdentifierName);
1175 #else
1176   swprintf (WName, L"%S", StringIdentifierName);
1177 #endif
1178   Id = StringDBFindStringIdentifierByName (WName);
1179   if (Id != NULL) {
1180     Id->Flags |= STRING_FLAGS_REFERENCED;
1181   } else {
1182     if (IgnoreNotFound == 0) {
1183       ParserWarning (0, StringIdentifierName, "string identifier not found in database");
1184       Status = STATUS_WARNING;
1185     }
1186   }
1187 
1188   free (WName);
1189   return Status;
1190 }
1191 
1192 /*****************************************************************************/
1193 
1194 /*++
1195 
1196 Routine Description:
1197 
1198   Dump the contents of a database to an output unicode file.
1199 
1200 Arguments:
1201 
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
1205 
1206 Returns:
1207 
1208   STATUS
1209 
1210 Notes:
1211 
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().
1215 
1216 --*/
1217 STATUS
StringDBDumpDatabase(INT8 * DBFileName,INT8 * OutputFileName,BOOLEAN Verbose)1218 StringDBDumpDatabase (
1219   INT8                *DBFileName,
1220   INT8                *OutputFileName,
1221   BOOLEAN             Verbose
1222   )
1223 {
1224   LANGUAGE_LIST     *Lang;
1225   STRING_IDENTIFIER *StringIdentifier;
1226   STRING_LIST       *StrList;
1227   FILE              *OutFptr;
1228   WCHAR             WChar;
1229   WCHAR             *WOutputFileName;
1230   WCHAR             CrLf[2];
1231   WCHAR             Line[200];
1232   WCHAR             *Scope;
1233   //
1234   // This function assumes the database has already been read, and
1235   // we're just dumping our internal data structures to a unicode file.
1236   //
1237   if (Verbose) {
1238     fprintf (stdout, "Dumping database file %s\n", DBFileName);
1239   }
1240 
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;
1247   }
1248 
1249   WChar = UNICODE_FILE_START;
1250   fwrite (&WChar, sizeof (WCHAR), 1, OutFptr);
1251   CrLf[1] = UNICODE_LF;
1252   CrLf[0] = UNICODE_CR;
1253   //
1254   // The default control character is '/'. Make it '#' by writing
1255   // "/=#" to the output file.
1256   //
1257 #ifdef USE_VC8
1258   swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"/=#");
1259 #else
1260   swprintf (Line, L"/=#");
1261 #endif
1262   fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1263   fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1264   fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1265   //
1266   // Dump all the string identifiers and their values
1267   //
1268   StringDBAssignStringIndexes ();
1269   for (StringIdentifier = mDBData.StringIdentifier; StringIdentifier != NULL; StringIdentifier = StringIdentifier->Next) {
1270     //
1271     // Write the "#define " string
1272     //
1273     if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
1274 #ifdef USE_VC8
1275       swprintf (
1276         Line,
1277         wcslen(Line) * sizeof (WCHAR),
1278         L"%s %-60.60s 0x%04X",
1279         DEFINE_STR,
1280         StringIdentifier->StringName,
1281         StringIdentifier->Index
1282         );
1283 #else
1284       swprintf (
1285         Line,
1286         L"%s %-60.60s 0x%04X",
1287         DEFINE_STR,
1288         StringIdentifier->StringName,
1289         StringIdentifier->Index
1290         );
1291 #endif
1292     } else {
1293 #ifdef USE_VC8
1294       swprintf (
1295         Line,
1296         wcslen(Line) * sizeof (WCHAR),
1297         L"%s %-60.60s 0x%04X  // NOT REFERENCED",
1298         DEFINE_STR,
1299         StringIdentifier->StringName,
1300         StringIdentifier->Index
1301         );
1302 #else
1303       swprintf (
1304         Line,
1305         L"%s %-60.60s 0x%04X  // NOT REFERENCED",
1306         DEFINE_STR,
1307         StringIdentifier->StringName,
1308         StringIdentifier->Index
1309         );
1310 #endif
1311     }
1312 
1313     fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1314     fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1315   }
1316 
1317   fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1318   //
1319   // Now write all the strings for each language.
1320   //
1321   WChar = UNICODE_DOUBLE_QUOTE;
1322   Scope = NULL;
1323   for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
1324     fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1325 #ifdef USE_VC8
1326     swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName);
1327 #else
1328     swprintf (Line, L"#langdef %s \"%s\"", Lang->LanguageName, Lang->PrintableLanguageName);
1329 #endif
1330     fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1331     fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1332     fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1333     //
1334     // Now the strings (in double-quotes) for this language. Write
1335     // #string STR_NAME  #language eng "string"
1336     //
1337     for (StrList = Lang->String; StrList != NULL; StrList = StrList->Next) {
1338       //
1339       // Print the internal flags for debug
1340       //
1341 #ifdef USE_VC8
1342       swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"// flags=0x%02X", (UINT32) StrList->Flags);
1343 #else
1344       swprintf (Line, L"// flags=0x%02X", (UINT32) StrList->Flags);
1345 #endif
1346       fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1347       fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1348       //
1349       // Print the scope if changed
1350       //
1351       if ((Scope == NULL) || (wcscmp (Scope, StrList->Scope) != 0)) {
1352 #ifdef USE_VC8
1353         swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"#scope %s", StrList->Scope);
1354 #else
1355         swprintf (Line, L"#scope %s", StrList->Scope);
1356 #endif
1357         fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1358         fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1359         Scope = StrList->Scope;
1360       }
1361 
1362 #ifdef USE_VC8
1363       swprintf (
1364         Line,
1365         wcslen(Line) * sizeof (WCHAR),
1366         L"#string %-50.50s #language %s \"",
1367         StrList->StringName,
1368         Lang->LanguageName
1369         );
1370 #else
1371       swprintf (
1372         Line,
1373         L"#string %-50.50s #language %s \"",
1374         StrList->StringName,
1375         Lang->LanguageName
1376         );
1377 #endif
1378       fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1379       fwrite (StrList->Str, StrList->Size - sizeof (WCHAR), 1, OutFptr);
1380 #ifdef USE_VC8
1381       swprintf (Line, wcslen(Line) * sizeof (WCHAR), L"\"");
1382 #else
1383       swprintf (Line, L"\"");
1384 #endif
1385       fwrite (Line, wcslen (Line) * sizeof (WCHAR), 1, OutFptr);
1386       fwrite (&CrLf, sizeof (CrLf), 1, OutFptr);
1387     }
1388   }
1389 
1390   fclose (OutFptr);
1391   return STATUS_SUCCESS;
1392 }
1393 
1394 /*****************************************************************************/
1395 
1396 /*++
1397 
1398 Routine Description:
1399 
1400   Given a primary language, a string identifier number, and a list of
1401   languages, find a secondary string.
1402 
1403 Arguments:
1404 
1405   LanguageName      - primary language, like "spa"
1406   StringId          - string index value
1407   LanguageList      - linked list of "eng", "spa+cat",...
1408 
1409 Returns:
1410 
1411   Pointer to a secondary string if found. NULL otherwise.
1412 
1413 Notes:
1414 
1415   Given: LanguageName "spa"   and  LanguageList "spa+cat", match the
1416   "spa" and extract the "cat" and see if there is a string defined
1417   for "cat".StringId.
1418 
1419 --*/
1420 static
1421 STATUS
StringDBWriteStringIdentifier(FILE * DBFptr,UINT16 StringId,UINT16 Flags,WCHAR * IdentifierName)1422 StringDBWriteStringIdentifier (
1423   FILE                *DBFptr,
1424   UINT16              StringId,
1425   UINT16              Flags,
1426   WCHAR               *IdentifierName
1427   )
1428 {
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;
1435   }
1436 
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;
1440   }
1441 
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;
1445   }
1446 
1447   if (StringDBWriteGenericString (DBFptr, IdentifierName) != STATUS_SUCCESS) {
1448     return STATUS_ERROR;
1449   }
1450 
1451   return STATUS_SUCCESS;
1452 }
1453 
1454 static
1455 STATUS
StringDBReadStringIdentifier(FILE * DBFptr)1456 StringDBReadStringIdentifier (
1457   FILE                *DBFptr
1458   )
1459 {
1460   WCHAR   *IdentifierName;
1461   UINT16  Flags;
1462   UINT16  StringId;
1463   UINT16  Size;
1464 
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;
1468   }
1469 
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;
1473   }
1474 
1475   if (StringDBReadGenericString (DBFptr, &Size, &IdentifierName) != STATUS_SUCCESS) {
1476     return STATUS_ERROR;
1477   }
1478 
1479   StringDBAddStringIdentifier (IdentifierName, &StringId, Flags);
1480   //
1481   // printf ("STRID:  0x%04X %S\n", (UINT32)StringId, IdentifierName);
1482   //
1483   FREE (IdentifierName);
1484   return STATUS_SUCCESS;
1485 }
1486 
1487 static
1488 STATUS
StringDBWriteString(FILE * DBFptr,UINT16 Flags,WCHAR * Language,WCHAR * StringName,WCHAR * Scope,WCHAR * Str)1489 StringDBWriteString (
1490   FILE            *DBFptr,
1491   UINT16          Flags,
1492   WCHAR           *Language,
1493   WCHAR           *StringName,
1494   WCHAR           *Scope,
1495   WCHAR           *Str
1496   )
1497 {
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;
1504   }
1505 
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;
1509   }
1510 
1511   if (StringDBWriteGenericString (DBFptr, Language) != STATUS_SUCCESS) {
1512     return STATUS_ERROR;
1513   }
1514 
1515   if (StringDBWriteGenericString (DBFptr, StringName) != STATUS_SUCCESS) {
1516     return STATUS_ERROR;
1517   }
1518 
1519   if (StringDBWriteGenericString (DBFptr, Scope) != STATUS_SUCCESS) {
1520     return STATUS_ERROR;
1521   }
1522 
1523   if (StringDBWriteGenericString (DBFptr, Str) != STATUS_SUCCESS) {
1524     return STATUS_ERROR;
1525   }
1526   //
1527   // printf ("DBWriteString: %S.%S.%S\n", Language, StringName, Scope);
1528   //
1529   return STATUS_SUCCESS;
1530 }
1531 
1532 static
1533 STATUS
StringDBReadString(FILE * DBFptr)1534 StringDBReadString (
1535   FILE            *DBFptr
1536   )
1537 {
1538   UINT16  Flags;
1539   UINT16  Size;
1540   WCHAR   *Language;
1541   WCHAR   *StringName;
1542   WCHAR   *Scope;
1543   WCHAR   *Str;
1544 
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;
1548   }
1549 
1550   if (StringDBReadGenericString (DBFptr, &Size, &Language) != STATUS_SUCCESS) {
1551     return STATUS_ERROR;
1552   }
1553 
1554   if (StringDBReadGenericString (DBFptr, &Size, &StringName) != STATUS_SUCCESS) {
1555     return STATUS_ERROR;
1556   }
1557 
1558   if (StringDBReadGenericString (DBFptr, &Size, &Scope) != STATUS_SUCCESS) {
1559     return STATUS_ERROR;
1560   }
1561 
1562   if (StringDBReadGenericString (DBFptr, &Size, &Str) != STATUS_SUCCESS) {
1563     return STATUS_ERROR;
1564   }
1565   //
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
1568   // the database.
1569   //
1570   if (StringName[0] != L'$') {
1571     StringDBAddString (Language, StringName, Scope, Str, FALSE, Flags);
1572   }
1573   //
1574   // printf ("DBReadString: %S.%S.%S\n", Language, StringName, Scope);
1575   //
1576   FREE (Language);
1577   FREE (StringName);
1578   if (Str != NULL) {
1579     FREE (Str);
1580   }
1581 
1582   if (Scope != NULL) {
1583     FREE (Scope);
1584   }
1585 
1586   return STATUS_SUCCESS;
1587 }
1588 
1589 static
1590 STATUS
StringDBWriteLanguageDefinition(FILE * DBFptr,WCHAR * LanguageName,WCHAR * PrintableLanguageName,WCHAR * SecondaryLanguageList)1591 StringDBWriteLanguageDefinition (
1592   FILE            *DBFptr,
1593   WCHAR           *LanguageName,
1594   WCHAR           *PrintableLanguageName,
1595   WCHAR           *SecondaryLanguageList
1596   )
1597 {
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;
1604   }
1605 
1606   if (StringDBWriteGenericString (DBFptr, LanguageName) != STATUS_SUCCESS) {
1607     return STATUS_ERROR;
1608   }
1609 
1610   if (StringDBWriteGenericString (DBFptr, PrintableLanguageName) != STATUS_SUCCESS) {
1611     return STATUS_ERROR;
1612   }
1613 
1614   if (StringDBWriteGenericString (DBFptr, SecondaryLanguageList) != STATUS_SUCCESS) {
1615     return STATUS_ERROR;
1616   }
1617 
1618   return STATUS_SUCCESS;
1619 }
1620 
1621 static
1622 STATUS
StringDBReadLanguageDefinition(FILE * DBFptr)1623 StringDBReadLanguageDefinition (
1624   FILE            *DBFptr
1625   )
1626 {
1627   WCHAR   *LanguageName = NULL;
1628   WCHAR   *PrintableLanguageName = NULL;
1629   WCHAR   *SecondaryLanguageList = NULL;
1630   UINT16  Size;
1631   STATUS  Status;
1632 
1633   if (StringDBReadGenericString (DBFptr, &Size, &LanguageName) != STATUS_SUCCESS) {
1634     return STATUS_ERROR;
1635   }
1636 
1637   if (StringDBReadGenericString (DBFptr, &Size, &PrintableLanguageName) != STATUS_SUCCESS) {
1638     return STATUS_ERROR;
1639   }
1640 
1641   if (StringDBReadGenericString (DBFptr, &Size, &SecondaryLanguageList) != STATUS_SUCCESS) {
1642     return STATUS_ERROR;
1643   }
1644 
1645   //
1646   // printf("LANG: %S %S\n", LanguageName, PrintableLanguageName);
1647   //
1648   Status = StringDBAddLanguage (LanguageName, PrintableLanguageName, SecondaryLanguageList);
1649   FREE (LanguageName);
1650   FREE (PrintableLanguageName);
1651   FREE (SecondaryLanguageList);
1652   return Status;
1653 }
1654 //
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.
1658 //
1659 static
1660 STATUS
StringDBReadGenericString(FILE * DBFptr,UINT16 * Size,WCHAR ** Str)1661 StringDBReadGenericString (
1662   FILE      *DBFptr,
1663   UINT16    *Size,
1664   WCHAR     **Str
1665   )
1666 {
1667   UINT16  LSize;
1668   UINT16  Flags;
1669   WCHAR   *LStr;
1670 
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;
1674   }
1675 
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;
1679   }
1680 
1681   LStr = MALLOC (LSize);
1682   if (LStr == NULL) {
1683     Error (__FILE__, __LINE__, 0, "memory allocation failed reading the database", NULL);
1684     return STATUS_ERROR;
1685   }
1686 
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));
1690     free (LStr);
1691     return STATUS_ERROR;
1692   }
1693   //
1694   // printf ("DBR: %S\n", LStr);
1695   //
1696   // If the flags field indicated we were asked to write a NULL string, then
1697   // return them a NULL pointer.
1698   //
1699   if (Flags & STRING_FLAGS_UNDEFINED) {
1700     *Size = 0;
1701     *Str  = NULL;
1702   } else {
1703     *Size = LSize;
1704     *Str  = LStr;
1705   }
1706 
1707   return STATUS_SUCCESS;
1708 }
1709 
1710 static
1711 STATUS
StringDBWriteGenericString(FILE * DBFptr,WCHAR * Str)1712 StringDBWriteGenericString (
1713   FILE      *DBFptr,
1714   WCHAR     *Str
1715   )
1716 {
1717   UINT16  Size;
1718   UINT16  Flags;
1719   WCHAR   ZeroString[1];
1720   //
1721   // Strings in the database consist of a size UINT16 followed
1722   // by the string itself.
1723   //
1724   if (Str == NULL) {
1725     ZeroString[0] = 0;
1726     Str           = ZeroString;
1727     Size          = sizeof (ZeroString);
1728     Flags         = STRING_FLAGS_UNDEFINED;
1729   } else {
1730     Flags = 0;
1731     Size  = (UINT16) ((wcslen (Str) + 1) * sizeof (WCHAR));
1732   }
1733 
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;
1737   }
1738 
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;
1742   }
1743 
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;
1747   }
1748 
1749   return STATUS_SUCCESS;
1750 }
1751 
1752 static
1753 STRING_LIST *
StringDBFindString(WCHAR * LanguageName,WCHAR * StringName,WCHAR * Scope,WCHAR_STRING_LIST * LanguagesOfInterest,WCHAR_MATCHING_STRING_LIST * IndirectionList)1754 StringDBFindString (
1755   WCHAR                       *LanguageName,
1756   WCHAR                       *StringName,
1757   WCHAR                       *Scope,
1758   WCHAR_STRING_LIST           *LanguagesOfInterest,
1759   WCHAR_MATCHING_STRING_LIST  *IndirectionList
1760   )
1761 {
1762   LANGUAGE_LIST               *Lang;
1763   STRING_LIST                 *CurrString;
1764   WCHAR_MATCHING_STRING_LIST  *IndListPtr;
1765   WCHAR                       TempLangName[LANGUAGE_IDENTIFIER_NAME_LEN + 1];
1766   WCHAR                       *WCharPtr;
1767 
1768   //
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.
1773   //
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) {
1779           return CurrString;
1780         }
1781       }
1782     }
1783   }
1784   //
1785   // First look for exact match language.stringname
1786   //
1787   for (Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next) {
1788     if (wcscmp (LanguageName, Lang->LanguageName) == 0) {
1789       //
1790       // Found language match. Try to find string name match
1791       //
1792       for (CurrString = Lang->String; CurrString != NULL; CurrString = CurrString->Next) {
1793         if (wcscmp (StringName, CurrString->StringName) == 0) {
1794           //
1795           // Found a string name match. See if we're supposed to find
1796           // a scope match.
1797           //
1798           if (Scope != NULL) {
1799             if (wcscmp (CurrString->Scope, Scope) == 0) {
1800               return CurrString;
1801             }
1802           } else {
1803             return CurrString;
1804           }
1805         }
1806       }
1807     }
1808   }
1809   //
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"
1813   //
1814   while (LanguagesOfInterest != NULL) {
1815     //
1816     // If this is the language we're looking for, then process the
1817     // languages of interest list for it.
1818     //
1819     if (wcsncmp (LanguageName, LanguagesOfInterest->Str, LANGUAGE_IDENTIFIER_NAME_LEN) == 0) {
1820       WCharPtr = LanguagesOfInterest->Str + LANGUAGE_IDENTIFIER_NAME_LEN;
1821       while (*WCharPtr) {
1822         //
1823         // Double-check the length, though it should have been checked on the
1824         // command line.
1825         //
1826         if (wcslen (WCharPtr) < LANGUAGE_IDENTIFIER_NAME_LEN) {
1827           Error (NULL, 0, 0, "malformed alternate language list", "%S", LanguagesOfInterest->Str);
1828           return NULL;
1829         }
1830 
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) {
1835           return CurrString;
1836         }
1837 
1838         WCharPtr += LANGUAGE_IDENTIFIER_NAME_LEN;
1839       }
1840     }
1841 
1842     LanguagesOfInterest = LanguagesOfInterest->Next;
1843   }
1844 
1845   return NULL;
1846 }
1847 
1848 STATUS
StringDBSetScope(WCHAR * Scope)1849 StringDBSetScope (
1850   WCHAR   *Scope
1851   )
1852 {
1853   //
1854   // Free up existing scope memory.
1855   //
1856   if (mDBData.CurrentScope != NULL) {
1857     FREE (mDBData.CurrentScope);
1858   }
1859 
1860   mDBData.CurrentScope = DuplicateString (Scope);
1861   return STATUS_SUCCESS;
1862 }
1863 //
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
1869 // one referenced.
1870 //
1871 static
1872 void
StringDBAssignStringIndexes(VOID)1873 StringDBAssignStringIndexes (
1874   VOID
1875   )
1876 {
1877   STRING_IDENTIFIER *StrId;
1878   STRING_IDENTIFIER *FirstUsed;
1879   STRING_IDENTIFIER *LastUsed;
1880   STRING_IDENTIFIER *FirstUnused;
1881   STRING_IDENTIFIER *LastUnused;
1882   UINT32            Index;
1883   UINT32            MaxReferenced;
1884 
1885   //
1886   // Create two lists -- used and unused. Then put them together with
1887   // the unused ones on the end.
1888   //
1889   FirstUsed   = NULL;
1890   LastUsed    = NULL;
1891   FirstUnused = NULL;
1892   LastUnused  = NULL;
1893   StrId       = mDBData.StringIdentifier;
1894   while (StrId != NULL) {
1895     if ((StrId->Flags & STRING_FLAGS_REFERENCED) == 0) {
1896       //
1897       // Put it on the unused list
1898       //
1899       if (FirstUnused == NULL) {
1900         FirstUnused = StrId;
1901       } else {
1902         LastUnused->Next = StrId;
1903       }
1904 
1905       LastUnused        = StrId;
1906       StrId             = StrId->Next;
1907       LastUnused->Next  = NULL;
1908     } else {
1909       //
1910       // Put it on the used list
1911       //
1912       if (FirstUsed == NULL) {
1913         FirstUsed = StrId;
1914       } else {
1915         LastUsed->Next = StrId;
1916       }
1917 
1918       LastUsed        = StrId;
1919       StrId           = StrId->Next;
1920       LastUsed->Next  = NULL;
1921     }
1922   }
1923   //
1924   // Join the lists
1925   //
1926   if (FirstUsed != NULL) {
1927     mDBData.StringIdentifier  = FirstUsed;
1928     LastUsed->Next            = FirstUnused;
1929   } else {
1930     mDBData.StringIdentifier = FirstUnused;
1931   }
1932 
1933   MaxReferenced = 0;
1934   Index         = 0;
1935   for (StrId = mDBData.StringIdentifier; StrId != NULL; StrId = StrId->Next) {
1936     StrId->Index = Index;
1937     Index++;
1938     if (StrId->Flags & STRING_FLAGS_REFERENCED) {
1939       mDBData.NumStringIdentifiersReferenced = Index;
1940     }
1941   }
1942 
1943   mDBData.NumStringIdentifiers = Index;
1944 }
1945 
1946 static
1947 WCHAR *
DuplicateString(WCHAR * Str)1948 DuplicateString (
1949   WCHAR   *Str
1950   )
1951 {
1952   WCHAR *NewStr;
1953   if (Str == NULL) {
1954     return NULL;
1955   }
1956 
1957   NewStr = MALLOC ((wcslen (Str) + 1) * sizeof (WCHAR));
1958   if (NewStr == NULL) {
1959     Error (NULL, 0, 0, "memory allocation failure", NULL);
1960     return NULL;
1961   }
1962 
1963   wcscpy (NewStr, Str);
1964   return NewStr;
1965 }
1966 
1967 static
1968 WCHAR *
WstrCatenate(WCHAR * Dst,WCHAR * Src)1969 WstrCatenate (
1970   WCHAR *Dst,
1971   WCHAR *Src
1972   )
1973 {
1974   UINT32 Len  = 0;
1975   WCHAR  *Bak = Dst;
1976 
1977   if (Src == NULL) {
1978     return Dst;
1979   }
1980 
1981   if (Dst != NULL) {
1982     Len = wcslen (Dst);
1983   }
1984   Len += wcslen (Src);
1985   Dst = (WCHAR *) malloc ((Len + 1) * 2);
1986   if (Dst == NULL) {
1987     return NULL;
1988   }
1989 
1990   Dst[0] = L'\0';
1991   if (Bak != NULL) {
1992     wcscpy (Dst, Bak);
1993     FREE (Bak);
1994   }
1995   wcscat (Dst, Src);
1996   return Dst;
1997 }
1998 
1999 static
2000 WCHAR *
AsciiToWchar(INT8 * Str)2001 AsciiToWchar (
2002   INT8 *Str
2003   )
2004 {
2005   UINT32  Len;
2006   WCHAR   *NewStr;
2007   WCHAR   *Ptr;
2008 
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;
2013   }
2014 
2015   *Ptr = 0;
2016   return NewStr;
2017 }
2018 
2019 static
2020 CHAR8 *
WcharToAscii(WCHAR * Str)2021 WcharToAscii (
2022   WCHAR *Str
2023   )
2024 {
2025   UINT32  Len;
2026   CHAR8   *NewStr;
2027   CHAR8   *Ptr;
2028 
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;
2033   }
2034 
2035   *Ptr = '\0';
2036   return NewStr;
2037 }
2038 
2039 /*****************************************************************************/
2040 CHAR8 *
unicode2ascii(WCHAR * UnicodeStr)2041 unicode2ascii (
2042   WCHAR *UnicodeStr
2043   )
2044 {
2045   CHAR8     *RetStr   = (CHAR8 *)UnicodeStr;
2046   CHAR8     *AsciiStr = (CHAR8 *)UnicodeStr;
2047 
2048   while (*UnicodeStr != '\0') {
2049     *AsciiStr = (CHAR8) *(UnicodeStr++);
2050     AsciiStr++;
2051   }
2052   *AsciiStr = '\0';
2053 
2054   return RetStr;
2055 }
2056 
2057 STATUS
BuildStringPkgHdr(IN WCHAR * PrimaryLangName,IN WCHAR * SecondaryLangList,IN UINT32 Type,IN UINT32 PkgBlkSize,OUT EFI_HII_STRING_PACKAGE_HDR ** StrPkgHdr)2058 BuildStringPkgHdr (
2059   IN  WCHAR                       *PrimaryLangName,
2060   IN  WCHAR                       *SecondaryLangList,
2061   IN  UINT32                      Type,
2062   IN  UINT32                      PkgBlkSize,
2063   OUT EFI_HII_STRING_PACKAGE_HDR  **StrPkgHdr
2064   )
2065 {
2066   UINT32  LangNameLen;
2067 
2068   LangNameLen = wcslen (PrimaryLangName);
2069   if (SecondaryLangList != NULL) {
2070     LangNameLen += wcslen (SecondaryLangList) + 1;
2071   }
2072 
2073   *StrPkgHdr = (EFI_HII_STRING_PACKAGE_HDR *) malloc(sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);
2074   if (*StrPkgHdr == NULL) {
2075     return STATUS_ERROR;
2076   }
2077   memset (*StrPkgHdr, 0, sizeof (EFI_HII_STRING_PACKAGE_HDR) + LangNameLen);
2078 
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;
2085 
2086   strcpy ((*StrPkgHdr)->Language, unicode2ascii(PrimaryLangName));
2087   if (SecondaryLangList != NULL) {
2088     strcat ((*StrPkgHdr)->Language, ";");
2089     strcat ((*StrPkgHdr)->Language, unicode2ascii(SecondaryLangList));
2090   }
2091 
2092 #ifdef DEBUG_STRGATHER
2093   printf ("STR HDR\t %s\n", (*StrPkgHdr)->Language);
2094 #endif
2095   return STATUS_SUCCESS;
2096 }
2097 
2098 STATUS
BuildStringPkgUCS2Blk(IN EFI_STRING_ID StringId,IN WCHAR * LangName,IN WCHAR * StrName,OUT EFI_HII_SIBT_STRING_UCS2_BLOCK ** StrBlk,OUT UINT32 * BlkSize)2099 BuildStringPkgUCS2Blk (
2100   IN  EFI_STRING_ID                   StringId,
2101   IN  WCHAR                           *LangName,
2102   IN  WCHAR                           *StrName,
2103   OUT EFI_HII_SIBT_STRING_UCS2_BLOCK  **StrBlk,
2104   OUT UINT32                          *BlkSize
2105   )
2106 {
2107   UINT32      StrLen      = 0;
2108   STRING_LIST *CurrString = NULL;
2109 
2110   if ((LangName == NULL) || (StrName == NULL) || (StrBlk == NULL)) {
2111     return STATUS_ERROR;
2112   }
2113 
2114   *StrBlk  = NULL;
2115   *BlkSize = 0;
2116 
2117   CurrString = StringDBFindString (LangName, StrName, NULL, NULL, NULL);
2118   if (CurrString == NULL) {
2119   	return STATUS_WARNING;
2120   }
2121 
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) {
2126     *StrBlk  = NULL;
2127     *BlkSize = 0;
2128     return STATUS_ERROR;
2129   }
2130   (*StrBlk)->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
2131   wcscpy((*StrBlk)->StringText, CurrString->Str);
2132 
2133   return STATUS_SUCCESS;
2134 }
2135 
2136 STATUS
BuildStringPkgSKIP2Blk(IN EFI_STRING_ID SkipIdCount,OUT EFI_HII_SIBT_SKIP2_BLOCK ** StrBlk)2137 BuildStringPkgSKIP2Blk (
2138   IN  EFI_STRING_ID                   SkipIdCount,
2139   OUT EFI_HII_SIBT_SKIP2_BLOCK        **StrBlk
2140   )
2141 {
2142   if (StrBlk == NULL) {
2143     return STATUS_ERROR;
2144   }
2145 
2146   *StrBlk  = NULL;
2147 
2148   *StrBlk  = (EFI_HII_SIBT_SKIP2_BLOCK *) malloc (sizeof (EFI_HII_SIBT_SKIP2_BLOCK));
2149   if (*StrBlk == NULL) {
2150     *StrBlk  = NULL;
2151     return STATUS_ERROR;
2152   }
2153   (*StrBlk)->Header.BlockType = EFI_HII_SIBT_SKIP2;
2154   (*StrBlk)->SkipCount        = SkipIdCount;
2155 
2156   return STATUS_SUCCESS;
2157 }
2158 
2159 STATUS
BuildStringPkgEndBlk(OUT EFI_HII_SIBT_END_BLOCK ** End)2160 BuildStringPkgEndBlk (
2161   OUT EFI_HII_SIBT_END_BLOCK **End
2162   )
2163 {
2164   *End = (EFI_HII_SIBT_END_BLOCK *) malloc (sizeof (EFI_HII_SIBT_END_BLOCK));
2165   if (*End == NULL) {
2166     return STATUS_ERROR;
2167   }
2168 
2169   (*End)->Header.BlockType = EFI_HII_SIBT_END;
2170   return STATUS_SUCCESS;
2171 }
2172 
2173 /*++
2174 
2175 Routine Description:
2176 
2177   Create an HII export string pack for the strings in our database.
2178 
2179 Arguments:
2180 
2181   FileName        - name of the output file to write
2182 
2183 Returns:
2184 
2185   STATUS
2186 
2187 
2188 --*/
2189 STATUS
StrPkgBlkBufferListAddTail(IN EFI_STRING_ID StringId,IN WCHAR * StrName,IN SPkgBlkBuffer ** PkgBufferListHead,IN SPkgBlkBuffer ** PkgBufferListTail,IN VOID * Buffer,IN UINT32 Size)2190 StrPkgBlkBufferListAddTail (
2191   IN EFI_STRING_ID      StringId,
2192   IN WCHAR              *StrName,
2193   IN SPkgBlkBuffer      **PkgBufferListHead,
2194   IN SPkgBlkBuffer      **PkgBufferListTail,
2195   IN VOID               *Buffer,
2196   IN UINT32             Size
2197   )
2198 {
2199   SPkgBlkBuffer         *pNew = NULL;
2200 #ifdef DEBUG_STRGATHER
2201   EFI_HII_STRING_BLOCK  *SBlk = (EFI_HII_STRING_BLOCK *)Buffer;
2202 #endif
2203 
2204   if ((PkgBufferListHead == NULL) || (PkgBufferListTail == NULL)) {
2205     return STATUS_ERROR;
2206   }
2207 
2208   pNew = (SPkgBlkBuffer *) malloc (sizeof (SPkgBlkBuffer));
2209   if (pNew == NULL) {
2210     return STATUS_ERROR;
2211   }
2212 
2213   pNew->mBlkBuffer = Buffer;
2214   pNew->mBlkSize   = Size;
2215   if ((*PkgBufferListTail) == NULL) {
2216     (*PkgBufferListHead) = (*PkgBufferListTail) = pNew;
2217   } else {
2218     (*PkgBufferListTail)->mNext = pNew;
2219     (*PkgBufferListTail) = pNew;
2220     pNew->mNext = NULL;
2221   }
2222 
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);
2227     break;
2228   case EFI_HII_SIBT_SKIP2 :
2229     printf ("\tID: [NULL] TYPE: [SKIP2] SKIPCOUNT: [%x]\n", ((EFI_HII_SIBT_SKIP2_BLOCK *)SBlk)->SkipCount);
2230     break;
2231   case EFI_HII_SIBT_END :
2232     printf ("\tID: [%x] TYPE: [END]\n", StringId);
2233     break;
2234   default :
2235     printf ("!!!!UNKNOWN STRING TYPE!!!\n");
2236   }
2237 #endif
2238 
2239   return STATUS_SUCCESS;
2240 }
2241 
2242 VOID
StrPkgHdrFree(IN EFI_HII_STRING_PACKAGE_HDR * StrPkgHdr)2243 StrPkgHdrFree (
2244   IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
2245   )
2246 {
2247   if (StrPkgHdr != NULL) {
2248     free (StrPkgHdr);
2249   }
2250 }
2251 
2252 VOID
StrPkgBlkBufferListFree(IN SPkgBlkBuffer * PkgBlkList)2253 StrPkgBlkBufferListFree (
2254   IN SPkgBlkBuffer *PkgBlkList
2255   )
2256 {
2257   SPkgBlkBuffer  *Buffer;
2258 
2259   while (PkgBlkList != NULL) {
2260     Buffer      = PkgBlkList;
2261     PkgBlkList = PkgBlkList->mNext;
2262 
2263     if (Buffer->mBlkBuffer != NULL) {
2264       free (Buffer->mBlkBuffer);
2265     }
2266     free (Buffer);
2267   }
2268 }
2269 
2270 VOID
WriteBlockLine(IN FILE * pFile,IN UINT32 LineBytes,IN INT8 * LineHeader,IN INT8 * BlkBuf,IN UINT32 BlkSize)2271 WriteBlockLine (
2272   IN FILE   *pFile,
2273   IN UINT32 LineBytes,
2274   IN INT8   *LineHeader,
2275   IN INT8   *BlkBuf,
2276   IN UINT32 BlkSize
2277   )
2278 {
2279   UINT32    Index;
2280 
2281   if ((pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
2282     return;
2283   }
2284 
2285   for (Index = 0; Index < BlkSize; Index++) {
2286     if ((Index % LineBytes) == 0) {
2287       fprintf (pFile, "\n%s", LineHeader);
2288     }
2289     fprintf (pFile, "0x%02X,  ", (UINT8)BlkBuf[Index]);
2290   }
2291 }
2292 
2293 VOID
WriteBlockEnd(IN FILE * pFile,IN UINT32 LineBytes,IN INT8 * LineHeader,IN INT8 * BlkBuf,IN UINT32 BlkSize)2294 WriteBlockEnd (
2295   IN FILE   *pFile,
2296   IN UINT32 LineBytes,
2297   IN INT8   *LineHeader,
2298   IN INT8   *BlkBuf,
2299   IN UINT32 BlkSize
2300   )
2301 {
2302   UINT32    Index;
2303 
2304   if ((BlkSize == 0) || (pFile == NULL) || (LineHeader == NULL) || (BlkBuf == NULL)) {
2305     return;
2306   }
2307 
2308   for (Index = 0; Index < BlkSize - 1; Index++) {
2309     if ((Index % LineBytes) == 0) {
2310       fprintf (pFile, "\n%s", LineHeader);
2311     }
2312     fprintf (pFile, "0x%02X,  ", (UINT8)BlkBuf[Index]);
2313   }
2314 
2315   if ((Index % LineBytes) == 0) {
2316     fprintf (pFile, "\n%s", LineHeader);
2317   }
2318   fprintf (pFile, "0x%02X\n", (UINT8)BlkBuf[Index]);
2319 }
2320 
2321 #define BYTES_PRE_LINE 0x10
2322 
2323 VOID
StrPkgWriteHdrCFile(IN FILE * File,IN EFI_HII_STRING_PACKAGE_HDR * StrPkgHdr)2324 StrPkgWriteHdrCFile (
2325   IN FILE                       *File,
2326   IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
2327   )
2328 {
2329   if (StrPkgHdr != NULL) {
2330     fprintf (File, "\n  // PACKAGE HEADER\n");
2331     WriteBlockLine(File, BYTES_PRE_LINE, "  ", (INT8 *)StrPkgHdr, StrPkgHdr->HdrSize);
2332   }
2333 }
2334 
2335 VOID
StrPkgWirteArrayLength(IN FILE * File,IN UINT32 PkgNumber,IN EFI_HII_STRING_PACKAGE_HDR ** PkgHdr)2336 StrPkgWirteArrayLength (
2337   IN FILE                       *File,
2338   IN UINT32                     PkgNumber,
2339   IN EFI_HII_STRING_PACKAGE_HDR **PkgHdr
2340   )
2341 {
2342   UINT32                        Index;
2343   UINT32                        ArrayLen;
2344 
2345   ArrayLen = sizeof (UINT32);
2346   for (Index = 0; Index < PkgNumber; Index++) {
2347     if (PkgHdr[Index] != NULL) {
2348       ArrayLen += PkgHdr[Index]->Header.Length;
2349     }
2350   }
2351 
2352   fprintf (File, "\n  // STRING ARRAY LENGTH\n");
2353   WriteBlockLine(File, BYTES_PRE_LINE, "  ", (UINT8 *)&ArrayLen, sizeof (UINT32));
2354 }
2355 
2356 VOID
StrPkgWriteBlkListCFile(IN FILE * File,IN SPkgBlkBuffer * BlkList,IN BOOLEAN WriteEnd)2357 StrPkgWriteBlkListCFile (
2358   IN FILE                       *File,
2359   IN SPkgBlkBuffer              *BlkList,
2360   IN BOOLEAN                    WriteEnd
2361   )
2362 {
2363   SPkgBlkBuffer  *Buffer;
2364 
2365   fprintf (File, "\n\n  // PACKAGE DATA\n");
2366 
2367   while (BlkList != NULL) {
2368     Buffer   = BlkList;
2369     BlkList = BlkList->mNext;
2370 
2371     if ((Buffer->mNext == NULL) && (WriteEnd == TRUE)) {
2372       if (Buffer->mBlkBuffer != NULL) {
2373         WriteBlockEnd (File, BYTES_PRE_LINE, "  ", Buffer->mBlkBuffer, Buffer->mBlkSize);
2374       }
2375     } else {
2376       if (Buffer->mBlkBuffer != NULL) {
2377         WriteBlockLine(File, BYTES_PRE_LINE, "  ", Buffer->mBlkBuffer, Buffer->mBlkSize);
2378       }
2379     }
2380   }
2381 }
2382 
2383 VOID
StrPkgWriteHdrBinary(IN FILE * File,IN EFI_HII_STRING_PACKAGE_HDR * StrPkgHdr)2384 StrPkgWriteHdrBinary (
2385   IN FILE                       *File,
2386   IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
2387   )
2388 {
2389   fwrite (StrPkgHdr, StrPkgHdr->HdrSize, 1, File);
2390 }
2391 
2392 VOID
StrPkgWriteBlkListBinary(IN FILE * File,IN SPkgBlkBuffer * BlkList)2393 StrPkgWriteBlkListBinary (
2394   IN FILE                       *File,
2395   IN SPkgBlkBuffer              *BlkList
2396   )
2397 {
2398   SPkgBlkBuffer  *Buffer;
2399 
2400   while (BlkList != NULL) {
2401     Buffer   = BlkList;
2402     BlkList = BlkList->mNext;
2403 
2404     if (Buffer->mBlkBuffer != NULL) {
2405       fwrite (Buffer->mBlkBuffer, Buffer->mBlkSize, 1, File);
2406     }
2407   }
2408 }
2409 
2410 STATUS
StringDBGenStrPkgHdrAndBlkList(IN LANGUAGE_LIST * Lang,OUT EFI_HII_STRING_PACKAGE_HDR ** StrPkgHdr,OUT SPkgBlkBuffer ** BlkList)2411 StringDBGenStrPkgHdrAndBlkList (
2412   IN  LANGUAGE_LIST              *Lang,
2413   OUT EFI_HII_STRING_PACKAGE_HDR **StrPkgHdr,
2414   OUT SPkgBlkBuffer              **BlkList
2415   )
2416 {
2417   STATUS                          Status;
2418   UINT32                          StringIndex;
2419   EFI_STRING_ID                   StringIdCurrent;
2420   EFI_STRING_ID                   SkipIdCount;
2421   UINT32                          BlkSize = 0;
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;
2429 
2430   if ((Lang == NULL) || (StrPkgHdr == NULL) || (BlkList == NULL)) {
2431     return STATUS_ERROR;
2432   }
2433 
2434   //
2435   // Assign index values to the string identifiers
2436   //
2437   StringDBAssignStringIndexes ();
2438   StringIdCurrent = EFI_STRING_ID_BEGIN;
2439   SkipIdCount     = 0;
2440 
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);
2444       goto ExportPackOut;
2445     }
2446 
2447     if (StringIdentifier->Flags & STRING_FLAGS_REFERENCED) {
2448       Status = BuildStringPkgUCS2Blk (StringIdCurrent, Lang->LanguageName, StringIdentifier->StringName, &StrUCS2Blk, &BlkSize);
2449       switch (Status) {
2450       case STATUS_ERROR:
2451         goto ExportPackOut;
2452         break;
2453       case STATUS_WARNING :
2454         SkipIdCount++;
2455         break;
2456       case STATUS_SUCCESS :
2457         if (SkipIdCount == 0) {
2458           if (StrPkgBlkBufferListAddTail (
2459                 StringIdCurrent,
2460                 StringIdentifier->StringName,
2461                 &PkgBufferListHead,
2462                 &PkgBufferListTail,
2463                 StrUCS2Blk,
2464                 BlkSize
2465                 ) != STATUS_SUCCESS) {
2466             goto ExportPackOut;
2467           }
2468           PkgBlkSize += BlkSize;
2469         } else {
2470           if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {
2471             goto ExportPackOut;
2472           } else {
2473             if (StrPkgBlkBufferListAddTail (
2474                 StringIdCurrent,
2475                 NULL,
2476                 &PkgBufferListHead,
2477                 &PkgBufferListTail,
2478                 StrSKIP2Blk,
2479                 sizeof (EFI_HII_SIBT_SKIP2_BLOCK)
2480                 ) != STATUS_SUCCESS) {
2481               goto ExportPackOut;
2482             }
2483             PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
2484             SkipIdCount = 0;
2485           }
2486 
2487           if (StrPkgBlkBufferListAddTail (
2488                 StringIdCurrent,
2489                 StringIdentifier->StringName,
2490                 &PkgBufferListHead,
2491                 &PkgBufferListTail,
2492                 StrUCS2Blk,
2493                 BlkSize
2494                 ) != STATUS_SUCCESS) {
2495             goto ExportPackOut;
2496           }
2497           PkgBlkSize += BlkSize;
2498         }
2499       }
2500     }
2501 
2502     StringIdCurrent++;
2503   }
2504 
2505   if (SkipIdCount != 0) {
2506     if (BuildStringPkgSKIP2Blk (SkipIdCount, &StrSKIP2Blk) != STATUS_SUCCESS) {
2507       goto ExportPackOut;
2508     } else {
2509       if (StrPkgBlkBufferListAddTail (
2510             StringIdCurrent,
2511             NULL,
2512             &PkgBufferListHead,
2513             &PkgBufferListTail,
2514             StrSKIP2Blk,
2515             sizeof (EFI_HII_SIBT_SKIP2_BLOCK)
2516             ) != STATUS_SUCCESS) {
2517         goto ExportPackOut;
2518       }
2519       PkgBlkSize += sizeof (EFI_HII_SIBT_SKIP2_BLOCK);
2520       SkipIdCount = 0;
2521     }
2522   }
2523 
2524   if (BuildStringPkgEndBlk (&EndBlk) != STATUS_SUCCESS) {
2525     goto ExportPackOut;
2526   } else if (StrPkgBlkBufferListAddTail (
2527                StringIdCurrent,
2528                NULL,
2529                &PkgBufferListHead,
2530                &PkgBufferListTail,
2531                EndBlk,
2532                sizeof (EFI_HII_SIBT_END_BLOCK)
2533                ) != STATUS_SUCCESS) {
2534     goto ExportPackOut;
2535   }
2536   StringIdCurrent++;
2537   PkgBlkSize += sizeof (EFI_HII_SIBT_END_BLOCK);
2538 
2539   if (BuildStringPkgHdr(
2540         Lang->LanguageName,
2541         Lang->SecondaryLanguageList,
2542         EFI_HII_PACKAGE_STRINGS,
2543         PkgBlkSize,
2544         StrPkgHdr
2545         ) != STATUS_SUCCESS) {
2546     goto ExportPackOut;
2547   }
2548 
2549   *BlkList   = PkgBufferListHead;
2550 
2551   return STATUS_SUCCESS;
2552 
2553 ExportPackOut:
2554   StrPkgBlkBufferListFree(PkgBufferListHead);
2555   *BlkList   = NULL;
2556   *StrPkgHdr = NULL;
2557   return STATUS_ERROR;
2558 }
2559 
2560 STATUS
StringDBCreateHiiExportPack(INT8 * FileName,WCHAR_STRING_LIST * LanguagesOfInterest)2561 StringDBCreateHiiExportPack (
2562   INT8                        *FileName,
2563   WCHAR_STRING_LIST           *LanguagesOfInterest
2564   )
2565 {
2566   FILE                            *File;
2567   LANGUAGE_LIST                   *Lang;
2568   EFI_HII_STRING_PACKAGE_HDR      *StrPkgHdr;
2569   SPkgBlkBuffer                   *BlkList;
2570   WCHAR_STRING_LIST               *LOIPtr;
2571 
2572   if (FileName == NULL) {
2573     return STATUS_ERROR;
2574   }
2575 
2576   if ((File = fopen (FileName, "wb")) == NULL) {
2577     Error (NULL, 0, 0, FileName, "failed to open output HII export file");
2578     return STATUS_ERROR;
2579   }
2580 
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) {
2584         break;
2585       }
2586     }
2587 
2588     if ((LanguagesOfInterest == NULL) ||
2589         (LanguagesOfInterest != NULL && LOIPtr != NULL)) {
2590       if (StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr, &BlkList) != STATUS_SUCCESS) {
2591         fclose (File);
2592         return STATUS_SUCCESS;
2593       }
2594 
2595       StrPkgWriteHdrBinary (File, StrPkgHdr);
2596       StrPkgWriteBlkListBinary (File, BlkList);
2597 
2598       StrPkgHdrFree (StrPkgHdr);
2599       StrPkgBlkBufferListFree (BlkList);
2600     }
2601   }
2602   fclose (File);
2603   return STATUS_SUCCESS;
2604 }
2605 
2606 static const char *gSourceFileHeader[] = {
2607   "//",
2608   "//  DO NOT EDIT -- auto-generated file",
2609   "//",
2610   "//  This file is generated by the StrGather utility",
2611   "//",
2612   NULL
2613 };
2614 
2615 STATUS
StringDBDumpCStrings(INT8 * BaseName,INT8 * FileName,WCHAR_STRING_LIST * LanguagesOfInterest)2616 StringDBDumpCStrings (
2617   INT8                            *BaseName,
2618   INT8                            *FileName,
2619   WCHAR_STRING_LIST               *LanguagesOfInterest
2620   )
2621 {
2622   EFI_STATUS                      Status;
2623   FILE                            *File;
2624   LANGUAGE_LIST                   *Lang;
2625   EFI_HII_STRING_PACKAGE_HDR      **StrPkgHdr;
2626   SPkgBlkBuffer                   **BlkList;
2627   UINT32                          Index;
2628   UINT32                          LangNumber;
2629   WCHAR_STRING_LIST               *LOIPtr;
2630 
2631   if ((BaseName == NULL) || (FileName == NULL)) {
2632     return STATUS_ERROR;
2633   }
2634 
2635   if (mDBData.LanguageList == NULL) {
2636     return STATUS_SUCCESS;
2637   }
2638 
2639   for (LangNumber = 0, Lang = mDBData.LanguageList; Lang != NULL; Lang = Lang->Next, LangNumber++)
2640     ;
2641 
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;
2647   }
2648 
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) {
2652         break;
2653       }
2654     }
2655     if ((LanguagesOfInterest == NULL) ||
2656         (LanguagesOfInterest != NULL && LOIPtr != NULL)) {
2657       Status = StringDBGenStrPkgHdrAndBlkList(Lang, &StrPkgHdr[Index], &BlkList[Index]);
2658       Index++;
2659       if (EFI_ERROR(Status)) {
2660         free (StrPkgHdr);
2661         free (BlkList);
2662         return STATUS_ERROR;
2663       }
2664     }
2665   }
2666 
2667   //
2668   // Update LangNumber after filter
2669   //
2670   LangNumber = Index;
2671 
2672   if (LangNumber == 0) {
2673     free (StrPkgHdr);
2674     free (BlkList);
2675     return STATUS_SUCCESS;
2676   }
2677 
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;
2681   }
2682 
2683   for (Index = 0; gSourceFileHeader[Index] != NULL; Index++) {
2684     fprintf (File, "%s\n", gSourceFileHeader[Index]);
2685   }
2686 
2687   fprintf (File, "\nunsigned char %s[] = {\n", BaseName);
2688 
2689   //
2690   // Save the length of the string package array.
2691   //
2692   StrPkgWirteArrayLength (File, LangNumber, StrPkgHdr);
2693 
2694   for (Index = 0; Index < LangNumber; Index++) {
2695     StrPkgWriteHdrCFile (File, StrPkgHdr[Index]);
2696     StrPkgWriteBlkListCFile (File, BlkList[Index], (Index == LangNumber - 1) ? TRUE : FALSE);
2697 
2698     StrPkgHdrFree (StrPkgHdr[Index]);
2699     StrPkgBlkBufferListFree (BlkList[Index]);
2700   }
2701 
2702   fprintf (File, "\n};\n");
2703 
2704   fclose (File);
2705   free (StrPkgHdr);
2706   free (BlkList);
2707   return STATUS_SUCCESS;
2708 }
2709