diff options
author | Eric Beckmann <ecbeckmann@google.com> | 2017-07-26 01:21:55 +0000 |
---|---|---|
committer | Eric Beckmann <ecbeckmann@google.com> | 2017-07-26 01:21:55 +0000 |
commit | f74bed27b433390460f80b2b6d1235cbadc5f482 (patch) | |
tree | cb5e8a7244d7936dbdfbd827f9af5c8fbb10c408 /lib/WindowsManifest | |
parent | 49fc1e6fbc4dbcde96f77f13f9d47e717f83872b (diff) |
Move manifest utils into separate lib, to reduce libxml2 deps.
Summary:
Previously were in support. Since many many things depend on support,
were all forced to also depend on libxml2, which we only want in a few cases.
This puts all the libxml2 deps in a separate lib to be used only in a few
places.
Reviewers: ruiu, thakis, rnk
Subscribers: mgorny, hiraditya, llvm-commits
Differential Revision: https://reviews.llvm.org/D35819
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309070 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/WindowsManifest')
-rw-r--r-- | lib/WindowsManifest/CMakeLists.txt | 18 | ||||
-rw-r--r-- | lib/WindowsManifest/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | lib/WindowsManifest/WindowsManifestMerger.cpp | 212 |
3 files changed, 252 insertions, 0 deletions
diff --git a/lib/WindowsManifest/CMakeLists.txt b/lib/WindowsManifest/CMakeLists.txt new file mode 100644 index 00000000000..0bf5f421c18 --- /dev/null +++ b/lib/WindowsManifest/CMakeLists.txt @@ -0,0 +1,18 @@ +set(system_libs)
+if( CMAKE_HOST_UNIX )
+ if( LLVM_LIBXML2_ENABLED )
+ set(system_libs ${system_libs} ${LIBXML2_LIBS})
+ endif()
+endif()
+
+add_llvm_library(LLVMWindowsManifest
+ WindowsManifestMerger.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${LLVM_MAIN_INCLUDE_DIR}/llvm/WindowsManifest
+ ${Backtrace_INCLUDE_DIRS}
+
+ LINK_LIBS ${system_libs}
+ )
+
+set_property(TARGET LLVMWindowsManifest PROPERTY LLVM_SYSTEM_LIBS "${system_libs}")
diff --git a/lib/WindowsManifest/LLVMBuild.txt b/lib/WindowsManifest/LLVMBuild.txt new file mode 100644 index 00000000000..d5de0275b66 --- /dev/null +++ b/lib/WindowsManifest/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./lib/WindowsManifest/LLVMBuild.txt ----------------------*- Conf -*--===;
+;
+; The LLVM Compiler Infrastructure
+;
+; This file is distributed under the University of Illinois Open Source
+; License. See LICENSE.TXT for details.
+;
+;===------------------------------------------------------------------------===;
+;
+; This is an LLVMBuild description file for the components in this subdirectory.
+;
+; For more information on the LLVMBuild system, please see:
+;
+; http://llvm.org/docs/LLVMBuild.html
+;
+;===------------------------------------------------------------------------===;
+
+[component_0]
+type = Library
+name = WindowsManifest
+parent = Libraries
+required_libraries = Support
diff --git a/lib/WindowsManifest/WindowsManifestMerger.cpp b/lib/WindowsManifest/WindowsManifestMerger.cpp new file mode 100644 index 00000000000..0c9e7fda579 --- /dev/null +++ b/lib/WindowsManifest/WindowsManifestMerger.cpp @@ -0,0 +1,212 @@ +//===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +// +// This file implements the .manifest merger class. +// +//===---------------------------------------------------------------------===// + +#include "llvm/WindowsManifest/WindowsManifestMerger.h" +#include "llvm/Support/MemoryBuffer.h" + +#include <stdarg.h> + +#define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X) +#define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X) + +using namespace llvm; + +namespace llvm { + +char WindowsManifestError::ID = 0; + +WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} + +void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } + +#if LLVM_LIBXML2_ENABLED +static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) { + return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0; +} +#endif + +bool isMergeableElement(const unsigned char *ElementName) { + for (StringRef S : {"application", "assembly", "assemblyIdentity", + "compatibility", "noInherit", "requestedExecutionLevel", + "requestedPrivileges", "security", "trustInfo"}) { + if (S == FROM_XML_CHAR(ElementName)) + return true; + } + return false; +} + +XMLNodeImpl getChildWithName(XMLNodeImpl Parent, + const unsigned char *ElementName) { +#if LLVM_LIBXML2_ENABLED + for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next) + if (xmlStringsEqual(Child->name, ElementName)) { + return Child; + } +#endif + return nullptr; +} + +const unsigned char *getAttribute(XMLNodeImpl Node, + const unsigned char *AttributeName) { +#if LLVM_LIBXML2_ENABLED + for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr; + Attribute = Attribute->next) { + if (xmlStringsEqual(Attribute->name, AttributeName)) + return Attribute->children->content; + } +#endif + return nullptr; +} + +Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) { +#if LLVM_LIBXML2_ENABLED + for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr; + Attribute = Attribute->next) { + if (const unsigned char *OriginalValue = + getAttribute(OriginalNode, Attribute->name)) { + // Attributes of the same name must also have the same value. Otherwise + // an error is thrown. + if (!xmlStringsEqual(OriginalValue, Attribute->children->content)) + return make_error<WindowsManifestError>( + Twine("conflicting attributes for ") + + FROM_XML_CHAR(OriginalNode->name)); + } else { + char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name)); + char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content)); + xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy)); + } + } +#endif + return Error::success(); +} + +Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) { +#if LLVM_LIBXML2_ENABLED + XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children; + for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) { + XMLNodeImpl OriginalChildWithName; + if (!isMergeableElement(Child->name) || + !(OriginalChildWithName = + getChildWithName(OriginalRoot, Child->name))) { + XMLNodeImpl NewChild = xmlCopyNode(Child, 1); + if (!NewChild) + return make_error<WindowsManifestError>(Twine("error when copying ") + + FROM_XML_CHAR(Child->name)); + if (NewChild->ns) + xmlFreeNs(NewChild->ns); // xmlCopyNode explicitly defines default + // namespace, undo this here. + if (!xmlAddChild(OriginalRoot, NewChild)) + return make_error<WindowsManifestError>(Twine("could not merge ") + + FROM_XML_CHAR(NewChild->name)); + } else if (auto E = treeMerge(OriginalChildWithName, Child)) { + return E; + } + } + if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot)) + return E; +#endif + return Error::success(); +} + +void stripCommentsAndText(XMLNodeImpl Root) { +#if LLVM_LIBXML2_ENABLED + xmlNode StoreNext; + for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) { + if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) && + !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) { + stripCommentsAndText(Child); + } else { + StoreNext.next = Child->next; + XMLNodeImpl Remove = Child; + Child = &StoreNext; + xmlUnlinkNode(Remove); + xmlFreeNode(Remove); + } + } +#endif +} + +WindowsManifestMerger::~WindowsManifestMerger() { +#if LLVM_LIBXML2_ENABLED + for (auto &Doc : MergedDocs) + xmlFreeDoc(Doc); +#endif +} + +Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) { +#if LLVM_LIBXML2_ENABLED + if (Manifest.getBufferSize() == 0) + return make_error<WindowsManifestError>( + "attempted to merge empty manifest"); + xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback); + XMLDocumentImpl ManifestXML = + xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(), + "manifest.xml", nullptr, XML_PARSE_NOBLANKS); + xmlSetGenericErrorFunc(nullptr, nullptr); + if (auto E = getParseError()) + return E; + XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML); + stripCommentsAndText(AdditionalRoot); + if (CombinedDoc == nullptr) { + CombinedDoc = ManifestXML; + } else { + XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc); + if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) && + isMergeableElement(AdditionalRoot->name)) { + if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) { + return E; + } + } else { + XMLNodeImpl NewChild = xmlCopyNode(AdditionalRoot, 1); + if (!NewChild) + return make_error<WindowsManifestError>("could not copy manifest"); + if (!xmlAddChild(CombinedRoot, NewChild)) + return make_error<WindowsManifestError>("could not append manifest"); + } + } + MergedDocs.push_back(ManifestXML); +#endif + return Error::success(); +} + +std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() { +#if LLVM_LIBXML2_ENABLED + unsigned char *XmlBuff; + int BufferSize = 0; + if (CombinedDoc) { + std::unique_ptr<xmlDoc> OutputDoc(xmlNewDoc((const unsigned char *)"1.0")); + xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc)); + xmlKeepBlanksDefault(0); + xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1); + } + if (BufferSize == 0) + return nullptr; + return MemoryBuffer::getMemBuffer( + StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize)); +#else + return nullptr; +#endif +} + +void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) { + auto *Merger = (WindowsManifestMerger *)Ctx; + Merger->ParseErrorOccurred = true; +} + +Error WindowsManifestMerger::getParseError() { + if (!ParseErrorOccurred) + return Error::success(); + return make_error<WindowsManifestError>("invalid xml document"); +} + +} // namespace llvm |