10b57cec5SDimitry Andric //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===---------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file implements the .manifest merger class. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===---------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/WindowsManifest/WindowsManifestMerger.h" 140b57cec5SDimitry Andric #include "llvm/Config/config.h" 150b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 160b57cec5SDimitry Andric 170b57cec5SDimitry Andric #include <map> 180b57cec5SDimitry Andric 19*e8d8bef9SDimitry Andric #if LLVM_ENABLE_LIBXML2 200b57cec5SDimitry Andric #include <libxml/xmlreader.h> 210b57cec5SDimitry Andric #endif 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X) 240b57cec5SDimitry Andric #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X) 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace llvm; 270b57cec5SDimitry Andric using namespace windows_manifest; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric char WindowsManifestError::ID = 0; 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric class WindowsManifestMerger::WindowsManifestMergerImpl { 360b57cec5SDimitry Andric public: 370b57cec5SDimitry Andric ~WindowsManifestMergerImpl(); 380b57cec5SDimitry Andric Error merge(const MemoryBuffer &Manifest); 390b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> getMergedManifest(); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric private: 420b57cec5SDimitry Andric static void errorCallback(void *Ctx, const char *Format, ...); 430b57cec5SDimitry Andric Error getParseError(); 44*e8d8bef9SDimitry Andric #if LLVM_ENABLE_LIBXML2 450b57cec5SDimitry Andric xmlDocPtr CombinedDoc = nullptr; 460b57cec5SDimitry Andric std::vector<xmlDocPtr> MergedDocs; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric bool Merged = false; 490b57cec5SDimitry Andric struct XmlDeleter { 500b57cec5SDimitry Andric void operator()(xmlChar *Ptr) { xmlFree(Ptr); } 510b57cec5SDimitry Andric void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); } 520b57cec5SDimitry Andric }; 530b57cec5SDimitry Andric int BufferSize = 0; 540b57cec5SDimitry Andric std::unique_ptr<xmlChar, XmlDeleter> Buffer; 550b57cec5SDimitry Andric #endif 560b57cec5SDimitry Andric bool ParseErrorOccurred = false; 570b57cec5SDimitry Andric }; 580b57cec5SDimitry Andric 59*e8d8bef9SDimitry Andric #if LLVM_ENABLE_LIBXML2 600b57cec5SDimitry Andric 618bcb0991SDimitry Andric static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = { 620b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"}, 630b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"}, 640b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"}, 650b57cec5SDimitry Andric {"http://schemas.microsoft.com/SMI/2005/WindowsSettings", 660b57cec5SDimitry Andric "ms_windowsSettings"}, 670b57cec5SDimitry Andric {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}}; 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) { 700b57cec5SDimitry Andric // Handle null pointers. Comparison of 2 null pointers returns true because 710b57cec5SDimitry Andric // this indicates the prefix of a default namespace. 720b57cec5SDimitry Andric if (!A || !B) 730b57cec5SDimitry Andric return A == B; 740b57cec5SDimitry Andric return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0; 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric static bool isMergeableElement(const unsigned char *ElementName) { 780b57cec5SDimitry Andric for (StringRef S : {"application", "assembly", "assemblyIdentity", 790b57cec5SDimitry Andric "compatibility", "noInherit", "requestedExecutionLevel", 800b57cec5SDimitry Andric "requestedPrivileges", "security", "trustInfo"}) { 810b57cec5SDimitry Andric if (S == FROM_XML_CHAR(ElementName)) { 820b57cec5SDimitry Andric return true; 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric return false; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric static xmlNodePtr getChildWithName(xmlNodePtr Parent, 890b57cec5SDimitry Andric const unsigned char *ElementName) { 900b57cec5SDimitry Andric for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) { 910b57cec5SDimitry Andric if (xmlStringsEqual(Child->name, ElementName)) { 920b57cec5SDimitry Andric return Child; 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric return nullptr; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric static xmlAttrPtr getAttribute(xmlNodePtr Node, 990b57cec5SDimitry Andric const unsigned char *AttributeName) { 1000b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr; 1010b57cec5SDimitry Andric Attribute = Attribute->next) { 1020b57cec5SDimitry Andric if (xmlStringsEqual(Attribute->name, AttributeName)) { 1030b57cec5SDimitry Andric return Attribute; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric } 1060b57cec5SDimitry Andric return nullptr; 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric 1090b57cec5SDimitry Andric // Check if namespace specified by HRef1 overrides that of HRef2. 1100b57cec5SDimitry Andric static bool namespaceOverrides(const unsigned char *HRef1, 1110b57cec5SDimitry Andric const unsigned char *HRef2) { 1120b57cec5SDimitry Andric auto HRef1Position = llvm::find_if( 1130b57cec5SDimitry Andric MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) { 1140b57cec5SDimitry Andric return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data())); 1150b57cec5SDimitry Andric }); 1160b57cec5SDimitry Andric auto HRef2Position = llvm::find_if( 1170b57cec5SDimitry Andric MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) { 1180b57cec5SDimitry Andric return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data())); 1190b57cec5SDimitry Andric }); 1200b57cec5SDimitry Andric return HRef1Position < HRef2Position; 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Search for prefix-defined namespace specified by HRef, starting on Node and 1240b57cec5SDimitry Andric // continuing recursively upwards. Returns the namespace or nullptr if not 1250b57cec5SDimitry Andric // found. 1260b57cec5SDimitry Andric static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) { 1270b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 1280b57cec5SDimitry Andric if (Def->prefix && xmlStringsEqual(Def->href, HRef)) { 1290b57cec5SDimitry Andric return Def; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric if (Node->parent) { 1330b57cec5SDimitry Andric return search(HRef, Node->parent); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric return nullptr; 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // Return the prefix that corresponds to the HRef. If HRef is not a recognized 1390b57cec5SDimitry Andric // URI, then just return the HRef itself to use as the prefix. 1400b57cec5SDimitry Andric static const unsigned char *getPrefixForHref(const unsigned char *HRef) { 1410b57cec5SDimitry Andric for (auto &Ns : MtNsHrefsPrefixes) { 1420b57cec5SDimitry Andric if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) { 1430b57cec5SDimitry Andric return TO_XML_CHAR(Ns.second.data()); 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric return HRef; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Search for prefix-defined namespace specified by HRef, starting on Node and 1500b57cec5SDimitry Andric // continuing recursively upwards. If it is found, then return it. If it is 1510b57cec5SDimitry Andric // not found, then prefix-define that namespace on the node and return a 1520b57cec5SDimitry Andric // reference to it. 1530b57cec5SDimitry Andric static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef, 1540b57cec5SDimitry Andric xmlNodePtr Node) { 1550b57cec5SDimitry Andric if (xmlNsPtr Def = search(HRef, Node)) 1560b57cec5SDimitry Andric return Def; 1570b57cec5SDimitry Andric if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef))) 1580b57cec5SDimitry Andric return Def; 1590b57cec5SDimitry Andric return make_error<WindowsManifestError>("failed to create new namespace"); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric // Set the namespace of OrigionalAttribute on OriginalNode to be that of 1630b57cec5SDimitry Andric // AdditionalAttribute's. 1640b57cec5SDimitry Andric static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute, 1650b57cec5SDimitry Andric xmlNodePtr OriginalNode, 1660b57cec5SDimitry Andric xmlAttrPtr AdditionalAttribute) { 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = 1690b57cec5SDimitry Andric searchOrDefine(AdditionalAttribute->ns->href, OriginalNode); 1700b57cec5SDimitry Andric if (!ExplicitOrError) 1710b57cec5SDimitry Andric return ExplicitOrError.takeError(); 1720b57cec5SDimitry Andric OriginalAttribute->ns = std::move(ExplicitOrError.get()); 1730b57cec5SDimitry Andric return Error::success(); 1740b57cec5SDimitry Andric } 1750b57cec5SDimitry Andric 1760b57cec5SDimitry Andric // Return the corresponding namespace definition for the prefix, defined on the 1770b57cec5SDimitry Andric // given Node. Returns nullptr if there is no such definition. 1780b57cec5SDimitry Andric static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix, 1790b57cec5SDimitry Andric xmlNodePtr Node) { 1800b57cec5SDimitry Andric if (Node == nullptr) 1810b57cec5SDimitry Andric return nullptr; 1820b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 1830b57cec5SDimitry Andric if (xmlStringsEqual(Def->prefix, Prefix)) { 1840b57cec5SDimitry Andric return Def; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric } 1870b57cec5SDimitry Andric return nullptr; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric // Search for the closest inheritable default namespace, starting on (and 1910b57cec5SDimitry Andric // including) the Node and traveling upwards through parent nodes. Returns 1920b57cec5SDimitry Andric // nullptr if there are no inheritable default namespaces. 1930b57cec5SDimitry Andric static xmlNsPtr getClosestDefault(xmlNodePtr Node) { 1940b57cec5SDimitry Andric if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node)) 1950b57cec5SDimitry Andric return Ret; 1960b57cec5SDimitry Andric if (Node->parent == nullptr) 1970b57cec5SDimitry Andric return nullptr; 1980b57cec5SDimitry Andric return getClosestDefault(Node->parent); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric // Merge the attributes of AdditionalNode into OriginalNode. If attributes 2020b57cec5SDimitry Andric // with identical types are present, they are not duplicated but rather if 2030b57cec5SDimitry Andric // their values are not consistent and error is thrown. In addition, the 2040b57cec5SDimitry Andric // higher priority namespace is used for each attribute, EXCEPT in the case 2050b57cec5SDimitry Andric // of merging two default namespaces and the lower priority namespace 2060b57cec5SDimitry Andric // definition occurs closer than the higher priority one. 2070b57cec5SDimitry Andric static Error mergeAttributes(xmlNodePtr OriginalNode, 2080b57cec5SDimitry Andric xmlNodePtr AdditionalNode) { 2090b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode); 2100b57cec5SDimitry Andric for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute; 2110b57cec5SDimitry Andric Attribute = Attribute->next) { 2120b57cec5SDimitry Andric if (xmlAttrPtr OriginalAttribute = 2130b57cec5SDimitry Andric getAttribute(OriginalNode, Attribute->name)) { 2140b57cec5SDimitry Andric if (!xmlStringsEqual(OriginalAttribute->children->content, 2150b57cec5SDimitry Andric Attribute->children->content)) { 2160b57cec5SDimitry Andric return make_error<WindowsManifestError>( 2170b57cec5SDimitry Andric Twine("conflicting attributes for ") + 2180b57cec5SDimitry Andric FROM_XML_CHAR(OriginalNode->name)); 2190b57cec5SDimitry Andric } 2200b57cec5SDimitry Andric if (!Attribute->ns) { 2210b57cec5SDimitry Andric continue; 2220b57cec5SDimitry Andric } 2230b57cec5SDimitry Andric if (!OriginalAttribute->ns) { 2240b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 2250b57cec5SDimitry Andric Attribute)) { 2260b57cec5SDimitry Andric return E; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric continue; 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric if (namespaceOverrides(OriginalAttribute->ns->href, 2310b57cec5SDimitry Andric Attribute->ns->href)) { 2320b57cec5SDimitry Andric // In this case, the original attribute has a higher priority namespace 2330b57cec5SDimitry Andric // than the incomiing attribute, however the namespace definition of 2340b57cec5SDimitry Andric // the lower priority namespace occurs first traveling upwards in the 2350b57cec5SDimitry Andric // tree. Therefore the lower priority namespace is applied. 2360b57cec5SDimitry Andric if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix && 2370b57cec5SDimitry Andric ClosestDefault && 2380b57cec5SDimitry Andric xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) { 2390b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 2400b57cec5SDimitry Andric Attribute)) { 2410b57cec5SDimitry Andric return E; 2420b57cec5SDimitry Andric } 2430b57cec5SDimitry Andric continue; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric continue; 2460b57cec5SDimitry Andric // This covers the case where the incoming attribute has the higher 2470b57cec5SDimitry Andric // priority. The higher priority namespace is applied in all cases 2480b57cec5SDimitry Andric // EXCEPT when both of the namespaces are default inherited, and the 2490b57cec5SDimitry Andric // closest inherited default is the lower priority one. 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric if (Attribute->ns->prefix || OriginalAttribute->ns->prefix || 2520b57cec5SDimitry Andric (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href, 2530b57cec5SDimitry Andric ClosestDefault->href))) { 2540b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 2550b57cec5SDimitry Andric Attribute)) { 2560b57cec5SDimitry Andric return E; 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric continue; 2590b57cec5SDimitry Andric } 2600b57cec5SDimitry Andric continue; 2610b57cec5SDimitry Andric } 2620b57cec5SDimitry Andric // If the incoming attribute is not already found on the node, append it 2630b57cec5SDimitry Andric // to the end of the properties list. Also explicitly apply its 2640b57cec5SDimitry Andric // namespace as a prefix because it might be contained in a separate 2650b57cec5SDimitry Andric // namespace that doesn't use the attribute. 2660b57cec5SDimitry Andric xmlAttrPtr NewProp = 2670b57cec5SDimitry Andric xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content); 2680b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = 2690b57cec5SDimitry Andric searchOrDefine(Attribute->ns->href, OriginalNode); 2700b57cec5SDimitry Andric if (!ExplicitOrError) 2710b57cec5SDimitry Andric return ExplicitOrError.takeError(); 2720b57cec5SDimitry Andric NewProp->ns = std::move(ExplicitOrError.get()); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric return Error::success(); 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric // Given two nodes, return the one with the higher priority namespace. 2780b57cec5SDimitry Andric static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) { 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric if (!Node1 || !Node1->ns) 2810b57cec5SDimitry Andric return Node2; 2820b57cec5SDimitry Andric if (!Node2 || !Node2->ns) 2830b57cec5SDimitry Andric return Node1; 2840b57cec5SDimitry Andric if (namespaceOverrides(Node1->ns->href, Node2->ns->href)) 2850b57cec5SDimitry Andric return Node1; 2860b57cec5SDimitry Andric return Node2; 2870b57cec5SDimitry Andric } 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric // Checks if this Node's namespace is inherited or one it defined itself. 2900b57cec5SDimitry Andric static bool hasInheritedNs(xmlNodePtr Node) { 2910b57cec5SDimitry Andric return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node); 2920b57cec5SDimitry Andric } 2930b57cec5SDimitry Andric 2940b57cec5SDimitry Andric // Check if this Node's namespace is a default namespace that it inherited, as 2950b57cec5SDimitry Andric // opposed to defining itself. 2960b57cec5SDimitry Andric static bool hasInheritedDefaultNs(xmlNodePtr Node) { 2970b57cec5SDimitry Andric return hasInheritedNs(Node) && Node->ns->prefix == nullptr; 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // Check if this Node's namespace is a default namespace it defined itself. 3010b57cec5SDimitry Andric static bool hasDefinedDefaultNamespace(xmlNodePtr Node) { 3020b57cec5SDimitry Andric return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node)); 3030b57cec5SDimitry Andric } 3040b57cec5SDimitry Andric 3050b57cec5SDimitry Andric // For the given explicit prefix-definition of a namespace, travel downwards 3060b57cec5SDimitry Andric // from a node recursively, and for every implicit, inherited default usage of 3070b57cec5SDimitry Andric // that namespace replace it with that explicit prefix use. This is important 3080b57cec5SDimitry Andric // when namespace overriding occurs when merging, so that elements unique to a 3090b57cec5SDimitry Andric // namespace will still stay in that namespace. 3100b57cec5SDimitry Andric static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) { 3110b57cec5SDimitry Andric // If a node as its own default namespace definition it clearly cannot have 3120b57cec5SDimitry Andric // inherited the given default namespace, and neither will any of its 3130b57cec5SDimitry Andric // children. 3140b57cec5SDimitry Andric if (hasDefinedDefaultNamespace(Node)) 3150b57cec5SDimitry Andric return; 3160b57cec5SDimitry Andric if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) && 3170b57cec5SDimitry Andric hasInheritedDefaultNs(Node)) 3180b57cec5SDimitry Andric Node->ns = PrefixDef; 3190b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 3200b57cec5SDimitry Andric Attribute = Attribute->next) { 3210b57cec5SDimitry Andric if (Attribute->ns && 3220b57cec5SDimitry Andric xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) { 3230b57cec5SDimitry Andric Attribute->ns = PrefixDef; 3240b57cec5SDimitry Andric } 3250b57cec5SDimitry Andric } 3260b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 3270b57cec5SDimitry Andric explicateNamespace(PrefixDef, Child); 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric } 3300b57cec5SDimitry Andric 3310b57cec5SDimitry Andric // Perform the namespace merge between two nodes. 3320b57cec5SDimitry Andric static Error mergeNamespaces(xmlNodePtr OriginalNode, 3330b57cec5SDimitry Andric xmlNodePtr AdditionalNode) { 3340b57cec5SDimitry Andric // Save the original default namespace definition in case the incoming node 3350b57cec5SDimitry Andric // overrides it. 3360b57cec5SDimitry Andric const unsigned char *OriginalDefinedDefaultHref = nullptr; 3370b57cec5SDimitry Andric if (xmlNsPtr OriginalDefinedDefaultNs = 3380b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, OriginalNode)) { 3390b57cec5SDimitry Andric OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href); 3400b57cec5SDimitry Andric } 3410b57cec5SDimitry Andric const unsigned char *NewDefinedDefaultHref = nullptr; 3420b57cec5SDimitry Andric // Copy all namespace definitions. There can only be one default namespace 3430b57cec5SDimitry Andric // definition per node, so the higher priority one takes precedence in the 3440b57cec5SDimitry Andric // case of collision. 3450b57cec5SDimitry Andric for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) { 3460b57cec5SDimitry Andric if (xmlNsPtr OriginalNsDef = 3470b57cec5SDimitry Andric getNamespaceWithPrefix(Def->prefix, OriginalNode)) { 3480b57cec5SDimitry Andric if (!Def->prefix) { 3490b57cec5SDimitry Andric if (namespaceOverrides(Def->href, OriginalNsDef->href)) { 3500b57cec5SDimitry Andric NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href))); 3510b57cec5SDimitry Andric } 3520b57cec5SDimitry Andric } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) { 3530b57cec5SDimitry Andric return make_error<WindowsManifestError>( 3540b57cec5SDimitry Andric Twine("conflicting namespace definitions for ") + 3550b57cec5SDimitry Andric FROM_XML_CHAR(Def->prefix)); 3560b57cec5SDimitry Andric } 3570b57cec5SDimitry Andric } else { 3580b57cec5SDimitry Andric xmlNsPtr NewDef = xmlCopyNamespace(Def); 3590b57cec5SDimitry Andric NewDef->next = OriginalNode->nsDef; 3600b57cec5SDimitry Andric OriginalNode->nsDef = NewDef; 3610b57cec5SDimitry Andric } 3620b57cec5SDimitry Andric } 3630b57cec5SDimitry Andric 3640b57cec5SDimitry Andric // Check whether the original node or the incoming node has the higher 3650b57cec5SDimitry Andric // priority namespace. Depending on which one is dominant, we will have 3660b57cec5SDimitry Andric // to recursively apply namespace changes down to children of the original 3670b57cec5SDimitry Andric // node. 3680b57cec5SDimitry Andric xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode); 3690b57cec5SDimitry Andric xmlNodePtr NonDominantNode = 3700b57cec5SDimitry Andric DominantNode == OriginalNode ? AdditionalNode : OriginalNode; 3710b57cec5SDimitry Andric if (DominantNode == OriginalNode) { 3720b57cec5SDimitry Andric if (OriginalDefinedDefaultHref) { 3730b57cec5SDimitry Andric xmlNsPtr NonDominantDefinedDefault = 3740b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, NonDominantNode); 3750b57cec5SDimitry Andric // In this case, both the nodes defined a default namespace. However 3760b57cec5SDimitry Andric // the lower priority node ended up having a higher priority default 3770b57cec5SDimitry Andric // definition. This can occur if the higher priority node is prefix 3780b57cec5SDimitry Andric // namespace defined. In this case we have to define an explicit 3790b57cec5SDimitry Andric // prefix for the overridden definition and apply it to all children 3800b57cec5SDimitry Andric // who relied on that definition. 3810b57cec5SDimitry Andric if (NonDominantDefinedDefault && 3820b57cec5SDimitry Andric namespaceOverrides(NonDominantDefinedDefault->href, 3830b57cec5SDimitry Andric OriginalDefinedDefaultHref)) { 3840b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 3850b57cec5SDimitry Andric searchOrDefine(OriginalDefinedDefaultHref, DominantNode); 3860b57cec5SDimitry Andric if (!EC) { 3870b57cec5SDimitry Andric return EC.takeError(); 3880b57cec5SDimitry Andric } 3890b57cec5SDimitry Andric xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get()); 3900b57cec5SDimitry Andric explicateNamespace(PrefixDominantDefinedDefault, DominantNode); 3910b57cec5SDimitry Andric } 3920b57cec5SDimitry Andric // In this case the node with a higher priority namespace did not have a 3930b57cec5SDimitry Andric // default namespace definition, but the lower priority node did. In this 3940b57cec5SDimitry Andric // case the new default namespace definition is copied. A side effect of 3950b57cec5SDimitry Andric // this is that all children will suddenly find themselves in a different 3960b57cec5SDimitry Andric // default namespace. To maintain correctness we need to ensure that all 3970b57cec5SDimitry Andric // children now explicitly refer to the namespace that they had previously 3980b57cec5SDimitry Andric // implicitly inherited. 3990b57cec5SDimitry Andric } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) { 4000b57cec5SDimitry Andric if (DominantNode->parent) { 4010b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent); 4020b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 4030b57cec5SDimitry Andric searchOrDefine(ClosestDefault->href, DominantNode); 4040b57cec5SDimitry Andric if (!EC) { 4050b57cec5SDimitry Andric return EC.takeError(); 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 4080b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, DominantNode); 4090b57cec5SDimitry Andric } 4100b57cec5SDimitry Andric } 4110b57cec5SDimitry Andric } else { 4120b57cec5SDimitry Andric // Covers case where the incoming node has a default namespace definition 4130b57cec5SDimitry Andric // that overrides the original node's namespace. This always leads to 4140b57cec5SDimitry Andric // the original node receiving that new default namespace. 4150b57cec5SDimitry Andric if (hasDefinedDefaultNamespace(DominantNode)) { 4160b57cec5SDimitry Andric NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode); 4170b57cec5SDimitry Andric } else { 4180b57cec5SDimitry Andric // This covers the case where the incoming node either has a prefix 4190b57cec5SDimitry Andric // namespace, or an inherited default namespace. Since the namespace 4200b57cec5SDimitry Andric // may not yet be defined in the original tree we do a searchOrDefine 4210b57cec5SDimitry Andric // for it, and then set the namespace equal to it. 4220b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 4230b57cec5SDimitry Andric searchOrDefine(DominantNode->ns->href, NonDominantNode); 4240b57cec5SDimitry Andric if (!EC) { 4250b57cec5SDimitry Andric return EC.takeError(); 4260b57cec5SDimitry Andric } 4270b57cec5SDimitry Andric xmlNsPtr Explicit = std::move(EC.get()); 4280b57cec5SDimitry Andric NonDominantNode->ns = Explicit; 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric // This covers cases where the incoming dominant node HAS a default 4310b57cec5SDimitry Andric // namespace definition, but MIGHT NOT NECESSARILY be in that namespace. 4320b57cec5SDimitry Andric if (xmlNsPtr DominantDefaultDefined = 4330b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, DominantNode)) { 4340b57cec5SDimitry Andric if (OriginalDefinedDefaultHref) { 4350b57cec5SDimitry Andric if (namespaceOverrides(DominantDefaultDefined->href, 4360b57cec5SDimitry Andric OriginalDefinedDefaultHref)) { 4370b57cec5SDimitry Andric // In this case, the incoming node's default definition overrides 4380b57cec5SDimitry Andric // the original default definition, all children who relied on that 4390b57cec5SDimitry Andric // definition must be updated accordingly. 4400b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 4410b57cec5SDimitry Andric searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode); 4420b57cec5SDimitry Andric if (!EC) { 4430b57cec5SDimitry Andric return EC.takeError(); 4440b57cec5SDimitry Andric } 4450b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 4460b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, NonDominantNode); 4470b57cec5SDimitry Andric } 4480b57cec5SDimitry Andric } else { 4490b57cec5SDimitry Andric // The original did not define a default definition, however the new 4500b57cec5SDimitry Andric // default definition still applies to all children, so they must be 4510b57cec5SDimitry Andric // updated to explicitly refer to the namespace they had previously 4520b57cec5SDimitry Andric // been inheriting implicitly. 4530b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode); 4540b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 4550b57cec5SDimitry Andric searchOrDefine(ClosestDefault->href, NonDominantNode); 4560b57cec5SDimitry Andric if (!EC) { 4570b57cec5SDimitry Andric return EC.takeError(); 4580b57cec5SDimitry Andric } 4590b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 4600b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, NonDominantNode); 4610b57cec5SDimitry Andric } 4620b57cec5SDimitry Andric } 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric if (NewDefinedDefaultHref) { 4650b57cec5SDimitry Andric xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode); 4660b57cec5SDimitry Andric xmlFree(const_cast<unsigned char *>(OriginalNsDef->href)); 4670b57cec5SDimitry Andric OriginalNsDef->href = NewDefinedDefaultHref; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref)); 4700b57cec5SDimitry Andric return Error::success(); 4710b57cec5SDimitry Andric } 4720b57cec5SDimitry Andric 4730b57cec5SDimitry Andric static bool isRecognizedNamespace(const unsigned char *NsHref) { 4740b57cec5SDimitry Andric for (auto &Ns : MtNsHrefsPrefixes) { 4750b57cec5SDimitry Andric if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) { 4760b57cec5SDimitry Andric return true; 4770b57cec5SDimitry Andric } 4780b57cec5SDimitry Andric } 4790b57cec5SDimitry Andric return false; 4800b57cec5SDimitry Andric } 4810b57cec5SDimitry Andric 4820b57cec5SDimitry Andric static bool hasRecognizedNamespace(xmlNodePtr Node) { 4830b57cec5SDimitry Andric return isRecognizedNamespace(Node->ns->href); 4840b57cec5SDimitry Andric } 4850b57cec5SDimitry Andric 4860b57cec5SDimitry Andric // Ensure a node's inherited namespace is actually defined in the tree it 4870b57cec5SDimitry Andric // resides in. 4880b57cec5SDimitry Andric static Error reconcileNamespaces(xmlNodePtr Node) { 4890b57cec5SDimitry Andric if (!Node) { 4900b57cec5SDimitry Andric return Error::success(); 4910b57cec5SDimitry Andric } 4920b57cec5SDimitry Andric if (hasInheritedNs(Node)) { 4930b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node); 4940b57cec5SDimitry Andric if (!ExplicitOrError) { 4950b57cec5SDimitry Andric return ExplicitOrError.takeError(); 4960b57cec5SDimitry Andric } 4970b57cec5SDimitry Andric xmlNsPtr Explicit = std::move(ExplicitOrError.get()); 4980b57cec5SDimitry Andric Node->ns = Explicit; 4990b57cec5SDimitry Andric } 5000b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 5010b57cec5SDimitry Andric if (auto E = reconcileNamespaces(Child)) { 5020b57cec5SDimitry Andric return E; 5030b57cec5SDimitry Andric } 5040b57cec5SDimitry Andric } 5050b57cec5SDimitry Andric return Error::success(); 5060b57cec5SDimitry Andric } 5070b57cec5SDimitry Andric 5080b57cec5SDimitry Andric // Recursively merge the two given manifest trees, depending on which elements 5090b57cec5SDimitry Andric // are of a mergeable type, and choose namespaces according to which have 5100b57cec5SDimitry Andric // higher priority. 5110b57cec5SDimitry Andric static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) { 5120b57cec5SDimitry Andric if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) 5130b57cec5SDimitry Andric return E; 5140b57cec5SDimitry Andric if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot)) 5150b57cec5SDimitry Andric return E; 5160b57cec5SDimitry Andric xmlNodePtr AdditionalFirstChild = AdditionalRoot->children; 5170b57cec5SDimitry Andric xmlNode StoreNext; 5180b57cec5SDimitry Andric for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) { 5190b57cec5SDimitry Andric xmlNodePtr OriginalChildWithName; 5200b57cec5SDimitry Andric if (!isMergeableElement(Child->name) || 5210b57cec5SDimitry Andric !(OriginalChildWithName = 5220b57cec5SDimitry Andric getChildWithName(OriginalRoot, Child->name)) || 5230b57cec5SDimitry Andric !hasRecognizedNamespace(Child)) { 5240b57cec5SDimitry Andric StoreNext.next = Child->next; 5250b57cec5SDimitry Andric xmlUnlinkNode(Child); 5260b57cec5SDimitry Andric if (!xmlAddChild(OriginalRoot, Child)) { 5270b57cec5SDimitry Andric return make_error<WindowsManifestError>(Twine("could not merge ") + 5280b57cec5SDimitry Andric FROM_XML_CHAR(Child->name)); 5290b57cec5SDimitry Andric } 5300b57cec5SDimitry Andric if (auto E = reconcileNamespaces(Child)) { 5310b57cec5SDimitry Andric return E; 5320b57cec5SDimitry Andric } 5330b57cec5SDimitry Andric Child = &StoreNext; 5340b57cec5SDimitry Andric } else if (auto E = treeMerge(OriginalChildWithName, Child)) { 5350b57cec5SDimitry Andric return E; 5360b57cec5SDimitry Andric } 5370b57cec5SDimitry Andric } 5380b57cec5SDimitry Andric return Error::success(); 5390b57cec5SDimitry Andric } 5400b57cec5SDimitry Andric 5410b57cec5SDimitry Andric static void stripComments(xmlNodePtr Root) { 5420b57cec5SDimitry Andric xmlNode StoreNext; 5430b57cec5SDimitry Andric for (xmlNodePtr Child = Root->children; Child; Child = Child->next) { 5440b57cec5SDimitry Andric if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) { 5450b57cec5SDimitry Andric stripComments(Child); 5460b57cec5SDimitry Andric continue; 5470b57cec5SDimitry Andric } 5480b57cec5SDimitry Andric StoreNext.next = Child->next; 5490b57cec5SDimitry Andric xmlNodePtr Remove = Child; 5500b57cec5SDimitry Andric Child = &StoreNext; 5510b57cec5SDimitry Andric xmlUnlinkNode(Remove); 5520b57cec5SDimitry Andric xmlFreeNode(Remove); 5530b57cec5SDimitry Andric } 5540b57cec5SDimitry Andric } 5550b57cec5SDimitry Andric 5560b57cec5SDimitry Andric // libxml2 assumes that attributes do not inherit default namespaces, whereas 5570b57cec5SDimitry Andric // the original mt.exe does make this assumption. This function reconciles 5580b57cec5SDimitry Andric // this by setting all attributes to have the inherited default namespace. 5590b57cec5SDimitry Andric static void setAttributeNamespaces(xmlNodePtr Node) { 5600b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 5610b57cec5SDimitry Andric Attribute = Attribute->next) { 5620b57cec5SDimitry Andric if (!Attribute->ns) { 5630b57cec5SDimitry Andric Attribute->ns = getClosestDefault(Node); 5640b57cec5SDimitry Andric } 5650b57cec5SDimitry Andric } 5660b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 5670b57cec5SDimitry Andric setAttributeNamespaces(Child); 5680b57cec5SDimitry Andric } 5690b57cec5SDimitry Andric } 5700b57cec5SDimitry Andric 5710b57cec5SDimitry Andric // The merging process may create too many prefix defined namespaces. This 5720b57cec5SDimitry Andric // function removes all unnecessary ones from the tree. 5730b57cec5SDimitry Andric static void checkAndStripPrefixes(xmlNodePtr Node, 5740b57cec5SDimitry Andric std::vector<xmlNsPtr> &RequiredPrefixes) { 5750b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 5760b57cec5SDimitry Andric checkAndStripPrefixes(Child, RequiredPrefixes); 5770b57cec5SDimitry Andric } 5780b57cec5SDimitry Andric if (Node->ns && Node->ns->prefix != nullptr) { 5790b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(Node); 5800b57cec5SDimitry Andric if (ClosestDefault && 5810b57cec5SDimitry Andric xmlStringsEqual(ClosestDefault->href, Node->ns->href)) { 5820b57cec5SDimitry Andric Node->ns = ClosestDefault; 5830b57cec5SDimitry Andric } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) { 5840b57cec5SDimitry Andric RequiredPrefixes.push_back(Node->ns); 5850b57cec5SDimitry Andric } 5860b57cec5SDimitry Andric } 5870b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 5880b57cec5SDimitry Andric Attribute = Attribute->next) { 5890b57cec5SDimitry Andric if (Attribute->ns && Attribute->ns->prefix != nullptr) { 5900b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(Node); 5910b57cec5SDimitry Andric if (ClosestDefault && 5920b57cec5SDimitry Andric xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) { 5930b57cec5SDimitry Andric Attribute->ns = ClosestDefault; 5940b57cec5SDimitry Andric } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) { 5950b57cec5SDimitry Andric RequiredPrefixes.push_back(Attribute->ns); 5960b57cec5SDimitry Andric } 5970b57cec5SDimitry Andric } 5980b57cec5SDimitry Andric } 5990b57cec5SDimitry Andric xmlNsPtr Prev; 6000b57cec5SDimitry Andric xmlNs Temp; 6010b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 6020b57cec5SDimitry Andric if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) { 6030b57cec5SDimitry Andric Prev = Def; 6040b57cec5SDimitry Andric continue; 6050b57cec5SDimitry Andric } 6060b57cec5SDimitry Andric if (Def == Node->nsDef) { 6070b57cec5SDimitry Andric Node->nsDef = Def->next; 6080b57cec5SDimitry Andric } else { 6090b57cec5SDimitry Andric Prev->next = Def->next; 6100b57cec5SDimitry Andric } 6110b57cec5SDimitry Andric Temp.next = Def->next; 6120b57cec5SDimitry Andric xmlFreeNs(Def); 6130b57cec5SDimitry Andric Def = &Temp; 6140b57cec5SDimitry Andric } 6150b57cec5SDimitry Andric } 6160b57cec5SDimitry Andric 6170b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 6180b57cec5SDimitry Andric for (auto &Doc : MergedDocs) 6190b57cec5SDimitry Andric xmlFreeDoc(Doc); 6200b57cec5SDimitry Andric } 6210b57cec5SDimitry Andric 6220b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 6230b57cec5SDimitry Andric const MemoryBuffer &Manifest) { 6240b57cec5SDimitry Andric if (Merged) 6250b57cec5SDimitry Andric return make_error<WindowsManifestError>( 6260b57cec5SDimitry Andric "merge after getMergedManifest is not supported"); 6270b57cec5SDimitry Andric if (Manifest.getBufferSize() == 0) 6280b57cec5SDimitry Andric return make_error<WindowsManifestError>( 6290b57cec5SDimitry Andric "attempted to merge empty manifest"); 6300b57cec5SDimitry Andric xmlSetGenericErrorFunc((void *)this, 6310b57cec5SDimitry Andric WindowsManifestMergerImpl::errorCallback); 6320b57cec5SDimitry Andric xmlDocPtr ManifestXML = xmlReadMemory( 6330b57cec5SDimitry Andric Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml", 6340b57cec5SDimitry Andric nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT); 6350b57cec5SDimitry Andric xmlSetGenericErrorFunc(nullptr, nullptr); 6360b57cec5SDimitry Andric if (auto E = getParseError()) 6370b57cec5SDimitry Andric return E; 6380b57cec5SDimitry Andric xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML); 6390b57cec5SDimitry Andric stripComments(AdditionalRoot); 6400b57cec5SDimitry Andric setAttributeNamespaces(AdditionalRoot); 6410b57cec5SDimitry Andric if (CombinedDoc == nullptr) { 6420b57cec5SDimitry Andric CombinedDoc = ManifestXML; 6430b57cec5SDimitry Andric } else { 6440b57cec5SDimitry Andric xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc); 6450b57cec5SDimitry Andric if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) || 6460b57cec5SDimitry Andric !isMergeableElement(AdditionalRoot->name) || 6470b57cec5SDimitry Andric !hasRecognizedNamespace(AdditionalRoot)) { 6480b57cec5SDimitry Andric return make_error<WindowsManifestError>("multiple root nodes"); 6490b57cec5SDimitry Andric } 6500b57cec5SDimitry Andric if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) { 6510b57cec5SDimitry Andric return E; 6520b57cec5SDimitry Andric } 6530b57cec5SDimitry Andric } 6540b57cec5SDimitry Andric MergedDocs.push_back(ManifestXML); 6550b57cec5SDimitry Andric return Error::success(); 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric 6580b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 6590b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 6600b57cec5SDimitry Andric if (!Merged) { 6610b57cec5SDimitry Andric Merged = true; 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric if (!CombinedDoc) 6640b57cec5SDimitry Andric return nullptr; 6650b57cec5SDimitry Andric 6660b57cec5SDimitry Andric xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc); 6670b57cec5SDimitry Andric std::vector<xmlNsPtr> RequiredPrefixes; 6680b57cec5SDimitry Andric checkAndStripPrefixes(CombinedRoot, RequiredPrefixes); 6690b57cec5SDimitry Andric std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc( 6700b57cec5SDimitry Andric xmlNewDoc((const unsigned char *)"1.0")); 6710b57cec5SDimitry Andric xmlDocSetRootElement(OutputDoc.get(), CombinedRoot); 6720b57cec5SDimitry Andric assert(0 == xmlDocGetRootElement(CombinedDoc)); 6730b57cec5SDimitry Andric 6740b57cec5SDimitry Andric xmlKeepBlanksDefault(0); 6750b57cec5SDimitry Andric xmlChar *Buff = nullptr; 6760b57cec5SDimitry Andric xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1); 6770b57cec5SDimitry Andric Buffer.reset(Buff); 6780b57cec5SDimitry Andric } 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef( 6810b57cec5SDimitry Andric FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize)) 6820b57cec5SDimitry Andric : nullptr; 6830b57cec5SDimitry Andric } 6840b57cec5SDimitry Andric 6850b57cec5SDimitry Andric bool windows_manifest::isAvailable() { return true; } 6860b57cec5SDimitry Andric 6870b57cec5SDimitry Andric #else 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 6900b57cec5SDimitry Andric } 6910b57cec5SDimitry Andric 6920b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 6930b57cec5SDimitry Andric const MemoryBuffer &Manifest) { 6940b57cec5SDimitry Andric return make_error<WindowsManifestError>("no libxml2"); 6950b57cec5SDimitry Andric } 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 6980b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 6990b57cec5SDimitry Andric return nullptr; 7000b57cec5SDimitry Andric } 7010b57cec5SDimitry Andric 7020b57cec5SDimitry Andric bool windows_manifest::isAvailable() { return false; } 7030b57cec5SDimitry Andric 7040b57cec5SDimitry Andric #endif 7050b57cec5SDimitry Andric 7060b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMerger() 7078bcb0991SDimitry Andric : Impl(std::make_unique<WindowsManifestMergerImpl>()) {} 7080b57cec5SDimitry Andric 7090b57cec5SDimitry Andric WindowsManifestMerger::~WindowsManifestMerger() {} 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) { 7120b57cec5SDimitry Andric return Impl->merge(Manifest); 7130b57cec5SDimitry Andric } 7140b57cec5SDimitry Andric 7150b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() { 7160b57cec5SDimitry Andric return Impl->getMergedManifest(); 7170b57cec5SDimitry Andric } 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback( 7200b57cec5SDimitry Andric void *Ctx, const char *Format, ...) { 7210b57cec5SDimitry Andric auto *Merger = (WindowsManifestMergerImpl *)Ctx; 7220b57cec5SDimitry Andric Merger->ParseErrorOccurred = true; 7230b57cec5SDimitry Andric } 7240b57cec5SDimitry Andric 7250b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() { 7260b57cec5SDimitry Andric if (!ParseErrorOccurred) 7270b57cec5SDimitry Andric return Error::success(); 7280b57cec5SDimitry Andric return make_error<WindowsManifestError>("invalid xml document"); 7290b57cec5SDimitry Andric } 730