14#include "llvm/Config/config.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)
39 static void errorCallback(
void *Ctx,
const char *
Format, ...);
40 Error getParseError();
41#if LLVM_ENABLE_LIBXML2
43 void operator()(xmlChar *
Ptr) { xmlFree(
Ptr); }
44 void operator()(xmlDoc *
Ptr) { xmlFreeDoc(
Ptr); }
46 xmlDocPtr CombinedDoc =
nullptr;
47 std::vector<std::unique_ptr<xmlDoc, XmlDeleter>> MergedDocs;
50 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
52 bool ParseErrorOccurred =
false;
55#if LLVM_ENABLE_LIBXML2
57static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = {
58 {
"urn:schemas-microsoft-com:asm.v1",
"ms_asmv1"},
59 {
"urn:schemas-microsoft-com:asm.v2",
"ms_asmv2"},
60 {
"urn:schemas-microsoft-com:asm.v3",
"ms_asmv3"},
61 {
"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
62 "ms_windowsSettings"},
63 {
"urn:schemas-microsoft-com:compatibility.v1",
"ms_compatibilityv1"}};
65static bool xmlStringsEqual(
const unsigned char *
A,
const unsigned char *
B) {
73static bool isMergeableElement(
const unsigned char *ElementName) {
74 for (StringRef S : {
"application",
"assembly",
"assemblyIdentity",
75 "compatibility",
"noInherit",
"requestedExecutionLevel",
76 "requestedPrivileges",
"security",
"trustInfo"}) {
84static xmlNodePtr getChildWithName(xmlNodePtr Parent,
85 const unsigned char *ElementName) {
86 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
87 if (xmlStringsEqual(Child->name, ElementName)) {
94static xmlAttrPtr getAttribute(xmlNodePtr Node,
95 const unsigned char *AttributeName) {
98 if (xmlStringsEqual(
Attribute->name, AttributeName)) {
106static bool namespaceOverrides(
const unsigned char *HRef1,
107 const unsigned char *HRef2) {
109 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
110 return xmlStringsEqual(HRef1,
TO_XML_CHAR(Element.first.data()));
113 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
114 return xmlStringsEqual(HRef2,
TO_XML_CHAR(Element.first.data()));
116 return HRef1Position < HRef2Position;
122static xmlNsPtr search(
const unsigned char *HRef, xmlNodePtr Node) {
123 for (xmlNsPtr Def =
Node->nsDef; Def; Def =
Def->next) {
124 if (
Def->prefix && xmlStringsEqual(
Def->href, HRef)) {
129 return search(HRef,
Node->parent);
136static const unsigned char *getPrefixForHref(
const unsigned char *HRef) {
137 for (
auto &Ns : MtNsHrefsPrefixes) {
138 if (xmlStringsEqual(HRef,
TO_XML_CHAR(Ns.first.data()))) {
149static Expected<xmlNsPtr> searchOrDefine(
const unsigned char *HRef,
151 if (xmlNsPtr Def = search(HRef, Node))
153 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
160static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
161 xmlNodePtr OriginalNode,
162 xmlAttrPtr AdditionalAttribute) {
164 Expected<xmlNsPtr> ExplicitOrError =
165 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
166 if (!ExplicitOrError)
168 OriginalAttribute->ns = std::move(ExplicitOrError.
get());
174static xmlNsPtr getNamespaceWithPrefix(
const unsigned char *Prefix,
178 for (xmlNsPtr Def =
Node->nsDef; Def; Def =
Def->next) {
179 if (xmlStringsEqual(
Def->prefix, Prefix)) {
189static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
190 if (xmlNsPtr Ret = getNamespaceWithPrefix(
nullptr, Node))
192 if (
Node->parent ==
nullptr)
194 return getClosestDefault(
Node->parent);
203static Error mergeAttributes(xmlNodePtr OriginalNode,
204 xmlNodePtr AdditionalNode) {
205 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
208 if (xmlAttrPtr OriginalAttribute =
209 getAttribute(OriginalNode,
Attribute->name)) {
210 if (!xmlStringsEqual(OriginalAttribute->children->content,
213 Twine(
"conflicting attributes for ") +
219 if (!OriginalAttribute->ns) {
220 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
226 if (namespaceOverrides(OriginalAttribute->ns->href,
232 if (!OriginalAttribute->ns->prefix && !
Attribute->ns->prefix &&
234 xmlStringsEqual(
Attribute->ns->href, ClosestDefault->href)) {
235 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
247 if (
Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
248 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
249 ClosestDefault->href))) {
250 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
264 Expected<xmlNsPtr> ExplicitOrError =
265 searchOrDefine(
Attribute->ns->href, OriginalNode);
266 if (!ExplicitOrError)
268 NewProp->ns = std::move(ExplicitOrError.
get());
274static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
276 if (!Node1 || !Node1->ns)
278 if (!Node2 || !Node2->ns)
280 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
286static bool hasInheritedNs(xmlNodePtr Node) {
287 return Node->ns &&
Node->ns != getNamespaceWithPrefix(
Node->ns->prefix, Node);
292static bool hasInheritedDefaultNs(xmlNodePtr Node) {
293 return hasInheritedNs(Node) &&
Node->ns->prefix ==
nullptr;
297static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
298 return Node->ns && (
Node->ns == getNamespaceWithPrefix(
nullptr, Node));
306static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
310 if (hasDefinedDefaultNamespace(Node))
312 if (
Node->ns && xmlStringsEqual(
Node->ns->href, PrefixDef->href) &&
313 hasInheritedDefaultNs(Node))
314 Node->ns = PrefixDef;
318 xmlStringsEqual(
Attribute->ns->href, PrefixDef->href)) {
322 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
323 explicateNamespace(PrefixDef, Child);
328static Error mergeNamespaces(xmlNodePtr OriginalNode,
329 xmlNodePtr AdditionalNode) {
332 const unsigned char *OriginalDefinedDefaultHref =
nullptr;
333 if (xmlNsPtr OriginalDefinedDefaultNs =
334 getNamespaceWithPrefix(
nullptr, OriginalNode)) {
335 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
337 const unsigned char *NewDefinedDefaultHref =
nullptr;
341 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def =
Def->next) {
342 if (xmlNsPtr OriginalNsDef =
343 getNamespaceWithPrefix(
Def->prefix, OriginalNode)) {
345 if (namespaceOverrides(
Def->href, OriginalNsDef->href)) {
348 }
else if (!xmlStringsEqual(OriginalNsDef->href,
Def->href)) {
350 Twine(
"conflicting namespace definitions for ") +
354 xmlNsPtr NewDef = xmlCopyNamespace(Def);
355 NewDef->next = OriginalNode->nsDef;
356 OriginalNode->nsDef = NewDef;
364 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
365 xmlNodePtr NonDominantNode =
366 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
367 if (DominantNode == OriginalNode) {
368 if (OriginalDefinedDefaultHref) {
369 xmlNsPtr NonDominantDefinedDefault =
370 getNamespaceWithPrefix(
nullptr, NonDominantNode);
377 if (NonDominantDefinedDefault &&
378 namespaceOverrides(NonDominantDefinedDefault->href,
379 OriginalDefinedDefaultHref)) {
380 Expected<xmlNsPtr>
EC =
381 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
383 return EC.takeError();
385 xmlNsPtr PrefixDominantDefinedDefault = std::move(
EC.get());
386 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
395 }
else if (getNamespaceWithPrefix(
nullptr, NonDominantNode)) {
396 if (DominantNode->parent) {
397 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
398 Expected<xmlNsPtr>
EC =
399 searchOrDefine(ClosestDefault->href, DominantNode);
401 return EC.takeError();
403 xmlNsPtr ExplicitDefault = std::move(
EC.get());
404 explicateNamespace(ExplicitDefault, DominantNode);
411 if (hasDefinedDefaultNamespace(DominantNode)) {
412 NonDominantNode->ns = getNamespaceWithPrefix(
nullptr, NonDominantNode);
418 Expected<xmlNsPtr>
EC =
419 searchOrDefine(DominantNode->ns->href, NonDominantNode);
421 return EC.takeError();
423 xmlNsPtr Explicit = std::move(
EC.get());
424 NonDominantNode->ns = Explicit;
428 if (xmlNsPtr DominantDefaultDefined =
429 getNamespaceWithPrefix(
nullptr, DominantNode)) {
430 if (OriginalDefinedDefaultHref) {
431 if (namespaceOverrides(DominantDefaultDefined->href,
432 OriginalDefinedDefaultHref)) {
436 Expected<xmlNsPtr>
EC =
437 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
439 return EC.takeError();
441 xmlNsPtr ExplicitDefault = std::move(
EC.get());
442 explicateNamespace(ExplicitDefault, NonDominantNode);
449 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
450 Expected<xmlNsPtr>
EC =
451 searchOrDefine(ClosestDefault->href, NonDominantNode);
453 return EC.takeError();
455 xmlNsPtr ExplicitDefault = std::move(
EC.get());
456 explicateNamespace(ExplicitDefault, NonDominantNode);
460 if (NewDefinedDefaultHref) {
461 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(
nullptr, OriginalNode);
462 xmlFree(
const_cast<unsigned char *
>(OriginalNsDef->href));
463 OriginalNsDef->href = NewDefinedDefaultHref;
465 xmlFree(
const_cast<unsigned char *
>(OriginalDefinedDefaultHref));
469static bool isRecognizedNamespace(
const unsigned char *NsHref) {
470 for (
auto &Ns : MtNsHrefsPrefixes) {
471 if (xmlStringsEqual(NsHref,
TO_XML_CHAR(Ns.first.data()))) {
478static bool hasRecognizedNamespace(xmlNodePtr Node) {
479 return isRecognizedNamespace(
Node->ns->href);
484static Error reconcileNamespaces(xmlNodePtr Node) {
488 if (hasInheritedNs(Node)) {
489 Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(
Node->ns->href, Node);
490 if (!ExplicitOrError) {
493 xmlNsPtr Explicit = std::move(ExplicitOrError.
get());
496 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
497 if (
auto E = reconcileNamespaces(Child)) {
507static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
508 if (
auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
510 if (
auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
512 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
514 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
515 xmlNodePtr OriginalChildWithName;
516 if (!isMergeableElement(Child->name) ||
517 !(OriginalChildWithName =
518 getChildWithName(OriginalRoot, Child->name)) ||
519 !hasRecognizedNamespace(Child)) {
520 StoreNext.next = Child->next;
521 xmlUnlinkNode(Child);
522 if (!xmlAddChild(OriginalRoot, Child)) {
526 if (
auto E = reconcileNamespaces(Child)) {
530 }
else if (
auto E = treeMerge(OriginalChildWithName, Child)) {
537static void stripComments(xmlNodePtr Root) {
539 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
540 if (!xmlStringsEqual(Child->name,
TO_XML_CHAR(
"comment"))) {
541 stripComments(Child);
544 StoreNext.next = Child->next;
545 xmlNodePtr Remove = Child;
547 xmlUnlinkNode(Remove);
555static void setAttributeNamespaces(xmlNodePtr Node) {
562 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
563 setAttributeNamespaces(Child);
569static void checkAndStripPrefixes(xmlNodePtr Node,
570 std::vector<xmlNsPtr> &RequiredPrefixes) {
571 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
572 checkAndStripPrefixes(Child, RequiredPrefixes);
574 if (
Node->ns &&
Node->ns->prefix !=
nullptr) {
575 xmlNsPtr ClosestDefault = getClosestDefault(Node);
576 if (ClosestDefault &&
577 xmlStringsEqual(ClosestDefault->href,
Node->ns->href)) {
578 Node->ns = ClosestDefault;
580 RequiredPrefixes.push_back(
Node->ns);
586 xmlNsPtr ClosestDefault = getClosestDefault(Node);
587 if (ClosestDefault &&
588 xmlStringsEqual(ClosestDefault->href,
Attribute->ns->href)) {
591 RequiredPrefixes.push_back(
Attribute->ns);
597 for (xmlNsPtr Def =
Node->nsDef; Def; Def =
Def->next) {
602 if (Def ==
Node->nsDef) {
605 Prev->next =
Def->next;
607 Temp.next =
Def->next;
614 MemoryBufferRef Manifest) {
617 "merge after getMergedManifest is not supported");
620 "attempted to merge empty manifest");
621 xmlSetGenericErrorFunc((
void *)
this,
622 WindowsManifestMergerImpl::errorCallback);
623 std::unique_ptr<xmlDoc, XmlDeleter> ManifestXML(xmlReadMemory(
625 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT));
626 xmlSetGenericErrorFunc(
nullptr,
nullptr);
627 if (
auto E = getParseError())
629 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML.get());
630 stripComments(AdditionalRoot);
631 setAttributeNamespaces(AdditionalRoot);
632 if (CombinedDoc ==
nullptr) {
633 CombinedDoc = ManifestXML.get();
635 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
636 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
637 !isMergeableElement(AdditionalRoot->name) ||
638 !hasRecognizedNamespace(AdditionalRoot)) {
641 if (
auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
645 MergedDocs.push_back(std::move(ManifestXML));
649std::unique_ptr<MemoryBuffer>
657 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
658 std::vector<xmlNsPtr> RequiredPrefixes;
659 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
660 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
661 xmlNewDoc((
const unsigned char *)
"1.0"));
662 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
663 assert(
nullptr == xmlDocGetRootElement(CombinedDoc));
665 xmlChar *Buff =
nullptr;
666 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize,
"UTF-8", 1);
684std::unique_ptr<MemoryBuffer>
699 return Impl->merge(Manifest);
703 return Impl->getMergedManifest();
706void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
707 void *Ctx,
const char *
Format, ...) {
708 auto *
Merger = (WindowsManifestMergerImpl *)Ctx;
709 Merger->ParseErrorOccurred =
true;
712Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
713 if (!ParseErrorOccurred)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Error merge(MemoryBufferRef Manifest)
std::unique_ptr< MemoryBuffer > getMergedManifest()
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
size_t getBufferSize() const
const char * getBufferStart() const
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
This class implements an extremely fast bulk output stream that can only output to a stream.
WindowsManifestError(const Twine &Msg)
void log(raw_ostream &OS) const override
Print an error message to an output stream.
LLVM_ABI WindowsManifestMerger()
LLVM_ABI ~WindowsManifestMerger()
LLVM_ABI std::unique_ptr< MemoryBuffer > getMergedManifest()
LLVM_ABI Error merge(MemoryBufferRef Manifest)
NodeAddr< DefNode * > Def
NodeAddr< NodeBase * > Node
LLVM_ABI bool isAvailable()
This is an optimization pass for GlobalISel generic memory operations.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Implement std::hash so that hash_code can be used in STL containers.