15 #include "llvm/Config/config.h" 20 #if LLVM_LIBXML2_ENABLED 21 #include <libxml/xmlreader.h> 24 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X) 25 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X) 28 using namespace windows_manifest;
40 std::unique_ptr<MemoryBuffer> getMergedManifest();
43 static void errorCallback(
void *Ctx,
const char *
Format, ...);
44 Error getParseError();
45 #if LLVM_LIBXML2_ENABLED 46 xmlDocPtr CombinedDoc =
nullptr;
47 std::vector<xmlDocPtr> MergedDocs;
51 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
52 void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
55 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
57 bool ParseErrorOccurred =
false;
60 #if LLVM_LIBXML2_ENABLED 62 static const std::pair<StringRef, StringRef> MtNsHrefsPrefixes[] = {
63 {
"urn:schemas-microsoft-com:asm.v1",
"ms_asmv1"},
64 {
"urn:schemas-microsoft-com:asm.v2",
"ms_asmv2"},
65 {
"urn:schemas-microsoft-com:asm.v3",
"ms_asmv3"},
66 {
"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
67 "ms_windowsSettings"},
68 {
"urn:schemas-microsoft-com:compatibility.v1",
"ms_compatibilityv1"}};
70 static bool xmlStringsEqual(
const unsigned char *A,
const unsigned char *
B) {
78 static bool isMergeableElement(
const unsigned char *ElementName) {
79 for (
StringRef S : {
"application",
"assembly",
"assemblyIdentity",
80 "compatibility",
"noInherit",
"requestedExecutionLevel",
81 "requestedPrivileges",
"security",
"trustInfo"}) {
89 static xmlNodePtr getChildWithName(xmlNodePtr Parent,
90 const unsigned char *ElementName) {
91 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
92 if (xmlStringsEqual(Child->name, ElementName)) {
99 static xmlAttrPtr getAttribute(xmlNodePtr Node,
100 const unsigned char *AttributeName) {
103 if (xmlStringsEqual(
Attribute->name, AttributeName)) {
111 static bool namespaceOverrides(
const unsigned char *HRef1,
112 const unsigned char *HRef2) {
114 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
115 return xmlStringsEqual(HRef1,
TO_XML_CHAR(Element.first.data()));
118 MtNsHrefsPrefixes, [=](
const std::pair<StringRef, StringRef> &Element) {
119 return xmlStringsEqual(HRef2,
TO_XML_CHAR(Element.first.data()));
121 return HRef1Position < HRef2Position;
127 static xmlNsPtr search(
const unsigned char *HRef, xmlNodePtr Node) {
128 for (xmlNsPtr
Def = Node->nsDef;
Def;
Def =
Def->next) {
129 if (
Def->prefix && xmlStringsEqual(
Def->href, HRef)) {
134 return search(HRef, Node->parent);
141 static const unsigned char *getPrefixForHref(
const unsigned char *HRef) {
142 for (
auto &Ns : MtNsHrefsPrefixes) {
143 if (xmlStringsEqual(HRef,
TO_XML_CHAR(Ns.first.data()))) {
156 if (xmlNsPtr
Def = search(HRef, Node))
158 if (xmlNsPtr
Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
160 return make_error<WindowsManifestError>(
"failed to create new namespace");
165 static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
166 xmlNodePtr OriginalNode,
167 xmlAttrPtr AdditionalAttribute) {
170 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
171 if (!ExplicitOrError)
173 OriginalAttribute->ns = std::move(ExplicitOrError.
get());
179 static xmlNsPtr getNamespaceWithPrefix(
const unsigned char *
Prefix,
183 for (xmlNsPtr
Def = Node->nsDef;
Def;
Def =
Def->next) {
184 if (xmlStringsEqual(
Def->prefix,
Prefix)) {
194 static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
195 if (xmlNsPtr
Ret = getNamespaceWithPrefix(
nullptr, Node))
197 if (Node->parent ==
nullptr)
199 return getClosestDefault(Node->parent);
208 static Error mergeAttributes(xmlNodePtr OriginalNode,
209 xmlNodePtr AdditionalNode) {
210 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
213 if (xmlAttrPtr OriginalAttribute =
214 getAttribute(OriginalNode,
Attribute->name)) {
215 if (!xmlStringsEqual(OriginalAttribute->children->content,
217 return make_error<WindowsManifestError>(
218 Twine(
"conflicting attributes for ") +
224 if (!OriginalAttribute->ns) {
225 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
231 if (namespaceOverrides(OriginalAttribute->ns->href,
237 if (!OriginalAttribute->ns->prefix && !
Attribute->ns->prefix &&
239 xmlStringsEqual(
Attribute->ns->href, ClosestDefault->href)) {
240 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
252 if (
Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
253 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
254 ClosestDefault->href))) {
255 if (
auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
270 searchOrDefine(
Attribute->ns->href, OriginalNode);
271 if (!ExplicitOrError)
273 NewProp->ns = std::move(ExplicitOrError.
get());
279 static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
281 if (!Node1 || !Node1->ns)
283 if (!Node2 || !Node2->ns)
285 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
291 static bool hasInheritedNs(xmlNodePtr Node) {
292 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
297 static bool hasInheritedDefaultNs(xmlNodePtr Node) {
298 return hasInheritedNs(Node) && Node->ns->prefix ==
nullptr;
302 static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
303 return Node->ns && (Node->ns == getNamespaceWithPrefix(
nullptr, Node));
311 static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
315 if (hasDefinedDefaultNamespace(Node))
317 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
318 hasInheritedDefaultNs(Node))
319 Node->ns = PrefixDef;
323 xmlStringsEqual(
Attribute->ns->href, PrefixDef->href)) {
327 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
328 explicateNamespace(PrefixDef, Child);
333 static Error mergeNamespaces(xmlNodePtr OriginalNode,
334 xmlNodePtr AdditionalNode) {
337 const unsigned char *OriginalDefinedDefaultHref =
nullptr;
338 if (xmlNsPtr OriginalDefinedDefaultNs =
339 getNamespaceWithPrefix(
nullptr, OriginalNode)) {
340 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
342 const unsigned char *NewDefinedDefaultHref =
nullptr;
346 for (xmlNsPtr
Def = AdditionalNode->nsDef;
Def;
Def =
Def->next) {
347 if (xmlNsPtr OriginalNsDef =
348 getNamespaceWithPrefix(
Def->prefix, OriginalNode)) {
350 if (namespaceOverrides(
Def->href, OriginalNsDef->href)) {
353 }
else if (!xmlStringsEqual(OriginalNsDef->href,
Def->href)) {
354 return make_error<WindowsManifestError>(
355 Twine(
"conflicting namespace definitions for ") +
359 xmlNsPtr NewDef = xmlCopyNamespace(
Def);
360 NewDef->next = OriginalNode->nsDef;
361 OriginalNode->nsDef = NewDef;
369 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
370 xmlNodePtr NonDominantNode =
371 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
372 if (DominantNode == OriginalNode) {
373 if (OriginalDefinedDefaultHref) {
374 xmlNsPtr NonDominantDefinedDefault =
375 getNamespaceWithPrefix(
nullptr, NonDominantNode);
382 if (NonDominantDefinedDefault &&
383 namespaceOverrides(NonDominantDefinedDefault->href,
384 OriginalDefinedDefaultHref)) {
386 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
390 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.
get());
391 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
400 }
else if (getNamespaceWithPrefix(
nullptr, NonDominantNode)) {
401 if (DominantNode->parent) {
402 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
404 searchOrDefine(ClosestDefault->href, DominantNode);
408 xmlNsPtr ExplicitDefault = std::move(EC.
get());
409 explicateNamespace(ExplicitDefault, DominantNode);
416 if (hasDefinedDefaultNamespace(DominantNode)) {
417 NonDominantNode->ns = getNamespaceWithPrefix(
nullptr, NonDominantNode);
424 searchOrDefine(DominantNode->ns->href, NonDominantNode);
428 xmlNsPtr Explicit = std::move(EC.
get());
429 NonDominantNode->ns = Explicit;
433 if (xmlNsPtr DominantDefaultDefined =
434 getNamespaceWithPrefix(
nullptr, DominantNode)) {
435 if (OriginalDefinedDefaultHref) {
436 if (namespaceOverrides(DominantDefaultDefined->href,
437 OriginalDefinedDefaultHref)) {
442 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
446 xmlNsPtr ExplicitDefault = std::move(EC.
get());
447 explicateNamespace(ExplicitDefault, NonDominantNode);
454 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
456 searchOrDefine(ClosestDefault->href, NonDominantNode);
460 xmlNsPtr ExplicitDefault = std::move(EC.
get());
461 explicateNamespace(ExplicitDefault, NonDominantNode);
465 if (NewDefinedDefaultHref) {
466 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(
nullptr, OriginalNode);
467 xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
468 OriginalNsDef->href = NewDefinedDefaultHref;
470 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
474 static bool isRecognizedNamespace(
const unsigned char *NsHref) {
475 for (
auto &Ns : MtNsHrefsPrefixes) {
476 if (xmlStringsEqual(NsHref,
TO_XML_CHAR(Ns.first.data()))) {
483 static bool hasRecognizedNamespace(xmlNodePtr Node) {
484 return isRecognizedNamespace(Node->ns->href);
489 static Error reconcileNamespaces(xmlNodePtr Node) {
493 if (hasInheritedNs(Node)) {
495 if (!ExplicitOrError) {
498 xmlNsPtr Explicit = std::move(ExplicitOrError.
get());
501 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
502 if (
auto E = reconcileNamespaces(Child)) {
512 static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
513 if (
auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
515 if (
auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
517 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
519 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
520 xmlNodePtr OriginalChildWithName;
521 if (!isMergeableElement(Child->name) ||
522 !(OriginalChildWithName =
523 getChildWithName(OriginalRoot, Child->name)) ||
524 !hasRecognizedNamespace(Child)) {
525 StoreNext.next = Child->next;
526 xmlUnlinkNode(Child);
527 if (!xmlAddChild(OriginalRoot, Child)) {
528 return make_error<WindowsManifestError>(
Twine(
"could not merge ") +
531 if (
auto E = reconcileNamespaces(Child)) {
535 }
else if (
auto E = treeMerge(OriginalChildWithName, Child)) {
542 static void stripComments(xmlNodePtr Root) {
544 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
545 if (!xmlStringsEqual(Child->name,
TO_XML_CHAR(
"comment"))) {
546 stripComments(Child);
549 StoreNext.next = Child->next;
550 xmlNodePtr Remove = Child;
552 xmlUnlinkNode(Remove);
560 static void setAttributeNamespaces(xmlNodePtr Node) {
567 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
568 setAttributeNamespaces(Child);
574 static void checkAndStripPrefixes(xmlNodePtr Node,
575 std::vector<xmlNsPtr> &RequiredPrefixes) {
576 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
577 checkAndStripPrefixes(Child, RequiredPrefixes);
579 if (Node->ns && Node->ns->prefix !=
nullptr) {
580 xmlNsPtr ClosestDefault = getClosestDefault(Node);
581 if (ClosestDefault &&
582 xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
583 Node->ns = ClosestDefault;
585 RequiredPrefixes.push_back(Node->ns);
591 xmlNsPtr ClosestDefault = getClosestDefault(Node);
592 if (ClosestDefault &&
593 xmlStringsEqual(ClosestDefault->href,
Attribute->ns->href)) {
596 RequiredPrefixes.push_back(
Attribute->ns);
602 for (xmlNsPtr
Def = Node->nsDef;
Def;
Def =
Def->next) {
607 if (
Def == Node->nsDef) {
608 Node->nsDef =
Def->next;
610 Prev->next =
Def->next;
612 Temp.next =
Def->next;
619 for (
auto &Doc : MergedDocs)
626 return make_error<WindowsManifestError>(
627 "merge after getMergedManifest is not supported");
629 return make_error<WindowsManifestError>(
630 "attempted to merge empty manifest");
631 xmlSetGenericErrorFunc((
void *)
this,
632 WindowsManifestMergerImpl::errorCallback);
633 xmlDocPtr ManifestXML = xmlReadMemory(
635 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT);
636 xmlSetGenericErrorFunc(
nullptr,
nullptr);
637 if (
auto E = getParseError())
639 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
640 stripComments(AdditionalRoot);
641 setAttributeNamespaces(AdditionalRoot);
642 if (CombinedDoc ==
nullptr) {
643 CombinedDoc = ManifestXML;
645 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
646 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
647 !isMergeableElement(AdditionalRoot->name) ||
648 !hasRecognizedNamespace(AdditionalRoot)) {
649 return make_error<WindowsManifestError>(
"multiple root nodes");
651 if (
auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
655 MergedDocs.push_back(ManifestXML);
659 std::unique_ptr<MemoryBuffer>
667 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
668 std::vector<xmlNsPtr> RequiredPrefixes;
669 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
670 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
671 xmlNewDoc((
const unsigned char *)
"1.0"));
672 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
673 assert(0 == xmlDocGetRootElement(CombinedDoc));
675 xmlKeepBlanksDefault(0);
676 xmlChar *Buff =
nullptr;
677 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize,
"UTF-8", 1);
695 return make_error<WindowsManifestError>(
"no libxml2");
698 std::unique_ptr<MemoryBuffer>
713 return Impl->merge(Manifest);
717 return Impl->getMergedManifest();
720 void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
721 void *Ctx,
const char *
Format, ...) {
723 Merger->ParseErrorOccurred =
true;
726 Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
727 if (!ParseErrorOccurred)
729 return make_error<WindowsManifestError>(
"invalid xml document");
This class represents lattice values for constants.
size_t getBufferSize() const
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&... args)
Constructs a new T() with the given args and returns a unique_ptr<T> which owns the object...
Error takeError()
Take ownership of the stored error.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
WindowsManifestError(const Twine &Msg)
Tagged union holding either a T or a Error.
void log(raw_ostream &OS) const override
Print an error message to an output stream.
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Error merge(const MemoryBuffer &Manifest)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
std::unique_ptr< MemoryBuffer > getMergedManifest()
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range))
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly...
static ErrorSuccess success()
Create a success value.
reference get()
Returns a reference to the stored T value.
Error merge(const MemoryBuffer &Manifest)
This interface provides simple read-only access to a block of memory, and provides simple methods for...
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...
std::unique_ptr< MemoryBuffer > getMergedManifest()
const char * getBufferStart() const
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
This class implements an extremely fast bulk output stream that can only output to a stream...
StringRef - Represent a constant reference to a string, i.e.
~WindowsManifestMergerImpl()
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.