1*0b57cec5SDimitry Andric //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===---------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file implements the .manifest merger class. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===---------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "llvm/WindowsManifest/WindowsManifestMerger.h" 14*0b57cec5SDimitry Andric #include "llvm/Config/config.h" 15*0b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include <map> 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric #if LLVM_LIBXML2_ENABLED 20*0b57cec5SDimitry Andric #include <libxml/xmlreader.h> 21*0b57cec5SDimitry Andric #endif 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X) 24*0b57cec5SDimitry Andric #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X) 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric using namespace llvm; 27*0b57cec5SDimitry Andric using namespace windows_manifest; 28*0b57cec5SDimitry Andric 29*0b57cec5SDimitry Andric char WindowsManifestError::ID = 0; 30*0b57cec5SDimitry Andric 31*0b57cec5SDimitry Andric WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric class WindowsManifestMerger::WindowsManifestMergerImpl { 36*0b57cec5SDimitry Andric public: 37*0b57cec5SDimitry Andric ~WindowsManifestMergerImpl(); 38*0b57cec5SDimitry Andric Error merge(const MemoryBuffer &Manifest); 39*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> getMergedManifest(); 40*0b57cec5SDimitry Andric 41*0b57cec5SDimitry Andric private: 42*0b57cec5SDimitry Andric static void errorCallback(void *Ctx, const char *Format, ...); 43*0b57cec5SDimitry Andric Error getParseError(); 44*0b57cec5SDimitry Andric #if LLVM_LIBXML2_ENABLED 45*0b57cec5SDimitry Andric xmlDocPtr CombinedDoc = nullptr; 46*0b57cec5SDimitry Andric std::vector<xmlDocPtr> MergedDocs; 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric bool Merged = false; 49*0b57cec5SDimitry Andric struct XmlDeleter { 50*0b57cec5SDimitry Andric void operator()(xmlChar *Ptr) { xmlFree(Ptr); } 51*0b57cec5SDimitry Andric void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); } 52*0b57cec5SDimitry Andric }; 53*0b57cec5SDimitry Andric int BufferSize = 0; 54*0b57cec5SDimitry Andric std::unique_ptr<xmlChar, XmlDeleter> Buffer; 55*0b57cec5SDimitry Andric #endif 56*0b57cec5SDimitry Andric bool ParseErrorOccurred = false; 57*0b57cec5SDimitry Andric }; 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric #if LLVM_LIBXML2_ENABLED 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric static const std::pair<StringRef, StringRef> MtNsHrefsPrefixes[] = { 62*0b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"}, 63*0b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"}, 64*0b57cec5SDimitry Andric {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"}, 65*0b57cec5SDimitry Andric {"http://schemas.microsoft.com/SMI/2005/WindowsSettings", 66*0b57cec5SDimitry Andric "ms_windowsSettings"}, 67*0b57cec5SDimitry Andric {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}}; 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) { 70*0b57cec5SDimitry Andric // Handle null pointers. Comparison of 2 null pointers returns true because 71*0b57cec5SDimitry Andric // this indicates the prefix of a default namespace. 72*0b57cec5SDimitry Andric if (!A || !B) 73*0b57cec5SDimitry Andric return A == B; 74*0b57cec5SDimitry Andric return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0; 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric static bool isMergeableElement(const unsigned char *ElementName) { 78*0b57cec5SDimitry Andric for (StringRef S : {"application", "assembly", "assemblyIdentity", 79*0b57cec5SDimitry Andric "compatibility", "noInherit", "requestedExecutionLevel", 80*0b57cec5SDimitry Andric "requestedPrivileges", "security", "trustInfo"}) { 81*0b57cec5SDimitry Andric if (S == FROM_XML_CHAR(ElementName)) { 82*0b57cec5SDimitry Andric return true; 83*0b57cec5SDimitry Andric } 84*0b57cec5SDimitry Andric } 85*0b57cec5SDimitry Andric return false; 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric static xmlNodePtr getChildWithName(xmlNodePtr Parent, 89*0b57cec5SDimitry Andric const unsigned char *ElementName) { 90*0b57cec5SDimitry Andric for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) { 91*0b57cec5SDimitry Andric if (xmlStringsEqual(Child->name, ElementName)) { 92*0b57cec5SDimitry Andric return Child; 93*0b57cec5SDimitry Andric } 94*0b57cec5SDimitry Andric } 95*0b57cec5SDimitry Andric return nullptr; 96*0b57cec5SDimitry Andric } 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric static xmlAttrPtr getAttribute(xmlNodePtr Node, 99*0b57cec5SDimitry Andric const unsigned char *AttributeName) { 100*0b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr; 101*0b57cec5SDimitry Andric Attribute = Attribute->next) { 102*0b57cec5SDimitry Andric if (xmlStringsEqual(Attribute->name, AttributeName)) { 103*0b57cec5SDimitry Andric return Attribute; 104*0b57cec5SDimitry Andric } 105*0b57cec5SDimitry Andric } 106*0b57cec5SDimitry Andric return nullptr; 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric // Check if namespace specified by HRef1 overrides that of HRef2. 110*0b57cec5SDimitry Andric static bool namespaceOverrides(const unsigned char *HRef1, 111*0b57cec5SDimitry Andric const unsigned char *HRef2) { 112*0b57cec5SDimitry Andric auto HRef1Position = llvm::find_if( 113*0b57cec5SDimitry Andric MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) { 114*0b57cec5SDimitry Andric return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data())); 115*0b57cec5SDimitry Andric }); 116*0b57cec5SDimitry Andric auto HRef2Position = llvm::find_if( 117*0b57cec5SDimitry Andric MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) { 118*0b57cec5SDimitry Andric return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data())); 119*0b57cec5SDimitry Andric }); 120*0b57cec5SDimitry Andric return HRef1Position < HRef2Position; 121*0b57cec5SDimitry Andric } 122*0b57cec5SDimitry Andric 123*0b57cec5SDimitry Andric // Search for prefix-defined namespace specified by HRef, starting on Node and 124*0b57cec5SDimitry Andric // continuing recursively upwards. Returns the namespace or nullptr if not 125*0b57cec5SDimitry Andric // found. 126*0b57cec5SDimitry Andric static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) { 127*0b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 128*0b57cec5SDimitry Andric if (Def->prefix && xmlStringsEqual(Def->href, HRef)) { 129*0b57cec5SDimitry Andric return Def; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric } 132*0b57cec5SDimitry Andric if (Node->parent) { 133*0b57cec5SDimitry Andric return search(HRef, Node->parent); 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric return nullptr; 136*0b57cec5SDimitry Andric } 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric // Return the prefix that corresponds to the HRef. If HRef is not a recognized 139*0b57cec5SDimitry Andric // URI, then just return the HRef itself to use as the prefix. 140*0b57cec5SDimitry Andric static const unsigned char *getPrefixForHref(const unsigned char *HRef) { 141*0b57cec5SDimitry Andric for (auto &Ns : MtNsHrefsPrefixes) { 142*0b57cec5SDimitry Andric if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) { 143*0b57cec5SDimitry Andric return TO_XML_CHAR(Ns.second.data()); 144*0b57cec5SDimitry Andric } 145*0b57cec5SDimitry Andric } 146*0b57cec5SDimitry Andric return HRef; 147*0b57cec5SDimitry Andric } 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric // Search for prefix-defined namespace specified by HRef, starting on Node and 150*0b57cec5SDimitry Andric // continuing recursively upwards. If it is found, then return it. If it is 151*0b57cec5SDimitry Andric // not found, then prefix-define that namespace on the node and return a 152*0b57cec5SDimitry Andric // reference to it. 153*0b57cec5SDimitry Andric static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef, 154*0b57cec5SDimitry Andric xmlNodePtr Node) { 155*0b57cec5SDimitry Andric if (xmlNsPtr Def = search(HRef, Node)) 156*0b57cec5SDimitry Andric return Def; 157*0b57cec5SDimitry Andric if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef))) 158*0b57cec5SDimitry Andric return Def; 159*0b57cec5SDimitry Andric return make_error<WindowsManifestError>("failed to create new namespace"); 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric // Set the namespace of OrigionalAttribute on OriginalNode to be that of 163*0b57cec5SDimitry Andric // AdditionalAttribute's. 164*0b57cec5SDimitry Andric static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute, 165*0b57cec5SDimitry Andric xmlNodePtr OriginalNode, 166*0b57cec5SDimitry Andric xmlAttrPtr AdditionalAttribute) { 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = 169*0b57cec5SDimitry Andric searchOrDefine(AdditionalAttribute->ns->href, OriginalNode); 170*0b57cec5SDimitry Andric if (!ExplicitOrError) 171*0b57cec5SDimitry Andric return ExplicitOrError.takeError(); 172*0b57cec5SDimitry Andric OriginalAttribute->ns = std::move(ExplicitOrError.get()); 173*0b57cec5SDimitry Andric return Error::success(); 174*0b57cec5SDimitry Andric } 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // Return the corresponding namespace definition for the prefix, defined on the 177*0b57cec5SDimitry Andric // given Node. Returns nullptr if there is no such definition. 178*0b57cec5SDimitry Andric static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix, 179*0b57cec5SDimitry Andric xmlNodePtr Node) { 180*0b57cec5SDimitry Andric if (Node == nullptr) 181*0b57cec5SDimitry Andric return nullptr; 182*0b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 183*0b57cec5SDimitry Andric if (xmlStringsEqual(Def->prefix, Prefix)) { 184*0b57cec5SDimitry Andric return Def; 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric } 187*0b57cec5SDimitry Andric return nullptr; 188*0b57cec5SDimitry Andric } 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric // Search for the closest inheritable default namespace, starting on (and 191*0b57cec5SDimitry Andric // including) the Node and traveling upwards through parent nodes. Returns 192*0b57cec5SDimitry Andric // nullptr if there are no inheritable default namespaces. 193*0b57cec5SDimitry Andric static xmlNsPtr getClosestDefault(xmlNodePtr Node) { 194*0b57cec5SDimitry Andric if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node)) 195*0b57cec5SDimitry Andric return Ret; 196*0b57cec5SDimitry Andric if (Node->parent == nullptr) 197*0b57cec5SDimitry Andric return nullptr; 198*0b57cec5SDimitry Andric return getClosestDefault(Node->parent); 199*0b57cec5SDimitry Andric } 200*0b57cec5SDimitry Andric 201*0b57cec5SDimitry Andric // Merge the attributes of AdditionalNode into OriginalNode. If attributes 202*0b57cec5SDimitry Andric // with identical types are present, they are not duplicated but rather if 203*0b57cec5SDimitry Andric // their values are not consistent and error is thrown. In addition, the 204*0b57cec5SDimitry Andric // higher priority namespace is used for each attribute, EXCEPT in the case 205*0b57cec5SDimitry Andric // of merging two default namespaces and the lower priority namespace 206*0b57cec5SDimitry Andric // definition occurs closer than the higher priority one. 207*0b57cec5SDimitry Andric static Error mergeAttributes(xmlNodePtr OriginalNode, 208*0b57cec5SDimitry Andric xmlNodePtr AdditionalNode) { 209*0b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode); 210*0b57cec5SDimitry Andric for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute; 211*0b57cec5SDimitry Andric Attribute = Attribute->next) { 212*0b57cec5SDimitry Andric if (xmlAttrPtr OriginalAttribute = 213*0b57cec5SDimitry Andric getAttribute(OriginalNode, Attribute->name)) { 214*0b57cec5SDimitry Andric if (!xmlStringsEqual(OriginalAttribute->children->content, 215*0b57cec5SDimitry Andric Attribute->children->content)) { 216*0b57cec5SDimitry Andric return make_error<WindowsManifestError>( 217*0b57cec5SDimitry Andric Twine("conflicting attributes for ") + 218*0b57cec5SDimitry Andric FROM_XML_CHAR(OriginalNode->name)); 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric if (!Attribute->ns) { 221*0b57cec5SDimitry Andric continue; 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric if (!OriginalAttribute->ns) { 224*0b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 225*0b57cec5SDimitry Andric Attribute)) { 226*0b57cec5SDimitry Andric return E; 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric continue; 229*0b57cec5SDimitry Andric } 230*0b57cec5SDimitry Andric if (namespaceOverrides(OriginalAttribute->ns->href, 231*0b57cec5SDimitry Andric Attribute->ns->href)) { 232*0b57cec5SDimitry Andric // In this case, the original attribute has a higher priority namespace 233*0b57cec5SDimitry Andric // than the incomiing attribute, however the namespace definition of 234*0b57cec5SDimitry Andric // the lower priority namespace occurs first traveling upwards in the 235*0b57cec5SDimitry Andric // tree. Therefore the lower priority namespace is applied. 236*0b57cec5SDimitry Andric if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix && 237*0b57cec5SDimitry Andric ClosestDefault && 238*0b57cec5SDimitry Andric xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) { 239*0b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 240*0b57cec5SDimitry Andric Attribute)) { 241*0b57cec5SDimitry Andric return E; 242*0b57cec5SDimitry Andric } 243*0b57cec5SDimitry Andric continue; 244*0b57cec5SDimitry Andric } 245*0b57cec5SDimitry Andric continue; 246*0b57cec5SDimitry Andric // This covers the case where the incoming attribute has the higher 247*0b57cec5SDimitry Andric // priority. The higher priority namespace is applied in all cases 248*0b57cec5SDimitry Andric // EXCEPT when both of the namespaces are default inherited, and the 249*0b57cec5SDimitry Andric // closest inherited default is the lower priority one. 250*0b57cec5SDimitry Andric } 251*0b57cec5SDimitry Andric if (Attribute->ns->prefix || OriginalAttribute->ns->prefix || 252*0b57cec5SDimitry Andric (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href, 253*0b57cec5SDimitry Andric ClosestDefault->href))) { 254*0b57cec5SDimitry Andric if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode, 255*0b57cec5SDimitry Andric Attribute)) { 256*0b57cec5SDimitry Andric return E; 257*0b57cec5SDimitry Andric } 258*0b57cec5SDimitry Andric continue; 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric continue; 261*0b57cec5SDimitry Andric } 262*0b57cec5SDimitry Andric // If the incoming attribute is not already found on the node, append it 263*0b57cec5SDimitry Andric // to the end of the properties list. Also explicitly apply its 264*0b57cec5SDimitry Andric // namespace as a prefix because it might be contained in a separate 265*0b57cec5SDimitry Andric // namespace that doesn't use the attribute. 266*0b57cec5SDimitry Andric xmlAttrPtr NewProp = 267*0b57cec5SDimitry Andric xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content); 268*0b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = 269*0b57cec5SDimitry Andric searchOrDefine(Attribute->ns->href, OriginalNode); 270*0b57cec5SDimitry Andric if (!ExplicitOrError) 271*0b57cec5SDimitry Andric return ExplicitOrError.takeError(); 272*0b57cec5SDimitry Andric NewProp->ns = std::move(ExplicitOrError.get()); 273*0b57cec5SDimitry Andric } 274*0b57cec5SDimitry Andric return Error::success(); 275*0b57cec5SDimitry Andric } 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // Given two nodes, return the one with the higher priority namespace. 278*0b57cec5SDimitry Andric static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) { 279*0b57cec5SDimitry Andric 280*0b57cec5SDimitry Andric if (!Node1 || !Node1->ns) 281*0b57cec5SDimitry Andric return Node2; 282*0b57cec5SDimitry Andric if (!Node2 || !Node2->ns) 283*0b57cec5SDimitry Andric return Node1; 284*0b57cec5SDimitry Andric if (namespaceOverrides(Node1->ns->href, Node2->ns->href)) 285*0b57cec5SDimitry Andric return Node1; 286*0b57cec5SDimitry Andric return Node2; 287*0b57cec5SDimitry Andric } 288*0b57cec5SDimitry Andric 289*0b57cec5SDimitry Andric // Checks if this Node's namespace is inherited or one it defined itself. 290*0b57cec5SDimitry Andric static bool hasInheritedNs(xmlNodePtr Node) { 291*0b57cec5SDimitry Andric return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node); 292*0b57cec5SDimitry Andric } 293*0b57cec5SDimitry Andric 294*0b57cec5SDimitry Andric // Check if this Node's namespace is a default namespace that it inherited, as 295*0b57cec5SDimitry Andric // opposed to defining itself. 296*0b57cec5SDimitry Andric static bool hasInheritedDefaultNs(xmlNodePtr Node) { 297*0b57cec5SDimitry Andric return hasInheritedNs(Node) && Node->ns->prefix == nullptr; 298*0b57cec5SDimitry Andric } 299*0b57cec5SDimitry Andric 300*0b57cec5SDimitry Andric // Check if this Node's namespace is a default namespace it defined itself. 301*0b57cec5SDimitry Andric static bool hasDefinedDefaultNamespace(xmlNodePtr Node) { 302*0b57cec5SDimitry Andric return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node)); 303*0b57cec5SDimitry Andric } 304*0b57cec5SDimitry Andric 305*0b57cec5SDimitry Andric // For the given explicit prefix-definition of a namespace, travel downwards 306*0b57cec5SDimitry Andric // from a node recursively, and for every implicit, inherited default usage of 307*0b57cec5SDimitry Andric // that namespace replace it with that explicit prefix use. This is important 308*0b57cec5SDimitry Andric // when namespace overriding occurs when merging, so that elements unique to a 309*0b57cec5SDimitry Andric // namespace will still stay in that namespace. 310*0b57cec5SDimitry Andric static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) { 311*0b57cec5SDimitry Andric // If a node as its own default namespace definition it clearly cannot have 312*0b57cec5SDimitry Andric // inherited the given default namespace, and neither will any of its 313*0b57cec5SDimitry Andric // children. 314*0b57cec5SDimitry Andric if (hasDefinedDefaultNamespace(Node)) 315*0b57cec5SDimitry Andric return; 316*0b57cec5SDimitry Andric if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) && 317*0b57cec5SDimitry Andric hasInheritedDefaultNs(Node)) 318*0b57cec5SDimitry Andric Node->ns = PrefixDef; 319*0b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 320*0b57cec5SDimitry Andric Attribute = Attribute->next) { 321*0b57cec5SDimitry Andric if (Attribute->ns && 322*0b57cec5SDimitry Andric xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) { 323*0b57cec5SDimitry Andric Attribute->ns = PrefixDef; 324*0b57cec5SDimitry Andric } 325*0b57cec5SDimitry Andric } 326*0b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 327*0b57cec5SDimitry Andric explicateNamespace(PrefixDef, Child); 328*0b57cec5SDimitry Andric } 329*0b57cec5SDimitry Andric } 330*0b57cec5SDimitry Andric 331*0b57cec5SDimitry Andric // Perform the namespace merge between two nodes. 332*0b57cec5SDimitry Andric static Error mergeNamespaces(xmlNodePtr OriginalNode, 333*0b57cec5SDimitry Andric xmlNodePtr AdditionalNode) { 334*0b57cec5SDimitry Andric // Save the original default namespace definition in case the incoming node 335*0b57cec5SDimitry Andric // overrides it. 336*0b57cec5SDimitry Andric const unsigned char *OriginalDefinedDefaultHref = nullptr; 337*0b57cec5SDimitry Andric if (xmlNsPtr OriginalDefinedDefaultNs = 338*0b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, OriginalNode)) { 339*0b57cec5SDimitry Andric OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href); 340*0b57cec5SDimitry Andric } 341*0b57cec5SDimitry Andric const unsigned char *NewDefinedDefaultHref = nullptr; 342*0b57cec5SDimitry Andric // Copy all namespace definitions. There can only be one default namespace 343*0b57cec5SDimitry Andric // definition per node, so the higher priority one takes precedence in the 344*0b57cec5SDimitry Andric // case of collision. 345*0b57cec5SDimitry Andric for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) { 346*0b57cec5SDimitry Andric if (xmlNsPtr OriginalNsDef = 347*0b57cec5SDimitry Andric getNamespaceWithPrefix(Def->prefix, OriginalNode)) { 348*0b57cec5SDimitry Andric if (!Def->prefix) { 349*0b57cec5SDimitry Andric if (namespaceOverrides(Def->href, OriginalNsDef->href)) { 350*0b57cec5SDimitry Andric NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href))); 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) { 353*0b57cec5SDimitry Andric return make_error<WindowsManifestError>( 354*0b57cec5SDimitry Andric Twine("conflicting namespace definitions for ") + 355*0b57cec5SDimitry Andric FROM_XML_CHAR(Def->prefix)); 356*0b57cec5SDimitry Andric } 357*0b57cec5SDimitry Andric } else { 358*0b57cec5SDimitry Andric xmlNsPtr NewDef = xmlCopyNamespace(Def); 359*0b57cec5SDimitry Andric NewDef->next = OriginalNode->nsDef; 360*0b57cec5SDimitry Andric OriginalNode->nsDef = NewDef; 361*0b57cec5SDimitry Andric } 362*0b57cec5SDimitry Andric } 363*0b57cec5SDimitry Andric 364*0b57cec5SDimitry Andric // Check whether the original node or the incoming node has the higher 365*0b57cec5SDimitry Andric // priority namespace. Depending on which one is dominant, we will have 366*0b57cec5SDimitry Andric // to recursively apply namespace changes down to children of the original 367*0b57cec5SDimitry Andric // node. 368*0b57cec5SDimitry Andric xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode); 369*0b57cec5SDimitry Andric xmlNodePtr NonDominantNode = 370*0b57cec5SDimitry Andric DominantNode == OriginalNode ? AdditionalNode : OriginalNode; 371*0b57cec5SDimitry Andric if (DominantNode == OriginalNode) { 372*0b57cec5SDimitry Andric if (OriginalDefinedDefaultHref) { 373*0b57cec5SDimitry Andric xmlNsPtr NonDominantDefinedDefault = 374*0b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, NonDominantNode); 375*0b57cec5SDimitry Andric // In this case, both the nodes defined a default namespace. However 376*0b57cec5SDimitry Andric // the lower priority node ended up having a higher priority default 377*0b57cec5SDimitry Andric // definition. This can occur if the higher priority node is prefix 378*0b57cec5SDimitry Andric // namespace defined. In this case we have to define an explicit 379*0b57cec5SDimitry Andric // prefix for the overridden definition and apply it to all children 380*0b57cec5SDimitry Andric // who relied on that definition. 381*0b57cec5SDimitry Andric if (NonDominantDefinedDefault && 382*0b57cec5SDimitry Andric namespaceOverrides(NonDominantDefinedDefault->href, 383*0b57cec5SDimitry Andric OriginalDefinedDefaultHref)) { 384*0b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 385*0b57cec5SDimitry Andric searchOrDefine(OriginalDefinedDefaultHref, DominantNode); 386*0b57cec5SDimitry Andric if (!EC) { 387*0b57cec5SDimitry Andric return EC.takeError(); 388*0b57cec5SDimitry Andric } 389*0b57cec5SDimitry Andric xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get()); 390*0b57cec5SDimitry Andric explicateNamespace(PrefixDominantDefinedDefault, DominantNode); 391*0b57cec5SDimitry Andric } 392*0b57cec5SDimitry Andric // In this case the node with a higher priority namespace did not have a 393*0b57cec5SDimitry Andric // default namespace definition, but the lower priority node did. In this 394*0b57cec5SDimitry Andric // case the new default namespace definition is copied. A side effect of 395*0b57cec5SDimitry Andric // this is that all children will suddenly find themselves in a different 396*0b57cec5SDimitry Andric // default namespace. To maintain correctness we need to ensure that all 397*0b57cec5SDimitry Andric // children now explicitly refer to the namespace that they had previously 398*0b57cec5SDimitry Andric // implicitly inherited. 399*0b57cec5SDimitry Andric } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) { 400*0b57cec5SDimitry Andric if (DominantNode->parent) { 401*0b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent); 402*0b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 403*0b57cec5SDimitry Andric searchOrDefine(ClosestDefault->href, DominantNode); 404*0b57cec5SDimitry Andric if (!EC) { 405*0b57cec5SDimitry Andric return EC.takeError(); 406*0b57cec5SDimitry Andric } 407*0b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 408*0b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, DominantNode); 409*0b57cec5SDimitry Andric } 410*0b57cec5SDimitry Andric } 411*0b57cec5SDimitry Andric } else { 412*0b57cec5SDimitry Andric // Covers case where the incoming node has a default namespace definition 413*0b57cec5SDimitry Andric // that overrides the original node's namespace. This always leads to 414*0b57cec5SDimitry Andric // the original node receiving that new default namespace. 415*0b57cec5SDimitry Andric if (hasDefinedDefaultNamespace(DominantNode)) { 416*0b57cec5SDimitry Andric NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode); 417*0b57cec5SDimitry Andric } else { 418*0b57cec5SDimitry Andric // This covers the case where the incoming node either has a prefix 419*0b57cec5SDimitry Andric // namespace, or an inherited default namespace. Since the namespace 420*0b57cec5SDimitry Andric // may not yet be defined in the original tree we do a searchOrDefine 421*0b57cec5SDimitry Andric // for it, and then set the namespace equal to it. 422*0b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 423*0b57cec5SDimitry Andric searchOrDefine(DominantNode->ns->href, NonDominantNode); 424*0b57cec5SDimitry Andric if (!EC) { 425*0b57cec5SDimitry Andric return EC.takeError(); 426*0b57cec5SDimitry Andric } 427*0b57cec5SDimitry Andric xmlNsPtr Explicit = std::move(EC.get()); 428*0b57cec5SDimitry Andric NonDominantNode->ns = Explicit; 429*0b57cec5SDimitry Andric } 430*0b57cec5SDimitry Andric // This covers cases where the incoming dominant node HAS a default 431*0b57cec5SDimitry Andric // namespace definition, but MIGHT NOT NECESSARILY be in that namespace. 432*0b57cec5SDimitry Andric if (xmlNsPtr DominantDefaultDefined = 433*0b57cec5SDimitry Andric getNamespaceWithPrefix(nullptr, DominantNode)) { 434*0b57cec5SDimitry Andric if (OriginalDefinedDefaultHref) { 435*0b57cec5SDimitry Andric if (namespaceOverrides(DominantDefaultDefined->href, 436*0b57cec5SDimitry Andric OriginalDefinedDefaultHref)) { 437*0b57cec5SDimitry Andric // In this case, the incoming node's default definition overrides 438*0b57cec5SDimitry Andric // the original default definition, all children who relied on that 439*0b57cec5SDimitry Andric // definition must be updated accordingly. 440*0b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 441*0b57cec5SDimitry Andric searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode); 442*0b57cec5SDimitry Andric if (!EC) { 443*0b57cec5SDimitry Andric return EC.takeError(); 444*0b57cec5SDimitry Andric } 445*0b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 446*0b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, NonDominantNode); 447*0b57cec5SDimitry Andric } 448*0b57cec5SDimitry Andric } else { 449*0b57cec5SDimitry Andric // The original did not define a default definition, however the new 450*0b57cec5SDimitry Andric // default definition still applies to all children, so they must be 451*0b57cec5SDimitry Andric // updated to explicitly refer to the namespace they had previously 452*0b57cec5SDimitry Andric // been inheriting implicitly. 453*0b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode); 454*0b57cec5SDimitry Andric Expected<xmlNsPtr> EC = 455*0b57cec5SDimitry Andric searchOrDefine(ClosestDefault->href, NonDominantNode); 456*0b57cec5SDimitry Andric if (!EC) { 457*0b57cec5SDimitry Andric return EC.takeError(); 458*0b57cec5SDimitry Andric } 459*0b57cec5SDimitry Andric xmlNsPtr ExplicitDefault = std::move(EC.get()); 460*0b57cec5SDimitry Andric explicateNamespace(ExplicitDefault, NonDominantNode); 461*0b57cec5SDimitry Andric } 462*0b57cec5SDimitry Andric } 463*0b57cec5SDimitry Andric } 464*0b57cec5SDimitry Andric if (NewDefinedDefaultHref) { 465*0b57cec5SDimitry Andric xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode); 466*0b57cec5SDimitry Andric xmlFree(const_cast<unsigned char *>(OriginalNsDef->href)); 467*0b57cec5SDimitry Andric OriginalNsDef->href = NewDefinedDefaultHref; 468*0b57cec5SDimitry Andric } 469*0b57cec5SDimitry Andric xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref)); 470*0b57cec5SDimitry Andric return Error::success(); 471*0b57cec5SDimitry Andric } 472*0b57cec5SDimitry Andric 473*0b57cec5SDimitry Andric static bool isRecognizedNamespace(const unsigned char *NsHref) { 474*0b57cec5SDimitry Andric for (auto &Ns : MtNsHrefsPrefixes) { 475*0b57cec5SDimitry Andric if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) { 476*0b57cec5SDimitry Andric return true; 477*0b57cec5SDimitry Andric } 478*0b57cec5SDimitry Andric } 479*0b57cec5SDimitry Andric return false; 480*0b57cec5SDimitry Andric } 481*0b57cec5SDimitry Andric 482*0b57cec5SDimitry Andric static bool hasRecognizedNamespace(xmlNodePtr Node) { 483*0b57cec5SDimitry Andric return isRecognizedNamespace(Node->ns->href); 484*0b57cec5SDimitry Andric } 485*0b57cec5SDimitry Andric 486*0b57cec5SDimitry Andric // Ensure a node's inherited namespace is actually defined in the tree it 487*0b57cec5SDimitry Andric // resides in. 488*0b57cec5SDimitry Andric static Error reconcileNamespaces(xmlNodePtr Node) { 489*0b57cec5SDimitry Andric if (!Node) { 490*0b57cec5SDimitry Andric return Error::success(); 491*0b57cec5SDimitry Andric } 492*0b57cec5SDimitry Andric if (hasInheritedNs(Node)) { 493*0b57cec5SDimitry Andric Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node); 494*0b57cec5SDimitry Andric if (!ExplicitOrError) { 495*0b57cec5SDimitry Andric return ExplicitOrError.takeError(); 496*0b57cec5SDimitry Andric } 497*0b57cec5SDimitry Andric xmlNsPtr Explicit = std::move(ExplicitOrError.get()); 498*0b57cec5SDimitry Andric Node->ns = Explicit; 499*0b57cec5SDimitry Andric } 500*0b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 501*0b57cec5SDimitry Andric if (auto E = reconcileNamespaces(Child)) { 502*0b57cec5SDimitry Andric return E; 503*0b57cec5SDimitry Andric } 504*0b57cec5SDimitry Andric } 505*0b57cec5SDimitry Andric return Error::success(); 506*0b57cec5SDimitry Andric } 507*0b57cec5SDimitry Andric 508*0b57cec5SDimitry Andric // Recursively merge the two given manifest trees, depending on which elements 509*0b57cec5SDimitry Andric // are of a mergeable type, and choose namespaces according to which have 510*0b57cec5SDimitry Andric // higher priority. 511*0b57cec5SDimitry Andric static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) { 512*0b57cec5SDimitry Andric if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) 513*0b57cec5SDimitry Andric return E; 514*0b57cec5SDimitry Andric if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot)) 515*0b57cec5SDimitry Andric return E; 516*0b57cec5SDimitry Andric xmlNodePtr AdditionalFirstChild = AdditionalRoot->children; 517*0b57cec5SDimitry Andric xmlNode StoreNext; 518*0b57cec5SDimitry Andric for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) { 519*0b57cec5SDimitry Andric xmlNodePtr OriginalChildWithName; 520*0b57cec5SDimitry Andric if (!isMergeableElement(Child->name) || 521*0b57cec5SDimitry Andric !(OriginalChildWithName = 522*0b57cec5SDimitry Andric getChildWithName(OriginalRoot, Child->name)) || 523*0b57cec5SDimitry Andric !hasRecognizedNamespace(Child)) { 524*0b57cec5SDimitry Andric StoreNext.next = Child->next; 525*0b57cec5SDimitry Andric xmlUnlinkNode(Child); 526*0b57cec5SDimitry Andric if (!xmlAddChild(OriginalRoot, Child)) { 527*0b57cec5SDimitry Andric return make_error<WindowsManifestError>(Twine("could not merge ") + 528*0b57cec5SDimitry Andric FROM_XML_CHAR(Child->name)); 529*0b57cec5SDimitry Andric } 530*0b57cec5SDimitry Andric if (auto E = reconcileNamespaces(Child)) { 531*0b57cec5SDimitry Andric return E; 532*0b57cec5SDimitry Andric } 533*0b57cec5SDimitry Andric Child = &StoreNext; 534*0b57cec5SDimitry Andric } else if (auto E = treeMerge(OriginalChildWithName, Child)) { 535*0b57cec5SDimitry Andric return E; 536*0b57cec5SDimitry Andric } 537*0b57cec5SDimitry Andric } 538*0b57cec5SDimitry Andric return Error::success(); 539*0b57cec5SDimitry Andric } 540*0b57cec5SDimitry Andric 541*0b57cec5SDimitry Andric static void stripComments(xmlNodePtr Root) { 542*0b57cec5SDimitry Andric xmlNode StoreNext; 543*0b57cec5SDimitry Andric for (xmlNodePtr Child = Root->children; Child; Child = Child->next) { 544*0b57cec5SDimitry Andric if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) { 545*0b57cec5SDimitry Andric stripComments(Child); 546*0b57cec5SDimitry Andric continue; 547*0b57cec5SDimitry Andric } 548*0b57cec5SDimitry Andric StoreNext.next = Child->next; 549*0b57cec5SDimitry Andric xmlNodePtr Remove = Child; 550*0b57cec5SDimitry Andric Child = &StoreNext; 551*0b57cec5SDimitry Andric xmlUnlinkNode(Remove); 552*0b57cec5SDimitry Andric xmlFreeNode(Remove); 553*0b57cec5SDimitry Andric } 554*0b57cec5SDimitry Andric } 555*0b57cec5SDimitry Andric 556*0b57cec5SDimitry Andric // libxml2 assumes that attributes do not inherit default namespaces, whereas 557*0b57cec5SDimitry Andric // the original mt.exe does make this assumption. This function reconciles 558*0b57cec5SDimitry Andric // this by setting all attributes to have the inherited default namespace. 559*0b57cec5SDimitry Andric static void setAttributeNamespaces(xmlNodePtr Node) { 560*0b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 561*0b57cec5SDimitry Andric Attribute = Attribute->next) { 562*0b57cec5SDimitry Andric if (!Attribute->ns) { 563*0b57cec5SDimitry Andric Attribute->ns = getClosestDefault(Node); 564*0b57cec5SDimitry Andric } 565*0b57cec5SDimitry Andric } 566*0b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 567*0b57cec5SDimitry Andric setAttributeNamespaces(Child); 568*0b57cec5SDimitry Andric } 569*0b57cec5SDimitry Andric } 570*0b57cec5SDimitry Andric 571*0b57cec5SDimitry Andric // The merging process may create too many prefix defined namespaces. This 572*0b57cec5SDimitry Andric // function removes all unnecessary ones from the tree. 573*0b57cec5SDimitry Andric static void checkAndStripPrefixes(xmlNodePtr Node, 574*0b57cec5SDimitry Andric std::vector<xmlNsPtr> &RequiredPrefixes) { 575*0b57cec5SDimitry Andric for (xmlNodePtr Child = Node->children; Child; Child = Child->next) { 576*0b57cec5SDimitry Andric checkAndStripPrefixes(Child, RequiredPrefixes); 577*0b57cec5SDimitry Andric } 578*0b57cec5SDimitry Andric if (Node->ns && Node->ns->prefix != nullptr) { 579*0b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(Node); 580*0b57cec5SDimitry Andric if (ClosestDefault && 581*0b57cec5SDimitry Andric xmlStringsEqual(ClosestDefault->href, Node->ns->href)) { 582*0b57cec5SDimitry Andric Node->ns = ClosestDefault; 583*0b57cec5SDimitry Andric } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) { 584*0b57cec5SDimitry Andric RequiredPrefixes.push_back(Node->ns); 585*0b57cec5SDimitry Andric } 586*0b57cec5SDimitry Andric } 587*0b57cec5SDimitry Andric for (xmlAttrPtr Attribute = Node->properties; Attribute; 588*0b57cec5SDimitry Andric Attribute = Attribute->next) { 589*0b57cec5SDimitry Andric if (Attribute->ns && Attribute->ns->prefix != nullptr) { 590*0b57cec5SDimitry Andric xmlNsPtr ClosestDefault = getClosestDefault(Node); 591*0b57cec5SDimitry Andric if (ClosestDefault && 592*0b57cec5SDimitry Andric xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) { 593*0b57cec5SDimitry Andric Attribute->ns = ClosestDefault; 594*0b57cec5SDimitry Andric } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) { 595*0b57cec5SDimitry Andric RequiredPrefixes.push_back(Attribute->ns); 596*0b57cec5SDimitry Andric } 597*0b57cec5SDimitry Andric } 598*0b57cec5SDimitry Andric } 599*0b57cec5SDimitry Andric xmlNsPtr Prev; 600*0b57cec5SDimitry Andric xmlNs Temp; 601*0b57cec5SDimitry Andric for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) { 602*0b57cec5SDimitry Andric if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) { 603*0b57cec5SDimitry Andric Prev = Def; 604*0b57cec5SDimitry Andric continue; 605*0b57cec5SDimitry Andric } 606*0b57cec5SDimitry Andric if (Def == Node->nsDef) { 607*0b57cec5SDimitry Andric Node->nsDef = Def->next; 608*0b57cec5SDimitry Andric } else { 609*0b57cec5SDimitry Andric Prev->next = Def->next; 610*0b57cec5SDimitry Andric } 611*0b57cec5SDimitry Andric Temp.next = Def->next; 612*0b57cec5SDimitry Andric xmlFreeNs(Def); 613*0b57cec5SDimitry Andric Def = &Temp; 614*0b57cec5SDimitry Andric } 615*0b57cec5SDimitry Andric } 616*0b57cec5SDimitry Andric 617*0b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 618*0b57cec5SDimitry Andric for (auto &Doc : MergedDocs) 619*0b57cec5SDimitry Andric xmlFreeDoc(Doc); 620*0b57cec5SDimitry Andric } 621*0b57cec5SDimitry Andric 622*0b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 623*0b57cec5SDimitry Andric const MemoryBuffer &Manifest) { 624*0b57cec5SDimitry Andric if (Merged) 625*0b57cec5SDimitry Andric return make_error<WindowsManifestError>( 626*0b57cec5SDimitry Andric "merge after getMergedManifest is not supported"); 627*0b57cec5SDimitry Andric if (Manifest.getBufferSize() == 0) 628*0b57cec5SDimitry Andric return make_error<WindowsManifestError>( 629*0b57cec5SDimitry Andric "attempted to merge empty manifest"); 630*0b57cec5SDimitry Andric xmlSetGenericErrorFunc((void *)this, 631*0b57cec5SDimitry Andric WindowsManifestMergerImpl::errorCallback); 632*0b57cec5SDimitry Andric xmlDocPtr ManifestXML = xmlReadMemory( 633*0b57cec5SDimitry Andric Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml", 634*0b57cec5SDimitry Andric nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT); 635*0b57cec5SDimitry Andric xmlSetGenericErrorFunc(nullptr, nullptr); 636*0b57cec5SDimitry Andric if (auto E = getParseError()) 637*0b57cec5SDimitry Andric return E; 638*0b57cec5SDimitry Andric xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML); 639*0b57cec5SDimitry Andric stripComments(AdditionalRoot); 640*0b57cec5SDimitry Andric setAttributeNamespaces(AdditionalRoot); 641*0b57cec5SDimitry Andric if (CombinedDoc == nullptr) { 642*0b57cec5SDimitry Andric CombinedDoc = ManifestXML; 643*0b57cec5SDimitry Andric } else { 644*0b57cec5SDimitry Andric xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc); 645*0b57cec5SDimitry Andric if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) || 646*0b57cec5SDimitry Andric !isMergeableElement(AdditionalRoot->name) || 647*0b57cec5SDimitry Andric !hasRecognizedNamespace(AdditionalRoot)) { 648*0b57cec5SDimitry Andric return make_error<WindowsManifestError>("multiple root nodes"); 649*0b57cec5SDimitry Andric } 650*0b57cec5SDimitry Andric if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) { 651*0b57cec5SDimitry Andric return E; 652*0b57cec5SDimitry Andric } 653*0b57cec5SDimitry Andric } 654*0b57cec5SDimitry Andric MergedDocs.push_back(ManifestXML); 655*0b57cec5SDimitry Andric return Error::success(); 656*0b57cec5SDimitry Andric } 657*0b57cec5SDimitry Andric 658*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 659*0b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 660*0b57cec5SDimitry Andric if (!Merged) { 661*0b57cec5SDimitry Andric Merged = true; 662*0b57cec5SDimitry Andric 663*0b57cec5SDimitry Andric if (!CombinedDoc) 664*0b57cec5SDimitry Andric return nullptr; 665*0b57cec5SDimitry Andric 666*0b57cec5SDimitry Andric xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc); 667*0b57cec5SDimitry Andric std::vector<xmlNsPtr> RequiredPrefixes; 668*0b57cec5SDimitry Andric checkAndStripPrefixes(CombinedRoot, RequiredPrefixes); 669*0b57cec5SDimitry Andric std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc( 670*0b57cec5SDimitry Andric xmlNewDoc((const unsigned char *)"1.0")); 671*0b57cec5SDimitry Andric xmlDocSetRootElement(OutputDoc.get(), CombinedRoot); 672*0b57cec5SDimitry Andric assert(0 == xmlDocGetRootElement(CombinedDoc)); 673*0b57cec5SDimitry Andric 674*0b57cec5SDimitry Andric xmlKeepBlanksDefault(0); 675*0b57cec5SDimitry Andric xmlChar *Buff = nullptr; 676*0b57cec5SDimitry Andric xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1); 677*0b57cec5SDimitry Andric Buffer.reset(Buff); 678*0b57cec5SDimitry Andric } 679*0b57cec5SDimitry Andric 680*0b57cec5SDimitry Andric return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef( 681*0b57cec5SDimitry Andric FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize)) 682*0b57cec5SDimitry Andric : nullptr; 683*0b57cec5SDimitry Andric } 684*0b57cec5SDimitry Andric 685*0b57cec5SDimitry Andric bool windows_manifest::isAvailable() { return true; } 686*0b57cec5SDimitry Andric 687*0b57cec5SDimitry Andric #else 688*0b57cec5SDimitry Andric 689*0b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 690*0b57cec5SDimitry Andric } 691*0b57cec5SDimitry Andric 692*0b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 693*0b57cec5SDimitry Andric const MemoryBuffer &Manifest) { 694*0b57cec5SDimitry Andric return make_error<WindowsManifestError>("no libxml2"); 695*0b57cec5SDimitry Andric } 696*0b57cec5SDimitry Andric 697*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> 698*0b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 699*0b57cec5SDimitry Andric return nullptr; 700*0b57cec5SDimitry Andric } 701*0b57cec5SDimitry Andric 702*0b57cec5SDimitry Andric bool windows_manifest::isAvailable() { return false; } 703*0b57cec5SDimitry Andric 704*0b57cec5SDimitry Andric #endif 705*0b57cec5SDimitry Andric 706*0b57cec5SDimitry Andric WindowsManifestMerger::WindowsManifestMerger() 707*0b57cec5SDimitry Andric : Impl(make_unique<WindowsManifestMergerImpl>()) {} 708*0b57cec5SDimitry Andric 709*0b57cec5SDimitry Andric WindowsManifestMerger::~WindowsManifestMerger() {} 710*0b57cec5SDimitry Andric 711*0b57cec5SDimitry Andric Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) { 712*0b57cec5SDimitry Andric return Impl->merge(Manifest); 713*0b57cec5SDimitry Andric } 714*0b57cec5SDimitry Andric 715*0b57cec5SDimitry Andric std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() { 716*0b57cec5SDimitry Andric return Impl->getMergedManifest(); 717*0b57cec5SDimitry Andric } 718*0b57cec5SDimitry Andric 719*0b57cec5SDimitry Andric void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback( 720*0b57cec5SDimitry Andric void *Ctx, const char *Format, ...) { 721*0b57cec5SDimitry Andric auto *Merger = (WindowsManifestMergerImpl *)Ctx; 722*0b57cec5SDimitry Andric Merger->ParseErrorOccurred = true; 723*0b57cec5SDimitry Andric } 724*0b57cec5SDimitry Andric 725*0b57cec5SDimitry Andric Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() { 726*0b57cec5SDimitry Andric if (!ParseErrorOccurred) 727*0b57cec5SDimitry Andric return Error::success(); 728*0b57cec5SDimitry Andric return make_error<WindowsManifestError>("invalid xml document"); 729*0b57cec5SDimitry Andric } 730