llvm.org GIT mirror llvm / b0707e1
llvm-mt: implement simple merging of manifests, not factoring namespaces. Summary: Does a simple merge, where mergeable elements are combined, all others are appended. Does not apply trickly namespace rules. Subscribers: llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D35753 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309047 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
8 changed file(s) with 238 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
5656
5757 class WindowsManifestMerger {
5858 public:
59 ~WindowsManifestMerger();
60
5961 Error merge(const MemoryBuffer &Manifest);
6062
6163 // Returns vector containing merged xml manifest, or uninitialized vector for
6769 Error getParseError();
6870
6971 #if LLVM_LIBXML2_ENABLED
70 XMLNodeImpl CombinedRoot = nullptr;
72 XMLDocumentImpl CombinedDoc = nullptr;
73 std::vector MergedDocs;
7174 #endif
7275 bool ParseErrorOccurred = false;
7376 };
1515
1616 #include
1717
18 #define TO_XML_CHAR(X) reinterpret_cast(X)
19 #define FROM_XML_CHAR(X) reinterpret_cast(X)
20
21 using namespace llvm;
22
1823 namespace llvm {
1924
2025 char WindowsManifestError::ID = 0;
2328
2429 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
2530
31 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
32 return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
33 }
34
35 bool isMergeableElement(const unsigned char *ElementName) {
36 for (StringRef S : {"application", "assembly", "assemblyIdentity",
37 "compatibility", "noInherit", "requestedExecutionLevel",
38 "requestedPrivileges", "security", "trustInfo"}) {
39 if (S == FROM_XML_CHAR(ElementName))
40 return true;
41 }
42 return false;
43 }
44
45 XMLNodeImpl getChildWithName(XMLNodeImpl Parent,
46 const unsigned char *ElementName) {
47 #if LLVM_LIBXML2_ENABLED
48 for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next)
49 if (xmlStringsEqual(Child->name, ElementName)) {
50 return Child;
51 }
52 #endif
53 return nullptr;
54 }
55
56 const unsigned char *getAttribute(XMLNodeImpl Node,
57 const unsigned char *AttributeName) {
58 #if LLVM_LIBXML2_ENABLED
59 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
60 Attribute = Attribute->next) {
61 if (xmlStringsEqual(Attribute->name, AttributeName))
62 return Attribute->children->content;
63 }
64 #endif
65 return nullptr;
66 }
67
68 Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) {
69 #if LLVM_LIBXML2_ENABLED
70 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr;
71 Attribute = Attribute->next) {
72 if (const unsigned char *OriginalValue =
73 getAttribute(OriginalNode, Attribute->name)) {
74 // Attributes of the same name must also have the same value. Otherwise
75 // an error is thrown.
76 if (!xmlStringsEqual(OriginalValue, Attribute->children->content))
77 return make_error(
78 Twine("conflicting attributes for ") +
79 FROM_XML_CHAR(OriginalNode->name));
80 } else {
81 char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name));
82 char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content));
83 xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy));
84 }
85 }
86 #endif
87 return Error::success();
88 }
89
90 Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) {
91 #if LLVM_LIBXML2_ENABLED
92 XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children;
93 for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) {
94 XMLNodeImpl OriginalChildWithName;
95 if (!isMergeableElement(Child->name) ||
96 !(OriginalChildWithName =
97 getChildWithName(OriginalRoot, Child->name))) {
98 XMLNodeImpl NewChild = xmlCopyNode(Child, 1);
99 if (!NewChild)
100 return make_error(Twine("error when copying ") +
101 FROM_XML_CHAR(Child->name));
102 if (NewChild->ns)
103 xmlFreeNs(NewChild->ns); // xmlCopyNode explicitly defines default
104 // namespace, undo this here.
105 if (!xmlAddChild(OriginalRoot, NewChild))
106 return make_error(Twine("could not merge ") +
107 FROM_XML_CHAR(NewChild->name));
108 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
109 return E;
110 }
111 }
112 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
113 return E;
114 #endif
115 return Error::success();
116 }
117
118 void stripCommentsAndText(XMLNodeImpl Root) {
119 xmlNode StoreNext;
120 for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) {
121 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) &&
122 !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
123 stripCommentsAndText(Child);
124 } else {
125 StoreNext.next = Child->next;
126 XMLNodeImpl Remove = Child;
127 Child = &StoreNext;
128 xmlUnlinkNode(Remove);
129 xmlFreeNode(Remove);
130 }
131 }
132 }
133
134 WindowsManifestMerger::~WindowsManifestMerger() {
135 #if LLVM_LIBXML2_ENABLED
136 for (auto &Doc : MergedDocs)
137 xmlFreeDoc(Doc);
138 #endif
139 }
140
26141 Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
27142 #if LLVM_LIBXML2_ENABLED
143 if (Manifest.getBufferSize() == 0)
144 return make_error(
145 "attempted to merge empty manifest");
28146 xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
29147 XMLDocumentImpl ManifestXML =
30148 xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
31 "manifest.xml", nullptr, 0);
149 "manifest.xml", nullptr, XML_PARSE_NOBLANKS);
32150 xmlSetGenericErrorFunc(nullptr, nullptr);
33151 if (auto E = getParseError())
34152 return E;
35 CombinedRoot = xmlDocGetRootElement(ManifestXML);
153 XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML);
154 stripCommentsAndText(AdditionalRoot);
155 if (CombinedDoc == nullptr) {
156 CombinedDoc = ManifestXML;
157 } else {
158 XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc);
159 if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) &&
160 isMergeableElement(AdditionalRoot->name)) {
161 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
162 return E;
163 }
164 } else {
165 XMLNodeImpl NewChild = xmlCopyNode(AdditionalRoot, 1);
166 if (!NewChild)
167 return make_error("could not copy manifest");
168 if (!xmlAddChild(CombinedRoot, NewChild))
169 return make_error("could not append manifest");
170 }
171 }
172 MergedDocs.push_back(ManifestXML);
36173 #endif
37174 return Error::success();
38175 }
41178 #if LLVM_LIBXML2_ENABLED
42179 unsigned char *XmlBuff;
43180 int BufferSize = 0;
44 if (CombinedRoot) {
181 if (CombinedDoc) {
45182 std::unique_ptr OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
46 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
47 xmlDocDumpMemory(OutputDoc.get(), &XmlBuff, &BufferSize);
183 xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc));
184 xmlKeepBlanksDefault(0);
185 xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1);
48186 }
49187 if (BufferSize == 0)
50188 return nullptr;
51189 return MemoryBuffer::getMemBuffer(
52 StringRef(reinterpret_cast(XmlBuff), (size_t)BufferSize));
190 StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize));
53191 #else
54192 return nullptr;
55193 #endif
0 REQUIRES: libxml2
1 UNSUPPORTED: windows
2
3 RUN: not llvm-mt /manifest %p/Inputs/test_manifest.manifest /manifest \
4 RUN: %p/Inputs/conflicting.manifest /out:%t 2>&1 >/dev/null | FileCheck %s
5
6 CHECK: llvm-mt error: conflicting attributes for requestedExecutionLevel
0 REQUIRES: libxml2
1 UNSUPPORTED: windows
2
3 RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /manifest \
4 RUN: %p/Inputs/additional.manifest /out:%t
5 RUN: FileCheck %s -input-file=%t
6
7 CHECK:
8 CHECK-NEXT:
9 CHECK-NEXT:
10 CHECK-NEXT:
11 CHECK-NEXT:
12 CHECK-NEXT:
13 CHECK-NEXT:
14 CHECK-NEXT:
15 CHECK-NEXT:
16 CHECK-NEXT:
17 CHECK-NEXT:
18 CHECK-NEXT:
19 CHECK-NEXT:
20 CHECK-NEXT:
21 CHECK-NEXT:
22 CHECK-NEXT:
23 CHECK-NEXT:
24 CHECK-NEXT:
25 CHECK-NEXT:
26 CHECK-NEXT:
27 CHECK-NEXT:
28 CHECK-NEXT:
29 CHECK-NEXT:
30 CHECK-NEXT:
31 CHECK-NEXT:
32 CHECK-NEXT:
33 CHECK-NEXT:
34 CHECK-NEXT:
35 CHECK-NEXT:
36 CHECK-NEXT:
37 CHECK-NEXT:
38 CHECK-NEXT:
9494 SpecificBumpPtrAllocator ArgAllocator;
9595 ExitOnErr(errorCodeToError(sys::Process::GetArgumentVector(
9696 argv_buf, makeArrayRef(argv, argc), ArgAllocator)));
97
9897 llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
9998
10099 CvtResOptTable T;