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