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

Generated by: LCOV version 1.13