1 //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
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
7 //===---------------------------------------------------------------------===//
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"
19 #if LLVM_LIBXML2_ENABLED
20 #include <libxml/xmlreader.h>
23 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
24 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
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
{
37 ~WindowsManifestMergerImpl();
38 Error
merge(const MemoryBuffer
&Manifest
);
39 std::unique_ptr
<MemoryBuffer
> getMergedManifest();
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
;
50 void operator()(xmlChar
*Ptr
) { xmlFree(Ptr
); }
51 void operator()(xmlDoc
*Ptr
) { xmlFreeDoc(Ptr
); }
54 std::unique_ptr
<xmlChar
, XmlDeleter
> Buffer
;
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.
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
)) {
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
)) {
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
)) {
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
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
)) {
133 return search(HRef
, Node
->parent
);
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());
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
153 static Expected
<xmlNsPtr
> searchOrDefine(const unsigned char *HRef
,
155 if (xmlNsPtr Def
= search(HRef
, Node
))
157 if (xmlNsPtr Def
= xmlNewNs(Node
, HRef
, getPrefixForHref(HRef
)))
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
,
182 for (xmlNsPtr Def
= Node
->nsDef
; Def
; Def
= Def
->next
) {
183 if (xmlStringsEqual(Def
->prefix
, Prefix
)) {
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
))
196 if (Node
->parent
== 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
) {
223 if (!OriginalAttribute
->ns
) {
224 if (auto E
= copyAttributeNamespace(OriginalAttribute
, OriginalNode
,
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
&&
238 xmlStringsEqual(Attribute
->ns
->href
, ClosestDefault
->href
)) {
239 if (auto E
= copyAttributeNamespace(OriginalAttribute
, OriginalNode
,
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
,
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.
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
)
282 if (!Node2
|| !Node2
->ns
)
284 if (namespaceOverrides(Node1
->ns
->href
, Node2
->ns
->href
))
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
314 if (hasDefinedDefaultNamespace(Node
))
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
) {
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
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
)) {
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
));
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
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
);
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
);
405 return EC
.takeError();
407 xmlNsPtr ExplicitDefault
= std::move(EC
.get());
408 explicateNamespace(ExplicitDefault
, DominantNode
);
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
);
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
);
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
);
443 return EC
.takeError();
445 xmlNsPtr ExplicitDefault
= std::move(EC
.get());
446 explicateNamespace(ExplicitDefault
, NonDominantNode
);
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
);
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()))) {
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
488 static Error
reconcileNamespaces(xmlNodePtr 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());
500 for (xmlNodePtr Child
= Node
->children
; Child
; Child
= Child
->next
) {
501 if (auto E
= reconcileNamespaces(Child
)) {
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
511 static Error
treeMerge(xmlNodePtr OriginalRoot
, xmlNodePtr AdditionalRoot
) {
512 if (auto E
= mergeAttributes(OriginalRoot
, AdditionalRoot
))
514 if (auto E
= mergeNamespaces(OriginalRoot
, AdditionalRoot
))
516 xmlNodePtr AdditionalFirstChild
= AdditionalRoot
->children
;
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
)) {
534 } else if (auto E
= treeMerge(OriginalChildWithName
, Child
)) {
538 return Error::success();
541 static void stripComments(xmlNodePtr Root
) {
543 for (xmlNodePtr Child
= Root
->children
; Child
; Child
= Child
->next
) {
544 if (!xmlStringsEqual(Child
->name
, TO_XML_CHAR("comment"))) {
545 stripComments(Child
);
548 StoreNext
.next
= Child
->next
;
549 xmlNodePtr Remove
= Child
;
551 xmlUnlinkNode(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
);
601 for (xmlNsPtr Def
= Node
->nsDef
; Def
; Def
= Def
->next
) {
602 if (!Def
->prefix
|| llvm::is_contained(RequiredPrefixes
, Def
)) {
606 if (Def
== Node
->nsDef
) {
607 Node
->nsDef
= Def
->next
;
609 Prev
->next
= Def
->next
;
611 Temp
.next
= Def
->next
;
617 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
618 for (auto &Doc
: MergedDocs
)
622 Error
WindowsManifestMerger::WindowsManifestMergerImpl::merge(
623 const MemoryBuffer
&Manifest
) {
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())
638 xmlNodePtr AdditionalRoot
= xmlDocGetRootElement(ManifestXML
);
639 stripComments(AdditionalRoot
);
640 setAttributeNamespaces(AdditionalRoot
);
641 if (CombinedDoc
== nullptr) {
642 CombinedDoc
= ManifestXML
;
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
)) {
654 MergedDocs
.push_back(ManifestXML
);
655 return Error::success();
658 std::unique_ptr
<MemoryBuffer
>
659 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
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);
680 return BufferSize
? MemoryBuffer::getMemBufferCopy(StringRef(
681 FROM_XML_CHAR(Buffer
.get()), (size_t)BufferSize
))
685 bool windows_manifest::isAvailable() { return true; }
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() {
702 bool windows_manifest::isAvailable() { return false; }
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");