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
24using namespace llvm;
25using namespace windows_manifest;
26
27char WindowsManifestError::ID = 0;
28
29WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {}
30
31void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
32
33class WindowsManifestMerger::WindowsManifestMergerImpl {
34public:
35 Error merge(MemoryBufferRef Manifest);
36 std::unique_ptr<MemoryBuffer> getMergedManifest();
37
38private:
39 static void errorCallback(void *Ctx, const char *Format, ...);
40 Error getParseError();
41#if LLVM_ENABLE_LIBXML2
42 struct XmlDeleter {
43 void operator()(xmlChar *Ptr) { xmlFree(Ptr); }
44 void operator()(xmlDoc *Ptr) { xmlFreeDoc(cur: 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
57static 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
65static 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
73static 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
84static xmlNodePtr getChildWithName(xmlNodePtr Parent,
85 const unsigned char *ElementName) {
86 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
87 if (xmlStringsEqual(A: Child->name, B: ElementName)) {
88 return Child;
89 }
90 }
91 return nullptr;
92}
93
94static xmlAttrPtr getAttribute(xmlNodePtr Node,
95 const unsigned char *AttributeName) {
96 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
97 Attribute = Attribute->next) {
98 if (xmlStringsEqual(A: Attribute->name, B: AttributeName)) {
99 return Attribute;
100 }
101 }
102 return nullptr;
103}
104
105// Check if namespace specified by HRef1 overrides that of HRef2.
106static bool namespaceOverrides(const unsigned char *HRef1,
107 const unsigned char *HRef2) {
108 auto HRef1Position = llvm::find_if(
109 Range: MtNsHrefsPrefixes, P: [=](const std::pair<StringRef, StringRef> &Element) {
110 return xmlStringsEqual(A: HRef1, TO_XML_CHAR(Element.first.data()));
111 });
112 auto HRef2Position = llvm::find_if(
113 Range: MtNsHrefsPrefixes, P: [=](const std::pair<StringRef, StringRef> &Element) {
114 return xmlStringsEqual(A: 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.
122static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
123 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
124 if (Def->prefix && xmlStringsEqual(A: Def->href, B: HRef)) {
125 return Def;
126 }
127 }
128 if (Node->parent) {
129 return search(HRef, Node: 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.
136static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
137 for (auto &Ns : MtNsHrefsPrefixes) {
138 if (xmlStringsEqual(A: 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.
149static 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: Node, href: HRef, prefix: getPrefixForHref(HRef)))
154 return Def;
155 return make_error<WindowsManifestError>(Args: "failed to create new namespace");
156}
157
158// Set the namespace of OrigionalAttribute on OriginalNode to be that of
159// AdditionalAttribute's.
160static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
161 xmlNodePtr OriginalNode,
162 xmlAttrPtr AdditionalAttribute) {
163
164 Expected<xmlNsPtr> ExplicitOrError =
165 searchOrDefine(HRef: AdditionalAttribute->ns->href, Node: 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.
174static 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(A: Def->prefix, B: 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.
189static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
190 if (xmlNsPtr Ret = getNamespaceWithPrefix(Prefix: nullptr, Node))
191 return Ret;
192 if (Node->parent == nullptr)
193 return nullptr;
194 return getClosestDefault(Node: 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.
203static Error mergeAttributes(xmlNodePtr OriginalNode,
204 xmlNodePtr AdditionalNode) {
205 xmlNsPtr ClosestDefault = getClosestDefault(Node: OriginalNode);
206 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
207 Attribute = Attribute->next) {
208 if (xmlAttrPtr OriginalAttribute =
209 getAttribute(Node: OriginalNode, AttributeName: Attribute->name)) {
210 if (!xmlStringsEqual(A: OriginalAttribute->children->content,
211 B: Attribute->children->content)) {
212 return make_error<WindowsManifestError>(
213 Args: 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 AdditionalAttribute: Attribute)) {
222 return E;
223 }
224 continue;
225 }
226 if (namespaceOverrides(HRef1: OriginalAttribute->ns->href,
227 HRef2: 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(A: Attribute->ns->href, B: ClosestDefault->href)) {
235 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
236 AdditionalAttribute: 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(A: OriginalAttribute->ns->href,
249 B: ClosestDefault->href))) {
250 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
251 AdditionalAttribute: 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(node: OriginalNode, name: Attribute->name, value: Attribute->children->content);
264 Expected<xmlNsPtr> ExplicitOrError =
265 searchOrDefine(HRef: Attribute->ns->href, Node: 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.
274static 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(HRef1: Node1->ns->href, HRef2: 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.
286static bool hasInheritedNs(xmlNodePtr Node) {
287 return Node->ns && Node->ns != getNamespaceWithPrefix(Prefix: 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.
292static 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.
297static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
298 return Node->ns && (Node->ns == getNamespaceWithPrefix(Prefix: 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.
306static 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(A: Node->ns->href, B: 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(A: Attribute->ns->href, B: PrefixDef->href)) {
319 Attribute->ns = PrefixDef;
320 }
321 }
322 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
323 explicateNamespace(PrefixDef, Node: Child);
324 }
325}
326
327// Perform the namespace merge between two nodes.
328static 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(Prefix: nullptr, Node: OriginalNode)) {
335 OriginalDefinedDefaultHref = xmlStrdup(cur: 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(Prefix: Def->prefix, Node: OriginalNode)) {
344 if (!Def->prefix) {
345 if (namespaceOverrides(HRef1: Def->href, HRef2: OriginalNsDef->href)) {
346 NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
347 }
348 } else if (!xmlStringsEqual(A: OriginalNsDef->href, B: Def->href)) {
349 return make_error<WindowsManifestError>(
350 Args: Twine("conflicting namespace definitions for ") +
351 FROM_XML_CHAR(Def->prefix));
352 }
353 } else {
354 xmlNsPtr NewDef = xmlCopyNamespace(cur: 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(Node1: OriginalNode, Node2: AdditionalNode);
365 xmlNodePtr NonDominantNode =
366 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
367 if (DominantNode == OriginalNode) {
368 if (OriginalDefinedDefaultHref) {
369 xmlNsPtr NonDominantDefinedDefault =
370 getNamespaceWithPrefix(Prefix: nullptr, Node: 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(HRef1: NonDominantDefinedDefault->href,
379 HRef2: OriginalDefinedDefaultHref)) {
380 Expected<xmlNsPtr> EC =
381 searchOrDefine(HRef: OriginalDefinedDefaultHref, Node: DominantNode);
382 if (!EC) {
383 return EC.takeError();
384 }
385 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
386 explicateNamespace(PrefixDef: PrefixDominantDefinedDefault, Node: 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(Prefix: nullptr, Node: NonDominantNode)) {
396 if (DominantNode->parent) {
397 xmlNsPtr ClosestDefault = getClosestDefault(Node: DominantNode->parent);
398 Expected<xmlNsPtr> EC =
399 searchOrDefine(HRef: ClosestDefault->href, Node: DominantNode);
400 if (!EC) {
401 return EC.takeError();
402 }
403 xmlNsPtr ExplicitDefault = std::move(EC.get());
404 explicateNamespace(PrefixDef: ExplicitDefault, Node: 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(Node: DominantNode)) {
412 NonDominantNode->ns = getNamespaceWithPrefix(Prefix: nullptr, Node: 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(HRef: DominantNode->ns->href, Node: 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(Prefix: nullptr, Node: DominantNode)) {
430 if (OriginalDefinedDefaultHref) {
431 if (namespaceOverrides(HRef1: DominantDefaultDefined->href,
432 HRef2: 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(HRef: OriginalDefinedDefaultHref, Node: NonDominantNode);
438 if (!EC) {
439 return EC.takeError();
440 }
441 xmlNsPtr ExplicitDefault = std::move(EC.get());
442 explicateNamespace(PrefixDef: ExplicitDefault, Node: 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(Node: NonDominantNode);
450 Expected<xmlNsPtr> EC =
451 searchOrDefine(HRef: ClosestDefault->href, Node: NonDominantNode);
452 if (!EC) {
453 return EC.takeError();
454 }
455 xmlNsPtr ExplicitDefault = std::move(EC.get());
456 explicateNamespace(PrefixDef: ExplicitDefault, Node: NonDominantNode);
457 }
458 }
459 }
460 if (NewDefinedDefaultHref) {
461 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(Prefix: nullptr, Node: 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
469static bool isRecognizedNamespace(const unsigned char *NsHref) {
470 for (auto &Ns : MtNsHrefsPrefixes) {
471 if (xmlStringsEqual(A: NsHref, TO_XML_CHAR(Ns.first.data()))) {
472 return true;
473 }
474 }
475 return false;
476}
477
478static bool hasRecognizedNamespace(xmlNodePtr Node) {
479 return isRecognizedNamespace(NsHref: Node->ns->href);
480}
481
482// Ensure a node's inherited namespace is actually defined in the tree it
483// resides in.
484static Error reconcileNamespaces(xmlNodePtr Node) {
485 if (!Node) {
486 return Error::success();
487 }
488 if (hasInheritedNs(Node)) {
489 Expected<xmlNsPtr> ExplicitOrError = searchOrDefine(HRef: 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(Node: 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.
507static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
508 if (auto E = mergeAttributes(OriginalNode: OriginalRoot, AdditionalNode: AdditionalRoot))
509 return E;
510 if (auto E = mergeNamespaces(OriginalNode: OriginalRoot, AdditionalNode: 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(ElementName: Child->name) ||
517 !(OriginalChildWithName =
518 getChildWithName(Parent: OriginalRoot, ElementName: Child->name)) ||
519 !hasRecognizedNamespace(Node: Child)) {
520 StoreNext.next = Child->next;
521 xmlUnlinkNode(cur: Child);
522 if (!xmlAddChild(parent: OriginalRoot, cur: Child)) {
523 return make_error<WindowsManifestError>(Args: Twine("could not merge ") +
524 FROM_XML_CHAR(Child->name));
525 }
526 if (auto E = reconcileNamespaces(Node: Child)) {
527 return E;
528 }
529 Child = &StoreNext;
530 } else if (auto E = treeMerge(OriginalRoot: OriginalChildWithName, AdditionalRoot: Child)) {
531 return E;
532 }
533 }
534 return Error::success();
535}
536
537static void stripComments(xmlNodePtr Root) {
538 xmlNode StoreNext;
539 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
540 if (!xmlStringsEqual(A: Child->name, TO_XML_CHAR("comment"))) {
541 stripComments(Root: Child);
542 continue;
543 }
544 StoreNext.next = Child->next;
545 xmlNodePtr Remove = Child;
546 Child = &StoreNext;
547 xmlUnlinkNode(cur: Remove);
548 xmlFreeNode(cur: 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.
555static 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.
569static void checkAndStripPrefixes(xmlNodePtr Node,
570 std::vector<xmlNsPtr> &RequiredPrefixes) {
571 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
572 checkAndStripPrefixes(Node: Child, RequiredPrefixes);
573 }
574 if (Node->ns && Node->ns->prefix != nullptr) {
575 xmlNsPtr ClosestDefault = getClosestDefault(Node);
576 if (ClosestDefault &&
577 xmlStringsEqual(A: ClosestDefault->href, B: Node->ns->href)) {
578 Node->ns = ClosestDefault;
579 } else if (!llvm::is_contained(Range&: RequiredPrefixes, Element: Node->ns)) {
580 RequiredPrefixes.push_back(x: 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(A: ClosestDefault->href, B: Attribute->ns->href)) {
589 Attribute->ns = ClosestDefault;
590 } else if (!llvm::is_contained(Range&: RequiredPrefixes, Element: Node->ns)) {
591 RequiredPrefixes.push_back(x: 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(Range&: RequiredPrefixes, Element: 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(cur: Def);
609 Def = &Temp;
610 }
611}
612
613Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
614 MemoryBufferRef Manifest) {
615 if (Merged)
616 return make_error<WindowsManifestError>(
617 Args: "merge after getMergedManifest is not supported");
618 if (Manifest.getBufferSize() == 0)
619 return make_error<WindowsManifestError>(
620 Args: "attempted to merge empty manifest");
621 xmlSetGenericErrorFunc(ctx: (void *)this,
622 handler: WindowsManifestMergerImpl::errorCallback);
623 std::unique_ptr<xmlDoc, XmlDeleter> ManifestXML(xmlReadMemory(
624 buffer: Manifest.getBufferStart(), size: Manifest.getBufferSize(), URL: "manifest.xml",
625 encoding: nullptr, options: XML_PARSE_NOBLANKS | XML_PARSE_NODICT));
626 xmlSetGenericErrorFunc(ctx: nullptr, handler: nullptr);
627 if (auto E = getParseError())
628 return E;
629 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(doc: ManifestXML.get());
630 stripComments(Root: AdditionalRoot);
631 setAttributeNamespaces(AdditionalRoot);
632 if (CombinedDoc == nullptr) {
633 CombinedDoc = ManifestXML.get();
634 } else {
635 xmlNodePtr CombinedRoot = xmlDocGetRootElement(doc: CombinedDoc);
636 if (!xmlStringsEqual(A: CombinedRoot->name, B: AdditionalRoot->name) ||
637 !isMergeableElement(ElementName: AdditionalRoot->name) ||
638 !hasRecognizedNamespace(Node: AdditionalRoot)) {
639 return make_error<WindowsManifestError>(Args: "multiple root nodes");
640 }
641 if (auto E = treeMerge(OriginalRoot: CombinedRoot, AdditionalRoot)) {
642 return E;
643 }
644 }
645 MergedDocs.push_back(x: std::move(ManifestXML));
646 return Error::success();
647}
648
649std::unique_ptr<MemoryBuffer>
650WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
651 if (!Merged) {
652 Merged = true;
653
654 if (!CombinedDoc)
655 return nullptr;
656
657 xmlNodePtr CombinedRoot = xmlDocGetRootElement(doc: CombinedDoc);
658 std::vector<xmlNsPtr> RequiredPrefixes;
659 checkAndStripPrefixes(Node: CombinedRoot, RequiredPrefixes);
660 std::unique_ptr<xmlDoc, XmlDeleter> OutputDoc(
661 xmlNewDoc(version: (const unsigned char *)"1.0"));
662 xmlDocSetRootElement(doc: OutputDoc.get(), root: CombinedRoot);
663 assert(nullptr == xmlDocGetRootElement(CombinedDoc));
664
665 xmlChar *Buff = nullptr;
666 xmlDocDumpFormatMemoryEnc(out_doc: OutputDoc.get(), doc_txt_ptr: &Buff, doc_txt_len: &BufferSize, txt_encoding: "UTF-8", format: 1);
667 Buffer.reset(p: Buff);
668 }
669
670 return BufferSize ? MemoryBuffer::getMemBufferCopy(InputData: StringRef(
671 FROM_XML_CHAR(Buffer.get()), (size_t)BufferSize))
672 : nullptr;
673}
674
675bool windows_manifest::isAvailable() { return true; }
676
677#else
678
679Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
680 MemoryBufferRef Manifest) {
681 return make_error<WindowsManifestError>("no libxml2");
682}
683
684std::unique_ptr<MemoryBuffer>
685WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
686 return nullptr;
687}
688
689bool windows_manifest::isAvailable() { return false; }
690
691#endif
692
693WindowsManifestMerger::WindowsManifestMerger()
694 : Impl(std::make_unique<WindowsManifestMergerImpl>()) {}
695
696WindowsManifestMerger::~WindowsManifestMerger() = default;
697
698Error WindowsManifestMerger::merge(MemoryBufferRef Manifest) {
699 return Impl->merge(Manifest);
700}
701
702std::unique_ptr<MemoryBuffer> WindowsManifestMerger::getMergedManifest() {
703 return Impl->getMergedManifest();
704}
705
706void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
707 void *Ctx, const char *Format, ...) {
708 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
709 Merger->ParseErrorOccurred = true;
710}
711
712Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
713 if (!ParseErrorOccurred)
714 return Error::success();
715 return make_error<WindowsManifestError>(Args: "invalid xml document");
716}
717