llvm.org GIT mirror llvm / 79fe536
llvm-mt: Merge manifest namespaces. mt.exe performs a tree merge where certain element nodes are combined into one. This introduces the possibility of xml namespaces conflicting with each other. The original mt.exe has a hierarchy whereby certain namespace names can override others, and nodes that would then end up in ambigious namespaces have their namespaces explicitly defined. This namespace handles this merging process. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@311215 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Beckmann 2 years ago
14 changed file(s) with 730 addition(s) and 114 deletion(s). Raw diff Collapse all Expand all
2828 #include "llvm/Config/config.h"
2929 #include "llvm/Support/Error.h"
3030
31 #if LLVM_LIBXML2_ENABLED
32 #include
33 #endif
34
3531 namespace llvm {
3632
3733 class MemoryBuffer;
3834
39 #if LLVM_LIBXML2_ENABLED
40 typedef xmlDocPtr XMLDocumentImpl;
41 typedef xmlNodePtr XMLNodeImpl;
42 #else
43 typedef void *XMLDocumentImpl;
44 typedef void *XMLNodeImpl;
45 #endif
35 namespace windows_manifest {
4636
4737 class WindowsManifestError : public ErrorInfo {
4838 public:
5646
5747 class WindowsManifestMerger {
5848 public:
49 WindowsManifestMerger();
5950 ~WindowsManifestMerger();
60
6151 Error merge(const MemoryBuffer &Manifest);
6252
6353 // Returns vector containing merged xml manifest, or uninitialized vector for
6555 std::unique_ptr getMergedManifest();
6656
6757 private:
68 static void errorCallback(void *Ctx, const char *Format, ...);
69 Error getParseError();
70
71 #if LLVM_LIBXML2_ENABLED
72 XMLDocumentImpl CombinedDoc = nullptr;
73 std::vector MergedDocs;
74 #endif
75 bool ParseErrorOccurred = false;
58 class WindowsManifestMergerImpl;
59 std::unique_ptr Impl;
7660 };
7761
62 } // namespace windows_manifest
7863 } // namespace llvm
7964 #endif
1313 #include "llvm/WindowsManifest/WindowsManifestMerger.h"
1414 #include "llvm/Support/MemoryBuffer.h"
1515
16 #include <stdarg.h>
16 #include <map>
17
18 #if LLVM_LIBXML2_ENABLED
19 #include
20 #endif
1721
1822 #define TO_XML_CHAR(X) reinterpret_cast(X)
1923 #define FROM_XML_CHAR(X) reinterpret_cast(X)
2024
2125 using namespace llvm;
22
23 namespace llvm {
26 using namespace windows_manifest;
2427
2528 char WindowsManifestError::ID = 0;
2629
2831
2932 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; }
3033
34 class WindowsManifestMerger::WindowsManifestMergerImpl {
35 public:
36 ~WindowsManifestMergerImpl();
37 Error merge(const MemoryBuffer &Manifest);
38 std::unique_ptr getMergedManifest();
39
40 private:
41 static void errorCallback(void *Ctx, const char *Format, ...);
42 Error getParseError();
3143 #if LLVM_LIBXML2_ENABLED
44 xmlDocPtr CombinedDoc = nullptr;
45 std::vector MergedDocs;
46 #endif
47 bool ParseErrorOccurred = false;
48 };
49
50 #if LLVM_LIBXML2_ENABLED
51
52 static const std::pair MtNsHrefsPrefixes[] = {
53 {"urn:schemas-microsoft-com:asm.v1", "ms_asmv1"},
54 {"urn:schemas-microsoft-com:asm.v2", "ms_asmv2"},
55 {"urn:schemas-microsoft-com:asm.v3", "ms_asmv3"},
56 {"http://schemas.microsoft.com/SMI/2005/WindowsSettings",
57 "ms_windowsSettings"},
58 {"urn:schemas-microsoft-com:compatibility.v1", "ms_compatibilityv1"}};
59
3260 static bool xmlStringsEqual(const unsigned char *A, const unsigned char *B) {
61 // Handle null pointers. Comparison of 2 null pointers returns true because
62 // this indicates the prefix of a default namespace.
63 if (!A || !B)
64 return A == B;
3365 return strcmp(FROM_XML_CHAR(A), FROM_XML_CHAR(B)) == 0;
3466 }
35 #endif
36
37 bool isMergeableElement(const unsigned char *ElementName) {
67
68 static bool isMergeableElement(const unsigned char *ElementName) {
3869 for (StringRef S : {"application", "assembly", "assemblyIdentity",
3970 "compatibility", "noInherit", "requestedExecutionLevel",
4071 "requestedPrivileges", "security", "trustInfo"}) {
41 if (S == FROM_XML_CHAR(ElementName))
72 if (S == FROM_XML_CHAR(ElementName)) {
4273 return true;
74 }
4375 }
4476 return false;
4577 }
4678
47 XMLNodeImpl getChildWithName(XMLNodeImpl Parent,
48 const unsigned char *ElementName) {
49 #if LLVM_LIBXML2_ENABLED
50 for (XMLNodeImpl Child = Parent->children; Child; Child = Child->next)
79 static xmlNodePtr getChildWithName(xmlNodePtr Parent,
80 const unsigned char *ElementName) {
81 for (xmlNodePtr Child = Parent->children; Child; Child = Child->next) {
5182 if (xmlStringsEqual(Child->name, ElementName)) {
5283 return Child;
5384 }
54 #endif
85 }
5586 return nullptr;
5687 }
5788
58 const unsigned char *getAttribute(XMLNodeImpl Node,
59 const unsigned char *AttributeName) {
60 #if LLVM_LIBXML2_ENABLED
89 static xmlAttrPtr getAttribute(xmlNodePtr Node,
90 const unsigned char *AttributeName) {
6191 for (xmlAttrPtr Attribute = Node->properties; Attribute != nullptr;
6292 Attribute = Attribute->next) {
63 if (xmlStringsEqual(Attribute->name, AttributeName))
64 return Attribute->children->content;
65 }
66 #endif
93 if (xmlStringsEqual(Attribute->name, AttributeName)) {
94 return Attribute;
95 }
96 }
6797 return nullptr;
6898 }
6999
70 Error mergeAttributes(XMLNodeImpl OriginalNode, XMLNodeImpl AdditionalNode) {
71 #if LLVM_LIBXML2_ENABLED
72 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute != nullptr;
100 // Check if namespace specified by HRef1 overrides that of HRef2.
101 static bool namespaceOverrides(const unsigned char *HRef1,
102 const unsigned char *HRef2) {
103 auto HRef1Position = llvm::find_if(
104 MtNsHrefsPrefixes, [=](const std::pair &Element) {
105 return xmlStringsEqual(HRef1, TO_XML_CHAR(Element.first.data()));
106 });
107 auto HRef2Position = llvm::find_if(
108 MtNsHrefsPrefixes, [=](const std::pair &Element) {
109 return xmlStringsEqual(HRef2, TO_XML_CHAR(Element.first.data()));
110 });
111 return HRef1Position < HRef2Position;
112 }
113
114 // Search for prefix-defined namespace specified by HRef, starting on Node and
115 // continuing recursively upwards. Returns the namespace or nullptr if not
116 // found.
117 static xmlNsPtr search(const unsigned char *HRef, xmlNodePtr Node) {
118 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
119 if (Def->prefix && xmlStringsEqual(Def->href, HRef)) {
120 return Def;
121 }
122 }
123 if (Node->parent) {
124 return search(HRef, Node->parent);
125 }
126 return nullptr;
127 }
128
129 // Return the prefix that corresponds to the HRef. If HRef is not a recognized
130 // URI, then just return the HRef itself to use as the prefix.
131 static const unsigned char *getPrefixForHref(const unsigned char *HRef) {
132 for (auto &Ns : MtNsHrefsPrefixes) {
133 if (xmlStringsEqual(HRef, TO_XML_CHAR(Ns.first.data()))) {
134 return TO_XML_CHAR(Ns.second.data());
135 }
136 }
137 return HRef;
138 }
139
140 // Search for prefix-defined namespace specified by HRef, starting on Node and
141 // continuing recursively upwards. If it is found, then return it. If it is
142 // not found, then prefix-define that namespace on the node and return a
143 // reference to it.
144 static Expected searchOrDefine(const unsigned char *HRef,
145 xmlNodePtr Node) {
146 if (xmlNsPtr Def = search(HRef, Node))
147 return Def;
148 if (xmlNsPtr Def = xmlNewNs(Node, HRef, getPrefixForHref(HRef)))
149 return Def;
150 return make_error("failed to create new namespace");
151 }
152
153 // Set the namespace of OrigionalAttribute on OriginalNode to be that of
154 // AdditionalAttribute's.
155 static Error copyAttributeNamespace(xmlAttrPtr OriginalAttribute,
156 xmlNodePtr OriginalNode,
157 xmlAttrPtr AdditionalAttribute) {
158
159 Expected ExplicitOrError =
160 searchOrDefine(AdditionalAttribute->ns->href, OriginalNode);
161 if (!ExplicitOrError)
162 return ExplicitOrError.takeError();
163 OriginalAttribute->ns = std::move(ExplicitOrError.get());
164 return Error::success();
165 }
166
167 // Return the corresponding namespace definition for the prefix, defined on the
168 // given Node. Returns nullptr if there is no such definition.
169 static xmlNsPtr getNamespaceWithPrefix(const unsigned char *Prefix,
170 xmlNodePtr Node) {
171 if (Node == nullptr)
172 return nullptr;
173 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
174 if (xmlStringsEqual(Def->prefix, Prefix)) {
175 return Def;
176 }
177 }
178 return nullptr;
179 }
180
181 // Search for the closest inheritable default namespace, starting on (and
182 // including) the Node and traveling upwards through parent nodes. Returns
183 // nullptr if there are no inheritable default namespaces.
184 static xmlNsPtr getClosestDefault(xmlNodePtr Node) {
185 if (xmlNsPtr Ret = getNamespaceWithPrefix(nullptr, Node))
186 return Ret;
187 if (Node->parent == nullptr)
188 return nullptr;
189 return getClosestDefault(Node->parent);
190 }
191
192 // Merge the attributes of AdditionalNode into OriginalNode. If attributes
193 // with identical types are present, they are not duplicated but rather if
194 // their values are not consistent and error is thrown. In addition, the
195 // higher priority namespace is used for each attribute, EXCEPT in the case
196 // of merging two default namespaces and the lower priority namespace
197 // definition occurs closer than the higher priority one.
198 static Error mergeAttributes(xmlNodePtr OriginalNode,
199 xmlNodePtr AdditionalNode) {
200 xmlNsPtr ClosestDefault = getClosestDefault(OriginalNode);
201 for (xmlAttrPtr Attribute = AdditionalNode->properties; Attribute;
73202 Attribute = Attribute->next) {
74 if (const unsigned char *OriginalValue =
203 if (xmlAttrPtr OriginalAttribute =
75204 getAttribute(OriginalNode, Attribute->name)) {
76 // Attributes of the same name must also have the same value. Otherwise
77 // an error is thrown.
78 if (!xmlStringsEqual(OriginalValue, Attribute->children->content))
205 if (!xmlStringsEqual(OriginalAttribute->children->content,
206 Attribute->children->content)) {
79207 return make_error(
80208 Twine("conflicting attributes for ") +
81209 FROM_XML_CHAR(OriginalNode->name));
210 }
211 if (!Attribute->ns) {
212 continue;
213 }
214 if (!OriginalAttribute->ns) {
215 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
216 Attribute)) {
217 return E;
218 }
219 continue;
220 }
221 if (namespaceOverrides(OriginalAttribute->ns->href,
222 Attribute->ns->href)) {
223 // In this case, the original attribute has a higher priority namespace
224 // than the incomiing attribute, however the namespace definition of
225 // the lower priority namespace occurs first traveling upwards in the
226 // tree. Therefore the lower priority namespace is applied.
227 if (!OriginalAttribute->ns->prefix && !Attribute->ns->prefix &&
228 ClosestDefault &&
229 xmlStringsEqual(Attribute->ns->href, ClosestDefault->href)) {
230 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
231 Attribute)) {
232 return E;
233 }
234 continue;
235 }
236 continue;
237 // This covers the case where the incoming attribute has the higher
238 // priority. The higher priority namespace is applied in all cases
239 // EXCEPT when both of the namespaces are default inherited, and the
240 // closest inherited default is the lower priority one.
241 }
242 if (Attribute->ns->prefix || OriginalAttribute->ns->prefix ||
243 (ClosestDefault && !xmlStringsEqual(OriginalAttribute->ns->href,
244 ClosestDefault->href))) {
245 if (auto E = copyAttributeNamespace(OriginalAttribute, OriginalNode,
246 Attribute)) {
247 return E;
248 }
249 continue;
250 }
251 continue;
252 }
253 // If the incoming attribute is not already found on the node, append it
254 // to the end of the properties list. Also explicitly apply its
255 // namespace as a prefix because it might be contained in a separate
256 // namespace that doesn't use the attribute.
257 xmlAttrPtr NewProp =
258 xmlNewProp(OriginalNode, Attribute->name, Attribute->children->content);
259 Expected ExplicitOrError =
260 searchOrDefine(Attribute->ns->href, OriginalNode);
261 if (!ExplicitOrError)
262 return ExplicitOrError.takeError();
263 NewProp->ns = std::move(ExplicitOrError.get());
264 }
265 return Error::success();
266 }
267
268 // Given two nodes, return the one with the higher priority namespace.
269 static xmlNodePtr getDominantNode(xmlNodePtr Node1, xmlNodePtr Node2) {
270
271 if (!Node1 || !Node1->ns)
272 return Node2;
273 if (!Node2 || !Node2->ns)
274 return Node1;
275 if (namespaceOverrides(Node1->ns->href, Node2->ns->href))
276 return Node1;
277 return Node2;
278 }
279
280 // Checks if this Node's namespace is inherited or one it defined itself.
281 static bool hasInheritedNs(xmlNodePtr Node) {
282 return Node->ns && Node->ns != getNamespaceWithPrefix(Node->ns->prefix, Node);
283 }
284
285 // Check if this Node's namespace is a default namespace that it inherited, as
286 // opposed to defining itself.
287 static bool hasInheritedDefaultNs(xmlNodePtr Node) {
288 return hasInheritedNs(Node) && Node->ns->prefix == nullptr;
289 }
290
291 // Check if this Node's namespace is a default namespace it defined itself.
292 static bool hasDefinedDefaultNamespace(xmlNodePtr Node) {
293 return Node->ns && (Node->ns == getNamespaceWithPrefix(nullptr, Node));
294 }
295
296 // For the given explicit prefix-definition of a namespace, travel downwards
297 // from a node recursively, and for every implicit, inherited default usage of
298 // that namespace replace it with that explicit prefix use. This is important
299 // when namespace overriding occurs when merging, so that elements unique to a
300 // namespace will still stay in that namespace.
301 static void explicateNamespace(xmlNsPtr PrefixDef, xmlNodePtr Node) {
302 // If a node as its own default namespace definition it clearly cannot have
303 // inherited the given default namespace, and neither will any of its
304 // children.
305 if (hasDefinedDefaultNamespace(Node))
306 return;
307 if (Node->ns && xmlStringsEqual(Node->ns->href, PrefixDef->href) &&
308 hasInheritedDefaultNs(Node))
309 Node->ns = PrefixDef;
310 for (xmlAttrPtr Attribute = Node->properties; Attribute;
311 Attribute = Attribute->next) {
312 if (Attribute->ns &&
313 xmlStringsEqual(Attribute->ns->href, PrefixDef->href)) {
314 Attribute->ns = PrefixDef;
315 }
316 }
317 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
318 explicateNamespace(PrefixDef, Child);
319 }
320 }
321
322 // Perform the namespace merge between two nodes.
323 static Error mergeNamespaces(xmlNodePtr OriginalNode,
324 xmlNodePtr AdditionalNode) {
325 // Save the original default namespace definition in case the incoming node
326 // overrides it.
327 const unsigned char *OriginalDefinedDefaultHref = nullptr;
328 if (xmlNsPtr OriginalDefinedDefaultNs =
329 getNamespaceWithPrefix(nullptr, OriginalNode)) {
330 OriginalDefinedDefaultHref = xmlStrdup(OriginalDefinedDefaultNs->href);
331 }
332 const unsigned char *NewDefinedDefaultHref = nullptr;
333 // Copy all namespace definitions. There can only be one default namespace
334 // definition per node, so the higher priority one takes precedence in the
335 // case of collision.
336 for (xmlNsPtr Def = AdditionalNode->nsDef; Def; Def = Def->next) {
337 if (xmlNsPtr OriginalNsDef =
338 getNamespaceWithPrefix(Def->prefix, OriginalNode)) {
339 if (!Def->prefix) {
340 if (namespaceOverrides(Def->href, OriginalNsDef->href)) {
341 NewDefinedDefaultHref = TO_XML_CHAR(strdup(FROM_XML_CHAR(Def->href)));
342 }
343 } else if (!xmlStringsEqual(OriginalNsDef->href, Def->href)) {
344 return make_error(
345 Twine("conflicting namespace definitions for ") +
346 FROM_XML_CHAR(Def->prefix));
347 }
82348 } else {
83 char *NameCopy = strdup(FROM_XML_CHAR(Attribute->name));
84 char *ContentCopy = strdup(FROM_XML_CHAR(Attribute->children->content));
85 xmlNewProp(OriginalNode, TO_XML_CHAR(NameCopy), TO_XML_CHAR(ContentCopy));
86 }
87 }
88 #endif
349 xmlNsPtr NewDef = xmlCopyNamespace(Def);
350 NewDef->next = OriginalNode->nsDef;
351 OriginalNode->nsDef = NewDef;
352 }
353 }
354
355 // Check whether the original node or the incoming node has the higher
356 // priority namespace. Depending on which one is dominant, we will have
357 // to recursively apply namespace changes down to children of the original
358 // node.
359 xmlNodePtr DominantNode = getDominantNode(OriginalNode, AdditionalNode);
360 xmlNodePtr NonDominantNode =
361 DominantNode == OriginalNode ? AdditionalNode : OriginalNode;
362 if (DominantNode == OriginalNode) {
363 if (OriginalDefinedDefaultHref) {
364 xmlNsPtr NonDominantDefinedDefault =
365 getNamespaceWithPrefix(nullptr, NonDominantNode);
366 // In this case, both the nodes defined a default namespace. However
367 // the lower priority node ended up having a higher priority default
368 // definition. This can occur if the higher priority node is prefix
369 // namespace defined. In this case we have to define an explicit
370 // prefix for the overridden definition and apply it to all children
371 // who relied on that definition.
372 if (NonDominantDefinedDefault &&
373 namespaceOverrides(NonDominantDefinedDefault->href,
374 OriginalDefinedDefaultHref)) {
375 Expected EC =
376 searchOrDefine(OriginalDefinedDefaultHref, DominantNode);
377 if (!EC) {
378 return EC.takeError();
379 }
380 xmlNsPtr PrefixDominantDefinedDefault = std::move(EC.get());
381 explicateNamespace(PrefixDominantDefinedDefault, DominantNode);
382 }
383 // In this case the node with a higher priority namespace did not have a
384 // default namespace definition, but the lower priority node did. In this
385 // case the new default namespace definition is copied. A side effect of
386 // this is that all children will suddenly find themselves in a different
387 // default namespace. To maintain correctness we need to ensure that all
388 // children now explicitly refer to the namespace that they had previously
389 // implicitly inherited.
390 } else if (getNamespaceWithPrefix(nullptr, NonDominantNode)) {
391 if (DominantNode->parent) {
392 xmlNsPtr ClosestDefault = getClosestDefault(DominantNode->parent);
393 Expected EC =
394 searchOrDefine(ClosestDefault->href, DominantNode);
395 if (!EC) {
396 return EC.takeError();
397 }
398 xmlNsPtr ExplicitDefault = std::move(EC.get());
399 explicateNamespace(ExplicitDefault, DominantNode);
400 }
401 }
402 } else {
403 // Covers case where the incoming node has a default namespace definition
404 // that overrides the original node's namespace. This always leads to
405 // the original node receiving that new default namespace.
406 if (hasDefinedDefaultNamespace(DominantNode)) {
407 NonDominantNode->ns = getNamespaceWithPrefix(nullptr, NonDominantNode);
408 } else {
409 // This covers the case where the incoming node either has a prefix
410 // namespace, or an inherited default namespace. Since the namespace
411 // may not yet be defined in the original tree we do a searchOrDefine
412 // for it, and then set the namespace equal to it.
413 Expected EC =
414 searchOrDefine(DominantNode->ns->href, NonDominantNode);
415 if (!EC) {
416 return EC.takeError();
417 }
418 xmlNsPtr Explicit = std::move(EC.get());
419 NonDominantNode->ns = Explicit;
420 }
421 // This covers cases where the incoming dominant node HAS a default
422 // namespace definition, but MIGHT NOT NECESSARILY be in that namespace.
423 if (xmlNsPtr DominantDefaultDefined =
424 getNamespaceWithPrefix(nullptr, DominantNode)) {
425 if (OriginalDefinedDefaultHref) {
426 if (namespaceOverrides(DominantDefaultDefined->href,
427 OriginalDefinedDefaultHref)) {
428 // In this case, the incoming node's default definition overrides
429 // the original default definition, all children who relied on that
430 // definition must be updated accordingly.
431 Expected EC =
432 searchOrDefine(OriginalDefinedDefaultHref, NonDominantNode);
433 if (!EC) {
434 return EC.takeError();
435 }
436 xmlNsPtr ExplicitDefault = std::move(EC.get());
437 explicateNamespace(ExplicitDefault, NonDominantNode);
438 }
439 } else {
440 // The original did not define a default definition, however the new
441 // default definition still applies to all children, so they must be
442 // updated to explicitly refer to the namespace they had previously
443 // been inheriting implicitly.
444 xmlNsPtr ClosestDefault = getClosestDefault(NonDominantNode);
445 Expected EC =
446 searchOrDefine(ClosestDefault->href, NonDominantNode);
447 if (!EC) {
448 return EC.takeError();
449 }
450 xmlNsPtr ExplicitDefault = std::move(EC.get());
451 explicateNamespace(ExplicitDefault, NonDominantNode);
452 }
453 }
454 }
455 if (NewDefinedDefaultHref) {
456 xmlNsPtr OriginalNsDef = getNamespaceWithPrefix(nullptr, OriginalNode);
457 xmlFree(const_cast(OriginalNsDef->href));
458 OriginalNsDef->href = NewDefinedDefaultHref;
459 }
460 xmlFree(const_cast(OriginalDefinedDefaultHref));
89461 return Error::success();
90462 }
91463
92 Error treeMerge(XMLNodeImpl OriginalRoot, XMLNodeImpl AdditionalRoot) {
93 #if LLVM_LIBXML2_ENABLED
94 XMLNodeImpl AdditionalFirstChild = AdditionalRoot->children;
464 static bool isRecognizedNamespace(const unsigned char *NsHref) {
465 for (auto &Ns : MtNsHrefsPrefixes) {
466 if (xmlStringsEqual(NsHref, TO_XML_CHAR(Ns.first.data()))) {
467 return true;
468 }
469 }
470 return false;
471 }
472
473 static bool hasRecognizedNamespace(xmlNodePtr Node) {
474 return isRecognizedNamespace(Node->ns->href);
475 }
476
477 // Ensure a node's inherited namespace is actually defined in the tree it
478 // resides in.
479 static Error reconcileNamespaces(xmlNodePtr Node) {
480 if (!Node) {
481 return Error::success();
482 }
483 if (hasInheritedNs(Node)) {
484 Expected ExplicitOrError = searchOrDefine(Node->ns->href, Node);
485 if (!ExplicitOrError) {
486 return ExplicitOrError.takeError();
487 }
488 xmlNsPtr Explicit = std::move(ExplicitOrError.get());
489 Node->ns = Explicit;
490 }
491 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
492 if (auto E = reconcileNamespaces(Child)) {
493 return E;
494 }
495 }
496 return Error::success();
497 }
498
499 // Recursively merge the two given manifest trees, depending on which elements
500 // are of a mergeable type, and choose namespaces according to which have
501 // higher priority.
502 static Error treeMerge(xmlNodePtr OriginalRoot, xmlNodePtr AdditionalRoot) {
503 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
504 return E;
505 if (auto E = mergeNamespaces(OriginalRoot, AdditionalRoot))
506 return E;
507 xmlNodePtr AdditionalFirstChild = AdditionalRoot->children;
95508 xmlNode StoreNext;
96 for (XMLNodeImpl Child = AdditionalFirstChild; Child; Child = Child->next) {
97 XMLNodeImpl OriginalChildWithName;
509 for (xmlNodePtr Child = AdditionalFirstChild; Child; Child = Child->next) {
510 xmlNodePtr OriginalChildWithName;
98511 if (!isMergeableElement(Child->name) ||
99512 !(OriginalChildWithName =
100 getChildWithName(OriginalRoot, Child->name))) {
513 getChildWithName(OriginalRoot, Child->name)) ||
514 !hasRecognizedNamespace(Child)) {
101515 StoreNext.next = Child->next;
102516 xmlUnlinkNode(Child);
103 if (!xmlAddChild(OriginalRoot, Child))
517 if (!xmlAddChild(OriginalRoot, Child)) {
104518 return make_error(Twine("could not merge ") +
105519 FROM_XML_CHAR(Child->name));
520 }
521 if (auto E = reconcileNamespaces(Child)) {
522 return E;
523 }
106524 Child = &StoreNext;
107525 } else if (auto E = treeMerge(OriginalChildWithName, Child)) {
108526 return E;
109527 }
110528 }
111 if (auto E = mergeAttributes(OriginalRoot, AdditionalRoot))
112 return E;
113 #endif
114529 return Error::success();
115530 }
116531
117 void stripCommentsAndText(XMLNodeImpl Root) {
118 #if LLVM_LIBXML2_ENABLED
532 static void stripComments(xmlNodePtr Root) {
119533 xmlNode StoreNext;
120 for (XMLNodeImpl Child = Root->children; Child; Child = Child->next) {
121 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("text")) &&
122 !xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
123 stripCommentsAndText(Child);
534 for (xmlNodePtr Child = Root->children; Child; Child = Child->next) {
535 if (!xmlStringsEqual(Child->name, TO_XML_CHAR("comment"))) {
536 stripComments(Child);
537 continue;
538 }
539 StoreNext.next = Child->next;
540 xmlNodePtr Remove = Child;
541 Child = &StoreNext;
542 xmlUnlinkNode(Remove);
543 xmlFreeNode(Remove);
544 }
545 }
546
547 // libxml2 assumes that attributes do not inherit default namespaces, whereas
548 // the original mt.exe does make this assumption. This function reconciles
549 // this by setting all attributes to have the inherited default namespace.
550 static void setAttributeNamespaces(xmlNodePtr Node) {
551 for (xmlAttrPtr Attribute = Node->properties; Attribute;
552 Attribute = Attribute->next) {
553 if (!Attribute->ns) {
554 Attribute->ns = getClosestDefault(Node);
555 }
556 }
557 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
558 setAttributeNamespaces(Child);
559 }
560 }
561
562 // The merging process may create too many prefix defined namespaces. This
563 // function removes all unnecessary ones from the tree.
564 static void checkAndStripPrefixes(xmlNodePtr Node,
565 std::vector &RequiredPrefixes) {
566 for (xmlNodePtr Child = Node->children; Child; Child = Child->next) {
567 checkAndStripPrefixes(Child, RequiredPrefixes);
568 }
569 if (Node->ns && Node->ns->prefix != nullptr) {
570 xmlNsPtr ClosestDefault = getClosestDefault(Node);
571 if (ClosestDefault &&
572 xmlStringsEqual(ClosestDefault->href, Node->ns->href)) {
573 Node->ns = ClosestDefault;
574 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
575 RequiredPrefixes.push_back(Node->ns);
576 }
577 }
578 for (xmlAttrPtr Attribute = Node->properties; Attribute;
579 Attribute = Attribute->next) {
580 if (Attribute->ns && Attribute->ns->prefix != nullptr) {
581 xmlNsPtr ClosestDefault = getClosestDefault(Node);
582 if (ClosestDefault &&
583 xmlStringsEqual(ClosestDefault->href, Attribute->ns->href)) {
584 Attribute->ns = ClosestDefault;
585 } else if (!llvm::is_contained(RequiredPrefixes, Node->ns)) {
586 RequiredPrefixes.push_back(Attribute->ns);
587 }
588 }
589 }
590 xmlNsPtr Prev;
591 xmlNs Temp;
592 for (xmlNsPtr Def = Node->nsDef; Def; Def = Def->next) {
593 if (!Def->prefix || llvm::is_contained(RequiredPrefixes, Def)) {
594 Prev = Def;
595 continue;
596 }
597 if (Def == Node->nsDef) {
598 Node->nsDef = Def->next;
124599 } else {
125 StoreNext.next = Child->next;
126 XMLNodeImpl Remove = Child;
127 Child = &StoreNext;
128 xmlUnlinkNode(Remove);
129 xmlFreeNode(Remove);
130 }
131 }
132 #endif
133 }
134
135 WindowsManifestMerger::~WindowsManifestMerger() {
136 #if LLVM_LIBXML2_ENABLED
600 Prev->next = Def->next;
601 }
602 Temp.next = Def->next;
603 xmlFreeNs(Def);
604 Def = &Temp;
605 }
606 }
607
608 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
137609 for (auto &Doc : MergedDocs)
138610 xmlFreeDoc(Doc);
139 #endif
140 }
141
142 Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
143 #if LLVM_LIBXML2_ENABLED
611 }
612
613 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
614 const MemoryBuffer &Manifest) {
144615 if (Manifest.getBufferSize() == 0)
145616 return make_error(
146617 "attempted to merge empty manifest");
147 xmlSetGenericErrorFunc((void *)this, WindowsManifestMerger::errorCallback);
148 XMLDocumentImpl ManifestXML =
618 xmlSetGenericErrorFunc((void *)this,
619 WindowsManifestMergerImpl::errorCallback);
620 xmlDocPtr ManifestXML =
149621 xmlReadMemory(Manifest.getBufferStart(), Manifest.getBufferSize(),
150622 "manifest.xml", nullptr, XML_PARSE_NOBLANKS);
151623 xmlSetGenericErrorFunc(nullptr, nullptr);
152624 if (auto E = getParseError())
153625 return E;
154 XMLNodeImpl AdditionalRoot = xmlDocGetRootElement(ManifestXML);
155 stripCommentsAndText(AdditionalRoot);
626 xmlNodePtr AdditionalRoot = xmlDocGetRootElement(ManifestXML);
627 stripComments(AdditionalRoot);
628 setAttributeNamespaces(AdditionalRoot);
156629 if (CombinedDoc == nullptr) {
157630 CombinedDoc = ManifestXML;
158631 } else {
159 XMLNodeImpl CombinedRoot = xmlDocGetRootElement(CombinedDoc);
160 if (xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) &&
161 isMergeableElement(AdditionalRoot->name)) {
162 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
163 return E;
164 }
165 } else {
632 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
633 if (!xmlStringsEqual(CombinedRoot->name, AdditionalRoot->name) ||
634 !isMergeableElement(AdditionalRoot->name) ||
635 !hasRecognizedNamespace(AdditionalRoot)) {
166636 return make_error("multiple root nodes");
167637 }
638 if (auto E = treeMerge(CombinedRoot, AdditionalRoot)) {
639 return E;
640 }
168641 }
169642 MergedDocs.push_back(ManifestXML);
170 #endif
171643 return Error::success();
172644 }
173645
174 std::unique_ptr WindowsManifestMerger::getMergedManifest() {
175 #if LLVM_LIBXML2_ENABLED
646 std::unique_ptr
647 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
176648 unsigned char *XmlBuff;
177649 int BufferSize = 0;
178650 if (CombinedDoc) {
651 xmlNodePtr CombinedRoot = xmlDocGetRootElement(CombinedDoc);
652 std::vector RequiredPrefixes;
653 checkAndStripPrefixes(CombinedRoot, RequiredPrefixes);
179654 std::unique_ptr OutputDoc(xmlNewDoc((const unsigned char *)"1.0"));
180 xmlDocSetRootElement(OutputDoc.get(), xmlDocGetRootElement(CombinedDoc));
655 xmlDocSetRootElement(OutputDoc.get(), CombinedRoot);
181656 xmlKeepBlanksDefault(0);
182 xmlDocDumpFormatMemory(OutputDoc.get(), &XmlBuff, &BufferSize, 1);
657 xmlDocDumpFormatMemoryEnc(OutputDoc.get(), &XmlBuff, &BufferSize, "UTF-8",
658 1);
183659 }
184660 if (BufferSize == 0)
185661 return nullptr;
186662 return MemoryBuffer::getMemBuffer(
187663 StringRef(FROM_XML_CHAR(XmlBuff), (size_t)BufferSize));
664 }
665
188666 #else
667
668 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() {
669 }
670
671 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge(
672 const MemoryBuffer &Manifest) {
673 return Error::success();
674 }
675
676 std::unique_ptr
677 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() {
189678 return nullptr;
679 }
680
190681 #endif
191 }
192
193 void WindowsManifestMerger::errorCallback(void *Ctx, const char *Format, ...) {
194 auto *Merger = (WindowsManifestMerger *)Ctx;
682
683 WindowsManifestMerger::WindowsManifestMerger()
684 : Impl(make_unique()) {}
685
686 WindowsManifestMerger::~WindowsManifestMerger() {}
687
688 Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) {
689 return Impl->merge(Manifest);
690 }
691
692 std::unique_ptr WindowsManifestMerger::getMergedManifest() {
693 return Impl->getMergedManifest();
694 }
695
696 void WindowsManifestMerger::WindowsManifestMergerImpl::errorCallback(
697 void *Ctx, const char *Format, ...) {
698 auto *Merger = (WindowsManifestMergerImpl *)Ctx;
195699 Merger->ParseErrorOccurred = true;
196700 }
197701
198 Error WindowsManifestMerger::getParseError() {
702 Error WindowsManifestMerger::WindowsManifestMergerImpl::getParseError() {
199703 if (!ParseErrorOccurred)
200704 return Error::success();
201705 return make_error("invalid xml document");
202706 }
203
204 } // namespace llvm
0 REQUIRES: libxml2
1 UNSUPPORTED: windows
2
3 RUN: llvm-mt /manifest %p/Inputs/trust_info.manifest \
4 RUN: /manifest %p/Inputs/assembly_identity.manifest \
5 RUN: /manifest %p/Inputs/trust_and_identity.manifest \
6 RUN: /manifest %p/Inputs/compatibility.manifest \
7 RUN: /manifest %p/Inputs/windows_settings.manifest /out:%t
8 RUN: FileCheck %s -input-file=%t
9
10 CHECK:
11 CHECK-NEXT:
12 CHECK-NEXT:
13 CHECK-NEXT:
14 CHECK-NEXT:
15 CHECK-NEXT:
16 CHECK-NEXT:
17 CHECK-NEXT:
18 CHECK-NEXT:
19 CHECK-NEXT:
20 CHECK-NEXT:
21 CHECK-NEXT:
22 CHECK-NEXT:
23 CHECK-NEXT:
24 CHECK-NEXT:
25 CHECK-NEXT:
26 CHECK-NEXT:
27 CHECK-NEXT:
28 CHECK-NEXT:
29 CHECK-NEXT:
30 CHECK-NEXT:
31 CHECK-NEXT:
32 CHECK-NEXT:
33 CHECK-NEXT:
34 CHECK-NEXT:
35 CHECK-NEXT: true/pm
36 CHECK-NEXT:
37 CHECK-NEXT:
38 CHECK-NEXT:
0 RUN: llvm-mt /h | FileCheck %s -check-prefix=HELP
11
22 HELP: OVERVIEW: Manifest Tool
3
4 RUN: not llvm-mt /foo 2>&1 >/dev/null | FileCheck %s -check-prefix=INVALID
5
6 INVALID: llvm-mt error: invalid option /foo
44 RUN: %p/Inputs/additional.manifest /out:%t
55 RUN: FileCheck %s -input-file=%t
66
7 CHECK: ?>
7 CHECK: encoding="UTF-8"?>
88 CHECK-NEXT:
99 CHECK-NEXT:
1010 CHECK-NEXT:
33 RUN: llvm-mt /manifest %p/Inputs/test_manifest.manifest /out:%t
44 RUN: FileCheck %s --input-file=%t
55
6 CHECK: ?>
6 CHECK: encoding="UTF-8"?>
77 CHECK-NEXT:
88 CHECK-NEXT:
99 CHECK-NEXT:
1010
1111 EMPTY: llvm-mt error: attempted to merge empty manifest
1212
13 RUN: llvm-mt /inputresource:foo.res /manifest \
14 RUN: %p/Inputs/test_manifest.manifest | FileCheck %s \
15 RUN: -check-prefix=NOT_SUPPORTED
13 RUN: llvm-mt /inputresource:foo.res \
14 RUN: /manifest %p/Inputs/test_manifest.manifest \
15 RUN: /out:%t | FileCheck %s -check-prefix=NOT_SUPPORTED
1616
1717 NOT_SUPPORTED: llvm-mt: ignoring unsupported 'inputresource:' option
101101 ArrayRef ArgsArr = makeArrayRef(argv + 1, argc);
102102 opt::InputArgList InputArgs = T.ParseArgs(ArgsArr, MAI, MAC);
103103
104 for (auto *Arg : InputArgs.filtered(OPT_INPUT))
105 reportError(Twine("invalid option ") + Arg->getSpelling());
106
104107 for (auto &Arg : InputArgs) {
105108 if (Arg->getOption().matches(OPT_unsupported)) {
106109 outs() << "llvm-mt: ignoring unsupported '" << Arg->getOption().getName()
128131 reportError("no output file specified");
129132 }
130133
131 WindowsManifestMerger Merger;
134 windows_manifest::WindowsManifestMerger Merger;
132135
133136 for (const auto &File : InputFiles) {
134137 ErrorOr> ManifestOrErr =