mirror of
https://github.com/reactos/reactos.git
synced 2024-11-01 12:26:32 +00:00
774 lines
20 KiB
C++
774 lines
20 KiB
C++
/*
|
|
* PROJECT: xml2sdb
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
|
* PURPOSE: Conversion functions from xml -> db
|
|
* COPYRIGHT: Copyright 2016-2018 Mark Jansen (mark.jansen@reactos.org)
|
|
*/
|
|
|
|
#include "xml2sdb.h"
|
|
#include "sdbpapi.h"
|
|
#include "tinyxml2.h"
|
|
#include <time.h>
|
|
#include <algorithm>
|
|
|
|
using tinyxml2::XMLText;
|
|
|
|
static const GUID GUID_NULL = { 0 };
|
|
static const char szCompilerVersion[] = "1.7.0.1";
|
|
|
|
#if !defined(C_ASSERT)
|
|
#define C_ASSERT(expr) extern char (*c_assert(void)) [(expr) ? 1 : -1]
|
|
#endif
|
|
|
|
|
|
C_ASSERT(sizeof(GUID) == 16);
|
|
C_ASSERT(sizeof(ULONG) == 4);
|
|
C_ASSERT(sizeof(LARGE_INTEGER) == 8);
|
|
C_ASSERT(sizeof(WCHAR) == 2);
|
|
C_ASSERT(sizeof(wchar_t) == 2);
|
|
C_ASSERT(sizeof(TAG) == 2);
|
|
C_ASSERT(sizeof(TAGID) == 4);
|
|
|
|
|
|
extern "C"
|
|
VOID NTAPI RtlSecondsSince1970ToTime(IN ULONG SecondsSince1970,
|
|
OUT PLARGE_INTEGER Time);
|
|
|
|
|
|
/***********************************************************************
|
|
* Helper functions
|
|
*/
|
|
|
|
|
|
// Convert utf8 to utf16:
|
|
// http://stackoverflow.com/a/7154226/4928207
|
|
|
|
bool IsEmptyGuid(const GUID& g)
|
|
{
|
|
return !memcmp(&g, &GUID_NULL, sizeof(GUID));
|
|
}
|
|
|
|
void RandomGuid(GUID& g)
|
|
{
|
|
BYTE* p = (BYTE*)&g;
|
|
for (size_t n = 0; n < sizeof(GUID); ++n)
|
|
p[n] = (BYTE)(rand() % 0xff);
|
|
}
|
|
|
|
// Given a node, return the node value (safe)
|
|
std::string ToString(XMLHandle node)
|
|
{
|
|
XMLText* txtNode = node.FirstChild().ToText();
|
|
const char* txt = txtNode ? txtNode->Value() : NULL;
|
|
if (txt)
|
|
return std::string(txt);
|
|
return std::string();
|
|
}
|
|
|
|
// Given a node, return the node name (safe)
|
|
std::string ToNodeName(XMLHandle node)
|
|
{
|
|
tinyxml2::XMLNode* raw = node.ToNode();
|
|
const char* txt = raw ? raw->Value() : NULL;
|
|
if (txt)
|
|
return std::string(txt);
|
|
return std::string();
|
|
}
|
|
|
|
// Read either an attribute, or a child node
|
|
std::string ReadStringNode(XMLHandle dbNode, const char* nodeName)
|
|
{
|
|
tinyxml2::XMLElement* elem = dbNode.ToElement();
|
|
if (elem)
|
|
{
|
|
const char* rawVal = elem->Attribute(nodeName);
|
|
if (rawVal)
|
|
return std::string(rawVal);
|
|
}
|
|
return ToString(dbNode.FirstChildElement(nodeName));
|
|
}
|
|
|
|
DWORD ReadQWordNode(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<QWORD>(strtoul(value.c_str(), NULL, base));
|
|
}
|
|
|
|
DWORD ReadDWordNode(XMLHandle dbNode, const char* nodeName)
|
|
{
|
|
return static_cast<DWORD>(ReadQWordNode(dbNode, nodeName));
|
|
}
|
|
|
|
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)
|
|
{
|
|
const char *lpszGUID = str.c_str();
|
|
BYTE* lpOut = (BYTE*)&guid;
|
|
int i = 0;
|
|
bool expectBrace = true;
|
|
while (i <= 37)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0:
|
|
if (*lpszGUID != '{')
|
|
{
|
|
i++;
|
|
expectBrace = false;
|
|
continue;
|
|
}
|
|
break;
|
|
|
|
case 9:
|
|
case 14:
|
|
case 19:
|
|
case 24:
|
|
if (*lpszGUID != '-')
|
|
return false;
|
|
break;
|
|
|
|
case 37:
|
|
return expectBrace == (*lpszGUID == '}');
|
|
|
|
default:
|
|
{
|
|
CHAR ch = *lpszGUID, ch2 = lpszGUID[1];
|
|
unsigned char byte;
|
|
bool converted = true;
|
|
|
|
byte = char2byte(ch, &converted) << 4 | char2byte(ch2, &converted);
|
|
if (!converted)
|
|
return false;
|
|
|
|
switch (i)
|
|
{
|
|
#ifndef WORDS_BIGENDIAN
|
|
/* For Big Endian machines, we store the data such that the
|
|
* dword/word members can be read as DWORDS and WORDS correctly. */
|
|
/* Dword */
|
|
case 1:
|
|
lpOut[3] = byte;
|
|
break;
|
|
case 3:
|
|
lpOut[2] = byte;
|
|
break;
|
|
case 5:
|
|
lpOut[1] = byte;
|
|
break;
|
|
case 7:
|
|
lpOut[0] = byte;
|
|
lpOut += 4;
|
|
break;
|
|
/* Word */
|
|
case 10:
|
|
case 15:
|
|
lpOut[1] = byte;
|
|
break;
|
|
case 12:
|
|
case 17:
|
|
lpOut[0] = byte;
|
|
lpOut += 2;
|
|
break;
|
|
#endif
|
|
/* Byte */
|
|
default:
|
|
lpOut[0] = byte;
|
|
lpOut++;
|
|
break;
|
|
}
|
|
|
|
lpszGUID++; /* Skip 2nd character of byte */
|
|
i++;
|
|
}
|
|
}
|
|
|
|
lpszGUID++;
|
|
i++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ReadGuidNode(XMLHandle dbNode, const char* nodeName, GUID& guid)
|
|
{
|
|
std::string value = ReadStringNode(dbNode, nodeName);
|
|
if (!StringToGuid(value, guid))
|
|
{
|
|
memset(&guid, 0, sizeof(GUID));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ReadBinaryNode(XMLHandle dbNode, const char* nodeName, std::vector<BYTE>& 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
|
|
*/
|
|
|
|
bool InExclude::fromXml(XMLHandle dbNode)
|
|
{
|
|
Module = ReadStringNode(dbNode, "MODULE");
|
|
// Special module names: '$' and '*'
|
|
if (!Module.empty())
|
|
{
|
|
Include = ToNodeName(dbNode) == "INCLUDE";
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InExclude::toSdb(PDB pdb, Database& db)
|
|
{
|
|
TAGID tagid = db.BeginWriteListTag(pdb, TAG_INEXCLUD);
|
|
db.WriteString(pdb, TAG_MODULE, Module, true);
|
|
if (Include)
|
|
SdbWriteNULLTag(pdb, TAG_INCLUDE);
|
|
return !!db.EndWriteListTag(pdb, tagid);
|
|
}
|
|
|
|
|
|
template<typename T>
|
|
void ReadGeneric(XMLHandle dbNode, std::list<T>& result, const char* nodeName)
|
|
{
|
|
XMLHandle node = dbNode.FirstChildElement(nodeName);
|
|
while (node.ToNode())
|
|
{
|
|
T object;
|
|
if (object.fromXml(node))
|
|
result.push_back(object);
|
|
|
|
node = node.NextSiblingElement(nodeName);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
bool WriteGeneric(PDB pdb, std::list<T>& data, Database& db)
|
|
{
|
|
for (typename std::list<T>::iterator it = data.begin(); it != data.end(); ++it)
|
|
{
|
|
if (!it->toSdb(pdb, db))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* ShimRef
|
|
*/
|
|
|
|
bool ShimRef::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
CommandLine = ReadStringNode(dbNode, "COMMAND_LINE");
|
|
ReadGeneric(dbNode, InExcludes, "INCLUDE");
|
|
ReadGeneric(dbNode, InExcludes, "EXCLUDE");
|
|
return !Name.empty();
|
|
}
|
|
|
|
bool ShimRef::toSdb(PDB pdb, Database& db)
|
|
{
|
|
TAGID tagid = db.BeginWriteListTag(pdb, TAG_SHIM_REF);
|
|
db.WriteString(pdb, TAG_NAME, Name, true);
|
|
db.WriteString(pdb, TAG_COMMAND_LINE, CommandLine);
|
|
|
|
if (!ShimTagid)
|
|
ShimTagid = db.FindShimTagid(Name);
|
|
SdbWriteDWORDTag(pdb, TAG_SHIM_TAGID, ShimTagid);
|
|
return !!db.EndWriteListTag(pdb, tagid);
|
|
}
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
* FlagRef
|
|
*/
|
|
|
|
bool FlagRef::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
return !Name.empty();
|
|
}
|
|
|
|
bool FlagRef::toSdb(PDB pdb, Database& db)
|
|
{
|
|
TAGID tagid = db.BeginWriteListTag(pdb, TAG_FLAG_REF);
|
|
db.WriteString(pdb, TAG_NAME, Name, true);
|
|
|
|
if (!FlagTagid)
|
|
FlagTagid = db.FindFlagTagid(Name);
|
|
SdbWriteDWORDTag(pdb, TAG_FLAG_TAGID, FlagTagid);
|
|
return !!db.EndWriteListTag(pdb, tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Shim
|
|
*/
|
|
|
|
bool Shim::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
DllFile = ReadStringNode(dbNode, "DLLFILE");
|
|
ReadGuidNode(dbNode, "FIX_ID", FixID);
|
|
// GENERAL ?
|
|
// DESCRIPTION_RC_ID
|
|
ReadGeneric(dbNode, InExcludes, "INCLUDE");
|
|
ReadGeneric(dbNode, InExcludes, "EXCLUDE");
|
|
return !Name.empty() && !DllFile.empty();
|
|
}
|
|
|
|
bool Shim::toSdb(PDB pdb, Database& db)
|
|
{
|
|
Tagid = db.BeginWriteListTag(pdb, TAG_SHIM);
|
|
db.InsertShimTagid(Name, Tagid);
|
|
db.WriteString(pdb, TAG_NAME, Name);
|
|
db.WriteString(pdb, TAG_DLLFILE, DllFile);
|
|
if (IsEmptyGuid(FixID))
|
|
RandomGuid(FixID);
|
|
db.WriteBinary(pdb, TAG_FIX_ID, FixID);
|
|
if (!WriteGeneric(pdb, InExcludes, db))
|
|
return false;
|
|
return !!db.EndWriteListTag(pdb, Tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Flag
|
|
*/
|
|
|
|
bool Flag::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
|
|
KernelFlags = ReadQWordNode(dbNode, "FLAG_MASK_KERNEL");
|
|
UserFlags = ReadQWordNode(dbNode, "FLAG_MASK_USER");
|
|
ProcessParamFlags = ReadQWordNode(dbNode, "FLAG_PROCESSPARAM");
|
|
|
|
return !Name.empty();
|
|
}
|
|
|
|
bool Flag::toSdb(PDB pdb, Database& db)
|
|
{
|
|
Tagid = db.BeginWriteListTag(pdb, TAG_FLAG);
|
|
db.InsertFlagTagid(Name, Tagid);
|
|
db.WriteString(pdb, TAG_NAME, Name, true);
|
|
|
|
db.WriteQWord(pdb, TAG_FLAG_MASK_KERNEL, KernelFlags);
|
|
db.WriteQWord(pdb, TAG_FLAG_MASK_USER, UserFlags);
|
|
db.WriteQWord(pdb, TAG_FLAG_PROCESSPARAM, ProcessParamFlags);
|
|
|
|
return !!db.EndWriteListTag(pdb, Tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Data
|
|
*/
|
|
|
|
#ifndef REG_SZ
|
|
#define REG_SZ 1
|
|
//#define REG_BINARY 3
|
|
#define REG_DWORD 4
|
|
#define REG_QWORD 11
|
|
#endif
|
|
|
|
|
|
bool Data::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
|
|
StringData = ReadStringNode(dbNode, "DATA_STRING");
|
|
if (!StringData.empty())
|
|
{
|
|
DataType = REG_SZ;
|
|
return !Name.empty();
|
|
}
|
|
DWordData = ReadDWordNode(dbNode, "DATA_DWORD");
|
|
if (DWordData)
|
|
{
|
|
DataType = REG_DWORD;
|
|
return !Name.empty();
|
|
}
|
|
QWordData = ReadQWordNode(dbNode, "DATA_QWORD");
|
|
if (QWordData)
|
|
{
|
|
DataType = REG_QWORD;
|
|
return !Name.empty();
|
|
}
|
|
|
|
SHIM_ERR("Data node (%s) without value!\n", Name.c_str());
|
|
return false;
|
|
}
|
|
|
|
bool Data::toSdb(PDB pdb, Database& db)
|
|
{
|
|
Tagid = db.BeginWriteListTag(pdb, TAG_DATA);
|
|
db.WriteString(pdb, TAG_NAME, Name, true);
|
|
db.WriteDWord(pdb, TAG_DATA_VALUETYPE, DataType, true);
|
|
switch (DataType)
|
|
{
|
|
case REG_SZ:
|
|
db.WriteString(pdb, TAG_DATA_STRING, StringData);
|
|
break;
|
|
case REG_DWORD:
|
|
db.WriteDWord(pdb, TAG_DATA_DWORD, DWordData);
|
|
break;
|
|
case REG_QWORD:
|
|
db.WriteQWord(pdb, TAG_DATA_QWORD, QWordData);
|
|
break;
|
|
default:
|
|
SHIM_ERR("Data node (%s) with unknown type (0x%x)\n", Name.c_str(), DataType);
|
|
return false;
|
|
}
|
|
|
|
return !!db.EndWriteListTag(pdb, Tagid);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* Layer
|
|
*/
|
|
|
|
bool Layer::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
ReadGeneric(dbNode, ShimRefs, "SHIM_REF");
|
|
ReadGeneric(dbNode, FlagRefs, "FLAG_REF");
|
|
ReadGeneric(dbNode, Datas, "DATA");
|
|
return true;
|
|
}
|
|
|
|
bool Layer::toSdb(PDB pdb, Database& db)
|
|
{
|
|
Tagid = db.BeginWriteListTag(pdb, TAG_LAYER);
|
|
db.WriteString(pdb, TAG_NAME, Name, true);
|
|
if (!WriteGeneric(pdb, ShimRefs, db))
|
|
return false;
|
|
if (!WriteGeneric(pdb, FlagRefs, db))
|
|
return false;
|
|
if (!WriteGeneric(pdb, Datas, db))
|
|
return false;
|
|
return !!db.EndWriteListTag(pdb, Tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* MatchingFile
|
|
*/
|
|
|
|
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 = ReadDWordNode(dbNode, "LINK_DATE");
|
|
VerLanguage = ReadStringNode(dbNode, "VER_LANGUAGE");
|
|
FileDescription = ReadStringNode(dbNode, "FILE_DESCRIPTION");
|
|
OriginalFilename = ReadStringNode(dbNode, "ORIGINAL_FILENAME");
|
|
UptoBinFileVersion = ReadStringNode(dbNode, "UPTO_BIN_FILE_VERSION");
|
|
LinkerVersion = ReadDWordNode(dbNode, "LINKER_VERSION");
|
|
return true;
|
|
}
|
|
|
|
bool MatchingFile::toSdb(PDB pdb, Database& db)
|
|
{
|
|
TAGID tagid = db.BeginWriteListTag(pdb, TAG_MATCHING_FILE);
|
|
|
|
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);
|
|
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);
|
|
db.WriteDWord(pdb, TAG_LINKER_VERSION, LinkerVersion);
|
|
|
|
return !!db.EndWriteListTag(pdb, tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Exe
|
|
*/
|
|
|
|
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");
|
|
ReadGeneric(dbNode, FlagRefs, "FLAG_REF");
|
|
|
|
return !Name.empty();
|
|
}
|
|
|
|
bool Exe::toSdb(PDB pdb, Database& db)
|
|
{
|
|
Tagid = db.BeginWriteListTag(pdb, TAG_EXE);
|
|
|
|
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;
|
|
if (!WriteGeneric(pdb, FlagRefs, db))
|
|
return false;
|
|
|
|
return !!db.EndWriteListTag(pdb, Tagid);
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
* Database
|
|
*/
|
|
|
|
void Database::WriteBinary(PDB pdb, TAG tag, const GUID& guid, bool always)
|
|
{
|
|
if (always || !IsEmptyGuid(guid))
|
|
SdbWriteBinaryTag(pdb, tag, (BYTE*)&guid, sizeof(GUID));
|
|
}
|
|
|
|
void Database::WriteBinary(PDB pdb, TAG tag, const std::vector<BYTE>& data, bool always)
|
|
{
|
|
if (always || !data.empty())
|
|
SdbWriteBinaryTag(pdb, tag, data.data(), data.size());
|
|
}
|
|
|
|
void Database::WriteString(PDB pdb, TAG tag, const sdbstring& str, bool always)
|
|
{
|
|
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);
|
|
}
|
|
|
|
void Database::WriteQWord(PDB pdb, TAG tag, QWORD value, bool always)
|
|
{
|
|
if (always || value)
|
|
SdbWriteQWORDTag(pdb, tag, value);
|
|
}
|
|
|
|
TAGID Database::BeginWriteListTag(PDB pdb, TAG tag)
|
|
{
|
|
return SdbBeginWriteListTag(pdb, tag);
|
|
}
|
|
|
|
BOOL Database::EndWriteListTag(PDB pdb, TAGID tagid)
|
|
{
|
|
return SdbEndWriteListTag(pdb, tagid);
|
|
}
|
|
|
|
bool Database::fromXml(XMLHandle dbNode)
|
|
{
|
|
Name = ReadStringNode(dbNode, "NAME");
|
|
ReadGuidNode(dbNode, "DATABASE_ID", ID);
|
|
|
|
XMLHandle libChild = dbNode.FirstChildElement("LIBRARY").FirstChild();
|
|
while (libChild.ToNode())
|
|
{
|
|
std::string NodeName = ToNodeName(libChild);
|
|
if (NodeName == "SHIM")
|
|
{
|
|
Shim shim;
|
|
if (shim.fromXml(libChild))
|
|
Library.Shims.push_back(shim);
|
|
}
|
|
else if (NodeName == "FLAG")
|
|
{
|
|
Flag flag;
|
|
if (flag.fromXml(libChild))
|
|
Library.Flags.push_back(flag);
|
|
}
|
|
else if (NodeName == "INCLUDE" || NodeName == "EXCLUDE")
|
|
{
|
|
InExclude inex;
|
|
if (inex.fromXml(libChild))
|
|
Library.InExcludes.push_back(inex);
|
|
}
|
|
libChild = libChild.NextSibling();
|
|
}
|
|
|
|
ReadGeneric(dbNode, Layers, "LAYER");
|
|
ReadGeneric(dbNode, Exes, "EXE");
|
|
return true;
|
|
}
|
|
|
|
bool Database::fromXml(const char* fileName)
|
|
{
|
|
tinyxml2::XMLDocument doc;
|
|
tinyxml2::XMLError err = doc.LoadFile(fileName);
|
|
XMLHandle dbHandle = tinyxml2::XMLHandle(&doc).FirstChildElement("SDB").FirstChildElement("DATABASE");
|
|
return fromXml(dbHandle);
|
|
}
|
|
|
|
bool Database::toSdb(LPCWSTR path)
|
|
{
|
|
PDB pdb = SdbCreateDatabase(path, DOS_PATH);
|
|
TAGID tidDatabase = BeginWriteListTag(pdb, TAG_DATABASE);
|
|
LARGE_INTEGER li = { 0 };
|
|
RtlSecondsSince1970ToTime(time(0), &li);
|
|
SdbWriteQWORDTag(pdb, TAG_TIME, li.QuadPart);
|
|
WriteString(pdb, TAG_COMPILER_VERSION, szCompilerVersion);
|
|
SdbWriteDWORDTag(pdb, TAG_OS_PLATFORM, 1);
|
|
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.InExcludes, *this))
|
|
return false;
|
|
if (!WriteGeneric(pdb, Library.Shims, *this))
|
|
return false;
|
|
if (!WriteGeneric(pdb, Library.Flags, *this))
|
|
return false;
|
|
EndWriteListTag(pdb, tidLibrary);
|
|
if (!WriteGeneric(pdb, Layers, *this))
|
|
return false;
|
|
if (!WriteGeneric(pdb, Exes, *this))
|
|
return false;
|
|
EndWriteListTag(pdb, tidDatabase);
|
|
|
|
SdbCloseDatabaseWrite(pdb);
|
|
return true;
|
|
}
|
|
|
|
static void InsertTagid(const sdbstring& name, TAGID tagid, std::map<sdbstring, TAGID>& lookup, const char* type)
|
|
{
|
|
sdbstring nameLower = name;
|
|
std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower);
|
|
if (lookup.find(nameLower) != lookup.end())
|
|
{
|
|
std::string nameA(name.begin(), name.end());
|
|
SHIM_WARN("%s '%s' redefined\n", type, nameA.c_str());
|
|
return;
|
|
}
|
|
lookup[nameLower] = tagid;
|
|
}
|
|
|
|
static TAGID FindTagid(const sdbstring& name, const std::map<sdbstring, TAGID>& lookup)
|
|
{
|
|
sdbstring nameLower = name;
|
|
std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower);
|
|
std::map<sdbstring, TAGID>::const_iterator it = lookup.find(nameLower);
|
|
if (it == lookup.end())
|
|
return 0;
|
|
return it->second;
|
|
}
|
|
|
|
void Database::InsertShimTagid(const sdbstring& name, TAGID tagid)
|
|
{
|
|
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);
|
|
}
|
|
|
|
void Database::InsertFlagTagid(const sdbstring& name, TAGID tagid)
|
|
{
|
|
InsertTagid(name, tagid, KnownFlags, "Flag");
|
|
}
|
|
|
|
TAGID Database::FindFlagTagid(const sdbstring& name)
|
|
{
|
|
return FindTagid(name, KnownFlags);
|
|
}
|
|
|
|
|
|
bool xml_2_db(const char* xml, const WCHAR* sdb)
|
|
{
|
|
Database db;
|
|
if (db.fromXml(xml))
|
|
{
|
|
return db.toSdb((LPCWSTR)sdb);
|
|
}
|
|
return false;
|
|
}
|