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