summaryrefslogtreecommitdiff
path: root/unoxml/source/dom/node.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'unoxml/source/dom/node.cxx')
-rw-r--r--unoxml/source/dom/node.cxx1008
1 files changed, 1008 insertions, 0 deletions
diff --git a/unoxml/source/dom/node.cxx b/unoxml/source/dom/node.cxx
new file mode 100644
index 000000000000..2a03896502a9
--- /dev/null
+++ b/unoxml/source/dom/node.cxx
@@ -0,0 +1,1008 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "node.hxx"
+#include "element.hxx"
+#include "text.hxx"
+#include "cdatasection.hxx"
+#include "entityreference.hxx"
+#include "entity.hxx"
+#include "processinginstruction.hxx"
+#include "comment.hxx"
+#include "document.hxx"
+#include "documenttype.hxx"
+#include "documentfragment.hxx"
+#include "notation.hxx"
+#include "childlist.hxx"
+#include "attr.hxx"
+
+#include <com/sun/star/xml/sax/FastToken.hpp>
+
+#include "../events/eventdispatcher.hxx"
+#include "../events/mutationevent.hxx"
+
+#include <boost/bind.hpp>
+#include <algorithm>
+
+namespace DOM
+{
+ void pushContext(Context& io_rContext)
+ {
+ io_rContext.maNamespaces.push_back(
+ io_rContext.maNamespaces.back());
+ }
+
+ void popContext(Context& io_rContext)
+ {
+ io_rContext.maNamespaces.pop_back();
+ }
+
+ void addNamespaces(Context& io_rContext, xmlNodePtr pNode)
+ {
+ // add node's namespaces to current context
+ for (xmlNsPtr pNs = pNode->nsDef; pNs != 0; pNs = pNs->next) {
+ const xmlChar *pPrefix = pNs->prefix;
+ OString prefix(reinterpret_cast<const sal_Char*>(pPrefix),
+ strlen(reinterpret_cast<const char*>(pPrefix)));
+ const xmlChar *pHref = pNs->href;
+ OUString val(reinterpret_cast<const sal_Char*>(pHref),
+ strlen(reinterpret_cast<const char*>(pHref)),
+ RTL_TEXTENCODING_UTF8);
+
+ OSL_TRACE("Trying to add namespace %s (prefix %s)",
+ (const char*)pHref, (const char*)pPrefix);
+
+ Context::NamespaceMapType::iterator aIter=
+ io_rContext.maNamespaceMap.find(val);
+ if( aIter != io_rContext.maNamespaceMap.end() )
+ {
+ Context::Namespace aNS;
+ aNS.maPrefix = prefix;
+ aNS.mnToken = aIter->second;
+ aNS.maNamespaceURL = val;
+
+ io_rContext.maNamespaces.back().push_back(aNS);
+
+ OSL_TRACE("Added with token 0x%x", aIter->second);
+ }
+ }
+ }
+
+ sal_Int32 getToken( const Context& rContext, const sal_Char* pToken )
+ {
+ const Sequence<sal_Int8> aSeq( (sal_Int8*)pToken, strlen( pToken ) );
+ return rContext.mxTokenHandler->getTokenFromUTF8( aSeq );
+ }
+
+ sal_Int32 getTokenWithPrefix( const Context& rContext, const sal_Char* pPrefix, const sal_Char* pName )
+ {
+ sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
+ OString prefix(pPrefix,
+ strlen(reinterpret_cast<const char*>(pPrefix)));
+
+ OSL_TRACE("getTokenWithPrefix(): prefix %s, name %s",
+ (const char*)pPrefix, (const char*)pName);
+
+ Context::NamespaceVectorType::value_type::const_iterator aIter;
+ if( (aIter=std::find_if(rContext.maNamespaces.back().begin(),
+ rContext.maNamespaces.back().end(),
+ boost::bind(std::equal_to<OString>(),
+ boost::bind(&Context::Namespace::getPrefix,
+ _1),
+ boost::cref(prefix)))) != rContext.maNamespaces.back().end() )
+ {
+ nNamespaceToken = aIter->mnToken;
+ sal_Int32 nNameToken = getToken( rContext, pName );
+ if( nNameToken != FastToken::DONTKNOW )
+ nNamespaceToken |= nNameToken;
+ }
+
+ return nNamespaceToken;
+ }
+
+
+ nodemap_t CNode::theNodeMap;
+
+ void CNode::remove(const xmlNodePtr aNode)
+ {
+ nodemap_t::iterator i = CNode::theNodeMap.find(aNode);
+ if (i != CNode::theNodeMap.end())
+ {
+ // CNode *pNode = i->second;
+ CNode::theNodeMap.erase(i);
+ }
+ }
+
+
+ CNode* CNode::get(const xmlNodePtr aNode, sal_Bool bCreate)
+ {
+ CNode* pNode = 0;
+ if (aNode == NULL)
+ return 0;
+
+ //check whether there is already an instance for this node
+ nodemap_t::const_iterator i = CNode::theNodeMap.find(aNode);
+ if (i != CNode::theNodeMap.end())
+ {
+ pNode = i->second;
+ } else
+ {
+
+ // there is not yet an instance wrapping this node,
+ // create it and store it in the map
+ if (!bCreate) return NULL;
+
+ switch (aNode->type)
+ {
+ case XML_ELEMENT_NODE:
+ // m_aNodeType = NodeType::ELEMENT_NODE;
+ pNode = static_cast< CNode* >(new CElement(aNode));
+ break;
+ case XML_TEXT_NODE:
+ // m_aNodeType = NodeType::TEXT_NODE;
+ pNode = static_cast< CNode* >(new CText(aNode));
+ break;
+ case XML_CDATA_SECTION_NODE:
+ // m_aNodeType = NodeType::CDATA_SECTION_NODE;
+ pNode = static_cast< CNode* >(new CCDATASection(aNode));
+ break;
+ case XML_ENTITY_REF_NODE:
+ // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
+ pNode = static_cast< CNode* >(new CEntityReference(aNode));
+ break;
+ case XML_ENTITY_NODE:
+ // m_aNodeType = NodeType::ENTITY_NODE;
+ pNode = static_cast< CNode* >(new CEntity((xmlEntityPtr)aNode));
+ break;
+ case XML_PI_NODE:
+ // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
+ pNode = static_cast< CNode* >(new CProcessingInstruction(aNode));
+ break;
+ case XML_COMMENT_NODE:
+ // m_aNodeType = NodeType::COMMENT_NODE;
+ pNode = static_cast< CNode* >(new CComment(aNode));
+ break;
+ case XML_DOCUMENT_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_NODE;
+ pNode = static_cast< CNode* >(new CDocument((xmlDocPtr)aNode));
+ break;
+ case XML_DOCUMENT_TYPE_NODE:
+ case XML_DTD_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
+ pNode = static_cast< CNode* >(new CDocumentType((xmlDtdPtr)aNode));
+ break;
+ case XML_DOCUMENT_FRAG_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
+ pNode = static_cast< CNode* >(new CDocumentFragment(aNode));
+ break;
+ case XML_NOTATION_NODE:
+ // m_aNodeType = NodeType::NOTATION_NODE;
+ pNode = static_cast< CNode* >(new CNotation((xmlNotationPtr)aNode));
+ break;
+ case XML_ATTRIBUTE_NODE:
+ // m_aNodeType = NodeType::NOTATION_NODE;
+ pNode = static_cast< CNode* >(new CAttr((xmlAttrPtr)aNode));
+ break;
+ // unsopported node types
+ case XML_HTML_DOCUMENT_NODE:
+ case XML_ELEMENT_DECL:
+ case XML_ATTRIBUTE_DECL:
+ case XML_ENTITY_DECL:
+ case XML_NAMESPACE_DECL:
+ default:
+ pNode = 0;
+ break;
+ }
+ }
+ if ( pNode != 0 )
+ {
+ if(CNode::theNodeMap.insert(nodemap_t::value_type(aNode, pNode)).second)
+ {
+ // insertion done, register node with document
+ xmlDocPtr doc = aNode->doc;
+ if( doc != NULL)
+ {
+ CDocument* pDoc = static_cast< CDocument* >(CNode::get((xmlNodePtr)doc));
+ pDoc->addnode(aNode);
+ } else
+ {
+ // if insertion failed, delete the new instance and return null
+ delete pNode;
+ pNode = 0;
+ }
+ }
+ }
+ OSL_ENSURE(pNode, "no node produced during CNode::get!");
+ return pNode;
+ }
+
+ xmlNodePtr CNode::getNodePtr(const Reference< XNode >& aNode)
+ {
+ try {
+ CNode* pNode=dynamic_cast<CNode*>(aNode.get());
+ if( pNode )
+ return pNode->m_aNodePtr;
+ }
+ catch(...) {}
+ return 0;
+ }
+
+ CNode::CNode()
+ : m_aNodePtr(0)
+ {
+ }
+
+ void CNode::init_node(const xmlNodePtr aNode)
+ {
+ m_aNodePtr = aNode;
+
+ // keep containing document alive
+ // (if we are not that document ourselves)
+ if (m_aNodePtr->type != XML_DOCUMENT_NODE)
+ m_rDocument = getOwnerDocument();
+ }
+
+ CNode::~CNode()
+ {
+ //remove from list if this wrapper goes away
+ if (m_aNodePtr != 0)
+ CNode::remove(m_aNodePtr);
+ }
+
+ static void _nsexchange(const xmlNodePtr aNode, xmlNsPtr oldNs, xmlNsPtr newNs)
+ {
+ // recursively exchange any references to oldNs with references to newNs
+ xmlNodePtr cur = aNode;
+ while (cur != 0)
+ {
+ if (cur->ns == oldNs)
+ cur->ns = newNs;
+ if (cur->type == XML_ELEMENT_NODE)
+ {
+ xmlAttrPtr curAttr = cur->properties;
+ while(curAttr != 0)
+ {
+ if (curAttr->ns == oldNs)
+ curAttr->ns = newNs;
+ curAttr = curAttr->next;
+ }
+ _nsexchange(cur->children, oldNs, newNs);
+ }
+ cur = cur->next;
+ }
+ }
+
+ /*static*/ void _nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
+ {
+ xmlNodePtr cur = aNode;
+
+ //handle attributes
+ if (cur != NULL && cur->type == XML_ELEMENT_NODE)
+ {
+ xmlAttrPtr curAttr = cur->properties;
+ while(curAttr != 0)
+ {
+ if (curAttr->ns != NULL)
+ {
+ xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix);
+ if (ns != NULL)
+ curAttr->ns = ns;
+ }
+ curAttr = curAttr->next;
+ }
+ }
+
+ while (cur != NULL)
+ {
+ _nscleanup(cur->children, cur);
+ if (cur->ns != NULL)
+ {
+ xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
+ if (ns != NULL && ns != cur->ns && strcmp((char*)ns->href, (char*)cur->ns->href)==0)
+ {
+ xmlNsPtr curDef = cur->nsDef;
+ xmlNsPtr *refp = &(cur->nsDef); // insert point
+ while (curDef != NULL)
+ {
+ ns = xmlSearchNs(cur->doc, aParent, curDef->prefix);
+ if (ns != NULL && ns != curDef && strcmp((char*)ns->href, (char*)curDef->href)==0)
+ {
+ // reconnect ns pointers in sub-tree to newly found ns before
+ // removing redundant nsdecl to prevent dangling pointers.
+ _nsexchange(cur, curDef, ns);
+ *refp = curDef->next;
+ xmlFreeNs(curDef);
+ curDef = *refp;
+ } else {
+ refp = &(curDef->next);
+ curDef = curDef->next;
+ }
+ }
+ }
+ }
+ cur = cur->next;
+ }
+ }
+
+ void SAL_CALL CNode::saxify(
+ const Reference< XDocumentHandler >& i_xHandler) {
+ if (!i_xHandler.is()) throw RuntimeException();
+ // default: do nothing
+ }
+
+ void SAL_CALL CNode::fastSaxify(Context& io_rContext) {
+ if (!io_rContext.mxDocHandler.is()) throw RuntimeException();
+ // default: do nothing
+ }
+
+ /**
+ Adds the node newChild to the end of the list of children of this node.
+ */
+ Reference< XNode > CNode::appendChild(const Reference< XNode >& newChild)
+ throw (RuntimeException, DOMException)
+ {
+ Reference< XNode> aNode;
+ if (m_aNodePtr != NULL) {
+ xmlNodePtr cur = CNode::getNodePtr(newChild.get());
+
+ // error checks:
+ // from other document
+ if (cur->doc != m_aNodePtr->doc) {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+ // same node
+ if (cur == m_aNodePtr) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ // already has parant and is not attribute
+ if (cur->parent != NULL && cur->type != XML_ATTRIBUTE_NODE) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ // check whether this is an attribute node so we remove it's
+ // carrier node if it has one
+ xmlNodePtr res = NULL;
+ if (cur->type == XML_ATTRIBUTE_NODE)
+ {
+ if (cur->parent != NULL)
+ {
+ if (m_aNodePtr->type != XML_ELEMENT_NODE ||
+ strcmp((char*)cur->parent->name, "__private") != 0)
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ xmlNsPtr pAttrNs = cur->ns;
+ xmlNsPtr pParentNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, pAttrNs->prefix);
+ if (pParentNs == NULL || strcmp((char*)pParentNs->href, (char*)pAttrNs->href) != 0)
+ pParentNs = xmlNewNs(m_aNodePtr, pAttrNs->href, pAttrNs->prefix);
+
+ if (cur->children != NULL)
+ res = (xmlNodePtr)xmlNewNsProp(m_aNodePtr, pParentNs, cur->name, cur->children->content);
+ else
+ res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, (xmlChar*) "");
+
+ xmlFreeNode(cur->parent);
+ cur->parent = NULL;
+ }
+ else
+ {
+ if (cur->children != NULL)
+ res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, cur->children->content);
+ else
+ res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, (xmlChar*) "");
+ }
+ }
+ else
+ {
+ res = xmlAddChild(m_aNodePtr, cur);
+ }
+
+ // libxml can do optimizations, when appending nodes.
+ // if res != cur, something was optimized and the newchild-wrapper
+ // should be updated
+ if (cur != res)
+ CNode::remove(cur);
+
+ // use custom ns cleanup instaead of
+ // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
+ // because that will not remove unneeded ns decls
+ _nscleanup(res, m_aNodePtr);
+
+ aNode = Reference< XNode>(CNode::get(res));
+ }
+ //XXX check for errors
+
+ // dispatch DOMNodeInserted event, target is the new node
+ // this node is the related node
+ // does bubble
+ if (aNode.is())
+ {
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ OUString::createFromAscii("DOMNodeInserted")), UNO_QUERY);
+ event->initMutationEvent(OUString::createFromAscii("DOMNodeInserted")
+ , sal_True, sal_False, Reference< XNode >(CNode::get(m_aNodePtr)),
+ OUString(), OUString(), OUString(), (AttrChangeType)0 );
+ dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
+
+ // dispatch subtree modified for this node
+ dispatchSubtreeModified();
+ }
+ return aNode;
+ }
+
+ /**
+ Returns a duplicate of this node, i.e., serves as a generic copy
+ constructor for nodes.
+ */
+ Reference< XNode > CNode::cloneNode(sal_Bool bDeep)
+ throw (RuntimeException)
+ {
+ Reference< XNode> aNode;
+ if (m_aNodePtr != NULL)
+ {
+ aNode = Reference< XNode>(CNode::get(
+ xmlCopyNode (m_aNodePtr, static_cast< int >(bDeep))
+ ));
+ }
+ //XXX check for errors
+ return aNode;
+ }
+
+ /**
+ A NamedNodeMap containing the attributes of this node (if it is an Element)
+ or null otherwise.
+ */
+ Reference< XNamedNodeMap > CNode::getAttributes()
+ throw (RuntimeException)
+ {
+ // return empty reference
+ // only element node may override this impl
+ return Reference< XNamedNodeMap>();
+
+ // get all children that are attributes
+ /* --> CElement
+ Reference< NamedNodeMap > aNodeMap(new AttributeNamedNodeMap(m_aNodePtr), UNO_QUERY);
+ return aNodeMap;
+ */
+ }
+
+ /**
+ A NodeList that contains all children of this node.
+ */
+ Reference< XNodeList > CNode::getChildNodes()
+ throw (RuntimeException)
+ {
+ Reference< XNodeList > aNodeList;
+ if (m_aNodePtr != NULL)
+ {
+ aNodeList = Reference< XNodeList >(new CChildList(CNode::get(m_aNodePtr)));
+ }
+ // XXX check for errors?
+ return aNodeList;
+ }
+
+ /**
+ The first child of this node.
+ */
+ Reference< XNode > CNode::getFirstChild()
+ throw (RuntimeException)
+ {
+ Reference< XNode > aNode;
+ if (m_aNodePtr != NULL) {
+ aNode = Reference< XNode >(CNode::get(m_aNodePtr->children));
+ }
+ return aNode;
+ }
+
+ /**
+ The last child of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getLastChild()
+ throw (RuntimeException)
+ {
+ Reference< XNode > aNode;
+ if (m_aNodePtr != NULL) {
+ aNode = Reference< XNode >(CNode::get(xmlGetLastChild(m_aNodePtr)));
+ }
+ return aNode;
+ }
+
+ /**
+ Returns the local part of the qualified name of this node.
+ */
+ OUString SAL_CALL CNode::getLocalName()
+ throw (RuntimeException)
+ {
+ OUString aName;
+ /*
+ --> Element / Attribute
+ if(m_aNodePtr != NULL && (m_aNodeType == NodeType::ATTRIBUTE_NODE
+ || m_aNodeType == NodeType::ELEMENT_NODE))
+ {
+ aName = OUString(m_aNodePtr->name, RTL_TEXTENCODING_UTF8);
+ }
+ //XXX error checking
+ */
+ return aName;
+ }
+
+
+ /**
+ The namespace URI of this node, or null if it is unspecified.
+ */
+ OUString SAL_CALL CNode::getNamespaceURI()
+ throw (RuntimeException)
+ {
+ OUString aURI;
+ if (m_aNodePtr != NULL &&
+ (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
+ m_aNodePtr->ns != NULL)
+ {
+ const xmlChar* xHref = m_aNodePtr->ns->href;
+ aURI = OUString((sal_Char*)xHref, strlen((char*)xHref), RTL_TEXTENCODING_UTF8);
+ }
+ return aURI;
+ }
+
+ /**
+ The node immediately following this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getNextSibling()
+ throw (RuntimeException)
+ {
+ Reference< XNode > aNode;
+ if(m_aNodePtr != NULL)
+ {
+ aNode = Reference< XNode >(CNode::get(m_aNodePtr->next));
+ }
+ return aNode;
+ }
+
+ /**
+ The name of this node, depending on its type; see the table above.
+ */
+ OUString SAL_CALL CNode::getNodeName()
+ throw (RuntimeException)
+ {
+ /*
+ Interface nodeName nodeValue attributes
+ --------------------------------------------------------------------------------------
+ Attr name of attribute value of attribute null
+ CDATASection "#cdata-section" content of the CDATA Section null
+ Comment "#comment" content of the comment null
+ Document "#document" null null
+ DocumentFragment "#document-fragment" null null
+ DocumentType document type name null null
+ Element tag name null NamedNodeMap
+ Entity entity name null null
+ EntityReference name of entity null null
+ referenced
+ Notation notation name null null
+ Processing\ target entire content excluding null
+ Instruction the target
+ Text "#text" content of the text node null
+ */
+ OUString aName;
+ return aName;
+ }
+
+ /**
+ A code representing the type of the underlying object, as defined above.
+ */
+ NodeType SAL_CALL CNode::getNodeType()
+ throw (RuntimeException)
+ {
+ return m_aNodeType;
+ }
+
+ /**
+ The value of this node, depending on its type; see the table above.
+ */
+ OUString SAL_CALL CNode::getNodeValue()
+ throw (RuntimeException)
+ {
+ OUString aValue;
+ return aValue;
+ }
+
+ /**
+ The Document object associated with this node.
+ */
+ Reference< XDocument > SAL_CALL CNode::getOwnerDocument()
+ throw (RuntimeException)
+ {
+ Reference<XDocument> aDoc;
+ if (m_aNodePtr != NULL)
+ {
+ aDoc = Reference< XDocument >(static_cast< CDocument* >(
+ CNode::get((xmlNodePtr)m_aNodePtr->doc)));
+ }
+ return aDoc;
+
+ }
+
+ /**
+ The parent of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getParentNode()
+ throw (RuntimeException)
+ {
+ Reference<XNode> aNode;
+ if (m_aNodePtr != NULL)
+ {
+ aNode = Reference< XNode >(CNode::get(m_aNodePtr->parent));
+ }
+ return aNode;
+ }
+
+ /**
+ The namespace prefix of this node, or null if it is unspecified.
+ */
+ OUString SAL_CALL CNode::getPrefix()
+ throw (RuntimeException)
+ {
+ OUString aPrefix;
+ if (m_aNodePtr != NULL &&
+ (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
+ m_aNodePtr->ns != NULL)
+ {
+ const xmlChar* xPrefix = m_aNodePtr->ns->prefix;
+ if( xPrefix != NULL )
+ aPrefix = OUString((sal_Char*)xPrefix, strlen((char*)xPrefix), RTL_TEXTENCODING_UTF8);
+ }
+ return aPrefix;
+
+ }
+
+ /**
+ The node immediately preceding this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getPreviousSibling()
+ throw (RuntimeException)
+ {
+ Reference< XNode > aNode;
+ if (m_aNodePtr != NULL)
+ {
+ aNode = Reference< XNode >(CNode::get(m_aNodePtr->prev));
+ }
+ return aNode;
+ }
+
+ /**
+ Returns whether this node (if it is an element) has any attributes.
+ */
+ sal_Bool SAL_CALL CNode::hasAttributes()
+ throw (RuntimeException)
+ {
+ return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL);
+ }
+
+ /**
+ Returns whether this node has any children.
+ */
+ sal_Bool SAL_CALL CNode::hasChildNodes()
+ throw (RuntimeException)
+ {
+ return (m_aNodePtr != NULL && m_aNodePtr->children != NULL);
+ }
+
+ /**
+ Inserts the node newChild before the existing child node refChild.
+ */
+ Reference< XNode > SAL_CALL CNode::insertBefore(
+ const Reference< XNode >& newChild, const Reference< XNode >& refChild)
+ throw (RuntimeException, DOMException)
+ {
+
+ if (newChild->getOwnerDocument() != getOwnerDocument()) {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+ if (refChild->getParentNode() != Reference< XNode >(this)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ xmlNodePtr pRefChild = CNode::getNodePtr(refChild.get());
+ xmlNodePtr pNewChild = CNode::getNodePtr(newChild.get());
+ xmlNodePtr cur = m_aNodePtr->children;
+
+ //search cild before which to insert
+ while (cur != NULL)
+ {
+ if (cur == pRefChild) {
+ // insert before
+ pNewChild->next = cur;
+ pNewChild->prev = cur->prev;
+ cur->prev = pNewChild;
+ if( pNewChild->prev != NULL)
+ pNewChild->prev->next = pNewChild;
+ }
+ cur = cur->next;
+ }
+ return refChild;
+ }
+
+ /**
+ Tests whether the DOM implementation implements a specific feature and
+ that feature is supported by this node.
+ */
+ sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/)
+ throw (RuntimeException)
+ {
+ // XXX
+ return sal_False;
+ }
+
+ /**
+ Puts all Text nodes in the full depth of the sub-tree underneath this
+ Node, including attribute nodes, into a "normal" form where only structure
+ (e.g., elements, comments, processing instructions, CDATA sections, and
+ entity references) separates Text nodes, i.e., there are neither adjacent
+ Text nodes nor empty Text nodes.
+ */
+ void SAL_CALL CNode::normalize()
+ throw (RuntimeException)
+ {
+ //XXX combine adjacent text nodes and remove empty ones
+ }
+
+ /**
+ Removes the child node indicated by oldChild from the list of children,
+ and returns it.
+ */
+ Reference< XNode > SAL_CALL CNode::removeChild(const Reference< XNode >& oldChild)
+ throw (RuntimeException, DOMException)
+ {
+
+ if (oldChild->getParentNode() != Reference< XNode >(this)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ Reference<XNode> xReturn( oldChild );
+
+ xmlNodePtr old = CNode::getNodePtr(oldChild);
+
+ if( old->type == XML_ATTRIBUTE_NODE )
+ {
+ xmlAttrPtr pAttr = (xmlAttrPtr) old;
+ xmlRemoveProp( pAttr );
+ xReturn.clear();
+ }
+ else
+ {
+
+ // update .last
+ if (m_aNodePtr->last == old)
+ m_aNodePtr->last = old->prev;
+
+ xmlNodePtr cur = m_aNodePtr->children;
+ //find old node in child list
+ while (cur != NULL)
+ {
+ if(cur == old)
+ {
+ // unlink node from list
+ if (cur->prev != NULL)
+ cur->prev->next = cur->next;
+ if (cur->next != NULL)
+ cur->next->prev = cur->prev;
+ if (cur->parent != NULL && cur->parent->children == cur)
+ cur->parent->children = cur->next;
+ cur->prev = NULL;
+ cur->next = NULL;
+ cur->parent = NULL;
+ }
+ cur = cur->next;
+ }
+ }
+
+ /*DOMNodeRemoved
+ * Fired when a node is being removed from its parent node.
+ * This event is dispatched before the node is removed from the tree.
+ * The target of this event is the node being removed.
+ * Bubbles: Yes
+ * Cancelable: No
+ * Context Info: relatedNode holds the parent node
+ */
+ if (oldChild.is())
+ {
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ OUString::createFromAscii("DOMNodeRemoved")), UNO_QUERY);
+ event->initMutationEvent(OUString::createFromAscii("DOMNodeRemoved"), sal_True,
+ sal_False, Reference< XNode >(CNode::get(m_aNodePtr)),
+ OUString(), OUString(), OUString(), (AttrChangeType)0 );
+ dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
+
+ // subtree modofied for this node
+ dispatchSubtreeModified();
+ }
+ return xReturn;
+ }
+
+ /**
+ Replaces the child node oldChild with newChild in the list of children,
+ and returns the oldChild node.
+ */
+ Reference< XNode > SAL_CALL CNode::replaceChild(
+ const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
+ throw (RuntimeException, DOMException)
+ {
+ // XXX check node types
+
+ if (oldChild->getParentNode() != Reference< XNode >(this)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+/*
+ Reference< XNode > aNode = removeChild(oldChild);
+ appendChild(newChild);
+*/
+ xmlNodePtr pOld = CNode::getNodePtr(oldChild);
+ xmlNodePtr pNew = CNode::getNodePtr(newChild);
+
+ if( pOld->type == XML_ATTRIBUTE_NODE )
+ {
+ // can only replace attribute with attribute
+ if ( pOld->type != pNew->type )
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ xmlAttrPtr pAttr = (xmlAttrPtr)pOld;
+ xmlRemoveProp( pAttr );
+ appendChild( newChild );
+ }
+ else
+ {
+
+ xmlNodePtr cur = m_aNodePtr->children;
+ //find old node in child list
+ while (cur != NULL)
+ {
+ if(cur == pOld)
+ {
+ // exchange nodes
+ pNew->prev = pOld->prev;
+ if (pNew->prev != NULL)
+ pNew->prev->next = pNew;
+ pNew->next = pOld->next;
+ if (pNew->next != NULL)
+ pNew->next->prev = pNew;
+ pNew->parent = pOld->parent;
+ if(pNew->parent->children == pOld)
+ pNew->parent->children = pNew;
+ if(pNew->parent->last == pOld)
+ pNew->parent->last = pNew;
+ pOld->next = NULL;
+ pOld->prev = NULL;
+ pOld->parent = NULL;
+ }
+ cur = cur->next;
+ }
+ }
+
+ dispatchSubtreeModified();
+
+ return oldChild;
+ }
+
+ void CNode::dispatchSubtreeModified()
+ {
+ // dispatch DOMSubtreeModified
+ // target is _this_ node
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ OUString::createFromAscii("DOMSubtreeModified")), UNO_QUERY);
+ event->initMutationEvent(OUString::createFromAscii("DOMSubtreeModified"), sal_True,
+ sal_False, Reference< XNode >(),
+ OUString(), OUString(), OUString(), (AttrChangeType)0 );
+ dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
+ }
+
+ /**
+ The value of this node, depending on its type; see the table above.
+ */
+ void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
+ throw (RuntimeException, DOMException)
+ {
+ // use specific node implememntation
+ // if we end up down here, something went wrong
+ DOMException e;
+ e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR;
+ throw e;
+ }
+
+ /**
+ The namespace prefix of this node, or null if it is unspecified.
+ */
+ void SAL_CALL CNode::setPrefix(const OUString& prefix)
+ throw (RuntimeException, DOMException)
+ {
+ OString o1 = OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
+ xmlChar *pBuf = (xmlChar*)o1.getStr();
+ // XXX copy buf?
+ // XXX free old string? (leak?)
+ if (m_aNodePtr != NULL && m_aNodePtr->ns != NULL)
+ {
+ m_aNodePtr->ns->prefix = pBuf;
+ }
+
+ }
+
+ // --- XEventTarget
+ void SAL_CALL CNode::addEventListener(const OUString& eventType,
+ const Reference< com::sun::star::xml::dom::events::XEventListener >& listener,
+ sal_Bool useCapture)
+ throw (RuntimeException)
+ {
+ events::CEventDispatcher::addListener(m_aNodePtr, eventType, listener, useCapture);
+ }
+
+ void SAL_CALL CNode::removeEventListener(const OUString& eventType,
+ const Reference< com::sun::star::xml::dom::events::XEventListener >& listener,
+ sal_Bool useCapture)
+ throw (RuntimeException)
+ {
+ events::CEventDispatcher::removeListener(m_aNodePtr, eventType, listener, useCapture);
+ }
+
+ sal_Bool SAL_CALL CNode::dispatchEvent(const Reference< XEvent >& evt)
+ throw(RuntimeException, EventException)
+ {
+ events::CEventDispatcher::dispatchEvent(m_aNodePtr, evt);
+ return sal_True;
+ }
+
+ ::sal_Int64 SAL_CALL CNode::getSomething(const Sequence< ::sal_Int8 >& /*aIdentifier*/)
+ throw (RuntimeException)
+ {
+ return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(m_aNodePtr));
+ }
+}
+