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 ()__anon2a610bde0111::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 { 300 ::osl::ClearableMutexGuard guard(m_rMutex); 301 302 if (0 == m_aNodePtr) { return 0; } 303 304 CNode *const pNewChild(CNode::GetImplementation(xNewChild)); 305 if (!pNewChild) { throw RuntimeException(); } 306 xmlNodePtr const cur = pNewChild->GetNodePtr(); 307 if (!cur) { throw RuntimeException(); } 308 309 // error checks: 310 // from other document 311 if (cur->doc != m_aNodePtr->doc) { 312 DOMException e; 313 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 314 throw e; 315 } 316 // same node 317 if (cur == m_aNodePtr) { 318 DOMException e; 319 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 320 throw e; 321 } 322 if (cur->parent != NULL) { 323 DOMException e; 324 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 325 throw e; 326 } 327 if (!IsChildTypeAllowed(pNewChild->m_aNodeType)) { 328 DOMException e; 329 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 330 throw e; 331 } 332 333 // check whether this is an attribute node; it needs special handling 334 xmlNodePtr res = NULL; 335 if (cur->type == XML_ATTRIBUTE_NODE) 336 { 337 xmlChar const*const pChildren((cur->children) 338 ? cur->children->content 339 : reinterpret_cast<xmlChar const*>("")); 340 CAttr *const pCAttr(dynamic_cast<CAttr *>(pNewChild)); 341 if (!pCAttr) { throw RuntimeException(); } 342 xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) ); 343 if (pNs) { 344 res = reinterpret_cast<xmlNodePtr>( 345 xmlNewNsProp(m_aNodePtr, pNs, cur->name, pChildren)); 346 } else { 347 res = reinterpret_cast<xmlNodePtr>( 348 xmlNewProp(m_aNodePtr, cur->name, pChildren)); 349 } 350 } 351 else 352 { 353 res = xmlAddChild(m_aNodePtr, cur); 354 355 // libxml can do optimization when appending nodes. 356 // if res != cur, something was optimized and the newchild-wrapper 357 // should be updated 358 if (res && (cur != res)) { 359 pNewChild->invalidate(); // cur has been freed 360 } 361 } 362 363 if (!res) { return 0; } 364 365 // use custom ns cleanup instead of 366 // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr); 367 // because that will not remove unneeded ns decls 368 nscleanup(res, m_aNodePtr); 369 370 ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res); 371 372 if (!pNode.is()) { return 0; } 373 374 // dispatch DOMNodeInserted event, target is the new node 375 // this node is the related node 376 // does bubble 377 pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 378 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 379 Reference< XMutationEvent > event(docevent->createEvent( 380 OUString::createFromAscii("DOMNodeInserted")), UNO_QUERY); 381 event->initMutationEvent(OUString::createFromAscii("DOMNodeInserted") 382 , sal_True, sal_False, 383 this, 384 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 385 386 // the following dispatch functions use only UNO interfaces 387 // and call event listeners, so release mutex to prevent deadlocks. 388 guard.clear(); 389 390 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 391 // dispatch subtree modified for this node 392 dispatchSubtreeModified(); 393 394 return pNode.get(); 395 } 396 397 /** 398 Returns a duplicate of this node, i.e., serves as a generic copy 399 constructor for nodes. 400 */ cloneNode(sal_Bool bDeep)401 Reference< XNode > SAL_CALL CNode::cloneNode(sal_Bool bDeep) 402 { 403 ::osl::MutexGuard const g(m_rMutex); 404 405 if (0 == m_aNodePtr) { 406 return 0; 407 } 408 ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode( 409 xmlCopyNode(m_aNodePtr, (bDeep) ? 1 : 0)); 410 if (!pNode.is()) { return 0; } 411 pNode->m_bUnlinked = true; // not linked yet 412 return pNode.get(); 413 } 414 415 /** 416 A NamedNodeMap containing the attributes of this node (if it is an Element) 417 or null otherwise. 418 */ getAttributes()419 Reference< XNamedNodeMap > SAL_CALL CNode::getAttributes() 420 { 421 // return empty reference; only element node may override this impl 422 return Reference< XNamedNodeMap>(); 423 } 424 425 /** 426 A NodeList that contains all children of this node. 427 */ getChildNodes()428 Reference< XNodeList > SAL_CALL CNode::getChildNodes() 429 { 430 ::osl::MutexGuard const g(m_rMutex); 431 432 if (0 == m_aNodePtr) { 433 return 0; 434 } 435 Reference< XNodeList > const xNodeList(new CChildList(this, m_rMutex)); 436 return xNodeList; 437 } 438 439 /** 440 The first child of this node. 441 */ getFirstChild()442 Reference< XNode > SAL_CALL CNode::getFirstChild() 443 { 444 ::osl::MutexGuard const g(m_rMutex); 445 446 if (0 == m_aNodePtr) { 447 return 0; 448 } 449 Reference< XNode > const xNode( 450 GetOwnerDocument().GetCNode(m_aNodePtr->children).get()); 451 return xNode; 452 } 453 454 /** 455 The last child of this node. 456 */ getLastChild()457 Reference< XNode > SAL_CALL CNode::getLastChild() 458 { 459 ::osl::MutexGuard const g(m_rMutex); 460 461 if (0 == m_aNodePtr) { 462 return 0; 463 } 464 Reference< XNode > const xNode( 465 GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr)).get()); 466 return xNode; 467 } 468 469 /** 470 Returns the local part of the qualified name of this node. 471 */ getLocalName()472 OUString SAL_CALL CNode::getLocalName() 473 { 474 // see CElement/CAttr 475 return ::rtl::OUString(); 476 } 477 478 479 /** 480 The namespace URI of this node, or null if it is unspecified. 481 */ getNamespaceURI()482 OUString SAL_CALL CNode::getNamespaceURI() 483 { 484 ::osl::MutexGuard const g(m_rMutex); 485 486 OUString aURI; 487 if (m_aNodePtr != NULL && 488 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) && 489 m_aNodePtr->ns != NULL) 490 { 491 const xmlChar* xHref = m_aNodePtr->ns->href; 492 aURI = OUString((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8); 493 } 494 return aURI; 495 } 496 497 /** 498 The node immediately following this node. 499 */ getNextSibling()500 Reference< XNode > SAL_CALL CNode::getNextSibling() 501 { 502 ::osl::MutexGuard const g(m_rMutex); 503 504 if (0 == m_aNodePtr) { 505 return 0; 506 } 507 Reference< XNode > const xNode( 508 GetOwnerDocument().GetCNode(m_aNodePtr->next).get()); 509 return xNode; 510 } 511 512 /** 513 The name of this node, depending on its type; see the table above. 514 */ getNodeName()515 OUString SAL_CALL CNode::getNodeName() 516 { 517 /* 518 Interface nodeName nodeValue attributes 519 -------------------------------------------------------------------------------------- 520 Attr name of attribute value of attribute null 521 CDATASection "#cdata-section" content of the CDATA Section null 522 Comment "#comment" content of the comment null 523 Document "#document" null null 524 DocumentFragment "#document-fragment" null null 525 DocumentType document type name null null 526 Element tag name null NamedNodeMap 527 Entity entity name null null 528 EntityReference name of entity null null 529 referenced 530 Notation notation name null null 531 Processing\ target entire content excluding null 532 Instruction the target 533 Text "#text" content of the text node null 534 */ 535 OUString aName; 536 return aName; 537 } 538 539 /** 540 A code representing the type of the underlying object, as defined above. 541 */ getNodeType()542 NodeType SAL_CALL CNode::getNodeType() 543 { 544 ::osl::MutexGuard const g(m_rMutex); 545 546 return m_aNodeType; 547 } 548 549 /** 550 The value of this node, depending on its type; see the table above. 551 */ getNodeValue()552 OUString SAL_CALL CNode::getNodeValue() 553 { 554 OUString aValue; 555 return aValue; 556 } 557 558 /** 559 The Document object associated with this node. 560 */ getOwnerDocument()561 Reference< XDocument > SAL_CALL CNode::getOwnerDocument() 562 { 563 ::osl::MutexGuard const g(m_rMutex); 564 565 if (0 == m_aNodePtr) { 566 return 0; 567 } 568 Reference< XDocument > const xDoc(& GetOwnerDocument()); 569 return xDoc; 570 } 571 572 /** 573 The parent of this node. 574 */ getParentNode()575 Reference< XNode > SAL_CALL CNode::getParentNode() 576 { 577 ::osl::MutexGuard const g(m_rMutex); 578 579 if (0 == m_aNodePtr) { 580 return 0; 581 } 582 Reference< XNode > const xNode( 583 GetOwnerDocument().GetCNode(m_aNodePtr->parent).get()); 584 return xNode; 585 } 586 587 /** 588 The namespace prefix of this node, or null if it is unspecified. 589 */ getPrefix()590 OUString SAL_CALL CNode::getPrefix() 591 { 592 ::osl::MutexGuard const g(m_rMutex); 593 594 OUString aPrefix; 595 if (m_aNodePtr != NULL && 596 (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) && 597 m_aNodePtr->ns != NULL) 598 { 599 const xmlChar* xPrefix = m_aNodePtr->ns->prefix; 600 if( xPrefix != NULL ) 601 aPrefix = OUString((sal_Char*)xPrefix, strlen((char*)xPrefix), RTL_TEXTENCODING_UTF8); 602 } 603 return aPrefix; 604 605 } 606 607 /** 608 The node immediately preceding this node. 609 */ getPreviousSibling()610 Reference< XNode > SAL_CALL CNode::getPreviousSibling() 611 { 612 ::osl::MutexGuard const g(m_rMutex); 613 614 if (0 == m_aNodePtr) { 615 return 0; 616 } 617 Reference< XNode > const xNode( 618 GetOwnerDocument().GetCNode(m_aNodePtr->prev).get()); 619 return xNode; 620 } 621 622 /** 623 Returns whether this node (if it is an element) has any attributes. 624 */ hasAttributes()625 sal_Bool SAL_CALL CNode::hasAttributes() 626 { 627 ::osl::MutexGuard const g(m_rMutex); 628 629 return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL); 630 } 631 632 /** 633 Returns whether this node has any children. 634 */ hasChildNodes()635 sal_Bool SAL_CALL CNode::hasChildNodes() 636 { 637 ::osl::MutexGuard const g(m_rMutex); 638 639 return (m_aNodePtr != NULL && m_aNodePtr->children != NULL); 640 } 641 642 /** 643 Inserts the node newChild before the existing child node refChild. 644 */ insertBefore(const Reference<XNode> & newChild,const Reference<XNode> & refChild)645 Reference< XNode > SAL_CALL CNode::insertBefore( 646 const Reference< XNode >& newChild, const Reference< XNode >& refChild) 647 { 648 if (!newChild.is() || !refChild.is()) { throw RuntimeException(); } 649 650 if (newChild->getOwnerDocument() != getOwnerDocument()) { 651 DOMException e; 652 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 653 throw e; 654 } 655 if (refChild->getParentNode() != Reference< XNode >(this)) { 656 DOMException e; 657 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 658 throw e; 659 } 660 661 ::osl::ClearableMutexGuard guard(m_rMutex); 662 663 CNode *const pNewNode(CNode::GetImplementation(newChild)); 664 CNode *const pRefNode(CNode::GetImplementation(refChild)); 665 if (!pNewNode || !pRefNode) { throw RuntimeException(); } 666 xmlNodePtr const pNewChild(pNewNode->GetNodePtr()); 667 xmlNodePtr const pRefChild(pRefNode->GetNodePtr()); 668 if (!pNewChild || !pRefChild) { throw RuntimeException(); } 669 670 if (pNewChild == m_aNodePtr) { 671 DOMException e; 672 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 673 throw e; 674 } 675 // already has parent 676 if (pNewChild->parent != NULL) 677 { 678 DOMException e; 679 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 680 throw e; 681 } 682 if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { 683 DOMException e; 684 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 685 throw e; 686 } 687 688 // attributes are unordered anyway, so just do appendChild 689 if (XML_ATTRIBUTE_NODE == pNewChild->type) { 690 guard.clear(); 691 return appendChild(newChild); 692 } 693 694 xmlNodePtr cur = m_aNodePtr->children; 695 696 //search child before which to insert 697 while (cur != NULL) 698 { 699 if (cur == pRefChild) { 700 // insert before 701 pNewChild->next = cur; 702 pNewChild->prev = cur->prev; 703 cur->prev = pNewChild; 704 if (pNewChild->prev != NULL) { 705 pNewChild->prev->next = pNewChild; 706 } 707 pNewChild->parent = cur->parent; 708 if (pNewChild->parent->children == cur) { 709 pNewChild->parent->children = pNewChild; 710 } 711 // do not update parent->last here! 712 pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 713 break; 714 } 715 cur = cur->next; 716 } 717 return refChild; 718 } 719 720 /** 721 Tests whether the DOM implementation implements a specific feature and 722 that feature is supported by this node. 723 */ isSupported(const OUString &,const OUString &)724 sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/) 725 { 726 OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)"); 727 return sal_False; 728 } 729 730 /** 731 Puts all Text nodes in the full depth of the sub-tree underneath this 732 Node, including attribute nodes, into a "normal" form where only structure 733 (e.g., elements, comments, processing instructions, CDATA sections, and 734 entity references) separates Text nodes, i.e., there are neither adjacent 735 Text nodes nor empty Text nodes. 736 */ normalize()737 void SAL_CALL CNode::normalize() 738 { 739 //XXX combine adjacent text nodes and remove empty ones 740 OSL_ENSURE(false, "CNode::normalize: not implemented (#i113683#)"); 741 } 742 743 /** 744 Removes the child node indicated by oldChild from the list of children, 745 and returns it. 746 */ 747 Reference< XNode > SAL_CALL removeChild(const Reference<XNode> & xOldChild)748 CNode::removeChild(const Reference< XNode >& xOldChild) 749 { 750 if (!xOldChild.is()) { 751 throw RuntimeException(); 752 } 753 754 if (xOldChild->getOwnerDocument() != getOwnerDocument()) { 755 DOMException e; 756 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 757 throw e; 758 } 759 if (xOldChild->getParentNode() != Reference< XNode >(this)) { 760 DOMException e; 761 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 762 throw e; 763 } 764 765 ::osl::ClearableMutexGuard guard(m_rMutex); 766 767 if (!m_aNodePtr) { throw RuntimeException(); } 768 769 Reference<XNode> xReturn( xOldChild ); 770 771 ::rtl::Reference<CNode> const pOld(CNode::GetImplementation(xOldChild)); 772 if (!pOld.is()) { throw RuntimeException(); } 773 xmlNodePtr const old = pOld->GetNodePtr(); 774 if (!old) { throw RuntimeException(); } 775 776 if( old->type == XML_ATTRIBUTE_NODE ) 777 { 778 xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(old); 779 xmlRemoveProp( pAttr ); 780 pOld->invalidate(); // freed by xmlRemoveProp 781 xReturn.clear(); 782 } 783 else 784 { 785 xmlUnlinkNode(old); 786 pOld->m_bUnlinked = true; 787 } 788 789 /*DOMNodeRemoved 790 * Fired when a node is being removed from its parent node. 791 * This event is dispatched before the node is removed from the tree. 792 * The target of this event is the node being removed. 793 * Bubbles: Yes 794 * Cancelable: No 795 * Context Info: relatedNode holds the parent node 796 */ 797 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 798 Reference< XMutationEvent > event(docevent->createEvent( 799 OUString::createFromAscii("DOMNodeRemoved")), UNO_QUERY); 800 event->initMutationEvent(OUString::createFromAscii("DOMNodeRemoved"), 801 sal_True, 802 sal_False, 803 this, 804 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 805 806 // the following dispatch functions use only UNO interfaces 807 // and call event listeners, so release mutex to prevent deadlocks. 808 guard.clear(); 809 810 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 811 // subtree modified for this node 812 dispatchSubtreeModified(); 813 814 return xReturn; 815 } 816 817 /** 818 Replaces the child node oldChild with newChild in the list of children, 819 and returns the oldChild node. 820 */ replaceChild(Reference<XNode> const & xNewChild,Reference<XNode> const & xOldChild)821 Reference< XNode > SAL_CALL CNode::replaceChild( 822 Reference< XNode > const& xNewChild, 823 Reference< XNode > const& xOldChild) 824 { 825 if (!xOldChild.is() || !xNewChild.is()) { 826 throw RuntimeException(); 827 } 828 829 if (xNewChild->getOwnerDocument() != getOwnerDocument()) { 830 DOMException e; 831 e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR; 832 throw e; 833 } 834 if (xOldChild->getParentNode() != Reference< XNode >(this)) { 835 DOMException e; 836 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 837 throw e; 838 } 839 840 ::osl::ClearableMutexGuard guard(m_rMutex); 841 842 /* 843 Reference< XNode > aNode = removeChild(oldChild); 844 appendChild(newChild); 845 */ 846 ::rtl::Reference<CNode> const pOldNode( 847 CNode::GetImplementation(xOldChild)); 848 ::rtl::Reference<CNode> const pNewNode( 849 CNode::GetImplementation(xNewChild)); 850 if (!pOldNode.is() || !pNewNode.is()) { throw RuntimeException(); } 851 xmlNodePtr const pOld = pOldNode->GetNodePtr(); 852 xmlNodePtr const pNew = pNewNode->GetNodePtr(); 853 if (!pOld || !pNew) { throw RuntimeException(); } 854 855 if (pNew == m_aNodePtr) { 856 DOMException e; 857 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 858 throw e; 859 } 860 // already has parent 861 if (pNew->parent != NULL) { 862 DOMException e; 863 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 864 throw e; 865 } 866 if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) { 867 DOMException e; 868 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 869 throw e; 870 } 871 872 if( pOld->type == XML_ATTRIBUTE_NODE ) 873 { 874 // can only replace attribute with attribute 875 if ( pOld->type != pNew->type ) 876 { 877 DOMException e; 878 e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR; 879 throw e; 880 } 881 882 xmlAttrPtr pAttr = (xmlAttrPtr)pOld; 883 xmlRemoveProp( pAttr ); 884 pOldNode->invalidate(); // freed by xmlRemoveProp 885 appendChild(xNewChild); 886 } 887 else 888 { 889 890 xmlNodePtr cur = m_aNodePtr->children; 891 //find old node in child list 892 while (cur != NULL) 893 { 894 if(cur == pOld) 895 { 896 // exchange nodes 897 pNew->prev = pOld->prev; 898 if (pNew->prev != NULL) 899 pNew->prev->next = pNew; 900 pNew->next = pOld->next; 901 if (pNew->next != NULL) 902 pNew->next->prev = pNew; 903 pNew->parent = pOld->parent; 904 if(pNew->parent->children == pOld) 905 pNew->parent->children = pNew; 906 if(pNew->parent->last == pOld) 907 pNew->parent->last = pNew; 908 pOld->next = NULL; 909 pOld->prev = NULL; 910 pOld->parent = NULL; 911 pOldNode->m_bUnlinked = true; 912 pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc 913 } 914 cur = cur->next; 915 } 916 } 917 918 guard.clear(); // release for calling event handlers 919 dispatchSubtreeModified(); 920 921 return xOldChild; 922 } 923 dispatchSubtreeModified()924 void CNode::dispatchSubtreeModified() 925 { 926 // only uses UNO interfaces => needs no mutex 927 928 // dispatch DOMSubtreeModified 929 // target is _this_ node 930 Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY); 931 Reference< XMutationEvent > event(docevent->createEvent( 932 OUString::createFromAscii("DOMSubtreeModified")), UNO_QUERY); 933 event->initMutationEvent( 934 OUString::createFromAscii("DOMSubtreeModified"), sal_True, 935 sal_False, Reference< XNode >(), 936 OUString(), OUString(), OUString(), (AttrChangeType)0 ); 937 dispatchEvent(Reference< XEvent >(event, UNO_QUERY)); 938 } 939 940 /** 941 The value of this node, depending on its type; see the table above. 942 */ setNodeValue(const OUString &)943 void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/) 944 { 945 // use specific node implementation 946 // if we end up down here, something went wrong 947 DOMException e; 948 e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR; 949 throw e; 950 } 951 952 /** 953 The namespace prefix of this node, or null if it is unspecified. 954 */ setPrefix(const OUString & prefix)955 void SAL_CALL CNode::setPrefix(const OUString& prefix) 956 { 957 ::osl::MutexGuard const g(m_rMutex); 958 959 if ((0 == m_aNodePtr) || 960 ((m_aNodePtr->type != XML_ELEMENT_NODE) && 961 (m_aNodePtr->type != XML_ATTRIBUTE_NODE))) 962 { 963 DOMException e; 964 e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR; 965 throw e; 966 } 967 OString o1 = OUStringToOString(prefix, RTL_TEXTENCODING_UTF8); 968 xmlChar *pBuf = (xmlChar*)o1.getStr(); 969 if (m_aNodePtr != NULL && m_aNodePtr->ns != NULL) 970 { 971 xmlFree(const_cast<xmlChar *>(m_aNodePtr->ns->prefix)); 972 m_aNodePtr->ns->prefix = xmlStrdup(pBuf); 973 } 974 975 } 976 977 // --- XEventTarget addEventListener(const OUString & eventType,const Reference<com::sun::star::xml::dom::events::XEventListener> & listener,sal_Bool useCapture)978 void SAL_CALL CNode::addEventListener(const OUString& eventType, 979 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener, 980 sal_Bool useCapture) 981 { 982 ::osl::MutexGuard const g(m_rMutex); 983 984 CDocument & rDocument(GetOwnerDocument()); 985 events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher()); 986 rDispatcher.addListener(m_aNodePtr, eventType, listener, useCapture); 987 } 988 removeEventListener(const OUString & eventType,const Reference<com::sun::star::xml::dom::events::XEventListener> & listener,sal_Bool useCapture)989 void SAL_CALL CNode::removeEventListener(const OUString& eventType, 990 const Reference< com::sun::star::xml::dom::events::XEventListener >& listener, 991 sal_Bool useCapture) 992 { 993 ::osl::MutexGuard const g(m_rMutex); 994 995 CDocument & rDocument(GetOwnerDocument()); 996 events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher()); 997 rDispatcher.removeListener(m_aNodePtr, eventType, listener, useCapture); 998 } 999 dispatchEvent(const Reference<XEvent> & evt)1000 sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt) 1001 { 1002 CDocument * pDocument; 1003 events::CEventDispatcher * pDispatcher; 1004 xmlNodePtr pNode; 1005 { 1006 ::osl::MutexGuard const g(m_rMutex); 1007 1008 pDocument = & GetOwnerDocument(); 1009 pDispatcher = & pDocument->GetEventDispatcher(); 1010 pNode = m_aNodePtr; 1011 } 1012 // this calls event listeners, do not call with locked mutex 1013 pDispatcher->dispatchEvent(*pDocument, m_rMutex, pNode, this, evt); 1014 return sal_True; 1015 } 1016 1017 ::sal_Int64 SAL_CALL getSomething(Sequence<::sal_Int8> const & rId)1018 CNode::getSomething(Sequence< ::sal_Int8 > const& rId) 1019 { 1020 if ((rId.getLength() == 16) && 1021 (0 == rtl_compareMemory(UnoTunnelId::get().getConstArray(), 1022 rId.getConstArray(), 16))) 1023 { 1024 return ::sal::static_int_cast< sal_Int64 >( 1025 reinterpret_cast< sal_IntPtr >(this) ); 1026 } 1027 return 0; 1028 } 1029 } 1030