xref: /reactos/sdk/tools/xml2sdb/xml2sdb.cpp (revision 3551953c)
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 
IsEmptyGuid(const GUID & g)46 bool IsEmptyGuid(const GUID& g)
47 {
48     return !memcmp(&g, &GUID_NULL, sizeof(GUID));
49 }
50 
RandomGuid(GUID & g)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)
ToString(XMLHandle node)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)
ToNodeName(XMLHandle node)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
ReadStringNode(XMLHandle dbNode,const char * nodeName)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 
ReadQWordNode(XMLHandle dbNode,const char * nodeName)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 
ReadDWordNode(XMLHandle dbNode,const char * nodeName)103 DWORD ReadDWordNode(XMLHandle dbNode, const char* nodeName)
104 {
105     return static_cast<DWORD>(ReadQWordNode(dbNode, nodeName));
106 }
107 
char2byte(char hexChar,bool * success=NULL)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
StringToGuid(const std::string & str,GUID & guid)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 
ReadGuidNode(XMLHandle dbNode,const char * nodeName,GUID & guid)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 
ReadBinaryNode(XMLHandle dbNode,const char * nodeName,std::vector<BYTE> & data)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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>
ReadGeneric(XMLHandle dbNode,std::list<T> & result,const char * nodeName)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>
WriteGeneric(PDB pdb,std::list<T> & data,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)323 bool FlagRef::fromXml(XMLHandle dbNode)
324 {
325     Name = ReadStringNode(dbNode, "NAME");
326     return !Name.empty();
327 }
328 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
fromXml(XMLHandle dbNode)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 
toSdb(PDB pdb,Database & db)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 
WriteBinary(PDB pdb,TAG tag,const GUID & guid,bool always)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 
WriteBinary(PDB pdb,TAG tag,const std::vector<BYTE> & data,bool always)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 
WriteString(PDB pdb,TAG tag,const sdbstring & str,bool always)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 
WriteString(PDB pdb,TAG tag,const std::string & str,bool always)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 
WriteDWord(PDB pdb,TAG tag,DWORD value,bool always)612 void Database::WriteDWord(PDB pdb, TAG tag, DWORD value, bool always)
613 {
614     if (always || value)
615         SdbWriteDWORDTag(pdb, tag, value);
616 }
617 
WriteQWord(PDB pdb,TAG tag,QWORD value,bool always)618 void Database::WriteQWord(PDB pdb, TAG tag, QWORD value, bool always)
619 {
620     if (always || value)
621         SdbWriteQWORDTag(pdb, tag, value);
622 }
623 
BeginWriteListTag(PDB pdb,TAG tag)624 TAGID Database::BeginWriteListTag(PDB pdb, TAG tag)
625 {
626     return SdbBeginWriteListTag(pdb, tag);
627 }
628 
EndWriteListTag(PDB pdb,TAGID tagid)629 BOOL Database::EndWriteListTag(PDB pdb, TAGID tagid)
630 {
631     return SdbEndWriteListTag(pdb, tagid);
632 }
633 
fromXml(XMLHandle dbNode)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 
fromXml(const char * fileName)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 
toSdb(LPCWSTR path)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 
InsertTagid(const sdbstring & name,TAGID tagid,std::map<sdbstring,TAGID> & lookup,const char * type)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 
FindTagid(const sdbstring & name,const std::map<sdbstring,TAGID> & lookup)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 
InsertShimTagid(const sdbstring & name,TAGID tagid)734 void Database::InsertShimTagid(const sdbstring& name, TAGID tagid)
735 {
736     InsertTagid(name, tagid, KnownShims, "Shim");
737 }
738 
FindShimTagid(const sdbstring & name)739 TAGID Database::FindShimTagid(const sdbstring& name)
740 {
741     return FindTagid(name, KnownShims);
742 }
743 
InsertPatchTagid(const sdbstring & name,TAGID tagid)744 void Database::InsertPatchTagid(const sdbstring& name, TAGID tagid)
745 {
746     InsertTagid(name, tagid, KnownPatches, "Patch");
747 }
748 
FindPatchTagid(const sdbstring & name)749 TAGID Database::FindPatchTagid(const sdbstring& name)
750 {
751     return FindTagid(name, KnownPatches);
752 }
753 
InsertFlagTagid(const sdbstring & name,TAGID tagid)754 void Database::InsertFlagTagid(const sdbstring& name, TAGID tagid)
755 {
756     InsertTagid(name, tagid, KnownFlags, "Flag");
757 }
758 
FindFlagTagid(const sdbstring & name)759 TAGID Database::FindFlagTagid(const sdbstring& name)
760 {
761     return FindTagid(name, KnownFlags);
762 }
763 
764 
xml_2_db(const char * xml,const WCHAR * sdb)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