diff --git a/reactos/sdk/tools/xml2sdb/CMakeLists.txt b/reactos/sdk/tools/xml2sdb/CMakeLists.txt index 72118641922..576e4b6a8c0 100644 --- a/reactos/sdk/tools/xml2sdb/CMakeLists.txt +++ b/reactos/sdk/tools/xml2sdb/CMakeLists.txt @@ -5,6 +5,7 @@ list(APPEND SOURCE main.cpp tinyxml2.cpp xml2sdb.cpp + xml2sdb.h ${REACTOS_SOURCE_DIR}/dll/appcompat/apphelp/sdbwrite.c ${REACTOS_SOURCE_DIR}/dll/appcompat/apphelp/sdbstringtable.c) diff --git a/reactos/sdk/tools/xml2sdb/main.cpp b/reactos/sdk/tools/xml2sdb/main.cpp index 4c3ebe99371..3afcc079442 100644 --- a/reactos/sdk/tools/xml2sdb/main.cpp +++ b/reactos/sdk/tools/xml2sdb/main.cpp @@ -186,14 +186,19 @@ static bool run_one(std::string& input, std::string& output) static std::string get_strarg(int argc, char* argv[], int& i) { - if (argv[i][2] == 0) - { - ++i; - if (i >= argc || !argv[i]) - return std::string(); - return argv[i]; - } - return std::string(argv[i] + 2); + if (argv[i][2] != 0) + return std::string(argv[i] + 2); + + ++i; + if (i >= argc || !argv[i]) + return std::string(); + return argv[i]; +} + +static void update_loglevel(int argc, char* argv[], int& i) +{ + std::string value = get_strarg(argc, argv, i); + g_ShimDebugLevel = strtoul(value.c_str(), NULL, 10); } // -i R:\src\apphelp\reactos\media\sdb\sysmain.xml -oR:\build\apphelp\devenv_msvc\media\sdb\ros2.sdb @@ -204,25 +209,28 @@ int main(int argc, char * argv[]) for (int i = 1; i < argc; ++i) { - if (argv[i][0] == '/' || argv[i][0] == '-') + if (argv[i][0] != '/' && argv[i][0] != '-') + continue; + + switch(argv[i][1]) { - switch(argv[i][1]) - { - case 'i': - input = get_strarg(argc, argv, i); - break; - case 'o': - output = get_strarg(argc, argv, i); - break; - } - if (!input.empty() && !output.empty()) - { - if (!run_one(input, output)) - { - printf("Failed converting '%s' to '%s'\n", input.c_str(), output.c_str()); - return 1; - } - } + case 'i': + input = get_strarg(argc, argv, i); + break; + case 'o': + output = get_strarg(argc, argv, i); + break; + case 'l': + update_loglevel(argc, argv, i); + break; + } + if (input.empty() || output.empty()) + continue; + + if (!run_one(input, output)) + { + printf("Failed converting '%s' to '%s'\n", input.c_str(), output.c_str()); + return 1; } } return 0; diff --git a/reactos/sdk/tools/xml2sdb/xml2sdb.cpp b/reactos/sdk/tools/xml2sdb/xml2sdb.cpp index d5663ac30e5..59d8724bc02 100644 --- a/reactos/sdk/tools/xml2sdb/xml2sdb.cpp +++ b/reactos/sdk/tools/xml2sdb/xml2sdb.cpp @@ -2,7 +2,7 @@ * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS xml to sdb converter * FILE: sdk/tools/xml2sdb/xml2sdb.cpp - * PURPOSE: Main conversion functions from xml -> db + * PURPOSE: Conversion functions from xml -> db * PROGRAMMERS: Mark Jansen * */ @@ -16,6 +16,7 @@ using tinyxml2::XMLText; static const GUID GUID_NULL = { 0 }; +static const char szCompilerVersion[] = "1.5.0.0"; #if !defined(C_ASSERT) #define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1] @@ -44,7 +45,7 @@ VOID NTAPI RtlSecondsSince1970ToTime(IN ULONG SecondsSince1970, // Convert utf8 to utf16: // http://stackoverflow.com/a/7154226/4928207 -bool IsEmptyGuid(GUID& g) +bool IsEmptyGuid(const GUID& g) { return !memcmp(&g, &GUID_NULL, sizeof(GUID)); } @@ -89,6 +90,32 @@ std::string ReadStringNode(XMLHandle dbNode, const char* nodeName) return ToString(dbNode.FirstChildElement(nodeName)); } +DWORD ReadDWordNode(XMLHandle dbNode, const char* nodeName) +{ + std::string value = ReadStringNode(dbNode, nodeName); + int base = 10; + if (value.size() > 2 && value[0] == '0' && value[1] == 'x') + { + base = 16; + value = value.substr(2); + } + return static_cast(strtoul(value.c_str(), NULL, base)); +} + +unsigned char char2byte(char hexChar, bool* success = NULL) +{ + if (hexChar >= '0' && hexChar <= '9') + return hexChar - '0'; + if (hexChar >= 'A' && hexChar <= 'F') + return hexChar - 'A' + 10; + if (hexChar >= 'a' && hexChar <= 'f') + return hexChar - 'a' + 10; + + if (success) + *success = false; + return 0; +} + // adapted from wine's ntdll\rtlstr.c rev 1.45 static bool StringToGuid(const std::string& str, GUID& guid) { @@ -124,28 +151,12 @@ static bool StringToGuid(const std::string& str, GUID& guid) { CHAR ch = *lpszGUID, ch2 = lpszGUID[1]; unsigned char byte; + bool converted = true; - /* Read two hex digits as a byte value */ - if (ch >= '0' && ch <= '9') - ch = ch - '0'; - else if (ch >= 'a' && ch <= 'f') - ch = ch - 'a' + 10; - else if (ch >= 'A' && ch <= 'F') - ch = ch - 'A' + 10; - else + byte = char2byte(ch, &converted) << 4 | char2byte(ch2, &converted); + if (!converted) return false; - if (ch2 >= '0' && ch2 <= '9') - ch2 = ch2 - '0'; - else if (ch2 >= 'a' && ch2 <= 'f') - ch2 = ch2 - 'a' + 10; - else if (ch2 >= 'A' && ch2 <= 'F') - ch2 = ch2 - 'A' + 10; - else - return false; - - byte = ch << 4 | ch2; - switch (i) { #ifndef WORDS_BIGENDIAN @@ -194,7 +205,7 @@ static bool StringToGuid(const std::string& str, GUID& guid) return false; } -bool ReadBinaryNode(XMLHandle dbNode, const char* nodeName, GUID& guid) +bool ReadGuidNode(XMLHandle dbNode, const char* nodeName, GUID& guid) { std::string value = ReadStringNode(dbNode, nodeName); if (!StringToGuid(value, guid)) @@ -205,6 +216,23 @@ bool ReadBinaryNode(XMLHandle dbNode, const char* nodeName, GUID& guid) return true; } +bool ReadBinaryNode(XMLHandle dbNode, const char* nodeName, std::vector& data) +{ + std::string value = ReadStringNode(dbNode, nodeName); + value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end()); + + size_t length = value.size() / 2; + if (length * 2 != value.size()) + return false; + + data.resize(length); + for (size_t n = 0; n < length; ++n) + { + data[n] = (BYTE)(char2byte(value[n * 2]) << 4 | char2byte(value[(n * 2) + 1])); + } + return true; +} + /*********************************************************************** * InExclude @@ -234,7 +262,7 @@ bool InExclude::fromXml(XMLHandle dbNode) bool InExclude::toSdb(PDB pdb, Database& db) { TAGID tagid = db.BeginWriteListTag(pdb, TAG_INEXCLUD); - db.WriteString(pdb, TAG_MODULE, Module); + db.WriteString(pdb, TAG_MODULE, Module, true); if (Include) SdbWriteNULLTag(pdb, TAG_INCLUDE); return !!db.EndWriteListTag(pdb, tagid); @@ -282,9 +310,8 @@ bool ShimRef::fromXml(XMLHandle dbNode) bool ShimRef::toSdb(PDB pdb, Database& db) { TAGID tagid = db.BeginWriteListTag(pdb, TAG_SHIM_REF); - db.WriteString(pdb, TAG_NAME, Name); - if (!CommandLine.empty()) - db.WriteString(pdb, TAG_COMMAND_LINE, CommandLine); + db.WriteString(pdb, TAG_NAME, Name, true); + db.WriteString(pdb, TAG_COMMAND_LINE, CommandLine); if (!ShimTagid) ShimTagid = db.FindShimTagid(Name); @@ -301,7 +328,7 @@ bool Shim::fromXml(XMLHandle dbNode) { Name = ReadStringNode(dbNode, "NAME"); DllFile = ReadStringNode(dbNode, "DLLFILE"); - ReadBinaryNode(dbNode, "FIX_ID", FixID); + ReadGuidNode(dbNode, "FIX_ID", FixID); // GENERAL ? // DESCRIPTION_RC_ID ReadGeneric(dbNode, InExcludes, "INEXCLUDE"); @@ -337,7 +364,7 @@ bool Layer::fromXml(XMLHandle dbNode) bool Layer::toSdb(PDB pdb, Database& db) { Tagid = db.BeginWriteListTag(pdb, TAG_LAYER); - db.WriteString(pdb, TAG_NAME, Name); + db.WriteString(pdb, TAG_NAME, Name, true); if (!WriteGeneric(pdb, ShimRefs, db)) return false; return !!db.EndWriteListTag(pdb, Tagid); @@ -351,9 +378,13 @@ bool Layer::toSdb(PDB pdb, Database& db) bool MatchingFile::fromXml(XMLHandle dbNode) { Name = ReadStringNode(dbNode, "NAME"); + Size = ReadDWordNode(dbNode, "SIZE"); + Checksum = ReadDWordNode(dbNode, "CHECKSUM"); CompanyName = ReadStringNode(dbNode, "COMPANY_NAME"); + InternalName = ReadStringNode(dbNode, "INTERNAL_NAME"); ProductName = ReadStringNode(dbNode, "PRODUCT_NAME"); ProductVersion = ReadStringNode(dbNode, "PRODUCT_VERSION"); + FileVersion = ReadStringNode(dbNode, "FILE_VERSION"); BinFileVersion = ReadStringNode(dbNode, "BIN_FILE_VERSION"); LinkDate = ReadStringNode(dbNode, "LINK_DATE"); VerLanguage = ReadStringNode(dbNode, "VER_LANGUAGE"); @@ -367,7 +398,28 @@ bool MatchingFile::fromXml(XMLHandle dbNode) bool MatchingFile::toSdb(PDB pdb, Database& db) { TAGID tagid = db.BeginWriteListTag(pdb, TAG_MATCHING_FILE); - SHIM_ERR("Unimplemented\n"); + + db.WriteString(pdb, TAG_NAME, Name, true); + db.WriteDWord(pdb, TAG_SIZE, Size); + db.WriteDWord(pdb, TAG_CHECKSUM, Checksum); + db.WriteString(pdb, TAG_COMPANY_NAME, CompanyName); + db.WriteString(pdb, TAG_INTERNAL_NAME, InternalName); + db.WriteString(pdb, TAG_PRODUCT_NAME, ProductName); + db.WriteString(pdb, TAG_PRODUCT_VERSION, ProductVersion); + db.WriteString(pdb, TAG_FILE_VERSION, FileVersion); + if (!BinFileVersion.empty()) + SHIM_ERR("TAG_BIN_FILE_VERSION Unimplemented\n"); //db.WriteQWord(pdb, TAG_BIN_FILE_VERSION, BinFileVersion); + if (!LinkDate.empty()) + SHIM_ERR("TAG_LINK_DATE Unimplemented\n"); //db.WriteDWord(pdb, TAG_LINK_DATE, LinkDate); + if (!VerLanguage.empty()) + SHIM_ERR("TAG_VER_LANGUAGE Unimplemented\n"); //db.WriteDWord(pdb, TAG_VER_LANGUAGE, VerLanguage); + db.WriteString(pdb, TAG_FILE_DESCRIPTION, FileDescription); + db.WriteString(pdb, TAG_ORIGINAL_FILENAME, OriginalFilename); + if (!UptoBinFileVersion.empty()) + SHIM_ERR("TAG_UPTO_BIN_FILE_VERSION Unimplemented\n"); //db.WriteQWord(pdb, TAG_UPTO_BIN_FILE_VERSION, UptoBinFileVersion); + if (!LinkerVersion.empty()) + SHIM_ERR("TAG_LINKER_VERSION Unimplemented\n"); //db.WriteDWord(pdb, TAG_LINKER_VERSION, LinkerVersion); + return !!db.EndWriteListTag(pdb, tagid); } @@ -380,9 +432,12 @@ bool MatchingFile::toSdb(PDB pdb, Database& db) bool Exe::fromXml(XMLHandle dbNode) { Name = ReadStringNode(dbNode, "NAME"); + ReadGuidNode(dbNode, "EXE_ID", ExeID); AppName = ReadStringNode(dbNode, "APP_NAME"); Vendor = ReadStringNode(dbNode, "VENDOR"); + ReadGeneric(dbNode, MatchingFiles, "MATCHING_FILE"); + ReadGeneric(dbNode, ShimRefs, "SHIM_REF"); return !Name.empty(); @@ -391,7 +446,20 @@ bool Exe::fromXml(XMLHandle dbNode) bool Exe::toSdb(PDB pdb, Database& db) { Tagid = db.BeginWriteListTag(pdb, TAG_EXE); - SHIM_ERR("Unimplemented\n"); + + db.WriteString(pdb, TAG_NAME, Name, true); + if (IsEmptyGuid(ExeID)) + RandomGuid(ExeID); + db.WriteBinary(pdb, TAG_EXE_ID, ExeID); + + + db.WriteString(pdb, TAG_APP_NAME, AppName); + db.WriteString(pdb, TAG_VENDOR, Vendor); + + if (!WriteGeneric(pdb, MatchingFiles, db)) + return false; + if (!WriteGeneric(pdb, ShimRefs, db)) + return false; return !!db.EndWriteListTag(pdb, Tagid); } @@ -401,19 +469,33 @@ bool Exe::toSdb(PDB pdb, Database& db) * Database */ -void Database::WriteBinary(PDB pdb, TAG tag, const GUID& guid) +void Database::WriteBinary(PDB pdb, TAG tag, const GUID& guid, bool always) { - SdbWriteBinaryTag(pdb, tag, (BYTE*)&guid, sizeof(GUID)); + if (always || !IsEmptyGuid(guid)) + SdbWriteBinaryTag(pdb, tag, (BYTE*)&guid, sizeof(GUID)); } -void Database::WriteString(PDB pdb, TAG tag, const sdbstring& str) +void Database::WriteBinary(PDB pdb, TAG tag, const std::vector& data, bool always) { - SdbWriteStringTag(pdb, tag, (LPCWSTR)str.c_str()); + if (always || !data.empty()) + SdbWriteBinaryTag(pdb, tag, data.data(), data.size()); } -void Database::WriteString(PDB pdb, TAG tag, const std::string& str) +void Database::WriteString(PDB pdb, TAG tag, const sdbstring& str, bool always) { - WriteString(pdb, tag, sdbstring(str.begin(), str.end())); + if (always || !str.empty()) + SdbWriteStringTag(pdb, tag, (LPCWSTR)str.c_str()); +} + +void Database::WriteString(PDB pdb, TAG tag, const std::string& str, bool always) +{ + WriteString(pdb, tag, sdbstring(str.begin(), str.end()), always); +} + +void Database::WriteDWord(PDB pdb, TAG tag, DWORD value, bool always) +{ + if (always || value) + SdbWriteDWORDTag(pdb, tag, value); } TAGID Database::BeginWriteListTag(PDB db, TAG tag) @@ -429,7 +511,7 @@ BOOL Database::EndWriteListTag(PDB db, TAGID tagid) bool Database::fromXml(XMLHandle dbNode) { Name = ReadStringNode(dbNode, "NAME"); - ReadBinaryNode(dbNode, "DATABASE_ID", ID); + ReadGuidNode(dbNode, "DATABASE_ID", ID); XMLHandle libChild = dbNode.FirstChildElement("LIBRARY").FirstChild(); while (libChild.ToNode()) @@ -439,7 +521,7 @@ bool Database::fromXml(XMLHandle dbNode) { Shim shim; if (shim.fromXml(libChild)) - Library.push_back(shim); + Library.Shims.push_back(shim); } else if (NodeName == "FLAG") { @@ -468,12 +550,17 @@ bool Database::toSdb(LPCWSTR path) LARGE_INTEGER li = { 0 }; RtlSecondsSince1970ToTime(time(0), &li); SdbWriteQWORDTag(pdb, TAG_TIME, li.QuadPart); - WriteString(pdb, TAG_COMPILER_VERSION, "1.0.0.0"); + WriteString(pdb, TAG_COMPILER_VERSION, szCompilerVersion); SdbWriteDWORDTag(pdb, TAG_OS_PLATFORM, 1); - WriteString(pdb, TAG_NAME, Name); + WriteString(pdb, TAG_NAME, Name, true); + if (IsEmptyGuid(ID)) + { + SHIM_WARN("DB has empty ID!\n"); + RandomGuid(ID); + } WriteBinary(pdb, TAG_DATABASE_ID, ID); TAGID tidLibrary = BeginWriteListTag(pdb, TAG_LIBRARY); - if (!WriteGeneric(pdb, Library, *this)) + if (!WriteGeneric(pdb, Library.Shims, *this)) return false; EndWriteListTag(pdb, tidLibrary); if (!WriteGeneric(pdb, Layers, *this)) @@ -486,40 +573,50 @@ bool Database::toSdb(LPCWSTR path) return true; } - -void Database::InsertShimTagid(const sdbstring& name, TAGID tagid) +static void InsertTagid(const sdbstring& name, TAGID tagid, std::map& lookup, const char* type) { sdbstring nameLower = name; std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); - if (KnownShims.find(nameLower) != KnownShims.end()) + if (lookup.find(nameLower) != lookup.end()) { std::string nameA(name.begin(), name.end()); - SHIM_WARN("Shim '%s' redefined\n", nameA.c_str()); + SHIM_WARN("%s '%s' redefined\n", type, nameA.c_str()); return; } - KnownShims[nameLower] = tagid; + lookup[nameLower] = tagid; } -void Database::InsertShimTagid(const std::string& name, TAGID tagid) -{ - InsertShimTagid(sdbstring(name.begin(), name.end()), tagid); -} - -TAGID Database::FindShimTagid(const sdbstring& name) +static TAGID FindTagid(const sdbstring& name, const std::map& lookup) { sdbstring nameLower = name; std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); - std::map::iterator it = KnownShims.find(nameLower); - if (it == KnownShims.end()) + std::map::const_iterator it = lookup.find(nameLower); + if (it == lookup.end()) return 0; return it->second; } -TAGID Database::FindShimTagid(const std::string& name) +void Database::InsertShimTagid(const sdbstring& name, TAGID tagid) { - return FindShimTagid(sdbstring(name.begin(), name.end())); + InsertTagid(name, tagid, KnownShims, "Shim"); } +TAGID Database::FindShimTagid(const sdbstring& name) +{ + return FindTagid(name, KnownShims); +} + +void Database::InsertPatchTagid(const sdbstring& name, TAGID tagid) +{ + InsertTagid(name, tagid, KnownPatches, "Patch"); +} + +TAGID Database::FindPatchTagid(const sdbstring& name) +{ + return FindTagid(name, KnownPatches); +} + + bool xml_2_db(const char* xml, const WCHAR* sdb) { diff --git a/reactos/sdk/tools/xml2sdb/xml2sdb.h b/reactos/sdk/tools/xml2sdb/xml2sdb.h index c1ab640d37b..c9bba09175e 100644 --- a/reactos/sdk/tools/xml2sdb/xml2sdb.h +++ b/reactos/sdk/tools/xml2sdb/xml2sdb.h @@ -71,13 +71,19 @@ struct Layer struct MatchingFile { + MatchingFile() : Size(0), Checksum(0) {;} + bool fromXml(XMLHandle dbNode); bool toSdb(PDB pdb, Database& db); std::string Name; + DWORD Size; + DWORD Checksum; std::string CompanyName; + std::string InternalName; std::string ProductName; std::string ProductVersion; + std::string FileVersion; std::string BinFileVersion; std::string LinkDate; std::string VerLanguage; @@ -95,12 +101,19 @@ struct Exe bool toSdb(PDB pdb, Database& db); std::string Name; + GUID ExeID; std::string AppName; std::string Vendor; TAGID Tagid; + std::list MatchingFiles; std::list ShimRefs; }; +struct Library +{ + std::list Shims; +}; + struct Database { @@ -108,25 +121,34 @@ struct Database bool fromXml(XMLHandle dbNode); bool toSdb(LPCWSTR path); - void WriteString(PDB pdb, TAG tag, const sdbstring& str); - void WriteString(PDB pdb, TAG tag, const std::string& str); - void WriteBinary(PDB pdb, TAG tag, const GUID& guid); + void WriteString(PDB pdb, TAG tag, const sdbstring& str, bool always = false); + void WriteString(PDB pdb, TAG tag, const std::string& str, bool always = false); + void WriteBinary(PDB pdb, TAG tag, const GUID& guid, bool always = false); + void WriteBinary(PDB pdb, TAG tag, const std::vector& data, bool always = false); + void WriteDWord(PDB pdb, TAG tag, DWORD value, bool always = false); TAGID BeginWriteListTag(PDB db, TAG tag); BOOL EndWriteListTag(PDB db, TAGID tagid); void InsertShimTagid(const sdbstring& name, TAGID tagid); - void InsertShimTagid(const std::string& name, TAGID tagid); + inline void InsertShimTagid(const std::string& name, TAGID tagid) + { + InsertShimTagid(sdbstring(name.begin(), name.end()), tagid); + } TAGID FindShimTagid(const sdbstring& name); - TAGID FindShimTagid(const std::string& name); + inline TAGID FindShimTagid(const std::string& name) + { + return FindShimTagid(sdbstring(name.begin(), name.end())); + } std::string Name; GUID ID; - std::list Library; + struct Library Library; std::list Layers; std::list Exes; private: std::map KnownShims; + std::map KnownPatches; };