Reactos
at master 825 lines 22 kB view raw
1/* 2 * PROJECT: xml2sdb 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: Conversion functions from xml -> db 5 * COPYRIGHT: Copyright 2016-2025 Mark Jansen <mark.jansen@reactos.org> 6 */ 7 8#include "xml2sdb.h" 9#include "sdbpapi.h" 10#include "tinyxml2.h" 11#include <time.h> 12#include <algorithm> 13#include <sstream> 14 15using tinyxml2::XMLText; 16 17static const GUID GUID_NULL = { 0 }; 18static const char szCompilerVersion[] = "1.8.0.0"; 19 20#if !defined(C_ASSERT) 21#define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1] 22#endif 23 24 25C_ASSERT(sizeof(GUID) == 16); 26C_ASSERT(sizeof(ULONG) == 4); 27C_ASSERT(sizeof(LARGE_INTEGER) == 8); 28C_ASSERT(sizeof(WCHAR) == 2); 29C_ASSERT(sizeof(wchar_t) == 2); 30C_ASSERT(sizeof(TAG) == 2); 31C_ASSERT(sizeof(TAGID) == 4); 32 33 34extern "C" 35VOID NTAPI RtlSecondsSince1970ToTime(IN ULONG SecondsSince1970, 36 OUT PLARGE_INTEGER Time); 37 38 39/*********************************************************************** 40 * Helper functions 41 */ 42str_to_flag platform_to_flag[] = { 43 {"X86", PLATFORM_X86}, 44 {"I386", PLATFORM_X86}, 45 {"AMD64", PLATFORM_AMD64}, 46 {"ANY", PLATFORM_ANY}, 47 {nullptr, 0}, 48}; 49 50DWORD 51str_to_enum(const std::string& str, const str_to_flag* table) 52{ 53 DWORD value = 0; 54 std::istringstream iss(str); 55 std::string item; 56 while (std::getline(iss, item, ',')) 57 { 58 std::string trimmedItem = item; 59 trimmedItem.erase(remove_if(trimmedItem.begin(), trimmedItem.end(), isspace), trimmedItem.end()); 60 std::transform(trimmedItem.begin(), trimmedItem.end(), trimmedItem.begin(), ::toupper); 61 for (const str_to_flag* p = table; p->name; ++p) 62 { 63 if (trimmedItem == p->name) 64 { 65 value |= p->flag; 66 break; 67 } 68 } 69 } 70 return value; 71} 72 73 74// Convert utf8 to utf16: 75// http://stackoverflow.com/a/7154226/4928207 76 77bool IsEmptyGuid(const GUID& g) 78{ 79 return !memcmp(&g, &GUID_NULL, sizeof(GUID)); 80} 81 82void RandomGuid(GUID& g) 83{ 84 BYTE* p = (BYTE*)&g; 85 for (size_t n = 0; n < sizeof(GUID); ++n) 86 p[n] = (BYTE)(rand() % 0xff); 87} 88 89// Given a node, return the node value (safe) 90std::string ToString(XMLHandle node) 91{ 92 XMLText* txtNode = node.FirstChild().ToText(); 93 const char* txt = txtNode ? txtNode->Value() : NULL; 94 if (txt) 95 return std::string(txt); 96 return std::string(); 97} 98 99// Given a node, return the node name (safe) 100std::string ToNodeName(XMLHandle node) 101{ 102 tinyxml2::XMLNode* raw = node.ToNode(); 103 const char* txt = raw ? raw->Value() : NULL; 104 if (txt) 105 return std::string(txt); 106 return std::string(); 107} 108 109// Read either an attribute, or a child node 110std::string ReadStringNode(XMLHandle dbNode, const char* nodeName) 111{ 112 tinyxml2::XMLElement* elem = dbNode.ToElement(); 113 if (elem) 114 { 115 const char* rawVal = elem->Attribute(nodeName); 116 if (rawVal) 117 return std::string(rawVal); 118 } 119 return ToString(dbNode.FirstChildElement(nodeName)); 120} 121 122QWORD ReadQWordNode(XMLHandle dbNode, const char* nodeName) 123{ 124 std::string value = ReadStringNode(dbNode, nodeName); 125 int base = 10; 126 if (value.size() > 2 && value[0] == '0' && value[1] == 'x') 127 { 128 base = 16; 129 value = value.substr(2); 130 } 131 return static_cast<QWORD>(strtoull(value.c_str(), NULL, base)); 132} 133 134DWORD ReadDWordNode(XMLHandle dbNode, const char* nodeName) 135{ 136 return static_cast<DWORD>(ReadQWordNode(dbNode, nodeName)); 137} 138 139PlatformType ReadPlatformNode(XMLHandle dbNode, const char *nodeName) 140{ 141 std::string value = ReadStringNode(dbNode, nodeName); 142 if (value.empty()) 143 return PLATFORM_ANY; 144 DWORD platform = str_to_enum(value, platform_to_flag); 145 return static_cast<PlatformType>(platform); 146} 147 148unsigned char char2byte(char hexChar, bool* success = NULL) 149{ 150 if (hexChar >= '0' && hexChar <= '9') 151 return hexChar - '0'; 152 if (hexChar >= 'A' && hexChar <= 'F') 153 return hexChar - 'A' + 10; 154 if (hexChar >= 'a' && hexChar <= 'f') 155 return hexChar - 'a' + 10; 156 157 if (success) 158 *success = false; 159 return 0; 160} 161 162// adapted from wine's ntdll\rtlstr.c rev 1.45 163static bool StringToGuid(const std::string& str, GUID& guid) 164{ 165 const char *lpszGUID = str.c_str(); 166 BYTE* lpOut = (BYTE*)&guid; 167 int i = 0; 168 bool expectBrace = true; 169 while (i <= 37) 170 { 171 switch (i) 172 { 173 case 0: 174 if (*lpszGUID != '{') 175 { 176 i++; 177 expectBrace = false; 178 continue; 179 } 180 break; 181 182 case 9: 183 case 14: 184 case 19: 185 case 24: 186 if (*lpszGUID != '-') 187 return false; 188 break; 189 190 case 37: 191 return expectBrace == (*lpszGUID == '}'); 192 193 default: 194 { 195 CHAR ch = *lpszGUID, ch2 = lpszGUID[1]; 196 unsigned char byte; 197 bool converted = true; 198 199 byte = char2byte(ch, &converted) << 4 | char2byte(ch2, &converted); 200 if (!converted) 201 return false; 202 203 switch (i) 204 { 205#ifndef WORDS_BIGENDIAN 206 /* For Big Endian machines, we store the data such that the 207 * dword/word members can be read as DWORDS and WORDS correctly. */ 208 /* Dword */ 209 case 1: 210 lpOut[3] = byte; 211 break; 212 case 3: 213 lpOut[2] = byte; 214 break; 215 case 5: 216 lpOut[1] = byte; 217 break; 218 case 7: 219 lpOut[0] = byte; 220 lpOut += 4; 221 break; 222 /* Word */ 223 case 10: 224 case 15: 225 lpOut[1] = byte; 226 break; 227 case 12: 228 case 17: 229 lpOut[0] = byte; 230 lpOut += 2; 231 break; 232#endif 233 /* Byte */ 234 default: 235 lpOut[0] = byte; 236 lpOut++; 237 break; 238 } 239 240 lpszGUID++; /* Skip 2nd character of byte */ 241 i++; 242 } 243 } 244 245 lpszGUID++; 246 i++; 247 } 248 return false; 249} 250 251bool ReadGuidNode(XMLHandle dbNode, const char* nodeName, GUID& guid) 252{ 253 std::string value = ReadStringNode(dbNode, nodeName); 254 if (!StringToGuid(value, guid)) 255 { 256 memset(&guid, 0, sizeof(GUID)); 257 return false; 258 } 259 return true; 260} 261 262bool ReadBinaryNode(XMLHandle dbNode, const char* nodeName, std::vector<BYTE>& data) 263{ 264 std::string value = ReadStringNode(dbNode, nodeName); 265 value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end()); 266 267 size_t length = value.size() / 2; 268 if (length * 2 != value.size()) 269 return false; 270 271 data.resize(length); 272 for (size_t n = 0; n < length; ++n) 273 { 274 data[n] = (BYTE)(char2byte(value[n * 2]) << 4 | char2byte(value[(n * 2) + 1])); 275 } 276 return true; 277} 278 279 280/*********************************************************************** 281 * InExclude 282 */ 283 284bool InExclude::fromXml(XMLHandle dbNode) 285{ 286 Module = ReadStringNode(dbNode, "MODULE"); 287 // Special module names: '$' and '*' 288 if (!Module.empty()) 289 { 290 Include = ToNodeName(dbNode) == "INCLUDE"; 291 return true; 292 } 293 return false; 294} 295 296bool InExclude::toSdb(Database& db) 297{ 298 TAGID tagid = db.BeginWriteListTag(TAG_INEXCLUD); 299 db.WriteString(TAG_MODULE, Module, true); 300 if (Include) 301 db.WriteNull(TAG_INCLUDE); 302 return !!db.EndWriteListTag(tagid); 303} 304 305 306template<typename T> 307void ReadGeneric(XMLHandle dbNode, std::list<T>& result, const char* nodeName) 308{ 309 XMLHandle node = dbNode.FirstChildElement(nodeName); 310 while (node.ToNode()) 311 { 312 T object; 313 if (object.fromXml(node)) 314 result.push_back(object); 315 316 node = node.NextSiblingElement(nodeName); 317 } 318} 319 320template<typename T> 321void ReadGeneric(XMLHandle dbNode, std::list<T>& result, const char* nodeName, PlatformType platform) 322{ 323 XMLHandle node = dbNode.FirstChildElement(nodeName); 324 while (node.ToNode()) 325 { 326 T object; 327 if (object.fromXml(node) && ((object.Platform & platform) != PLATFORM_NONE)) 328 result.push_back(object); 329 330 node = node.NextSiblingElement(nodeName); 331 } 332} 333 334template<typename T> 335bool WriteGeneric(std::list<T>& data, Database& db) 336{ 337 for (typename std::list<T>::iterator it = data.begin(); it != data.end(); ++it) 338 { 339 if (!it->toSdb(db)) 340 return false; 341 } 342 return true; 343} 344 345 346/*********************************************************************** 347 * ShimRef 348 */ 349 350bool ShimRef::fromXml(XMLHandle dbNode) 351{ 352 Name = ReadStringNode(dbNode, "NAME"); 353 CommandLine = ReadStringNode(dbNode, "COMMAND_LINE"); 354 ReadGeneric(dbNode, InExcludes, "INCLUDE"); 355 ReadGeneric(dbNode, InExcludes, "EXCLUDE"); 356 return !Name.empty(); 357} 358 359bool ShimRef::toSdb(Database& db) 360{ 361 TAGID tagid = db.BeginWriteListTag(TAG_SHIM_REF); 362 db.WriteString(TAG_NAME, Name, true); 363 db.WriteString(TAG_COMMAND_LINE, CommandLine); 364 365 if (!ShimTagid) 366 ShimTagid = db.FindShimTagid(Name); 367 db.WriteDWord(TAG_SHIM_TAGID, ShimTagid); 368 return !!db.EndWriteListTag(tagid); 369} 370 371 372 373/*********************************************************************** 374 * FlagRef 375 */ 376 377bool FlagRef::fromXml(XMLHandle dbNode) 378{ 379 Name = ReadStringNode(dbNode, "NAME"); 380 return !Name.empty(); 381} 382 383bool FlagRef::toSdb(Database& db) 384{ 385 TAGID tagid = db.BeginWriteListTag(TAG_FLAG_REF); 386 db.WriteString(TAG_NAME, Name, true); 387 388 if (!FlagTagid) 389 FlagTagid = db.FindFlagTagid(Name); 390 db.WriteDWord(TAG_FLAG_TAGID, FlagTagid); 391 return !!db.EndWriteListTag(tagid); 392} 393 394 395/*********************************************************************** 396 * Shim 397 */ 398 399bool Shim::fromXml(XMLHandle dbNode) 400{ 401 Name = ReadStringNode(dbNode, "NAME"); 402 DllFile = ReadStringNode(dbNode, "DLLFILE"); 403 ReadGuidNode(dbNode, "FIX_ID", FixID); 404 // GENERAL ? 405 // DESCRIPTION_RC_ID 406 ReadGeneric(dbNode, InExcludes, "INCLUDE"); 407 ReadGeneric(dbNode, InExcludes, "EXCLUDE"); 408 return !Name.empty() && !DllFile.empty(); 409} 410 411bool Shim::toSdb(Database& db) 412{ 413 Tagid = db.BeginWriteListTag(TAG_SHIM); 414 db.InsertShimTagid(Name, Tagid); 415 db.WriteString(TAG_NAME, Name); 416 db.WriteString(TAG_DLLFILE, DllFile); 417 if (IsEmptyGuid(FixID)) 418 RandomGuid(FixID); 419 db.WriteBinary(TAG_FIX_ID, FixID); 420 if (!WriteGeneric(InExcludes, db)) 421 return false; 422 return !!db.EndWriteListTag(Tagid); 423} 424 425 426/*********************************************************************** 427 * Flag 428 */ 429 430bool Flag::fromXml(XMLHandle dbNode) 431{ 432 Name = ReadStringNode(dbNode, "NAME"); 433 434 KernelFlags = ReadQWordNode(dbNode, "FLAG_MASK_KERNEL"); 435 UserFlags = ReadQWordNode(dbNode, "FLAG_MASK_USER"); 436 ProcessParamFlags = ReadQWordNode(dbNode, "FLAG_PROCESSPARAM"); 437 438 return !Name.empty(); 439} 440 441bool Flag::toSdb(Database& db) 442{ 443 Tagid = db.BeginWriteListTag(TAG_FLAG); 444 db.InsertFlagTagid(Name, Tagid); 445 db.WriteString(TAG_NAME, Name, true); 446 447 db.WriteQWord(TAG_FLAG_MASK_KERNEL, KernelFlags); 448 db.WriteQWord(TAG_FLAG_MASK_USER, UserFlags); 449 db.WriteQWord(TAG_FLAG_PROCESSPARAM, ProcessParamFlags); 450 451 return !!db.EndWriteListTag(Tagid); 452} 453 454 455/*********************************************************************** 456 * Data 457 */ 458 459#ifndef REG_SZ 460#define REG_SZ 1 461//#define REG_BINARY 3 462#define REG_DWORD 4 463#define REG_QWORD 11 464#endif 465 466 467bool Data::fromXml(XMLHandle dbNode) 468{ 469 Name = ReadStringNode(dbNode, "NAME"); 470 471 StringData = ReadStringNode(dbNode, "DATA_STRING"); 472 if (!StringData.empty()) 473 { 474 DataType = REG_SZ; 475 return !Name.empty(); 476 } 477 DWordData = ReadDWordNode(dbNode, "DATA_DWORD"); 478 if (DWordData) 479 { 480 DataType = REG_DWORD; 481 return !Name.empty(); 482 } 483 QWordData = ReadQWordNode(dbNode, "DATA_QWORD"); 484 if (QWordData) 485 { 486 DataType = REG_QWORD; 487 return !Name.empty(); 488 } 489 490 SHIM_ERR("Data node (%s) without value!\n", Name.c_str()); 491 return false; 492} 493 494bool Data::toSdb(Database& db) 495{ 496 Tagid = db.BeginWriteListTag(TAG_DATA); 497 db.WriteString(TAG_NAME, Name, true); 498 db.WriteDWord(TAG_DATA_VALUETYPE, DataType, true); 499 switch (DataType) 500 { 501 case REG_SZ: 502 db.WriteString(TAG_DATA_STRING, StringData); 503 break; 504 case REG_DWORD: 505 db.WriteDWord(TAG_DATA_DWORD, DWordData); 506 break; 507 case REG_QWORD: 508 db.WriteQWord(TAG_DATA_QWORD, QWordData); 509 break; 510 default: 511 SHIM_ERR("Data node (%s) with unknown type (0x%x)\n", Name.c_str(), DataType); 512 return false; 513 } 514 515 return !!db.EndWriteListTag(Tagid); 516} 517 518/*********************************************************************** 519 * Layer 520 */ 521 522bool Layer::fromXml(XMLHandle dbNode) 523{ 524 Name = ReadStringNode(dbNode, "NAME"); 525 ReadGeneric(dbNode, ShimRefs, "SHIM_REF"); 526 ReadGeneric(dbNode, FlagRefs, "FLAG_REF"); 527 ReadGeneric(dbNode, Datas, "DATA"); 528 return true; 529} 530 531bool Layer::toSdb(Database& db) 532{ 533 Tagid = db.BeginWriteListTag(TAG_LAYER); 534 db.WriteString(TAG_NAME, Name, true); 535 if (!WriteGeneric(ShimRefs, db)) 536 return false; 537 if (!WriteGeneric(FlagRefs, db)) 538 return false; 539 if (!WriteGeneric(Datas, db)) 540 return false; 541 return !!db.EndWriteListTag(Tagid); 542} 543 544 545/*********************************************************************** 546 * MatchingFile 547 */ 548 549bool MatchingFile::fromXml(XMLHandle dbNode) 550{ 551 Name = ReadStringNode(dbNode, "NAME"); 552 Size = ReadDWordNode(dbNode, "SIZE"); 553 Checksum = ReadDWordNode(dbNode, "CHECKSUM"); 554 CompanyName = ReadStringNode(dbNode, "COMPANY_NAME"); 555 InternalName = ReadStringNode(dbNode, "INTERNAL_NAME"); 556 ProductName = ReadStringNode(dbNode, "PRODUCT_NAME"); 557 ProductVersion = ReadStringNode(dbNode, "PRODUCT_VERSION"); 558 FileVersion = ReadStringNode(dbNode, "FILE_VERSION"); 559 BinFileVersion = ReadStringNode(dbNode, "BIN_FILE_VERSION"); 560 LinkDate = ReadDWordNode(dbNode, "LINK_DATE"); 561 VerLanguage = ReadStringNode(dbNode, "VER_LANGUAGE"); 562 FileDescription = ReadStringNode(dbNode, "FILE_DESCRIPTION"); 563 OriginalFilename = ReadStringNode(dbNode, "ORIGINAL_FILENAME"); 564 UptoBinFileVersion = ReadStringNode(dbNode, "UPTO_BIN_FILE_VERSION"); 565 LinkerVersion = ReadDWordNode(dbNode, "LINKER_VERSION"); 566 return true; 567} 568 569bool MatchingFile::toSdb(Database& db) 570{ 571 TAGID tagid = db.BeginWriteListTag(TAG_MATCHING_FILE); 572 573 db.WriteString(TAG_NAME, Name, true); 574 db.WriteDWord(TAG_SIZE, Size); 575 db.WriteDWord(TAG_CHECKSUM, Checksum); 576 db.WriteString(TAG_COMPANY_NAME, CompanyName); 577 db.WriteString(TAG_INTERNAL_NAME, InternalName); 578 db.WriteString(TAG_PRODUCT_NAME, ProductName); 579 db.WriteString(TAG_PRODUCT_VERSION, ProductVersion); 580 db.WriteString(TAG_FILE_VERSION, FileVersion); 581 if (!BinFileVersion.empty()) 582 SHIM_ERR("TAG_BIN_FILE_VERSION Unimplemented\n"); //db.WriteQWord(TAG_BIN_FILE_VERSION, BinFileVersion); 583 db.WriteDWord(TAG_LINK_DATE, LinkDate); 584 if (!VerLanguage.empty()) 585 SHIM_ERR("TAG_VER_LANGUAGE Unimplemented\n"); //db.WriteDWord(TAG_VER_LANGUAGE, VerLanguage); 586 db.WriteString(TAG_FILE_DESCRIPTION, FileDescription); 587 db.WriteString(TAG_ORIGINAL_FILENAME, OriginalFilename); 588 if (!UptoBinFileVersion.empty()) 589 SHIM_ERR("TAG_UPTO_BIN_FILE_VERSION Unimplemented\n"); //db.WriteQWord(TAG_UPTO_BIN_FILE_VERSION, UptoBinFileVersion); 590 db.WriteDWord(TAG_LINKER_VERSION, LinkerVersion); 591 592 return !!db.EndWriteListTag(tagid); 593} 594 595 596/*********************************************************************** 597 * Exe 598 */ 599 600bool Exe::fromXml(XMLHandle dbNode) 601{ 602 Name = ReadStringNode(dbNode, "NAME"); 603 ReadGuidNode(dbNode, "EXE_ID", ExeID); 604 AppName = ReadStringNode(dbNode, "APP_NAME"); 605 Vendor = ReadStringNode(dbNode, "VENDOR"); 606 607 ReadGeneric(dbNode, MatchingFiles, "MATCHING_FILE"); 608 609 ReadGeneric(dbNode, ShimRefs, "SHIM_REF"); 610 ReadGeneric(dbNode, FlagRefs, "FLAG_REF"); 611 612 Platform = ReadPlatformNode(dbNode, "RUNTIME_PLATFORM"); 613 614 return !Name.empty(); 615} 616 617bool Exe::toSdb(Database& db) 618{ 619 Tagid = db.BeginWriteListTag(TAG_EXE); 620 621 db.WriteString(TAG_NAME, Name, true); 622 if (IsEmptyGuid(ExeID)) 623 RandomGuid(ExeID); 624 db.WriteBinary(TAG_EXE_ID, ExeID); 625 626 627 db.WriteString(TAG_APP_NAME, AppName); 628 db.WriteString(TAG_VENDOR, Vendor); 629 630 if (!WriteGeneric(MatchingFiles, db)) 631 return false; 632 if (!WriteGeneric(ShimRefs, db)) 633 return false; 634 if (!WriteGeneric(FlagRefs, db)) 635 return false; 636 637 return !!db.EndWriteListTag(Tagid); 638} 639 640 641/*********************************************************************** 642 * Database 643 */ 644 645void Database::WriteBinary(TAG tag, const GUID& guid, bool always) 646{ 647 if (always || !IsEmptyGuid(guid)) 648 SdbWriteBinaryTag(pdb, tag, (BYTE*)&guid, sizeof(GUID)); 649} 650 651void Database::WriteBinary(TAG tag, const std::vector<BYTE>& data, bool always) 652{ 653 if (always || !data.empty()) 654 SdbWriteBinaryTag(pdb, tag, data.data(), data.size()); 655} 656 657void Database::WriteString(TAG tag, const sdbstring& str, bool always) 658{ 659 if (always || !str.empty()) 660 SdbWriteStringTag(pdb, tag, (LPCWSTR)str.c_str()); 661} 662 663void Database::WriteString(TAG tag, const std::string& str, bool always) 664{ 665 WriteString(tag, sdbstring(str.begin(), str.end()), always); 666} 667 668void Database::WriteDWord(TAG tag, DWORD value, bool always) 669{ 670 if (always || value) 671 SdbWriteDWORDTag(pdb, tag, value); 672} 673 674void Database::WriteQWord(TAG tag, QWORD value, bool always) 675{ 676 if (always || value) 677 SdbWriteQWORDTag(pdb, tag, value); 678} 679 680void Database::WriteNull(TAG tag) 681{ 682 SdbWriteNULLTag(pdb, tag); 683} 684 685TAGID Database::BeginWriteListTag(TAG tag) 686{ 687 return SdbBeginWriteListTag(pdb, tag); 688} 689 690BOOL Database::EndWriteListTag(TAGID tagid) 691{ 692 return SdbEndWriteListTag(pdb, tagid); 693} 694 695bool Database::fromXml(XMLHandle dbNode) 696{ 697 Name = ReadStringNode(dbNode, "NAME"); 698 ReadGuidNode(dbNode, "DATABASE_ID", ID); 699 700 XMLHandle libChild = dbNode.FirstChildElement("LIBRARY").FirstChild(); 701 while (libChild.ToNode()) 702 { 703 std::string NodeName = ToNodeName(libChild); 704 if (NodeName == "SHIM") 705 { 706 Shim shim; 707 if (shim.fromXml(libChild) && ((shim.Platform & platform) != PLATFORM_NONE)) 708 Library.Shims.push_back(shim); 709 } 710 else if (NodeName == "FLAG") 711 { 712 Flag flag; 713 if (flag.fromXml(libChild)) 714 Library.Flags.push_back(flag); 715 } 716 else if (NodeName == "INCLUDE" || NodeName == "EXCLUDE") 717 { 718 InExclude inex; 719 if (inex.fromXml(libChild)) 720 Library.InExcludes.push_back(inex); 721 } 722 libChild = libChild.NextSibling(); 723 } 724 725 ReadGeneric(dbNode, Layers, "LAYER", platform); 726 ReadGeneric(dbNode, Exes, "EXE", platform); 727 return true; 728} 729 730bool Database::fromXml(const char* fileName, PlatformType platform_) 731{ 732 tinyxml2::XMLDocument doc; 733 tinyxml2::XMLError err = doc.LoadFile(fileName); 734 XMLHandle dbHandle = tinyxml2::XMLHandle(&doc).FirstChildElement("SDB").FirstChildElement("DATABASE"); 735 platform = platform_; 736 return fromXml(dbHandle); 737} 738 739bool Database::toSdb(LPCWSTR path) 740{ 741 pdb = SdbCreateDatabase(path, DOS_PATH); 742 TAGID tidDatabase = BeginWriteListTag(TAG_DATABASE); 743 LARGE_INTEGER li = { 0 }; 744 RtlSecondsSince1970ToTime(time(0), &li); 745 WriteQWord(TAG_TIME, li.QuadPart); 746 WriteString(TAG_COMPILER_VERSION, szCompilerVersion); 747 WriteDWord(TAG_OS_PLATFORM, platform); 748 WriteString(TAG_NAME, Name, true); 749 if (IsEmptyGuid(ID)) 750 { 751 SHIM_WARN("DB has empty ID!\n"); 752 RandomGuid(ID); 753 } 754 WriteBinary(TAG_DATABASE_ID, ID); 755 TAGID tidLibrary = BeginWriteListTag(TAG_LIBRARY); 756 if (!WriteGeneric(Library.InExcludes, *this)) 757 return false; 758 if (!WriteGeneric(Library.Shims, *this)) 759 return false; 760 if (!WriteGeneric(Library.Flags, *this)) 761 return false; 762 EndWriteListTag(tidLibrary); 763 if (!WriteGeneric(Layers, *this)) 764 return false; 765 if (!WriteGeneric(Exes, *this)) 766 return false; 767 EndWriteListTag(tidDatabase); 768 769 SdbCloseDatabaseWrite(pdb); 770 pdb = nullptr; 771 return true; 772} 773 774static void InsertTagid(const sdbstring& name, TAGID tagid, std::map<sdbstring, TAGID>& lookup, const char* type) 775{ 776 sdbstring nameLower = name; 777 std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); 778 if (lookup.find(nameLower) != lookup.end()) 779 { 780 std::string nameA(name.begin(), name.end()); 781 SHIM_WARN("%s '%s' redefined\n", type, nameA.c_str()); 782 return; 783 } 784 lookup[nameLower] = tagid; 785} 786 787static TAGID FindTagid(const sdbstring& name, const std::map<sdbstring, TAGID>& lookup) 788{ 789 sdbstring nameLower = name; 790 std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); 791 std::map<sdbstring, TAGID>::const_iterator it = lookup.find(nameLower); 792 if (it == lookup.end()) 793 return 0; 794 return it->second; 795} 796 797void Database::InsertShimTagid(const sdbstring& name, TAGID tagid) 798{ 799 InsertTagid(name, tagid, KnownShims, "Shim"); 800} 801 802TAGID Database::FindShimTagid(const sdbstring& name) 803{ 804 return FindTagid(name, KnownShims); 805} 806 807void Database::InsertPatchTagid(const sdbstring& name, TAGID tagid) 808{ 809 InsertTagid(name, tagid, KnownPatches, "Patch"); 810} 811 812TAGID Database::FindPatchTagid(const sdbstring& name) 813{ 814 return FindTagid(name, KnownPatches); 815} 816 817void Database::InsertFlagTagid(const sdbstring& name, TAGID tagid) 818{ 819 InsertTagid(name, tagid, KnownFlags, "Flag"); 820} 821 822TAGID Database::FindFlagTagid(const sdbstring& name) 823{ 824 return FindTagid(name, KnownFlags); 825}