LLVM 22.0.0git
WindowsManifestMerger.cpp
Go to the documentation of this file.
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
14#include "llvm/Config/config.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
28
30
31void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
32
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(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(Child->name, 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(Attribute->name, 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 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.
122static 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.
136static 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.
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, 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.
160static 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.
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(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.
189static 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.
203static 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)) {
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.
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(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.
286static 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.
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(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(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.
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(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)) {
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
469static 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
478static 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.
484static 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.
507static 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
537static 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.
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(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
614 MemoryBufferRef Manifest) {
615 if (Merged)
617 "merge after getMergedManifest is not supported");
618 if (Manifest.getBufferSize() == 0)
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
649std::unique_ptr<MemoryBuffer>
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
675bool windows_manifest::isAvailable() { return true; }
676
677#else
678
683
684std::unique_ptr<MemoryBuffer>
688
689bool windows_manifest::isAvailable() { return false; }
690
691#endif
692
695
697
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>("invalid xml document");
716}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
R600 Vector Reg Merger
#define TO_XML_CHAR(X)
#define FROM_XML_CHAR(X)
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
reference get()
Returns a reference to the stored T value.
Definition Error.h:582
size_t getBufferSize() const
const char * getBufferStart() const
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
void log(raw_ostream &OS) const override
Print an error message to an output stream.
LLVM_ABI std::unique_ptr< MemoryBuffer > getMergedManifest()
LLVM_ABI Error merge(MemoryBufferRef Manifest)
NodeAddr< DefNode * > Def
Definition RDFGraph.h:384
NodeAddr< NodeBase * > Node
Definition RDFGraph.h:381
This is an optimization pass for GlobalISel generic memory operations.
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1738
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1877
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:851