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.cxx796
1 files changed, 420 insertions, 376 deletions
diff --git a/unoxml/source/dom/node.cxx b/unoxml/source/dom/node.cxx
index d4b317b425b3..fb95fa6ade02 100644
--- a/unoxml/source/dom/node.cxx
+++ b/unoxml/source/dom/node.cxx
@@ -25,35 +25,47 @@
*
************************************************************************/
+#include <node.hxx>
+
#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 <libxml/xmlstring.h>
+
+#include <algorithm>
+
+#include <boost/bind.hpp>
+
+#include <rtl/uuid.h>
+#include <rtl/instance.hxx>
+#include <osl/mutex.hxx>
#include <com/sun/star/xml/sax/FastToken.hpp>
-#include "rtl/instance.hxx"
-#include "osl/mutex.hxx"
+
+#include <document.hxx>
+#include <attr.hxx>
+#include <childlist.hxx>
+
#include "../events/eventdispatcher.hxx"
#include "../events/mutationevent.hxx"
-#include <boost/bind.hpp>
-#include <algorithm>
+
+
+using namespace ::com::sun::star;
+
namespace {
-//see CNode::remove
- struct NodeMutex: public ::rtl::Static<osl::Mutex, NodeMutex> {};
+ struct UnoTunnelId
+ : public ::rtl::StaticWithInit< Sequence<sal_Int8>, UnoTunnelId >
+ {
+ Sequence<sal_Int8> operator() ()
+ {
+ Sequence<sal_Int8> ret(16);
+ rtl_createUuid(
+ reinterpret_cast<sal_uInt8*>(ret.getArray()), 0, sal_True);
+ return ret;
+ }
+ };
}
namespace DOM
@@ -133,160 +145,64 @@ namespace DOM
}
- nodemap_t CNode::theNodeMap;
-
- void CNode::remove(const xmlNodePtr aNode)
+ CNode::CNode(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ NodeType const& reNodeType, xmlNodePtr const& rpNode)
+ : m_bUnlinked(false)
+ , m_aNodeType(reNodeType)
+ , m_aNodePtr(rpNode)
+ // keep containing document alive
+ // (but not if this is a document; that would create a leak!)
+ , m_xDocument( (m_aNodePtr->type != XML_DOCUMENT_NODE)
+ ? &const_cast<CDocument&>(rDocument) : 0 )
+ , m_rMutex(const_cast< ::osl::Mutex & >(rMutex))
{
- //Using the guard here protects against races when at the same time
- //CNode::get() is called. This fix helps in many cases but is still
- //incorrect. remove is called from ~CNode. That is, while the object
- //is being destructed it can still be obtained by calling CNode::get().
- //Another bug currently prevents the correct destruction of CNodes. So
- //the destructor is rarely called.
- //
- //Doing this right would probably mean to store WeakReferences in the
- //map and also guard oder functions. To keep the risk at a minimum
- //we keep this imperfect fix for the upcoming release and fix it later
- //properly (http://qa.openoffice.org/issues/show_bug.cgi?id=113682)
- ::osl::MutexGuard guard(NodeMutex::get());
- nodemap_t::iterator i = CNode::theNodeMap.find(aNode);
- if (i != CNode::theNodeMap.end())
- {
- // CNode *pNode = i->second;
- CNode::theNodeMap.erase(i);
- }
+ OSL_ASSERT(m_aNodePtr);
}
-
- CNode* CNode::get(const xmlNodePtr aNode, sal_Bool bCreate)
+ void CNode::invalidate()
{
- CNode* pNode = 0;
- if (aNode == NULL)
- return 0;
- //see CNode::remove
- ::osl::MutexGuard guard(NodeMutex::get());
- //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;
- // unsupported 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)
- {
- // if insertion failed, delete the new instance and return null
- delete pNode;
- pNode = 0;
- }
- }
+ //remove from list if this wrapper goes away
+ if (m_aNodePtr != 0 && m_xDocument.is()) {
+ m_xDocument->RemoveCNode(m_aNodePtr, this);
+ }
+ // #i113663#: unlinked nodes will not be freed by xmlFreeDoc
+ if (m_bUnlinked) {
+ xmlFreeNode(m_aNodePtr);
}
- OSL_ENSURE(pNode, "no node produced during CNode::get!");
- return pNode;
+ m_aNodePtr = 0;
}
- xmlNodePtr CNode::getNodePtr(const Reference< XNode >& aNode)
+ CNode::~CNode()
{
- try {
- CNode* pNode=dynamic_cast<CNode*>(aNode.get());
- if( pNode )
- return pNode->m_aNodePtr;
- }
- catch(...) {}
- return 0;
+ // if this is the document itself, the mutex is already freed!
+ if (NodeType_DOCUMENT_NODE == m_aNodeType) {
+ invalidate();
+ } else {
+ ::osl::MutexGuard const g(m_rMutex);
+ invalidate(); // other nodes are still alive so must lock mutex
+ }
}
- CNode::CNode()
- : m_aNodePtr(0)
+ CNode *
+ CNode::GetImplementation(uno::Reference<uno::XInterface> const& xNode)
{
+ uno::Reference<lang::XUnoTunnel> const xUnoTunnel(xNode, UNO_QUERY);
+ if (!xUnoTunnel.is()) { return 0; }
+ CNode *const pCNode( reinterpret_cast< CNode* >(
+ ::sal::static_int_cast< sal_IntPtr >(
+ xUnoTunnel->getSomething(UnoTunnelId::get()))));
+ return pCNode;
}
- void CNode::init_node(const xmlNodePtr aNode)
+ CDocument & CNode::GetOwnerDocument()
{
- m_aNodePtr = aNode;
-
- // keep containing document alive
- // (if we are not that document ourselves)
- if (m_aNodePtr->type != XML_DOCUMENT_NODE)
- m_rDocument = getOwnerDocument();
+ OSL_ASSERT(m_xDocument.is());
+ return *m_xDocument; // needs overriding in CDocument!
}
- 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)
+ static void lcl_nsexchange(
+ xmlNodePtr const aNode, xmlNsPtr const oldNs, xmlNsPtr const newNs)
{
// recursively exchange any references to oldNs with references to newNs
xmlNodePtr cur = aNode;
@@ -303,13 +219,13 @@ namespace DOM
curAttr->ns = newNs;
curAttr = curAttr->next;
}
- _nsexchange(cur->children, oldNs, newNs);
+ lcl_nsexchange(cur->children, oldNs, newNs);
}
cur = cur->next;
}
}
- /*static*/ void _nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
+ /*static*/ void nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
{
xmlNodePtr cur = aNode;
@@ -331,7 +247,7 @@ namespace DOM
while (cur != NULL)
{
- _nscleanup(cur->children, cur);
+ nscleanup(cur->children, cur);
if (cur->ns != NULL)
{
xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
@@ -346,7 +262,7 @@ namespace DOM
{
// reconnect ns pointers in sub-tree to newly found ns before
// removing redundant nsdecl to prevent dangling pointers.
- _nsexchange(cur, curDef, ns);
+ lcl_nsexchange(cur, curDef, ns);
*refp = curDef->next;
xmlFreeNs(curDef);
curDef = *refp;
@@ -361,184 +277,187 @@ namespace DOM
}
}
- void SAL_CALL CNode::saxify(
- const Reference< XDocumentHandler >& i_xHandler) {
+ void CNode::saxify(const Reference< XDocumentHandler >& i_xHandler)
+ {
if (!i_xHandler.is()) throw RuntimeException();
// default: do nothing
}
- void SAL_CALL CNode::fastSaxify(Context& io_rContext) {
+ void CNode::fastSaxify(Context& io_rContext)
+ {
if (!io_rContext.mxDocHandler.is()) throw RuntimeException();
// default: do nothing
}
+ bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/)
+ {
+ // default: no children allowed
+ return false;
+ }
+
/**
Adds the node newChild to the end of the list of children of this node.
*/
- Reference< XNode > CNode::appendChild(const Reference< XNode >& newChild)
+ Reference< XNode > SAL_CALL CNode::appendChild(
+ Reference< XNode > const& xNewChild)
throw (RuntimeException, DOMException)
{
- Reference< XNode> aNode;
- if (m_aNodePtr != NULL) {
- xmlNodePtr cur = CNode::getNodePtr(newChild.get());
+ ::osl::ClearableMutexGuard guard(m_rMutex);
- // 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;
- }
+ if (0 == m_aNodePtr) { return 0; }
- // 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);
+ CNode *const pNewChild(CNode::GetImplementation(xNewChild));
+ if (!pNewChild) { throw RuntimeException(); }
+ xmlNodePtr const cur = pNewChild->GetNodePtr();
+ if (!cur) { throw RuntimeException(); }
- if (cur->children != NULL)
- res = (xmlNodePtr)xmlNewNsProp(m_aNodePtr, pParentNs, cur->name, cur->children->content);
- else
- res = (xmlNodePtr)xmlNewProp(m_aNodePtr, cur->name, (xmlChar*) "");
+ // 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;
+ }
+ if (cur->parent != NULL) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewChild->m_aNodeType)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
- 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);
+ // check whether this is an attribute node; it needs special handling
+ xmlNodePtr res = NULL;
+ if (cur->type == XML_ATTRIBUTE_NODE)
+ {
+ xmlChar const*const pChildren((cur->children)
+ ? cur->children->content
+ : reinterpret_cast<xmlChar const*>(""));
+ CAttr *const pCAttr(dynamic_cast<CAttr *>(pNewChild));
+ if (!pCAttr) { throw RuntimeException(); }
+ xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
+ if (pNs) {
+ res = reinterpret_cast<xmlNodePtr>(
+ xmlNewNsProp(m_aNodePtr, pNs, cur->name, pChildren));
+ } else {
+ res = reinterpret_cast<xmlNodePtr>(
+ xmlNewProp(m_aNodePtr, cur->name, pChildren));
}
+ }
+ else
+ {
+ res = xmlAddChild(m_aNodePtr, cur);
- // libxml can do optimizations, when appending nodes.
+ // libxml can do optimization when appending nodes.
// if res != cur, something was optimized and the newchild-wrapper
// should be updated
- if (cur != res)
- CNode::remove(cur);
+ if (res && (cur != res)) {
+ pNewChild->invalidate(); // cur has been freed
+ }
+ }
+
+ if (!res) { return 0; }
- // use custom ns cleanup instaead of
- // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
+ // use custom ns cleanup instead of
+ // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
// because that will not remove unneeded ns decls
- _nscleanup(res, m_aNodePtr);
+ nscleanup(res, m_aNodePtr);
- aNode = Reference< XNode>(CNode::get(res));
- }
- //XXX check for errors
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res);
+
+ if (!pNode.is()) { return 0; }
// 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));
+ pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
+ 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,
+ this,
+ OUString(), OUString(), OUString(), (AttrChangeType)0 );
- // dispatch subtree modified for this node
- dispatchSubtreeModified();
- }
- return aNode;
+ // the following dispatch functions use only UNO interfaces
+ // and call event listeners, so release mutex to prevent deadlocks.
+ guard.clear();
+
+ dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
+ // dispatch subtree modified for this node
+ dispatchSubtreeModified();
+
+ return pNode.get();
}
/**
Returns a duplicate of this node, i.e., serves as a generic copy
constructor for nodes.
*/
- Reference< XNode > CNode::cloneNode(sal_Bool bDeep)
+ Reference< XNode > SAL_CALL 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))
- ));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- //XXX check for errors
- return aNode;
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
+ xmlCopyNode(m_aNodePtr, (bDeep) ? 1 : 0));
+ if (!pNode.is()) { return 0; }
+ pNode->m_bUnlinked = true; // not linked yet
+ return pNode.get();
}
/**
A NamedNodeMap containing the attributes of this node (if it is an Element)
or null otherwise.
*/
- Reference< XNamedNodeMap > CNode::getAttributes()
+ Reference< XNamedNodeMap > SAL_CALL CNode::getAttributes()
throw (RuntimeException)
{
- // return empty reference
- // only element node may override this impl
+ // 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()
+ Reference< XNodeList > SAL_CALL CNode::getChildNodes()
throw (RuntimeException)
{
- Reference< XNodeList > aNodeList;
- if (m_aNodePtr != NULL)
- {
- aNodeList = Reference< XNodeList >(new CChildList(CNode::get(m_aNodePtr)));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- // XXX check for errors?
- return aNodeList;
+ Reference< XNodeList > const xNodeList(new CChildList(this, m_rMutex));
+ return xNodeList;
}
/**
The first child of this node.
*/
- Reference< XNode > CNode::getFirstChild()
+ Reference< XNode > SAL_CALL CNode::getFirstChild()
throw (RuntimeException)
{
- Reference< XNode > aNode;
- if (m_aNodePtr != NULL) {
- aNode = Reference< XNode >(CNode::get(m_aNodePtr->children));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- return aNode;
+ Reference< XNode > const xNode(
+ GetOwnerDocument().GetCNode(m_aNodePtr->children).get());
+ return xNode;
}
/**
@@ -547,11 +466,14 @@ namespace DOM
Reference< XNode > SAL_CALL CNode::getLastChild()
throw (RuntimeException)
{
- Reference< XNode > aNode;
- if (m_aNodePtr != NULL) {
- aNode = Reference< XNode >(CNode::get(xmlGetLastChild(m_aNodePtr)));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- return aNode;
+ Reference< XNode > const xNode(
+ GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr)).get());
+ return xNode;
}
/**
@@ -560,17 +482,8 @@ namespace DOM
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;
+ // see CElement/CAttr
+ return ::rtl::OUString();
}
@@ -580,6 +493,8 @@ namespace DOM
OUString SAL_CALL CNode::getNamespaceURI()
throw (RuntimeException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
OUString aURI;
if (m_aNodePtr != NULL &&
(m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
@@ -597,12 +512,14 @@ namespace DOM
Reference< XNode > SAL_CALL CNode::getNextSibling()
throw (RuntimeException)
{
- Reference< XNode > aNode;
- if(m_aNodePtr != NULL)
- {
- aNode = Reference< XNode >(CNode::get(m_aNodePtr->next));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- return aNode;
+ Reference< XNode > const xNode(
+ GetOwnerDocument().GetCNode(m_aNodePtr->next).get());
+ return xNode;
}
/**
@@ -639,6 +556,8 @@ namespace DOM
NodeType SAL_CALL CNode::getNodeType()
throw (RuntimeException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
return m_aNodeType;
}
@@ -658,14 +577,13 @@ namespace DOM
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;
+ ::osl::MutexGuard const g(m_rMutex);
+ if (0 == m_aNodePtr) {
+ return 0;
+ }
+ Reference< XDocument > const xDoc(& GetOwnerDocument());
+ return xDoc;
}
/**
@@ -674,12 +592,14 @@ namespace DOM
Reference< XNode > SAL_CALL CNode::getParentNode()
throw (RuntimeException)
{
- Reference<XNode> aNode;
- if (m_aNodePtr != NULL)
- {
- aNode = Reference< XNode >(CNode::get(m_aNodePtr->parent));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- return aNode;
+ Reference< XNode > const xNode(
+ GetOwnerDocument().GetCNode(m_aNodePtr->parent).get());
+ return xNode;
}
/**
@@ -688,6 +608,8 @@ namespace DOM
OUString SAL_CALL CNode::getPrefix()
throw (RuntimeException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
OUString aPrefix;
if (m_aNodePtr != NULL &&
(m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
@@ -707,12 +629,14 @@ namespace DOM
Reference< XNode > SAL_CALL CNode::getPreviousSibling()
throw (RuntimeException)
{
- Reference< XNode > aNode;
- if (m_aNodePtr != NULL)
- {
- aNode = Reference< XNode >(CNode::get(m_aNodePtr->prev));
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (0 == m_aNodePtr) {
+ return 0;
}
- return aNode;
+ Reference< XNode > const xNode(
+ GetOwnerDocument().GetCNode(m_aNodePtr->prev).get());
+ return xNode;
}
/**
@@ -721,6 +645,8 @@ namespace DOM
sal_Bool SAL_CALL CNode::hasAttributes()
throw (RuntimeException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
return (m_aNodePtr != NULL && m_aNodePtr->properties != NULL);
}
@@ -730,6 +656,8 @@ namespace DOM
sal_Bool SAL_CALL CNode::hasChildNodes()
throw (RuntimeException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
return (m_aNodePtr != NULL && m_aNodePtr->children != NULL);
}
@@ -740,6 +668,7 @@ namespace DOM
const Reference< XNode >& newChild, const Reference< XNode >& refChild)
throw (RuntimeException, DOMException)
{
+ if (!newChild.is() || !refChild.is()) { throw RuntimeException(); }
if (newChild->getOwnerDocument() != getOwnerDocument()) {
DOMException e;
@@ -752,11 +681,42 @@ namespace DOM
throw e;
}
- xmlNodePtr pRefChild = CNode::getNodePtr(refChild.get());
- xmlNodePtr pNewChild = CNode::getNodePtr(newChild.get());
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ CNode *const pNewNode(CNode::GetImplementation(newChild));
+ CNode *const pRefNode(CNode::GetImplementation(refChild));
+ if (!pNewNode || !pRefNode) { throw RuntimeException(); }
+ xmlNodePtr const pNewChild(pNewNode->GetNodePtr());
+ xmlNodePtr const pRefChild(pRefNode->GetNodePtr());
+ if (!pNewChild || !pRefChild) { throw RuntimeException(); }
+
+ if (pNewChild == m_aNodePtr) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ // already has parent
+ if (pNewChild->parent != NULL)
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ // attributes are unordered anyway, so just do appendChild
+ if (XML_ATTRIBUTE_NODE == pNewChild->type) {
+ guard.clear();
+ return appendChild(newChild);
+ }
+
xmlNodePtr cur = m_aNodePtr->children;
- //search cild before which to insert
+ //search child before which to insert
while (cur != NULL)
{
if (cur == pRefChild) {
@@ -764,8 +724,16 @@ namespace DOM
pNewChild->next = cur;
pNewChild->prev = cur->prev;
cur->prev = pNewChild;
- if( pNewChild->prev != NULL)
+ if (pNewChild->prev != NULL) {
pNewChild->prev->next = pNewChild;
+ }
+ pNewChild->parent = cur->parent;
+ if (pNewChild->parent->children == cur) {
+ pNewChild->parent->children = pNewChild;
+ }
+ // do not update parent->last here!
+ pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
+ break;
}
cur = cur->next;
}
@@ -779,7 +747,7 @@ namespace DOM
sal_Bool SAL_CALL CNode::isSupported(const OUString& /*feature*/, const OUString& /*ver*/)
throw (RuntimeException)
{
- // XXX
+ OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)");
return sal_False;
}
@@ -794,58 +762,54 @@ namespace DOM
throw (RuntimeException)
{
//XXX combine adjacent text nodes and remove empty ones
+ OSL_ENSURE(false, "CNode::normalize: not implemented (#i113683#)");
}
/**
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)
+ Reference< XNode > SAL_CALL
+ CNode::removeChild(const Reference< XNode >& xOldChild)
throw (RuntimeException, DOMException)
{
+ if (!xOldChild.is()) {
+ throw RuntimeException();
+ }
- if (oldChild->getParentNode() != Reference< XNode >(this)) {
+ if (xOldChild->getOwnerDocument() != getOwnerDocument()) {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+ if (xOldChild->getParentNode() != Reference< XNode >(this)) {
DOMException e;
e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
throw e;
}
- Reference<XNode> xReturn( oldChild );
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (!m_aNodePtr) { throw RuntimeException(); }
- xmlNodePtr old = CNode::getNodePtr(oldChild);
+ Reference<XNode> xReturn( xOldChild );
+
+ ::rtl::Reference<CNode> const pOld(CNode::GetImplementation(xOldChild));
+ if (!pOld.is()) { throw RuntimeException(); }
+ xmlNodePtr const old = pOld->GetNodePtr();
+ if (!old) { throw RuntimeException(); }
if( old->type == XML_ATTRIBUTE_NODE )
{
- xmlAttrPtr pAttr = (xmlAttrPtr) old;
+ xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(old);
xmlRemoveProp( pAttr );
+ pOld->invalidate(); // freed by xmlRemoveProp
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;
- }
+ xmlUnlinkNode(old);
+ pOld->m_bUnlinked = true;
}
/*DOMNodeRemoved
@@ -856,19 +820,23 @@ namespace DOM
* 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));
+ 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,
+ this,
+ OUString(), OUString(), OUString(), (AttrChangeType)0 );
+
+ // the following dispatch functions use only UNO interfaces
+ // and call event listeners, so release mutex to prevent deadlocks.
+ guard.clear();
+
+ dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
+ // subtree modified for this node
+ dispatchSubtreeModified();
- // subtree modofied for this node
- dispatchSubtreeModified();
- }
return xReturn;
}
@@ -877,23 +845,56 @@ namespace DOM
and returns the oldChild node.
*/
Reference< XNode > SAL_CALL CNode::replaceChild(
- const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
+ Reference< XNode > const& xNewChild,
+ Reference< XNode > const& xOldChild)
throw (RuntimeException, DOMException)
{
- // XXX check node types
+ if (!xOldChild.is() || !xNewChild.is()) {
+ throw RuntimeException();
+ }
- if (oldChild->getParentNode() != Reference< XNode >(this)) {
+ if (xNewChild->getOwnerDocument() != getOwnerDocument()) {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+ if (xOldChild->getParentNode() != Reference< XNode >(this)) {
DOMException e;
e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
throw e;
}
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
/*
Reference< XNode > aNode = removeChild(oldChild);
appendChild(newChild);
*/
- xmlNodePtr pOld = CNode::getNodePtr(oldChild);
- xmlNodePtr pNew = CNode::getNodePtr(newChild);
+ ::rtl::Reference<CNode> const pOldNode(
+ CNode::GetImplementation(xOldChild));
+ ::rtl::Reference<CNode> const pNewNode(
+ CNode::GetImplementation(xNewChild));
+ if (!pOldNode.is() || !pNewNode.is()) { throw RuntimeException(); }
+ xmlNodePtr const pOld = pOldNode->GetNodePtr();
+ xmlNodePtr const pNew = pNewNode->GetNodePtr();
+ if (!pOld || !pNew) { throw RuntimeException(); }
+
+ if (pNew == m_aNodePtr) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ // already has parent
+ if (pNew->parent != NULL) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewNode->m_aNodeType)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
if( pOld->type == XML_ATTRIBUTE_NODE )
{
@@ -907,7 +908,8 @@ namespace DOM
xmlAttrPtr pAttr = (xmlAttrPtr)pOld;
xmlRemoveProp( pAttr );
- appendChild( newChild );
+ pOldNode->invalidate(); // freed by xmlRemoveProp
+ appendChild(xNewChild);
}
else
{
@@ -933,24 +935,30 @@ namespace DOM
pOld->next = NULL;
pOld->prev = NULL;
pOld->parent = NULL;
+ pOldNode->m_bUnlinked = true;
+ pNewNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
}
cur = cur->next;
}
}
+ guard.clear(); // release for calling event handlers
dispatchSubtreeModified();
- return oldChild;
+ return xOldChild;
}
void CNode::dispatchSubtreeModified()
{
+ // only uses UNO interfaces => needs no mutex
+
// 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,
+ event->initMutationEvent(
+ OUString::createFromAscii("DOMSubtreeModified"), sal_True,
sal_False, Reference< XNode >(),
OUString(), OUString(), OUString(), (AttrChangeType)0 );
dispatchEvent(Reference< XEvent >(event, UNO_QUERY));
@@ -959,7 +967,7 @@ namespace DOM
/**
The value of this node, depending on its type; see the table above.
*/
- void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
+ void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
throw (RuntimeException, DOMException)
{
// use specific node implememntation
@@ -975,13 +983,22 @@ namespace DOM
void SAL_CALL CNode::setPrefix(const OUString& prefix)
throw (RuntimeException, DOMException)
{
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if ((0 == m_aNodePtr) ||
+ ((m_aNodePtr->type != XML_ELEMENT_NODE) &&
+ (m_aNodePtr->type != XML_ATTRIBUTE_NODE)))
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_NO_MODIFICATION_ALLOWED_ERR;
+ throw e;
+ }
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;
+ xmlFree(const_cast<xmlChar *>(m_aNodePtr->ns->prefix));
+ m_aNodePtr->ns->prefix = xmlStrdup(pBuf);
}
}
@@ -992,7 +1009,11 @@ namespace DOM
sal_Bool useCapture)
throw (RuntimeException)
{
- events::CEventDispatcher::addListener(m_aNodePtr, eventType, listener, useCapture);
+ ::osl::MutexGuard const g(m_rMutex);
+
+ CDocument & rDocument(GetOwnerDocument());
+ events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher());
+ rDispatcher.addListener(m_aNodePtr, eventType, listener, useCapture);
}
void SAL_CALL CNode::removeEventListener(const OUString& eventType,
@@ -1000,20 +1021,43 @@ namespace DOM
sal_Bool useCapture)
throw (RuntimeException)
{
- events::CEventDispatcher::removeListener(m_aNodePtr, eventType, listener, useCapture);
+ ::osl::MutexGuard const g(m_rMutex);
+
+ CDocument & rDocument(GetOwnerDocument());
+ events::CEventDispatcher & rDispatcher(rDocument.GetEventDispatcher());
+ rDispatcher.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);
+ CDocument * pDocument;
+ events::CEventDispatcher * pDispatcher;
+ xmlNodePtr pNode;
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ pDocument = & GetOwnerDocument();
+ pDispatcher = & pDocument->GetEventDispatcher();
+ pNode = m_aNodePtr;
+ }
+ // this calls event listeners, do not call with locked mutex
+ pDispatcher->dispatchEvent(*pDocument, m_rMutex, pNode, this, evt);
return sal_True;
}
- ::sal_Int64 SAL_CALL CNode::getSomething(const Sequence< ::sal_Int8 >& /*aIdentifier*/)
+ ::sal_Int64 SAL_CALL
+ CNode::getSomething(Sequence< ::sal_Int8 > const& rId)
throw (RuntimeException)
{
- return sal::static_int_cast<sal_Int64>(reinterpret_cast<sal_IntPtr>(m_aNodePtr));
+ if ((rId.getLength() == 16) &&
+ (0 == rtl_compareMemory(UnoTunnelId::get().getConstArray(),
+ rId.getConstArray(), 16)))
+ {
+ return ::sal::static_int_cast< sal_Int64 >(
+ reinterpret_cast< sal_IntPtr >(this) );
+ }
+ return 0;
}
}