1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include <node.hxx> 29 30 #include <stdio.h> 31 #include <string.h> 32 33 #include <libxml/xmlstring.h> 34 35 #include <algorithm> 36 37 #include <boost/bind.hpp> 38 39 #include <rtl/uuid.h> 40 #include <rtl/instance.hxx> 41 #include <osl/mutex.hxx> 42 43 #include <com/sun/star/xml/sax/FastToken.hpp> 44 45 #include <document.hxx> 46 #include <attr.hxx> 47 #include <childlist.hxx> 48 49 #include "../events/eventdispatcher.hxx" 50 #include "../events/mutationevent.hxx" 51 52 53 54 using namespace ::com::sun::star; 55 56 57 namespace { 58 struct UnoTunnelId 59 : public ::rtl::StaticWithInit< Sequence<sal_Int8>, UnoTunnelId > 60 { 61 Sequence<sal_Int8> operator() () 62 { 63 Sequence<sal_Int8> ret(16); 64 rtl_createUuid( 65 reinterpret_cast<sal_uInt8*>(ret.getArray()), 0, sal_True); 66 return ret; 67 } 68 }; 69 } 70 71 namespace DOM 72 { 73 void pushContext(Context& io_rContext) 74 { 75 io_rContext.maNamespaces.push_back( 76 io_rContext.maNamespaces.back()); 77 } 78 79 void popContext(Context& io_rContext) 80 { 81 io_rContext.maNamespaces.pop_back(); 82 } 83 84 void addNamespaces(Context& io_rContext, xmlNodePtr pNode) 85 { 86 // add node's namespaces to current context 87 for (xmlNsPtr pNs = pNode->nsDef; pNs != 0; pNs = pNs->next) { 88 const xmlChar *pPrefix = pNs->prefix; 89 OString prefix(reinterpret_cast<const sal_Char*>(pPrefix), 90 strlen(reinterpret_cast<const char*>(pPrefix))); 91 const xmlChar *pHref = pNs->href; 92 OUString val(reinterpret_cast<const sal_Char*>(pHref), 93 strlen(reinterpret_cast<const char*>(pHref)), 94 RTL_TEXTENCODING_UTF8); 95 96 OSL_TRACE("Trying to add namespace %s (prefix %s)", 97 (const char*)pHref, (const char*)pPrefix); 98 99 Context::NamespaceMapType::iterator aIter= 100 io_rContext.maNamespaceMap.find(val); 101 if( aIter != io_rContext.maNamespaceMap.end() ) 102 { 103 Context::Namespace aNS; 104 aNS.maPrefix = prefix; 105 aNS.mnToken = aIter->second; 106 aNS.maNamespaceURL = val; 107 108 io_rContext.maNamespaces.back().push_back(aNS); 109 110 OSL_TRACE("Added with token 0x%x", aIter->second); 111 } 112 } 113 } 114 115 sal_Int32 getToken( const Context& rContext, const sal_Char* pToken ) 116 { 117 const Sequence<sal_Int8> aSeq( (sal_Int8*)pToken, strlen( pToken ) ); 118 return rContext.mxTokenHandler->getTokenFromUTF8( aSeq ); 119 } 120 121 sal_Int32 getTokenWithPrefix( const Context& rContext, const sal_Char* pPrefix, const sal_Char* pName ) 122 { 123 sal_Int32 nNamespaceToken = FastToken::DONTKNOW; 124 OString prefix(pPrefix, 125 strlen(reinterpret_cast<const char*>(pPrefix))); 126 127 OSL_TRACE("getTokenWithPrefix(): prefix %s, name %s", 128 (const char*)pPrefix, (const char*)pName); 129 130 Context::NamespaceVectorType::value_type::const_iterator aIter; 131 if( (aIter=std::find_if(rContext.maNamespaces.back().begin(), 132 rContext.maNamespaces.back().end(), 133 boost::bind(std::equal_to<OString>(), 134 boost::bind(&Context::Namespace::getPrefix, 135 _1), 136 boost::cref(prefix)))) != rContext.maNamespaces.back().end() ) 137 { 138 nNamespaceToken = aIter->mnToken; 139 sal_Int32 nNameToken = getToken( rContext, pName ); 140 if( nNameToken != FastToken::DONTKNOW ) 141 nNamespaceToken |= nNameToken; 142 } 143 144 return nNamespaceToken; 145 } 146 147 148 CNode::CNode(CDocument const& rDocument, ::osl::Mutex const& rMutex, 149 NodeType const& reNodeType, xmlNodePtr const& rpNode) 150 : m_bUnlinked(false) 151 , m_aNodeType(reNodeType) 152 , m_aNodePtr(rpNode) 153 // keep containing document alive 154 // (but not if this is a document; that would create a leak!) 155 , m_xDocument( (m_aNodePtr->type != XML_DOCUMENT_NODE) 156 ? &const_cast<CDocument&>(rDocument) : 0 ) 157 , m_rMutex(const_cast< ::osl::Mutex & >(rMutex)) 158 { 159 OSL_ASSERT(m_aNodePtr); 160 } 161 162 void CNode::invalidate() 163 { 164 //remove from list if this wrapper goes away 165 if (m_aNodePtr != 0 && m_xDocument.is()) { 166 m_xDocument->RemoveCNode(m_aNodePtr, this); 167 } 168 // #i113663#: unlinked nodes will not be freed by xmlFreeDoc 169 if (m_bUnlinked) { 170 xmlFreeNode(m_aNodePtr); 171 } 172 m_aNodePtr = 0; 173 } 174 175 CNode::~CNode() 176 { 177 // if this is the document itself, the mutex is already freed! 178 if (NodeType_DOCUMENT_NODE == m_aNodeType) { 179 invalidate(); 180 } else { 181 ::osl::MutexGuard const g(m_rMutex); 182 invalidate(); // other nodes are still alive so must lock mutex 183 } 184 } 185 186 CNode * 187 CNode::GetImplementation(uno::Reference<uno::XInterface> const& xNode) 188 { 189 uno::Reference<lang::XUnoTunnel> const xUnoTunnel(xNode, UNO_QUERY); 190 if (!xUnoTunnel.is()) { return 0; } 191 CNode *const pCNode( reinterpret_cast< CNode* >( 192 ::sal::static_int_cast< sal_IntPtr >( 193 xUnoTunnel->getSomething(UnoTunnelId::get())))); 194 return pCNode; 195 } 196 197 CDocument & CNode::GetOwnerDocument() 198 { 199 OSL_ASSERT(m_xDocument.is()); 200 return *m_xDocument; // needs overriding in CDocument! 201 } 202 203 204 static void lcl_nsexchange( 205 xmlNodePtr const aNode, xmlNsPtr const oldNs, xmlNsPtr const newNs) 206 { 207 // recursively exchange any references to oldNs with references to newNs 208 xmlNodePtr cur = aNode; 209 while (cur != 0) 210 { 211 if (cur->ns == oldNs) 212 cur->ns = newNs; 213 if (cur->type == XML_ELEMENT_NODE) 214 { 215 xmlAttrPtr curAttr = cur->properties; 216 while(curAttr != 0) 217 { 218 if (curAttr->ns == oldNs) 219 curAttr->ns = newNs; 220 curAttr = curAttr->next; 221 } 222 lcl_nsexchange(cur->children, oldNs, newNs); 223 } 224 cur = cur->next; 225 } 226 } 227 228 /*static*/ void nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent) 229 { 230 xmlNodePtr cur = aNode; 231 232 //handle attributes 233 if (cur != NULL && cur->type == XML_ELEMENT_NODE) 234 { 235 xmlAttrPtr curAttr = cur->properties; 236 while(curAttr != 0) 237 { 238 if (curAttr->ns != NULL) 239 { 240 xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix); 241 if (ns != NULL) 242 curAttr->ns = ns; 243 } 244 curAttr = curAttr->next; 245 } 246 } 247 248 while (cur != NULL) 249 { 250 nscleanup(cur->children, cur); 251 if (cur->ns != NULL) 252 { 253 xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix); 254 if (ns != NULL && ns != cur->ns && strcmp((char*)ns->href, (char*)cur->ns->href)==0) 255 { 256 xmlNsPtr curDef = cur->nsDef; 257 xmlNsPtr *refp = &(cur->nsDef); // insert point 258 while (curDef != NULL) 259 { 260 ns = xmlSearchNs(cur->doc, aParent, curDef->prefix); 261 if (ns != NULL && ns != curDef && strcmp((char*)ns->href, (char*)curDef->href)==0) 262 { 263 // reconnect ns pointers in sub-tree to newly found ns before 264 // removing redundant nsdecl to prevent dangling pointers. 265 lcl_nsexchange(cur, curDef, ns); 266 *refp = curDef->next; 267 xmlFreeNs(curDef); 268 curDef = *refp; 269 } else { 270 refp = &(curDef->next); 271 curDef = curDef->next; 272 } 273 } 274 } 275 } 276 cur = cur->next; 277 } 278 } 279 280 void CNode::saxify(const Reference< XDocumentHandler >& i_xHandler) 281 { 282 if (!i_xHandler.is()) throw RuntimeException(); 283 // default: do nothing 284 } 285 286 void CNode::fastSaxify(Context& io_rContext) 287 { 288 if (!io_rContext.mxDocHandler.is()) throw RuntimeException(); 289 // default: do nothing 290 } 291 292 bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/) 293 { 294 // default: no children allowed 295 return false; 296 } 297 298 /** 299 Adds the node newChild to the end of the list of children of this node. 300 */ 301 Reference< XNode > SAL_CALL CNode::appendChild( 302 Reference< XNode > const& xNewChild) 303 throw (RuntimeException, DOMException) 304 { 305 ::osl::ClearableMutexGuard guard(m_rMutex); 306 307 if (0 == m_aNodePtr) { return 0; } 308 309 CNode *const pNewChild(CNode::GetImplementation(xNewChild)); 310 if (!pNewChild) { throw RuntimeException(); } 311 xmlNodePtr const cur = pNewChild->GetNodePtr(); 312 if (!cur) { throw RuntimeException(); } 313 314 // error checks: 315 // from other document 316 if (cur->doc != m_aNodePtr->doc) { 317 DOMException e; 318 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 319 throw e; 320 } 321 // same node 322 if (cur == m_aNodePtr) { 323 DOMException e; 324 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 325 throw e; 326 } 327 if (cur->parent != NULL) { 328 DOMException e; 329 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 330 throw e; 331 } 332 if (!IsChildTypeAllowed(pNewChild->m_aNodeType)) { 333 DOMException e; 334 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 335 throw e; 336 } 337 338 // check whether this is an attribute node; it needs special handling 339 xmlNodePtr res = NULL; 340 if (cur->type == XML_ATTRIBUTE_NODE) 341 { 342 xmlChar const*const pChildren((cur->children) 343 ? cur->children->content 344 : reinterpret_cast<xmlChar const*>("")); 345 CAttr *const pCAttr(dynamic_cast<CAttr *>(pNewChild)); 346 if (!pCAttr) { throw RuntimeException(); } 347 xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) ); 348 if (pNs) { 349 res = reinterpret_cast<xmlNodePtr>( 350 xmlNewNsProp(m_aNodePtr, pNs, cur->name, pChildren)); 351 } else { 352 res = reinterpret_cast<xmlNodePtr>( 353 xmlNewProp(m_aNodePtr, cur->name, pChildren)); 354 } 355 } 356 else 357 { 358 res = xmlAddChild(m_aNodePtr, cur); 359 360 // libxml can do optimization when appending nodes. 361 // if res != cur, something was optimized and the newchild-wrapper 362 // should be updated 363 if (res && (cur != res)) { 364 pNewChild->invalidate(); // cur has been freed 365 } 366 } 367 368 if (!res) { return 0; } 369 370 // use custom ns cleanup instead of 371 // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr); 372 // because that will not remove unneeded ns decls 373 nscleanup(res, m_aNodePtr); 374 375 ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res); 376 377 if (!pNode.is()) { return 0; } 378 379 // dispatch DOMNodeInserted event, target is the new node 380 // this node is the related node 381 // does bubble 382 pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 383 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 384 Reference< XMutationEvent > event(docevent->createEvent( 385 OUString::createFromAscii("DOMNodeInserted")), UNO_QUERY); 386 event->initMutationEvent(OUString::createFromAscii("DOMNodeInserted") 387 , sal_True, sal_False, 388 this, 389 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 390 391 // the following dispatch functions use only UNO interfaces 392 // and call event listeners, so release mutex to prevent deadlocks. 393 guard.clear(); 394 395 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 396 // dispatch subtree modified for this node 397 dispatchSubtreeModified(); 398 399 return pNode.get(); 400 } 401 402 /** 403 Returns a duplicate of this node, i.e., serves as a generic copy 404 constructor for nodes. 405 */ 406 Reference< XNode > SAL_CALL CNode::cloneNode(sal_Bool bDeep) 407 throw (RuntimeException) 408 { 409 ::osl::MutexGuard const g(m_rMutex); 410 411 if (0 == m_aNodePtr) { 412 return 0; 413 } 414 ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode( 415 xmlCopyNode(m_aNodePtr, (bDeep) ? 1 : 0)); 416 if (!pNode.is()) { return 0; } 417 pNode->m_bUnlinked = true; // not linked yet 418 return pNode.get(); 419 } 420 421 /** 422 A NamedNodeMap containing the attributes of this node (if it is an Element) 423 or null otherwise. 424 */ 425 Reference< XNamedNodeMap > SAL_CALL CNode::getAttributes() 426 throw (RuntimeException) 427 { 428 // return empty reference; only element node may override this impl 429 return Reference< XNamedNodeMap>(); 430 } 431 432 /** 433 A NodeList that contains all children of this node. 434 */ 435 Reference< XNodeList > SAL_CALL CNode::getChildNodes() 436 throw (RuntimeException) 437 { 438 ::osl::MutexGuard const g(m_rMutex); 439 440 if (0 == m_aNodePtr) { 441 return 0; 442 } 443 Reference< XNodeList > const xNodeList(new CChildList(this, m_rMutex)); 444 return xNodeList; 445 } 446 447 /** 448 The first child of this node. 449 */ 450 Reference< XNode > SAL_CALL CNode::getFirstChild() 451 throw (RuntimeException) 452 { 453 ::osl::MutexGuard const g(m_rMutex); 454 455 if (0 == m_aNodePtr) { 456 return 0; 457 } 458 Reference< XNode > const xNode( 459 GetOwnerDocument().GetCNode(m_aNodePtr->children).get()); 460 return xNode; 461 } 462 463 /** 464 The last child of this node. 465 */ 466 Reference< XNode > SAL_CALL CNode::getLastChild() 467 throw (RuntimeException) 468 { 469 ::osl::MutexGuard const g(m_rMutex); 470 471 if (0 == m_aNodePtr) { 472 return 0; 473 } 474 Reference< XNode > const xNode( 475 GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr)).get()); 476 return xNode; 477 } 478 479 /** 480 Returns the local part of the qualified name of this node. 481 */ 482 OUString SAL_CALL CNode::getLocalName() 483 throw (RuntimeException) 484 { 485 // see CElement/CAttr 486 return ::rtl::OUString(); 487 } 488 489 490 /** 491 The namespace URI of this node, or null if it is unspecified. 492 */ 493 OUString SAL_CALL CNode::getNamespaceURI() 494 throw (RuntimeException) 495 { 496 ::osl::MutexGuard const g(m_rMutex); 497 498 OUString aURI; 499 if (m_aNodePtr != NULL && 500 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) && 501 m_aNodePtr->ns != NULL) 502 { 503 const xmlChar* xHref = m_aNodePtr->ns->href; 504 aURI = OUString((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8); 505 } 506 return aURI; 507 } 508 509 /** 510 The node immediately following this node. 511 */ 512 Reference< XNode > SAL_CALL CNode::getNextSibling() 513 throw (RuntimeException) 514 { 515 ::osl::MutexGuard const g(m_rMutex); 516 517 if (0 == m_aNodePtr) { 518 return 0; 519 } 520 Reference< XNode > const xNode( 521 GetOwnerDocument().GetCNode(m_aNodePtr->next).get()); 522 return xNode; 523 } 524 525 /** 526 The name of this node, depending on its type; see the table above. 527 */ 528 OUString SAL_CALL CNode::getNodeName() 529 throw (RuntimeException) 530 { 531 /* 532 Interface nodeName nodeValue attributes 533 -------------------------------------------------------------------------------------- 534 Attr name of attribute value of attribute null 535 CDATASection "#cdata-section" content of the CDATA Section null 536 Comment "#comment" content of the comment null 537 Document "#document" null null 538 DocumentFragment "#document-fragment" null null 539 DocumentType document type name null null 540 Element tag name null NamedNodeMap 541 Entity entity name null null 542 EntityReference name of entity null null 543 referenced 544 Notation notation name null null 545 Processing\ target entire content excluding null 546 Instruction the target 547 Text "#text" content of the text node null 548 */ 549 OUString aName; 550 return aName; 551 } 552 553 /** 554 A code representing the type of the underlying object, as defined above. 555 */ 556 NodeType SAL_CALL CNode::getNodeType() 557 throw (RuntimeException) 558 { 559 ::osl::MutexGuard const g(m_rMutex); 560 561 return m_aNodeType; 562 } 563 564 /** 565 The value of this node, depending on its type; see the table above. 566 */ 567 OUString SAL_CALL CNode::getNodeValue() 568 throw (RuntimeException) 569 { 570 OUString aValue; 571 return aValue; 572 } 573 574 /** 575 The Document object associated with this node. 576 */ 577 Reference< XDocument > SAL_CALL CNode::getOwnerDocument() 578 throw (RuntimeException) 579 { 580 ::osl::MutexGuard const g(m_rMutex); 581 582 if (0 == m_aNodePtr) { 583 return 0; 584 } 585 Reference< XDocument > const xDoc(& GetOwnerDocument()); 586 return xDoc; 587 } 588 589 /** 590 The parent of this node. 591 */ 592 Reference< XNode > SAL_CALL CNode::getParentNode() 593 throw (RuntimeException) 594 { 595 ::osl::MutexGuard const g(m_rMutex); 596 597 if (0 == m_aNodePtr) { 598 return 0; 599 } 600 Reference< XNode > const xNode( 601 GetOwnerDocument().GetCNode(m_aNodePtr->parent).get()); 602 return xNode; 603 } 604 605 /** 606 The namespace prefix of this node, or null if it is unspecified. 607 */ 608 OUString SAL_CALL CNode::getPrefix() 609 throw (RuntimeException) 610 { 611 ::osl::MutexGuard const g(m_rMutex); 612 613 OUString aPrefix; 614 if (m_aNodePtr != NULL && 615 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) && 616 m_aNodePtr->ns != NULL) 617 { 618 const xmlChar* xPrefix = m_aNodePtr->ns->prefix; 619 if( xPrefix != NULL ) 620 aPrefix = OUString((sal_Char*)xPrefix, strlen((char*)xPrefix), RTL_TEXTENCODING_UTF8); 621 } 622 return aPrefix; 623 624 } 625 626 /** 627 The node immediately preceding this node. 628 */ 629 Reference< XNode > SAL_CALL CNode::getPreviousSibling() 630 throw (RuntimeException) 631 { 632 ::osl::MutexGuard const g(m_rMutex); 633 634 if (0 == m_aNodePtr) { 635 return 0; 636 } 637 Reference< XNode > const xNode( 638 GetOwnerDocument().GetCNode(m_aNodePtr->prev).get()); 639 return xNode; 640 } 641 642 /** 643 Returns whether this node (if it is an element) has any attributes. 644 */ 645 sal_Bool SAL_CALL CNode::hasAttributes() 646 throw (RuntimeException) 647 { 648 ::osl::MutexGuard const g(m_rMutex); 649 650 return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL); 651 } 652 653 /** 654 Returns whether this node has any children. 655 */ 656 sal_Bool SAL_CALL CNode::hasChildNodes() 657 throw (RuntimeException) 658 { 659 ::osl::MutexGuard const g(m_rMutex); 660 661 return (m_aNodePtr != NULL && m_aNodePtr->children != NULL); 662 } 663 664 /** 665 Inserts the node newChild before the existing child node refChild. 666 */ 667 Reference< XNode > SAL_CALL CNode::insertBefore( 668 const Reference< XNode >& newChild, const Reference< XNode >& refChild) 669 throw (RuntimeException, DOMException) 670 { 671 if (!newChild.is() || !refChild.is()) { throw RuntimeException(); } 672 673 if (newChild->getOwnerDocument() != getOwnerDocument()) { 674 DOMException e; 675 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 676 throw e; 677 } 678 if (refChild->getParentNode() != Reference< XNode >(this)) { 679 DOMException e; 680 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 681 throw e; 682 } 683 684 ::osl::ClearableMutexGuard guard(m_rMutex); 685 686 CNode *const pNewNode(CNode::GetImplementation(newChild)); 687 CNode *const pRefNode(CNode::GetImplementation(refChild)); 688 if (!pNewNode || !pRefNode) { throw RuntimeException(); } 689 xmlNodePtr const pNewChild(pNewNode->GetNodePtr()); 690 xmlNodePtr const pRefChild(pRefNode->GetNodePtr()); 691 if (!pNewChild || !pRefChild) { throw RuntimeException(); } 692 693 if (pNewChild == m_aNodePtr) { 694 DOMException e; 695 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 696 throw e; 697 } 698 // already has parent 699 if (pNewChild->parent != NULL) 700 { 701 DOMException e; 702 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 703 throw e; 704 } 705 if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { 706 DOMException e; 707 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 708 throw e; 709 } 710 711 // attributes are unordered anyway, so just do appendChild 712 if (XML_ATTRIBUTE_NODE == pNewChild->type) { 713 guard.clear(); 714 return appendChild(newChild); 715 } 716 717 xmlNodePtr cur = m_aNodePtr->children; 718 719 //search child before which to insert 720 while (cur != NULL) 721 { 722 if (cur == pRefChild) { 723 // insert before 724 pNewChild->next = cur; 725 pNewChild->prev = cur->prev; 726 cur->prev = pNewChild; 727 if (pNewChild->prev != NULL) { 728 pNewChild->prev->next = pNewChild; 729 } 730 pNewChild->parent = cur->parent; 731 if (pNewChild->parent->children == cur) { 732 pNewChild->parent->children = pNewChild; 733 } 734 // do not update parent->last here! 735 pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 736 break; 737 } 738 cur = cur->next; 739 } 740 return refChild; 741 } 742 743 /** 744 Tests whether the DOM implementation implements a specific feature and 745 that feature is supported by this node. 746 */ 747 sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/) 748 throw (RuntimeException) 749 { 750 OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)"); 751 return sal_False; 752 } 753 754 /** 755 Puts all Text nodes in the full depth of the sub-tree underneath this 756 Node, including attribute nodes, into a "normal" form where only structure 757 (e.g., elements, comments, processing instructions, CDATA sections, and 758 entity references) separates Text nodes, i.e., there are neither adjacent 759 Text nodes nor empty Text nodes. 760 */ 761 void SAL_CALL CNode::normalize() 762 throw (RuntimeException) 763 { 764 //XXX combine adjacent text nodes and remove empty ones 765 OSL_ENSURE(false, "CNode::normalize: not implemented (#i113683#)"); 766 } 767 768 /** 769 Removes the child node indicated by oldChild from the list of children, 770 and returns it. 771 */ 772 Reference< XNode > SAL_CALL 773 CNode::removeChild(const Reference< XNode >& xOldChild) 774 throw (RuntimeException, DOMException) 775 { 776 if (!xOldChild.is()) { 777 throw RuntimeException(); 778 } 779 780 if (xOldChild->getOwnerDocument() != getOwnerDocument()) { 781 DOMException e; 782 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 783 throw e; 784 } 785 if (xOldChild->getParentNode() != Reference< XNode >(this)) { 786 DOMException e; 787 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 788 throw e; 789 } 790 791 ::osl::ClearableMutexGuard guard(m_rMutex); 792 793 if (!m_aNodePtr) { throw RuntimeException(); } 794 795 Reference<XNode> xReturn( xOldChild ); 796 797 ::rtl::Reference<CNode> const pOld(CNode::GetImplementation(xOldChild)); 798 if (!pOld.is()) { throw RuntimeException(); } 799 xmlNodePtr const old = pOld->GetNodePtr(); 800 if (!old) { throw RuntimeException(); } 801 802 if( old->type == XML_ATTRIBUTE_NODE ) 803 { 804 xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(old); 805 xmlRemoveProp( pAttr ); 806 pOld->invalidate(); // freed by xmlRemoveProp 807 xReturn.clear(); 808 } 809 else 810 { 811 xmlUnlinkNode(old); 812 pOld->m_bUnlinked = true; 813 } 814 815 /*DOMNodeRemoved 816 * Fired when a node is being removed from its parent node. 817 * This event is dispatched before the node is removed from the tree. 818 * The target of this event is the node being removed. 819 * Bubbles: Yes 820 * Cancelable: No 821 * Context Info: relatedNode holds the parent node 822 */ 823 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 824 Reference< XMutationEvent > event(docevent->createEvent( 825 OUString::createFromAscii("DOMNodeRemoved")), UNO_QUERY); 826 event->initMutationEvent(OUString::createFromAscii("DOMNodeRemoved"), 827 sal_True, 828 sal_False, 829 this, 830 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 831 832 // the following dispatch functions use only UNO interfaces 833 // and call event listeners, so release mutex to prevent deadlocks. 834 guard.clear(); 835 836 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 837 // subtree modified for this node 838 dispatchSubtreeModified(); 839 840 return xReturn; 841 } 842 843 /** 844 Replaces the child node oldChild with newChild in the list of children, 845 and returns the oldChild node. 846 */ 847 Reference< XNode > SAL_CALL CNode::replaceChild( 848 Reference< XNode > const& xNewChild, 849 Reference< XNode > const& xOldChild) 850 throw (RuntimeException, DOMException) 851 { 852 if (!xOldChild.is() || !xNewChild.is()) { 853 throw RuntimeException(); 854 } 855 856 if (xNewChild->getOwnerDocument() != getOwnerDocument()) { 857 DOMException e; 858 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 859 throw e; 860 } 861 if (xOldChild->getParentNode() != Reference< XNode >(this)) { 862 DOMException e; 863 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 864 throw e; 865 } 866 867 ::osl::ClearableMutexGuard guard(m_rMutex); 868 869 /* 870 Reference< XNode > aNode = removeChild(oldChild); 871 appendChild(newChild); 872 */ 873 ::rtl::Reference<CNode> const pOldNode( 874 CNode::GetImplementation(xOldChild)); 875 ::rtl::Reference<CNode> const pNewNode( 876 CNode::GetImplementation(xNewChild)); 877 if (!pOldNode.is() || !pNewNode.is()) { throw RuntimeException(); } 878 xmlNodePtr const pOld = pOldNode->GetNodePtr(); 879 xmlNodePtr const pNew = pNewNode->GetNodePtr(); 880 if (!pOld || !pNew) { throw RuntimeException(); } 881 882 if (pNew == m_aNodePtr) { 883 DOMException e; 884 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 885 throw e; 886 } 887 // already has parent 888 if (pNew->parent != NULL) { 889 DOMException e; 890 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 891 throw e; 892 } 893 if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { 894 DOMException e; 895 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 896 throw e; 897 } 898 899 if( pOld->type == XML_ATTRIBUTE_NODE ) 900 { 901 // can only replace attribute with attribute 902 if ( pOld->type != pNew->type ) 903 { 904 DOMException e; 905 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 906 throw e; 907 } 908 909 xmlAttrPtr pAttr = (xmlAttrPtr)pOld; 910 xmlRemoveProp( pAttr ); 911 pOldNode->invalidate(); // freed by xmlRemoveProp 912 appendChild(xNewChild); 913 } 914 else 915 { 916 917 xmlNodePtr cur = m_aNodePtr->children; 918 //find old node in child list 919 while (cur != NULL) 920 { 921 if(cur == pOld) 922 { 923 // exchange nodes 924 pNew->prev = pOld->prev; 925 if (pNew->prev != NULL) 926 pNew->prev->next = pNew; 927 pNew->next = pOld->next; 928 if (pNew->next != NULL) 929 pNew->next->prev = pNew; 930 pNew->parent = pOld->parent; 931 if(pNew->parent->children == pOld) 932 pNew->parent->children = pNew; 933 if(pNew->parent->last == pOld) 934 pNew->parent->last = pNew; 935 pOld->next = NULL; 936 pOld->prev = NULL; 937 pOld->parent = NULL; 938 pOldNode->m_bUnlinked = true; 939 pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 940 } 941 cur = cur->next; 942 } 943 } 944 945 guard.clear(); // release for calling event handlers 946 dispatchSubtreeModified(); 947 948 return xOldChild; 949 } 950 951 void CNode::dispatchSubtreeModified() 952 { 953 // only uses UNO interfaces => needs no mutex 954 955 // dispatch DOMSubtreeModified 956 // target is _this_ node 957 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 958 Reference< XMutationEvent > event(docevent->createEvent( 959 OUString::createFromAscii("DOMSubtreeModified")), UNO_QUERY); 960 event->initMutationEvent( 961 OUString::createFromAscii("DOMSubtreeModified"), sal_True, 962 sal_False, Reference< XNode >(), 963 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 964 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 965 } 966 967 /** 968 The value of this node, depending on its type; see the table above. 969 */ 970 void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/) 971 throw (RuntimeException, DOMException) 972 { 973 // use specific node implememntation 974 // if we end up down here, something went wrong 975 DOMException e; 976 e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR; 977 throw e; 978 } 979 980 /** 981 The namespace prefix of this node, or null if it is unspecified. 982 */ 983 void SAL_CALL CNode::setPrefix(const OUString& prefix) 984 throw (RuntimeException, DOMException) 985 { 986 ::osl::MutexGuard const g(m_rMutex); 987 988 if ((0 == m_aNodePtr) || 989 ((m_aNodePtr->type != XML_ELEMENT_NODE) && 990 (m_aNodePtr->type != XML_ATTRIBUTE_NODE))) 991 { 992 DOMException e; 993 e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR; 994 throw e; 995 } 996 OString o1 = OUStringToOString(prefix, RTL_TEXTENCODING_UTF8); 997 xmlChar *pBuf = (xmlChar*)o1.getStr(); 998 if (m_aNodePtr != NULL && m_aNodePtr->ns != NULL) 999 { 1000 xmlFree(const_cast<xmlChar *>(m_aNodePtr->ns->prefix)); 1001 m_aNodePtr->ns->prefix = xmlStrdup(pBuf); 1002 } 1003 1004 } 1005 1006 // --- XEventTarget 1007 void SAL_CALL CNode::addEventListener(const OUString& eventType, 1008 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener, 1009 sal_Bool useCapture) 1010 throw (RuntimeException) 1011 { 1012 ::osl::MutexGuard const g(m_rMutex); 1013 1014 CDocument & rDocument(GetOwnerDocument()); 1015 events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher()); 1016 rDispatcher.addListener(m_aNodePtr, eventType, listener, useCapture); 1017 } 1018 1019 void SAL_CALL CNode::removeEventListener(const OUString& eventType, 1020 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener, 1021 sal_Bool useCapture) 1022 throw (RuntimeException) 1023 { 1024 ::osl::MutexGuard const g(m_rMutex); 1025 1026 CDocument & rDocument(GetOwnerDocument()); 1027 events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher()); 1028 rDispatcher.removeListener(m_aNodePtr, eventType, listener, useCapture); 1029 } 1030 1031 sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt) 1032 throw(RuntimeException, EventException) 1033 { 1034 CDocument * pDocument; 1035 events::CEventDispatcher * pDispatcher; 1036 xmlNodePtr pNode; 1037 { 1038 ::osl::MutexGuard const g(m_rMutex); 1039 1040 pDocument = & GetOwnerDocument(); 1041 pDispatcher = & pDocument->GetEventDispatcher(); 1042 pNode = m_aNodePtr; 1043 } 1044 // this calls event listeners, do not call with locked mutex 1045 pDispatcher->dispatchEvent(*pDocument, m_rMutex, pNode, this, evt); 1046 return sal_True; 1047 } 1048 1049 ::sal_Int64 SAL_CALL 1050 CNode::getSomething(Sequence< ::sal_Int8 > const& rId) 1051 throw (RuntimeException) 1052 { 1053 if ((rId.getLength() == 16) && 1054 (0 == rtl_compareMemory(UnoTunnelId::get().getConstArray(), 1055 rId.getConstArray(), 16))) 1056 { 1057 return ::sal::static_int_cast< sal_Int64 >( 1058 reinterpret_cast< sal_IntPtr >(this) ); 1059 } 1060 return 0; 1061 } 1062 } 1063 1064