xref: /trunk/main/unoxml/source/dom/node.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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