]> git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Tools/Source/UefiStrGather/StringDB.c
EdkCompatibilityPkg: Fix some typos of "according"
[mirror_edk2.git] / EdkCompatibilityPkg / Sample / Tools / Source / UefiStrGather / StringDB.c
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
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
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
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
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
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 *
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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 *
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 *
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 *
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 *
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 *
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
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
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
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
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
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
2243 StrPkgHdrFree (
2244 IN EFI_HII_STRING_PACKAGE_HDR *StrPkgHdr
2245 )
2246 {
2247 if (StrPkgHdr != NULL) {
2248 free (StrPkgHdr);
2249 }
2250 }
2251
2252 VOID
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
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
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
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
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
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
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
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
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
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
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 }