xref: /freebsd/contrib/llvm-project/llvm/lib/WindowsManifest/WindowsManifestMerger.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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-exception
6 //
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_LIBXML2
18 #include <libxml/xmlreader.h>
19 #endif
20 
21 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
22 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
23 
24 using namespace llvm;
25 using namespace windows_manifest;
26 
27 char WindowsManifestError::ID = 0;
28 
WindowsManifestError(const Twine & Msg)29 WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
30 
log(raw_ostream & OS) const31 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
32 
33 class WindowsManifestMerger::WindowsManifestMergerImpl {
34 public:
35   Error merge(MemoryBufferRef Manifest);
36   std::unique_ptr<MemoryBuffer> getMergedManifest();
37 
38 private:
39   static void errorCallback(void *Ctx, const char *Format, ...);
40   Error getParseError();
41 #if LLVM_ENABLE_LIBXML2
42   struct XmlDeleter {
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter43     void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter44     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 #endif
52   bool ParseErrorOccurred = false;
53 };
54 
55 #if LLVM_ENABLE_LIBXML2
56 
57 static 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 
xmlStringsEqual(const unsigned char * A,const unsigned char * B)65 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
66   // Handle null pointers.  Comparison of 2 null pointers returns true because
67   // 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 
isMergeableElement(const unsigned char * ElementName)73 static 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 
getChildWithName(xmlNodePtr Parent,const unsigned char * ElementName)84 static 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 
getAttribute(xmlNodePtr Node,const unsigned char * AttributeName)94 static 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.
namespaceOverrides(const unsigned char * HRef1,const unsigned char * HRef2)106 static 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 and
120 // continuing recursively upwards.  Returns the namespace or nullptr if not
121 // found.
search(const unsigned char * HRef,xmlNodePtr Node)122 static 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 recognized
135 // URI, then just return the HRef itself to use as the prefix.
getPrefixForHref(const unsigned char * HRef)136 static 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 and
146 // continuing recursively upwards.  If it is found, then return it.  If it is
147 // not found, then prefix-define that namespace on the node and return a
148 // reference to it.
searchOrDefine(const unsigned char * HRef,xmlNodePtr Node)149 static 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 of
159 // AdditionalAttribute's.
copyAttributeNamespace(xmlAttrPtr OriginalAttribute,xmlNodePtr OriginalNode,xmlAttrPtr AdditionalAttribute)160 static 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 the
173 // given Node.  Returns nullptr if there is no such definition.
getNamespaceWithPrefix(const unsigned char * Prefix,xmlNodePtr Node)174 static 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 (and
187 // including) the Node and traveling upwards through parent nodes.  Returns
188 // nullptr if there are no inheritable default namespaces.
getClosestDefault(xmlNodePtr Node)189 static 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 attributes
198 // with identical types are present, they are not duplicated but rather if
199 // their values are not consistent and error is thrown.  In addition, the
200 // higher priority namespace is used for each attribute, EXCEPT in the case
201 // of merging two default namespaces and the lower priority namespace
202 // definition occurs closer than the higher priority one.
mergeAttributes(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)203 static 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 namespace
229         // than the incomiing attribute, however the namespace definition of
230         // the lower priority namespace occurs first traveling upwards in the
231         // 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 higher
243         // priority.  The higher priority namespace is applied in all cases
244         // EXCEPT when both of the namespaces are default inherited, and the
245         // 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 it
259     // to the end of the properties list.  Also explicitly apply its
260     // namespace as a prefix because it might be contained in a separate
261     // 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.
getDominantNode(xmlNodePtr Node1,xmlNodePtr Node2)274 static 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.
hasInheritedNs(xmlNodePtr Node)286 static 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, as
291 // opposed to defining itself.
hasInheritedDefaultNs(xmlNodePtr Node)292 static 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.
hasDefinedDefaultNamespace(xmlNodePtr Node)297 static 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 downwards
302 // from a node recursively, and for every implicit, inherited default usage of
303 // that namespace replace it with that explicit prefix use.  This is important
304 // when namespace overriding occurs when merging, so that elements unique to a
305 // namespace will still stay in that namespace.
explicateNamespace(xmlNsPtr PrefixDef,xmlNodePtr Node)306 static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
307   // If a node as its own default namespace definition it clearly cannot have
308   // inherited the given default namespace, and neither will any of its
309   // 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.
mergeNamespaces(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)328 static Error mergeNamespaces(xmlNodePtr OriginalNode,
329                              xmlNodePtr AdditionalNode) {
330   // Save the original default namespace definition in case the incoming node
331   // 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 namespace
339   // definition per node, so the higher priority one takes precedence in the
340   // 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 higher
361   // priority namespace.  Depending on which one is dominant, we will have
362   // to recursively apply namespace changes down to children of the original
363   // 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.  However
372       // the lower priority node ended up having a higher priority default
373       // definition.  This can occur if the higher priority node is prefix
374       // namespace defined.  In this case we have to define an explicit
375       // prefix for the overridden definition and apply it to all children
376       // 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 a
389       // default namespace definition, but the lower priority node did.  In this
390       // case the new default namespace definition is copied.  A side effect of
391       // this is that all children will suddenly find themselves in a different
392       // default namespace.  To maintain correctness we need to ensure that all
393       // children now explicitly refer to the namespace that they had previously
394       // 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 definition
409     // that overrides the original node's namespace.  This always leads to
410     // 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 prefix
415       // namespace, or an inherited default namespace.  Since the namespace
416       // may not yet be defined in the original tree we do a searchOrDefine
417       // 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 default
427     // 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 overrides
434           // the original default definition, all children who relied on that
435           // 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 new
446         // default definition still applies to all children, so they must be
447         // updated to explicitly refer to the namespace they had previously
448         // 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 
isRecognizedNamespace(const unsigned char * NsHref)469 static 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 
hasRecognizedNamespace(xmlNodePtr Node)478 static 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 it
483 // resides in.
reconcileNamespaces(xmlNodePtr Node)484 static 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 elements
505 // are of a mergeable type, and choose namespaces according to which have
506 // higher priority.
treeMerge(xmlNodePtr OriginalRoot,xmlNodePtr AdditionalRoot)507 static 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 
stripComments(xmlNodePtr Root)537 static 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, whereas
553 // the original  mt.exe does make this assumption.  This function reconciles
554 // this by setting all attributes to have the inherited default namespace.
setAttributeNamespaces(xmlNodePtr Node)555 static 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.  This
568 // function removes all unnecessary ones from the tree.
checkAndStripPrefixes(xmlNodePtr Node,std::vector<xmlNsPtr> & RequiredPrefixes)569 static 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 
merge(MemoryBufferRef Manifest)613 Error 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 
649 std::unique_ptr<MemoryBuffer>
getMergedManifest()650 WindowsManifestMerger::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 
isAvailable()675 bool windows_manifest::isAvailable() { return true; }
676 
677 #else
678 
merge(MemoryBufferRef Manifest)679 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
680     MemoryBufferRef Manifest) {
681   return make_error<WindowsManifestError>("no libxml2");
682 }
683 
684 std::unique_ptr<MemoryBuffer>
getMergedManifest()685 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
686   return nullptr;
687 }
688 
isAvailable()689 bool windows_manifest::isAvailable() { return false; }
690 
691 #endif
692 
WindowsManifestMerger()693 WindowsManifestMerger::WindowsManifestMerger()
694     : Impl(std::make_unique<WindowsManifestMergerImpl>()) {}
695 
696 WindowsManifestMerger::~WindowsManifestMerger() = default;
697 
merge(MemoryBufferRef Manifest)698 Error WindowsManifestMerger::merge(MemoryBufferRef Manifest) {
699   return Impl->merge(Manifest);
700 }
701 
getMergedManifest()702 std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
703   return Impl->getMergedManifest();
704 }
705 
errorCallback(void * Ctx,const char * Format,...)706 void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
707     void *Ctx, const char *Format, ...) {
708   auto *Merger = (WindowsManifestMergerImpl *)Ctx;
709   Merger->ParseErrorOccurred = true;
710 }
711 
getParseError()712 Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
713   if (!ParseErrorOccurred)
714     return Error::success();
715   return make_error<WindowsManifestError>("invalid xml document");
716 }
717