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