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