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)
25using namespace windows_manifest;
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
59static 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"}};
67static bool xmlStringsEqual(
const unsigned char *
A,
const unsigned char *
B) {
75static bool isMergeableElement(
const unsigned char *ElementName) {
76 for (
StringRef S : {
"application",
"assembly",
"assemblyIdentity",
77 "compatibility",
"noInherit",
"requestedExecutionLevel",
78 "requestedPrivileges",
"security",
"trustInfo"}) {
86static 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)) {
96static xmlAttrPtr getAttribute(xmlNodePtr
Node,
97 const unsigned char *AttributeName) {
100 if (xmlStringsEqual(
Attribute->name, AttributeName)) {
108static bool namespaceOverrides(
const unsigned char *HRef1,
109 const unsigned char *HRef2) {
111 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
112 return xmlStringsEqual(HRef1,
TO_XML_CHAR(Element.first.data()));
115 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
116 return xmlStringsEqual(HRef2,
TO_XML_CHAR(Element.first.data()));
118 return HRef1Position < HRef2Position;
124static 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);
138static const unsigned char *getPrefixForHref(
const unsigned char *HRef) {
139 for (
auto &Ns : MtNsHrefsPrefixes) {
140 if (xmlStringsEqual(HRef,
TO_XML_CHAR(Ns.first.data()))) {
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");
162static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
163 xmlNodePtr OriginalNode,
164 xmlAttrPtr AdditionalAttribute) {
167 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
168 if (!ExplicitOrError)
170 OriginalAttribute->ns = std::move(ExplicitOrError.
get());
176static xmlNsPtr getNamespaceWithPrefix(
const unsigned char *Prefix,
180 for (xmlNsPtr Def =
Node->nsDef; Def; Def =
Def->next) {
181 if (xmlStringsEqual(
Def->prefix, Prefix)) {
191static xmlNsPtr getClosestDefault(xmlNodePtr
Node) {
192 if (xmlNsPtr Ret = getNamespaceWithPrefix(
nullptr,
Node))
194 if (
Node->parent ==
nullptr)
196 return getClosestDefault(
Node->parent);
205static Error mergeAttributes(xmlNodePtr OriginalNode,
206 xmlNodePtr AdditionalNode) {
207 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
210 if (xmlAttrPtr OriginalAttribute =
211 getAttribute(OriginalNode,
Attribute->name)) {
212 if (!xmlStringsEqual(OriginalAttribute->children->content,
214 return make_error<WindowsManifestError>(
215 Twine(
"conflicting attributes for ") +
221 if (!OriginalAttribute->ns) {
222 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
228 if (namespaceOverrides(OriginalAttribute->ns->href,
234 if (!OriginalAttribute->ns->prefix && !
Attribute->ns->prefix &&
236 xmlStringsEqual(
Attribute->ns->href, ClosestDefault->href)) {
237 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
249 if (
Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
250 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
251 ClosestDefault->href))) {
252 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
267 searchOrDefine(
Attribute->ns->href, OriginalNode);
268 if (!ExplicitOrError)
270 NewProp->ns = std::move(ExplicitOrError.
get());
276static 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))
288static bool hasInheritedNs(xmlNodePtr
Node) {
289 return Node->ns &&
Node->ns != getNamespaceWithPrefix(
Node->ns->prefix,
Node);
294static bool hasInheritedDefaultNs(xmlNodePtr
Node) {
295 return hasInheritedNs(
Node) &&
Node->ns->prefix ==
nullptr;
299static bool hasDefinedDefaultNamespace(xmlNodePtr
Node) {
300 return Node->ns && (
Node->ns == getNamespaceWithPrefix(
nullptr,
Node));
308static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr
Node) {
312 if (hasDefinedDefaultNamespace(
Node))
314 if (
Node->ns && xmlStringsEqual(
Node->ns->href, PrefixDef->href) &&
315 hasInheritedDefaultNs(
Node))
316 Node->ns = PrefixDef;
320 xmlStringsEqual(
Attribute->ns->href, PrefixDef->href)) {
324 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
325 explicateNamespace(PrefixDef, Child);
330static Error mergeNamespaces(xmlNodePtr OriginalNode,
331 xmlNodePtr AdditionalNode) {
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;
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)) {
350 }
else if (!xmlStringsEqual(OriginalNsDef->href,
Def->href)) {
351 return make_error<WindowsManifestError>(
352 Twine(
"conflicting namespace definitions for ") +
356 xmlNsPtr NewDef = xmlCopyNamespace(Def);
357 NewDef->next = OriginalNode->nsDef;
358 OriginalNode->nsDef = NewDef;
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);
379 if (NonDominantDefinedDefault &&
380 namespaceOverrides(NonDominantDefinedDefault->href,
381 OriginalDefinedDefaultHref)) {
383 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
385 return EC.takeError();
387 xmlNsPtr PrefixDominantDefinedDefault = std::move(
EC.get());
388 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
397 }
else if (getNamespaceWithPrefix(
nullptr, NonDominantNode)) {
398 if (DominantNode->parent) {
399 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
401 searchOrDefine(ClosestDefault->href, DominantNode);
403 return EC.takeError();
405 xmlNsPtr ExplicitDefault = std::move(
EC.get());
406 explicateNamespace(ExplicitDefault, DominantNode);
413 if (hasDefinedDefaultNamespace(DominantNode)) {
414 NonDominantNode->ns = getNamespaceWithPrefix(
nullptr, NonDominantNode);
421 searchOrDefine(DominantNode->ns->href, NonDominantNode);
423 return EC.takeError();
425 xmlNsPtr Explicit = std::move(
EC.get());
426 NonDominantNode->ns = Explicit;
430 if (xmlNsPtr DominantDefaultDefined =
431 getNamespaceWithPrefix(
nullptr, DominantNode)) {
432 if (OriginalDefinedDefaultHref) {
433 if (namespaceOverrides(DominantDefaultDefined->href,
434 OriginalDefinedDefaultHref)) {
439 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
441 return EC.takeError();
443 xmlNsPtr ExplicitDefault = std::move(
EC.get());
444 explicateNamespace(ExplicitDefault, NonDominantNode);
451 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
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));
471static bool isRecognizedNamespace(
const unsigned char *NsHref) {
472 for (
auto &Ns : MtNsHrefsPrefixes) {
473 if (xmlStringsEqual(NsHref,
TO_XML_CHAR(Ns.first.data()))) {
480static bool hasRecognizedNamespace(xmlNodePtr
Node) {
481 return isRecognizedNamespace(
Node->ns->href);
486static Error reconcileNamespaces(xmlNodePtr
Node) {
490 if (hasInheritedNs(
Node)) {
492 if (!ExplicitOrError) {
495 xmlNsPtr Explicit = std::move(ExplicitOrError.
get());
498 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
499 if (
auto E = reconcileNamespaces(Child)) {
509static 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 ") +
528 if (
auto E = reconcileNamespaces(Child)) {
532 }
else if (
auto E = treeMerge(OriginalChildWithName, Child)) {
539static 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);
557static void setAttributeNamespaces(xmlNodePtr
Node) {
564 for (xmlNodePtr Child =
Node->children; Child; Child = Child->next) {
565 setAttributeNamespaces(Child);
571static 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;
582 RequiredPrefixes.push_back(
Node->ns);
588 xmlNsPtr ClosestDefault = getClosestDefault(
Node);
589 if (ClosestDefault &&
590 xmlStringsEqual(ClosestDefault->href,
Attribute->ns->href)) {
593 RequiredPrefixes.push_back(
Attribute->ns);
599 for (xmlNsPtr Def =
Node->nsDef; Def; Def =
Def->next) {
604 if (Def ==
Node->nsDef) {
607 Prev->next =
Def->next;
609 Temp.next =
Def->next;
616 for (
auto &Doc : MergedDocs)
623 return make_error<WindowsManifestError>(
624 "merge after getMergedManifest is not supported");
626 return make_error<WindowsManifestError>(
627 "attempted to merge empty manifest");
628 xmlSetGenericErrorFunc((
void *)
this,
629 WindowsManifestMergerImpl::errorCallback);
630 xmlDocPtr ManifestXML = xmlReadMemory(
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);
656std::unique_ptr<MemoryBuffer>
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 xmlChar *Buff =
nullptr;
673 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize,
"UTF-8", 1);
691 return make_error<WindowsManifestError>(
"no libxml2");
694std::unique_ptr<MemoryBuffer>
709 return Impl->merge(Manifest);
713 return Impl->getMergedManifest();
716void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
717 void *Ctx,
const char *
Format, ...) {
718 auto *
Merger = (WindowsManifestMergerImpl *)Ctx;
719 Merger->ParseErrorOccurred =
true;
722Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
723 if (!ParseErrorOccurred)
725 return make_error<WindowsManifestError>(
"invalid xml document");
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
~WindowsManifestMergerImpl()
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.
Tagged union holding either a T or a Error.
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.
StringRef - Represent a constant reference to a string, i.e.
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.
std::unique_ptr< MemoryBuffer > getMergedManifest()
Error merge(MemoryBufferRef Manifest)
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
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.