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