summaryrefslogtreecommitdiff
path: root/lib/WindowsManifest
diff options
context:
space:
mode:
authorEric Beckmann <ecbeckmann@google.com>2017-07-26 01:21:55 +0000
committerEric Beckmann <ecbeckmann@google.com>2017-07-26 01:21:55 +0000
commitf74bed27b433390460f80b2b6d1235cbadc5f482 (patch)
treecb5e8a7244d7936dbdfbd827f9af5c8fbb10c408 /lib/WindowsManifest
parent49fc1e6fbc4dbcde96f77f13f9d47e717f83872b (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.txt18
-rw-r--r--lib/WindowsManifest/LLVMBuild.txt22
-rw-r--r--lib/WindowsManifest/WindowsManifestMerger.cpp212
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