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