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