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