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