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"
17 #if LLVM_ENABLE_LIBXML2
18 #include <libxml/xmlreader.h>
21 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
22 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
25 using namespace windows_manifest
;
27 char WindowsManifestError::ID
= 0;
29 WindowsManifestError::WindowsManifestError(const Twine
&Msg
) : Msg(Msg
.str()) {}
31 void WindowsManifestError::log(raw_ostream
&OS
) const { OS
<< Msg
; }
33 class WindowsManifestMerger::WindowsManifestMergerImpl
{
35 ~WindowsManifestMergerImpl();
36 Error
merge(MemoryBufferRef Manifest
);
37 std::unique_ptr
<MemoryBuffer
> getMergedManifest();
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
;
48 void operator()(xmlChar
*Ptr
) { xmlFree(Ptr
); }
49 void operator()(xmlDoc
*Ptr
) { xmlFreeDoc(Ptr
); }
52 std::unique_ptr
<xmlChar
, XmlDeleter
> Buffer
;
54 bool ParseErrorOccurred
= false;
57 #if LLVM_ENABLE_LIBXML2
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"}};
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.
72 return strcmp(FROM_XML_CHAR(A
), FROM_XML_CHAR(B
)) == 0;
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
)) {
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
)) {
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
)) {
107 // Check if namespace specified by HRef1 overrides that of 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()));
114 auto HRef2Position
= llvm::find_if(
115 MtNsHrefsPrefixes
, [=](const std::pair
<StringRef
, StringRef
> &Element
) {
116 return xmlStringsEqual(HRef2
, TO_XML_CHAR(Element
.first
.data()));
118 return HRef1Position
< HRef2Position
;
121 // Search for prefix-defined namespace specified by HRef, starting on Node and
122 // continuing recursively upwards. Returns the namespace or nullptr if not
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
)) {
131 return search(HRef
, Node
->parent
);
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.
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());
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
151 static Expected
<xmlNsPtr
> searchOrDefine(const unsigned char *HRef
,
153 if (xmlNsPtr Def
= search(HRef
, Node
))
155 if (xmlNsPtr Def
= xmlNewNs(Node
, HRef
, getPrefixForHref(HRef
)))
157 return make_error
<WindowsManifestError
>("failed to create new namespace");
160 // Set the namespace of OrigionalAttribute on OriginalNode to be that of
161 // AdditionalAttribute's.
162 static Error
copyAttributeNamespace(xmlAttrPtr OriginalAttribute
,
163 xmlNodePtr OriginalNode
,
164 xmlAttrPtr AdditionalAttribute
) {
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();
174 // Return the corresponding namespace definition for the prefix, defined on the
175 // given Node. Returns nullptr if there is no such definition.
176 static xmlNsPtr
getNamespaceWithPrefix(const unsigned char *Prefix
,
180 for (xmlNsPtr Def
= Node
->nsDef
; Def
; Def
= Def
->next
) {
181 if (xmlStringsEqual(Def
->prefix
, Prefix
)) {
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.
191 static xmlNsPtr
getClosestDefault(xmlNodePtr Node
) {
192 if (xmlNsPtr Ret
= getNamespaceWithPrefix(nullptr, Node
))
194 if (Node
->parent
== nullptr)
196 return getClosestDefault(Node
->parent
);
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.
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
));
218 if (!Attribute
->ns
) {
221 if (!OriginalAttribute
->ns
) {
222 if (auto E
= copyAttributeNamespace(OriginalAttribute
, OriginalNode
,
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
&&
236 xmlStringsEqual(Attribute
->ns
->href
, ClosestDefault
->href
)) {
237 if (auto E
= copyAttributeNamespace(OriginalAttribute
, OriginalNode
,
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.
249 if (Attribute
->ns
->prefix
|| OriginalAttribute
->ns
->prefix
||
250 (ClosestDefault
&& !xmlStringsEqual(OriginalAttribute
->ns
->href
,
251 ClosestDefault
->href
))) {
252 if (auto E
= copyAttributeNamespace(OriginalAttribute
, OriginalNode
,
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.
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());
272 return Error::success();
275 // Given two nodes, return the one with the higher priority namespace.
276 static xmlNodePtr
getDominantNode(xmlNodePtr Node1
, xmlNodePtr Node2
) {
278 if (!Node1
|| !Node1
->ns
)
280 if (!Node2
|| !Node2
->ns
)
282 if (namespaceOverrides(Node1
->ns
->href
, Node2
->ns
->href
))
287 // Checks if this Node's namespace is inherited or one it defined itself.
288 static bool hasInheritedNs(xmlNodePtr Node
) {
289 return Node
->ns
&& Node
->ns
!= getNamespaceWithPrefix(Node
->ns
->prefix
, Node
);
292 // Check if this Node's namespace is a default namespace that it inherited, as
293 // opposed to defining itself.
294 static bool hasInheritedDefaultNs(xmlNodePtr Node
) {
295 return hasInheritedNs(Node
) && Node
->ns
->prefix
== nullptr;
298 // Check if this Node's namespace is a default namespace it defined itself.
299 static bool hasDefinedDefaultNamespace(xmlNodePtr Node
) {
300 return Node
->ns
&& (Node
->ns
== getNamespaceWithPrefix(nullptr, Node
));
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.
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
312 if (hasDefinedDefaultNamespace(Node
))
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
) {
320 xmlStringsEqual(Attribute
->ns
->href
, PrefixDef
->href
)) {
321 Attribute
->ns
= PrefixDef
;
324 for (xmlNodePtr Child
= Node
->children
; Child
; Child
= Child
->next
) {
325 explicateNamespace(PrefixDef
, Child
);
329 // Perform the namespace merge between two nodes.
330 static Error
mergeNamespaces(xmlNodePtr OriginalNode
,
331 xmlNodePtr AdditionalNode
) {
332 // Save the original default namespace definition in case the incoming node
334 const unsigned char *OriginalDefinedDefaultHref
= nullptr;
335 if (xmlNsPtr OriginalDefinedDefaultNs
=
336 getNamespaceWithPrefix(nullptr, OriginalNode
)) {
337 OriginalDefinedDefaultHref
= xmlStrdup(OriginalDefinedDefaultNs
->href
);
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
)) {
347 if (namespaceOverrides(Def
->href
, OriginalNsDef
->href
)) {
348 NewDefinedDefaultHref
= TO_XML_CHAR(strdup(FROM_XML_CHAR(Def
->href
)));
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
));
356 xmlNsPtr NewDef
= xmlCopyNamespace(Def
);
357 NewDef
->next
= OriginalNode
->nsDef
;
358 OriginalNode
->nsDef
= NewDef
;
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
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
);
385 return EC
.takeError();
387 xmlNsPtr PrefixDominantDefinedDefault
= std::move(EC
.get());
388 explicateNamespace(PrefixDominantDefinedDefault
, DominantNode
);
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
);
403 return EC
.takeError();
405 xmlNsPtr ExplicitDefault
= std::move(EC
.get());
406 explicateNamespace(ExplicitDefault
, DominantNode
);
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
);
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
);
423 return EC
.takeError();
425 xmlNsPtr Explicit
= std::move(EC
.get());
426 NonDominantNode
->ns
= Explicit
;
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
);
441 return EC
.takeError();
443 xmlNsPtr ExplicitDefault
= std::move(EC
.get());
444 explicateNamespace(ExplicitDefault
, NonDominantNode
);
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
);
455 return EC
.takeError();
457 xmlNsPtr ExplicitDefault
= std::move(EC
.get());
458 explicateNamespace(ExplicitDefault
, NonDominantNode
);
462 if (NewDefinedDefaultHref
) {
463 xmlNsPtr OriginalNsDef
= getNamespaceWithPrefix(nullptr, OriginalNode
);
464 xmlFree(const_cast<unsigned char *>(OriginalNsDef
->href
));
465 OriginalNsDef
->href
= NewDefinedDefaultHref
;
467 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref
));
468 return Error::success();
471 static bool isRecognizedNamespace(const unsigned char *NsHref
) {
472 for (auto &Ns
: MtNsHrefsPrefixes
) {
473 if (xmlStringsEqual(NsHref
, TO_XML_CHAR(Ns
.first
.data()))) {
480 static bool hasRecognizedNamespace(xmlNodePtr Node
) {
481 return isRecognizedNamespace(Node
->ns
->href
);
484 // Ensure a node's inherited namespace is actually defined in the tree it
486 static Error
reconcileNamespaces(xmlNodePtr Node
) {
488 return Error::success();
490 if (hasInheritedNs(Node
)) {
491 Expected
<xmlNsPtr
> ExplicitOrError
= searchOrDefine(Node
->ns
->href
, Node
);
492 if (!ExplicitOrError
) {
493 return ExplicitOrError
.takeError();
495 xmlNsPtr Explicit
= std::move(ExplicitOrError
.get());
498 for (xmlNodePtr Child
= Node
->children
; Child
; Child
= Child
->next
) {
499 if (auto E
= reconcileNamespaces(Child
)) {
503 return Error::success();
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
509 static Error
treeMerge(xmlNodePtr OriginalRoot
, xmlNodePtr AdditionalRoot
) {
510 if (auto E
= mergeAttributes(OriginalRoot
, AdditionalRoot
))
512 if (auto E
= mergeNamespaces(OriginalRoot
, AdditionalRoot
))
514 xmlNodePtr AdditionalFirstChild
= AdditionalRoot
->children
;
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
));
528 if (auto E
= reconcileNamespaces(Child
)) {
532 } else if (auto E
= treeMerge(OriginalChildWithName
, Child
)) {
536 return Error::success();
539 static void stripComments(xmlNodePtr Root
) {
541 for (xmlNodePtr Child
= Root
->children
; Child
; Child
= Child
->next
) {
542 if (!xmlStringsEqual(Child
->name
, TO_XML_CHAR("comment"))) {
543 stripComments(Child
);
546 StoreNext
.next
= Child
->next
;
547 xmlNodePtr Remove
= Child
;
549 xmlUnlinkNode(Remove
);
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.
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
);
564 for (xmlNodePtr Child
= Node
->children
; Child
; Child
= Child
->next
) {
565 setAttributeNamespaces(Child
);
569 // The merging process may create too many prefix defined namespaces. This
570 // function removes all unnecessary ones from the tree.
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
);
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
);
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
);
599 for (xmlNsPtr Def
= Node
->nsDef
; Def
; Def
= Def
->next
) {
600 if (!Def
->prefix
|| llvm::is_contained(RequiredPrefixes
, Def
)) {
604 if (Def
== Node
->nsDef
) {
605 Node
->nsDef
= Def
->next
;
607 Prev
->next
= Def
->next
;
609 Temp
.next
= Def
->next
;
615 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
616 for (auto &Doc
: MergedDocs
)
620 Error
WindowsManifestMerger::WindowsManifestMergerImpl::merge(
621 MemoryBufferRef Manifest
) {
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())
636 xmlNodePtr AdditionalRoot
= xmlDocGetRootElement(ManifestXML
);
637 stripComments(AdditionalRoot
);
638 setAttributeNamespaces(AdditionalRoot
);
639 if (CombinedDoc
== nullptr) {
640 CombinedDoc
= ManifestXML
;
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");
648 if (auto E
= treeMerge(CombinedRoot
, AdditionalRoot
)) {
652 MergedDocs
.push_back(ManifestXML
);
653 return Error::success();
656 std::unique_ptr
<MemoryBuffer
>
657 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
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
));
672 xmlKeepBlanksDefault(0);
673 xmlChar
*Buff
= nullptr;
674 xmlDocDumpFormatMemoryEnc(OutputDoc
.get(), &Buff
, &BufferSize
, "UTF-8", 1);
678 return BufferSize
? MemoryBuffer::getMemBufferCopy(StringRef(
679 FROM_XML_CHAR(Buffer
.get()), (size_t)BufferSize
))
683 bool windows_manifest::isAvailable() { return true; }
687 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
690 Error
WindowsManifestMerger::WindowsManifestMergerImpl::merge(
691 MemoryBufferRef Manifest
) {
692 return make_error
<WindowsManifestError
>("no libxml2");
695 std::unique_ptr
<MemoryBuffer
>
696 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
700 bool windows_manifest::isAvailable() { return false; }
704 WindowsManifestMerger::WindowsManifestMerger()
705 : Impl(std::make_unique
<WindowsManifestMergerImpl
>()) {}
707 WindowsManifestMerger::~WindowsManifestMerger() = default;
709 Error
WindowsManifestMerger::merge(MemoryBufferRef Manifest
) {
710 return Impl
->merge(Manifest
);
713 std::unique_ptr
<MemoryBuffer
> WindowsManifestMerger::getMergedManifest() {
714 return Impl
->getMergedManifest();
717 void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
718 void *Ctx
, const char *Format
, ...) {
719 auto *Merger
= (WindowsManifestMergerImpl
*)Ctx
;
720 Merger
->ParseErrorOccurred
= true;
723 Error
WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
724 if (!ParseErrorOccurred
)
725 return Error::success();
726 return make_error
<WindowsManifestError
>("invalid xml document");