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