LCOV - code coverage report
Current view: top level - lib/WindowsManifest - WindowsManifestMerger.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 0 21 0.0 %
Date: 2018-10-20 13:21:21 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13