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