1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
25 #include <libxml/xmlstring.h>
30 #include <rtl/instance.hxx>
31 #include <osl/mutex.hxx>
32 #include <osl/diagnose.h>
34 #include <com/sun/star/xml/sax/FastToken.hpp>
36 #include <comphelper/servicehelper.hxx>
38 #include "document.hxx"
40 #include "childlist.hxx"
42 #include <eventdispatcher.hxx>
43 #include <mutationevent.hxx>
46 using namespace css::uno
;
47 using namespace css::xml::dom
;
48 using namespace css::xml::dom::events
;
49 using namespace css::xml::sax
;
53 class theCNodeUnoTunnelId
: public rtl::Static
< UnoTunnelIdInit
, theCNodeUnoTunnelId
> {};
58 void pushContext(Context
& io_rContext
)
60 // Explicitly use a temp. variable.
61 // Windows/VC++ seems to mess up if .back() is directly passed as
62 // parameter. i.e. Don't use push_back( .back() );
63 Context::NamespaceVectorType::value_type aVal
= io_rContext
.maNamespaces
.back();
64 io_rContext
.maNamespaces
.push_back( aVal
);
67 void popContext(Context
& io_rContext
)
69 io_rContext
.maNamespaces
.pop_back();
72 void addNamespaces(Context
& io_rContext
, xmlNodePtr pNode
)
74 // add node's namespaces to current context
75 for (xmlNsPtr pNs
= pNode
->nsDef
; pNs
!= nullptr; pNs
= pNs
->next
) {
76 const xmlChar
*pPrefix
= pNs
->prefix
;
77 // prefix can be NULL when xmlns attribute is empty (xmlns="")
78 OString
prefix(reinterpret_cast<const sal_Char
*>(pPrefix
),
79 pPrefix
? strlen(reinterpret_cast<const char*>(pPrefix
)) : 0);
80 const xmlChar
*pHref
= pNs
->href
;
81 OUString
val(reinterpret_cast<const sal_Char
*>(pHref
),
82 strlen(reinterpret_cast<const char*>(pHref
)),
83 RTL_TEXTENCODING_UTF8
);
85 Context::NamespaceMapType::iterator aIter
=
86 io_rContext
.maNamespaceMap
.find(val
);
87 if( aIter
!= io_rContext
.maNamespaceMap
.end() )
89 Context::Namespace aNS
;
90 aNS
.maPrefix
= prefix
;
91 aNS
.mnToken
= aIter
->second
;
92 aNS
.maNamespaceURL
= val
;
94 io_rContext
.maNamespaces
.back().push_back(aNS
);
96 SAL_INFO("unoxml", "Added with token " << aIter
->second
);
101 sal_Int32
getToken( const Context
& rContext
, const sal_Char
* pToken
)
103 const Sequence
<sal_Int8
> aSeq( reinterpret_cast<sal_Int8
const *>(pToken
), strlen( pToken
) );
104 return rContext
.mxTokenHandler
->getTokenFromUTF8( aSeq
);
107 sal_Int32
getTokenWithPrefix( const Context
& rContext
, const sal_Char
* pPrefix
, const sal_Char
* pName
)
109 sal_Int32 nNamespaceToken
= FastToken::DONTKNOW
;
110 OString
prefix(pPrefix
,
111 strlen(reinterpret_cast<const char*>(pPrefix
)));
113 SAL_INFO("unoxml", "getTokenWithPrefix(): prefix " << pPrefix
<< ", name " << pName
);
115 Context::NamespaceVectorType::value_type::const_iterator aIter
;
116 if( (aIter
=std::find_if(rContext
.maNamespaces
.back().begin(),
117 rContext
.maNamespaces
.back().end(),
118 [&prefix
](const Context::Namespace
&aNamespace
){ return aNamespace
.getPrefix() == prefix
; } )) !=
119 rContext
.maNamespaces
.back().end() )
121 nNamespaceToken
= aIter
->mnToken
;
122 sal_Int32 nNameToken
= getToken( rContext
, pName
);
123 if( nNameToken
== FastToken::DONTKNOW
)
124 nNamespaceToken
= FastToken::DONTKNOW
;
126 nNamespaceToken
|= nNameToken
;
129 return nNamespaceToken
;
133 CNode::CNode(CDocument
const& rDocument
, ::osl::Mutex
const& rMutex
,
134 NodeType
const& reNodeType
, xmlNodePtr
const& rpNode
)
136 , m_aNodeType(reNodeType
)
138 // keep containing document alive
139 // (but not if this is a document; that would create a leak!)
140 , m_xDocument( (m_aNodePtr
->type
!= XML_DOCUMENT_NODE
)
141 ? &const_cast<CDocument
&>(rDocument
) : nullptr )
142 , m_rMutex(const_cast< ::osl::Mutex
& >(rMutex
))
144 OSL_ASSERT(m_aNodePtr
);
147 void CNode::invalidate()
149 //remove from list if this wrapper goes away
150 if (m_aNodePtr
!= nullptr && m_xDocument
.is()) {
151 m_xDocument
->RemoveCNode(m_aNodePtr
, this);
153 // #i113663#: unlinked nodes will not be freed by xmlFreeDoc
155 xmlFreeNode(m_aNodePtr
);
157 m_aNodePtr
= nullptr;
162 // if this is the document itself, the mutex is already freed!
163 if (NodeType_DOCUMENT_NODE
== m_aNodeType
) {
166 ::osl::MutexGuard
const g(m_rMutex
);
167 invalidate(); // other nodes are still alive so must lock mutex
172 CNode::GetImplementation(uno::Reference
<uno::XInterface
> const& xNode
)
174 uno::Reference
<lang::XUnoTunnel
> const xUnoTunnel(xNode
, UNO_QUERY
);
175 if (!xUnoTunnel
.is()) { return nullptr; }
176 CNode
*const pCNode( reinterpret_cast< CNode
* >(
177 ::sal::static_int_cast
< sal_IntPtr
>(
178 xUnoTunnel
->getSomething(theCNodeUnoTunnelId::get().getSeq()))));
182 CDocument
& CNode::GetOwnerDocument()
184 OSL_ASSERT(m_xDocument
.is());
185 return *m_xDocument
; // needs overriding in CDocument!
189 static void lcl_nsexchange(
190 xmlNodePtr
const aNode
, xmlNsPtr
const oldNs
, xmlNsPtr
const newNs
)
192 // recursively exchange any references to oldNs with references to newNs
193 xmlNodePtr cur
= aNode
;
194 while (cur
!= nullptr)
196 if (cur
->ns
== oldNs
)
198 if (cur
->type
== XML_ELEMENT_NODE
)
200 xmlAttrPtr curAttr
= cur
->properties
;
201 while(curAttr
!= nullptr)
203 if (curAttr
->ns
== oldNs
)
205 curAttr
= curAttr
->next
;
207 lcl_nsexchange(cur
->children
, oldNs
, newNs
);
213 /*static*/ void nscleanup(const xmlNodePtr aNode
, const xmlNodePtr aParent
)
215 xmlNodePtr cur
= aNode
;
218 if (cur
!= nullptr && cur
->type
== XML_ELEMENT_NODE
)
220 xmlAttrPtr curAttr
= cur
->properties
;
221 while(curAttr
!= nullptr)
223 if (curAttr
->ns
!= nullptr)
225 xmlNsPtr ns
= xmlSearchNs(cur
->doc
, aParent
, curAttr
->ns
->prefix
);
229 curAttr
= curAttr
->next
;
233 while (cur
!= nullptr)
235 nscleanup(cur
->children
, cur
);
236 if (cur
->ns
!= nullptr)
238 xmlNsPtr ns
= xmlSearchNs(cur
->doc
, aParent
, cur
->ns
->prefix
);
239 if (ns
!= nullptr && ns
!= cur
->ns
&& strcmp(reinterpret_cast<char const *>(ns
->href
), reinterpret_cast<char const *>(cur
->ns
->href
))==0)
241 xmlNsPtr curDef
= cur
->nsDef
;
242 xmlNsPtr
*refp
= &(cur
->nsDef
); // insert point
243 while (curDef
!= nullptr)
245 ns
= xmlSearchNs(cur
->doc
, aParent
, curDef
->prefix
);
246 if (ns
!= nullptr && ns
!= curDef
&& strcmp(reinterpret_cast<char const *>(ns
->href
), reinterpret_cast<char const *>(curDef
->href
))==0)
248 // reconnect ns pointers in sub-tree to newly found ns before
249 // removing redundant nsdecl to prevent dangling pointers.
250 lcl_nsexchange(cur
, curDef
, ns
);
251 *refp
= curDef
->next
;
255 refp
= &(curDef
->next
);
256 curDef
= curDef
->next
;
265 void CNode::saxify(const Reference
< XDocumentHandler
>& i_xHandler
)
267 if (!i_xHandler
.is()) throw RuntimeException();
268 // default: do nothing
271 void CNode::fastSaxify(Context
& io_rContext
)
273 if (!io_rContext
.mxDocHandler
.is()) throw RuntimeException();
274 // default: do nothing
277 bool CNode::IsChildTypeAllowed(NodeType
const /*nodeType*/)
279 // default: no children allowed
284 Adds the node newChild to the end of the list of children of this node.
286 Reference
< XNode
> SAL_CALL
CNode::appendChild(
287 Reference
< XNode
> const& xNewChild
)
289 ::osl::ClearableMutexGuard
guard(m_rMutex
);
291 if (nullptr == m_aNodePtr
) { return nullptr; }
293 CNode
*const pNewChild(CNode::GetImplementation(xNewChild
));
294 if (!pNewChild
) { throw RuntimeException(); }
295 xmlNodePtr
const cur
= pNewChild
->GetNodePtr();
296 if (!cur
) { throw RuntimeException(); }
299 // from other document
300 if (cur
->doc
!= m_aNodePtr
->doc
) {
302 e
.Code
= DOMExceptionType_WRONG_DOCUMENT_ERR
;
306 if (cur
== m_aNodePtr
) {
308 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
311 if (cur
->parent
!= nullptr) {
313 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
316 if (!IsChildTypeAllowed(pNewChild
->m_aNodeType
)) {
318 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
322 // check whether this is an attribute node; it needs special handling
323 xmlNodePtr res
= nullptr;
324 if (cur
->type
== XML_ATTRIBUTE_NODE
)
326 xmlChar
const*const pChildren((cur
->children
)
327 ? cur
->children
->content
328 : reinterpret_cast<xmlChar
const*>(""));
329 CAttr
*const pCAttr(dynamic_cast<CAttr
*>(pNewChild
));
330 if (!pCAttr
) { throw RuntimeException(); }
331 xmlNsPtr
const pNs( pCAttr
->GetNamespace(m_aNodePtr
) );
333 res
= reinterpret_cast<xmlNodePtr
>(
334 xmlNewNsProp(m_aNodePtr
, pNs
, cur
->name
, pChildren
));
336 res
= reinterpret_cast<xmlNodePtr
>(
337 xmlNewProp(m_aNodePtr
, cur
->name
, pChildren
));
342 res
= xmlAddChild(m_aNodePtr
, cur
);
344 // libxml can do optimization when appending nodes.
345 // if res != cur, something was optimized and the newchild-wrapper
347 if (res
&& (cur
!= res
)) {
348 pNewChild
->invalidate(); // cur has been freed
352 if (!res
) { return nullptr; }
354 // use custom ns cleanup instead of
355 // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
356 // because that will not remove unneeded ns decls
357 nscleanup(res
, m_aNodePtr
);
359 ::rtl::Reference
<CNode
> const pNode
= GetOwnerDocument().GetCNode(res
);
361 if (!pNode
.is()) { return nullptr; }
363 // dispatch DOMNodeInserted event, target is the new node
364 // this node is the related node
366 pNode
->m_bUnlinked
= false; // will be deleted by xmlFreeDoc
367 Reference
< XDocumentEvent
> docevent(getOwnerDocument(), UNO_QUERY
);
368 Reference
< XMutationEvent
> event(docevent
->createEvent(
369 "DOMNodeInserted"), UNO_QUERY
);
370 event
->initMutationEvent("DOMNodeInserted", true, false, this,
371 OUString(), OUString(), OUString(), AttrChangeType(0) );
373 // the following dispatch functions use only UNO interfaces
374 // and call event listeners, so release mutex to prevent deadlocks.
377 dispatchEvent(event
);
378 // dispatch subtree modified for this node
379 dispatchSubtreeModified();
385 Returns a duplicate of this node, i.e., serves as a generic copy
386 constructor for nodes.
388 Reference
< XNode
> SAL_CALL
CNode::cloneNode(sal_Bool bDeep
)
390 ::osl::MutexGuard
const g(m_rMutex
);
392 if (nullptr == m_aNodePtr
) {
395 ::rtl::Reference
<CNode
> const pNode
= GetOwnerDocument().GetCNode(
396 xmlCopyNode(m_aNodePtr
, bDeep
? 1 : 0));
397 if (!pNode
.is()) { return nullptr; }
398 pNode
->m_bUnlinked
= true; // not linked yet
403 A NamedNodeMap containing the attributes of this node (if it is an Element)
406 Reference
< XNamedNodeMap
> SAL_CALL
CNode::getAttributes()
408 // return empty reference; only element node may override this impl
409 return Reference
< XNamedNodeMap
>();
413 A NodeList that contains all children of this node.
415 Reference
< XNodeList
> SAL_CALL
CNode::getChildNodes()
417 ::osl::MutexGuard
const g(m_rMutex
);
419 if (nullptr == m_aNodePtr
) {
422 Reference
< XNodeList
> const xNodeList(new CChildList(this, m_rMutex
));
427 The first child of this node.
429 Reference
< XNode
> SAL_CALL
CNode::getFirstChild()
431 ::osl::MutexGuard
const g(m_rMutex
);
433 if (nullptr == m_aNodePtr
) {
436 Reference
< XNode
> const xNode(
437 GetOwnerDocument().GetCNode(m_aNodePtr
->children
).get());
442 The last child of this node.
444 Reference
< XNode
> SAL_CALL
CNode::getLastChild()
446 ::osl::MutexGuard
const g(m_rMutex
);
448 if (nullptr == m_aNodePtr
) {
451 Reference
< XNode
> const xNode(
452 GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr
)).get());
457 Returns the local part of the qualified name of this node.
459 OUString SAL_CALL
CNode::getLocalName()
461 // see CElement/CAttr
467 The namespace URI of this node, or null if it is unspecified.
469 OUString SAL_CALL
CNode::getNamespaceURI()
471 ::osl::MutexGuard
const g(m_rMutex
);
474 if (m_aNodePtr
!= nullptr &&
475 (m_aNodePtr
->type
== XML_ELEMENT_NODE
|| m_aNodePtr
->type
== XML_ATTRIBUTE_NODE
) &&
476 m_aNodePtr
->ns
!= nullptr)
478 const xmlChar
* pHref
= m_aNodePtr
->ns
->href
;
479 aURI
= OUString(reinterpret_cast<char const *>(pHref
), strlen(reinterpret_cast<char const *>(pHref
)), RTL_TEXTENCODING_UTF8
);
485 The node immediately following this node.
487 Reference
< XNode
> SAL_CALL
CNode::getNextSibling()
489 ::osl::MutexGuard
const g(m_rMutex
);
491 if (nullptr == m_aNodePtr
) {
494 Reference
< XNode
> const xNode(
495 GetOwnerDocument().GetCNode(m_aNodePtr
->next
).get());
500 The name of this node, depending on its type; see the table above.
502 OUString SAL_CALL
CNode::getNodeName()
505 Interface nodeName nodeValue attributes
506 --------------------------------------------------------------------------------------
507 Attr name of attribute value of attribute null
508 CDATASection "#cdata-section" content of the CDATA Section null
509 Comment "#comment" content of the comment null
510 Document "#document" null null
511 DocumentFragment "#document-fragment" null null
512 DocumentType document type name null null
513 Element tag name null NamedNodeMap
514 Entity entity name null null
515 EntityReference name of entity null null
517 Notation notation name null null
518 Processing\ target entire content excluding null
519 Instruction the target
520 Text "#text" content of the text node null
526 A code representing the type of the underlying object, as defined above.
528 NodeType SAL_CALL
CNode::getNodeType()
530 ::osl::MutexGuard
const g(m_rMutex
);
536 The value of this node, depending on its type; see the table above.
538 OUString SAL_CALL
CNode::getNodeValue()
544 The Document object associated with this node.
546 Reference
< XDocument
> SAL_CALL
CNode::getOwnerDocument()
548 ::osl::MutexGuard
const g(m_rMutex
);
550 if (nullptr == m_aNodePtr
) {
553 Reference
< XDocument
> const xDoc(& GetOwnerDocument());
558 The parent of this node.
560 Reference
< XNode
> SAL_CALL
CNode::getParentNode()
562 ::osl::MutexGuard
const g(m_rMutex
);
564 if (nullptr == m_aNodePtr
) {
567 Reference
< XNode
> const xNode(
568 GetOwnerDocument().GetCNode(m_aNodePtr
->parent
).get());
573 The namespace prefix of this node, or null if it is unspecified.
575 OUString SAL_CALL
CNode::getPrefix()
577 ::osl::MutexGuard
const g(m_rMutex
);
580 if (m_aNodePtr
!= nullptr &&
581 (m_aNodePtr
->type
== XML_ELEMENT_NODE
|| m_aNodePtr
->type
== XML_ATTRIBUTE_NODE
) &&
582 m_aNodePtr
->ns
!= nullptr)
584 const xmlChar
* pPrefix
= m_aNodePtr
->ns
->prefix
;
585 if( pPrefix
!= nullptr )
586 aPrefix
= OUString(reinterpret_cast<char const *>(pPrefix
), strlen(reinterpret_cast<char const *>(pPrefix
)), RTL_TEXTENCODING_UTF8
);
593 The node immediately preceding this node.
595 Reference
< XNode
> SAL_CALL
CNode::getPreviousSibling()
597 ::osl::MutexGuard
const g(m_rMutex
);
599 if (nullptr == m_aNodePtr
) {
602 Reference
< XNode
> const xNode(
603 GetOwnerDocument().GetCNode(m_aNodePtr
->prev
).get());
608 Returns whether this node (if it is an element) has any attributes.
610 sal_Bool SAL_CALL
CNode::hasAttributes()
612 ::osl::MutexGuard
const g(m_rMutex
);
614 return (m_aNodePtr
!= nullptr && m_aNodePtr
->properties
!= nullptr);
618 Returns whether this node has any children.
620 sal_Bool SAL_CALL
CNode::hasChildNodes()
622 ::osl::MutexGuard
const g(m_rMutex
);
624 return (m_aNodePtr
!= nullptr && m_aNodePtr
->children
!= nullptr);
628 Inserts the node newChild before the existing child node refChild.
630 Reference
< XNode
> SAL_CALL
CNode::insertBefore(
631 const Reference
< XNode
>& newChild
, const Reference
< XNode
>& refChild
)
633 if (!newChild
.is() || !refChild
.is()) { throw RuntimeException(); }
635 if (newChild
->getOwnerDocument() != getOwnerDocument()) {
637 e
.Code
= DOMExceptionType_WRONG_DOCUMENT_ERR
;
640 if (refChild
->getParentNode() != Reference
< XNode
>(this)) {
642 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
646 ::osl::ClearableMutexGuard
guard(m_rMutex
);
648 CNode
*const pNewNode(CNode::GetImplementation(newChild
));
649 CNode
*const pRefNode(CNode::GetImplementation(refChild
));
650 if (!pNewNode
|| !pRefNode
) { throw RuntimeException(); }
651 xmlNodePtr
const pNewChild(pNewNode
->GetNodePtr());
652 xmlNodePtr
const pRefChild(pRefNode
->GetNodePtr());
653 if (!pNewChild
|| !pRefChild
) { throw RuntimeException(); }
655 if (pNewChild
== m_aNodePtr
) {
657 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
660 // already has parent
661 if (pNewChild
->parent
!= nullptr)
664 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
667 if (!IsChildTypeAllowed(pNewNode
->m_aNodeType
)) {
669 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
673 // attributes are unordered anyway, so just do appendChild
674 if (XML_ATTRIBUTE_NODE
== pNewChild
->type
) {
676 return appendChild(newChild
);
679 xmlNodePtr cur
= m_aNodePtr
->children
;
681 //search child before which to insert
682 while (cur
!= nullptr)
684 if (cur
== pRefChild
) {
686 pNewChild
->next
= cur
;
687 pNewChild
->prev
= cur
->prev
;
688 cur
->prev
= pNewChild
;
689 if (pNewChild
->prev
!= nullptr) {
690 pNewChild
->prev
->next
= pNewChild
;
692 pNewChild
->parent
= cur
->parent
;
693 if (pNewChild
->parent
->children
== cur
) {
694 pNewChild
->parent
->children
= pNewChild
;
696 // do not update parent->last here!
697 pNewNode
->m_bUnlinked
= false; // will be deleted by xmlFreeDoc
706 Tests whether the DOM implementation implements a specific feature and
707 that feature is supported by this node.
709 sal_Bool SAL_CALL
CNode::isSupported(const OUString
& /*feature*/, const OUString
& /*ver*/)
711 OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)");
716 Puts all Text nodes in the full depth of the sub-tree underneath this
717 Node, including attribute nodes, into a "normal" form where only structure
718 (e.g., elements, comments, processing instructions, CDATA sections, and
719 entity references) separates Text nodes, i.e., there are neither adjacent
720 Text nodes nor empty Text nodes.
722 void SAL_CALL
CNode::normalize()
724 //XXX combine adjacent text nodes and remove empty ones
725 OSL_ENSURE(false, "CNode::normalize: not implemented (#i113683#)");
729 Removes the child node indicated by oldChild from the list of children,
732 Reference
< XNode
> SAL_CALL
733 CNode::removeChild(const Reference
< XNode
>& xOldChild
)
735 if (!xOldChild
.is()) {
736 throw RuntimeException();
739 if (xOldChild
->getOwnerDocument() != getOwnerDocument()) {
741 e
.Code
= DOMExceptionType_WRONG_DOCUMENT_ERR
;
744 if (xOldChild
->getParentNode() != Reference
< XNode
>(this)) {
746 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
750 ::osl::ClearableMutexGuard
guard(m_rMutex
);
752 if (!m_aNodePtr
) { throw RuntimeException(); }
754 Reference
<XNode
> xReturn( xOldChild
);
756 ::rtl::Reference
<CNode
> const pOld(CNode::GetImplementation(xOldChild
));
757 if (!pOld
.is()) { throw RuntimeException(); }
758 xmlNodePtr
const old
= pOld
->GetNodePtr();
759 if (!old
) { throw RuntimeException(); }
761 if( old
->type
== XML_ATTRIBUTE_NODE
)
763 xmlAttrPtr pAttr
= reinterpret_cast<xmlAttrPtr
>(old
);
764 xmlRemoveProp( pAttr
);
765 pOld
->invalidate(); // freed by xmlRemoveProp
771 pOld
->m_bUnlinked
= true;
775 * Fired when a node is being removed from its parent node.
776 * This event is dispatched before the node is removed from the tree.
777 * The target of this event is the node being removed.
780 * Context Info: relatedNode holds the parent node
782 Reference
< XDocumentEvent
> docevent(getOwnerDocument(), UNO_QUERY
);
783 Reference
< XMutationEvent
> event(docevent
->createEvent(
784 "DOMNodeRemoved"), UNO_QUERY
);
785 event
->initMutationEvent("DOMNodeRemoved",
789 OUString(), OUString(), OUString(), AttrChangeType(0) );
791 // the following dispatch functions use only UNO interfaces
792 // and call event listeners, so release mutex to prevent deadlocks.
795 dispatchEvent(event
);
796 // subtree modified for this node
797 dispatchSubtreeModified();
803 Replaces the child node oldChild with newChild in the list of children,
804 and returns the oldChild node.
806 Reference
< XNode
> SAL_CALL
CNode::replaceChild(
807 Reference
< XNode
> const& xNewChild
,
808 Reference
< XNode
> const& xOldChild
)
810 if (!xOldChild
.is() || !xNewChild
.is()) {
811 throw RuntimeException();
814 if (xNewChild
->getOwnerDocument() != getOwnerDocument()) {
816 e
.Code
= DOMExceptionType_WRONG_DOCUMENT_ERR
;
819 if (xOldChild
->getParentNode() != Reference
< XNode
>(this)) {
821 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
825 ::osl::ClearableMutexGuard
guard(m_rMutex
);
827 ::rtl::Reference
<CNode
> const pOldNode(
828 CNode::GetImplementation(xOldChild
));
829 ::rtl::Reference
<CNode
> const pNewNode(
830 CNode::GetImplementation(xNewChild
));
831 if (!pOldNode
.is() || !pNewNode
.is()) { throw RuntimeException(); }
832 xmlNodePtr
const pOld
= pOldNode
->GetNodePtr();
833 xmlNodePtr
const pNew
= pNewNode
->GetNodePtr();
834 if (!pOld
|| !pNew
) { throw RuntimeException(); }
836 if (pNew
== m_aNodePtr
) {
838 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
841 // already has parent
842 if (pNew
->parent
!= nullptr) {
844 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
847 if (!IsChildTypeAllowed(pNewNode
->m_aNodeType
)) {
849 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
853 if( pOld
->type
== XML_ATTRIBUTE_NODE
)
855 // can only replace attribute with attribute
856 if ( pOld
->type
!= pNew
->type
)
859 e
.Code
= DOMExceptionType_HIERARCHY_REQUEST_ERR
;
863 xmlAttrPtr pAttr
= reinterpret_cast<xmlAttrPtr
>(pOld
);
864 xmlRemoveProp( pAttr
);
865 pOldNode
->invalidate(); // freed by xmlRemoveProp
866 appendChild(xNewChild
);
871 xmlNodePtr cur
= m_aNodePtr
->children
;
872 //find old node in child list
873 while (cur
!= nullptr)
878 pNew
->prev
= pOld
->prev
;
879 if (pNew
->prev
!= nullptr)
880 pNew
->prev
->next
= pNew
;
881 pNew
->next
= pOld
->next
;
882 if (pNew
->next
!= nullptr)
883 pNew
->next
->prev
= pNew
;
884 pNew
->parent
= pOld
->parent
;
885 assert(pNew
->parent
&& "coverity[var_deref_op] pNew->parent cannot be NULL here");
886 if(pNew
->parent
->children
== pOld
)
887 pNew
->parent
->children
= pNew
;
888 if(pNew
->parent
->last
== pOld
)
889 pNew
->parent
->last
= pNew
;
890 pOld
->next
= nullptr;
891 pOld
->prev
= nullptr;
892 pOld
->parent
= nullptr;
893 pOldNode
->m_bUnlinked
= true;
894 pNewNode
->m_bUnlinked
= false; // will be deleted by xmlFreeDoc
900 guard
.clear(); // release for calling event handlers
901 dispatchSubtreeModified();
906 void CNode::dispatchSubtreeModified()
908 // only uses UNO interfaces => needs no mutex
910 // dispatch DOMSubtreeModified
911 // target is _this_ node
912 Reference
< XDocumentEvent
> docevent(getOwnerDocument(), UNO_QUERY
);
913 Reference
< XMutationEvent
> event(docevent
->createEvent(
914 "DOMSubtreeModified"), UNO_QUERY
);
915 event
->initMutationEvent(
916 "DOMSubtreeModified", true,
917 false, Reference
< XNode
>(),
918 OUString(), OUString(), OUString(), AttrChangeType(0) );
919 dispatchEvent(event
);
923 The value of this node, depending on its type; see the table above.
925 void SAL_CALL
CNode::setNodeValue(const OUString
& /*nodeValue*/)
927 // use specific node implementation
928 // if we end up down here, something went wrong
930 e
.Code
= DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR
;
935 The namespace prefix of this node, or null if it is unspecified.
937 void SAL_CALL
CNode::setPrefix(const OUString
& prefix
)
939 ::osl::MutexGuard
const g(m_rMutex
);
941 if ((nullptr == m_aNodePtr
) ||
942 ((m_aNodePtr
->type
!= XML_ELEMENT_NODE
) &&
943 (m_aNodePtr
->type
!= XML_ATTRIBUTE_NODE
)))
946 e
.Code
= DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR
;
949 OString o1
= OUStringToOString(prefix
, RTL_TEXTENCODING_UTF8
);
950 xmlChar
const *pBuf
= reinterpret_cast<xmlChar
const *>(o1
.getStr());
951 if (m_aNodePtr
!= nullptr && m_aNodePtr
->ns
!= nullptr)
953 xmlFree(const_cast<xmlChar
*>(m_aNodePtr
->ns
->prefix
));
954 m_aNodePtr
->ns
->prefix
= xmlStrdup(pBuf
);
960 void SAL_CALL
CNode::addEventListener(const OUString
& eventType
,
961 const Reference
< css::xml::dom::events::XEventListener
>& listener
,
964 ::osl::MutexGuard
const g(m_rMutex
);
966 CDocument
& rDocument(GetOwnerDocument());
967 events::CEventDispatcher
& rDispatcher(rDocument
.GetEventDispatcher());
968 rDispatcher
.addListener(m_aNodePtr
, eventType
, listener
, useCapture
);
971 void SAL_CALL
CNode::removeEventListener(const OUString
& eventType
,
972 const Reference
< css::xml::dom::events::XEventListener
>& listener
,
975 ::osl::MutexGuard
const g(m_rMutex
);
977 CDocument
& rDocument(GetOwnerDocument());
978 events::CEventDispatcher
& rDispatcher(rDocument
.GetEventDispatcher());
979 rDispatcher
.removeListener(m_aNodePtr
, eventType
, listener
, useCapture
);
982 sal_Bool SAL_CALL
CNode::dispatchEvent(const Reference
< XEvent
>& evt
)
984 CDocument
* pDocument
;
985 events::CEventDispatcher
* pDispatcher
;
988 ::osl::MutexGuard
const g(m_rMutex
);
990 pDocument
= & GetOwnerDocument();
991 pDispatcher
= & pDocument
->GetEventDispatcher();
994 // this calls event listeners, do not call with locked mutex
995 pDispatcher
->dispatchEvent(*pDocument
, m_rMutex
, pNode
, this, evt
);
1000 CNode::getSomething(Sequence
< ::sal_Int8
> const& rId
)
1002 if ((rId
.getLength() == 16) &&
1003 (0 == memcmp(theCNodeUnoTunnelId::get().getSeq().getConstArray(),
1004 rId
.getConstArray(), 16)))
1006 return ::sal::static_int_cast
< sal_Int64
>(
1007 reinterpret_cast< sal_IntPtr
>(this) );
1013 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */