109467b48Spatrick //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===---------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements the .manifest merger class.
1009467b48Spatrick //
1109467b48Spatrick //===---------------------------------------------------------------------===//
1209467b48Spatrick
1309467b48Spatrick #include "llvm/WindowsManifest/WindowsManifestMerger.h"
1409467b48Spatrick #include "llvm/Config/config.h"
1509467b48Spatrick #include "llvm/Support/MemoryBuffer.h"
1609467b48Spatrick
1773471bf0Spatrick #if LLVM_ENABLE_LIBXML2
1809467b48Spatrick #include <libxml/xmlreader.h>
1909467b48Spatrick #endif
2009467b48Spatrick
2109467b48Spatrick #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
2209467b48Spatrick #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
2309467b48Spatrick
2409467b48Spatrick using namespace llvm;
2509467b48Spatrick using namespace windows_manifest;
2609467b48Spatrick
2709467b48Spatrick char WindowsManifestError::ID = 0;
2809467b48Spatrick
WindowsManifestError(const Twine & Msg)2909467b48Spatrick WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
3009467b48Spatrick
log(raw_ostream & OS) const3109467b48Spatrick void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
3209467b48Spatrick
3309467b48Spatrick class WindowsManifestMerger::WindowsManifestMergerImpl {
3409467b48Spatrick public:
3509467b48Spatrick ~WindowsManifestMergerImpl();
36*d415bd75Srobert Error merge(MemoryBufferRef Manifest);
3709467b48Spatrick std::unique_ptr<MemoryBuffer> getMergedManifest();
3809467b48Spatrick
3909467b48Spatrick private:
4009467b48Spatrick static void errorCallback(void *Ctx, const char *Format, ...);
4109467b48Spatrick Error getParseError();
4273471bf0Spatrick #if LLVM_ENABLE_LIBXML2
4309467b48Spatrick xmlDocPtr CombinedDoc = nullptr;
4409467b48Spatrick std::vector<xmlDocPtr> MergedDocs;
4509467b48Spatrick
4609467b48Spatrick bool Merged = false;
4709467b48Spatrick struct XmlDeleter {
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter4809467b48Spatrick void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter4909467b48Spatrick void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
5009467b48Spatrick };
5109467b48Spatrick int BufferSize = 0;
5209467b48Spatrick std::unique_ptr<xmlChar, XmlDeleter> Buffer;
5309467b48Spatrick #endif
5409467b48Spatrick bool ParseErrorOccurred = false;
5509467b48Spatrick };
5609467b48Spatrick
5773471bf0Spatrick #if LLVM_ENABLE_LIBXML2
5809467b48Spatrick
5909467b48Spatrick static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = {
6009467b48Spatrick {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
6109467b48Spatrick {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
6209467b48Spatrick {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
6309467b48Spatrick {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
6409467b48Spatrick "ms_windowsSettings"},
6509467b48Spatrick {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
6609467b48Spatrick
xmlStringsEqual(const unsigned char * A,const unsigned char * B)6709467b48Spatrick static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
6809467b48Spatrick // Handle null pointers. Comparison of 2 null pointers returns true because
6909467b48Spatrick // this indicates the prefix of a default namespace.
7009467b48Spatrick if (!A || !B)
7109467b48Spatrick return A == B;
7209467b48Spatrick return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
7309467b48Spatrick }
7409467b48Spatrick
isMergeableElement(const unsigned char * ElementName)7509467b48Spatrick static bool isMergeableElement(const unsigned char *ElementName) {
7609467b48Spatrick for (StringRef S : {"application", "assembly", "assemblyIdentity",
7709467b48Spatrick "compatibility", "noInherit", "requestedExecutionLevel",
7809467b48Spatrick "requestedPrivileges", "security", "trustInfo"}) {
7909467b48Spatrick if (S == FROM_XML_CHAR(ElementName)) {
8009467b48Spatrick return true;
8109467b48Spatrick }
8209467b48Spatrick }
8309467b48Spatrick return false;
8409467b48Spatrick }
8509467b48Spatrick
getChildWithName(xmlNodePtr Parent,const unsigned char * ElementName)8609467b48Spatrick static xmlNodePtr getChildWithName(xmlNodePtr Parent,
8709467b48Spatrick const unsigned char *ElementName) {
8809467b48Spatrick for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
8909467b48Spatrick if (xmlStringsEqual(Child->name, ElementName)) {
9009467b48Spatrick return Child;
9109467b48Spatrick }
9209467b48Spatrick }
9309467b48Spatrick return nullptr;
9409467b48Spatrick }
9509467b48Spatrick
getAttribute(xmlNodePtr Node,const unsigned char * AttributeName)9609467b48Spatrick static xmlAttrPtr getAttribute(xmlNodePtr Node,
9709467b48Spatrick const unsigned char *AttributeName) {
9809467b48Spatrick for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
9909467b48Spatrick Attribute = Attribute->next) {
10009467b48Spatrick if (xmlStringsEqual(Attribute->name, AttributeName)) {
10109467b48Spatrick return Attribute;
10209467b48Spatrick }
10309467b48Spatrick }
10409467b48Spatrick return nullptr;
10509467b48Spatrick }
10609467b48Spatrick
10709467b48Spatrick // Check if namespace specified by HRef1 overrides that of HRef2.
namespaceOverrides(const unsigned char * HRef1,const unsigned char * HRef2)10809467b48Spatrick static bool namespaceOverrides(const unsigned char *HRef1,
10909467b48Spatrick const unsigned char *HRef2) {
11009467b48Spatrick auto HRef1Position = llvm::find_if(
11109467b48Spatrick MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
11209467b48Spatrick return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
11309467b48Spatrick });
11409467b48Spatrick auto HRef2Position = llvm::find_if(
11509467b48Spatrick MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
11609467b48Spatrick return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
11709467b48Spatrick });
11809467b48Spatrick return HRef1Position < HRef2Position;
11909467b48Spatrick }
12009467b48Spatrick
12109467b48Spatrick // Search for prefix-defined namespace specified by HRef, starting on Node and
12209467b48Spatrick // continuing recursively upwards. Returns the namespace or nullptr if not
12309467b48Spatrick // found.
search(const unsigned char * HRef,xmlNodePtr Node)12409467b48Spatrick static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
12509467b48Spatrick for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
12609467b48Spatrick if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
12709467b48Spatrick return Def;
12809467b48Spatrick }
12909467b48Spatrick }
13009467b48Spatrick if (Node->parent) {
13109467b48Spatrick return search(HRef, Node->parent);
13209467b48Spatrick }
13309467b48Spatrick return nullptr;
13409467b48Spatrick }
13509467b48Spatrick
13609467b48Spatrick // Return the prefix that corresponds to the HRef. If HRef is not a recognized
13709467b48Spatrick // URI, then just return the HRef itself to use as the prefix.
getPrefixForHref(const unsigned char * HRef)13809467b48Spatrick static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
13909467b48Spatrick for (auto &Ns : MtNsHrefsPrefixes) {
14009467b48Spatrick if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
14109467b48Spatrick return TO_XML_CHAR(Ns.second.data());
14209467b48Spatrick }
14309467b48Spatrick }
14409467b48Spatrick return HRef;
14509467b48Spatrick }
14609467b48Spatrick
14709467b48Spatrick // Search for prefix-defined namespace specified by HRef, starting on Node and
14809467b48Spatrick // continuing recursively upwards. If it is found, then return it. If it is
14909467b48Spatrick // not found, then prefix-define that namespace on the node and return a
15009467b48Spatrick // reference to it.
searchOrDefine(const unsigned char * HRef,xmlNodePtr Node)15109467b48Spatrick static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
15209467b48Spatrick xmlNodePtr Node) {
15309467b48Spatrick if (xmlNsPtr Def = search(HRef, Node))
15409467b48Spatrick return Def;
15509467b48Spatrick if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
15609467b48Spatrick return Def;
15709467b48Spatrick return make_error<WindowsManifestError>("failed to create new namespace");
15809467b48Spatrick }
15909467b48Spatrick
16009467b48Spatrick // Set the namespace of OrigionalAttribute on OriginalNode to be that of
16109467b48Spatrick // AdditionalAttribute's.
copyAttributeNamespace(xmlAttrPtr OriginalAttribute,xmlNodePtr OriginalNode,xmlAttrPtr AdditionalAttribute)16209467b48Spatrick static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
16309467b48Spatrick xmlNodePtr OriginalNode,
16409467b48Spatrick xmlAttrPtr AdditionalAttribute) {
16509467b48Spatrick
16609467b48Spatrick Expected<xmlNsPtr> ExplicitOrError =
16709467b48Spatrick searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
16809467b48Spatrick if (!ExplicitOrError)
16909467b48Spatrick return ExplicitOrError.takeError();
17009467b48Spatrick OriginalAttribute->ns = std::move(ExplicitOrError.get());
17109467b48Spatrick return Error::success();
17209467b48Spatrick }
17309467b48Spatrick
17409467b48Spatrick // Return the corresponding namespace definition for the prefix, defined on the
17509467b48Spatrick // given Node. Returns nullptr if there is no such definition.
getNamespaceWithPrefix(const unsigned char * Prefix,xmlNodePtr Node)17609467b48Spatrick static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
17709467b48Spatrick xmlNodePtr Node) {
17809467b48Spatrick if (Node == nullptr)
17909467b48Spatrick return nullptr;
18009467b48Spatrick for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
18109467b48Spatrick if (xmlStringsEqual(Def->prefix, Prefix)) {
18209467b48Spatrick return Def;
18309467b48Spatrick }
18409467b48Spatrick }
18509467b48Spatrick return nullptr;
18609467b48Spatrick }
18709467b48Spatrick
18809467b48Spatrick // Search for the closest inheritable default namespace, starting on (and
18909467b48Spatrick // including) the Node and traveling upwards through parent nodes. Returns
19009467b48Spatrick // nullptr if there are no inheritable default namespaces.
getClosestDefault(xmlNodePtr Node)19109467b48Spatrick static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
19209467b48Spatrick if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
19309467b48Spatrick return Ret;
19409467b48Spatrick if (Node->parent == nullptr)
19509467b48Spatrick return nullptr;
19609467b48Spatrick return getClosestDefault(Node->parent);
19709467b48Spatrick }
19809467b48Spatrick
19909467b48Spatrick // Merge the attributes of AdditionalNode into OriginalNode. If attributes
20009467b48Spatrick // with identical types are present, they are not duplicated but rather if
20109467b48Spatrick // their values are not consistent and error is thrown. In addition, the
20209467b48Spatrick // higher priority namespace is used for each attribute, EXCEPT in the case
20309467b48Spatrick // of merging two default namespaces and the lower priority namespace
20409467b48Spatrick // definition occurs closer than the higher priority one.
mergeAttributes(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)20509467b48Spatrick static Error mergeAttributes(xmlNodePtr OriginalNode,
20609467b48Spatrick xmlNodePtr AdditionalNode) {
20709467b48Spatrick xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
20809467b48Spatrick for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
20909467b48Spatrick Attribute = Attribute->next) {
21009467b48Spatrick if (xmlAttrPtr OriginalAttribute =
21109467b48Spatrick getAttribute(OriginalNode, Attribute->name)) {
21209467b48Spatrick if (!xmlStringsEqual(OriginalAttribute->children->content,
21309467b48Spatrick Attribute->children->content)) {
21409467b48Spatrick return make_error<WindowsManifestError>(
21509467b48Spatrick Twine("conflicting attributes for ") +
21609467b48Spatrick FROM_XML_CHAR(OriginalNode->name));
21709467b48Spatrick }
21809467b48Spatrick if (!Attribute->ns) {
21909467b48Spatrick continue;
22009467b48Spatrick }
22109467b48Spatrick if (!OriginalAttribute->ns) {
22209467b48Spatrick if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
22309467b48Spatrick Attribute)) {
22409467b48Spatrick return E;
22509467b48Spatrick }
22609467b48Spatrick continue;
22709467b48Spatrick }
22809467b48Spatrick if (namespaceOverrides(OriginalAttribute->ns->href,
22909467b48Spatrick Attribute->ns->href)) {
23009467b48Spatrick // In this case, the original attribute has a higher priority namespace
23109467b48Spatrick // than the incomiing attribute, however the namespace definition of
23209467b48Spatrick // the lower priority namespace occurs first traveling upwards in the
23309467b48Spatrick // tree. Therefore the lower priority namespace is applied.
23409467b48Spatrick if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
23509467b48Spatrick ClosestDefault &&
23609467b48Spatrick xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
23709467b48Spatrick if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
23809467b48Spatrick Attribute)) {
23909467b48Spatrick return E;
24009467b48Spatrick }
24109467b48Spatrick continue;
24209467b48Spatrick }
24309467b48Spatrick continue;
24409467b48Spatrick // This covers the case where the incoming attribute has the higher
24509467b48Spatrick // priority. The higher priority namespace is applied in all cases
24609467b48Spatrick // EXCEPT when both of the namespaces are default inherited, and the
24709467b48Spatrick // closest inherited default is the lower priority one.
24809467b48Spatrick }
24909467b48Spatrick if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
25009467b48Spatrick (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
25109467b48Spatrick ClosestDefault->href))) {
25209467b48Spatrick if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
25309467b48Spatrick Attribute)) {
25409467b48Spatrick return E;
25509467b48Spatrick }
25609467b48Spatrick continue;
25709467b48Spatrick }
25809467b48Spatrick continue;
25909467b48Spatrick }
26009467b48Spatrick // If the incoming attribute is not already found on the node, append it
26109467b48Spatrick // to the end of the properties list. Also explicitly apply its
26209467b48Spatrick // namespace as a prefix because it might be contained in a separate
26309467b48Spatrick // namespace that doesn't use the attribute.
26409467b48Spatrick xmlAttrPtr NewProp =
26509467b48Spatrick xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
26609467b48Spatrick Expected<xmlNsPtr> ExplicitOrError =
26709467b48Spatrick searchOrDefine(Attribute->ns->href, OriginalNode);
26809467b48Spatrick if (!ExplicitOrError)
26909467b48Spatrick return ExplicitOrError.takeError();
27009467b48Spatrick NewProp->ns = std::move(ExplicitOrError.get());
27109467b48Spatrick }
27209467b48Spatrick return Error::success();
27309467b48Spatrick }
27409467b48Spatrick
27509467b48Spatrick // Given two nodes, return the one with the higher priority namespace.
getDominantNode(xmlNodePtr Node1,xmlNodePtr Node2)27609467b48Spatrick static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
27709467b48Spatrick
27809467b48Spatrick if (!Node1 || !Node1->ns)
27909467b48Spatrick return Node2;
28009467b48Spatrick if (!Node2 || !Node2->ns)
28109467b48Spatrick return Node1;
28209467b48Spatrick if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
28309467b48Spatrick return Node1;
28409467b48Spatrick return Node2;
28509467b48Spatrick }
28609467b48Spatrick
28709467b48Spatrick // Checks if this Node's namespace is inherited or one it defined itself.
hasInheritedNs(xmlNodePtr Node)28809467b48Spatrick static bool hasInheritedNs(xmlNodePtr Node) {
28909467b48Spatrick return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
29009467b48Spatrick }
29109467b48Spatrick
29209467b48Spatrick // Check if this Node's namespace is a default namespace that it inherited, as
29309467b48Spatrick // opposed to defining itself.
hasInheritedDefaultNs(xmlNodePtr Node)29409467b48Spatrick static bool hasInheritedDefaultNs(xmlNodePtr Node) {
29509467b48Spatrick return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
29609467b48Spatrick }
29709467b48Spatrick
29809467b48Spatrick // Check if this Node's namespace is a default namespace it defined itself.
hasDefinedDefaultNamespace(xmlNodePtr Node)29909467b48Spatrick static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
30009467b48Spatrick return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
30109467b48Spatrick }
30209467b48Spatrick
30309467b48Spatrick // For the given explicit prefix-definition of a namespace, travel downwards
30409467b48Spatrick // from a node recursively, and for every implicit, inherited default usage of
30509467b48Spatrick // that namespace replace it with that explicit prefix use. This is important
30609467b48Spatrick // when namespace overriding occurs when merging, so that elements unique to a
30709467b48Spatrick // namespace will still stay in that namespace.
explicateNamespace(xmlNsPtr PrefixDef,xmlNodePtr Node)30809467b48Spatrick static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
30909467b48Spatrick // If a node as its own default namespace definition it clearly cannot have
31009467b48Spatrick // inherited the given default namespace, and neither will any of its
31109467b48Spatrick // children.
31209467b48Spatrick if (hasDefinedDefaultNamespace(Node))
31309467b48Spatrick return;
31409467b48Spatrick if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
31509467b48Spatrick hasInheritedDefaultNs(Node))
31609467b48Spatrick Node->ns = PrefixDef;
31709467b48Spatrick for (xmlAttrPtr Attribute = Node->properties; Attribute;
31809467b48Spatrick Attribute = Attribute->next) {
31909467b48Spatrick if (Attribute->ns &&
32009467b48Spatrick xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
32109467b48Spatrick Attribute->ns = PrefixDef;
32209467b48Spatrick }
32309467b48Spatrick }
32409467b48Spatrick for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
32509467b48Spatrick explicateNamespace(PrefixDef, Child);
32609467b48Spatrick }
32709467b48Spatrick }
32809467b48Spatrick
32909467b48Spatrick // Perform the namespace merge between two nodes.
mergeNamespaces(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)33009467b48Spatrick static Error mergeNamespaces(xmlNodePtr OriginalNode,
33109467b48Spatrick xmlNodePtr AdditionalNode) {
33209467b48Spatrick // Save the original default namespace definition in case the incoming node
33309467b48Spatrick // overrides it.
33409467b48Spatrick const unsigned char *OriginalDefinedDefaultHref = nullptr;
33509467b48Spatrick if (xmlNsPtr OriginalDefinedDefaultNs =
33609467b48Spatrick getNamespaceWithPrefix(nullptr, OriginalNode)) {
33709467b48Spatrick OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
33809467b48Spatrick }
33909467b48Spatrick const unsigned char *NewDefinedDefaultHref = nullptr;
34009467b48Spatrick // Copy all namespace definitions. There can only be one default namespace
34109467b48Spatrick // definition per node, so the higher priority one takes precedence in the
34209467b48Spatrick // case of collision.
34309467b48Spatrick for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
34409467b48Spatrick if (xmlNsPtr OriginalNsDef =
34509467b48Spatrick getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
34609467b48Spatrick if (!Def->prefix) {
34709467b48Spatrick if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
34809467b48Spatrick NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
34909467b48Spatrick }
35009467b48Spatrick } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
35109467b48Spatrick return make_error<WindowsManifestError>(
35209467b48Spatrick Twine("conflicting namespace definitions for ") +
35309467b48Spatrick FROM_XML_CHAR(Def->prefix));
35409467b48Spatrick }
35509467b48Spatrick } else {
35609467b48Spatrick xmlNsPtr NewDef = xmlCopyNamespace(Def);
35709467b48Spatrick NewDef->next = OriginalNode->nsDef;
35809467b48Spatrick OriginalNode->nsDef = NewDef;
35909467b48Spatrick }
36009467b48Spatrick }
36109467b48Spatrick
36209467b48Spatrick // Check whether the original node or the incoming node has the higher
36309467b48Spatrick // priority namespace. Depending on which one is dominant, we will have
36409467b48Spatrick // to recursively apply namespace changes down to children of the original
36509467b48Spatrick // node.
36609467b48Spatrick xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
36709467b48Spatrick xmlNodePtr NonDominantNode =
36809467b48Spatrick DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
36909467b48Spatrick if (DominantNode == OriginalNode) {
37009467b48Spatrick if (OriginalDefinedDefaultHref) {
37109467b48Spatrick xmlNsPtr NonDominantDefinedDefault =
37209467b48Spatrick getNamespaceWithPrefix(nullptr, NonDominantNode);
37309467b48Spatrick // In this case, both the nodes defined a default namespace. However
37409467b48Spatrick // the lower priority node ended up having a higher priority default
37509467b48Spatrick // definition. This can occur if the higher priority node is prefix
37609467b48Spatrick // namespace defined. In this case we have to define an explicit
37709467b48Spatrick // prefix for the overridden definition and apply it to all children
37809467b48Spatrick // who relied on that definition.
37909467b48Spatrick if (NonDominantDefinedDefault &&
38009467b48Spatrick namespaceOverrides(NonDominantDefinedDefault->href,
38109467b48Spatrick OriginalDefinedDefaultHref)) {
38209467b48Spatrick Expected<xmlNsPtr> EC =
38309467b48Spatrick searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
38409467b48Spatrick if (!EC) {
38509467b48Spatrick return EC.takeError();
38609467b48Spatrick }
38709467b48Spatrick xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
38809467b48Spatrick explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
38909467b48Spatrick }
39009467b48Spatrick // In this case the node with a higher priority namespace did not have a
39109467b48Spatrick // default namespace definition, but the lower priority node did. In this
39209467b48Spatrick // case the new default namespace definition is copied. A side effect of
39309467b48Spatrick // this is that all children will suddenly find themselves in a different
39409467b48Spatrick // default namespace. To maintain correctness we need to ensure that all
39509467b48Spatrick // children now explicitly refer to the namespace that they had previously
39609467b48Spatrick // implicitly inherited.
39709467b48Spatrick } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
39809467b48Spatrick if (DominantNode->parent) {
39909467b48Spatrick xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
40009467b48Spatrick Expected<xmlNsPtr> EC =
40109467b48Spatrick searchOrDefine(ClosestDefault->href, DominantNode);
40209467b48Spatrick if (!EC) {
40309467b48Spatrick return EC.takeError();
40409467b48Spatrick }
40509467b48Spatrick xmlNsPtr ExplicitDefault = std::move(EC.get());
40609467b48Spatrick explicateNamespace(ExplicitDefault, DominantNode);
40709467b48Spatrick }
40809467b48Spatrick }
40909467b48Spatrick } else {
41009467b48Spatrick // Covers case where the incoming node has a default namespace definition
41109467b48Spatrick // that overrides the original node's namespace. This always leads to
41209467b48Spatrick // the original node receiving that new default namespace.
41309467b48Spatrick if (hasDefinedDefaultNamespace(DominantNode)) {
41409467b48Spatrick NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
41509467b48Spatrick } else {
41609467b48Spatrick // This covers the case where the incoming node either has a prefix
41709467b48Spatrick // namespace, or an inherited default namespace. Since the namespace
41809467b48Spatrick // may not yet be defined in the original tree we do a searchOrDefine
41909467b48Spatrick // for it, and then set the namespace equal to it.
42009467b48Spatrick Expected<xmlNsPtr> EC =
42109467b48Spatrick searchOrDefine(DominantNode->ns->href, NonDominantNode);
42209467b48Spatrick if (!EC) {
42309467b48Spatrick return EC.takeError();
42409467b48Spatrick }
42509467b48Spatrick xmlNsPtr Explicit = std::move(EC.get());
42609467b48Spatrick NonDominantNode->ns = Explicit;
42709467b48Spatrick }
42809467b48Spatrick // This covers cases where the incoming dominant node HAS a default
42909467b48Spatrick // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
43009467b48Spatrick if (xmlNsPtr DominantDefaultDefined =
43109467b48Spatrick getNamespaceWithPrefix(nullptr, DominantNode)) {
43209467b48Spatrick if (OriginalDefinedDefaultHref) {
43309467b48Spatrick if (namespaceOverrides(DominantDefaultDefined->href,
43409467b48Spatrick OriginalDefinedDefaultHref)) {
43509467b48Spatrick // In this case, the incoming node's default definition overrides
43609467b48Spatrick // the original default definition, all children who relied on that
43709467b48Spatrick // definition must be updated accordingly.
43809467b48Spatrick Expected<xmlNsPtr> EC =
43909467b48Spatrick searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
44009467b48Spatrick if (!EC) {
44109467b48Spatrick return EC.takeError();
44209467b48Spatrick }
44309467b48Spatrick xmlNsPtr ExplicitDefault = std::move(EC.get());
44409467b48Spatrick explicateNamespace(ExplicitDefault, NonDominantNode);
44509467b48Spatrick }
44609467b48Spatrick } else {
44709467b48Spatrick // The original did not define a default definition, however the new
44809467b48Spatrick // default definition still applies to all children, so they must be
44909467b48Spatrick // updated to explicitly refer to the namespace they had previously
45009467b48Spatrick // been inheriting implicitly.
45109467b48Spatrick xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
45209467b48Spatrick Expected<xmlNsPtr> EC =
45309467b48Spatrick searchOrDefine(ClosestDefault->href, NonDominantNode);
45409467b48Spatrick if (!EC) {
45509467b48Spatrick return EC.takeError();
45609467b48Spatrick }
45709467b48Spatrick xmlNsPtr ExplicitDefault = std::move(EC.get());
45809467b48Spatrick explicateNamespace(ExplicitDefault, NonDominantNode);
45909467b48Spatrick }
46009467b48Spatrick }
46109467b48Spatrick }
46209467b48Spatrick if (NewDefinedDefaultHref) {
46309467b48Spatrick xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
46409467b48Spatrick xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
46509467b48Spatrick OriginalNsDef->href = NewDefinedDefaultHref;
46609467b48Spatrick }
46709467b48Spatrick xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
46809467b48Spatrick return Error::success();
46909467b48Spatrick }
47009467b48Spatrick
isRecognizedNamespace(const unsigned char * NsHref)47109467b48Spatrick static bool isRecognizedNamespace(const unsigned char *NsHref) {
47209467b48Spatrick for (auto &Ns : MtNsHrefsPrefixes) {
47309467b48Spatrick if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
47409467b48Spatrick return true;
47509467b48Spatrick }
47609467b48Spatrick }
47709467b48Spatrick return false;
47809467b48Spatrick }
47909467b48Spatrick
hasRecognizedNamespace(xmlNodePtr Node)48009467b48Spatrick static bool hasRecognizedNamespace(xmlNodePtr Node) {
48109467b48Spatrick return isRecognizedNamespace(Node->ns->href);
48209467b48Spatrick }
48309467b48Spatrick
48409467b48Spatrick // Ensure a node's inherited namespace is actually defined in the tree it
48509467b48Spatrick // resides in.
reconcileNamespaces(xmlNodePtr Node)48609467b48Spatrick static Error reconcileNamespaces(xmlNodePtr Node) {
48709467b48Spatrick if (!Node) {
48809467b48Spatrick return Error::success();
48909467b48Spatrick }
49009467b48Spatrick if (hasInheritedNs(Node)) {
49109467b48Spatrick Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
49209467b48Spatrick if (!ExplicitOrError) {
49309467b48Spatrick return ExplicitOrError.takeError();
49409467b48Spatrick }
49509467b48Spatrick xmlNsPtr Explicit = std::move(ExplicitOrError.get());
49609467b48Spatrick Node->ns = Explicit;
49709467b48Spatrick }
49809467b48Spatrick for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
49909467b48Spatrick if (auto E = reconcileNamespaces(Child)) {
50009467b48Spatrick return E;
50109467b48Spatrick }
50209467b48Spatrick }
50309467b48Spatrick return Error::success();
50409467b48Spatrick }
50509467b48Spatrick
50609467b48Spatrick // Recursively merge the two given manifest trees, depending on which elements
50709467b48Spatrick // are of a mergeable type, and choose namespaces according to which have
50809467b48Spatrick // higher priority.
treeMerge(xmlNodePtr OriginalRoot,xmlNodePtr AdditionalRoot)50909467b48Spatrick static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
51009467b48Spatrick if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
51109467b48Spatrick return E;
51209467b48Spatrick if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
51309467b48Spatrick return E;
51409467b48Spatrick xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
51509467b48Spatrick xmlNode StoreNext;
51609467b48Spatrick for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
51709467b48Spatrick xmlNodePtr OriginalChildWithName;
51809467b48Spatrick if (!isMergeableElement(Child->name) ||
51909467b48Spatrick !(OriginalChildWithName =
52009467b48Spatrick getChildWithName(OriginalRoot, Child->name)) ||
52109467b48Spatrick !hasRecognizedNamespace(Child)) {
52209467b48Spatrick StoreNext.next = Child->next;
52309467b48Spatrick xmlUnlinkNode(Child);
52409467b48Spatrick if (!xmlAddChild(OriginalRoot, Child)) {
52509467b48Spatrick return make_error<WindowsManifestError>(Twine("could not merge ") +
52609467b48Spatrick FROM_XML_CHAR(Child->name));
52709467b48Spatrick }
52809467b48Spatrick if (auto E = reconcileNamespaces(Child)) {
52909467b48Spatrick return E;
53009467b48Spatrick }
53109467b48Spatrick Child = &StoreNext;
53209467b48Spatrick } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
53309467b48Spatrick return E;
53409467b48Spatrick }
53509467b48Spatrick }
53609467b48Spatrick return Error::success();
53709467b48Spatrick }
53809467b48Spatrick
stripComments(xmlNodePtr Root)53909467b48Spatrick static void stripComments(xmlNodePtr Root) {
54009467b48Spatrick xmlNode StoreNext;
54109467b48Spatrick for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
54209467b48Spatrick if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
54309467b48Spatrick stripComments(Child);
54409467b48Spatrick continue;
54509467b48Spatrick }
54609467b48Spatrick StoreNext.next = Child->next;
54709467b48Spatrick xmlNodePtr Remove = Child;
54809467b48Spatrick Child = &StoreNext;
54909467b48Spatrick xmlUnlinkNode(Remove);
55009467b48Spatrick xmlFreeNode(Remove);
55109467b48Spatrick }
55209467b48Spatrick }
55309467b48Spatrick
55409467b48Spatrick // libxml2 assumes that attributes do not inherit default namespaces, whereas
55509467b48Spatrick // the original mt.exe does make this assumption. This function reconciles
55609467b48Spatrick // this by setting all attributes to have the inherited default namespace.
setAttributeNamespaces(xmlNodePtr Node)55709467b48Spatrick static void setAttributeNamespaces(xmlNodePtr Node) {
55809467b48Spatrick for (xmlAttrPtr Attribute = Node->properties; Attribute;
55909467b48Spatrick Attribute = Attribute->next) {
56009467b48Spatrick if (!Attribute->ns) {
56109467b48Spatrick Attribute->ns = getClosestDefault(Node);
56209467b48Spatrick }
56309467b48Spatrick }
56409467b48Spatrick for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
56509467b48Spatrick setAttributeNamespaces(Child);
56609467b48Spatrick }
56709467b48Spatrick }
56809467b48Spatrick
56909467b48Spatrick // The merging process may create too many prefix defined namespaces. This
57009467b48Spatrick // function removes all unnecessary ones from the tree.
checkAndStripPrefixes(xmlNodePtr Node,std::vector<xmlNsPtr> & RequiredPrefixes)57109467b48Spatrick static void checkAndStripPrefixes(xmlNodePtr Node,
57209467b48Spatrick std::vector<xmlNsPtr> &RequiredPrefixes) {
57309467b48Spatrick for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
57409467b48Spatrick checkAndStripPrefixes(Child, RequiredPrefixes);
57509467b48Spatrick }
57609467b48Spatrick if (Node->ns && Node->ns->prefix != nullptr) {
57709467b48Spatrick xmlNsPtr ClosestDefault = getClosestDefault(Node);
57809467b48Spatrick if (ClosestDefault &&
57909467b48Spatrick xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
58009467b48Spatrick Node->ns = ClosestDefault;
58109467b48Spatrick } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
58209467b48Spatrick RequiredPrefixes.push_back(Node->ns);
58309467b48Spatrick }
58409467b48Spatrick }
58509467b48Spatrick for (xmlAttrPtr Attribute = Node->properties; Attribute;
58609467b48Spatrick Attribute = Attribute->next) {
58709467b48Spatrick if (Attribute->ns && Attribute->ns->prefix != nullptr) {
58809467b48Spatrick xmlNsPtr ClosestDefault = getClosestDefault(Node);
58909467b48Spatrick if (ClosestDefault &&
59009467b48Spatrick xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
59109467b48Spatrick Attribute->ns = ClosestDefault;
59209467b48Spatrick } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
59309467b48Spatrick RequiredPrefixes.push_back(Attribute->ns);
59409467b48Spatrick }
59509467b48Spatrick }
59609467b48Spatrick }
59709467b48Spatrick xmlNsPtr Prev;
59809467b48Spatrick xmlNs Temp;
59909467b48Spatrick for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
60009467b48Spatrick if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
60109467b48Spatrick Prev = Def;
60209467b48Spatrick continue;
60309467b48Spatrick }
60409467b48Spatrick if (Def == Node->nsDef) {
60509467b48Spatrick Node->nsDef = Def->next;
60609467b48Spatrick } else {
60709467b48Spatrick Prev->next = Def->next;
60809467b48Spatrick }
60909467b48Spatrick Temp.next = Def->next;
61009467b48Spatrick xmlFreeNs(Def);
61109467b48Spatrick Def = &Temp;
61209467b48Spatrick }
61309467b48Spatrick }
61409467b48Spatrick
~WindowsManifestMergerImpl()61509467b48Spatrick WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
61609467b48Spatrick for (auto &Doc : MergedDocs)
61709467b48Spatrick xmlFreeDoc(Doc);
61809467b48Spatrick }
61909467b48Spatrick
merge(MemoryBufferRef Manifest)62009467b48Spatrick Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
621*d415bd75Srobert MemoryBufferRef Manifest) {
62209467b48Spatrick if (Merged)
62309467b48Spatrick return make_error<WindowsManifestError>(
62409467b48Spatrick "merge after getMergedManifest is not supported");
62509467b48Spatrick if (Manifest.getBufferSize() == 0)
62609467b48Spatrick return make_error<WindowsManifestError>(
62709467b48Spatrick "attempted to merge empty manifest");
62809467b48Spatrick xmlSetGenericErrorFunc((void *)this,
62909467b48Spatrick WindowsManifestMergerImpl::errorCallback);
63009467b48Spatrick xmlDocPtr ManifestXML = xmlReadMemory(
63109467b48Spatrick Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml",
63209467b48Spatrick nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT);
63309467b48Spatrick xmlSetGenericErrorFunc(nullptr, nullptr);
63409467b48Spatrick if (auto E = getParseError())
63509467b48Spatrick return E;
63609467b48Spatrick xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
63709467b48Spatrick stripComments(AdditionalRoot);
63809467b48Spatrick setAttributeNamespaces(AdditionalRoot);
63909467b48Spatrick if (CombinedDoc == nullptr) {
64009467b48Spatrick CombinedDoc = ManifestXML;
64109467b48Spatrick } else {
64209467b48Spatrick xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
64309467b48Spatrick if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
64409467b48Spatrick !isMergeableElement(AdditionalRoot->name) ||
64509467b48Spatrick !hasRecognizedNamespace(AdditionalRoot)) {
64609467b48Spatrick return make_error<WindowsManifestError>("multiple root nodes");
64709467b48Spatrick }
64809467b48Spatrick if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
64909467b48Spatrick return E;
65009467b48Spatrick }
65109467b48Spatrick }
65209467b48Spatrick MergedDocs.push_back(ManifestXML);
65309467b48Spatrick return Error::success();
65409467b48Spatrick }
65509467b48Spatrick
65609467b48Spatrick std::unique_ptr<MemoryBuffer>
getMergedManifest()65709467b48Spatrick WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
65809467b48Spatrick if (!Merged) {
65909467b48Spatrick Merged = true;
66009467b48Spatrick
66109467b48Spatrick if (!CombinedDoc)
66209467b48Spatrick return nullptr;
66309467b48Spatrick
66409467b48Spatrick xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
66509467b48Spatrick std::vector<xmlNsPtr> RequiredPrefixes;
66609467b48Spatrick checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
66709467b48Spatrick std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
66809467b48Spatrick xmlNewDoc((const unsigned char *)"1.0"));
66909467b48Spatrick xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
670*d415bd75Srobert assert(nullptr == xmlDocGetRootElement(CombinedDoc));
67109467b48Spatrick
67209467b48Spatrick xmlKeepBlanksDefault(0);
67309467b48Spatrick xmlChar *Buff = nullptr;
67409467b48Spatrick xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1);
67509467b48Spatrick Buffer.reset(Buff);
67609467b48Spatrick }
67709467b48Spatrick
67809467b48Spatrick return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef(
67909467b48Spatrick FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize))
68009467b48Spatrick : nullptr;
68109467b48Spatrick }
68209467b48Spatrick
isAvailable()68309467b48Spatrick bool windows_manifest::isAvailable() { return true; }
68409467b48Spatrick
68509467b48Spatrick #else
68609467b48Spatrick
~WindowsManifestMergerImpl()68709467b48Spatrick WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
68809467b48Spatrick }
68909467b48Spatrick
merge(MemoryBufferRef Manifest)69009467b48Spatrick Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
691*d415bd75Srobert MemoryBufferRef Manifest) {
69209467b48Spatrick return make_error<WindowsManifestError>("no libxml2");
69309467b48Spatrick }
69409467b48Spatrick
69509467b48Spatrick std::unique_ptr<MemoryBuffer>
getMergedManifest()69609467b48Spatrick WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
69709467b48Spatrick return nullptr;
69809467b48Spatrick }
69909467b48Spatrick
isAvailable()70009467b48Spatrick bool windows_manifest::isAvailable() { return false; }
70109467b48Spatrick
70209467b48Spatrick #endif
70309467b48Spatrick
WindowsManifestMerger()70409467b48Spatrick WindowsManifestMerger::WindowsManifestMerger()
70509467b48Spatrick : Impl(std::make_unique<WindowsManifestMergerImpl>()) {}
70609467b48Spatrick
707*d415bd75Srobert WindowsManifestMerger::~WindowsManifestMerger() = default;
70809467b48Spatrick
merge(MemoryBufferRef Manifest)709*d415bd75Srobert Error WindowsManifestMerger::merge(MemoryBufferRef Manifest) {
71009467b48Spatrick return Impl->merge(Manifest);
71109467b48Spatrick }
71209467b48Spatrick
getMergedManifest()71309467b48Spatrick std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
71409467b48Spatrick return Impl->getMergedManifest();
71509467b48Spatrick }
71609467b48Spatrick
errorCallback(void * Ctx,const char * Format,...)71709467b48Spatrick void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
71809467b48Spatrick void *Ctx, const char *Format, ...) {
71909467b48Spatrick auto *Merger = (WindowsManifestMergerImpl *)Ctx;
72009467b48Spatrick Merger->ParseErrorOccurred = true;
72109467b48Spatrick }
72209467b48Spatrick
getParseError()72309467b48Spatrick Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
72409467b48Spatrick if (!ParseErrorOccurred)
72509467b48Spatrick return Error::success();
72609467b48Spatrick return make_error<WindowsManifestError>("invalid xml document");
72709467b48Spatrick }
728