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