brintos

brintos / llvm-project-archived public Read only

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