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