1 //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===---------------------------------------------------------------------===//
8 //
9 // This file implements the .manifest merger class.
10 //
11 //===---------------------------------------------------------------------===//
12
13 #include "llvm/WindowsManifest/WindowsManifestMerger.h"
14 #include "llvm/Config/config.h"
15 #include "llvm/Support/MemoryBuffer.h"
16
17 #if LLVM_ENABLE_LIBXML2
18 #include <libxml/xmlreader.h>
19 #endif
20
21 #define TO_XML_CHAR(X) reinterpret_cast<const unsigned char *>(X)
22 #define FROM_XML_CHAR(X) reinterpret_cast<const char *>(X)
23
24 using namespace llvm;
25 using namespace windows_manifest;
26
27 char WindowsManifestError::ID = 0;
28
WindowsManifestError(const Twine & Msg)29 WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
30
log(raw_ostream & OS) const31 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
32
33 class WindowsManifestMerger::WindowsManifestMergerImpl {
34 public:
35 Error merge(MemoryBufferRef Manifest);
36 std::unique_ptr<MemoryBuffer> getMergedManifest();
37
38 private:
39 static void errorCallback(void *Ctx, const char *Format, ...);
40 Error getParseError();
41 #if LLVM_ENABLE_LIBXML2
42 struct XmlDeleter {
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter43 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
operator ()WindowsManifestMerger::WindowsManifestMergerImpl::XmlDeleter44 void operator()(xmlDoc *Ptr) { xmlFreeDoc(Ptr); }
45 };
46 xmlDocPtr CombinedDoc = nullptr;
47 std::vector<std::unique_ptr<xmlDoc, XmlDeleter>> MergedDocs;
48 bool Merged = false;
49 int BufferSize = 0;
50 std::unique_ptr<xmlChar, XmlDeleter> Buffer;
51 #endif
52 bool ParseErrorOccurred = false;
53 };
54
55 #if LLVM_ENABLE_LIBXML2
56
57 static constexpr std::pair<StringLiteral, StringLiteral> MtNsHrefsPrefixes[] = {
58 {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
59 {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
60 {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
61 {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
62 "ms_windowsSettings"},
63 {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
64
xmlStringsEqual(const unsigned char * A,const unsigned char * B)65 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
66 // Handle null pointers. Comparison of 2 null pointers returns true because
67 // this indicates the prefix of a default namespace.
68 if (!A || !B)
69 return A == B;
70 return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
71 }
72
isMergeableElement(const unsigned char * ElementName)73 static bool isMergeableElement(const unsigned char *ElementName) {
74 for (StringRef S : {"application", "assembly", "assemblyIdentity",
75 "compatibility", "noInherit", "requestedExecutionLevel",
76 "requestedPrivileges", "security", "trustInfo"}) {
77 if (S == FROM_XML_CHAR(ElementName)) {
78 return true;
79 }
80 }
81 return false;
82 }
83
getChildWithName(xmlNodePtr Parent,const unsigned char * ElementName)84 static xmlNodePtr getChildWithName(xmlNodePtr Parent,
85 const unsigned char *ElementName) {
86 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
87 if (xmlStringsEqual(Child->name, ElementName)) {
88 return Child;
89 }
90 }
91 return nullptr;
92 }
93
getAttribute(xmlNodePtr Node,const unsigned char * AttributeName)94 static xmlAttrPtr getAttribute(xmlNodePtr Node,
95 const unsigned char *AttributeName) {
96 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
97 Attribute = Attribute->next) {
98 if (xmlStringsEqual(Attribute->name, AttributeName)) {
99 return Attribute;
100 }
101 }
102 return nullptr;
103 }
104
105 // Check if namespace specified by HRef1 overrides that of HRef2.
namespaceOverrides(const unsigned char * HRef1,const unsigned char * HRef2)106 static bool namespaceOverrides(const unsigned char *HRef1,
107 const unsigned char *HRef2) {
108 auto HRef1Position = llvm::find_if(
109 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
110 return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
111 });
112 auto HRef2Position = llvm::find_if(
113 MtNsHrefsPrefixes, [=](const std::pair<StringRef, StringRef> &Element) {
114 return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
115 });
116 return HRef1Position < HRef2Position;
117 }
118
119 // Search for prefix-defined namespace specified by HRef, starting on Node and
120 // continuing recursively upwards. Returns the namespace or nullptr if not
121 // found.
search(const unsigned char * HRef,xmlNodePtr Node)122 static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
123 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
124 if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
125 return Def;
126 }
127 }
128 if (Node->parent) {
129 return search(HRef, Node->parent);
130 }
131 return nullptr;
132 }
133
134 // Return the prefix that corresponds to the HRef. If HRef is not a recognized
135 // URI, then just return the HRef itself to use as the prefix.
getPrefixForHref(const unsigned char * HRef)136 static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
137 for (auto &Ns : MtNsHrefsPrefixes) {
138 if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
139 return TO_XML_CHAR(Ns.second.data());
140 }
141 }
142 return HRef;
143 }
144
145 // Search for prefix-defined namespace specified by HRef, starting on Node and
146 // continuing recursively upwards. If it is found, then return it. If it is
147 // not found, then prefix-define that namespace on the node and return a
148 // reference to it.
searchOrDefine(const unsigned char * HRef,xmlNodePtr Node)149 static Expected<xmlNsPtr> searchOrDefine(const unsigned char *HRef,
150 xmlNodePtr Node) {
151 if (xmlNsPtr Def = search(HRef, Node))
152 return Def;
153 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
154 return Def;
155 return make_error<WindowsManifestError>("failed to create new namespace");
156 }
157
158 // Set the namespace of OrigionalAttribute on OriginalNode to be that of
159 // AdditionalAttribute's.
copyAttributeNamespace(xmlAttrPtr OriginalAttribute,xmlNodePtr OriginalNode,xmlAttrPtr AdditionalAttribute)160 static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
161 xmlNodePtr OriginalNode,
162 xmlAttrPtr AdditionalAttribute) {
163
164 Expected<xmlNsPtr> ExplicitOrError =
165 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
166 if (!ExplicitOrError)
167 return ExplicitOrError.takeError();
168 OriginalAttribute->ns = std::move(ExplicitOrError.get());
169 return Error::success();
170 }
171
172 // Return the corresponding namespace definition for the prefix, defined on the
173 // given Node. Returns nullptr if there is no such definition.
getNamespaceWithPrefix(const unsigned char * Prefix,xmlNodePtr Node)174 static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
175 xmlNodePtr Node) {
176 if (Node == nullptr)
177 return nullptr;
178 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
179 if (xmlStringsEqual(Def->prefix, Prefix)) {
180 return Def;
181 }
182 }
183 return nullptr;
184 }
185
186 // Search for the closest inheritable default namespace, starting on (and
187 // including) the Node and traveling upwards through parent nodes. Returns
188 // nullptr if there are no inheritable default namespaces.
getClosestDefault(xmlNodePtr Node)189 static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
190 if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
191 return Ret;
192 if (Node->parent == nullptr)
193 return nullptr;
194 return getClosestDefault(Node->parent);
195 }
196
197 // Merge the attributes of AdditionalNode into OriginalNode. If attributes
198 // with identical types are present, they are not duplicated but rather if
199 // their values are not consistent and error is thrown. In addition, the
200 // higher priority namespace is used for each attribute, EXCEPT in the case
201 // of merging two default namespaces and the lower priority namespace
202 // definition occurs closer than the higher priority one.
mergeAttributes(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)203 static Error mergeAttributes(xmlNodePtr OriginalNode,
204 xmlNodePtr AdditionalNode) {
205 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
206 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
207 Attribute = Attribute->next) {
208 if (xmlAttrPtr OriginalAttribute =
209 getAttribute(OriginalNode, Attribute->name)) {
210 if (!xmlStringsEqual(OriginalAttribute->children->content,
211 Attribute->children->content)) {
212 return make_error<WindowsManifestError>(
213 Twine("conflicting attributes for ") +
214 FROM_XML_CHAR(OriginalNode->name));
215 }
216 if (!Attribute->ns) {
217 continue;
218 }
219 if (!OriginalAttribute->ns) {
220 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
221 Attribute)) {
222 return E;
223 }
224 continue;
225 }
226 if (namespaceOverrides(OriginalAttribute->ns->href,
227 Attribute->ns->href)) {
228 // In this case, the original attribute has a higher priority namespace
229 // than the incomiing attribute, however the namespace definition of
230 // the lower priority namespace occurs first traveling upwards in the
231 // tree. Therefore the lower priority namespace is applied.
232 if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
233 ClosestDefault &&
234 xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
235 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
236 Attribute)) {
237 return E;
238 }
239 continue;
240 }
241 continue;
242 // This covers the case where the incoming attribute has the higher
243 // priority. The higher priority namespace is applied in all cases
244 // EXCEPT when both of the namespaces are default inherited, and the
245 // closest inherited default is the lower priority one.
246 }
247 if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
248 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
249 ClosestDefault->href))) {
250 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
251 Attribute)) {
252 return E;
253 }
254 continue;
255 }
256 continue;
257 }
258 // If the incoming attribute is not already found on the node, append it
259 // to the end of the properties list. Also explicitly apply its
260 // namespace as a prefix because it might be contained in a separate
261 // namespace that doesn't use the attribute.
262 xmlAttrPtr NewProp =
263 xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
264 Expected<xmlNsPtr> ExplicitOrError =
265 searchOrDefine(Attribute->ns->href, OriginalNode);
266 if (!ExplicitOrError)
267 return ExplicitOrError.takeError();
268 NewProp->ns = std::move(ExplicitOrError.get());
269 }
270 return Error::success();
271 }
272
273 // Given two nodes, return the one with the higher priority namespace.
getDominantNode(xmlNodePtr Node1,xmlNodePtr Node2)274 static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
275
276 if (!Node1 || !Node1->ns)
277 return Node2;
278 if (!Node2 || !Node2->ns)
279 return Node1;
280 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
281 return Node1;
282 return Node2;
283 }
284
285 // Checks if this Node's namespace is inherited or one it defined itself.
hasInheritedNs(xmlNodePtr Node)286 static bool hasInheritedNs(xmlNodePtr Node) {
287 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
288 }
289
290 // Check if this Node's namespace is a default namespace that it inherited, as
291 // opposed to defining itself.
hasInheritedDefaultNs(xmlNodePtr Node)292 static bool hasInheritedDefaultNs(xmlNodePtr Node) {
293 return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
294 }
295
296 // Check if this Node's namespace is a default namespace it defined itself.
hasDefinedDefaultNamespace(xmlNodePtr Node)297 static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
298 return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
299 }
300
301 // For the given explicit prefix-definition of a namespace, travel downwards
302 // from a node recursively, and for every implicit, inherited default usage of
303 // that namespace replace it with that explicit prefix use. This is important
304 // when namespace overriding occurs when merging, so that elements unique to a
305 // namespace will still stay in that namespace.
explicateNamespace(xmlNsPtr PrefixDef,xmlNodePtr Node)306 static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
307 // If a node as its own default namespace definition it clearly cannot have
308 // inherited the given default namespace, and neither will any of its
309 // children.
310 if (hasDefinedDefaultNamespace(Node))
311 return;
312 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
313 hasInheritedDefaultNs(Node))
314 Node->ns = PrefixDef;
315 for (xmlAttrPtr Attribute = Node->properties; Attribute;
316 Attribute = Attribute->next) {
317 if (Attribute->ns &&
318 xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
319 Attribute->ns = PrefixDef;
320 }
321 }
322 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
323 explicateNamespace(PrefixDef, Child);
324 }
325 }
326
327 // Perform the namespace merge between two nodes.
mergeNamespaces(xmlNodePtr OriginalNode,xmlNodePtr AdditionalNode)328 static Error mergeNamespaces(xmlNodePtr OriginalNode,
329 xmlNodePtr AdditionalNode) {
330 // Save the original default namespace definition in case the incoming node
331 // overrides it.
332 const unsigned char *OriginalDefinedDefaultHref = nullptr;
333 if (xmlNsPtr OriginalDefinedDefaultNs =
334 getNamespaceWithPrefix(nullptr, OriginalNode)) {
335 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
336 }
337 const unsigned char *NewDefinedDefaultHref = nullptr;
338 // Copy all namespace definitions. There can only be one default namespace
339 // definition per node, so the higher priority one takes precedence in the
340 // case of collision.
341 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
342 if (xmlNsPtr OriginalNsDef =
343 getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
344 if (!Def->prefix) {
345 if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
346 NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
347 }
348 } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
349 return make_error<WindowsManifestError>(
350 Twine("conflicting namespace definitions for ") +
351 FROM_XML_CHAR(Def->prefix));
352 }
353 } else {
354 xmlNsPtr NewDef = xmlCopyNamespace(Def);
355 NewDef->next = OriginalNode->nsDef;
356 OriginalNode->nsDef = NewDef;
357 }
358 }
359
360 // Check whether the original node or the incoming node has the higher
361 // priority namespace. Depending on which one is dominant, we will have
362 // to recursively apply namespace changes down to children of the original
363 // node.
364 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
365 xmlNodePtr NonDominantNode =
366 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
367 if (DominantNode == OriginalNode) {
368 if (OriginalDefinedDefaultHref) {
369 xmlNsPtr NonDominantDefinedDefault =
370 getNamespaceWithPrefix(nullptr, NonDominantNode);
371 // In this case, both the nodes defined a default namespace. However
372 // the lower priority node ended up having a higher priority default
373 // definition. This can occur if the higher priority node is prefix
374 // namespace defined. In this case we have to define an explicit
375 // prefix for the overridden definition and apply it to all children
376 // who relied on that definition.
377 if (NonDominantDefinedDefault &&
378 namespaceOverrides(NonDominantDefinedDefault->href,
379 OriginalDefinedDefaultHref)) {
380 Expected<xmlNsPtr> EC =
381 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
382 if (!EC) {
383 return EC.takeError();
384 }
385 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
386 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
387 }
388 // In this case the node with a higher priority namespace did not have a
389 // default namespace definition, but the lower priority node did. In this
390 // case the new default namespace definition is copied. A side effect of
391 // this is that all children will suddenly find themselves in a different
392 // default namespace. To maintain correctness we need to ensure that all
393 // children now explicitly refer to the namespace that they had previously
394 // implicitly inherited.
395 } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
396 if (DominantNode->parent) {
397 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
398 Expected<xmlNsPtr> EC =
399 searchOrDefine(ClosestDefault->href, DominantNode);
400 if (!EC) {
401 return EC.takeError();
402 }
403 xmlNsPtr ExplicitDefault = std::move(EC.get());
404 explicateNamespace(ExplicitDefault, DominantNode);
405 }
406 }
407 } else {
408 // Covers case where the incoming node has a default namespace definition
409 // that overrides the original node's namespace. This always leads to
410 // the original node receiving that new default namespace.
411 if (hasDefinedDefaultNamespace(DominantNode)) {
412 NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
413 } else {
414 // This covers the case where the incoming node either has a prefix
415 // namespace, or an inherited default namespace. Since the namespace
416 // may not yet be defined in the original tree we do a searchOrDefine
417 // for it, and then set the namespace equal to it.
418 Expected<xmlNsPtr> EC =
419 searchOrDefine(DominantNode->ns->href, NonDominantNode);
420 if (!EC) {
421 return EC.takeError();
422 }
423 xmlNsPtr Explicit = std::move(EC.get());
424 NonDominantNode->ns = Explicit;
425 }
426 // This covers cases where the incoming dominant node HAS a default
427 // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
428 if (xmlNsPtr DominantDefaultDefined =
429 getNamespaceWithPrefix(nullptr, DominantNode)) {
430 if (OriginalDefinedDefaultHref) {
431 if (namespaceOverrides(DominantDefaultDefined->href,
432 OriginalDefinedDefaultHref)) {
433 // In this case, the incoming node's default definition overrides
434 // the original default definition, all children who relied on that
435 // definition must be updated accordingly.
436 Expected<xmlNsPtr> EC =
437 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
438 if (!EC) {
439 return EC.takeError();
440 }
441 xmlNsPtr ExplicitDefault = std::move(EC.get());
442 explicateNamespace(ExplicitDefault, NonDominantNode);
443 }
444 } else {
445 // The original did not define a default definition, however the new
446 // default definition still applies to all children, so they must be
447 // updated to explicitly refer to the namespace they had previously
448 // been inheriting implicitly.
449 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
450 Expected<xmlNsPtr> EC =
451 searchOrDefine(ClosestDefault->href, NonDominantNode);
452 if (!EC) {
453 return EC.takeError();
454 }
455 xmlNsPtr ExplicitDefault = std::move(EC.get());
456 explicateNamespace(ExplicitDefault, NonDominantNode);
457 }
458 }
459 }
460 if (NewDefinedDefaultHref) {
461 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
462 xmlFree(const_cast<unsigned char *>(OriginalNsDef->href));
463 OriginalNsDef->href = NewDefinedDefaultHref;
464 }
465 xmlFree(const_cast<unsigned char *>(OriginalDefinedDefaultHref));
466 return Error::success();
467 }
468
isRecognizedNamespace(const unsigned char * NsHref)469 static bool isRecognizedNamespace(const unsigned char *NsHref) {
470 for (auto &Ns : MtNsHrefsPrefixes) {
471 if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
472 return true;
473 }
474 }
475 return false;
476 }
477
hasRecognizedNamespace(xmlNodePtr Node)478 static bool hasRecognizedNamespace(xmlNodePtr Node) {
479 return isRecognizedNamespace(Node->ns->href);
480 }
481
482 // Ensure a node's inherited namespace is actually defined in the tree it
483 // resides in.
reconcileNamespaces(xmlNodePtr Node)484 static Error reconcileNamespaces(xmlNodePtr Node) {
485 if (!Node) {
486 return Error::success();
487 }
488 if (hasInheritedNs(Node)) {
489 Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(Node->ns->href, Node);
490 if (!ExplicitOrError) {
491 return ExplicitOrError.takeError();
492 }
493 xmlNsPtr Explicit = std::move(ExplicitOrError.get());
494 Node->ns = Explicit;
495 }
496 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
497 if (auto E = reconcileNamespaces(Child)) {
498 return E;
499 }
500 }
501 return Error::success();
502 }
503
504 // Recursively merge the two given manifest trees, depending on which elements
505 // are of a mergeable type, and choose namespaces according to which have
506 // higher priority.
treeMerge(xmlNodePtr OriginalRoot,xmlNodePtr AdditionalRoot)507 static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
508 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
509 return E;
510 if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
511 return E;
512 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
513 xmlNode StoreNext;
514 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
515 xmlNodePtr OriginalChildWithName;
516 if (!isMergeableElement(Child->name) ||
517 !(OriginalChildWithName =
518 getChildWithName(OriginalRoot, Child->name)) ||
519 !hasRecognizedNamespace(Child)) {
520 StoreNext.next = Child->next;
521 xmlUnlinkNode(Child);
522 if (!xmlAddChild(OriginalRoot, Child)) {
523 return make_error<WindowsManifestError>(Twine("could not merge ") +
524 FROM_XML_CHAR(Child->name));
525 }
526 if (auto E = reconcileNamespaces(Child)) {
527 return E;
528 }
529 Child = &StoreNext;
530 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
531 return E;
532 }
533 }
534 return Error::success();
535 }
536
stripComments(xmlNodePtr Root)537 static void stripComments(xmlNodePtr Root) {
538 xmlNode StoreNext;
539 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
540 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
541 stripComments(Child);
542 continue;
543 }
544 StoreNext.next = Child->next;
545 xmlNodePtr Remove = Child;
546 Child = &StoreNext;
547 xmlUnlinkNode(Remove);
548 xmlFreeNode(Remove);
549 }
550 }
551
552 // libxml2 assumes that attributes do not inherit default namespaces, whereas
553 // the original mt.exe does make this assumption. This function reconciles
554 // this by setting all attributes to have the inherited default namespace.
setAttributeNamespaces(xmlNodePtr Node)555 static void setAttributeNamespaces(xmlNodePtr Node) {
556 for (xmlAttrPtr Attribute = Node->properties; Attribute;
557 Attribute = Attribute->next) {
558 if (!Attribute->ns) {
559 Attribute->ns = getClosestDefault(Node);
560 }
561 }
562 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
563 setAttributeNamespaces(Child);
564 }
565 }
566
567 // The merging process may create too many prefix defined namespaces. This
568 // function removes all unnecessary ones from the tree.
checkAndStripPrefixes(xmlNodePtr Node,std::vector<xmlNsPtr> & RequiredPrefixes)569 static void checkAndStripPrefixes(xmlNodePtr Node,
570 std::vector<xmlNsPtr> &RequiredPrefixes) {
571 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
572 checkAndStripPrefixes(Child, RequiredPrefixes);
573 }
574 if (Node->ns && Node->ns->prefix != nullptr) {
575 xmlNsPtr ClosestDefault = getClosestDefault(Node);
576 if (ClosestDefault &&
577 xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
578 Node->ns = ClosestDefault;
579 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
580 RequiredPrefixes.push_back(Node->ns);
581 }
582 }
583 for (xmlAttrPtr Attribute = Node->properties; Attribute;
584 Attribute = Attribute->next) {
585 if (Attribute->ns && Attribute->ns->prefix != nullptr) {
586 xmlNsPtr ClosestDefault = getClosestDefault(Node);
587 if (ClosestDefault &&
588 xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
589 Attribute->ns = ClosestDefault;
590 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
591 RequiredPrefixes.push_back(Attribute->ns);
592 }
593 }
594 }
595 xmlNsPtr Prev;
596 xmlNs Temp;
597 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
598 if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
599 Prev = Def;
600 continue;
601 }
602 if (Def == Node->nsDef) {
603 Node->nsDef = Def->next;
604 } else {
605 Prev->next = Def->next;
606 }
607 Temp.next = Def->next;
608 xmlFreeNs(Def);
609 Def = &Temp;
610 }
611 }
612
merge(MemoryBufferRef Manifest)613 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
614 MemoryBufferRef Manifest) {
615 if (Merged)
616 return make_error<WindowsManifestError>(
617 "merge after getMergedManifest is not supported");
618 if (Manifest.getBufferSize() == 0)
619 return make_error<WindowsManifestError>(
620 "attempted to merge empty manifest");
621 xmlSetGenericErrorFunc((void *)this,
622 WindowsManifestMergerImpl::errorCallback);
623 std::unique_ptr<xmlDoc, XmlDeleter> ManifestXML(xmlReadMemory(
624 Manifest.getBufferStart(), Manifest.getBufferSize(), "manifest.xml",
625 nullptr, XML_PARSE_NOBLANKS | XML_PARSE_NODICT));
626 xmlSetGenericErrorFunc(nullptr, nullptr);
627 if (auto E = getParseError())
628 return E;
629 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML.get());
630 stripComments(AdditionalRoot);
631 setAttributeNamespaces(AdditionalRoot);
632 if (CombinedDoc == nullptr) {
633 CombinedDoc = ManifestXML.get();
634 } else {
635 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
636 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
637 !isMergeableElement(AdditionalRoot->name) ||
638 !hasRecognizedNamespace(AdditionalRoot)) {
639 return make_error<WindowsManifestError>("multiple root nodes");
640 }
641 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
642 return E;
643 }
644 }
645 MergedDocs.push_back(std::move(ManifestXML));
646 return Error::success();
647 }
648
649 std::unique_ptr<MemoryBuffer>
getMergedManifest()650 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
651 if (!Merged) {
652 Merged = true;
653
654 if (!CombinedDoc)
655 return nullptr;
656
657 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
658 std::vector<xmlNsPtr> RequiredPrefixes;
659 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
660 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
661 xmlNewDoc((const unsigned char *)"1.0"));
662 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
663 assert(nullptr == xmlDocGetRootElement(CombinedDoc));
664
665 xmlChar *Buff = nullptr;
666 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &Buff, &BufferSize, "UTF-8", 1);
667 Buffer.reset(Buff);
668 }
669
670 return BufferSize ? MemoryBuffer::getMemBufferCopy(StringRef(
671 FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize))
672 : nullptr;
673 }
674
isAvailable()675 bool windows_manifest::isAvailable() { return true; }
676
677 #else
678
merge(MemoryBufferRef Manifest)679 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
680 MemoryBufferRef Manifest) {
681 return make_error<WindowsManifestError>("no libxml2");
682 }
683
684 std::unique_ptr<MemoryBuffer>
getMergedManifest()685 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
686 return nullptr;
687 }
688
isAvailable()689 bool windows_manifest::isAvailable() { return false; }
690
691 #endif
692
WindowsManifestMerger()693 WindowsManifestMerger::WindowsManifestMerger()
694 : Impl(std::make_unique<WindowsManifestMergerImpl>()) {}
695
696 WindowsManifestMerger::~WindowsManifestMerger() = default;
697
merge(MemoryBufferRef Manifest)698 Error WindowsManifestMerger::merge(MemoryBufferRef Manifest) {
699 return Impl->merge(Manifest);
700 }
701
getMergedManifest()702 std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
703 return Impl->getMergedManifest();
704 }
705
errorCallback(void * Ctx,const char * Format,...)706 void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
707 void *Ctx, const char *Format, ...) {
708 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
709 Merger->ParseErrorOccurred = true;
710 }
711
getParseError()712 Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
713 if (!ParseErrorOccurred)
714 return Error::success();
715 return make_error<WindowsManifestError>("invalid xml document");
716 }
717