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