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