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