LCOV - code coverage report
Current view: top level - unoxml/source/dom - node.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 381 451 84.5 %
Date: 2015-06-13 12:38:46 Functions: 44 48 91.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11