blob: 0a8abed230d41a9bb819815693167b6f69d890f2 [file] [log] [blame]
Eric Beckmannc1527442017-07-20 21:42:04 +00001//===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===---------------------------------------------------------------------===//
9//
10// This file implements the .manifest merger class.
11//
12//===---------------------------------------------------------------------===//
13
Eric Beckmannf74bed22017-07-26 01:21:55 +000014#include "llvm/WindowsManifest/WindowsManifestMerger.h"
Eric Beckmannfa580332017-09-14 23:01:13 +000015#include "llvm/Config/config.h"
Eric Beckmannc1527442017-07-20 21:42:04 +000016#include "llvm/Support/MemoryBuffer.h"
17
Eric Beckmann79fe5362017-08-19 00:37:41 +000018#include <map>
19
20#if LLVM_LIBXML2_ENABLED
21#include <libxml/xmlreader.h>
22#endif
Eric Beckmannc1527442017-07-20 21:42:04 +000023
Eric Beckmannec76cbb2017-07-26 00:25:12 +000024#define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
25#define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
26
27using namespace llvm;
Eric Beckmann79fe5362017-08-19 00:37:41 +000028using namespace windows_manifest;
Eric Beckmannc1527442017-07-20 21:42:04 +000029
30char WindowsManifestError::ID = 0;
31
32WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
33
34void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
35
Eric Beckmann79fe5362017-08-19 00:37:41 +000036class WindowsManifestMerger::WindowsManifestMergerImpl {
37public:
38 ~WindowsManifestMergerImpl();
39 Error merge(const MemoryBuffer &Manifest);
40 std::unique_ptr<MemoryBuffer> getMergedManifest();
41
42private:
43 static void errorCallback(void *Ctx, const char *Format, ...);
44 Error getParseError();
Eric Beckmannec76cbb2017-07-26 00:25:12 +000045#if LLVM_LIBXML2_ENABLED
Eric Beckmann79fe5362017-08-19 00:37:41 +000046 xmlDocPtr CombinedDoc = nullptr;
47 std::vector<xmlDocPtr> MergedDocs;
Vitaly Buka074e2822017-09-02 03:15:13 +000048
49 bool Merged = false;
50 struct XmlDeleter {
51 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
52 void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
53 };
54 int BufferSize = 0;
55 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
Eric Beckmann79fe5362017-08-19 00:37:41 +000056#endif
57 bool ParseErrorOccurred = false;
58};
59
60#if LLVM_LIBXML2_ENABLED
61
62static 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"}};
69
Eric Beckmannec76cbb2017-07-26 00:25:12 +000070static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
Eric Beckmann79fe5362017-08-19 00:37:41 +000071 // Handle null pointers. Comparison of 2 null pointers returns true because
72 // this indicates the prefix of a default namespace.
73 if (!A || !B)
74 return A == B;
Eric Beckmannec76cbb2017-07-26 00:25:12 +000075 return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
76}
Eric Beckmannec76cbb2017-07-26 00:25:12 +000077
Eric Beckmann79fe5362017-08-19 00:37:41 +000078static bool isMergeableElement(const unsigned char *ElementName) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +000079 for (StringRef S : {"application", "assembly", "assemblyIdentity",
80 "compatibility", "noInherit", "requestedExecutionLevel",
81 "requestedPrivileges", "security", "trustInfo"}) {
Eric Beckmann79fe5362017-08-19 00:37:41 +000082 if (S == FROM_XML_CHAR(ElementName)) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +000083 return true;
Eric Beckmann79fe5362017-08-19 00:37:41 +000084 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +000085 }
86 return false;
87}
88
Eric Beckmann79fe5362017-08-19 00:37:41 +000089static xmlNodePtr getChildWithName(xmlNodePtr Parent,
90 const unsigned char *ElementName) {
91 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +000092 if (xmlStringsEqual(Child->name, ElementName)) {
93 return Child;
94 }
Eric Beckmann79fe5362017-08-19 00:37:41 +000095 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +000096 return nullptr;
97}
98
Eric Beckmann79fe5362017-08-19 00:37:41 +000099static xmlAttrPtr getAttribute(xmlNodePtr Node,
100 const unsigned char *AttributeName) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000101 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
102 Attribute = Attribute->next) {
Eric Beckmann79fe5362017-08-19 00:37:41 +0000103 if (xmlStringsEqual(Attribute->name, AttributeName)) {
104 return Attribute;
105 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000106 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000107 return nullptr;
108}
109
Eric Beckmann79fe5362017-08-19 00:37:41 +0000110// Check if namespace specified by HRef1 overrides that of HRef2.
111static bool namespaceOverrides(const unsigned char *HRef1,
112 const unsigned char *HRef2) {
113 auto HRef1Position = llvm::find_if(
114 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
115 return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
116 });
117 auto HRef2Position = llvm::find_if(
118 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
119 return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
120 });
121 return HRef1Position < HRef2Position;
122}
123
124// Search for prefix-defined namespace specified by HRef, starting on Node and
125// continuing recursively upwards. Returns the namespace or nullptr if not
126// found.
127static 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)) {
130 return Def;
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000131 }
132 }
Eric Beckmann79fe5362017-08-19 00:37:41 +0000133 if (Node->parent) {
134 return search(HRef, Node->parent);
135 }
136 return nullptr;
137}
138
139// Return the prefix that corresponds to the HRef. If HRef is not a recognized
140// URI, then just return the HRef itself to use as the prefix.
141static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
142 for (auto &Ns : MtNsHrefsPrefixes) {
143 if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
144 return TO_XML_CHAR(Ns.second.data());
145 }
146 }
147 return HRef;
148}
149
150// Search for prefix-defined namespace specified by HRef, starting on Node and
151// continuing recursively upwards. If it is found, then return it. If it is
152// not found, then prefix-define that namespace on the node and return a
153// reference to it.
154static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
155 xmlNodePtr Node) {
156 if (xmlNsPtr Def = search(HRef, Node))
157 return Def;
158 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
159 return Def;
160 return make_error<WindowsManifestError>("failed to create new namespace");
161}
162
163// Set the namespace of OrigionalAttribute on OriginalNode to be that of
164// AdditionalAttribute's.
165static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
166 xmlNodePtr OriginalNode,
167 xmlAttrPtr AdditionalAttribute) {
168
169 Expected<xmlNsPtr> ExplicitOrError =
170 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
171 if (!ExplicitOrError)
172 return ExplicitOrError.takeError();
173 OriginalAttribute->ns = std::move(ExplicitOrError.get());
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000174 return Error::success();
175}
176
Eric Beckmann79fe5362017-08-19 00:37:41 +0000177// Return the corresponding namespace definition for the prefix, defined on the
178// given Node. Returns nullptr if there is no such definition.
179static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
180 xmlNodePtr Node) {
181 if (Node == nullptr)
182 return nullptr;
183 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
184 if (xmlStringsEqual(Def->prefix, Prefix)) {
185 return Def;
186 }
187 }
188 return nullptr;
189}
190
191// Search for the closest inheritable default namespace, starting on (and
192// including) the Node and traveling upwards through parent nodes. Returns
193// nullptr if there are no inheritable default namespaces.
194static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
195 if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
196 return Ret;
197 if (Node->parent == nullptr)
198 return nullptr;
199 return getClosestDefault(Node->parent);
200}
201
202// Merge the attributes of AdditionalNode into OriginalNode. If attributes
203// with identical types are present, they are not duplicated but rather if
204// their values are not consistent and error is thrown. In addition, the
205// higher priority namespace is used for each attribute, EXCEPT in the case
206// of merging two default namespaces and the lower priority namespace
207// definition occurs closer than the higher priority one.
208static Error mergeAttributes(xmlNodePtr OriginalNode,
209 xmlNodePtr AdditionalNode) {
210 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
211 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
212 Attribute = Attribute->next) {
213 if (xmlAttrPtr OriginalAttribute =
214 getAttribute(OriginalNode, Attribute->name)) {
215 if (!xmlStringsEqual(OriginalAttribute->children->content,
216 Attribute->children->content)) {
217 return make_error<WindowsManifestError>(
218 Twine("conflicting attributes for ") +
219 FROM_XML_CHAR(OriginalNode->name));
220 }
221 if (!Attribute->ns) {
222 continue;
223 }
224 if (!OriginalAttribute->ns) {
225 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
226 Attribute)) {
227 return E;
228 }
229 continue;
230 }
231 if (namespaceOverrides(OriginalAttribute->ns->href,
232 Attribute->ns->href)) {
233 // In this case, the original attribute has a higher priority namespace
234 // than the incomiing attribute, however the namespace definition of
235 // the lower priority namespace occurs first traveling upwards in the
236 // tree. Therefore the lower priority namespace is applied.
237 if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
238 ClosestDefault &&
239 xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
240 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
241 Attribute)) {
242 return E;
243 }
244 continue;
245 }
246 continue;
247 // This covers the case where the incoming attribute has the higher
248 // priority. The higher priority namespace is applied in all cases
249 // EXCEPT when both of the namespaces are default inherited, and the
250 // closest inherited default is the lower priority one.
251 }
252 if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
253 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
254 ClosestDefault->href))) {
255 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
256 Attribute)) {
257 return E;
258 }
259 continue;
260 }
261 continue;
262 }
263 // If the incoming attribute is not already found on the node, append it
264 // to the end of the properties list. Also explicitly apply its
265 // namespace as a prefix because it might be contained in a separate
266 // namespace that doesn't use the attribute.
267 xmlAttrPtr NewProp =
268 xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
269 Expected<xmlNsPtr> ExplicitOrError =
270 searchOrDefine(Attribute->ns->href, OriginalNode);
271 if (!ExplicitOrError)
272 return ExplicitOrError.takeError();
273 NewProp->ns = std::move(ExplicitOrError.get());
274 }
275 return Error::success();
276}
277
278// Given two nodes, return the one with the higher priority namespace.
279static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
280
281 if (!Node1 || !Node1->ns)
282 return Node2;
283 if (!Node2 || !Node2->ns)
284 return Node1;
285 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
286 return Node1;
287 return Node2;
288}
289
290// Checks if this Node's namespace is inherited or one it defined itself.
291static bool hasInheritedNs(xmlNodePtr Node) {
292 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
293}
294
295// Check if this Node's namespace is a default namespace that it inherited, as
296// opposed to defining itself.
297static bool hasInheritedDefaultNs(xmlNodePtr Node) {
298 return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
299}
300
301// Check if this Node's namespace is a default namespace it defined itself.
302static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
303 return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
304}
305
306// For the given explicit prefix-definition of a namespace, travel downwards
307// from a node recursively, and for every implicit, inherited default usage of
308// that namespace replace it with that explicit prefix use. This is important
309// when namespace overriding occurs when merging, so that elements unique to a
310// namespace will still stay in that namespace.
311static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
312 // If a node as its own default namespace definition it clearly cannot have
313 // inherited the given default namespace, and neither will any of its
314 // children.
315 if (hasDefinedDefaultNamespace(Node))
316 return;
317 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
318 hasInheritedDefaultNs(Node))
319 Node->ns = PrefixDef;
320 for (xmlAttrPtr Attribute = Node->properties; Attribute;
321 Attribute = Attribute->next) {
322 if (Attribute->ns &&
323 xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
324 Attribute->ns = PrefixDef;
325 }
326 }
327 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
328 explicateNamespace(PrefixDef, Child);
329 }
330}
331
332// Perform the namespace merge between two nodes.
333static Error mergeNamespaces(xmlNodePtr OriginalNode,
334 xmlNodePtr AdditionalNode) {
335 // Save the original default namespace definition in case the incoming node
336 // overrides it.
337 const unsigned char *OriginalDefinedDefaultHref = nullptr;
338 if (xmlNsPtr OriginalDefinedDefaultNs =
339 getNamespaceWithPrefix(nullptr, OriginalNode)) {
340 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
341 }
342 const unsigned char *NewDefinedDefaultHref = nullptr;
343 // Copy all namespace definitions. There can only be one default namespace
344 // definition per node, so the higher priority one takes precedence in the
345 // case of collision.
346 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
347 if (xmlNsPtr OriginalNsDef =
348 getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
349 if (!Def->prefix) {
350 if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
351 NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
352 }
353 } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
354 return make_error<WindowsManifestError>(
355 Twine("conflicting namespace definitions for ") +
356 FROM_XML_CHAR(Def->prefix));
357 }
358 } else {
359 xmlNsPtr NewDef = xmlCopyNamespace(Def);
360 NewDef->next = OriginalNode->nsDef;
361 OriginalNode->nsDef = NewDef;
362 }
363 }
364
365 // Check whether the original node or the incoming node has the higher
366 // priority namespace. Depending on which one is dominant, we will have
367 // to recursively apply namespace changes down to children of the original
368 // node.
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);
376 // In this case, both the nodes defined a default namespace. However
377 // the lower priority node ended up having a higher priority default
378 // definition. This can occur if the higher priority node is prefix
379 // namespace defined. In this case we have to define an explicit
380 // prefix for the overridden definition and apply it to all children
381 // who relied on that definition.
382 if (NonDominantDefinedDefault &&
383 namespaceOverrides(NonDominantDefinedDefault->href,
384 OriginalDefinedDefaultHref)) {
385 Expected<xmlNsPtr> EC =
386 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
387 if (!EC) {
388 return EC.takeError();
389 }
390 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
391 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
392 }
393 // In this case the node with a higher priority namespace did not have a
394 // default namespace definition, but the lower priority node did. In this
395 // case the new default namespace definition is copied. A side effect of
396 // this is that all children will suddenly find themselves in a different
397 // default namespace. To maintain correctness we need to ensure that all
398 // children now explicitly refer to the namespace that they had previously
399 // implicitly inherited.
400 } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
401 if (DominantNode->parent) {
402 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
403 Expected<xmlNsPtr> EC =
404 searchOrDefine(ClosestDefault->href, DominantNode);
405 if (!EC) {
406 return EC.takeError();
407 }
408 xmlNsPtr ExplicitDefault = std::move(EC.get());
409 explicateNamespace(ExplicitDefault, DominantNode);
410 }
411 }
412 } else {
413 // Covers case where the incoming node has a default namespace definition
414 // that overrides the original node's namespace. This always leads to
415 // the original node receiving that new default namespace.
416 if (hasDefinedDefaultNamespace(DominantNode)) {
417 NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
418 } else {
419 // This covers the case where the incoming node either has a prefix
420 // namespace, or an inherited default namespace. Since the namespace
421 // may not yet be defined in the original tree we do a searchOrDefine
422 // for it, and then set the namespace equal to it.
423 Expected<xmlNsPtr> EC =
424 searchOrDefine(DominantNode->ns->href, NonDominantNode);
425 if (!EC) {
426 return EC.takeError();
427 }
428 xmlNsPtr Explicit = std::move(EC.get());
429 NonDominantNode->ns = Explicit;
430 }
431 // This covers cases where the incoming dominant node HAS a default
432 // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
433 if (xmlNsPtr DominantDefaultDefined =
434 getNamespaceWithPrefix(nullptr, DominantNode)) {
435 if (OriginalDefinedDefaultHref) {
436 if (namespaceOverrides(DominantDefaultDefined->href,
437 OriginalDefinedDefaultHref)) {
438 // In this case, the incoming node's default definition overrides
439 // the original default definition, all children who relied on that
440 // definition must be updated accordingly.
441 Expected<xmlNsPtr> EC =
442 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
443 if (!EC) {
444 return EC.takeError();
445 }
446 xmlNsPtr ExplicitDefault = std::move(EC.get());
447 explicateNamespace(ExplicitDefault, NonDominantNode);
448 }
449 } else {
450 // The original did not define a default definition, however the new
451 // default definition still applies to all children, so they must be
452 // updated to explicitly refer to the namespace they had previously
453 // been inheriting implicitly.
454 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
455 Expected<xmlNsPtr> EC =
456 searchOrDefine(ClosestDefault->href, NonDominantNode);
457 if (!EC) {
458 return EC.takeError();
459 }
460 xmlNsPtr ExplicitDefault = std::move(EC.get());
461 explicateNamespace(ExplicitDefault, NonDominantNode);
462 }
463 }
464 }
465 if (NewDefinedDefaultHref) {
466 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
467 xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
468 OriginalNsDef->href = NewDefinedDefaultHref;
469 }
470 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
471 return Error::success();
472}
473
474static bool isRecognizedNamespace(const unsigned char *NsHref) {
475 for (auto &Ns : MtNsHrefsPrefixes) {
476 if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
477 return true;
478 }
479 }
480 return false;
481}
482
483static bool hasRecognizedNamespace(xmlNodePtr Node) {
484 return isRecognizedNamespace(Node->ns->href);
485}
486
487// Ensure a node's inherited namespace is actually defined in the tree it
488// resides in.
489static Error reconcileNamespaces(xmlNodePtr Node) {
490 if (!Node) {
491 return Error::success();
492 }
493 if (hasInheritedNs(Node)) {
494 Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
495 if (!ExplicitOrError) {
496 return ExplicitOrError.takeError();
497 }
498 xmlNsPtr Explicit = std::move(ExplicitOrError.get());
499 Node->ns = Explicit;
500 }
501 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
502 if (auto E = reconcileNamespaces(Child)) {
503 return E;
504 }
505 }
506 return Error::success();
507}
508
509// Recursively merge the two given manifest trees, depending on which elements
510// are of a mergeable type, and choose namespaces according to which have
511// higher priority.
512static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
513 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
514 return E;
515 if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
516 return E;
517 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
Eric Beckmann6caf0872017-07-26 18:33:21 +0000518 xmlNode StoreNext;
Eric Beckmann79fe5362017-08-19 00:37:41 +0000519 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
520 xmlNodePtr OriginalChildWithName;
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000521 if (!isMergeableElement(Child->name) ||
522 !(OriginalChildWithName =
Eric Beckmann79fe5362017-08-19 00:37:41 +0000523 getChildWithName(OriginalRoot, Child->name)) ||
524 !hasRecognizedNamespace(Child)) {
Eric Beckmann6caf0872017-07-26 18:33:21 +0000525 StoreNext.next = Child->next;
526 xmlUnlinkNode(Child);
Eric Beckmann79fe5362017-08-19 00:37:41 +0000527 if (!xmlAddChild(OriginalRoot, Child)) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000528 return make_error<WindowsManifestError>(Twine("could not merge ") +
Eric Beckmann6caf0872017-07-26 18:33:21 +0000529 FROM_XML_CHAR(Child->name));
Eric Beckmann79fe5362017-08-19 00:37:41 +0000530 }
531 if (auto E = reconcileNamespaces(Child)) {
532 return E;
533 }
Eric Beckmann6caf0872017-07-26 18:33:21 +0000534 Child = &StoreNext;
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000535 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
536 return E;
537 }
538 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000539 return Error::success();
540}
541
Eric Beckmann79fe5362017-08-19 00:37:41 +0000542static void stripComments(xmlNodePtr Root) {
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000543 xmlNode StoreNext;
Eric Beckmann79fe5362017-08-19 00:37:41 +0000544 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
545 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
546 stripComments(Child);
547 continue;
548 }
549 StoreNext.next = Child->next;
550 xmlNodePtr Remove = Child;
551 Child = &StoreNext;
552 xmlUnlinkNode(Remove);
553 xmlFreeNode(Remove);
554 }
555}
556
557// libxml2 assumes that attributes do not inherit default namespaces, whereas
558// the original mt.exe does make this assumption. This function reconciles
559// this by setting all attributes to have the inherited default namespace.
560static void setAttributeNamespaces(xmlNodePtr Node) {
561 for (xmlAttrPtr Attribute = Node->properties; Attribute;
562 Attribute = Attribute->next) {
563 if (!Attribute->ns) {
564 Attribute->ns = getClosestDefault(Node);
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000565 }
566 }
Eric Beckmann79fe5362017-08-19 00:37:41 +0000567 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
568 setAttributeNamespaces(Child);
569 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000570}
571
Eric Beckmann79fe5362017-08-19 00:37:41 +0000572// The merging process may create too many prefix defined namespaces. This
573// function removes all unnecessary ones from the tree.
574static void checkAndStripPrefixes(xmlNodePtr Node,
575 std::vector<xmlNsPtr> &RequiredPrefixes) {
576 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
577 checkAndStripPrefixes(Child, RequiredPrefixes);
578 }
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;
584 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
585 RequiredPrefixes.push_back(Node->ns);
586 }
587 }
588 for (xmlAttrPtr Attribute = Node->properties; Attribute;
589 Attribute = Attribute->next) {
590 if (Attribute->ns && Attribute->ns->prefix != nullptr) {
591 xmlNsPtr ClosestDefault = getClosestDefault(Node);
592 if (ClosestDefault &&
593 xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
594 Attribute->ns = ClosestDefault;
595 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
596 RequiredPrefixes.push_back(Attribute->ns);
597 }
598 }
599 }
600 xmlNsPtr Prev;
601 xmlNs Temp;
602 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
603 if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
604 Prev = Def;
605 continue;
606 }
607 if (Def == Node->nsDef) {
608 Node->nsDef = Def->next;
609 } else {
610 Prev->next = Def->next;
611 }
612 Temp.next = Def->next;
613 xmlFreeNs(Def);
614 Def = &Temp;
615 }
616}
617
618WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000619 for (auto &Doc : MergedDocs)
620 xmlFreeDoc(Doc);
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000621}
622
Eric Beckmann79fe5362017-08-19 00:37:41 +0000623Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
624 const MemoryBuffer &Manifest) {
Vitaly Buka074e2822017-09-02 03:15:13 +0000625 if (Merged)
626 return make_error<WindowsManifestError>(
627 "merge after getMergedManifest is not supported");
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000628 if (Manifest.getBufferSize() == 0)
629 return make_error<WindowsManifestError>(
630 "attempted to merge empty manifest");
Eric Beckmann79fe5362017-08-19 00:37:41 +0000631 xmlSetGenericErrorFunc((void *)this,
632 WindowsManifestMergerImpl::errorCallback);
Vitaly Buka074e2822017-09-02 03:15:13 +0000633 xmlDocPtr ManifestXML = xmlReadMemory(
634 Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml",
635 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT);
Eric Beckmannc1527442017-07-20 21:42:04 +0000636 xmlSetGenericErrorFunc(nullptr, nullptr);
637 if (auto E = getParseError())
638 return E;
Eric Beckmann79fe5362017-08-19 00:37:41 +0000639 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
640 stripComments(AdditionalRoot);
641 setAttributeNamespaces(AdditionalRoot);
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000642 if (CombinedDoc == nullptr) {
643 CombinedDoc = ManifestXML;
644 } else {
Eric Beckmann79fe5362017-08-19 00:37:41 +0000645 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
646 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
647 !isMergeableElement(AdditionalRoot->name) ||
648 !hasRecognizedNamespace(AdditionalRoot)) {
Eric Beckmann6caf0872017-07-26 18:33:21 +0000649 return make_error<WindowsManifestError>("multiple root nodes");
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000650 }
Eric Beckmann79fe5362017-08-19 00:37:41 +0000651 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
652 return E;
653 }
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000654 }
655 MergedDocs.push_back(ManifestXML);
Eric Beckmannc1527442017-07-20 21:42:04 +0000656 return Error::success();
657}
658
Eric Beckmann79fe5362017-08-19 00:37:41 +0000659std::unique_ptr<MemoryBuffer>
660WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
Vitaly Buka074e2822017-09-02 03:15:13 +0000661 if (!Merged) {
662 Merged = true;
663
664 if (!CombinedDoc)
665 return nullptr;
666
Eric Beckmann79fe5362017-08-19 00:37:41 +0000667 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
668 std::vector<xmlNsPtr> RequiredPrefixes;
669 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
Vitaly Buka074e2822017-09-02 03:15:13 +0000670 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
671 xmlNewDoc((const unsigned char *)"1.0"));
Eric Beckmann79fe5362017-08-19 00:37:41 +0000672 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
Vitaly Buka074e2822017-09-02 03:15:13 +0000673 assert(0 == xmlDocGetRootElement(CombinedDoc));
674
Eric Beckmannec76cbb2017-07-26 00:25:12 +0000675 xmlKeepBlanksDefault(0);
Vitaly Buka074e2822017-09-02 03:15:13 +0000676 xmlChar *Buff = nullptr;
677 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1);
678 Buffer.reset(Buff);
Eric Beckmannc1527442017-07-20 21:42:04 +0000679 }
Vitaly Buka074e2822017-09-02 03:15:13 +0000680
Vitaly Buka2ce7ffd2017-09-02 05:14:55 +0000681 return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef(
Vitaly Buka074e2822017-09-02 03:15:13 +0000682 FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize))
683 : nullptr;
Eric Beckmannc1527442017-07-20 21:42:04 +0000684}
685
Eric Beckmanne8aea292017-09-06 01:50:36 +0000686bool windows_manifest::isAvailable() { return true; }
687
Eric Beckmann79fe5362017-08-19 00:37:41 +0000688#else
689
690WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
691}
692
693Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
694 const MemoryBuffer &Manifest) {
Eric Beckmann3c6e1262017-08-22 03:15:28 +0000695 return make_error<WindowsManifestError>("no libxml2");
Eric Beckmann79fe5362017-08-19 00:37:41 +0000696}
697
698std::unique_ptr<MemoryBuffer>
699WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
700 return nullptr;
701}
702
Eric Beckmanne8aea292017-09-06 01:50:36 +0000703bool windows_manifest::isAvailable() { return false; }
704
Eric Beckmann79fe5362017-08-19 00:37:41 +0000705#endif
706
707WindowsManifestMerger::WindowsManifestMerger()
708 : Impl(make_unique<WindowsManifestMergerImpl>()) {}
709
710WindowsManifestMerger::~WindowsManifestMerger() {}
711
712Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
713 return Impl->merge(Manifest);
714}
715
716std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
717 return Impl->getMergedManifest();
718}
719
720void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
721 void *Ctx, const char *Format, ...) {
722 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
Eric Beckmannc1527442017-07-20 21:42:04 +0000723 Merger->ParseErrorOccurred = true;
724}
725
Eric Beckmann79fe5362017-08-19 00:37:41 +0000726Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
Eric Beckmannc1527442017-07-20 21:42:04 +0000727 if (!ParseErrorOccurred)
728 return Error::success();
729 return make_error<WindowsManifestError>("invalid xml document");
730}