llvm.org GIT mirror llvm / ec76cbb
Reapply "llvm-mt: implement simple merging of manifests, not factoring namespaces. This time with correct #if. This reverts commit 9cf4eca0e0383040c1ff1416815c7f649650c2a0. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@309064 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
8 changed file(s) with 242 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 #if LLVM_LIBXML2_ENABLED
32 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
33 return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
34 }
35 #endif
36
37 bool isMergeableElement(const unsigned char *ElementName) {
38 for (StringRef S : {"application", "assembly", "assemblyIdentity",
39 "compatibility", "noInherit", "requestedExecutionLevel",
40 "requestedPrivileges", "security", "trustInfo"}) {
41 if (S == FROM_XML_CHAR(ElementName))
42 return true;
43 }
44 return false;
45 }
46
47 XMLNodeImpl getChildWithName(XMLNodeImpl Parent,
48 const unsigned char *ElementName) {
49 #if LLVM_LIBXML2_ENABLED
50 for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next)
51 if (xmlStringsEqual(Child->name, ElementName)) {
52 return Child;
53 }
54 #endif
55 return nullptr;
56 }
57
58 const unsigned char *getAttribute(XMLNodeImpl Node,
59 const unsigned char *AttributeName) {
60 #if LLVM_LIBXML2_ENABLED
61 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
62 Attribute = Attribute->next) {
63 if (xmlStringsEqual(Attribute->name, AttributeName))
64 return Attribute->children->content;
65 }
66 #endif
67 return nullptr;
68 }
69
70 Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) {
71 #if LLVM_LIBXML2_ENABLED
72 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr;
73 Attribute = Attribute->next) {
74 if (const unsigned char *OriginalValue =
75 getAttribute(OriginalNode, Attribute->name)) {
76 // Attributes of the same name must also have the same value. Otherwise
77 // an error is thrown.
78 if (!xmlStringsEqual(OriginalValue, Attribute->children->content))
79 return make_error(
80 Twine("conflicting attributes for ") +
81 FROM_XML_CHAR(OriginalNode->name));
82 } else {
83 char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name));
84 char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content));
85 xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy));
86 }
87 }
88 #endif
89 return Error::success();
90 }
91
92 Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) {
93 #if LLVM_LIBXML2_ENABLED
94 XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children;
95 for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) {
96 XMLNodeImpl OriginalChildWithName;
97 if (!isMergeableElement(Child->name) ||
98 !(OriginalChildWithName =
99 getChildWithName(OriginalRoot, Child->name))) {
100 XMLNodeImpl NewChild = xmlCopyNode(Child, 1);
101 if (!NewChild)
102 return make_error(Twine("error when copying ") +
103 FROM_XML_CHAR(Child->name));
104 if (NewChild->ns)
105 xmlFreeNs(NewChild->ns); // xmlCopyNode explicitly defines default
106 // namespace, undo this here.
107 if (!xmlAddChild(OriginalRoot, NewChild))
108 return make_error(Twine("could not merge ") +
109 FROM_XML_CHAR(NewChild->name));
110 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
111 return E;
112 }
113 }
114 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
115 return E;
116 #endif
117 return Error::success();
118 }
119
120 void stripCommentsAndText(XMLNodeImpl Root) {
121 #if LLVM_LIBXML2_ENABLED
122 xmlNode StoreNext;
123 for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) {
124 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) &&
125 !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
126 stripCommentsAndText(Child);
127 } else {
128 StoreNext.next = Child->next;
129 XMLNodeImpl Remove = Child;
130 Child = &StoreNext;
131 xmlUnlinkNode(Remove);
132 xmlFreeNode(Remove);
133 }
134 }
135 #endif
136 }
137
138 WindowsManifestMerger::~WindowsManifestMerger() {
139 #if LLVM_LIBXML2_ENABLED
140 for (auto &Doc : MergedDocs)
141 xmlFreeDoc(Doc);
142 #endif
143 }
144
26145 Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
27146 #if LLVM_LIBXML2_ENABLED
147 if (Manifest.getBufferSize() == 0)
148 return make_error(
149 "attempted to merge empty manifest");
28150 xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
29151 XMLDocumentImpl ManifestXML =
30152 xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
31 "manifest.xml", nullptr, 0);
153 "manifest.xml", nullptr, XML_PARSE_NOBLANKS);
32154 xmlSetGenericErrorFunc(nullptr, nullptr);
33155 if (auto E = getParseError())
34156 return E;
35 CombinedRoot = xmlDocGetRootElement(ManifestXML);
157 XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML);
158 stripCommentsAndText(AdditionalRoot);
159 if (CombinedDoc == nullptr) {
160 CombinedDoc = ManifestXML;
161 } else {
162 XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc);
163 if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) &&
164 isMergeableElement(AdditionalRoot->name)) {
165 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
166 return E;
167 }
168 } else {
169 XMLNodeImpl NewChild = xmlCopyNode(AdditionalRoot, 1);
170 if (!NewChild)
171 return make_error("could not copy manifest");
172 if (!xmlAddChild(CombinedRoot, NewChild))
173 return make_error("could not append manifest");
174 }
175 }
176 MergedDocs.push_back(ManifestXML);
36177 #endif
37178 return Error::success();
38179 }
41182 #if LLVM_LIBXML2_ENABLED
42183 unsigned char *XmlBuff;
43184 int BufferSize = 0;
44 if (CombinedRoot) {
185 if (CombinedDoc) {
45186 std::unique_ptr OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
46 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
47 xmlDocDumpMemory(OutputDoc.get(), &XmlBuff, &BufferSize);
187 xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc));
188 xmlKeepBlanksDefault(0);
189 xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1);
48190 }
49191 if (BufferSize == 0)
50192 return nullptr;
51193 return MemoryBuffer::getMemBuffer(
52 StringRef(reinterpret_cast(XmlBuff), (size_t)BufferSize));
194 StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize));
53195 #else
54196 return nullptr;
55197 #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;