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