1 //===-- WindowsManifestMerger.cpp ------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===---------------------------------------------------------------------===// 8 // 9 // This file implements the .manifest merger class. 10 // 11 //===---------------------------------------------------------------------===// 12 13 #include "llvm/WindowsManifest/WindowsManifestMerger.h" 14 #include "llvm/Config/config.h" 15 #include "llvm/Support/MemoryBuffer.h" 16 17 #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 29 char WindowsManifestError::ID = 0; 30 31 WindowsManifestError::WindowsManifestError(const Twine &Msg) : Msg(Msg.str()) {} 32 33 void WindowsManifestError::log(raw_ostream &OS) const { OS << Msg; } 34 35 class WindowsManifestMerger::WindowsManifestMergerImpl { 36 public: 37 ~WindowsManifestMergerImpl(); 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 constexpr std::pair<StringLiteral, StringLiteral> 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)) { 384 Expected<xmlNsPtr> EC = 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); 402 Expected<xmlNsPtr> EC = 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. 422 Expected<xmlNsPtr> EC = 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. 440 Expected<xmlNsPtr> EC = 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); 454 Expected<xmlNsPtr> EC = 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 617 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 618 for (auto &Doc : MergedDocs) 619 xmlFreeDoc(Doc); 620 } 621 622 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 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> 659 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 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 689 WindowsManifestMerger::WindowsManifestMergerImpl::~WindowsManifestMergerImpl() { 690 } 691 692 Error WindowsManifestMerger::WindowsManifestMergerImpl::merge( 693 const MemoryBuffer &Manifest) { 694 return make_error<WindowsManifestError>("no libxml2"); 695 } 696 697 std::unique_ptr<MemoryBuffer> 698 WindowsManifestMerger::WindowsManifestMergerImpl::getMergedManifest() { 699 return nullptr; 700 } 701 702 bool windows_manifest::isAvailable() { return false; } 703 704 #endif 705 706 WindowsManifestMerger::WindowsManifestMerger() 707 : Impl(std::make_unique<WindowsManifestMergerImpl>()) {} 708 709 WindowsManifestMerger::~WindowsManifestMerger() {} 710 711 Error WindowsManifestMerger::merge(const MemoryBuffer &Manifest) { 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 } 730