summaryrefslogtreecommitdiffstats
path: root/unoxml/source
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /unoxml/source
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'unoxml/source')
-rw-r--r--unoxml/source/dom/attr.cxx268
-rw-r--r--unoxml/source/dom/attr.hxx178
-rw-r--r--unoxml/source/dom/attributesmap.cxx226
-rw-r--r--unoxml/source/dom/attributesmap.hxx95
-rw-r--r--unoxml/source/dom/cdatasection.cxx60
-rw-r--r--unoxml/source/dom/cdatasection.hxx189
-rw-r--r--unoxml/source/dom/characterdata.cxx264
-rw-r--r--unoxml/source/dom/characterdata.hxx201
-rw-r--r--unoxml/source/dom/childlist.cxx87
-rw-r--r--unoxml/source/dom/childlist.hxx59
-rw-r--r--unoxml/source/dom/comment.cxx56
-rw-r--r--unoxml/source/dom/comment.hxx183
-rw-r--r--unoxml/source/dom/document.cxx1027
-rw-r--r--unoxml/source/dom/document.hxx338
-rw-r--r--unoxml/source/dom/documentbuilder.cxx429
-rw-r--r--unoxml/source/dom/documentbuilder.hxx127
-rw-r--r--unoxml/source/dom/documentfragment.cxx60
-rw-r--r--unoxml/source/dom/documentfragment.hxx150
-rw-r--r--unoxml/source/dom/documenttype.cxx142
-rw-r--r--unoxml/source/dom/documenttype.hxx186
-rw-r--r--unoxml/source/dom/domimplementation.cxx80
-rw-r--r--unoxml/source/dom/domimplementation.hxx61
-rw-r--r--unoxml/source/dom/element.cxx756
-rw-r--r--unoxml/source/dom/element.hxx246
-rw-r--r--unoxml/source/dom/elementlist.cxx191
-rw-r--r--unoxml/source/dom/elementlist.hxx118
-rw-r--r--unoxml/source/dom/entitiesmap.cxx122
-rw-r--r--unoxml/source/dom/entitiesmap.hxx89
-rw-r--r--unoxml/source/dom/entity.cxx112
-rw-r--r--unoxml/source/dom/entity.hxx170
-rw-r--r--unoxml/source/dom/entityreference.cxx71
-rw-r--r--unoxml/source/dom/entityreference.hxx152
-rw-r--r--unoxml/source/dom/node.cxx984
-rw-r--r--unoxml/source/dom/notation.cxx75
-rw-r--r--unoxml/source/dom/notation.hxx157
-rw-r--r--unoxml/source/dom/notationsmap.cxx122
-rw-r--r--unoxml/source/dom/notationsmap.hxx89
-rw-r--r--unoxml/source/dom/processinginstruction.cxx137
-rw-r--r--unoxml/source/dom/processinginstruction.hxx165
-rw-r--r--unoxml/source/dom/saxbuilder.cxx344
-rw-r--r--unoxml/source/dom/saxbuilder.hxx92
-rw-r--r--unoxml/source/dom/text.cxx73
-rw-r--r--unoxml/source/dom/text.hxx203
-rw-r--r--unoxml/source/events/event.cxx108
-rw-r--r--unoxml/source/events/eventdispatcher.cxx251
-rw-r--r--unoxml/source/events/mouseevent.cxx194
-rw-r--r--unoxml/source/events/mutationevent.cxx137
-rw-r--r--unoxml/source/events/uievent.cxx113
-rw-r--r--unoxml/source/rdf/CBlankNode.cxx117
-rw-r--r--unoxml/source/rdf/CLiteral.cxx167
-rw-r--r--unoxml/source/rdf/CURI.cxx807
-rw-r--r--unoxml/source/rdf/librdf_repository.cxx2465
-rw-r--r--unoxml/source/rdf/unordf.component35
-rw-r--r--unoxml/source/service/unoxml.component34
-rw-r--r--unoxml/source/xpath/nodelist.cxx72
-rw-r--r--unoxml/source/xpath/nodelist.hxx70
-rw-r--r--unoxml/source/xpath/xpathapi.cxx398
-rw-r--r--unoxml/source/xpath/xpathapi.hxx107
-rw-r--r--unoxml/source/xpath/xpathobject.cxx181
-rw-r--r--unoxml/source/xpath/xpathobject.hxx109
60 files changed, 14299 insertions, 0 deletions
diff --git a/unoxml/source/dom/attr.cxx b/unoxml/source/dom/attr.cxx
new file mode 100644
index 000000000..4988aa421
--- /dev/null
+++ b/unoxml/source/dom/attr.cxx
@@ -0,0 +1,268 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "attr.hxx"
+
+#include <string.h>
+
+#include <memory>
+
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
+
+#include "document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+
+namespace DOM
+{
+ CAttr::CAttr(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlAttrPtr const pAttr)
+ : CAttr_Base(rDocument, rMutex,
+ NodeType_ATTRIBUTE_NODE, reinterpret_cast<xmlNodePtr>(pAttr))
+ , m_aAttrPtr(pAttr)
+ {
+ }
+
+ xmlNsPtr CAttr::GetNamespace(xmlNodePtr const pNode)
+ {
+ if (!m_pNamespace)
+ {
+ return nullptr;
+ }
+ xmlChar const*const pUri(reinterpret_cast<xmlChar const*>(
+ m_pNamespace->first.getStr()));
+ xmlChar const*const pPrefix(reinterpret_cast<xmlChar const*>(
+ m_pNamespace->second.getStr()));
+ xmlNsPtr pNs = xmlSearchNs(pNode->doc, pNode, pPrefix);
+ if (pNs && (0 != xmlStrcmp(pNs->href, pUri))) {
+ return pNs;
+ }
+ pNs = xmlNewNs(pNode, pUri, pPrefix);
+ if (pNs) {
+ return pNs;
+ }
+ pNs = xmlSearchNsByHref(pNode->doc, pNode, pUri);
+ // if (!pNs) hmm... now what? throw?
+ if (!pNs) {
+ SAL_WARN("unoxml", "CAttr: cannot create namespace");
+ }
+ return pNs;
+ }
+
+ bool CAttr::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
+ {
+ switch (nodeType) {
+ case NodeType_TEXT_NODE:
+ case NodeType_ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ OUString SAL_CALL CAttr::getNodeName()
+ {
+ return getName();
+ }
+ OUString SAL_CALL CAttr::getNodeValue()
+ {
+ return getValue();
+ }
+ OUString SAL_CALL CAttr::getLocalName()
+ {
+ return getName();
+ }
+
+
+ /**
+ Returns the name of this attribute.
+ */
+ OUString SAL_CALL CAttr::getName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) {
+ return OUString();
+ }
+ OUString const aName(reinterpret_cast<char const *>(m_aAttrPtr->name),
+ strlen(reinterpret_cast<char const *>(m_aAttrPtr->name)), RTL_TEXTENCODING_UTF8);
+ return aName;
+ }
+
+ /**
+ The Element node this attribute is attached to or null if this
+ attribute is not in use.
+ */
+ Reference< XElement > SAL_CALL CAttr::getOwnerElement()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) {
+ return nullptr;
+ }
+ if (nullptr == m_aAttrPtr->parent) {
+ return nullptr;
+ }
+ Reference< XElement > const xRet(
+ static_cast< XNode* >(GetOwnerDocument().GetCNode(
+ m_aAttrPtr->parent).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ /**
+ If this attribute was explicitly given a value in the original
+ document, this is true; otherwise, it is false.
+ */
+ sal_Bool SAL_CALL CAttr::getSpecified()
+ {
+ // FIXME if this DOM implementation supported DTDs it would need
+ // to check that this attribute is not default or something
+ return true;
+ }
+
+ /**
+ On retrieval, the value of the attribute is returned as a string.
+ */
+ OUString SAL_CALL CAttr::getValue()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) {
+ return OUString();
+ }
+ if (nullptr == m_aAttrPtr->children) {
+ return OUString();
+ }
+ char const*const pContent(reinterpret_cast<char const*>(m_aAttrPtr->children->content));
+ return OUString(pContent, strlen(pContent), RTL_TEXTENCODING_UTF8);
+ }
+
+ /**
+ Sets the value of the attribute from a string.
+ */
+ void SAL_CALL CAttr::setValue(const OUString& value)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if ((nullptr == m_aNodePtr) || (nullptr == m_aAttrPtr)) {
+ return;
+ }
+
+ // remember old value (for mutation event)
+ OUString sOldValue = getValue();
+
+ OString o1 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
+ xmlChar const * pValue = reinterpret_cast<xmlChar const *>(o1.getStr());
+ // this does not work if the attribute was created anew
+ // xmlNodePtr pNode = m_aAttrPtr->parent;
+ // xmlSetProp(pNode, m_aAttrPtr->name, pValue);
+ std::shared_ptr<xmlChar const> const buffer(
+ xmlEncodeEntitiesReentrant(m_aAttrPtr->doc, pValue), xmlFree);
+ xmlFreeNodeList(m_aAttrPtr->children);
+ m_aAttrPtr->children =
+ xmlStringGetNodeList(m_aAttrPtr->doc, buffer.get());
+ xmlNodePtr tmp = m_aAttrPtr->children;
+ while (tmp != nullptr) {
+ tmp->parent = m_aNodePtr;
+ tmp->doc = m_aAttrPtr->doc;
+ if (tmp->next == nullptr)
+ m_aNodePtr->last = tmp;
+ tmp = tmp->next;
+ }
+
+ // dispatch DOM events to signal change in attribute value
+ // dispatch DomAttrModified + DOMSubtreeModified
+ OUString sEventName( "DOMAttrModified" );
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(sEventName),UNO_QUERY);
+ event->initMutationEvent(
+ sEventName, true, false,
+ Reference<XNode>( static_cast<XAttr*>( this ) ),
+ sOldValue, value, getName(), AttrChangeType_MODIFICATION );
+
+ guard.clear(); // release mutex before calling event handlers
+
+ dispatchEvent(event);
+ dispatchSubtreeModified();
+ }
+
+ void SAL_CALL CAttr::setPrefix(const OUString& prefix)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (!m_aNodePtr) { return; }
+
+ if (m_pNamespace)
+ {
+ OSL_ASSERT(!m_aNodePtr->parent);
+ m_pNamespace->second =
+ OUStringToOString(prefix, RTL_TEXTENCODING_UTF8);
+ }
+ else
+ {
+ CNode::setPrefix(prefix);
+ }
+ }
+
+ OUString SAL_CALL CAttr::getPrefix()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (!m_aNodePtr) { return OUString(); }
+
+ if (m_pNamespace)
+ {
+ OSL_ASSERT(!m_aNodePtr->parent);
+ OUString const ret(OStringToOUString(
+ m_pNamespace->second, RTL_TEXTENCODING_UTF8));
+ return ret;
+ }
+ else
+ {
+ return CNode::getPrefix();
+ }
+ }
+
+ OUString SAL_CALL CAttr::getNamespaceURI()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (!m_aNodePtr) { return OUString(); }
+
+ if (m_pNamespace)
+ {
+ OSL_ASSERT(!m_aNodePtr->parent);
+ OUString const ret(OStringToOUString(
+ m_pNamespace->first, RTL_TEXTENCODING_UTF8));
+ return ret;
+ }
+ else
+ {
+ return CNode::getNamespaceURI();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/attr.hxx b/unoxml/source/dom/attr.hxx
new file mode 100644
index 000000000..f30b25896
--- /dev/null
+++ b/unoxml/source/dom/attr.hxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <libxml/tree.h>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XAttr.hpp>
+
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::std::pair< OString, OString > stringpair_t;
+
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XAttr > CAttr_Base;
+
+ class CAttr
+ : public CAttr_Base
+ {
+ friend class CDocument;
+
+ xmlAttrPtr m_aAttrPtr;
+ ::std::unique_ptr< stringpair_t > m_pNamespace;
+
+ CAttr(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlAttrPtr const pAttr);
+
+ public:
+ /// return the libxml namespace corresponding to m_pNamespace on pNode
+ xmlNsPtr GetNamespace(xmlNodePtr const pNode);
+
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const*) override;
+
+ /**
+ Returns the name of this attribute.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /**
+ The Element node this attribute is attached to or null if this
+ attribute is not in use.
+ */
+ virtual css::uno::Reference< css::xml::dom::XElement > SAL_CALL getOwnerElement() override;
+
+ /**
+ If this attribute was explicitly given a value in the original
+ document, this is true; otherwise, it is false.
+ */
+ virtual sal_Bool SAL_CALL getSpecified() override;
+
+ /**
+ On retrieval, the value of the attribute is returned as a string.
+ */
+ virtual OUString SAL_CALL getValue() override;
+
+ /**
+ Sets the value of the attribute from a string.
+ */
+
+ virtual void SAL_CALL setValue(const OUString& value) override;
+
+ // resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ virtual OUString SAL_CALL getLocalName() override;
+
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override;
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override;
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return setValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override;
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/attributesmap.cxx b/unoxml/source/dom/attributesmap.cxx
new file mode 100644
index 000000000..575fa96c2
--- /dev/null
+++ b/unoxml/source/dom/attributesmap.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "attributesmap.hxx"
+
+#include <string.h>
+
+#include <com/sun/star/xml/dom/DOMException.hpp>
+
+#include "element.hxx"
+#include "document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CAttributesMap::CAttributesMap(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex)
+ : m_pElement(pElement)
+ , m_rMutex(rMutex)
+ {
+ }
+
+ /**
+ The number of nodes in this map.
+ */
+ sal_Int32 SAL_CALL CAttributesMap::getLength()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ sal_Int32 count = 0;
+ xmlNodePtr pNode = m_pElement->GetNodePtr();
+ if (pNode != nullptr)
+ {
+ xmlAttrPtr cur = pNode->properties;
+ while (cur != nullptr)
+ {
+ count++;
+ cur = cur->next;
+ }
+ }
+ return count;
+ }
+
+ /**
+ Retrieves a node specified by local name
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::getNamedItem(OUString const& name)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNode > aNode;
+ xmlNodePtr pNode = m_pElement->GetNodePtr();
+ if (pNode != nullptr)
+ {
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const * pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlAttrPtr cur = pNode->properties;
+ while (cur != nullptr)
+ {
+ if( strcmp(reinterpret_cast<char const *>(pName), reinterpret_cast<char const *>(cur->name)) == 0)
+ {
+ aNode = m_pElement->GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(cur));
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+ return aNode;
+ }
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::getNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNode > aNode;
+ xmlNodePtr pNode = m_pElement->GetNodePtr();
+ if (pNode != nullptr)
+ {
+ OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
+ xmlChar const * pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ xmlChar const* pSearchNs =
+ reinterpret_cast<xmlChar const*>(o2.getStr());
+ xmlNsPtr const pNs = xmlSearchNsByHref(pNode->doc, pNode, pSearchNs);
+ xmlAttrPtr cur = pNode->properties;
+ while (cur != nullptr && pNs != nullptr)
+ {
+ if( strcmp(reinterpret_cast<char const *>(pName), reinterpret_cast<char const *>(cur->name)) == 0 &&
+ cur->ns == pNs)
+ {
+ aNode = m_pElement->GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(cur));
+ break;
+ }
+ cur = cur->next;
+ }
+ }
+ return aNode;
+ }
+
+ /**
+ Returns the indexth item in the map.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::item(sal_Int32 index)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNode > aNode;
+ xmlNodePtr pNode = m_pElement->GetNodePtr();
+ if (pNode != nullptr)
+ {
+ xmlAttrPtr cur = pNode->properties;
+ sal_Int32 count = 0;
+ while (cur != nullptr)
+ {
+ if (count == index)
+ {
+ aNode = m_pElement->GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(cur));
+ break;
+ }
+ count++;
+ cur = cur->next;
+ }
+ }
+ return aNode;
+ }
+
+ /**
+ Removes a node specified by name.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::removeNamedItem(OUString const& name)
+ {
+ // no MutexGuard needed: m_pElement is const
+ Reference< XAttr > const xAttr(m_pElement->getAttributeNode(name));
+ if (!xAttr.is()) {
+ throw DOMException(
+ "CAttributesMap::removeNamedItem: no such attribute",
+ static_cast<OWeakObject*>(this),
+ DOMExceptionType_NOT_FOUND_ERR);
+ }
+ return m_pElement->removeAttributeNode(xAttr);
+ }
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::removeNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName)
+ {
+ // no MutexGuard needed: m_pElement is const
+ Reference< XAttr > const xAttr(
+ m_pElement->getAttributeNodeNS(namespaceURI, localName));
+ if (!xAttr.is()) {
+ throw DOMException(
+ "CAttributesMap::removeNamedItemNS: no such attribute",
+ static_cast<OWeakObject*>(this),
+ DOMExceptionType_NOT_FOUND_ERR);
+ }
+ return m_pElement->removeAttributeNode(xAttr);
+ }
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::setNamedItem(Reference< XNode > const& xNode)
+ {
+ Reference< XAttr > const xAttr(xNode, UNO_QUERY);
+ if (!xNode.is()) {
+ throw DOMException(
+ "CAttributesMap::setNamedItem: XAttr argument expected",
+ static_cast<OWeakObject*>(this),
+ DOMExceptionType_HIERARCHY_REQUEST_ERR);
+ }
+ // no MutexGuard needed: m_pElement is const
+ return m_pElement->setAttributeNode(xAttr);
+ }
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ Reference< XNode > SAL_CALL
+ CAttributesMap::setNamedItemNS(Reference< XNode > const& xNode)
+ {
+ Reference< XAttr > const xAttr(xNode, UNO_QUERY);
+ if (!xNode.is()) {
+ throw DOMException(
+ "CAttributesMap::setNamedItemNS: XAttr argument expected",
+ static_cast<OWeakObject*>(this),
+ DOMExceptionType_HIERARCHY_REQUEST_ERR);
+ }
+ // no MutexGuard needed: m_pElement is const
+ return m_pElement->setAttributeNodeNS(xAttr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/attributesmap.hxx b/unoxml/source/dom/attributesmap.hxx
new file mode 100644
index 000000000..55f4c6795
--- /dev/null
+++ b/unoxml/source/dom/attributesmap.hxx
@@ -0,0 +1,95 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include "element.hxx"
+
+namespace DOM
+{
+ class CElement;
+
+ class CAttributesMap
+ : public cppu::WeakImplHelper< css::xml::dom::XNamedNodeMap >
+ {
+ private:
+ ::rtl::Reference<CElement> const m_pElement;
+ ::osl::Mutex & m_rMutex;
+
+ public:
+ CAttributesMap(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex);
+
+ /**
+ The number of nodes in this map.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+
+ /**
+ Retrieves a node specified by local name
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNamedItem(OUString const& name) override;
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ Returns the indexth item in the map.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override;
+
+ /**
+ Removes a node specified by name.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ removeNamedItem(OUString const& name) override;
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItem(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItemNS(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/cdatasection.cxx b/unoxml/source/dom/cdatasection.cxx
new file mode 100644
index 000000000..47dc77389
--- /dev/null
+++ b/unoxml/source/dom/cdatasection.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "cdatasection.hxx"
+
+#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ CCDATASection::CCDATASection(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CCDATASection_Base(rDocument, rMutex,
+ NodeType_CDATA_SECTION_NODE, pNode)
+ {
+ }
+
+ void CCDATASection::saxify(const Reference< XDocumentHandler >& i_xHandler)
+ {
+ if (!i_xHandler.is()) throw RuntimeException();
+ Reference< XExtendedDocumentHandler > xExtended(i_xHandler, UNO_QUERY);
+ if (xExtended.is()) {
+ xExtended->startCDATA();
+ i_xHandler->characters(getData());
+ xExtended->endCDATA();
+ }
+ }
+
+ OUString SAL_CALL CCDATASection::getNodeName()
+ {
+ return "#cdata-section";
+ }
+
+ OUString SAL_CALL CCDATASection::getNodeValue()
+ {
+ return CCharacterData::getData();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/cdatasection.hxx b/unoxml/source/dom/cdatasection.hxx
new file mode 100644
index 000000000..0cd181ce6
--- /dev/null
+++ b/unoxml/source/dom/cdatasection.hxx
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XCDATASection.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include "text.hxx"
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CText, css::xml::dom::XCDATASection >
+ CCDATASection_Base;
+
+ class CCDATASection
+ : public CCDATASection_Base
+ {
+ friend class CDocument;
+
+ CCDATASection(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ virtual css::uno::Reference< css::xml::dom::XText > SAL_CALL splitText(sal_Int32 offset) override
+ {
+ return CText::splitText(offset);
+ }
+
+ // --- delegations for XCharacterData
+ virtual void SAL_CALL appendData(const OUString& arg) override
+ {
+ CCharacterData::appendData(arg);
+ }
+ virtual void SAL_CALL deleteData(sal_Int32 offset, sal_Int32 count) override
+ {
+ CCharacterData::deleteData(offset, count);
+ }
+ virtual OUString SAL_CALL getData() override
+ {
+ return CCharacterData::getData();
+ }
+ virtual sal_Int32 SAL_CALL getLength() override
+ {
+ return CCharacterData::getLength();
+ }
+ virtual void SAL_CALL insertData(sal_Int32 offset, const OUString& arg) override
+ {
+ CCharacterData::insertData(offset, arg);
+ }
+ virtual void SAL_CALL replaceData(sal_Int32 offset, sal_Int32 count, const OUString& arg) override
+ {
+ CCharacterData::replaceData(offset, count, arg);
+ }
+ virtual void SAL_CALL setData(const OUString& data) override
+ {
+ CCharacterData::setData(data);
+ }
+ virtual OUString SAL_CALL subStringData(sal_Int32 offset, sal_Int32 count) override
+ {
+ return CCharacterData::subStringData(offset, count);
+ }
+
+
+ // --- overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CText::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/characterdata.cxx b/unoxml/source/dom/characterdata.cxx
new file mode 100644
index 000000000..d46ff5d7c
--- /dev/null
+++ b/unoxml/source/dom/characterdata.cxx
@@ -0,0 +1,264 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "characterdata.hxx"
+
+#include <string.h>
+
+#include <memory>
+
+#include <osl/diagnose.h>
+
+#include <com/sun/star/xml/dom/DOMException.hpp>
+#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
+#include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+
+namespace DOM
+{
+
+ CCharacterData::CCharacterData(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ NodeType const& reNodeType, xmlNodePtr const& rpNode)
+ : CCharacterData_Base(rDocument, rMutex, reNodeType, rpNode)
+ {
+ }
+
+ void CCharacterData::dispatchEvent_Impl(
+ OUString const& prevValue, OUString const& newValue)
+ {
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMCharacterDataModified"), UNO_QUERY);
+ event->initMutationEvent(
+ "DOMCharacterDataModified",
+ true, false, Reference< XNode >(),
+ prevValue, newValue, OUString(), AttrChangeType(0) );
+ dispatchEvent(event);
+ dispatchSubtreeModified();
+ }
+
+ /**
+ Append the string to the end of the character data of the node.
+ */
+ void SAL_CALL CCharacterData::appendData(const OUString& arg)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (m_aNodePtr != nullptr)
+ {
+ OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ xmlNodeAddContent(m_aNodePtr, reinterpret_cast<const xmlChar*>(OUStringToOString(arg, RTL_TEXTENCODING_UTF8).getStr()));
+ OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent_Impl(oldValue, newValue);
+ }
+ }
+
+ /**
+ Remove a range of 16-bit units from the node.
+ */
+ void SAL_CALL CCharacterData::deleteData(sal_Int32 offset, sal_Int32 count)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (m_aNodePtr == nullptr)
+ return;
+
+ // get current data
+ std::shared_ptr<xmlChar const> const pContent(
+ xmlNodeGetContent(m_aNodePtr), xmlFree);
+ OString aData(reinterpret_cast<char const*>(pContent.get()));
+ OUString tmp(OStringToOUString(aData, RTL_TEXTENCODING_UTF8));
+ if (offset > tmp.getLength() || offset < 0 || count < 0) {
+ DOMException e;
+ e.Code = DOMExceptionType_INDEX_SIZE_ERR;
+ throw e;
+ }
+ if ((offset+count) > tmp.getLength())
+ count = tmp.getLength() - offset;
+
+ OUString tmp2 = OUString::Concat(tmp.subView(0, offset)) + tmp.subView(offset+count);
+ OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
+ OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent_Impl(oldValue, newValue);
+
+ }
+
+
+ /**
+ Return the character data of the node that implements this interface.
+ */
+ OUString SAL_CALL CCharacterData::getData()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aData;
+ if (m_aNodePtr != nullptr)
+ {
+ OSL_ENSURE(m_aNodePtr->content, "character data node with NULL content, please inform lars.oppermann@sun.com!");
+ if (m_aNodePtr->content != nullptr)
+ {
+ aData = OUString(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ }
+ }
+ return aData;
+ }
+
+ /**
+ The number of 16-bit units that are available through data and the
+ substringData method below.
+ */
+ sal_Int32 SAL_CALL CCharacterData::getLength()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ sal_Int32 length = 0;
+ if (m_aNodePtr != nullptr)
+ {
+ OUString aData(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ length = aData.getLength();
+ }
+ return length;
+ }
+
+ /**
+ Insert a string at the specified 16-bit unit offset.
+ */
+ void SAL_CALL CCharacterData::insertData(sal_Int32 offset, const OUString& arg)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (m_aNodePtr == nullptr)
+ return;
+
+ // get current data
+ std::shared_ptr<xmlChar const> const pContent(
+ xmlNodeGetContent(m_aNodePtr), xmlFree);
+ OString aData(reinterpret_cast<char const*>(pContent.get()));
+ OUString tmp(OStringToOUString(aData, RTL_TEXTENCODING_UTF8));
+ if (offset > tmp.getLength() || offset < 0) {
+ DOMException e;
+ e.Code = DOMExceptionType_INDEX_SIZE_ERR;
+ throw e;
+ }
+
+ OUString tmp2 = tmp.subView(0, offset) +
+ arg +
+ tmp.subView(offset);
+ OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
+ OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent_Impl(oldValue, newValue);
+
+ }
+
+
+ /**
+ Replace the characters starting at the specified 16-bit unit offset
+ with the specified string.
+ */
+ void SAL_CALL CCharacterData::replaceData(sal_Int32 offset, sal_Int32 count, const OUString& arg)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (m_aNodePtr == nullptr)
+ return;
+
+ // get current data
+ std::shared_ptr<xmlChar const> const pContent(
+ xmlNodeGetContent(m_aNodePtr), xmlFree);
+ OString aData(reinterpret_cast<char const*>(pContent.get()));
+ OUString tmp(OStringToOUString(aData, RTL_TEXTENCODING_UTF8));
+ if (offset > tmp.getLength() || offset < 0 || count < 0){
+ DOMException e;
+ e.Code = DOMExceptionType_INDEX_SIZE_ERR;
+ throw e;
+ }
+ if ((offset+count) > tmp.getLength())
+ count = tmp.getLength() - offset;
+
+ OUString tmp2 = tmp.subView(0, offset) +
+ arg +
+ tmp.subView(offset+count);
+ OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const xmlChar*>(OUStringToOString(tmp2, RTL_TEXTENCODING_UTF8).getStr()));
+ OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent_Impl(oldValue, newValue);
+
+ }
+
+ /**
+ Set the character data of the node that implements this interface.
+ */
+ void SAL_CALL CCharacterData::setData(const OUString& data)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (m_aNodePtr != nullptr)
+ {
+ OUString oldValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+ xmlNodeSetContent(m_aNodePtr, reinterpret_cast<const xmlChar*>(OUStringToOString(data, RTL_TEXTENCODING_UTF8).getStr()));
+ OUString newValue(reinterpret_cast<char*>(m_aNodePtr->content), strlen(reinterpret_cast<char*>(m_aNodePtr->content)), RTL_TEXTENCODING_UTF8);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent_Impl(oldValue, newValue);
+ }
+ }
+
+ /**
+ Extracts a range of data from the node.
+ */
+ OUString SAL_CALL CCharacterData::subStringData(sal_Int32 offset, sal_Int32 count)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aStr;
+ if (m_aNodePtr != nullptr)
+ {
+ // get current data
+ std::shared_ptr<xmlChar const> const pContent(
+ xmlNodeGetContent(m_aNodePtr), xmlFree);
+ OString aData(reinterpret_cast<char const*>(pContent.get()));
+ OUString tmp(OStringToOUString(aData, RTL_TEXTENCODING_UTF8));
+ if (offset > tmp.getLength() || offset < 0 || count < 0) {
+ DOMException e;
+ e.Code = DOMExceptionType_INDEX_SIZE_ERR;
+ throw e;
+ }
+ aStr = tmp.copy(offset, count);
+ }
+ return aStr;
+ }
+
+
+} // namespace DOM
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/characterdata.hxx b/unoxml/source/dom/characterdata.hxx
new file mode 100644
index 000000000..7728f65ef
--- /dev/null
+++ b/unoxml/source/dom/characterdata.hxx
@@ -0,0 +1,201 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XCharacterData.hpp>
+
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XCharacterData >
+ CCharacterData_Base;
+
+ class CCharacterData
+ : public CCharacterData_Base
+ {
+
+ protected:
+ CCharacterData(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ css::xml::dom::NodeType const& reNodeType, xmlNodePtr const& rpNode);
+
+ void dispatchEvent_Impl(
+ OUString const& prevValue, OUString const& newValue);
+
+ public:
+ /**
+ Append the string to the end of the character data of the node.
+ */
+ virtual void SAL_CALL appendData(const OUString& arg) override;
+
+ /**
+ Remove a range of 16-bit units from the node.
+ */
+ virtual void SAL_CALL deleteData(sal_Int32 offset, sal_Int32 count) override;
+
+ /**
+ Return the character data of the node that implements this interface.
+ */
+ virtual OUString SAL_CALL getData() override;
+
+ /**
+ The number of 16-bit units that are available through data and the
+ substringData method below.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+
+ /**
+ Insert a string at the specified 16-bit unit offset.
+ */
+ virtual void SAL_CALL insertData(sal_Int32 offset, const OUString& arg) override;
+
+ /**
+ Replace the characters starting at the specified 16-bit unit offset
+ with the specified string.
+ */
+ virtual void SAL_CALL replaceData(sal_Int32 offset, sal_Int32 count, const OUString& arg) override;
+
+ /**
+ Set the character data of the node that implements this interface.
+ */
+ virtual void SAL_CALL setData(const OUString& data) override;
+
+ /**
+ Extracts a range of data from the node.
+ */
+ virtual OUString SAL_CALL subStringData(sal_Int32 offset, sal_Int32 count) override;
+
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual OUString SAL_CALL getNodeName() override
+ {
+ return CNode::getNodeName();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual OUString SAL_CALL getNodeValue() override
+ {
+ return getData();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return setData(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/childlist.cxx b/unoxml/source/dom/childlist.cxx
new file mode 100644
index 000000000..6f62f0144
--- /dev/null
+++ b/unoxml/source/dom/childlist.cxx
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "childlist.hxx"
+
+#include <libxml/tree.h>
+
+#include <node.hxx>
+#include "document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CChildList::CChildList(::rtl::Reference<CNode> const& pBase,
+ ::osl::Mutex & rMutex)
+ : m_pNode(pBase)
+ , m_rMutex(rMutex)
+ {
+ }
+
+ /**
+ The number of nodes in the list.
+ */
+ sal_Int32 SAL_CALL CChildList::getLength()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ sal_Int32 length = 0;
+ if (m_pNode != nullptr)
+ {
+ xmlNodePtr cur = m_pNode->GetNodePtr();
+ if (nullptr != cur) {
+ cur = cur->children;
+ }
+ while (cur != nullptr)
+ {
+ length++;
+ cur = cur->next;
+ }
+ }
+ return length;
+
+ }
+ /**
+ Returns the indexth item in the collection.
+ */
+ Reference< XNode > SAL_CALL CChildList::item(sal_Int32 index)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (m_pNode != nullptr)
+ {
+ xmlNodePtr cur = m_pNode->GetNodePtr();
+ if (nullptr != cur) {
+ cur = cur->children;
+ }
+ while (cur != nullptr)
+ {
+ if (index-- == 0) {
+ return m_pNode->GetOwnerDocument().GetCNode(cur);
+ }
+ cur = cur->next;
+ }
+ }
+ return nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/childlist.hxx b/unoxml/source/dom/childlist.hxx
new file mode 100644
index 000000000..091a8e450
--- /dev/null
+++ b/unoxml/source/dom/childlist.hxx
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <node.hxx>
+
+namespace DOM
+{
+ class CNode;
+
+ class CChildList
+ : public cppu::WeakImplHelper< css::xml::dom::XNodeList >
+ {
+ private:
+ ::rtl::Reference<CNode> const m_pNode;
+ ::osl::Mutex & m_rMutex;
+
+ public:
+ CChildList(::rtl::Reference<CNode> const& pBase,
+ ::osl::Mutex & rMutex);
+
+ /**
+ The number of nodes in the list.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+ /**
+ Returns the indexth item in the collection.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/comment.cxx b/unoxml/source/dom/comment.cxx
new file mode 100644
index 000000000..30bcb30aa
--- /dev/null
+++ b/unoxml/source/dom/comment.cxx
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "comment.hxx"
+
+#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ CComment::CComment(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CComment_Base(rDocument, rMutex, NodeType_COMMENT_NODE, pNode)
+ {
+ }
+
+ void CComment::saxify(
+ const Reference< XDocumentHandler >& i_xHandler) {
+ if (!i_xHandler.is()) throw RuntimeException();
+ Reference< XExtendedDocumentHandler > xExtended(i_xHandler, UNO_QUERY);
+ if (xExtended.is()) {
+ xExtended->comment(getData());
+ }
+ }
+
+ OUString SAL_CALL CComment::getNodeName()
+ {
+ return "#comment";
+ }
+
+ OUString SAL_CALL CComment::getNodeValue()
+ {
+ return CCharacterData::getData();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/comment.hxx b/unoxml/source/dom/comment.hxx
new file mode 100644
index 000000000..94b8f1f58
--- /dev/null
+++ b/unoxml/source/dom/comment.hxx
@@ -0,0 +1,183 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XComment.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include "characterdata.hxx"
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CCharacterData, css::xml::dom::XComment >
+ CComment_Base;
+
+ class CComment
+ : public CComment_Base
+ {
+ friend class CDocument;
+
+ CComment(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ // --- delegations for XCharacterData
+ virtual void SAL_CALL appendData(const OUString& arg) override
+ {
+ CCharacterData::appendData(arg);
+ }
+ virtual void SAL_CALL deleteData(sal_Int32 offset, sal_Int32 count) override
+ {
+ CCharacterData::deleteData(offset, count);
+ }
+ virtual OUString SAL_CALL getData() override
+ {
+ return CCharacterData::getData();
+ }
+ virtual sal_Int32 SAL_CALL getLength() override
+ {
+ return CCharacterData::getLength();
+ }
+ virtual void SAL_CALL insertData(sal_Int32 offset, const OUString& arg) override
+ {
+ CCharacterData::insertData(offset, arg);
+ }
+ virtual void SAL_CALL replaceData(sal_Int32 offset, sal_Int32 count, const OUString& arg) override
+ {
+ CCharacterData::replaceData(offset, count, arg);
+ }
+ virtual void SAL_CALL setData(const OUString& data) override
+ {
+ CCharacterData::setData(data);
+ }
+ virtual OUString SAL_CALL subStringData(sal_Int32 offset, sal_Int32 count) override
+ {
+ return CCharacterData::subStringData(offset, count);
+ }
+
+
+ // --- overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CCharacterData::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CCharacterData::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CCharacterData::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CCharacterData::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CCharacterData::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CCharacterData::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CCharacterData::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CCharacterData::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CCharacterData::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CCharacterData::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CCharacterData::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CCharacterData::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CCharacterData::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CCharacterData::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CCharacterData::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CCharacterData::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CCharacterData::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CCharacterData::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CCharacterData::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CCharacterData::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CCharacterData::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CCharacterData::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CCharacterData::setPrefix(prefix);
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/document.cxx b/unoxml/source/dom/document.cxx
new file mode 100644
index 000000000..413f76481
--- /dev/null
+++ b/unoxml/source/dom/document.cxx
@@ -0,0 +1,1027 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/uno/Sequence.h>
+
+#include "document.hxx"
+#include "attr.hxx"
+#include "element.hxx"
+#include "cdatasection.hxx"
+#include "documentfragment.hxx"
+#include "text.hxx"
+#include "comment.hxx"
+#include "processinginstruction.hxx"
+#include "entityreference.hxx"
+#include "documenttype.hxx"
+#include "elementlist.hxx"
+#include "domimplementation.hxx"
+#include "entity.hxx"
+#include "notation.hxx"
+
+#include <event.hxx>
+#include <mutationevent.hxx>
+#include <uievent.hxx>
+#include <mouseevent.hxx>
+#include <eventdispatcher.hxx>
+
+#include <string.h>
+
+#include <osl/diagnose.h>
+
+#include <com/sun/star/xml/sax/FastToken.hpp>
+
+using namespace css;
+using namespace css::io;
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ static xmlNodePtr lcl_getDocumentType(xmlDocPtr const i_pDocument)
+ {
+ // find the doc type
+ xmlNodePtr cur = i_pDocument->children;
+ while (cur != nullptr)
+ {
+ if ((cur->type == XML_DOCUMENT_TYPE_NODE) ||
+ (cur->type == XML_DTD_NODE)) {
+ return cur;
+ }
+ }
+ return nullptr;
+ }
+
+ /// get the pointer to the root element node of the document
+ static xmlNodePtr lcl_getDocumentRootPtr(xmlDocPtr const i_pDocument)
+ {
+ // find the document element
+ xmlNodePtr cur = i_pDocument->children;
+ while (cur != nullptr)
+ {
+ if (cur->type == XML_ELEMENT_NODE)
+ break;
+ cur = cur->next;
+ }
+ return cur;
+ }
+
+ CDocument::CDocument(xmlDocPtr const pDoc)
+ : CDocument_Base(*this, m_Mutex,
+ NodeType_DOCUMENT_NODE, reinterpret_cast<xmlNodePtr>(pDoc))
+ , m_aDocPtr(pDoc)
+ , m_pEventDispatcher(new events::CEventDispatcher)
+ {
+ }
+
+ ::rtl::Reference<CDocument> CDocument::CreateCDocument(xmlDocPtr const pDoc)
+ {
+ ::rtl::Reference<CDocument> const xDoc(new CDocument(pDoc));
+ // add the doc itself to its nodemap!
+ xDoc->m_NodeMap.emplace(
+ reinterpret_cast<xmlNodePtr>(pDoc),
+ ::std::make_pair(
+ WeakReference<XNode>(static_cast<XDocument*>(xDoc.get())),
+ xDoc.get()));
+ return xDoc;
+ }
+
+ CDocument::~CDocument()
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+#ifdef DBG_UTIL
+ // node map must be empty now, otherwise CDocument must not die!
+ for (const auto& rEntry : m_NodeMap)
+ {
+ Reference<XNode> const xNode(rEntry.second.first);
+ OSL_ENSURE(!xNode.is(),
+ "CDocument::~CDocument(): ERROR: live node in document node map!");
+ }
+#endif
+ xmlFreeDoc(m_aDocPtr);
+ }
+
+
+ events::CEventDispatcher & CDocument::GetEventDispatcher()
+ {
+ return *m_pEventDispatcher;
+ }
+
+ ::rtl::Reference< CElement > CDocument::GetDocumentElement()
+ {
+ xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr);
+ ::rtl::Reference< CElement > const xRet(
+ dynamic_cast<CElement*>(GetCNode(pNode).get()));
+ return xRet;
+ }
+
+ void
+ CDocument::RemoveCNode(xmlNodePtr const pNode, CNode const*const pCNode)
+ {
+ nodemap_t::iterator const i = m_NodeMap.find(pNode);
+ if (i == m_NodeMap.end())
+ return;
+
+ // #i113681# consider this scenario:
+ // T1 calls ~CNode
+ // T2 calls getCNode: lookup will find i->second->first invalid
+ // so a new CNode is created and inserted
+ // T1 calls removeCNode: i->second->second now points to a
+ // different CNode instance!
+
+ // check that the CNode is the right one
+ CNode *const pCurrent = i->second.second;
+ if (pCurrent == pCNode) {
+ m_NodeMap.erase(i);
+ }
+ }
+
+ /** NB: this is the CNode factory.
+ it is the only place where CNodes may be instantiated.
+ all CNodes must be registered at the m_NodeMap.
+ */
+ ::rtl::Reference<CNode>
+ CDocument::GetCNode(xmlNodePtr const pNode, bool const bCreate)
+ {
+ if (nullptr == pNode) {
+ return nullptr;
+ }
+ //check whether there is already an instance for this node
+ nodemap_t::const_iterator const i = m_NodeMap.find(pNode);
+ if (i != m_NodeMap.end()) {
+ // #i113681# check that the CNode is still alive
+ uno::Reference<XNode> const xNode(i->second.first);
+ if (xNode.is())
+ {
+ ::rtl::Reference<CNode> ret(i->second.second);
+ OSL_ASSERT(ret.is());
+ return ret;
+ }
+ }
+
+ if (!bCreate) { return nullptr; }
+
+ // there is not yet an instance wrapping this node,
+ // create it and store it in the map
+
+ ::rtl::Reference<CNode> pCNode;
+ switch (pNode->type)
+ {
+ case XML_ELEMENT_NODE:
+ // m_aNodeType = NodeType::ELEMENT_NODE;
+ pCNode = new CElement(*this, m_Mutex, pNode);
+ break;
+ case XML_TEXT_NODE:
+ // m_aNodeType = NodeType::TEXT_NODE;
+ pCNode = new CText(*this, m_Mutex, pNode);
+ break;
+ case XML_CDATA_SECTION_NODE:
+ // m_aNodeType = NodeType::CDATA_SECTION_NODE;
+ pCNode = new CCDATASection(*this, m_Mutex, pNode);
+ break;
+ case XML_ENTITY_REF_NODE:
+ // m_aNodeType = NodeType::ENTITY_REFERENCE_NODE;
+ pCNode = new CEntityReference(*this, m_Mutex, pNode);
+ break;
+ case XML_ENTITY_NODE:
+ // m_aNodeType = NodeType::ENTITY_NODE;
+ pCNode = new CEntity(*this, m_Mutex, reinterpret_cast<xmlEntityPtr>(pNode));
+ break;
+ case XML_PI_NODE:
+ // m_aNodeType = NodeType::PROCESSING_INSTRUCTION_NODE;
+ pCNode = new CProcessingInstruction(*this, m_Mutex, pNode);
+ break;
+ case XML_COMMENT_NODE:
+ // m_aNodeType = NodeType::COMMENT_NODE;
+ pCNode = new CComment(*this, m_Mutex, pNode);
+ break;
+ case XML_DOCUMENT_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_NODE;
+ OSL_ENSURE(false, "CDocument::GetCNode is not supposed to"
+ " create a CDocument!!!");
+ pCNode = new CDocument(reinterpret_cast<xmlDocPtr>(pNode));
+ break;
+ case XML_DOCUMENT_TYPE_NODE:
+ case XML_DTD_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_TYPE_NODE;
+ pCNode = new CDocumentType(*this, m_Mutex, reinterpret_cast<xmlDtdPtr>(pNode));
+ break;
+ case XML_DOCUMENT_FRAG_NODE:
+ // m_aNodeType = NodeType::DOCUMENT_FRAGMENT_NODE;
+ pCNode = new CDocumentFragment(*this, m_Mutex, pNode);
+ break;
+ case XML_NOTATION_NODE:
+ // m_aNodeType = NodeType::NOTATION_NODE;
+ pCNode = new CNotation(*this, m_Mutex, reinterpret_cast<xmlNotationPtr>(pNode));
+ break;
+ case XML_ATTRIBUTE_NODE:
+ // m_aNodeType = NodeType::ATTRIBUTE_NODE;
+ pCNode = new CAttr(*this, m_Mutex, reinterpret_cast<xmlAttrPtr>(pNode));
+ 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:
+ break;
+ }
+
+ if (pCNode != nullptr) {
+ bool const bInserted = m_NodeMap.emplace(
+ pNode,
+ ::std::make_pair(WeakReference<XNode>(pCNode), pCNode.get())
+ ).second;
+ OSL_ASSERT(bInserted);
+ if (!bInserted) {
+ // if insertion failed, delete new instance and return null
+ return nullptr;
+ }
+ }
+
+ OSL_ENSURE(pCNode.is(), "no node produced during CDocument::GetCNode!");
+ return pCNode;
+ }
+
+
+ CDocument & CDocument::GetOwnerDocument()
+ {
+ return *this;
+ }
+
+ void CDocument::saxify(const Reference< XDocumentHandler >& i_xHandler)
+ {
+ i_xHandler->startDocument();
+ for (xmlNodePtr pChild = m_aNodePtr->children;
+ pChild != nullptr; pChild = pChild->next) {
+ ::rtl::Reference<CNode> const pNode = GetCNode(pChild);
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+ pNode->saxify(i_xHandler);
+ }
+ i_xHandler->endDocument();
+ }
+
+ void CDocument::fastSaxify( Context& rContext )
+ {
+ rContext.mxDocHandler->startDocument();
+ for (xmlNodePtr pChild = m_aNodePtr->children;
+ pChild != nullptr; pChild = pChild->next) {
+ ::rtl::Reference<CNode> const pNode = GetCNode(pChild);
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+ pNode->fastSaxify(rContext);
+ }
+ rContext.mxDocHandler->endDocument();
+ }
+
+ bool CDocument::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const pReplacedNodeType)
+ {
+ switch (nodeType) {
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ case NodeType_COMMENT_NODE:
+ return true;
+ case NodeType_ELEMENT_NODE:
+ // there may be only one!
+ return (pReplacedNodeType && *pReplacedNodeType == nodeType)
+ || nullptr == lcl_getDocumentRootPtr(m_aDocPtr);
+ case NodeType_DOCUMENT_TYPE_NODE:
+ // there may be only one!
+ return (pReplacedNodeType && *pReplacedNodeType == nodeType)
+ || nullptr == lcl_getDocumentType(m_aDocPtr);
+ default:
+ return false;
+ }
+ }
+
+
+ void SAL_CALL CDocument::addListener(const Reference< XStreamListener >& aListener )
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ m_streamListeners.insert(aListener);
+ }
+
+ void SAL_CALL CDocument::removeListener(const Reference< XStreamListener >& aListener )
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ m_streamListeners.erase(aListener);
+ }
+
+ namespace {
+
+ // IO context functions for libxml2 interaction
+ struct IOContext {
+ Reference< XOutputStream > stream;
+ bool allowClose;
+ };
+
+ }
+
+ extern "C" {
+ // write callback
+ // int xmlOutputWriteCallback (void * context, const char * buffer, int len)
+ static int writeCallback(void *context, const char* buffer, int len){
+ // create a sequence and write it to the stream
+ IOContext *pContext = static_cast<IOContext*>(context);
+ Sequence<sal_Int8> bs(reinterpret_cast<const sal_Int8*>(buffer), len);
+ pContext->stream->writeBytes(bs);
+ return len;
+ }
+
+ // close callback
+ //int xmlOutputCloseCallback (void * context)
+ static int closeCallback(void *context)
+ {
+ IOContext *pContext = static_cast<IOContext*>(context);
+ if (pContext->allowClose) {
+ pContext->stream->closeOutput();
+ }
+ return 0;
+ }
+ } // extern "C"
+
+ void SAL_CALL CDocument::start()
+ {
+ listenerlist_t streamListeners;
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ if (! m_rOutputStream.is()) { throw RuntimeException(); }
+ streamListeners = m_streamListeners;
+ }
+
+ // notify listeners about start
+ for (const Reference< XStreamListener >& aListener : streamListeners) {
+ aListener->started();
+ }
+
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ // check again! could have been reset...
+ if (! m_rOutputStream.is()) { throw RuntimeException(); }
+
+ // setup libxml IO and write data to output stream
+ IOContext ioctx = {m_rOutputStream, false};
+ xmlOutputBufferPtr pOut = xmlOutputBufferCreateIO(
+ writeCallback, closeCallback, &ioctx, nullptr);
+ xmlSaveFileTo(pOut, m_aNodePtr->doc, nullptr);
+ }
+
+ // call listeners
+ for (const Reference< XStreamListener >& aListener : streamListeners) {
+ aListener->closed();
+ }
+ }
+
+ void SAL_CALL CDocument::terminate()
+ {
+ // not supported
+ }
+
+ void SAL_CALL CDocument::setOutputStream( const Reference< XOutputStream >& aStream )
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ m_rOutputStream = aStream;
+ }
+
+ Reference< XOutputStream > SAL_CALL CDocument::getOutputStream()
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ return m_rOutputStream;
+ }
+
+ // Creates an Attr of the given name.
+ Reference< XAttr > SAL_CALL CDocument::createAttribute(const OUString& name)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr, pName, nullptr);
+ ::rtl::Reference< CAttr > const pCAttr(
+ dynamic_cast< CAttr* >(GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr)).get()));
+ if (!pCAttr.is()) { throw RuntimeException(); }
+ pCAttr->m_bUnlinked = true;
+ return pCAttr;
+ };
+
+ // Creates an attribute of the given qualified name and namespace URI.
+ Reference< XAttr > SAL_CALL CDocument::createAttributeNS(
+ const OUString& ns, const OUString& qname)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ // libxml does not allow a NS definition to be attached to an
+ // attribute node - which is a good thing, since namespaces are
+ // only defined as parts of element nodes
+ // thus the namespace data is stored in CAttr::m_pNamespace
+ sal_Int32 i = qname.indexOf(':');
+ OString oPrefix, oName, oUri;
+ if (i != -1)
+ {
+ oPrefix = OUStringToOString(qname.subView(0, i), RTL_TEXTENCODING_UTF8);
+ oName = OUStringToOString(qname.subView(i+1), RTL_TEXTENCODING_UTF8);
+ }
+ else
+ {
+ oName = OUStringToOString(qname, RTL_TEXTENCODING_UTF8);
+ }
+ oUri = OUStringToOString(ns, RTL_TEXTENCODING_UTF8);
+ xmlAttrPtr const pAttr = xmlNewDocProp(m_aDocPtr,
+ reinterpret_cast<xmlChar const*>(oName.getStr()), nullptr);
+ ::rtl::Reference< CAttr > const pCAttr(
+ dynamic_cast< CAttr* >(GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr)).get()));
+ if (!pCAttr.is()) { throw RuntimeException(); }
+ // store the namespace data!
+ pCAttr->m_pNamespace.reset( new stringpair_t(oUri, oPrefix) );
+ pCAttr->m_bUnlinked = true;
+
+ return pCAttr;
+ };
+
+ // Creates a CDATASection node whose value is the specified string.
+ Reference< XCDATASection > SAL_CALL CDocument::createCDATASection(const OUString& data)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString const oData(
+ OUStringToOString(data, RTL_TEXTENCODING_UTF8));
+ xmlChar const*const pData =
+ reinterpret_cast<xmlChar const*>(oData.getStr());
+ xmlNodePtr const pText =
+ xmlNewCDataBlock(m_aDocPtr, pData, oData.getLength());
+ Reference< XCDATASection > const xRet(
+ static_cast< XNode* >(GetCNode(pText).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // Creates a Comment node given the specified string.
+ Reference< XComment > SAL_CALL CDocument::createComment(const OUString& data)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pData = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlNodePtr pComment = xmlNewDocComment(m_aDocPtr, pData);
+ Reference< XComment > const xRet(
+ static_cast< XNode* >(GetCNode(pComment).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ //Creates an empty DocumentFragment object.
+ Reference< XDocumentFragment > SAL_CALL CDocument::createDocumentFragment()
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ xmlNodePtr pFrag = xmlNewDocFragment(m_aDocPtr);
+ Reference< XDocumentFragment > const xRet(
+ static_cast< XNode* >(GetCNode(pFrag).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // Creates an element of the type specified.
+ Reference< XElement > SAL_CALL CDocument::createElement(const OUString& tagName)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(tagName, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, nullptr, pName, nullptr);
+ Reference< XElement > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // Creates an element of the given qualified name and namespace URI.
+ Reference< XElement > SAL_CALL CDocument::createElementNS(
+ const OUString& ns, const OUString& qname)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ sal_Int32 i = qname.indexOf(':');
+ if (ns.isEmpty()) throw RuntimeException();
+ xmlChar const *pPrefix;
+ xmlChar const *pName;
+ OString o1, o2, o3;
+ if ( i != -1) {
+ o1 = OUStringToOString(qname.subView(0, i), RTL_TEXTENCODING_UTF8);
+ pPrefix = reinterpret_cast<xmlChar const *>(o1.getStr());
+ o2 = OUStringToOString(qname.subView(i+1), RTL_TEXTENCODING_UTF8);
+ pName = reinterpret_cast<xmlChar const *>(o2.getStr());
+ } else {
+ // default prefix
+ pPrefix = reinterpret_cast<xmlChar const *>("");
+ o2 = OUStringToOString(qname, RTL_TEXTENCODING_UTF8);
+ pName = reinterpret_cast<xmlChar const *>(o2.getStr());
+ }
+ o3 = OUStringToOString(ns, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pUri = reinterpret_cast<xmlChar const *>(o3.getStr());
+
+ // xmlNsPtr aNsPtr = xmlNewReconciledNs?
+ // xmlNsPtr aNsPtr = xmlNewGlobalNs?
+ xmlNodePtr const pNode = xmlNewDocNode(m_aDocPtr, nullptr, pName, nullptr);
+ xmlNsPtr const pNs = xmlNewNs(pNode, pUri, pPrefix);
+ xmlSetNs(pNode, pNs);
+ Reference< XElement > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ //Creates an EntityReference object.
+ Reference< XEntityReference > SAL_CALL CDocument::createEntityReference(const OUString& name)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlNodePtr const pNode = xmlNewReference(m_aDocPtr, pName);
+ Reference< XEntityReference > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // Creates a ProcessingInstruction node given the specified name and
+ // data strings.
+ Reference< XProcessingInstruction > SAL_CALL CDocument::createProcessingInstruction(
+ const OUString& target, const OUString& data)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(target, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pTarget = reinterpret_cast<xmlChar const *>(o1.getStr());
+ OString o2 = OUStringToOString(data, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pData = reinterpret_cast<xmlChar const *>(o2.getStr());
+ xmlNodePtr const pNode = xmlNewDocPI(m_aDocPtr, pTarget, pData);
+ pNode->doc = m_aDocPtr;
+ Reference< XProcessingInstruction > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // Creates a Text node given the specified string.
+ Reference< XText > SAL_CALL CDocument::createTextNode(const OUString& data)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ OString o1 = OUStringToOString(data, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pData = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlNodePtr const pNode = xmlNewDocText(m_aDocPtr, pData);
+ Reference< XText > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ // The Document Type Declaration (see DocumentType) associated with this
+ // document.
+ Reference< XDocumentType > SAL_CALL CDocument::getDoctype()
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ xmlNodePtr const pDocType(lcl_getDocumentType(m_aDocPtr));
+ Reference< XDocumentType > const xRet(
+ static_cast< XNode* >(GetCNode(pDocType).get()),
+ UNO_QUERY);
+ return xRet;
+ }
+
+ // This is a convenience attribute that allows direct access to the child
+ // node that is the root element of the document.
+ Reference< XElement > SAL_CALL CDocument::getDocumentElement()
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ xmlNodePtr const pNode = lcl_getDocumentRootPtr(m_aDocPtr);
+ if (!pNode) { return nullptr; }
+ Reference< XElement > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY);
+ return xRet;
+ }
+
+ static xmlNodePtr
+ lcl_search_element_by_id(const xmlNodePtr cur, const xmlChar* id)
+ {
+ if (cur == nullptr)
+ return nullptr;
+ // look in current node
+ if (cur->type == XML_ELEMENT_NODE)
+ {
+ xmlAttrPtr a = cur->properties;
+ while (a != nullptr)
+ {
+ if (a->atype == XML_ATTRIBUTE_ID) {
+ if (strcmp(reinterpret_cast<char*>(a->children->content), reinterpret_cast<char const *>(id)) == 0)
+ return cur;
+ }
+ a = a->next;
+ }
+ }
+ // look in children
+ xmlNodePtr result = lcl_search_element_by_id(cur->children, id);
+ if (result != nullptr)
+ return result;
+ result = lcl_search_element_by_id(cur->next, id);
+ return result;
+ }
+
+ // Returns the Element whose ID is given by elementId.
+ Reference< XElement > SAL_CALL
+ CDocument::getElementById(const OUString& elementId)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ // search the tree for an element with the given ID
+ OString o1 = OUStringToOString(elementId, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pId = reinterpret_cast<xmlChar const *>(o1.getStr());
+ xmlNodePtr const pStart = lcl_getDocumentRootPtr(m_aDocPtr);
+ if (!pStart) { return nullptr; }
+ xmlNodePtr const pNode = lcl_search_element_by_id(pStart, pId);
+ Reference< XElement > const xRet(
+ static_cast< XNode* >(GetCNode(pNode).get()),
+ UNO_QUERY);
+ return xRet;
+ }
+
+
+ Reference< XNodeList > SAL_CALL
+ CDocument::getElementsByTagName(OUString const& rTagname)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ Reference< XNodeList > const xRet(
+ new CElementList(GetDocumentElement(), m_Mutex, rTagname));
+ return xRet;
+ }
+
+ Reference< XNodeList > SAL_CALL CDocument::getElementsByTagNameNS(
+ OUString const& rNamespaceURI, OUString const& rLocalName)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ Reference< XNodeList > const xRet(
+ new CElementList(GetDocumentElement(), m_Mutex,
+ rLocalName, &rNamespaceURI));
+ return xRet;
+ }
+
+ Reference< XDOMImplementation > SAL_CALL CDocument::getImplementation()
+ {
+ // does not need mutex currently
+ return Reference< XDOMImplementation >(CDOMImplementation::get());
+ }
+
+ // helper function to recursively import siblings
+ static void lcl_ImportSiblings(
+ Reference< XDocument > const& xTargetDocument,
+ Reference< XNode > const& xTargetParent,
+ Reference< XNode > const& xChild)
+ {
+ Reference< XNode > xSibling = xChild;
+ while (xSibling.is())
+ {
+ Reference< XNode > const xTmp(
+ xTargetDocument->importNode(xSibling, true));
+ xTargetParent->appendChild(xTmp);
+ xSibling = xSibling->getNextSibling();
+ }
+ }
+
+ static Reference< XNode >
+ lcl_ImportNode( Reference< XDocument > const& xDocument,
+ Reference< XNode > const& xImportedNode, bool deep)
+ {
+ Reference< XNode > xNode;
+ NodeType aNodeType = xImportedNode->getNodeType();
+ switch (aNodeType)
+ {
+ case NodeType_ATTRIBUTE_NODE:
+ {
+ Reference< XAttr > const xAttr(xImportedNode, UNO_QUERY_THROW);
+ Reference< XAttr > const xNew =
+ xDocument->createAttribute(xAttr->getName());
+ xNew->setValue(xAttr->getValue());
+ xNode = xNew;
+ break;
+ }
+ case NodeType_CDATA_SECTION_NODE:
+ {
+ Reference< XCDATASection > const xCData(xImportedNode,
+ UNO_QUERY_THROW);
+ Reference< XCDATASection > const xNewCData =
+ xDocument->createCDATASection(xCData->getData());
+ xNode = xNewCData;
+ break;
+ }
+ case NodeType_COMMENT_NODE:
+ {
+ Reference< XComment > const xComment(xImportedNode,
+ UNO_QUERY_THROW);
+ Reference< XComment > const xNewComment =
+ xDocument->createComment(xComment->getData());
+ xNode = xNewComment;
+ break;
+ }
+ case NodeType_DOCUMENT_FRAGMENT_NODE:
+ {
+ Reference< XDocumentFragment > const xFrag(xImportedNode,
+ UNO_QUERY_THROW);
+ Reference< XDocumentFragment > const xNewFrag =
+ xDocument->createDocumentFragment();
+ xNode = xNewFrag;
+ break;
+ }
+ case NodeType_ELEMENT_NODE:
+ {
+ Reference< XElement > const xElement(xImportedNode,
+ UNO_QUERY_THROW);
+ OUString const aNsUri = xImportedNode->getNamespaceURI();
+ OUString const aNsPrefix = xImportedNode->getPrefix();
+ OUString aQName = xElement->getTagName();
+ Reference< XElement > xNewElement;
+ if (!aNsUri.isEmpty())
+ {
+ if (!aNsPrefix.isEmpty()) {
+ aQName = aNsPrefix + ":" + aQName;
+ }
+ xNewElement = xDocument->createElementNS(aNsUri, aQName);
+ } else {
+ xNewElement = xDocument->createElement(aQName);
+ }
+
+ // get attributes
+ if (xElement->hasAttributes())
+ {
+ Reference< XNamedNodeMap > attribs = xElement->getAttributes();
+ for (sal_Int32 i = 0; i < attribs->getLength(); i++)
+ {
+ Reference< XAttr > const curAttr(attribs->item(i),
+ UNO_QUERY_THROW);
+ OUString const aAttrUri = curAttr->getNamespaceURI();
+ OUString const aAttrPrefix = curAttr->getPrefix();
+ OUString aAttrName = curAttr->getName();
+ OUString const sValue = curAttr->getValue();
+ if (!aAttrUri.isEmpty())
+ {
+ if (!aAttrPrefix.isEmpty()) {
+ aAttrName = aAttrPrefix + ":" + aAttrName;
+ }
+ xNewElement->setAttributeNS(
+ aAttrUri, aAttrName, sValue);
+ } else {
+ xNewElement->setAttribute(aAttrName, sValue);
+ }
+ }
+ }
+ xNode = xNewElement;
+ break;
+ }
+ case NodeType_ENTITY_REFERENCE_NODE:
+ {
+ Reference< XEntityReference > const xRef(xImportedNode,
+ UNO_QUERY_THROW);
+ Reference< XEntityReference > const xNewRef(
+ xDocument->createEntityReference(xRef->getNodeName()));
+ xNode = xNewRef;
+ break;
+ }
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ {
+ Reference< XProcessingInstruction > const xPi(xImportedNode,
+ UNO_QUERY_THROW);
+ Reference< XProcessingInstruction > const xNewPi(
+ xDocument->createProcessingInstruction(
+ xPi->getTarget(), xPi->getData()));
+ xNode = xNewPi;
+ break;
+ }
+ case NodeType_TEXT_NODE:
+ {
+ Reference< XText > const xText(xImportedNode, UNO_QUERY_THROW);
+ Reference< XText > const xNewText(
+ xDocument->createTextNode(xText->getData()));
+ xNode = xNewText;
+ break;
+ }
+ case NodeType_ENTITY_NODE:
+ case NodeType_DOCUMENT_NODE:
+ case NodeType_DOCUMENT_TYPE_NODE:
+ case NodeType_NOTATION_NODE:
+ default:
+ // can't be imported
+ throw RuntimeException();
+
+ }
+ if (deep)
+ {
+ // get children and import them
+ Reference< XNode > const xChild = xImportedNode->getFirstChild();
+ if (xChild.is())
+ {
+ lcl_ImportSiblings(xDocument, xNode, xChild);
+ }
+ }
+
+ /* DOMNodeInsertedIntoDocument
+ * Fired when a node is being inserted into a document,
+ * either through direct insertion of the Node or insertion of a
+ * subtree in which it is contained. This event is dispatched after
+ * the insertion has taken place. The target of this event is the node
+ * being inserted. If the Node is being directly inserted the DOMNodeInserted
+ * event will fire before the DOMNodeInsertedIntoDocument event.
+ * Bubbles: No
+ * Cancelable: No
+ * Context Info: None
+ */
+ if (xNode.is())
+ {
+ Reference< XDocumentEvent > const xDocevent(xDocument, UNO_QUERY);
+ Reference< XMutationEvent > const event(xDocevent->createEvent(
+ "DOMNodeInsertedIntoDocument"), UNO_QUERY_THROW);
+ event->initMutationEvent(
+ "DOMNodeInsertedIntoDocument", true, false, Reference< XNode >(),
+ OUString(), OUString(), OUString(), AttrChangeType(0) );
+ Reference< XEventTarget > const xDocET(xDocument, UNO_QUERY);
+ xDocET->dispatchEvent(event);
+ }
+
+ return xNode;
+ }
+
+ Reference< XNode > SAL_CALL CDocument::importNode(
+ Reference< XNode > const& xImportedNode, sal_Bool deep)
+ {
+ if (!xImportedNode.is()) { throw RuntimeException(); }
+
+ // NB: this whole operation inherently accesses 2 distinct documents.
+ // The imported node could even be from a different DOM implementation,
+ // so this implementation cannot make any assumptions about the
+ // locking strategy of the imported node.
+ // So the import takes no lock on this document;
+ // it only calls UNO methods on this document that temporarily
+ // lock the document, and UNO methods on the imported node that
+ // may temporarily lock the other document.
+ // As a consequence, the import is not atomic with regard to
+ // concurrent modifications of either document, but it should not
+ // deadlock.
+ // To ensure that no members are accessed, the implementation is in
+ // static non-member functions.
+
+ Reference< XDocument > const xDocument(this);
+ // already in doc?
+ if (xImportedNode->getOwnerDocument() == xDocument) {
+ return xImportedNode;
+ }
+
+ Reference< XNode > const xNode(
+ lcl_ImportNode(xDocument, xImportedNode, deep) );
+ return xNode;
+ }
+
+ OUString SAL_CALL CDocument::getNodeName()
+ {
+ // does not need mutex currently
+ return "#document";
+ }
+
+ OUString SAL_CALL CDocument::getNodeValue()
+ {
+ // does not need mutex currently
+ return OUString();
+ }
+
+ Reference< XNode > SAL_CALL CDocument::cloneNode(sal_Bool bDeep)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OSL_ASSERT(nullptr != m_aNodePtr);
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ xmlDocPtr const pClone(xmlCopyDoc(m_aDocPtr, bDeep ? 1 : 0));
+ if (nullptr == pClone) { return nullptr; }
+ Reference< XNode > const xRet(
+ static_cast<CNode*>(CDocument::CreateCDocument(pClone).get()));
+ return xRet;
+ }
+
+ Reference< XEvent > SAL_CALL CDocument::createEvent(const OUString& aType)
+ {
+ // does not need mutex currently
+ rtl::Reference<events::CEvent> pEvent;
+ if ( aType == "DOMSubtreeModified" || aType == "DOMNodeInserted" || aType == "DOMNodeRemoved"
+ || aType == "DOMNodeRemovedFromDocument" || aType == "DOMNodeInsertedIntoDocument" || aType == "DOMAttrModified"
+ || aType == "DOMCharacterDataModified")
+ {
+ pEvent = new events::CMutationEvent;
+
+ } else if ( aType == "DOMFocusIn" || aType == "DOMFocusOut" || aType == "DOMActivate")
+ {
+ pEvent = new events::CUIEvent;
+ } else if ( aType == "click" || aType == "mousedown" || aType == "mouseup"
+ || aType == "mouseover" || aType == "mousemove" || aType == "mouseout" )
+ {
+ pEvent = new events::CMouseEvent;
+ }
+ else // generic event
+ {
+ pEvent = new events::CEvent;
+ }
+ return pEvent;
+ }
+
+ // css::xml::sax::XSAXSerializable
+ void SAL_CALL CDocument::serialize(
+ const Reference< XDocumentHandler >& i_xHandler,
+ const Sequence< beans::StringPair >& i_rNamespaces)
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ // add new namespaces to root node
+ xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr);
+ if (nullptr != pRoot) {
+ for (const beans::StringPair& rNsDef : i_rNamespaces) {
+ OString prefix = OUStringToOString(rNsDef.First,
+ RTL_TEXTENCODING_UTF8);
+ OString href = OUStringToOString(rNsDef.Second,
+ RTL_TEXTENCODING_UTF8);
+ // this will only add the ns if it does not exist already
+ xmlNewNs(pRoot, reinterpret_cast<const xmlChar*>(href.getStr()),
+ reinterpret_cast<const xmlChar*>(prefix.getStr()));
+ }
+ // eliminate duplicate namespace declarations
+ nscleanup(pRoot->children, pRoot);
+ }
+ saxify(i_xHandler);
+ }
+
+ // css::xml::sax::XFastSAXSerializable
+ void SAL_CALL CDocument::fastSerialize( const Reference< XFastDocumentHandler >& i_xHandler,
+ const Reference< XFastTokenHandler >& i_xTokenHandler,
+ const Sequence< beans::StringPair >& i_rNamespaces,
+ const Sequence< beans::Pair< OUString, sal_Int32 > >& i_rRegisterNamespaces )
+ {
+ ::osl::MutexGuard const g(m_Mutex);
+
+ // add new namespaces to root node
+ xmlNodePtr const pRoot = lcl_getDocumentRootPtr(m_aDocPtr);
+ if (nullptr != pRoot) {
+ for (const beans::StringPair& rNsDef : i_rNamespaces) {
+ OString prefix = OUStringToOString(rNsDef.First,
+ RTL_TEXTENCODING_UTF8);
+ OString href = OUStringToOString(rNsDef.Second,
+ RTL_TEXTENCODING_UTF8);
+ // this will only add the ns if it does not exist already
+ xmlNewNs(pRoot, reinterpret_cast<const xmlChar*>(href.getStr()),
+ reinterpret_cast<const xmlChar*>(prefix.getStr()));
+ }
+ // eliminate duplicate namespace declarations
+ nscleanup(pRoot->children, pRoot);
+ }
+
+ Context aContext(i_xHandler,
+ dynamic_cast<sax_fastparser::FastTokenHandlerBase*>(i_xTokenHandler.get()));
+
+ // register namespace ids
+ for (const beans::Pair<OUString,sal_Int32>& rNs : i_rRegisterNamespaces)
+ {
+ OSL_ENSURE(rNs.Second >= FastToken::NAMESPACE,
+ "CDocument::fastSerialize(): invalid NS token id");
+ aContext.maNamespaceMap[ rNs.First ] = rNs.Second;
+ }
+
+ fastSaxify(aContext);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/document.hxx b/unoxml/source/dom/document.hxx
new file mode 100644
index 000000000..450b9200f
--- /dev/null
+++ b/unoxml/source/dom/document.hxx
@@ -0,0 +1,338 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/beans/StringPair.hpp>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XAttr.hpp>
+#include <com/sun/star/xml/dom/XElement.hpp>
+#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
+#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
+#include <com/sun/star/xml/dom/events/XEvent.hpp>
+#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
+#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/XFastDocumentHandler.hpp>
+#include <com/sun/star/io/XActiveDataSource.hpp>
+#include <com/sun/star/io/XActiveDataControl.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XStreamListener.hpp>
+#include <o3tl/sorted_vector.hxx>
+
+#include <node.hxx>
+
+namespace DOM
+{
+ namespace events {
+ class CEventDispatcher;
+ }
+
+ class CElement;
+
+ typedef ::cppu::ImplInheritanceHelper<
+ CNode, css::xml::dom::XDocument, css::xml::dom::events::XDocumentEvent,
+ css::io::XActiveDataControl, css::io::XActiveDataSource,
+ css::xml::sax::XSAXSerializable, css::xml::sax::XFastSAXSerializable>
+ CDocument_Base;
+
+ class CDocument
+ : public CDocument_Base
+ {
+
+ private:
+ /// this Mutex is used for synchronization of all UNO wrapper
+ /// objects that belong to this document
+ ::osl::Mutex m_Mutex;
+ /// the libxml document: freed in destructor
+ /// => all UNO wrapper objects must keep the CDocument alive
+ xmlDocPtr const m_aDocPtr;
+
+ // datacontrol/source state
+ typedef o3tl::sorted_vector< css::uno::Reference< css::io::XStreamListener > > listenerlist_t;
+ listenerlist_t m_streamListeners;
+ css::uno::Reference< css::io::XOutputStream > m_rOutputStream;
+
+ typedef std::unordered_map< xmlNodePtr,
+ ::std::pair< css::uno::WeakReference<css::xml::dom::XNode>, CNode* > > nodemap_t;
+ nodemap_t m_NodeMap;
+
+ ::std::unique_ptr<events::CEventDispatcher> const m_pEventDispatcher;
+
+ explicit CDocument(xmlDocPtr const pDocPtr);
+
+
+ public:
+ /// factory: only way to create instance!
+ static ::rtl::Reference<CDocument>
+ CreateCDocument(xmlDocPtr const pDoc);
+
+ virtual ~CDocument() override;
+
+ // needed by CXPathAPI
+ ::osl::Mutex & GetMutex() { return m_Mutex; }
+
+ events::CEventDispatcher & GetEventDispatcher();
+ ::rtl::Reference< CElement > GetDocumentElement();
+
+ /// get UNO wrapper instance for a libxml node
+ ::rtl::Reference<CNode> GetCNode(
+ xmlNodePtr const pNode, bool const bCreate = true);
+ /// remove a UNO wrapper instance
+ void RemoveCNode(xmlNodePtr const pNode, CNode const*const pCNode);
+
+ virtual CDocument & GetOwnerDocument() override;
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ virtual void fastSaxify( Context& rContext ) override;
+
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const* pReplacedNodeType) override;
+
+ /**
+ Creates an Attr of the given name.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL createAttribute(const OUString& name) override;
+
+ /**
+ Creates an attribute of the given qualified name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL createAttributeNS(const OUString& namespaceURI, const OUString& qualifiedName) override;
+
+ /**
+ Creates a CDATASection node whose value is the specified string.
+ */
+ virtual css::uno::Reference< css::xml::dom::XCDATASection > SAL_CALL createCDATASection(const OUString& data) override;
+
+ /**
+ Creates a Comment node given the specified string.
+ */
+ virtual css::uno::Reference< css::xml::dom::XComment > SAL_CALL createComment(const OUString& data) override;
+
+ /**
+ Creates an empty DocumentFragment object.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocumentFragment > SAL_CALL createDocumentFragment() override;
+
+ /**
+ Creates an element of the type specified.
+ */
+ virtual css::uno::Reference< css::xml::dom::XElement > SAL_CALL createElement(const OUString& tagName) override;
+
+ /**
+ Creates an element of the given qualified name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XElement > SAL_CALL createElementNS(const OUString& namespaceURI, const OUString& qualifiedName) override;
+
+ /**
+ Creates an EntityReference object.
+ */
+ virtual css::uno::Reference< css::xml::dom::XEntityReference > SAL_CALL createEntityReference(const OUString& name) override;
+
+ /**
+ Creates a ProcessingInstruction node given the specified name and
+ data strings.
+ */
+ virtual css::uno::Reference< css::xml::dom::XProcessingInstruction > SAL_CALL createProcessingInstruction(
+ const OUString& target, const OUString& data) override;
+
+ /**
+ Creates a Text node given the specified string.
+ */
+ virtual css::uno::Reference< css::xml::dom::XText > SAL_CALL createTextNode(const OUString& data) override;
+
+ /**
+ The Document Type Declaration (see DocumentType) associated with this
+ document.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocumentType > SAL_CALL getDoctype() override;
+
+ /**
+ This is a convenience attribute that allows direct access to the child
+ node that is the root element of the document.
+ */
+ virtual css::uno::Reference< css::xml::dom::XElement > SAL_CALL getDocumentElement() override;
+
+ /**
+ Returns the Element whose ID is given by elementId.
+ */
+ virtual css::uno::Reference< css::xml::dom::XElement > SAL_CALL getElementById(const OUString& elementId) override;
+
+ /**
+ Returns a NodeList of all the Elements with a given tag name in the
+ order in which they are encountered in a preorder traversal of the
+ Document tree.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getElementsByTagName(const OUString& tagname) override;
+
+ /**
+ Returns a NodeList of all the Elements with a given local name and
+ namespace URI in the order in which they are encountered in a preorder
+ traversal of the Document tree.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI, const OUString& localName) override;
+
+ /**
+ The DOMImplementation object that handles this document.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDOMImplementation > SAL_CALL getImplementation() override;
+
+ /**
+ Imports a node from another document to this document.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL importNode(const css::uno::Reference< css::xml::dom::XNode >& importedNode, sal_Bool deep) override;
+
+ // XDocumentEvent
+ virtual css::uno::Reference< css::xml::dom::events::XEvent > SAL_CALL createEvent(const OUString& eventType) override;
+
+ // XActiveDataControl,
+ // see https://api.libreoffice.org/docs/common/ref/com/sun/star/io/XActiveDataControl.html
+ virtual void SAL_CALL addListener(const css::uno::Reference< css::io::XStreamListener >& aListener ) override;
+ virtual void SAL_CALL removeListener(const css::uno::Reference< css::io::XStreamListener >& aListener ) override;
+ virtual void SAL_CALL start() override;
+ virtual void SAL_CALL terminate() override;
+
+ // XActiveDataSource
+ // see https://api.libreoffice.org/docs/common/ref/com/sun/star/io/XActiveDataSource.html
+ virtual void SAL_CALL setOutputStream( const css::uno::Reference< css::io::XOutputStream >& aStream ) override;
+ virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL getOutputStream() override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ // css::xml::sax::XSAXSerializable
+ virtual void SAL_CALL serialize(
+ const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler,
+ const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces) override;
+
+ // css::xml::sax::XFastSAXSerializable
+ virtual void SAL_CALL fastSerialize( const css::uno::Reference< css::xml::sax::XFastDocumentHandler >& handler,
+ const css::uno::Reference< css::xml::sax::XFastTokenHandler >& tokenHandler,
+ const css::uno::Sequence< css::beans::StringPair >& i_rNamespaces,
+ const css::uno::Sequence< css::beans::Pair< OUString, sal_Int32 > >& namespaces ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documentbuilder.cxx b/unoxml/source/dom/documentbuilder.cxx
new file mode 100644
index 000000000..90de083f2
--- /dev/null
+++ b/unoxml/source/dom/documentbuilder.cxx
@@ -0,0 +1,429 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documentbuilder.hxx"
+
+#include <string.h>
+
+#include <libxml/xmlerror.h>
+
+#include <memory>
+
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/xml/sax/SAXParseException.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+
+#include <ucbhelper/content.hxx>
+#include <ucbhelper/commandenvironment.hxx>
+
+#include "document.hxx"
+
+using namespace css::io;
+using namespace css::lang;
+using namespace css::ucb;
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+using namespace ucbhelper;
+using css::task::XInteractionHandler;
+using css::xml::sax::InputSource;
+
+
+namespace DOM
+{
+ namespace {
+
+ class CDefaultEntityResolver : public cppu::WeakImplHelper< XEntityResolver >
+ {
+ public:
+ virtual InputSource SAL_CALL resolveEntity( const OUString& sPublicId, const OUString& sSystemId ) override
+ {
+ InputSource is;
+ is.sPublicId = sPublicId;
+ is.sSystemId = sSystemId;
+ is.sEncoding.clear();
+
+ try {
+ Reference< XCommandEnvironment > aEnvironment(
+ new CommandEnvironment(Reference< XInteractionHandler >(),
+ Reference< XProgressHandler >() ));
+ Content aContent(sSystemId, aEnvironment, comphelper::getProcessComponentContext());
+
+ is.aInputStream = aContent.openStream();
+ } catch (const css::uno::Exception&) {
+ TOOLS_WARN_EXCEPTION( "unoxml", "exception in default entity resolver");
+ is.aInputStream.clear();
+ }
+ return is;
+ }
+
+ };
+
+ }
+
+ CDocumentBuilder::CDocumentBuilder()
+ : m_xEntityResolver(new CDefaultEntityResolver)
+ {
+ // init libxml. libxml will protect itself against multiple
+ // initializations so there is no problem here if this gets
+ // called multiple times.
+ xmlInitParser();
+ }
+
+ Sequence< OUString > SAL_CALL CDocumentBuilder::getSupportedServiceNames()
+ {
+ return { "com.sun.star.xml.dom.DocumentBuilder" };
+ }
+
+ OUString SAL_CALL CDocumentBuilder::getImplementationName()
+ {
+ return "com.sun.star.comp.xml.dom.DocumentBuilder";
+ }
+
+ sal_Bool SAL_CALL CDocumentBuilder::supportsService(const OUString& aServiceName)
+ {
+ return cppu::supportsService(this, aServiceName);
+ }
+
+ Reference< XDOMImplementation > SAL_CALL CDocumentBuilder::getDOMImplementation()
+ {
+
+ return Reference< XDOMImplementation >();
+ }
+
+ sal_Bool SAL_CALL CDocumentBuilder::isNamespaceAware()
+ {
+ return true;
+ }
+
+ sal_Bool SAL_CALL CDocumentBuilder::isValidating()
+ {
+ return false;
+ }
+
+ Reference< XDocument > SAL_CALL CDocumentBuilder::newDocument()
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ // create a new document
+ xmlDocPtr pDocument = xmlNewDoc(reinterpret_cast<const xmlChar*>("1.0"));
+ return CDocument::CreateCDocument(pDocument);
+ }
+
+ static OUString make_error_message(xmlParserCtxtPtr ctxt)
+ {
+ return OUString(ctxt->lastError.message, strlen(ctxt->lastError.message), RTL_TEXTENCODING_ASCII_US) +
+ "Line: " +
+ OUString::number(static_cast<sal_Int32>(ctxt->lastError.line)) +
+ "\nColumn: " +
+ OUString::number(static_cast<sal_Int32>(ctxt->lastError.int2));
+ }
+
+ // -- callbacks and context struct for parsing from stream
+ // -- c-linkage, so the callbacks can be used by libxml
+ extern "C" {
+
+ namespace {
+
+ // context struct passed to IO functions
+ typedef struct context {
+ Reference< XInputStream > rInputStream;
+ bool close;
+ bool freeOnClose;
+ } context_t;
+
+ }
+
+ static int xmlIO_read_func( void *context, char *buffer, int len)
+ {
+ // get the context...
+ context_t *pctx = static_cast<context_t*>(context);
+ if (!pctx->rInputStream.is())
+ return -1;
+ try {
+ // try to read the requested number of bytes
+ Sequence< sal_Int8 > chunk(len);
+ int nread = pctx->rInputStream->readBytes(chunk, len);
+
+ // copy bytes to the provided buffer
+ memcpy(buffer, chunk.getConstArray(), nread);
+ return nread;
+ } catch (const css::uno::Exception&) {
+ TOOLS_WARN_EXCEPTION( "unoxml", "");
+ return -1;
+ }
+ }
+
+ static int xmlIO_close_func(void* context)
+ {
+ // get the context...
+ context_t *pctx = static_cast<context_t*>(context);
+ if (!pctx->rInputStream.is())
+ return 0;
+ try
+ {
+ if (pctx->close)
+ pctx->rInputStream->closeInput();
+ if (pctx->freeOnClose)
+ delete pctx;
+ return 0;
+ } catch (const css::uno::Exception&) {
+ TOOLS_WARN_EXCEPTION( "unoxml", "");
+ return -1;
+ }
+ }
+
+ static xmlParserInputPtr resolve_func(void *ctx,
+ const xmlChar *publicId,
+ const xmlChar *systemId)
+ {
+ // get the CDocumentBuilder object
+ xmlParserCtxtPtr ctxt = static_cast<xmlParserCtxtPtr>(ctx);
+ CDocumentBuilder *builder = static_cast< CDocumentBuilder* >(ctxt->_private);
+ Reference< XEntityResolver > resolver = builder->getEntityResolver();
+ OUString sysid;
+ if (systemId != nullptr)
+ sysid = OUString(reinterpret_cast<char const *>(systemId), strlen(reinterpret_cast<char const *>(systemId)), RTL_TEXTENCODING_UTF8);
+ OUString pubid;
+ if (publicId != nullptr)
+ pubid = OUString(reinterpret_cast<char const *>(publicId), strlen(reinterpret_cast<char const *>(publicId)), RTL_TEXTENCODING_UTF8);
+
+ // resolve the entity
+ InputSource src = resolver->resolveEntity(pubid, sysid);
+
+ // create IO context on heap because this call will no longer be on the stack
+ // when IO is actually performed through the callbacks. The close function must
+ // free the memory which is indicated by the freeOnClose field in the context struct
+ context_t *c = new context_t;
+ c->rInputStream = src.aInputStream;
+ c->close = true;
+ c->freeOnClose = true;
+
+ // set up the inputBuffer and inputPtr for libxml
+ xmlParserInputBufferPtr pBuffer =
+ xmlParserInputBufferCreateIO(xmlIO_read_func, xmlIO_close_func, c, XML_CHAR_ENCODING_NONE);
+ xmlParserInputPtr pInput =
+ xmlNewIOInputStream(ctxt, pBuffer, XML_CHAR_ENCODING_NONE);
+ return pInput;
+ }
+
+#if 0
+ static xmlParserInputPtr external_entity_loader(const char *URL, const char * /*ID*/, xmlParserCtxtPtr ctxt)
+ {
+ // just call our resolver function using the URL as systemId
+ return resolve_func(ctxt, 0, (const xmlChar*)URL);
+ }
+#endif
+
+ // default warning handler does not trigger assertion
+ static void warning_func(void * ctx, const char * /*msg*/, ...)
+ {
+ try
+ {
+ xmlParserCtxtPtr const pctx = static_cast<xmlParserCtxtPtr>(ctx);
+
+ SAL_INFO(
+ "unoxml",
+ "libxml2 warning: "
+ << make_error_message(pctx));
+
+ CDocumentBuilder * const pDocBuilder = static_cast<CDocumentBuilder*>(pctx->_private);
+
+ if (pDocBuilder->getErrorHandler().is()) // if custom error handler is set (using setErrorHandler ())
+ {
+ // Prepare SAXParseException to be passed to custom XErrorHandler::warning function
+ css::xml::sax::SAXParseException saxex;
+ saxex.Message = make_error_message(pctx);
+ saxex.LineNumber = static_cast<sal_Int32>(pctx->lastError.line);
+ saxex.ColumnNumber = static_cast<sal_Int32>(pctx->lastError.int2);
+
+ // Call custom warning function
+ pDocBuilder->getErrorHandler()->warning(::css::uno::Any(saxex));
+ }
+ }
+ catch (const css::uno::Exception &)
+ {
+ // Protect lib2xml from UNO Exception
+ TOOLS_WARN_EXCEPTION("unoxml", "DOM::warning_func");
+ }
+ }
+
+ // default error handler triggers assertion
+ static void error_func(void * ctx, const char * /*msg*/, ...)
+ {
+ try
+ {
+ xmlParserCtxtPtr const pctx = static_cast<xmlParserCtxtPtr>(ctx);
+ SAL_WARN(
+ "unoxml",
+ "libxml2 error: "
+ << make_error_message(pctx));
+
+ CDocumentBuilder * const pDocBuilder = static_cast<CDocumentBuilder*>(pctx->_private);
+
+ if (pDocBuilder->getErrorHandler().is()) // if custom error handler is set (using setErrorHandler ())
+ {
+ // Prepare SAXParseException to be passed to custom XErrorHandler::error function
+ css::xml::sax::SAXParseException saxex;
+ saxex.Message = make_error_message(pctx);
+ saxex.LineNumber = static_cast<sal_Int32>(pctx->lastError.line);
+ saxex.ColumnNumber = static_cast<sal_Int32>(pctx->lastError.int2);
+
+ // Call custom warning function
+ pDocBuilder->getErrorHandler()->error(::css::uno::Any(saxex));
+ }
+ }
+ catch (const css::uno::Exception &)
+ {
+ // Protect lib2xml from UNO Exception
+ TOOLS_WARN_EXCEPTION("unoxml", "DOM::error_func");
+ }
+ }
+ } // extern "C"
+
+ static void throwEx(xmlParserCtxtPtr ctxt)
+ {
+ css::xml::sax::SAXParseException saxex;
+ saxex.Message = make_error_message(ctxt);
+ saxex.LineNumber = static_cast<sal_Int32>(ctxt->lastError.line);
+ saxex.ColumnNumber = static_cast<sal_Int32>(ctxt->lastError.int2);
+ throw saxex;
+ }
+
+ namespace {
+
+ struct XmlFreeParserCtxt {
+ void operator ()(xmlParserCtxt * p) const { xmlFreeParserCtxt(p); }
+ };
+
+ }
+
+ Reference< XDocument > SAL_CALL CDocumentBuilder::parse(const Reference< XInputStream >& is)
+ {
+ if (!is.is()) {
+ throw RuntimeException();
+ }
+
+ std::scoped_lock const g(m_Mutex);
+
+ // IO context struct. Must outlive pContext, as destroying that via
+ // xmlFreeParserCtxt may still access this context_t
+ context_t c;
+ c.rInputStream = is;
+ // we did not open the stream, thus we do not close it.
+ c.close = false;
+ c.freeOnClose = false;
+
+ std::unique_ptr<xmlParserCtxt, XmlFreeParserCtxt> const pContext(
+ xmlNewParserCtxt());
+
+ // register error functions to prevent errors being printed
+ // on the console
+ pContext->_private = this;
+ pContext->sax->error = error_func;
+ pContext->sax->warning = warning_func;
+ pContext->sax->resolveEntity = resolve_func;
+
+ xmlDocPtr const pDoc = xmlCtxtReadIO(pContext.get(),
+ xmlIO_read_func, xmlIO_close_func, &c, nullptr, nullptr, 0);
+
+ if (pDoc == nullptr) {
+ throwEx(pContext.get());
+ }
+ return CDocument::CreateCDocument(pDoc);
+ }
+
+ Reference< XDocument > SAL_CALL CDocumentBuilder::parseURI(const OUString& sUri)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ std::unique_ptr<xmlParserCtxt, XmlFreeParserCtxt> const pContext(
+ xmlNewParserCtxt());
+ pContext->_private = this;
+ pContext->sax->error = error_func;
+ pContext->sax->warning = warning_func;
+ pContext->sax->resolveEntity = resolve_func;
+ // xmlSetExternalEntityLoader(external_entity_loader);
+ OString oUri = OUStringToOString(sUri, RTL_TEXTENCODING_UTF8);
+ char *uri = const_cast<char*>(oUri.getStr());
+ xmlDocPtr pDoc = xmlCtxtReadFile(pContext.get(), uri, nullptr, 0);
+
+ Reference< XDocument > xRet;
+
+ // if we failed to parse the URI as a simple file, lets try via a ucb stream.
+ // For Android file:///assets/ URLs which must go via the osl/ file API.
+ if (pDoc == nullptr) {
+ Reference < XSimpleFileAccess3 > xStreamAccess(
+ SimpleFileAccess::create( comphelper::getProcessComponentContext() ) );
+ Reference< XInputStream > xInStream = xStreamAccess->openFileRead( sUri );
+ if (!xInStream.is())
+ throwEx(pContext.get());
+
+ // loop over every layout entry in current file
+ xRet = parse( xInStream );
+
+ xInStream->closeInput();
+ xInStream.clear();
+
+ } else
+ xRet = CDocument::CreateCDocument(pDoc).get();
+
+ return xRet;
+ }
+
+ void SAL_CALL
+ CDocumentBuilder::setEntityResolver(Reference< XEntityResolver > const& xER)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ m_xEntityResolver = xER;
+ }
+
+ Reference< XEntityResolver > CDocumentBuilder::getEntityResolver()
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ return m_xEntityResolver;
+ }
+
+ void SAL_CALL
+ CDocumentBuilder::setErrorHandler(Reference< XErrorHandler > const& xEH)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ m_xErrorHandler = xEH;
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CDocumentBuilder_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new DOM::CDocumentBuilder());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documentbuilder.hxx b/unoxml/source/dom/documentbuilder.hxx
new file mode 100644
index 000000000..b29e0410e
--- /dev/null
+++ b/unoxml/source/dom/documentbuilder.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+
+#include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
+#include <com/sun/star/xml/sax/XEntityResolver.hpp>
+#include <com/sun/star/xml/sax/XErrorHandler.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <mutex>
+
+namespace DOM
+{
+ typedef ::cppu::WeakImplHelper
+ < css::xml::dom::XDocumentBuilder
+ , css::lang::XServiceInfo
+ > CDocumentBuilder_Base;
+
+ class CDocumentBuilder
+ : public CDocumentBuilder_Base
+ {
+ private:
+ std::mutex m_Mutex;
+ css::uno::Reference< css::xml::sax::XEntityResolver > m_xEntityResolver;
+ css::uno::Reference< css::xml::sax::XErrorHandler > m_xErrorHandler;
+
+ public:
+
+ // ctor
+ explicit CDocumentBuilder();
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ /**
+ Obtain an instance of a DOMImplementation object.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDOMImplementation > SAL_CALL getDOMImplementation() override;
+
+ /**
+ Indicates whether or not this parser is configured to understand
+ namespaces.
+ */
+ virtual sal_Bool SAL_CALL isNamespaceAware() override;
+
+ /**
+ Indicates whether or not this parser is configured to validate XML
+ documents.
+ */
+ virtual sal_Bool SAL_CALL isValidating() override;
+
+ /**
+ Obtain a new instance of a DOM Document object to build a DOM tree
+ with.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL newDocument() override;
+
+ /**
+ Parse the content of the given InputStream as an XML document and
+ return a new DOM Document object.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL parse(const css::uno::Reference< css::io::XInputStream >& is) override;
+
+ /**
+ Parse the content of the given URI as an XML document and return
+ a new DOM Document object.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL parseURI(const OUString& uri) override;
+
+ /**
+ Specify the EntityResolver to be used to resolve entities present
+ in the XML document to be parsed.
+ */
+ virtual void SAL_CALL setEntityResolver(const css::uno::Reference< css::xml::sax::XEntityResolver >& er) override;
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::xml::sax::XEntityResolver > getEntityResolver();
+
+
+ /**
+ Specify the ErrorHandler to be used to report errors present in
+ the XML document to be parsed.
+ */
+ virtual void SAL_CALL setErrorHandler(const css::uno::Reference< css::xml::sax::XErrorHandler >& eh) override;
+
+ /*
+ Get the ErrorHandler to be used to report errors present in
+ the XML document to be parsed.
+ */
+
+ const css::uno::Reference< css::xml::sax::XErrorHandler >& getErrorHandler() const
+ {
+ return m_xErrorHandler;
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documentfragment.cxx b/unoxml/source/dom/documentfragment.cxx
new file mode 100644
index 000000000..dd3ed3c18
--- /dev/null
+++ b/unoxml/source/dom/documentfragment.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documentfragment.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CDocumentFragment::CDocumentFragment(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CDocumentFragment_Base(rDocument, rMutex,
+ NodeType_DOCUMENT_FRAGMENT_NODE, pNode)
+ {
+ }
+
+ bool CDocumentFragment::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
+ {
+ switch (nodeType) {
+ case NodeType_ELEMENT_NODE:
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ case NodeType_COMMENT_NODE:
+ case NodeType_TEXT_NODE:
+ case NodeType_CDATA_SECTION_NODE:
+ case NodeType_ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ OUString SAL_CALL CDocumentFragment::getNodeName()
+ {
+ return "#document-fragment";
+ }
+ OUString SAL_CALL CDocumentFragment::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documentfragment.hxx b/unoxml/source/dom/documentfragment.hxx
new file mode 100644
index 000000000..c71edc86a
--- /dev/null
+++ b/unoxml/source/dom/documentfragment.hxx
@@ -0,0 +1,150 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XDocumentFragment.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XDocumentFragment >
+ CDocumentFragment_Base;
+
+ class CDocumentFragment
+ : public CDocumentFragment_Base
+ {
+ friend class CDocument;
+
+ CDocumentFragment(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const*) override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documenttype.cxx b/unoxml/source/dom/documenttype.cxx
new file mode 100644
index 000000000..d79e2d0d0
--- /dev/null
+++ b/unoxml/source/dom/documenttype.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "documenttype.hxx"
+
+#include <string.h>
+
+#include <osl/diagnose.h>
+
+#include "entitiesmap.hxx"
+#include "notationsmap.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+
+ CDocumentType::CDocumentType(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlDtdPtr const pDtd)
+ : CDocumentType_Base(rDocument, rMutex,
+ NodeType_DOCUMENT_TYPE_NODE, reinterpret_cast<xmlNodePtr>(pDtd))
+ , m_aDtdPtr(pDtd)
+ {
+ }
+
+ /**
+ A NamedNodeMap containing the general entities, both external and
+ internal, declared in the DTD.
+ */
+ css::uno::Reference< XNamedNodeMap > SAL_CALL CDocumentType::getEntities()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ css::uno::Reference< XNamedNodeMap > aMap;
+ if (m_aDtdPtr != nullptr)
+ {
+ aMap.set(new CEntitiesMap);
+ }
+ return aMap;
+ }
+
+ /**
+ The internal subset as a string, or null if there is none.
+ */
+ OUString SAL_CALL CDocumentType::getInternalSubset()
+ {
+ OSL_ENSURE(false,
+ "CDocumentType::getInternalSubset: not implemented (#i113683#)");
+ return OUString();
+ }
+
+ /**
+ The name of DTD; i.e., the name immediately following the DOCTYPE
+ keyword.
+ */
+ OUString SAL_CALL CDocumentType::getName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aName;
+ if (m_aDtdPtr != nullptr)
+ {
+ aName = OUString(reinterpret_cast<char const *>(m_aDtdPtr->name), strlen(reinterpret_cast<char const *>(m_aDtdPtr->name)), RTL_TEXTENCODING_UTF8);
+ }
+ return aName;
+ }
+
+ /**
+ A NamedNodeMap containing the notations declared in the DTD.
+ */
+ css::uno::Reference< XNamedNodeMap > SAL_CALL CDocumentType::getNotations()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ css::uno::Reference< XNamedNodeMap > aMap;
+ if (m_aDtdPtr != nullptr)
+ {
+ aMap.set(new CNotationsMap);
+ }
+ return aMap;
+ }
+
+ /**
+ The public identifier of the external subset.
+ */
+ OUString SAL_CALL CDocumentType::getPublicId()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aId;
+ if (m_aDtdPtr != nullptr)
+ {
+ aId = OUString(reinterpret_cast<char const *>(m_aDtdPtr->name), strlen(reinterpret_cast<char const *>(m_aDtdPtr->ExternalID)), RTL_TEXTENCODING_UTF8);
+ }
+ return aId;
+ }
+
+ /**
+ The system identifier of the external subset.
+ */
+ OUString SAL_CALL CDocumentType::getSystemId()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aId;
+ if (m_aDtdPtr != nullptr)
+ {
+ aId = OUString(reinterpret_cast<char const *>(m_aDtdPtr->name), strlen(reinterpret_cast<char const *>(m_aDtdPtr->SystemID)), RTL_TEXTENCODING_UTF8);
+ }
+ return aId;
+ }
+
+ OUString SAL_CALL CDocumentType::getNodeName()
+ {
+ return getName();
+ }
+
+ OUString SAL_CALL CDocumentType::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/documenttype.hxx b/unoxml/source/dom/documenttype.hxx
new file mode 100644
index 000000000..48f857bf7
--- /dev/null
+++ b/unoxml/source/dom/documenttype.hxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XDocumentType.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XDocumentType >
+ CDocumentType_Base;
+
+ class CDocumentType
+ : public CDocumentType_Base
+ {
+ private:
+ friend class CDocument;
+
+ xmlDtdPtr m_aDtdPtr;
+
+ CDocumentType(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlDtdPtr const pDtd);
+
+ public:
+ /**
+ A NamedNodeMap containing the general entities, both external and
+ internal, declared in the DTD.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getEntities() override;
+
+ /**
+ The internal subset as a string, or null if there is none.
+ */
+ virtual OUString SAL_CALL getInternalSubset() override;
+
+ /**
+ The name of DTD; i.e., the name immediately following the DOCTYPE
+ keyword.
+ */
+ virtual OUString SAL_CALL getName() override;
+
+ /**
+ A NamedNodeMap containing the notations declared in the DTD.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getNotations() override;
+
+ /**
+ The public identifier of the external subset.
+ */
+ virtual OUString SAL_CALL getPublicId() override;
+
+ /**
+ The system identifier of the external subset.
+ */
+ virtual OUString SAL_CALL getSystemId() override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/domimplementation.cxx b/unoxml/source/dom/domimplementation.cxx
new file mode 100644
index 000000000..0bd7e5940
--- /dev/null
+++ b/unoxml/source/dom/domimplementation.cxx
@@ -0,0 +1,80 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "domimplementation.hxx"
+
+#include <osl/diagnose.h>
+#include <rtl/ref.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CDOMImplementation* CDOMImplementation::get()
+ {
+ // why the heck is this thing static?
+ // perhaps it would be helpful to know what the implementation should
+ // do to answer this question...
+ static rtl::Reference<CDOMImplementation> xDOMImplementation = new CDOMImplementation;
+ return &*xDOMImplementation;
+ }
+
+ // there is just 1 static instance, so these must not delete it!
+ void SAL_CALL CDOMImplementation::acquire() noexcept { }
+ void SAL_CALL CDOMImplementation::release() noexcept { }
+
+ /**
+ Creates a DOM Document object of the specified type with its document element.
+ */
+ Reference <XDocument > SAL_CALL CDOMImplementation::createDocument(
+ OUString const& /*rNamespaceURI*/,
+ OUString const& /*rQualifiedName*/,
+ Reference< XDocumentType > const& /*xDoctype*/)
+ {
+ OSL_ENSURE(false,
+ "CDOMImplementation::createDocument: not implemented (#i113683#)");
+ return Reference<XDocument>();
+ }
+
+ /**
+ Creates an empty DocumentType node.
+ */
+ Reference< XDocumentType > SAL_CALL CDOMImplementation::createDocumentType(
+ OUString const& /*rQualifiedName*/,
+ OUString const& /*rPublicId*/, OUString const& /*rSystemId*/)
+ {
+ OSL_ENSURE(false, "CDOMImplementation::createDocumentType: "
+ "not implemented (#i113683#)");
+ return Reference<XDocumentType>();
+ }
+
+ /**
+ Test if the DOM implementation implements a specific feature.
+ */
+ sal_Bool SAL_CALL
+ CDOMImplementation::hasFeature(OUString const& /*feature*/, OUString const& /*ver*/)
+ {
+ OSL_ENSURE(false,
+ "CDOMImplementation::hasFeature: not implemented (#i113683#)");
+ return false;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/domimplementation.hxx b/unoxml/source/dom/domimplementation.hxx
new file mode 100644
index 000000000..955a4e32e
--- /dev/null
+++ b/unoxml/source/dom/domimplementation.hxx
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/xml/dom/XDocumentType.hpp>
+#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace DOM
+{
+ class CDOMImplementation
+ : public cppu::WeakImplHelper< css::xml::dom::XDOMImplementation >
+ {
+
+ public:
+ static CDOMImplementation* get();
+
+ // there is just 1 static instance, so these must not delete it!
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ /**
+ Creates a DOM Document object of the specified type with its document element.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL createDocument(const OUString& namespaceURI, const OUString& qualifiedName, const css::uno::Reference< css::xml::dom::XDocumentType >& doctype) override;
+
+ /**
+ Creates an empty DocumentType node.
+ */
+ virtual css::uno::Reference< css::xml::dom::XDocumentType > SAL_CALL createDocumentType(const OUString& qualifiedName, const OUString& publicId, const OUString& systemId) override;
+
+ /**
+ Test if the DOM implementation implements a specific feature.
+ */
+ virtual sal_Bool SAL_CALL hasFeature(const OUString& feature, const OUString& ver) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/element.cxx b/unoxml/source/dom/element.cxx
new file mode 100644
index 000000000..61109de6b
--- /dev/null
+++ b/unoxml/source/dom/element.cxx
@@ -0,0 +1,756 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "element.hxx"
+
+#include <string.h>
+
+#include <memory>
+
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+
+#include <com/sun/star/xml/dom/DOMException.hpp>
+#include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
+#include <com/sun/star/xml/sax/FastToken.hpp>
+
+#include <comphelper/attributelist.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <node.hxx>
+#include "attr.hxx"
+#include "elementlist.hxx"
+#include "attributesmap.hxx"
+#include "document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+
+ CElement::CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CElement_Base(rDocument, rMutex, NodeType_ELEMENT_NODE, pNode)
+ {
+ }
+
+ void CElement::saxify(const Reference< XDocumentHandler >& i_xHandler)
+ {
+ if (!i_xHandler.is()) throw RuntimeException();
+ rtl::Reference<comphelper::AttributeList> pAttrs =
+ new comphelper::AttributeList();
+ OUString type = "";
+ // add namespace definitions to attributes
+ for (xmlNsPtr pNs = m_aNodePtr->nsDef; pNs != nullptr; pNs = pNs->next) {
+ const xmlChar *pPrefix = pNs->prefix ? pNs->prefix : reinterpret_cast<const xmlChar*>("");
+ OUString prefix(reinterpret_cast<const char*>(pPrefix),
+ strlen(reinterpret_cast<const char*>(pPrefix)),
+ RTL_TEXTENCODING_UTF8);
+ OUString name = (prefix.isEmpty())
+ ? OUString( "xmlns" ) : "xmlns:" + prefix;
+ const xmlChar *pHref = pNs->href;
+ OUString val(reinterpret_cast<const char*>(pHref),
+ strlen(reinterpret_cast<const char*>(pHref)),
+ RTL_TEXTENCODING_UTF8);
+ pAttrs->AddAttribute(name, type, val);
+ }
+ // add attributes
+ for (xmlAttrPtr pAttr = m_aNodePtr->properties;
+ pAttr != nullptr; pAttr = pAttr->next) {
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr));
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+ OUString prefix = pNode->getPrefix();
+ OUString name = (prefix.isEmpty())
+ ? pNode->getLocalName()
+ : prefix + ":" + pNode->getLocalName();
+ OUString val = pNode->getNodeValue();
+ pAttrs->AddAttribute(name, type, val);
+ }
+ OUString prefix = getPrefix();
+ OUString name = (prefix.isEmpty())
+ ? getLocalName()
+ : prefix + ":" + getLocalName();
+ i_xHandler->startElement(name, pAttrs);
+ // recurse
+ for (xmlNodePtr pChild = m_aNodePtr->children;
+ pChild != nullptr; pChild = pChild->next) {
+ ::rtl::Reference<CNode> const pNode(
+ GetOwnerDocument().GetCNode(pChild));
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+ pNode->saxify(i_xHandler);
+ }
+ i_xHandler->endElement(name);
+ }
+
+ void CElement::fastSaxify( Context& i_rContext )
+ {
+ if (!i_rContext.mxDocHandler.is()) throw RuntimeException();
+ pushContext(i_rContext);
+ addNamespaces(i_rContext,m_aNodePtr);
+
+ // add attributes
+ i_rContext.mxAttribList->clear();
+ for (xmlAttrPtr pAttr = m_aNodePtr->properties;
+ pAttr != nullptr; pAttr = pAttr->next) {
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr));
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+
+ const xmlChar* pName = pAttr->name;
+ sal_Int32 nAttributeToken=FastToken::DONTKNOW;
+
+ if( pAttr->ns && strlen(reinterpret_cast<char const *>(pAttr->ns->prefix)) )
+ nAttributeToken = getTokenWithPrefix( i_rContext,
+ reinterpret_cast<char const *>(pAttr->ns->prefix),
+ reinterpret_cast<char const *>(pName) );
+ else
+ nAttributeToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) );
+
+ if( nAttributeToken != FastToken::DONTKNOW )
+ i_rContext.mxAttribList->add( nAttributeToken,
+ OUStringToOString(pNode->getNodeValue(),
+ RTL_TEXTENCODING_UTF8));
+ }
+
+ const xmlChar* pPrefix = (m_aNodePtr->ns && m_aNodePtr->ns->prefix) ? m_aNodePtr->ns->prefix : reinterpret_cast<const xmlChar*>("");
+ const xmlChar* pName = m_aNodePtr->name;
+ sal_Int32 nElementToken=FastToken::DONTKNOW;
+ if( strlen(reinterpret_cast<char const *>(pPrefix)) )
+ nElementToken = getTokenWithPrefix( i_rContext, reinterpret_cast<char const *>(pPrefix), reinterpret_cast<char const *>(pName) );
+ else
+ nElementToken = getToken( i_rContext, reinterpret_cast<char const *>(pName) );
+
+ Reference<XFastContextHandler> xParentHandler(i_rContext.mxCurrentHandler);
+ try
+ {
+ Reference< XFastAttributeList > xAttr( i_rContext.mxAttribList );
+ if( nElementToken == FastToken::DONTKNOW )
+ {
+ const OUString aNamespace;
+ const OUString aElementName( reinterpret_cast<char const *>(pPrefix),
+ strlen(reinterpret_cast<char const *>(pPrefix)),
+ RTL_TEXTENCODING_UTF8 );
+
+ if( xParentHandler.is() )
+ i_rContext.mxCurrentHandler = xParentHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
+ else
+ i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createUnknownChildContext( aNamespace, aElementName, xAttr );
+
+ if( i_rContext.mxCurrentHandler.is() )
+ i_rContext.mxCurrentHandler->startUnknownElement( aNamespace, aElementName, xAttr );
+ }
+ else
+ {
+ if( xParentHandler.is() )
+ i_rContext.mxCurrentHandler = xParentHandler->createFastChildContext( nElementToken, xAttr );
+ else
+ i_rContext.mxCurrentHandler = i_rContext.mxDocHandler->createFastChildContext( nElementToken, xAttr );
+
+ if( i_rContext.mxCurrentHandler.is() )
+ i_rContext.mxCurrentHandler->startFastElement( nElementToken, xAttr );
+ }
+ }
+ catch( Exception& )
+ {}
+
+ // recurse
+ for (xmlNodePtr pChild = m_aNodePtr->children;
+ pChild != nullptr; pChild = pChild->next) {
+ ::rtl::Reference<CNode> const pNode(
+ GetOwnerDocument().GetCNode(pChild));
+ OSL_ENSURE(pNode != nullptr, "CNode::get returned 0");
+ pNode->fastSaxify(i_rContext);
+ }
+
+ if( i_rContext.mxCurrentHandler.is() ) try
+ {
+ if( nElementToken != FastToken::DONTKNOW )
+ i_rContext.mxCurrentHandler->endFastElement( nElementToken );
+ else
+ {
+ const OUString aElementName( reinterpret_cast<char const *>(pPrefix),
+ strlen(reinterpret_cast<char const *>(pPrefix)),
+ RTL_TEXTENCODING_UTF8 );
+
+ i_rContext.mxCurrentHandler->endUnknownElement( "", aElementName );
+ }
+ }
+ catch( Exception& )
+ {}
+
+ // restore after children have been processed
+ i_rContext.mxCurrentHandler = xParentHandler;
+ popContext(i_rContext);
+ }
+
+ bool CElement::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
+ {
+ switch (nodeType) {
+ case NodeType_ELEMENT_NODE:
+ case NodeType_TEXT_NODE:
+ case NodeType_COMMENT_NODE:
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ case NodeType_CDATA_SECTION_NODE:
+ case NodeType_ENTITY_REFERENCE_NODE:
+ return true;
+ case NodeType_ATTRIBUTE_NODE:
+ /* this is not really allowed by the DOM spec, but this
+ implementation has evidently supported it (by special case
+ handling, so the attribute does not actually become a child)
+ so allow it for backward compatibility */
+ return true;
+ default:
+ return false;
+ }
+ }
+
+
+ /**
+ Retrieves an attribute value by name.
+ return empty string if attribute is not set
+ */
+ OUString SAL_CALL CElement::getAttribute(OUString const& name)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+ // search properties
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ std::shared_ptr<xmlChar const> const pValue(
+ xmlGetProp(m_aNodePtr, reinterpret_cast<xmlChar const *>(o1.getStr())), xmlFree);
+ OUString const ret( pValue
+ ? OUString(reinterpret_cast<char const*>(pValue.get()),
+ strlen(reinterpret_cast<char const*>(pValue.get())),
+ RTL_TEXTENCODING_UTF8)
+ : OUString() );
+ return ret;
+ }
+
+ /**
+ Retrieves an attribute node by name.
+ */
+ Reference< XAttr > SAL_CALL CElement::getAttributeNode(OUString const& name)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pName =
+ reinterpret_cast<xmlChar const*>(o1.getStr());
+ xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
+ if (nullptr == pAttr) {
+ return nullptr;
+ }
+ Reference< XAttr > const xRet(
+ static_cast< XNode* >(GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr)).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ /**
+ Retrieves an Attr node by local name and namespace URI.
+ */
+ Reference< XAttr > SAL_CALL CElement::getAttributeNodeNS(
+ const OUString& namespaceURI, const OUString& localName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pName =
+ reinterpret_cast<xmlChar const*>(o1.getStr());
+ OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pNS =
+ reinterpret_cast<xmlChar const*>(o2.getStr());
+ xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pNS);
+ if (nullptr == pAttr) {
+ return nullptr;
+ }
+ Reference< XAttr > const xRet(
+ static_cast< XNode* >(GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr)).get()),
+ UNO_QUERY_THROW);
+ return xRet;
+ }
+
+ /**
+ Retrieves an attribute value by local name and namespace URI.
+ return empty string if attribute is not set
+ */
+ OUString SAL_CALL
+ CElement::getAttributeNS(
+ OUString const& namespaceURI, OUString const& localName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+ OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pName =
+ reinterpret_cast<xmlChar const*>(o1.getStr());
+ OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pNS =
+ reinterpret_cast<xmlChar const*>(o2.getStr());
+ std::shared_ptr<xmlChar const> const pValue(
+ xmlGetNsProp(m_aNodePtr, pName, pNS), xmlFree);
+ if (nullptr == pValue) {
+ return OUString();
+ }
+ OUString const ret(reinterpret_cast<char const*>(pValue.get()),
+ strlen(reinterpret_cast<char const*>(pValue.get())),
+ RTL_TEXTENCODING_UTF8);
+ return ret;
+ }
+
+ /**
+ Returns a NodeList of all descendant Elements with a given tag name,
+ in the order in which they are
+ encountered in a preorder traversal of this Element tree.
+ */
+ Reference< XNodeList > SAL_CALL
+ CElement::getElementsByTagName(OUString const& rLocalName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNodeList > const xList(
+ new CElementList(this, m_rMutex, rLocalName));
+ return xList;
+ }
+
+ /**
+ Returns a NodeList of all the descendant Elements with a given local
+ name and namespace URI in the order in which they are encountered in
+ a preorder traversal of this Element tree.
+ */
+ Reference< XNodeList > SAL_CALL
+ CElement::getElementsByTagNameNS(
+ OUString const& rNamespaceURI, OUString const& rLocalName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNodeList > const xList(
+ new CElementList(this, m_rMutex, rLocalName, &rNamespaceURI));
+ return xList;
+ }
+
+ /**
+ The name of the element.
+ */
+ OUString SAL_CALL CElement::getTagName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+ OUString const ret(reinterpret_cast<char const *>(m_aNodePtr->name),
+ strlen(reinterpret_cast<char const *>(m_aNodePtr->name)), RTL_TEXTENCODING_UTF8);
+ return ret;
+ }
+
+
+ /**
+ Returns true when an attribute with a given name is specified on this
+ element or has a default value, false otherwise.
+ */
+ sal_Bool SAL_CALL CElement::hasAttribute(OUString const& name)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ return (m_aNodePtr != nullptr && xmlHasProp(m_aNodePtr, pName) != nullptr);
+ }
+
+ /**
+ Returns true when an attribute with a given local name and namespace
+ URI is specified on this element or has a default value, false otherwise.
+ */
+ sal_Bool SAL_CALL CElement::hasAttributeNS(
+ OUString const& namespaceURI, OUString const& localName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pNs = reinterpret_cast<xmlChar const *>(o2.getStr());
+ return (m_aNodePtr != nullptr && xmlHasNsProp(m_aNodePtr, pName, pNs) != nullptr);
+ }
+
+ /**
+ Removes an attribute by name.
+ */
+ void SAL_CALL CElement::removeAttribute(OUString const& name)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return;
+ }
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pName =
+ reinterpret_cast<xmlChar const*>(o1.getStr());
+ xmlAttrPtr const pAttr = xmlHasProp(m_aNodePtr, pName);
+ if (0 == xmlUnsetProp(m_aNodePtr, pName)) {
+ ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr), false));
+ if (pCNode.is()) {
+ pCNode->invalidate(); // freed by xmlUnsetProp
+ }
+ }
+ }
+
+ /**
+ Removes an attribute by local name and namespace URI.
+ */
+ void SAL_CALL CElement::removeAttributeNS(
+ OUString const& namespaceURI, OUString const& localName)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return;
+ }
+ OString o1 = OUStringToOString(localName, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pName =
+ reinterpret_cast<xmlChar const*>(o1.getStr());
+ OString o2 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ xmlChar const*const pURI =
+ reinterpret_cast<xmlChar const*>(o2.getStr());
+ xmlNsPtr const pNs =
+ xmlSearchNsByHref(m_aNodePtr->doc, m_aNodePtr, pURI);
+ xmlAttrPtr const pAttr = xmlHasNsProp(m_aNodePtr, pName, pURI);
+ if (0 == xmlUnsetNsProp(m_aNodePtr, pNs, pName)) {
+ ::rtl::Reference<CNode> const pCNode(GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(pAttr), false));
+ if (pCNode.is()) {
+ pCNode->invalidate(); // freed by xmlUnsetNsProp
+ }
+ }
+ }
+
+ /**
+ Removes the specified attribute node.
+ */
+ Reference< XAttr > SAL_CALL
+ CElement::removeAttributeNode(Reference< XAttr > const& oldAttr)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+
+ ::rtl::Reference<CNode> const pCNode(
+ comphelper::getFromUnoTunnel<CNode>(Reference<XNode>(oldAttr)));
+ if (!pCNode.is()) { throw RuntimeException(); }
+
+ xmlNodePtr const pNode = pCNode->GetNodePtr();
+ xmlAttrPtr const pAttr = reinterpret_cast<xmlAttrPtr>(pNode);
+ if (!pAttr) { throw RuntimeException(); }
+
+ if (pAttr->parent != m_aNodePtr)
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (pAttr->doc != m_aNodePtr->doc)
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+
+ Reference< XAttr > aAttr;
+ if (!oldAttr->getNamespaceURI().isEmpty()) {
+ OUStringBuffer qname(oldAttr->getPrefix());
+ if (!qname.isEmpty()) {
+ qname.append(':');
+ }
+ qname.append(oldAttr->getName());
+ aAttr = GetOwnerDocument().createAttributeNS(
+ oldAttr->getNamespaceURI(), qname.makeStringAndClear());
+ } else {
+ aAttr = GetOwnerDocument().createAttribute(oldAttr->getName());
+ }
+ aAttr->setValue(oldAttr->getValue());
+ xmlRemoveProp(pAttr);
+ pCNode->invalidate(); // freed by xmlRemoveProp
+
+ return aAttr;
+ }
+
+ /**
+ Adds a new attribute node.
+ */
+ Reference< XAttr >
+ CElement::setAttributeNode_Impl_Lock(
+ Reference< XAttr > const& xNewAttr, bool const bNS)
+ {
+ if (xNewAttr->getOwnerDocument() != getOwnerDocument()) {
+ DOMException e;
+ e.Code = DOMExceptionType_WRONG_DOCUMENT_ERR;
+ throw e;
+ }
+
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ throw RuntimeException();
+ }
+
+ // get the implementation
+ CAttr *const pCAttr = dynamic_cast<CAttr*>(
+ comphelper::getFromUnoTunnel<CNode>(xNewAttr));
+ if (!pCAttr) { throw RuntimeException(); }
+ xmlAttrPtr const pAttr =
+ reinterpret_cast<xmlAttrPtr>(pCAttr->GetNodePtr());
+ if (!pAttr) { throw RuntimeException(); }
+
+ // check whether the attribute is not in use by another element
+ if (pAttr->parent) {
+ DOMException e;
+ e.Code = DOMExceptionType_INUSE_ATTRIBUTE_ERR;
+ throw e;
+ }
+
+ xmlAttrPtr res = nullptr;
+ xmlChar const*const pContent(
+ (pAttr->children) ? pAttr->children->content : nullptr);
+
+ if (bNS) {
+ xmlNsPtr const pNs( pCAttr->GetNamespace(m_aNodePtr) );
+ res = xmlNewNsProp(m_aNodePtr, pNs, pAttr->name, pContent);
+ } else {
+ res = xmlNewProp(m_aNodePtr, pAttr->name, pContent);
+ }
+
+ // get the new attr node
+ Reference< XAttr > const xAttr(
+ static_cast< XNode* >(GetOwnerDocument().GetCNode(
+ reinterpret_cast<xmlNodePtr>(res)).get()),
+ UNO_QUERY_THROW);
+
+ // attribute addition event
+ // dispatch DOMAttrModified event
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMAttrModified"), UNO_QUERY);
+ event->initMutationEvent("DOMAttrModified",
+ true, false, xAttr,
+ OUString(), xAttr->getValue(), xAttr->getName(),
+ AttrChangeType_ADDITION);
+
+ guard.clear(); // release mutex before calling event handlers
+
+ dispatchEvent(event);
+ dispatchSubtreeModified();
+
+ return xAttr;
+ }
+
+ Reference< XAttr >
+ CElement::setAttributeNode(const Reference< XAttr >& newAttr)
+ {
+ return setAttributeNode_Impl_Lock(newAttr, false);
+ }
+
+ /**
+ Adds a new attribute.
+ */
+ Reference< XAttr >
+ CElement::setAttributeNodeNS(const Reference< XAttr >& newAttr)
+ {
+ return setAttributeNode_Impl_Lock(newAttr, true);
+ }
+
+ /**
+ Adds a new attribute.
+ */
+ void SAL_CALL
+ CElement::setAttribute(OUString const& name, OUString const& value)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ OString o1 = OUStringToOString(name, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ OString o2 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o2.getStr());
+
+ if (nullptr == m_aNodePtr) {
+ throw RuntimeException();
+ }
+ OUString oldValue;
+ AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
+ std::shared_ptr<xmlChar const> const pOld(
+ xmlGetProp(m_aNodePtr, pName), xmlFree);
+ if (pOld == nullptr) {
+ aChangeType = AttrChangeType_ADDITION;
+ xmlNewProp(m_aNodePtr, pName, pValue);
+ } else {
+ oldValue = OUString(reinterpret_cast<char const*>(pOld.get()),
+ strlen(reinterpret_cast<char const*>(pOld.get())),
+ RTL_TEXTENCODING_UTF8);
+ xmlSetProp(m_aNodePtr, pName, pValue);
+ }
+
+ // dispatch DOMAttrModified event
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMAttrModified"), UNO_QUERY);
+ event->initMutationEvent("DOMAttrModified",
+ true, false,
+ getAttributeNode(name),
+ oldValue, value, name, aChangeType);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent(event);
+ dispatchSubtreeModified();
+ }
+
+ /**
+ Adds a new attribute.
+ */
+ void SAL_CALL
+ CElement::setAttributeNS(OUString const& namespaceURI,
+ OUString const& qualifiedName, OUString const& value)
+ {
+ if (namespaceURI.isEmpty()) throw RuntimeException();
+
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ OString o1, o2, o3, o4, o5;
+ xmlChar const *pPrefix = nullptr;
+ xmlChar const *pLName = nullptr;
+ o1 = OUStringToOString(qualifiedName, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pQName = reinterpret_cast<xmlChar const *>(o1.getStr());
+ sal_Int32 idx = qualifiedName.indexOf(':');
+ if (idx != -1)
+ {
+ o2 = OUStringToOString(
+ qualifiedName.subView(0,idx),
+ RTL_TEXTENCODING_UTF8);
+ pPrefix = reinterpret_cast<xmlChar const *>(o2.getStr());
+ o3 = OUStringToOString(
+ qualifiedName.subView(idx+1),
+ RTL_TEXTENCODING_UTF8);
+ pLName = reinterpret_cast<xmlChar const *>(o3.getStr());
+ } else {
+ pPrefix = reinterpret_cast<xmlChar const *>("");
+ pLName = pQName;
+ }
+ o4 = OUStringToOString(namespaceURI, RTL_TEXTENCODING_UTF8);
+ o5 = OUStringToOString(value, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pURI= reinterpret_cast<xmlChar const *>(o4.getStr());
+ xmlChar const *pValue = reinterpret_cast<xmlChar const *>(o5.getStr());
+
+ if (nullptr == m_aNodePtr) {
+ throw RuntimeException();
+ }
+
+ //find the right namespace
+ xmlNsPtr pNs = xmlSearchNs(m_aNodePtr->doc, m_aNodePtr, pPrefix);
+ // if no namespace found, create a new one
+ if (pNs == nullptr) {
+ pNs = xmlNewNs(m_aNodePtr, pURI, pPrefix);
+ }
+
+ if (strcmp(reinterpret_cast<char const *>(pNs->href), reinterpret_cast<char const *>(pURI)) != 0) {
+ // ambiguous ns prefix
+ throw RuntimeException();
+ }
+
+ // found namespace matches
+
+ OUString oldValue;
+ AttrChangeType aChangeType = AttrChangeType_MODIFICATION;
+ std::shared_ptr<xmlChar const> const pOld(
+ xmlGetNsProp(m_aNodePtr, pLName, pNs->href), xmlFree);
+ if (pOld == nullptr) {
+ aChangeType = AttrChangeType_ADDITION;
+ xmlNewNsProp(m_aNodePtr, pNs, pLName, pValue);
+ } else {
+ oldValue = OUString(reinterpret_cast<char const*>(pOld.get()),
+ strlen(reinterpret_cast<char const*>(pOld.get())),
+ RTL_TEXTENCODING_UTF8);
+ xmlSetNsProp(m_aNodePtr, pNs, pLName, pValue);
+ }
+ // dispatch DOMAttrModified event
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMAttrModified"), UNO_QUERY);
+ event->initMutationEvent(
+ "DOMAttrModified", true, false,
+ getAttributeNodeNS(namespaceURI, OUString(reinterpret_cast<char const *>(pLName), strlen(reinterpret_cast<char const *>(pLName)), RTL_TEXTENCODING_UTF8)),
+ oldValue, value, qualifiedName, aChangeType);
+
+ guard.clear(); // release mutex before calling event handlers
+ dispatchEvent(event);
+ dispatchSubtreeModified();
+ }
+
+ Reference< XNamedNodeMap > SAL_CALL
+ CElement::getAttributes()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNamedNodeMap > const xMap(
+ new CAttributesMap(this, m_rMutex));
+ return xMap;
+ }
+
+ OUString SAL_CALL CElement::getNodeName()
+ {
+ return getLocalName();
+ }
+
+ OUString SAL_CALL CElement::getLocalName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aName;
+ if (m_aNodePtr != nullptr)
+ {
+ const xmlChar* pName = m_aNodePtr->name;
+ aName = OUString(reinterpret_cast<const char*>(pName), strlen(reinterpret_cast<const char*>(pName)), RTL_TEXTENCODING_UTF8);
+ }
+ return aName;
+ }
+
+ OUString SAL_CALL CElement::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/element.hxx b/unoxml/source/dom/element.hxx
new file mode 100644
index 000000000..3810e0935
--- /dev/null
+++ b/unoxml/source/dom/element.hxx
@@ -0,0 +1,246 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+#include <com/sun/star/xml/dom/NodeType.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper<CNode, css::xml::dom::XElement > CElement_Base;
+
+ class CElement
+ : public CElement_Base
+ {
+ private:
+ friend class CDocument;
+
+ css::uno::Reference< css::xml::dom::XAttr > setAttributeNode_Impl_Lock(
+ css::uno::Reference< css::xml::dom::XAttr > const& xNewAttr, bool const bNS);
+
+ protected:
+ CElement(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ virtual void fastSaxify( Context& i_rContext ) override;
+
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const*) override;
+
+ /**
+ Retrieves an attribute value by name.
+ */
+ virtual OUString SAL_CALL getAttribute(const OUString& name) override;
+
+ /**
+ Retrieves an attribute node by name.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL getAttributeNode(const OUString& name) override;
+
+ /**
+ Retrieves an Attr node by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL getAttributeNodeNS(const OUString& namespaceURI, const OUString& localName) override;
+
+ /**
+ Retrieves an attribute value by local name and namespace URI.
+ */
+ virtual OUString SAL_CALL getAttributeNS(const OUString& namespaceURI, const OUString& localName) override;
+
+ /**
+ Returns a NodeList of all descendant Elements with a given tag name,
+ in the order in which they are
+ encountered in a preorder traversal of this Element tree.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getElementsByTagName(const OUString& name) override;
+
+ /**
+ Returns a NodeList of all the descendant Elements with a given local
+ name and namespace URI in the order in which they are encountered in
+ a preorder traversal of this Element tree.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI,
+ const OUString& localName) override;
+
+ /**
+ The name of the element.
+ */
+ virtual OUString SAL_CALL getTagName() override;
+
+ /**
+ Returns true when an attribute with a given name is specified on this
+ element or has a default value, false otherwise.
+ */
+ virtual sal_Bool SAL_CALL hasAttribute(const OUString& name) override;
+
+ /**
+ Returns true when an attribute with a given local name and namespace
+ URI is specified on this element or has a default value, false otherwise.
+ */
+ virtual sal_Bool SAL_CALL hasAttributeNS(const OUString& namespaceURI, const OUString& localName) override;
+
+ /**
+ Removes an attribute by name.
+ */
+ virtual void SAL_CALL removeAttribute(const OUString& name) override;
+
+ /**
+ Removes the specified attribute node.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL removeAttributeNode(const css::uno::Reference< css::xml::dom::XAttr >& oldAttr) override;
+
+ /**
+ Removes an attribute by local name and namespace URI.
+ */
+ virtual void SAL_CALL removeAttributeNS(const OUString& namespaceURI, const OUString& localName) override;
+
+ /**
+ Adds a new attribute.
+ */
+ virtual void SAL_CALL setAttribute(const OUString& name, const OUString& value) override;
+
+ /**
+ Adds a new attribute node.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL setAttributeNode(const css::uno::Reference< css::xml::dom::XAttr >& newAttr) override;
+
+ /**
+ Adds a new attribute.
+ */
+ virtual css::uno::Reference< css::xml::dom::XAttr > SAL_CALL setAttributeNodeNS(const css::uno::Reference< css::xml::dom::XAttr >& newAttr) override;
+
+ /**
+ Adds a new attribute.
+ */
+ virtual void SAL_CALL setAttributeNS(
+ const OUString& namespaceURI, const OUString& qualifiedName, const OUString& value) override;
+
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override;
+ virtual OUString SAL_CALL getLocalName() override;
+
+ // resolve uno inheritance problems...
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/elementlist.cxx b/unoxml/source/dom/elementlist.cxx
new file mode 100644
index 000000000..c8fc60437
--- /dev/null
+++ b/unoxml/source/dom/elementlist.cxx
@@ -0,0 +1,191 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "elementlist.hxx"
+
+#include <string.h>
+#include <string_view>
+
+#include <cppuhelper/implbase.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/diagnose_ex.h>
+
+#include "element.hxx"
+#include "document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+
+namespace
+{
+ class WeakEventListener : public ::cppu::WeakImplHelper<css::xml::dom::events::XEventListener>
+ {
+ private:
+ css::uno::WeakReference<css::xml::dom::events::XEventListener> mxOwner;
+
+ public:
+ explicit WeakEventListener(const css::uno::Reference<css::xml::dom::events::XEventListener>& rOwner)
+ : mxOwner(rOwner)
+ {
+ }
+
+ virtual void SAL_CALL handleEvent(const css::uno::Reference<css::xml::dom::events::XEvent>& rEvent) override
+ {
+ css::uno::Reference<css::xml::dom::events::XEventListener> xOwner(mxOwner.get(),
+ css::uno::UNO_QUERY);
+ if (xOwner.is())
+ xOwner->handleEvent(rEvent);
+ }
+ };
+}
+
+namespace DOM
+{
+
+ static xmlChar* lcl_initXmlString(std::u16string_view rString)
+ {
+ OString const os =
+ OUStringToOString(rString, RTL_TEXTENCODING_UTF8);
+ xmlChar *const pRet = new xmlChar[os.getLength() + 1];
+ strcpy(reinterpret_cast<char*>(pRet), os.getStr());
+ return pRet;
+ }
+
+ CElementList::CElementList(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex,
+ std::u16string_view rName, OUString const*const pURI)
+ : m_xImpl(new CElementListImpl(pElement, rMutex, rName, pURI))
+ {
+ if (pElement.is()) {
+ m_xImpl->registerListener(*pElement);
+ }
+ }
+
+ CElementListImpl::CElementListImpl(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex,
+ std::u16string_view rName, OUString const*const pURI)
+ : m_pElement(pElement)
+ , m_rMutex(rMutex)
+ , m_pName(lcl_initXmlString(rName))
+ , m_pURI(pURI ? lcl_initXmlString(*pURI) : nullptr)
+ , m_bRebuild(true)
+ {
+ }
+
+ CElementListImpl::~CElementListImpl()
+ {
+ if (m_xEventListener.is() && m_pElement.is())
+ {
+ Reference< XEventTarget > xTarget = m_pElement;
+ assert(xTarget.is());
+ if (!xTarget.is())
+ return;
+ xTarget->removeEventListener("DOMSubtreeModified", m_xEventListener, false/*capture*/);
+ }
+ }
+
+ void CElementListImpl::registerListener(CElement & rElement)
+ {
+ try {
+ Reference< XEventTarget > const xTarget(
+ static_cast<XElement*>(& rElement), UNO_QUERY_THROW);
+ m_xEventListener = new WeakEventListener(this);
+ xTarget->addEventListener("DOMSubtreeModified", m_xEventListener, false/*capture*/);
+ } catch (const Exception &){
+ TOOLS_WARN_EXCEPTION( "unoxml", "Exception caught while registering NodeList as listener");
+ }
+ }
+
+ void CElementListImpl::buildlist(xmlNodePtr pNode, bool start)
+ {
+ // bail out if no rebuild is needed
+ if (start) {
+ if (!m_bRebuild)
+ {
+ return;
+ } else {
+ m_nodevector.clear();
+ m_bRebuild = false; // don't rebuild until tree is mutated
+ }
+ }
+
+ while (pNode != nullptr )
+ {
+ if (pNode->type == XML_ELEMENT_NODE &&
+ (strcmp(reinterpret_cast<char const *>(pNode->name), reinterpret_cast<char*>(m_pName.get())) == 0))
+ {
+ if (!m_pURI) {
+ m_nodevector.push_back(pNode);
+ } else {
+ if (pNode->ns != nullptr && (0 ==
+ strcmp(reinterpret_cast<char const *>(pNode->ns->href), reinterpret_cast<char*>(m_pURI.get()))))
+ {
+ m_nodevector.push_back(pNode);
+ }
+ }
+ }
+ if (pNode->children != nullptr) buildlist(pNode->children, false);
+
+ if (!start) pNode = pNode->next;
+ else break; // fold back
+ }
+ }
+
+ /**
+ The number of nodes in the list.
+ */
+ sal_Int32 SAL_CALL CElementListImpl::getLength()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (!m_pElement.is()) { return 0; }
+
+ // this has to be 'live'
+ buildlist(m_pElement->GetNodePtr());
+ return m_nodevector.size();
+ }
+ /**
+ Returns the indexth item in the collection.
+ */
+ Reference< XNode > SAL_CALL CElementListImpl::item(sal_Int32 index)
+ {
+ if (index < 0) throw RuntimeException();
+
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (!m_pElement.is()) { return nullptr; }
+
+ buildlist(m_pElement->GetNodePtr());
+ if (m_nodevector.size() <= o3tl::make_unsigned(index)) {
+ throw RuntimeException();
+ }
+ return m_pElement->GetOwnerDocument().GetCNode(m_nodevector[index]);
+ }
+
+ // tree mutations can change the list
+ void SAL_CALL CElementListImpl::handleEvent(Reference< XEvent > const&)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ m_bRebuild = true;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/elementlist.hxx b/unoxml/source/dom/elementlist.hxx
new file mode 100644
index 000000000..66ce3beda
--- /dev/null
+++ b/unoxml/source/dom/elementlist.hxx
@@ -0,0 +1,118 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+#include <string_view>
+#include <memory>
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/dom/events/XEvent.hpp>
+#include <com/sun/star/xml/dom/events/XEventListener.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace DOM
+{
+ class CElement;
+
+ class CElementListImpl
+ : public cppu::WeakImplHelper< css::xml::dom::XNodeList,
+ css::xml::dom::events::XEventListener >
+ {
+ private:
+ /** @short proxy weak binding to forward Events to ourself without
+ an ownership cycle
+ */
+ css::uno::Reference< css::xml::dom::events::XEventListener > m_xEventListener;
+
+ ::rtl::Reference<CElement> const m_pElement;
+ ::osl::Mutex & m_rMutex;
+ ::std::unique_ptr<xmlChar[]> const m_pName;
+ ::std::unique_ptr<xmlChar[]> const m_pURI;
+ bool m_bRebuild;
+ std::vector< xmlNodePtr > m_nodevector;
+
+ void buildlist(xmlNodePtr pNode, bool start=true);
+
+ public:
+ CElementListImpl(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex,
+ std::u16string_view rName, OUString const*const pURI);
+
+ void registerListener(CElement & rElement);
+
+ virtual ~CElementListImpl() override;
+
+ /**
+ The number of nodes in the list.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+ /**
+ Returns the indexth item in the collection.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override;
+
+ // XEventListener
+ virtual void SAL_CALL handleEvent(const css::uno::Reference< css::xml::dom::events::XEvent >& evt) override;
+ };
+
+ class CElementList
+ : public cppu::WeakImplHelper< css::xml::dom::XNodeList,
+ css::xml::dom::events::XEventListener >
+ {
+ private:
+ rtl::Reference<CElementListImpl> m_xImpl;
+ public:
+ CElementList(::rtl::Reference<CElement> const& pElement,
+ ::osl::Mutex & rMutex,
+ std::u16string_view rName, OUString const*const pURI = nullptr);
+
+ /**
+ The number of nodes in the list.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override
+ {
+ return m_xImpl->getLength();
+ }
+ /**
+ Returns the indexth item in the collection.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override
+ {
+ return m_xImpl->item(index);
+ }
+
+ // XEventListener
+ virtual void SAL_CALL handleEvent(const css::uno::Reference< css::xml::dom::events::XEvent >& evt) override
+ {
+ m_xImpl->handleEvent(evt);
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entitiesmap.cxx b/unoxml/source/dom/entitiesmap.cxx
new file mode 100644
index 000000000..d5c65e7c2
--- /dev/null
+++ b/unoxml/source/dom/entitiesmap.cxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "entitiesmap.hxx"
+
+#include <osl/diagnose.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CEntitiesMap::CEntitiesMap()
+ {
+ }
+
+ /**
+ The number of nodes in this map.
+ */
+ sal_Int32 SAL_CALL CEntitiesMap::getLength()
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::getLength: not implemented (#i113683#)");
+ return 0;
+ }
+
+ /**
+ Retrieves a node specified by local name
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::getNamedItem(OUString const& /*name*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::getNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::getNamedItemNS(
+ OUString const& /*namespaceURI*/, OUString const& /*localName*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::getNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Returns the indexth item in the map.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::item(sal_Int32 /*index*/)
+ {
+ OSL_ENSURE(false, "CEntitiesMap::item: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Removes a node specified by name.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::removeNamedItem(OUString const& /*name*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::removeNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::removeNamedItemNS(
+ OUString const& /*namespaceURI*/, OUString const& /*localName*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::removeNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::setNamedItem(Reference< XNode > const& /*arg*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::setNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ Reference< XNode > SAL_CALL
+ CEntitiesMap::setNamedItemNS(Reference< XNode > const& /*arg*/)
+ {
+ OSL_ENSURE(false,
+ "CEntitiesMap::setNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entitiesmap.hxx b/unoxml/source/dom/entitiesmap.hxx
new file mode 100644
index 000000000..7349851dd
--- /dev/null
+++ b/unoxml/source/dom/entitiesmap.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace DOM
+{
+ class CDocumentType;
+
+ class CEntitiesMap
+ : public cppu::WeakImplHelper< css::xml::dom::XNamedNodeMap >
+ {
+ public:
+ CEntitiesMap();
+
+ /**
+ The number of nodes in this map.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+
+ /**
+ Retrieves a node specified by local name
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ getNamedItem(const OUString& name) override;
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ Returns the indexth item in the map.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ item(sal_Int32 index) override;
+
+ /**
+ Removes a node specified by name.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ removeNamedItem(OUString const& name) override;
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItem(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItemNS(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entity.cxx b/unoxml/source/dom/entity.cxx
new file mode 100644
index 000000000..ccc8a0872
--- /dev/null
+++ b/unoxml/source/dom/entity.cxx
@@ -0,0 +1,112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "entity.hxx"
+
+#include <osl/diagnose.h>
+
+#include <string.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+
+ CEntity::CEntity(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlEntityPtr const pEntity)
+ : CEntity_Base(rDocument, rMutex,
+ NodeType_ENTITY_NODE, reinterpret_cast<xmlNodePtr>(pEntity))
+ , m_aEntityPtr(pEntity)
+ {
+ }
+
+ bool CEntity::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
+ {
+ switch (nodeType) {
+ case NodeType_ELEMENT_NODE:
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ case NodeType_COMMENT_NODE:
+ case NodeType_TEXT_NODE:
+ case NodeType_CDATA_SECTION_NODE:
+ case NodeType_ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ For unparsed entities, the name of the notation for the entity.
+ */
+ OUString SAL_CALL CEntity::getNotationName()
+ {
+ OSL_ENSURE(false,
+ "CEntity::getNotationName: not implemented (#i113683#)");
+ return OUString();
+ }
+
+ /**
+ The public identifier associated with the entity, if specified.
+ */
+ OUString SAL_CALL CEntity::getPublicId()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aID;
+ if(m_aEntityPtr != nullptr)
+ {
+ aID = OUString(reinterpret_cast<char const *>(m_aEntityPtr->ExternalID), strlen(reinterpret_cast<char const *>(m_aEntityPtr->ExternalID)), RTL_TEXTENCODING_UTF8);
+ }
+ return aID;
+ }
+
+ /**
+ The system identifier associated with the entity, if specified.
+ */
+ OUString SAL_CALL CEntity::getSystemId()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aID;
+ if(m_aEntityPtr != nullptr)
+ {
+ aID = OUString(reinterpret_cast<char const *>(m_aEntityPtr->SystemID), strlen(reinterpret_cast<char const *>(m_aEntityPtr->SystemID)), RTL_TEXTENCODING_UTF8);
+ }
+ return aID;
+ }
+ OUString SAL_CALL CEntity::getNodeName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aName;
+ if (m_aNodePtr != nullptr)
+ {
+ const xmlChar* pName = m_aNodePtr->name;
+ aName = OUString(reinterpret_cast<char const *>(pName), strlen(reinterpret_cast<char const *>(pName)), RTL_TEXTENCODING_UTF8);
+ }
+ return aName;
+ }
+ OUString SAL_CALL CEntity::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entity.hxx b/unoxml/source/dom/entity.hxx
new file mode 100644
index 000000000..2668adb68
--- /dev/null
+++ b/unoxml/source/dom/entity.hxx
@@ -0,0 +1,170 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XEntity.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XEntity > CEntity_Base;
+
+ class CEntity
+ : public CEntity_Base
+ {
+ private:
+ friend class CDocument;
+
+ xmlEntityPtr m_aEntityPtr;
+
+ CEntity(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlEntityPtr const pEntity);
+
+ public:
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const*) override;
+
+ /**
+ For unparsed entities, the name of the notation for the entity.
+ */
+ virtual OUString SAL_CALL getNotationName() override;
+
+ /**
+ The public identifier associated with the entity, if specified.
+ */
+ virtual OUString SAL_CALL getPublicId() override;
+
+ /**
+ The system identifier associated with the entity, if specified.
+ */
+ virtual OUString SAL_CALL getSystemId() override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entityreference.cxx b/unoxml/source/dom/entityreference.cxx
new file mode 100644
index 000000000..a3a06a238
--- /dev/null
+++ b/unoxml/source/dom/entityreference.cxx
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "entityreference.hxx"
+
+#include <string.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CEntityReference::CEntityReference(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CEntityReference_Base(rDocument, rMutex,
+ NodeType_ENTITY_REFERENCE_NODE, pNode)
+ {
+ }
+
+ bool CEntityReference::IsChildTypeAllowed(NodeType const nodeType, NodeType const*const)
+ {
+ switch (nodeType) {
+ case NodeType_ELEMENT_NODE:
+ case NodeType_PROCESSING_INSTRUCTION_NODE:
+ case NodeType_COMMENT_NODE:
+ case NodeType_TEXT_NODE:
+ case NodeType_CDATA_SECTION_NODE:
+ case NodeType_ENTITY_REFERENCE_NODE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ OUString SAL_CALL CEntityReference::getNodeName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aName;
+ if (m_aNodePtr != nullptr)
+ {
+ const xmlChar* pName = m_aNodePtr->name;
+ aName = OUString(reinterpret_cast<char const *>(pName), strlen(reinterpret_cast<char const *>(pName)), RTL_TEXTENCODING_UTF8);
+ }
+ return aName;
+ }
+
+ OUString SAL_CALL CEntityReference::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/entityreference.hxx b/unoxml/source/dom/entityreference.hxx
new file mode 100644
index 000000000..2ed9f568b
--- /dev/null
+++ b/unoxml/source/dom/entityreference.hxx
@@ -0,0 +1,152 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XEntityReference.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XEntityReference >
+ CEntityReference_Base;
+
+ class CEntityReference
+ : public CEntityReference_Base
+ {
+ private:
+ friend class CDocument;
+
+ CEntityReference(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+ virtual bool IsChildTypeAllowed(css::xml::dom::NodeType const nodeType,
+ css::xml::dom::NodeType const*) override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/node.cxx b/unoxml/source/dom/node.cxx
new file mode 100644
index 000000000..32cbedc0e
--- /dev/null
+++ b/unoxml/source/dom/node.cxx
@@ -0,0 +1,984 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <node.hxx>
+
+#include <string.h>
+
+#include <libxml/xmlstring.h>
+
+#include <algorithm>
+
+#include <osl/mutex.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/xml/dom/DOMException.hpp>
+#include <com/sun/star/xml/dom/events/XMutationEvent.hpp>
+#include <com/sun/star/xml/sax/FastToken.hpp>
+
+#include <comphelper/servicehelper.hxx>
+
+#include "document.hxx"
+#include "attr.hxx"
+#include "childlist.hxx"
+
+#include <eventdispatcher.hxx>
+
+using namespace css;
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ void pushContext(Context& io_rContext)
+ {
+ // Explicitly use a temp. variable.
+ // Windows/VC++ seems to mess up if .back() is directly passed as
+ // parameter. i.e. Don't use push_back( .back() );
+ Context::NamespaceVectorType::value_type aVal = io_rContext.maNamespaces.back();
+ io_rContext.maNamespaces.push_back( aVal );
+ }
+
+ 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 != nullptr; pNs = pNs->next) {
+ const xmlChar *pPrefix = pNs->prefix;
+ // prefix can be NULL when xmlns attribute is empty (xmlns="")
+ OString prefix(reinterpret_cast<const char*>(pPrefix),
+ pPrefix ? strlen(reinterpret_cast<const char*>(pPrefix)) : 0);
+ const xmlChar *pHref = pNs->href;
+ OUString val(reinterpret_cast<const char*>(pHref),
+ strlen(reinterpret_cast<const char*>(pHref)),
+ RTL_TEXTENCODING_UTF8);
+
+ 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;
+
+ io_rContext.maNamespaces.back().push_back(aNS);
+
+ SAL_INFO("unoxml", "Added with token " << aIter->second);
+ }
+ }
+ }
+
+ sal_Int32 getToken( const Context& rContext, const char* pToken )
+ {
+ const Sequence<sal_Int8> aSeq( reinterpret_cast<sal_Int8 const *>(pToken), strlen( pToken ) );
+ return rContext.mxTokenHandler->getTokenFromUTF8( aSeq );
+ }
+
+ sal_Int32 getTokenWithPrefix( const Context& rContext, const char* pPrefix, const char* pName )
+ {
+ sal_Int32 nNamespaceToken = FastToken::DONTKNOW;
+ OString prefix(pPrefix,
+ strlen(pPrefix));
+
+ SAL_INFO("unoxml", "getTokenWithPrefix(): prefix " << pPrefix << ", name " << pName);
+
+ Context::NamespaceVectorType::value_type::const_iterator aIter;
+ if( (aIter=std::find_if(rContext.maNamespaces.back().begin(),
+ rContext.maNamespaces.back().end(),
+ [&prefix](const Context::Namespace &aNamespace){ return aNamespace.getPrefix() == prefix; } )) !=
+ rContext.maNamespaces.back().end() )
+ {
+ nNamespaceToken = aIter->mnToken;
+ sal_Int32 nNameToken = getToken( rContext, pName );
+ if( nNameToken == FastToken::DONTKNOW )
+ nNamespaceToken = FastToken::DONTKNOW;
+ else
+ nNamespaceToken |= nNameToken;
+ }
+
+ return nNamespaceToken;
+ }
+
+
+ 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) : nullptr )
+ , m_rMutex(const_cast< ::osl::Mutex & >(rMutex))
+ {
+ OSL_ASSERT(m_aNodePtr);
+ }
+
+ void CNode::invalidate()
+ {
+ //remove from list if this wrapper goes away
+ if (m_aNodePtr != nullptr && m_xDocument.is()) {
+ m_xDocument->RemoveCNode(m_aNodePtr, this);
+ }
+ // #i113663#: unlinked nodes will not be freed by xmlFreeDoc
+ if (m_bUnlinked) {
+ xmlFreeNode(m_aNodePtr);
+ }
+ m_aNodePtr = nullptr;
+ }
+
+ CNode::~CNode()
+ {
+ // 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
+ }
+ }
+
+ const css::uno::Sequence< sal_Int8 > & CNode::getUnoTunnelId() noexcept
+ {
+ static const comphelper::UnoIdInit theCNodeUnoTunnelId;
+ return theCNodeUnoTunnelId.getSeq();
+ }
+
+ CDocument & CNode::GetOwnerDocument()
+ {
+ OSL_ASSERT(m_xDocument.is());
+ return *m_xDocument; // needs overriding in CDocument!
+ }
+
+
+ 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;
+ while (cur != nullptr)
+ {
+ if (cur->ns == oldNs)
+ cur->ns = newNs;
+ if (cur->type == XML_ELEMENT_NODE)
+ {
+ xmlAttrPtr curAttr = cur->properties;
+ while(curAttr != nullptr)
+ {
+ if (curAttr->ns == oldNs)
+ curAttr->ns = newNs;
+ curAttr = curAttr->next;
+ }
+ lcl_nsexchange(cur->children, oldNs, newNs);
+ }
+ cur = cur->next;
+ }
+ }
+
+ /*static*/ void nscleanup(const xmlNodePtr aNode, const xmlNodePtr aParent)
+ {
+ xmlNodePtr cur = aNode;
+
+ //handle attributes
+ if (cur != nullptr && cur->type == XML_ELEMENT_NODE)
+ {
+ xmlAttrPtr curAttr = cur->properties;
+ while(curAttr != nullptr)
+ {
+ if (curAttr->ns != nullptr)
+ {
+ xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, curAttr->ns->prefix);
+ if (ns != nullptr)
+ curAttr->ns = ns;
+ }
+ curAttr = curAttr->next;
+ }
+ }
+
+ while (cur != nullptr)
+ {
+ nscleanup(cur->children, cur);
+ if (cur->ns != nullptr)
+ {
+ xmlNsPtr ns = xmlSearchNs(cur->doc, aParent, cur->ns->prefix);
+ if (ns != nullptr && ns != cur->ns && strcmp(reinterpret_cast<char const *>(ns->href), reinterpret_cast<char const *>(cur->ns->href))==0)
+ {
+ xmlNsPtr curDef = cur->nsDef;
+ xmlNsPtr *refp = &(cur->nsDef); // insert point
+ while (curDef != nullptr)
+ {
+ ns = xmlSearchNs(cur->doc, aParent, curDef->prefix);
+ if (ns != nullptr && ns != curDef && strcmp(reinterpret_cast<char const *>(ns->href), reinterpret_cast<char const *>(curDef->href))==0)
+ {
+ // reconnect ns pointers in sub-tree to newly found ns before
+ // removing redundant nsdecl to prevent dangling pointers.
+ lcl_nsexchange(cur, curDef, ns);
+ *refp = curDef->next;
+ xmlFreeNs(curDef);
+ curDef = *refp;
+ } else {
+ refp = &(curDef->next);
+ curDef = curDef->next;
+ }
+ }
+ }
+ }
+ cur = cur->next;
+ }
+ }
+
+ void CNode::saxify(const Reference< XDocumentHandler >& i_xHandler)
+ {
+ if (!i_xHandler.is()) throw RuntimeException();
+ // default: do nothing
+ }
+
+ void CNode::fastSaxify(Context& io_rContext)
+ {
+ if (!io_rContext.mxDocHandler.is()) throw RuntimeException();
+ // default: do nothing
+ }
+
+ bool CNode::IsChildTypeAllowed(NodeType const /*nodeType*/, NodeType const*const)
+ {
+ // default: no children allowed
+ return false;
+ }
+
+ /**
+ Adds the node newChild to the end of the list of children of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::appendChild(
+ Reference< XNode > const& xNewChild)
+ {
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (nullptr == m_aNodePtr) { return nullptr; }
+
+ CNode *const pNewChild(comphelper::getFromUnoTunnel<CNode>(xNewChild));
+ if (!pNewChild) { throw RuntimeException(); }
+ xmlNodePtr const cur = pNewChild->GetNodePtr();
+ if (!cur) { throw RuntimeException(); }
+
+ // 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 != nullptr) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewChild->m_aNodeType, nullptr)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ // check whether this is an attribute node; it needs special handling
+ xmlNodePtr res = nullptr;
+ 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 optimization when appending nodes.
+ // if res != cur, something was optimized and the newchild-wrapper
+ // should be updated
+ if (res && (cur != res)) {
+ pNewChild->invalidate(); // cur has been freed
+ }
+ }
+
+ if (!res) { return nullptr; }
+
+ // use custom ns cleanup instead of
+ // xmlReconciliateNs(m_aNodePtr->doc, m_aNodePtr);
+ // because that will not remove unneeded ns decls
+ nscleanup(res, m_aNodePtr);
+
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(res);
+
+ if (!pNode.is()) { return nullptr; }
+
+ // dispatch DOMNodeInserted event, target is the new node
+ // this node is the related node
+ // does bubble
+ pNode->m_bUnlinked = false; // will be deleted by xmlFreeDoc
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMNodeInserted"), UNO_QUERY);
+ event->initMutationEvent("DOMNodeInserted", true, 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(event);
+ // dispatch subtree modified for this node
+ dispatchSubtreeModified();
+
+ return pNode;
+ }
+
+ /**
+ Returns a duplicate of this node, i.e., serves as a generic copy
+ constructor for nodes.
+ */
+ Reference< XNode > SAL_CALL CNode::cloneNode(sal_Bool bDeep)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ ::rtl::Reference<CNode> const pNode = GetOwnerDocument().GetCNode(
+ xmlCopyNode(m_aNodePtr, bDeep ? 1 : 0));
+ if (!pNode.is()) { return nullptr; }
+ pNode->m_bUnlinked = true; // not linked yet
+ return pNode;
+ }
+
+ /**
+ A NamedNodeMap containing the attributes of this node (if it is an Element)
+ or null otherwise.
+ */
+ Reference< XNamedNodeMap > SAL_CALL CNode::getAttributes()
+ {
+ // return empty reference; only element node may override this impl
+ return Reference< XNamedNodeMap>();
+ }
+
+ /**
+ A NodeList that contains all children of this node.
+ */
+ Reference< XNodeList > SAL_CALL CNode::getChildNodes()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ Reference< XNodeList > const xNodeList(new CChildList(this, m_rMutex));
+ return xNodeList;
+ }
+
+ /**
+ The first child of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getFirstChild()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ return GetOwnerDocument().GetCNode(m_aNodePtr->children);
+ }
+
+ /**
+ The last child of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getLastChild()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ return GetOwnerDocument().GetCNode(xmlGetLastChild(m_aNodePtr));
+ }
+
+ /**
+ Returns the local part of the qualified name of this node.
+ */
+ OUString SAL_CALL CNode::getLocalName()
+ {
+ // see CElement/CAttr
+ return OUString();
+ }
+
+
+ /**
+ The namespace URI of this node, or null if it is unspecified.
+ */
+ OUString SAL_CALL CNode::getNamespaceURI()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aURI;
+ if (m_aNodePtr != nullptr &&
+ (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
+ m_aNodePtr->ns != nullptr)
+ {
+ const xmlChar* pHref = m_aNodePtr->ns->href;
+ aURI = OUString(reinterpret_cast<char const *>(pHref), strlen(reinterpret_cast<char const *>(pHref)), RTL_TEXTENCODING_UTF8);
+ }
+ return aURI;
+ }
+
+ /**
+ The node immediately following this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getNextSibling()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ return GetOwnerDocument().GetCNode(m_aNodePtr->next);
+ }
+
+ /**
+ The name of this node, depending on its type; see the table above.
+ */
+ OUString SAL_CALL CNode::getNodeName()
+ {
+ /*
+ 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
+ */
+ return OUString();
+ }
+
+ /**
+ A code representing the type of the underlying object, as defined above.
+ */
+ NodeType SAL_CALL CNode::getNodeType()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return m_aNodeType;
+ }
+
+ /**
+ The value of this node, depending on its type; see the table above.
+ */
+ OUString SAL_CALL CNode::getNodeValue()
+ {
+ return OUString();
+ }
+
+ /**
+ The Document object associated with this node.
+ */
+ Reference< XDocument > SAL_CALL CNode::getOwnerDocument()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ Reference< XDocument > const xDoc(& GetOwnerDocument());
+ return xDoc;
+ }
+
+ /**
+ The parent of this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getParentNode()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ return GetOwnerDocument().GetCNode(m_aNodePtr->parent);
+ }
+
+ /**
+ The namespace prefix of this node, or null if it is unspecified.
+ */
+ OUString SAL_CALL CNode::getPrefix()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aPrefix;
+ if (m_aNodePtr != nullptr &&
+ (m_aNodePtr->type == XML_ELEMENT_NODE || m_aNodePtr->type == XML_ATTRIBUTE_NODE) &&
+ m_aNodePtr->ns != nullptr)
+ {
+ const xmlChar* pPrefix = m_aNodePtr->ns->prefix;
+ if( pPrefix != nullptr )
+ aPrefix = OUString(reinterpret_cast<char const *>(pPrefix), strlen(reinterpret_cast<char const *>(pPrefix)), RTL_TEXTENCODING_UTF8);
+ }
+ return aPrefix;
+
+ }
+
+ /**
+ The node immediately preceding this node.
+ */
+ Reference< XNode > SAL_CALL CNode::getPreviousSibling()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return nullptr;
+ }
+ return GetOwnerDocument().GetCNode(m_aNodePtr->prev);
+ }
+
+ /**
+ Returns whether this node (if it is an element) has any attributes.
+ */
+ sal_Bool SAL_CALL CNode::hasAttributes()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return (m_aNodePtr != nullptr && m_aNodePtr->properties != nullptr);
+ }
+
+ /**
+ Returns whether this node has any children.
+ */
+ sal_Bool SAL_CALL CNode::hasChildNodes()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return (m_aNodePtr != nullptr && m_aNodePtr->children != nullptr);
+ }
+
+ /**
+ Inserts the node newChild before the existing child node refChild.
+ */
+ Reference< XNode > SAL_CALL CNode::insertBefore(
+ const Reference< XNode >& newChild, const Reference< XNode >& refChild)
+ {
+ if (!newChild.is() || !refChild.is()) { throw RuntimeException(); }
+
+ 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;
+ }
+
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ CNode *const pNewNode(comphelper::getFromUnoTunnel<CNode>(newChild));
+ CNode *const pRefNode(comphelper::getFromUnoTunnel<CNode>(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 != nullptr)
+ {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewNode->m_aNodeType, nullptr)) {
+ 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 child before which to insert
+ while (cur != nullptr)
+ {
+ if (cur == pRefChild) {
+ // insert before
+ pNewChild->next = cur;
+ pNewChild->prev = cur->prev;
+ cur->prev = pNewChild;
+ if (pNewChild->prev != nullptr) {
+ 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;
+ }
+ 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*/)
+ {
+ OSL_ENSURE(false, "CNode::isSupported: not implemented (#i113683#)");
+ return 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()
+ {
+ //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 >& xOldChild)
+ {
+ if (!xOldChild.is()) {
+ throw RuntimeException();
+ }
+
+ 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;
+ }
+
+ ::osl::ClearableMutexGuard guard(m_rMutex);
+
+ if (!m_aNodePtr) { throw RuntimeException(); }
+
+ Reference<XNode> xReturn( xOldChild );
+
+ ::rtl::Reference<CNode> const pOld(comphelper::getFromUnoTunnel<CNode>(xOldChild));
+ if (!pOld.is()) { throw RuntimeException(); }
+ xmlNodePtr const old = pOld->GetNodePtr();
+ if (!old) { throw RuntimeException(); }
+
+ if( old->type == XML_ATTRIBUTE_NODE )
+ {
+ xmlAttrPtr pAttr = reinterpret_cast<xmlAttrPtr>(old);
+ xmlRemoveProp( pAttr );
+ pOld->invalidate(); // freed by xmlRemoveProp
+ xReturn.clear();
+ }
+ else
+ {
+ xmlUnlinkNode(old);
+ pOld->m_bUnlinked = true;
+ }
+
+ /*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
+ */
+ Reference< XDocumentEvent > docevent(getOwnerDocument(), UNO_QUERY);
+ Reference< XMutationEvent > event(docevent->createEvent(
+ "DOMNodeRemoved"), UNO_QUERY);
+ event->initMutationEvent("DOMNodeRemoved",
+ true,
+ 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(event);
+ // subtree modified 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(
+ Reference< XNode > const& xNewChild,
+ Reference< XNode > const& xOldChild)
+ {
+ if (!xOldChild.is() || !xNewChild.is()) {
+ throw RuntimeException();
+ }
+
+ 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);
+
+ ::rtl::Reference<CNode> const pOldNode(
+ comphelper::getFromUnoTunnel<CNode>(xOldChild));
+ ::rtl::Reference<CNode> const pNewNode(
+ comphelper::getFromUnoTunnel<CNode>(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 != nullptr) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+ if (!IsChildTypeAllowed(pNewNode->m_aNodeType, &pOldNode->m_aNodeType)) {
+ DOMException e;
+ e.Code = DOMExceptionType_HIERARCHY_REQUEST_ERR;
+ throw e;
+ }
+
+ 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 = reinterpret_cast<xmlAttrPtr>(pOld);
+ xmlRemoveProp( pAttr );
+ pOldNode->invalidate(); // freed by xmlRemoveProp
+ appendChild(xNewChild);
+ }
+ else
+ {
+
+ xmlNodePtr cur = m_aNodePtr->children;
+ //find old node in child list
+ while (cur != nullptr)
+ {
+ if(cur == pOld)
+ {
+ // exchange nodes
+ pNew->prev = pOld->prev;
+ if (pNew->prev != nullptr)
+ pNew->prev->next = pNew;
+ pNew->next = pOld->next;
+ if (pNew->next != nullptr)
+ pNew->next->prev = pNew;
+ pNew->parent = pOld->parent;
+ assert(pNew->parent && "coverity[var_deref_op] pNew->parent cannot be NULL here");
+ if(pNew->parent->children == pOld)
+ pNew->parent->children = pNew;
+ if(pNew->parent->last == pOld)
+ pNew->parent->last = pNew;
+ pOld->next = nullptr;
+ pOld->prev = nullptr;
+ pOld->parent = nullptr;
+ 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 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(
+ "DOMSubtreeModified"), UNO_QUERY);
+ event->initMutationEvent(
+ "DOMSubtreeModified", true,
+ false, Reference< XNode >(),
+ OUString(), OUString(), OUString(), AttrChangeType(0) );
+ dispatchEvent(event);
+ }
+
+ /**
+ The value of this node, depending on its type; see the table above.
+ */
+ void SAL_CALL CNode::setNodeValue(const OUString& /*nodeValue*/)
+ {
+ // use specific node implementation
+ // 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)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if ((nullptr == 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 const *pBuf = reinterpret_cast<xmlChar const *>(o1.getStr());
+ if (m_aNodePtr != nullptr && m_aNodePtr->ns != nullptr)
+ {
+ xmlFree(const_cast<xmlChar *>(m_aNodePtr->ns->prefix));
+ m_aNodePtr->ns->prefix = xmlStrdup(pBuf);
+ }
+
+ }
+
+ // --- XEventTarget
+ void SAL_CALL CNode::addEventListener(const OUString& eventType,
+ const Reference< css::xml::dom::events::XEventListener >& listener,
+ sal_Bool 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,
+ const Reference< css::xml::dom::events::XEventListener >& listener,
+ sal_Bool 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)
+ {
+ 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 true;
+ }
+
+ ::sal_Int64 SAL_CALL
+ CNode::getSomething(Sequence< ::sal_Int8 > const& rId)
+ {
+ return comphelper::getSomethingImpl(rId, this);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/notation.cxx b/unoxml/source/dom/notation.cxx
new file mode 100644
index 000000000..352d5b002
--- /dev/null
+++ b/unoxml/source/dom/notation.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "notation.hxx"
+
+#include <string.h>
+
+#include <osl/diagnose.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CNotation::CNotation(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNotationPtr const pNotation)
+ : CNotation_Base(rDocument, rMutex,
+ NodeType_NOTATION_NODE, reinterpret_cast<xmlNodePtr>(pNotation))
+ {
+ }
+
+ OUString SAL_CALL CNotation::getPublicId()
+ {
+ OSL_ENSURE(false,
+ "CNotation::getPublicId: not implemented (#i113683#)");
+ return OUString();
+ }
+
+ /**
+ The system identifier of this notation.
+ */
+ OUString SAL_CALL CNotation::getSystemId()
+ {
+ OSL_ENSURE(false,
+ "CNotation::getSystemId: not implemented (#i113683#)");
+ return OUString();
+ }
+
+
+ OUString SAL_CALL CNotation::getNodeName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ OUString aName;
+ if (m_aNodePtr != nullptr)
+ {
+ const xmlChar* pName = m_aNodePtr->name;
+ aName = OUString(reinterpret_cast<char const *>(pName), strlen(reinterpret_cast<char const *>(pName)), RTL_TEXTENCODING_UTF8);
+ }
+ return aName;
+ }
+
+ OUString SAL_CALL CNotation::getNodeValue()
+ {
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/notation.hxx b/unoxml/source/dom/notation.hxx
new file mode 100644
index 000000000..2a95200f5
--- /dev/null
+++ b/unoxml/source/dom/notation.hxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNotation.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef cppu::ImplInheritanceHelper< CNode, css::xml::dom::XNotation > CNotation_Base;
+
+ class CNotation
+ : public CNotation_Base
+ {
+ private:
+ friend class CDocument;
+
+ CNotation(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNotationPtr const pNotation);
+
+ /**
+ The public identifier of this notation.
+ */
+ virtual OUString SAL_CALL getPublicId() override;
+
+ /**
+ The system identifier of this notation.
+ */
+ virtual OUString SAL_CALL getSystemId() override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CNode::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/notationsmap.cxx b/unoxml/source/dom/notationsmap.cxx
new file mode 100644
index 000000000..07cb851b3
--- /dev/null
+++ b/unoxml/source/dom/notationsmap.cxx
@@ -0,0 +1,122 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "notationsmap.hxx"
+
+#include <osl/diagnose.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace DOM
+{
+ CNotationsMap::CNotationsMap()
+ {
+ }
+
+ /**
+ The number of nodes in this map.
+ */
+ sal_Int32 SAL_CALL CNotationsMap::getLength()
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::getLength: not implemented (#i113683#)");
+ return 0;
+ }
+
+ /**
+ Retrieves a node specified by local name
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::getNamedItem(OUString const& /*name*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::getNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::getNamedItemNS(
+ OUString const& /*namespaceURI*/, OUString const& /*localName*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::getNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Returns the indexth item in the map.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::item(sal_Int32 /*index*/)
+ {
+ OSL_ENSURE(false, "CNotationsMap::item: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Removes a node specified by name.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::removeNamedItem(OUString const& /*name*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::removeNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::removeNamedItemNS(
+ OUString const& /*namespaceURI*/, OUString const& /*localName*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::removeNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::setNamedItem(Reference< XNode > const& /*arg*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::setNamedItem: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ Reference< XNode > SAL_CALL
+ CNotationsMap::setNamedItemNS(Reference< XNode > const& /*arg*/)
+ {
+ OSL_ENSURE(false,
+ "CNotationsMap::setNamedItemNS: not implemented (#i113683#)");
+ return Reference< XNode >();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/notationsmap.hxx b/unoxml/source/dom/notationsmap.hxx
new file mode 100644
index 000000000..9dac7d968
--- /dev/null
+++ b/unoxml/source/dom/notationsmap.hxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace DOM
+{
+ class CDocumentType;
+
+ class CNotationsMap
+ : public cppu::WeakImplHelper< css::xml::dom::XNamedNodeMap >
+ {
+ public:
+ CNotationsMap();
+
+ /**
+ The number of nodes in this map.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+
+ /**
+ Retrieves a node specified by local name
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ getNamedItem(OUString const& name) override;
+
+ /**
+ Retrieves a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ Returns the indexth item in the map.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ item(sal_Int32 index) override;
+
+ /**
+ Removes a node specified by name.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ removeNamedItem(OUString const& name) override;
+
+ /**
+ // Removes a node specified by local name and namespace URI.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeNamedItemNS(
+ OUString const& namespaceURI, OUString const& localName) override;
+
+ /**
+ // Adds a node using its nodeName attribute.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItem(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+
+ /**
+ Adds a node using its namespaceURI and localName.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL
+ setNamedItemNS(css::uno::Reference< css::xml::dom::XNode > const& arg) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/processinginstruction.cxx b/unoxml/source/dom/processinginstruction.cxx
new file mode 100644
index 000000000..9eda0b904
--- /dev/null
+++ b/unoxml/source/dom/processinginstruction.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "processinginstruction.hxx"
+
+#include <string.h>
+
+#include <com/sun/star/xml/sax/XExtendedDocumentHandler.hpp>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ CProcessingInstruction::CProcessingInstruction(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CProcessingInstruction_Base(rDocument, rMutex,
+ NodeType_PROCESSING_INSTRUCTION_NODE, pNode)
+ {
+ }
+
+ void CProcessingInstruction::saxify(
+ const Reference< XDocumentHandler >& i_xHandler) {
+ if (!i_xHandler.is()) throw RuntimeException();
+ Reference< XExtendedDocumentHandler > xExtended(i_xHandler, UNO_QUERY);
+ if (xExtended.is()) {
+ xExtended->processingInstruction(getTarget(), getData());
+ }
+ }
+
+ /**
+ The content of this processing instruction.
+ */
+ OUString SAL_CALL
+ CProcessingInstruction::getData()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+
+ char const*const pContent(
+ reinterpret_cast<char const*>(m_aNodePtr->content));
+ if (nullptr == pContent) {
+ return OUString();
+ }
+ OUString const ret(pContent, strlen(pContent), RTL_TEXTENCODING_UTF8);
+ return ret;
+ }
+
+ /**
+ The target of this processing instruction.
+ */
+ OUString SAL_CALL
+ CProcessingInstruction::getTarget()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+
+ char const*const pName(
+ reinterpret_cast<char const*>(m_aNodePtr->name));
+ if (nullptr == pName) {
+ return OUString();
+ }
+ OUString const ret(pName, strlen(pName), RTL_TEXTENCODING_UTF8);
+ return ret;
+ }
+
+ /**
+ The content of this processing instruction.
+ */
+ void SAL_CALL CProcessingInstruction::setData(OUString const& rData)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ throw RuntimeException();
+ }
+
+ OString const data(
+ OUStringToOString(rData, RTL_TEXTENCODING_UTF8));
+ xmlChar const*const pData(
+ reinterpret_cast<xmlChar const*>(data.getStr()) );
+ xmlFree(m_aNodePtr->content);
+ m_aNodePtr->content = xmlStrdup(pData);
+ }
+
+ OUString SAL_CALL
+ CProcessingInstruction::getNodeName()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_aNodePtr) {
+ return OUString();
+ }
+
+ char const*const pName =
+ reinterpret_cast<char const*>(m_aNodePtr->name);
+ OUString const ret(pName, strlen(pName), RTL_TEXTENCODING_UTF8);
+ return ret;
+ }
+
+ OUString SAL_CALL CProcessingInstruction::getNodeValue()
+ {
+ return getData();
+ }
+
+ void SAL_CALL
+ CProcessingInstruction::setNodeValue(OUString const& rNodeValue)
+ {
+ return setData(rNodeValue);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/processinginstruction.hxx b/unoxml/source/dom/processinginstruction.hxx
new file mode 100644
index 000000000..e2c027816
--- /dev/null
+++ b/unoxml/source/dom/processinginstruction.hxx
@@ -0,0 +1,165 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XProcessingInstruction.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <node.hxx>
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CNode, css::xml::dom::XProcessingInstruction >
+ CProcessingInstruction_Base;
+
+ class CProcessingInstruction
+ : public CProcessingInstruction_Base
+ {
+ private:
+ friend class CDocument;
+
+ CProcessingInstruction(
+ CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ /**
+ The content of this processing instruction.
+ */
+ virtual OUString SAL_CALL getData() override;
+
+ /**
+ The target of this processing instruction.
+ */
+ virtual OUString SAL_CALL getTarget() override;
+
+ /**
+ The content of this processing instruction.
+ */
+ virtual void SAL_CALL setData(const OUString& data) override;
+
+ // ---- resolve uno inheritance problems...
+ // overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+ virtual OUString SAL_CALL getNodeValue() override;
+ virtual void SAL_CALL setNodeValue(OUString const& rNodeValue) override;
+
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CNode::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CNode::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CNode::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CNode::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CNode::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CNode::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CNode::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CNode::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CNode::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CNode::getNodeType();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CNode::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CNode::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CNode::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CNode::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CNode::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CNode::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CNode::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CNode::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CNode::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CNode::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CNode::setPrefix(prefix);
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/saxbuilder.cxx b/unoxml/source/dom/saxbuilder.cxx
new file mode 100644
index 000000000..61b7a496a
--- /dev/null
+++ b/unoxml/source/dom/saxbuilder.cxx
@@ -0,0 +1,344 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "saxbuilder.hxx"
+
+#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
+#include <com/sun/star/xml/sax/SAXException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <sax/fastattribs.hxx>
+#include <xmloff/xmlimp.hxx>
+
+using namespace css::lang;
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ CSAXDocumentBuilder::CSAXDocumentBuilder(const Reference< XComponentContext >& ctx)
+ : m_xContext(ctx)
+ , m_aState( SAXDocumentBuilderState_READY)
+ {}
+
+ Sequence< OUString > SAL_CALL CSAXDocumentBuilder::getSupportedServiceNames()
+ {
+ return { "com.sun.star.xml.dom.SAXDocumentBuilder" };
+ }
+
+ OUString SAL_CALL CSAXDocumentBuilder::getImplementationName()
+ {
+ return "com.sun.star.comp.xml.dom.SAXDocumentBuilder";
+ }
+
+ sal_Bool SAL_CALL CSAXDocumentBuilder::supportsService(const OUString& aServiceName)
+ {
+ return cppu::supportsService(this, aServiceName);
+ }
+
+ SAXDocumentBuilderState SAL_CALL CSAXDocumentBuilder::getState()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ return m_aState;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::reset()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ m_aDocument.clear();
+ m_aFragment.clear();
+ while (!m_aNodeStack.empty()) m_aNodeStack.pop();
+ m_aState = SAXDocumentBuilderState_READY;
+ }
+
+ Reference< XDocument > SAL_CALL CSAXDocumentBuilder::getDocument()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ if (m_aState != SAXDocumentBuilderState_DOCUMENT_FINISHED)
+ throw RuntimeException();
+
+ return m_aDocument;
+ }
+
+ Reference< XDocumentFragment > SAL_CALL CSAXDocumentBuilder::getDocumentFragment()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ if (m_aState != SAXDocumentBuilderState_FRAGMENT_FINISHED)
+ throw RuntimeException();
+ return m_aFragment;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::startDocumentFragment(const Reference< XDocument >& ownerDoc)
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // start a new document fragment and push it onto the stack
+ // we have to be in a clean state to do this
+ if (m_aState != SAXDocumentBuilderState_READY)
+ throw RuntimeException();
+
+ m_aDocument = ownerDoc;
+ Reference< XDocumentFragment > aFragment = m_aDocument->createDocumentFragment();
+ m_aNodeStack.push(aFragment);
+ m_aFragment = aFragment;
+ m_aState = SAXDocumentBuilderState_BUILDING_FRAGMENT;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::endDocumentFragment()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // there should only be the document left on the node stack
+ if (m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ throw RuntimeException();
+
+ Reference< XNode > aNode = m_aNodeStack.top();
+ if ( aNode->getNodeType() != NodeType_DOCUMENT_FRAGMENT_NODE)
+ throw RuntimeException();
+ m_aNodeStack.pop();
+ m_aState = SAXDocumentBuilderState_FRAGMENT_FINISHED;
+ }
+
+ //XFastDocumentHandler
+ void SAL_CALL CSAXDocumentBuilder::startDocument()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // start a new document and push it onto the stack
+ // we have to be in a clean state to do this
+ if (m_aState != SAXDocumentBuilderState_READY)
+ throw SAXException();
+
+ Reference< XDocumentBuilder > aBuilder(DocumentBuilder::create(m_xContext));
+ Reference< XDocument > aDocument = aBuilder->newDocument();
+ m_aNodeStack.push(aDocument);
+ m_aDocument = aDocument;
+ m_aState = SAXDocumentBuilderState_BUILDING_DOCUMENT;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::endDocument()
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // there should only be the document left on the node stack
+ if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT)
+ throw SAXException();
+
+ Reference< XNode > aNode = m_aNodeStack.top();
+ if ( aNode->getNodeType() != NodeType_DOCUMENT_NODE)
+ throw SAXException();
+ m_aNodeStack.pop();
+ m_aState = SAXDocumentBuilderState_DOCUMENT_FINISHED;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::processingInstruction( const OUString& rTarget, const OUString& rData )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // append PI node to the current top
+ if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ throw SAXException();
+
+ Reference< XProcessingInstruction > aInstruction = m_aDocument->createProcessingInstruction(
+ rTarget, rData);
+ m_aNodeStack.top()->appendChild(aInstruction);
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::setDocumentLocator( const Reference< XLocator >& )
+ {
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::startFastElement( sal_Int32 nElement , const Reference< XFastAttributeList >& xAttribs )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ {
+ throw SAXException();
+ }
+
+ Reference< XElement > aElement;
+ const OUString& aPrefix(SvXMLImport::getNamespacePrefixFromToken(nElement, nullptr));
+ const OUString& aURI( SvXMLImport::getNamespaceURIFromToken( nElement ) );
+ OUString aQualifiedName( SvXMLImport::getNameFromToken( nElement ) );
+ if( !aPrefix.isEmpty() )
+ aQualifiedName = aPrefix + SvXMLImport::aNamespaceSeparator + aQualifiedName;
+
+ if ( !aURI.isEmpty() )
+ {
+ // found a URI for prefix
+ // qualified name
+ aElement = m_aDocument->createElementNS( aURI, aQualifiedName );
+ }
+ else
+ {
+ // no URI for prefix
+ aElement = m_aDocument->createElement( aQualifiedName );
+ }
+ aElement.set( m_aNodeStack.top()->appendChild(aElement), UNO_QUERY);
+ m_aNodeStack.push(aElement);
+
+ if (xAttribs.is())
+ setElementFastAttributes(aElement, xAttribs);
+ }
+
+ // For arbitrary meta elements
+ void SAL_CALL CSAXDocumentBuilder::startUnknownElement( const OUString& rNamespace, const OUString& rName, const Reference< XFastAttributeList >& xAttribs )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ {
+ throw SAXException();
+ }
+
+ Reference< XElement > aElement;
+ if ( !rNamespace.isEmpty() )
+ aElement = m_aDocument->createElementNS( rNamespace, rName );
+ else
+ aElement = m_aDocument->createElement( rName );
+
+ aElement.set( m_aNodeStack.top()->appendChild(aElement), UNO_QUERY);
+ m_aNodeStack.push(aElement);
+
+ if (!xAttribs.is())
+ return;
+
+ setElementFastAttributes(aElement, xAttribs);
+ const Sequence< css::xml::Attribute > unknownAttribs = xAttribs->getUnknownAttributes();
+ for ( const auto& rUnknownAttrib : unknownAttribs )
+ {
+ const OUString& rAttrValue = rUnknownAttrib.Value;
+ const OUString& rAttrName = rUnknownAttrib.Name;
+ const OUString& rAttrNamespace = rUnknownAttrib.NamespaceURL;
+ if ( !rAttrNamespace.isEmpty() )
+ aElement->setAttributeNS( rAttrNamespace, rAttrName, rAttrValue );
+ else
+ aElement->setAttribute( rAttrName, rAttrValue );
+ }
+ }
+
+ void CSAXDocumentBuilder::setElementFastAttributes(const Reference< XElement >& aElement, const Reference< XFastAttributeList >& xAttribs)
+ {
+ for (auto &it : sax_fastparser::castToFastAttributeList( xAttribs ))
+ {
+ sal_Int32 nAttrToken = it.getToken();
+ const OUString& aAttrPrefix(SvXMLImport::getNamespacePrefixFromToken(nAttrToken, nullptr));
+ const OUString& aAttrURI( SvXMLImport::getNamespaceURIFromToken( nAttrToken ) );
+ OUString aAttrQualifiedName( SvXMLImport::getNameFromToken( nAttrToken ) );
+ if( !aAttrPrefix.isEmpty() )
+ aAttrQualifiedName = aAttrPrefix + SvXMLImport::aNamespaceSeparator + aAttrQualifiedName;
+
+ if ( !aAttrURI.isEmpty() )
+ aElement->setAttributeNS( aAttrURI, aAttrQualifiedName, it.toString() );
+ else
+ aElement->setAttribute( aAttrQualifiedName, it.toString() );
+ }
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::endFastElement( sal_Int32 nElement )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // pop the current element from the stack
+ if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ throw SAXException();
+
+ Reference< XNode > aNode(m_aNodeStack.top());
+ if (aNode->getNodeType() != NodeType_ELEMENT_NODE)
+ throw SAXException();
+
+ Reference< XElement > aElement(aNode, UNO_QUERY);
+ if( aElement->getPrefix() != SvXMLImport::getNamespacePrefixFromToken(nElement, nullptr) ||
+ aElement->getTagName() != SvXMLImport::getNameFromToken( nElement ) ) // consistency check
+ throw SAXException();
+
+ // pop it
+ m_aNodeStack.pop();
+ }
+
+
+ void SAL_CALL CSAXDocumentBuilder::endUnknownElement( const OUString& /*rNamespace*/, const OUString& rName )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // pop the current element from the stack
+ if ( m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ throw SAXException();
+
+ Reference< XNode > aNode(m_aNodeStack.top());
+ if (aNode->getNodeType() != NodeType_ELEMENT_NODE)
+ throw SAXException();
+
+ Reference< XElement > aElement(aNode, UNO_QUERY);
+ OUString aRefName;
+ const OUString& aPrefix = aElement->getPrefix();
+ if (!aPrefix.isEmpty())
+ aRefName = aPrefix + SvXMLImport::aNamespaceSeparator + aElement->getTagName();
+ else
+ aRefName = aElement->getTagName();
+ if (aRefName != rName) // consistency check
+ throw SAXException();
+
+ // pop it
+ m_aNodeStack.pop();
+ }
+
+ Reference< XFastContextHandler > SAL_CALL CSAXDocumentBuilder::createFastChildContext( sal_Int32/* nElement */, const Reference< XFastAttributeList >&/* xAttribs */ )
+ {
+ return nullptr;
+ }
+
+
+ Reference< XFastContextHandler > SAL_CALL CSAXDocumentBuilder::createUnknownChildContext( const OUString&/* rNamespace */, const OUString&/* rName */, const Reference< XFastAttributeList >&/* xAttribs */ )
+ {
+ return nullptr;
+ }
+
+ void SAL_CALL CSAXDocumentBuilder::characters( const OUString& rChars )
+ {
+ std::scoped_lock g(m_Mutex);
+
+ // append text node to the current top element
+ if (m_aState != SAXDocumentBuilderState_BUILDING_DOCUMENT &&
+ m_aState != SAXDocumentBuilderState_BUILDING_FRAGMENT)
+ throw SAXException();
+
+ Reference< XText > aText = m_aDocument->createTextNode(rChars);
+ m_aNodeStack.top()->appendChild(aText);
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CSAXDocumentBuilder_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new DOM::CSAXDocumentBuilder(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/saxbuilder.hxx b/unoxml/source/dom/saxbuilder.hxx
new file mode 100644
index 000000000..83b82912e
--- /dev/null
+++ b/unoxml/source/dom/saxbuilder.hxx
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <mutex>
+#include <stack>
+
+#include <sal/types.h>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+
+#include <com/sun/star/xml/dom/XSAXDocumentBuilder2.hpp>
+#include <com/sun/star/xml/dom/SAXDocumentBuilderState.hpp>
+#include <com/sun/star/xml/dom/XDocument.hpp>
+#include <com/sun/star/xml/dom/XDocumentFragment.hpp>
+#include <com/sun/star/xml/sax/XLocator.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace DOM
+{
+ class CSAXDocumentBuilder
+ : public ::cppu::WeakImplHelper< css::xml::dom::XSAXDocumentBuilder2, css::lang::XServiceInfo >
+ {
+
+ private:
+ std::mutex m_Mutex;
+ const css::uno::Reference< css::uno::XComponentContext> m_xContext;
+
+ css::xml::dom::SAXDocumentBuilderState m_aState;
+ std::stack< css::uno::Reference< css::xml::dom::XNode > > m_aNodeStack;
+
+ css::uno::Reference< css::xml::dom::XDocument > m_aDocument;
+ css::uno::Reference< css::xml::dom::XDocumentFragment > m_aFragment;
+
+
+ public:
+ explicit CSAXDocumentBuilder(const css::uno::Reference< css::uno::XComponentContext >& );
+ static void setElementFastAttributes(const css::uno::Reference< css::xml::dom::XElement >& aElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttribs);
+
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+ // XFastDocumentHandler
+ virtual void SAL_CALL startDocument() override;
+ virtual void SAL_CALL endDocument() override;
+ virtual void SAL_CALL processingInstruction( const OUString& rTarget, const OUString& rData ) override;
+ virtual void SAL_CALL setDocumentLocator( const css::uno::Reference< css::xml::sax::XLocator >& xLocator ) override;
+
+ // XFastContextHandler
+ virtual void SAL_CALL startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL startUnknownElement( const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL endFastElement( sal_Int32 Element ) override;
+ virtual void SAL_CALL endUnknownElement( const OUString& Namespace, const OUString& Name ) override;
+ virtual css::uno::Reference< XFastContextHandler > SAL_CALL createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual css::uno::Reference< XFastContextHandler > SAL_CALL createUnknownChildContext( const OUString& Namespace, const OUString& Name, const css::uno::Reference< css::xml::sax::XFastAttributeList >& Attribs ) override;
+ virtual void SAL_CALL characters( const OUString& aChars ) override;
+
+ // XSAXDocumentBuilder
+ virtual css::xml::dom::SAXDocumentBuilderState SAL_CALL getState() override;
+ virtual void SAL_CALL reset() override;
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getDocument() override;
+ virtual css::uno::Reference< css::xml::dom::XDocumentFragment > SAL_CALL getDocumentFragment() override;
+ virtual void SAL_CALL startDocumentFragment(const css::uno::Reference< css::xml::dom::XDocument >& ownerDoc) override;
+ virtual void SAL_CALL endDocumentFragment() override;
+
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/text.cxx b/unoxml/source/dom/text.cxx
new file mode 100644
index 000000000..08db01ba3
--- /dev/null
+++ b/unoxml/source/dom/text.cxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "text.hxx"
+
+#include <osl/diagnose.h>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::sax;
+
+namespace DOM
+{
+ CText::CText(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ NodeType const& reNodeType, xmlNodePtr const& rpNode)
+ : CText_Base(rDocument, rMutex, reNodeType, rpNode)
+ {
+ }
+
+ CText::CText(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode)
+ : CText_Base(rDocument, rMutex, NodeType_TEXT_NODE, pNode)
+ {
+ }
+
+ void CText::saxify(
+ const Reference< XDocumentHandler >& i_xHandler) {
+ if (!i_xHandler.is()) throw RuntimeException();
+ i_xHandler->characters(getData());
+ }
+
+ void CText::fastSaxify( Context& io_rContext )
+ {
+ if (io_rContext.mxCurrentHandler.is())
+ {
+ try
+ {
+ io_rContext.mxCurrentHandler->characters( getData() );
+ }
+ catch( Exception& )
+ {}
+ }
+ }
+
+ OUString SAL_CALL CText::getNodeName()
+ {
+ return "#text";
+ }
+
+ Reference< XText > SAL_CALL CText::splitText(sal_Int32 /*offset*/)
+ {
+ OSL_FAIL("CText::splitText: not implemented (#i113683#)");
+ return Reference< XText >(this);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/dom/text.hxx b/unoxml/source/dom/text.hxx
new file mode 100644
index 000000000..d594b1586
--- /dev/null
+++ b/unoxml/source/dom/text.hxx
@@ -0,0 +1,203 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <libxml/tree.h>
+
+#include <sal/types.h>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XText.hpp>
+
+#include "characterdata.hxx"
+
+namespace DOM
+{
+ typedef ::cppu::ImplInheritanceHelper< CCharacterData, css::xml::dom::XText > CText_Base;
+
+ class CText
+ : public CText_Base
+ {
+ private:
+ friend class CDocument;
+
+ protected:
+ CText(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ css::xml::dom::NodeType const& reNodeType, xmlNodePtr const& rpNode);
+ CText(CDocument const& rDocument, ::osl::Mutex const& rMutex,
+ xmlNodePtr const pNode);
+
+ public:
+
+ virtual void saxify(const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_xHandler) override;
+
+ virtual void fastSaxify( Context& io_rContext ) override;
+
+ // Breaks this node into two nodes at the specified offset, keeping
+ // both in the tree as siblings.
+ virtual css::uno::Reference< css::xml::dom::XText > SAL_CALL splitText(sal_Int32 offset) override;
+
+
+ // --- delegations for XCharacterData
+ virtual void SAL_CALL appendData(const OUString& arg) override
+ {
+ CCharacterData::appendData(arg);
+ }
+ virtual void SAL_CALL deleteData(sal_Int32 offset, sal_Int32 count) override
+ {
+ CCharacterData::deleteData(offset, count);
+ }
+ virtual OUString SAL_CALL getData() override
+ {
+ return CCharacterData::getData();
+ }
+ virtual sal_Int32 SAL_CALL getLength() override
+ {
+ return CCharacterData::getLength();
+ }
+ virtual void SAL_CALL insertData(sal_Int32 offset, const OUString& arg) override
+ {
+ CCharacterData::insertData(offset, arg);
+ }
+ virtual void SAL_CALL replaceData(sal_Int32 offset, sal_Int32 count, const OUString& arg) override
+ {
+ CCharacterData::replaceData(offset, count, arg);
+ }
+ virtual void SAL_CALL setData(const OUString& data) override
+ {
+ CCharacterData::setData(data);
+ }
+ virtual OUString SAL_CALL subStringData(sal_Int32 offset, sal_Int32 count) override
+ {
+ return CCharacterData::subStringData(offset, count);
+ }
+
+
+ // --- overrides for XNode base
+ virtual OUString SAL_CALL getNodeName() override;
+
+ // --- resolve uno inheritance problems...
+ // --- delegation for XNode base.
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL appendChild(const css::uno::Reference< css::xml::dom::XNode >& newChild) override
+ {
+ return CCharacterData::appendChild(newChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL cloneNode(sal_Bool deep) override
+ {
+ return CCharacterData::cloneNode(deep);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNamedNodeMap > SAL_CALL getAttributes() override
+ {
+ return CCharacterData::getAttributes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getChildNodes() override
+ {
+ return CCharacterData::getChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getFirstChild() override
+ {
+ return CCharacterData::getFirstChild();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getLastChild() override
+ {
+ return CCharacterData::getLastChild();
+ }
+ virtual OUString SAL_CALL getLocalName() override
+ {
+ return CCharacterData::getLocalName();
+ }
+ virtual OUString SAL_CALL getNamespaceURI() override
+ {
+ return CCharacterData::getNamespaceURI();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getNextSibling() override
+ {
+ return CCharacterData::getNextSibling();
+ }
+ virtual css::xml::dom::NodeType SAL_CALL getNodeType() override
+ {
+ return CCharacterData::getNodeType();
+ }
+ virtual OUString SAL_CALL getNodeValue() override
+ {
+ return CCharacterData::getNodeValue();
+ }
+ virtual css::uno::Reference< css::xml::dom::XDocument > SAL_CALL getOwnerDocument() override
+ {
+ return CCharacterData::getOwnerDocument();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getParentNode() override
+ {
+ return CCharacterData::getParentNode();
+ }
+ virtual OUString SAL_CALL getPrefix() override
+ {
+ return CCharacterData::getPrefix();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL getPreviousSibling() override
+ {
+ return CCharacterData::getPreviousSibling();
+ }
+ virtual sal_Bool SAL_CALL hasAttributes() override
+ {
+ return CCharacterData::hasAttributes();
+ }
+ virtual sal_Bool SAL_CALL hasChildNodes() override
+ {
+ return CCharacterData::hasChildNodes();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL insertBefore(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& refChild) override
+ {
+ return CCharacterData::insertBefore(newChild, refChild);
+ }
+ virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver) override
+ {
+ return CCharacterData::isSupported(feature, ver);
+ }
+ virtual void SAL_CALL normalize() override
+ {
+ CCharacterData::normalize();
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL removeChild(const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CCharacterData::removeChild(oldChild);
+ }
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL replaceChild(
+ const css::uno::Reference< css::xml::dom::XNode >& newChild, const css::uno::Reference< css::xml::dom::XNode >& oldChild) override
+ {
+ return CCharacterData::replaceChild(newChild, oldChild);
+ }
+ virtual void SAL_CALL setNodeValue(const OUString& nodeValue) override
+ {
+ return CCharacterData::setNodeValue(nodeValue);
+ }
+ virtual void SAL_CALL setPrefix(const OUString& prefix) override
+ {
+ return CCharacterData::setPrefix(prefix);
+ }
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/events/event.cxx b/unoxml/source/events/event.cxx
new file mode 100644
index 000000000..e3b092ff3
--- /dev/null
+++ b/unoxml/source/events/event.cxx
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <event.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom::events;
+
+namespace DOM::events
+{
+
+ CEvent::CEvent()
+ : m_canceled(false)
+ , m_phase(PhaseType_CAPTURING_PHASE)
+ , m_bubbles(false)
+ , m_cancelable(true)
+ {
+ }
+
+ CEvent::~CEvent()
+ {
+ }
+
+ OUString SAL_CALL CEvent::getType()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_eventType;
+ }
+
+ Reference< XEventTarget > SAL_CALL
+ CEvent::getTarget()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_target;
+ }
+
+ Reference< XEventTarget > SAL_CALL
+ CEvent::getCurrentTarget()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_currentTarget;
+ }
+
+ PhaseType SAL_CALL CEvent::getEventPhase()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_phase;
+ }
+
+ sal_Bool SAL_CALL CEvent::getBubbles()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_bubbles;
+ }
+
+ sal_Bool SAL_CALL CEvent::getCancelable()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_cancelable;
+ }
+
+ css::util::Time SAL_CALL
+ CEvent::getTimeStamp()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_time;
+ }
+
+ void SAL_CALL CEvent::stopPropagation()
+ {
+ std::unique_lock const g(m_Mutex);
+ if (m_cancelable) { m_canceled = true; }
+ }
+
+ void SAL_CALL CEvent::preventDefault()
+ {
+ }
+
+ void SAL_CALL
+ CEvent::initEvent(OUString const& eventTypeArg, sal_Bool canBubbleArg,
+ sal_Bool cancelableArg)
+ {
+ std::unique_lock const g(m_Mutex);
+
+ m_eventType = eventTypeArg;
+ m_bubbles = canBubbleArg;
+ m_cancelable = cancelableArg;
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/events/eventdispatcher.cxx b/unoxml/source/events/eventdispatcher.cxx
new file mode 100644
index 000000000..201f682f7
--- /dev/null
+++ b/unoxml/source/events/eventdispatcher.cxx
@@ -0,0 +1,251 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <eventdispatcher.hxx>
+
+#include <event.hxx>
+#include <mutationevent.hxx>
+#include <uievent.hxx>
+#include <mouseevent.hxx>
+
+#include "../dom/document.hxx"
+
+#include <osl/mutex.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+
+namespace DOM::events {
+
+ void CEventDispatcher::addListener(xmlNodePtr pNode, const OUString& aType, const Reference<XEventListener>& aListener, bool bCapture)
+ {
+ TypeListenerMap *const pTMap = bCapture
+ ? (& m_CaptureListeners) : (& m_TargetListeners);
+
+ // get the multimap for the specified type
+ ListenerMap *pMap = nullptr;
+ auto tIter = pTMap->find(aType);
+ if (tIter == pTMap->end()) {
+ // the map has to be created
+ auto const pair = pTMap->emplace(aType, ListenerMap());
+ pMap = & pair.first->second;
+ } else {
+ pMap = & tIter->second;
+ }
+ assert(pMap != nullptr);
+ pMap->emplace(pNode, aListener);
+ }
+
+ void CEventDispatcher::removeListener(xmlNodePtr pNode, const OUString& aType, const Reference<XEventListener>& aListener, bool bCapture)
+ {
+ TypeListenerMap *const pTMap = bCapture
+ ? (& m_CaptureListeners) : (& m_TargetListeners);
+
+ // get the multimap for the specified type
+ auto tIter = pTMap->find(aType);
+ if (tIter == pTMap->end())
+ return;
+
+ ListenerMap & rMap = tIter->second;
+ // find listeners of specified type for specified node
+ ListenerMap::iterator iter = rMap.find(pNode);
+ while (iter != rMap.end() && iter->first == pNode)
+ {
+ // erase all references to specified listener
+ if (iter->second.is() && iter->second == aListener)
+ {
+ iter = rMap.erase(iter);
+ }
+ else
+ ++iter;
+ }
+ }
+
+ CEventDispatcher::~CEventDispatcher()
+ {
+ }
+
+ void CEventDispatcher::callListeners(
+ TypeListenerMap const& rTMap,
+ xmlNodePtr const pNode,
+ const OUString& aType, Reference< XEvent > const& xEvent)
+ {
+ // get the multimap for the specified type
+ TypeListenerMap::const_iterator tIter = rTMap.find(aType);
+ if (tIter != rTMap.end()) {
+ ListenerMap const& rMap = tIter->second;
+ auto iterRange = rMap.equal_range(pNode);
+ for( auto iter = iterRange.first; iter != iterRange.second; ++iter )
+ {
+ if(iter->second.is())
+ (iter->second)->handleEvent(xEvent);
+ }
+ }
+ }
+
+ void CEventDispatcher::dispatchEvent(
+ DOM::CDocument & rDocument, ::osl::Mutex & rMutex,
+ xmlNodePtr const pNode, Reference<XNode> const& xNode,
+ Reference< XEvent > const& i_xEvent) const
+ {
+ TypeListenerMap captureListeners;
+ TypeListenerMap targetListeners;
+ {
+ ::osl::MutexGuard g(rMutex);
+
+ captureListeners = m_CaptureListeners;
+ targetListeners = m_TargetListeners;
+ }
+
+ if (captureListeners.empty() && targetListeners.empty())
+ return;
+
+ rtl::Reference<CEvent> pEvent; // pointer to internal event representation
+
+ OUString const aType = i_xEvent->getType();
+ if (aType == "DOMSubtreeModified" ||
+ aType == "DOMNodeInserted" ||
+ aType == "DOMNodeRemoved" ||
+ aType == "DOMNodeRemovedFromDocument" ||
+ aType == "DOMNodeInsertedIntoDocument" ||
+ aType == "DOMAttrModified" ||
+ aType == "DOMCharacterDataModified" )
+ {
+ Reference< XMutationEvent > const aMEvent(i_xEvent,
+ UNO_QUERY_THROW);
+ // dispatch a mutation event
+ // we need to clone the event in order to have complete control
+ // over the implementation
+ rtl::Reference<CMutationEvent> pMEvent = new CMutationEvent;
+ pMEvent->initMutationEvent(
+ aType, aMEvent->getBubbles(), aMEvent->getCancelable(),
+ aMEvent->getRelatedNode(), aMEvent->getPrevValue(),
+ aMEvent->getNewValue(), aMEvent->getAttrName(),
+ aMEvent->getAttrChange());
+ pEvent = pMEvent;
+ } else if ( // UIEvent
+ aType == "DOMFocusIn" ||
+ aType == "DOMFocusOut" ||
+ aType == "DOMActivate" )
+ {
+ Reference< XUIEvent > const aUIEvent(i_xEvent, UNO_QUERY_THROW);
+ rtl::Reference<CUIEvent> pUIEvent = new CUIEvent;
+ pUIEvent->initUIEvent(aType,
+ aUIEvent->getBubbles(), aUIEvent->getCancelable(),
+ aUIEvent->getView(), aUIEvent->getDetail());
+ pEvent = pUIEvent;
+ } else if ( // MouseEvent
+ aType == "click" ||
+ aType == "mousedown" ||
+ aType == "mouseup" ||
+ aType == "mouseover" ||
+ aType == "mousemove" ||
+ aType == "mouseout" )
+ {
+ Reference< XMouseEvent > const aMouseEvent(i_xEvent,
+ UNO_QUERY_THROW);
+ rtl::Reference<CMouseEvent> pMouseEvent = new CMouseEvent;
+ pMouseEvent->initMouseEvent(aType,
+ aMouseEvent->getBubbles(), aMouseEvent->getCancelable(),
+ aMouseEvent->getView(), aMouseEvent->getDetail(),
+ aMouseEvent->getScreenX(), aMouseEvent->getScreenY(),
+ aMouseEvent->getClientX(), aMouseEvent->getClientY(),
+ aMouseEvent->getCtrlKey(), aMouseEvent->getAltKey(),
+ aMouseEvent->getShiftKey(), aMouseEvent->getMetaKey(),
+ aMouseEvent->getButton(), aMouseEvent->getRelatedTarget());
+ pEvent = pMouseEvent;
+ }
+ else // generic event
+ {
+ pEvent = new CEvent;
+ pEvent->initEvent(
+ aType, i_xEvent->getBubbles(), i_xEvent->getCancelable());
+ }
+ pEvent->m_target.set(xNode, UNO_QUERY_THROW);
+ pEvent->m_currentTarget = i_xEvent->getCurrentTarget();
+ pEvent->m_time = i_xEvent->getTimeStamp();
+
+ // create the reference to the private event implementation
+ // that will be dispatched to the listeners
+ Reference< XEvent > const xEvent(pEvent);
+
+ // build the path from target node to the root
+ typedef std::vector< ::std::pair<Reference<XEventTarget>, xmlNodePtr> >
+ NodeVector_t;
+ NodeVector_t captureVector;
+ {
+ ::osl::MutexGuard g(rMutex);
+
+ xmlNodePtr cur = pNode;
+ while (cur != nullptr)
+ {
+ Reference< XEventTarget > const xRef(
+ rDocument.GetCNode(cur));
+ captureVector.emplace_back(xRef, cur);
+ cur = cur->parent;
+ }
+ }
+
+ // the capture vector now holds the node path from target to root
+ // first we must search for capture listeners in order root to
+ // to target. after that, any target listeners have to be called
+ // then bubbeling phase listeners are called in target to root
+ // order
+ // start at the root
+ NodeVector_t::const_reverse_iterator rinode =
+ const_cast<NodeVector_t const&>(captureVector).rbegin();
+ if (rinode == const_cast<NodeVector_t const&>(captureVector).rend())
+ return;
+
+ // capturing phase:
+ pEvent->m_phase = PhaseType_CAPTURING_PHASE;
+ while (rinode !=
+ const_cast<NodeVector_t const&>(captureVector).rend())
+ {
+ pEvent->m_currentTarget = rinode->first;
+ callListeners(captureListeners, rinode->second, aType, xEvent);
+ if (pEvent->m_canceled) return;
+ ++rinode;
+ }
+
+ NodeVector_t::const_iterator inode = captureVector.begin();
+
+ // target phase
+ pEvent->m_phase = PhaseType_AT_TARGET;
+ pEvent->m_currentTarget = inode->first;
+ callListeners(targetListeners, inode->second, aType, xEvent);
+ if (pEvent->m_canceled) return;
+ // bubbeling phase
+ ++inode;
+ if (i_xEvent->getBubbles()) {
+ pEvent->m_phase = PhaseType_BUBBLING_PHASE;
+ while (inode != captureVector.end())
+ {
+ pEvent->m_currentTarget = inode->first;
+ callListeners(targetListeners,
+ inode->second, aType, xEvent);
+ if (pEvent->m_canceled) return;
+ ++inode;
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/events/mouseevent.cxx b/unoxml/source/events/mouseevent.cxx
new file mode 100644
index 000000000..4ae8a1b55
--- /dev/null
+++ b/unoxml/source/events/mouseevent.cxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mouseevent.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom::events;
+using namespace css::xml::dom::views;
+
+namespace DOM::events
+{
+ CMouseEvent::CMouseEvent()
+ : m_screenX(0)
+ , m_screenY(0)
+ , m_clientX(0)
+ , m_clientY(0)
+ , m_ctrlKey(false)
+ , m_shiftKey(false)
+ , m_altKey(false)
+ , m_metaKey(false)
+ , m_button(0)
+ {
+ }
+
+ sal_Int32 SAL_CALL CMouseEvent::getScreenX()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_screenX;
+ }
+ sal_Int32 SAL_CALL CMouseEvent::getScreenY()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_screenY;
+ }
+ sal_Int32 SAL_CALL CMouseEvent::getClientX()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_clientX;
+ }
+ sal_Int32 SAL_CALL CMouseEvent::getClientY()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_clientY;
+ }
+ sal_Bool SAL_CALL CMouseEvent::getCtrlKey()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_ctrlKey;
+ }
+ sal_Bool SAL_CALL CMouseEvent::getShiftKey()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_shiftKey;
+ }
+ sal_Bool SAL_CALL CMouseEvent::getAltKey()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_altKey;
+ }
+ sal_Bool SAL_CALL CMouseEvent::getMetaKey()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_metaKey;
+ }
+ sal_Int16 SAL_CALL CMouseEvent::getButton()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_button;
+ }
+ Reference< XEventTarget > SAL_CALL CMouseEvent::getRelatedTarget()
+ {
+ return Reference< XEventTarget >();
+ }
+
+ void SAL_CALL CMouseEvent::initMouseEvent(
+ const OUString& typeArg,
+ sal_Bool canBubbleArg,
+ sal_Bool cancelableArg,
+ const Reference< XAbstractView >& viewArg,
+ sal_Int32 detailArg,
+ sal_Int32 screenXArg,
+ sal_Int32 screenYArg,
+ sal_Int32 clientXArg,
+ sal_Int32 clientYArg,
+ sal_Bool ctrlKeyArg,
+ sal_Bool altKeyArg,
+ sal_Bool shiftKeyArg,
+ sal_Bool metaKeyArg,
+ sal_Int16 buttonArg,
+ const Reference< XEventTarget >& /*relatedTargetArg*/)
+ {
+ CUIEvent::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
+ std::unique_lock const g(m_Mutex);
+ m_screenX = screenXArg;
+ m_screenY = screenYArg;
+ m_clientX = clientXArg;
+ m_clientY = clientYArg;
+ m_ctrlKey = ctrlKeyArg;
+ m_altKey = altKeyArg;
+ m_shiftKey = shiftKeyArg;
+ m_metaKey = metaKeyArg;
+ m_button = buttonArg;
+ }
+
+ // delegate to CUIEvent, since we are inheriting from CUIEvent and XUIEvent
+ Reference< XAbstractView > SAL_CALL CMouseEvent::getView()
+ {
+ return CUIEvent::getView();
+ }
+
+ sal_Int32 SAL_CALL CMouseEvent::getDetail()
+ {
+ return CUIEvent::getDetail();
+ }
+
+ void SAL_CALL CMouseEvent::initUIEvent(const OUString& typeArg,
+ sal_Bool canBubbleArg,
+ sal_Bool cancelableArg,
+ const Reference< XAbstractView >& viewArg,
+ sal_Int32 detailArg)
+ {
+ CUIEvent::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
+ }
+
+ OUString SAL_CALL CMouseEvent::getType()
+ {
+ return CUIEvent::getType();
+ }
+
+ Reference< XEventTarget > SAL_CALL CMouseEvent::getTarget()
+ {
+ return CUIEvent::getTarget();
+ }
+
+ Reference< XEventTarget > SAL_CALL CMouseEvent::getCurrentTarget()
+ {
+ return CUIEvent::getCurrentTarget();
+ }
+
+ PhaseType SAL_CALL CMouseEvent::getEventPhase()
+ {
+ return CUIEvent::getEventPhase();
+ }
+
+ sal_Bool SAL_CALL CMouseEvent::getBubbles()
+ {
+ return CEvent::getBubbles();
+ }
+
+ sal_Bool SAL_CALL CMouseEvent::getCancelable()
+ {
+ return CUIEvent::getCancelable();
+ }
+
+ css::util::Time SAL_CALL CMouseEvent::getTimeStamp()
+ {
+ return CUIEvent::getTimeStamp();
+ }
+
+ void SAL_CALL CMouseEvent::stopPropagation()
+ {
+ CUIEvent::stopPropagation();
+ }
+
+ void SAL_CALL CMouseEvent::preventDefault()
+ {
+ CUIEvent::preventDefault();
+ }
+
+ void SAL_CALL CMouseEvent::initEvent(const OUString& eventTypeArg, sal_Bool canBubbleArg,
+ sal_Bool cancelableArg)
+ {
+ // base initializer
+ CUIEvent::initEvent(eventTypeArg, canBubbleArg, cancelableArg);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/events/mutationevent.cxx b/unoxml/source/events/mutationevent.cxx
new file mode 100644
index 000000000..8ef91f0e3
--- /dev/null
+++ b/unoxml/source/events/mutationevent.cxx
@@ -0,0 +1,137 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <mutationevent.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::dom::events;
+
+namespace DOM::events
+{
+ CMutationEvent::CMutationEvent()
+ : m_attrChangeType(AttrChangeType_MODIFICATION)
+ {
+ }
+
+ CMutationEvent::~CMutationEvent()
+ {
+ }
+
+ Reference< XNode > SAL_CALL CMutationEvent::getRelatedNode()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_relatedNode;
+ }
+
+ OUString SAL_CALL CMutationEvent::getPrevValue()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_prevValue;
+ }
+
+ OUString SAL_CALL CMutationEvent::getNewValue()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_newValue;
+ }
+
+ OUString SAL_CALL CMutationEvent::getAttrName()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_attrName;
+ }
+
+ AttrChangeType SAL_CALL CMutationEvent::getAttrChange()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_attrChangeType;
+ }
+
+ void SAL_CALL CMutationEvent::initMutationEvent(const OUString& typeArg,
+ sal_Bool canBubbleArg, sal_Bool cancelableArg,
+ const Reference< XNode >& relatedNodeArg, const OUString& prevValueArg,
+ const OUString& newValueArg, const OUString& attrNameArg,
+ AttrChangeType attrChangeArg)
+ {
+ CEvent::initEvent(typeArg, canBubbleArg, cancelableArg);
+
+ std::unique_lock const g(m_Mutex);
+
+ m_relatedNode = relatedNodeArg;
+ m_prevValue = prevValueArg;
+ m_newValue = newValueArg;
+ m_attrName = attrNameArg;
+ m_attrChangeType = attrChangeArg;
+ }
+
+ // delegate to CEvent, since we are inheriting from CEvent and XEvent
+ OUString SAL_CALL CMutationEvent::getType()
+ {
+ return CEvent::getType();
+ }
+
+ Reference< XEventTarget > SAL_CALL CMutationEvent::getTarget()
+ {
+ return CEvent::getTarget();
+ }
+
+ Reference< XEventTarget > SAL_CALL CMutationEvent::getCurrentTarget()
+ {
+ return CEvent::getCurrentTarget();
+ }
+
+ PhaseType SAL_CALL CMutationEvent::getEventPhase()
+ {
+ return CEvent::getEventPhase();
+ }
+
+ sal_Bool SAL_CALL CMutationEvent::getBubbles()
+ {
+ return CEvent::getBubbles();
+ }
+
+ sal_Bool SAL_CALL CMutationEvent::getCancelable()
+ {
+ return CEvent::getCancelable();
+ }
+
+ css::util::Time SAL_CALL CMutationEvent::getTimeStamp()
+ {
+ return CEvent::getTimeStamp();
+ }
+
+ void SAL_CALL CMutationEvent::stopPropagation()
+ {
+ CEvent::stopPropagation();
+ }
+ void SAL_CALL CMutationEvent::preventDefault()
+ {
+ CEvent::preventDefault();
+ }
+
+ void SAL_CALL CMutationEvent::initEvent(const OUString& eventTypeArg, sal_Bool canBubbleArg,
+ sal_Bool cancelableArg)
+ {
+ // base initializer
+ CEvent::initEvent(eventTypeArg, canBubbleArg, cancelableArg);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/events/uievent.cxx b/unoxml/source/events/uievent.cxx
new file mode 100644
index 000000000..be61ca5cf
--- /dev/null
+++ b/unoxml/source/events/uievent.cxx
@@ -0,0 +1,113 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <uievent.hxx>
+
+using namespace css::uno;
+using namespace css::xml::dom::events;
+using namespace css::xml::dom::views;
+
+namespace DOM::events
+{
+ CUIEvent::CUIEvent()
+ : m_detail(0)
+ {
+ }
+
+ Reference< XAbstractView > SAL_CALL
+ CUIEvent::getView()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_view;
+ }
+
+ sal_Int32 SAL_CALL CUIEvent::getDetail()
+ {
+ std::unique_lock const g(m_Mutex);
+ return m_detail;
+ }
+
+ void SAL_CALL CUIEvent::initUIEvent(const OUString& typeArg,
+ sal_Bool canBubbleArg,
+ sal_Bool cancelableArg,
+ const Reference< XAbstractView >& viewArg,
+ sal_Int32 detailArg)
+ {
+ CEvent::initEvent(typeArg, canBubbleArg, cancelableArg);
+ std::unique_lock const g(m_Mutex);
+ m_view = viewArg;
+ m_detail = detailArg;
+ }
+
+
+ // delegate to CEvent, since we are inheriting from CEvent and XEvent
+ OUString SAL_CALL CUIEvent::getType()
+ {
+ return CEvent::getType();
+ }
+
+ Reference< XEventTarget > SAL_CALL CUIEvent::getTarget()
+ {
+ return CEvent::getTarget();
+ }
+
+ Reference< XEventTarget > SAL_CALL CUIEvent::getCurrentTarget()
+ {
+ return CEvent::getCurrentTarget();
+ }
+
+ PhaseType SAL_CALL CUIEvent::getEventPhase()
+ {
+ return CEvent::getEventPhase();
+ }
+
+ sal_Bool SAL_CALL CUIEvent::getBubbles()
+ {
+ return CEvent::getBubbles();
+ }
+
+ sal_Bool SAL_CALL CUIEvent::getCancelable()
+ {
+ // mutation events cannot be canceled
+ return false;
+ }
+
+ css::util::Time SAL_CALL CUIEvent::getTimeStamp()
+ {
+ return CEvent::getTimeStamp();
+ }
+
+ void SAL_CALL CUIEvent::stopPropagation()
+ {
+ CEvent::stopPropagation();
+ }
+ void SAL_CALL CUIEvent::preventDefault()
+ {
+ CEvent::preventDefault();
+ }
+
+ void SAL_CALL CUIEvent::initEvent(const OUString& eventTypeArg, sal_Bool canBubbleArg,
+ sal_Bool cancelableArg)
+ {
+ // base initializer
+ CEvent::initEvent(eventTypeArg, canBubbleArg, cancelableArg);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/rdf/CBlankNode.cxx b/unoxml/source/rdf/CBlankNode.cxx
new file mode 100644
index 000000000..6e0140cc9
--- /dev/null
+++ b/unoxml/source/rdf/CBlankNode.cxx
@@ -0,0 +1,117 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/rdf/XBlankNode.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+
+/// anonymous implementation namespace
+namespace {
+
+class CBlankNode:
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::rdf::XBlankNode>
+{
+public:
+ CBlankNode();
+
+ // css::lang::XServiceInfo:
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::rdf::XNode:
+ virtual OUString SAL_CALL getStringValue() override;
+
+private:
+ CBlankNode(CBlankNode const&) = delete;
+ CBlankNode& operator=(CBlankNode const&) = delete;
+
+ OUString m_NodeID;
+};
+
+CBlankNode::CBlankNode()
+{}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL CBlankNode::getImplementationName()
+{
+ return "CBlankNode";
+}
+
+sal_Bool SAL_CALL CBlankNode::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL CBlankNode::getSupportedServiceNames()
+{
+ return { "com.sun.star.rdf.BlankNode" };
+}
+
+// css::lang::XInitialization:
+void SAL_CALL CBlankNode::initialize(const css::uno::Sequence< css::uno::Any > & aArguments)
+{
+ if (aArguments.getLength() != 1) {
+ throw css::lang::IllegalArgumentException(
+ "CBlankNode::initialize: must give exactly 1 argument", *this, 1);
+ }
+
+ OUString arg;
+ if (!(aArguments[0] >>= arg)) {
+ throw css::lang::IllegalArgumentException(
+ "CBlankNode::initialize: argument must be string", *this, 0);
+ }
+
+ //FIXME: what is legal?
+ if (arg.isEmpty()) {
+ throw css::lang::IllegalArgumentException(
+ "CBlankNode::initialize: argument is not valid blank node ID", *this, 0);
+ }
+ m_NodeID = arg;
+}
+
+// css::rdf::XNode:
+OUString SAL_CALL CBlankNode::getStringValue()
+{
+ return m_NodeID;
+}
+
+} // closing anonymous implementation namespace
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CBlankNode_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new CBlankNode());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/rdf/CLiteral.cxx b/unoxml/source/rdf/CLiteral.cxx
new file mode 100644
index 000000000..b1c756883
--- /dev/null
+++ b/unoxml/source/rdf/CLiteral.cxx
@@ -0,0 +1,167 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/rdf/XLiteral.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+
+/// anonymous implementation namespace
+namespace {
+
+class CLiteral:
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::rdf::XLiteral>
+{
+public:
+ explicit CLiteral();
+
+ // css::lang::XServiceInfo:
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::rdf::XNode:
+ virtual OUString SAL_CALL getStringValue() override;
+
+ // css::rdf::XLiteral:
+ virtual OUString SAL_CALL getValue() override;
+ virtual OUString SAL_CALL getLanguage() override;
+ virtual css::uno::Reference< css::rdf::XURI > SAL_CALL getDatatype() override;
+
+private:
+ CLiteral(CLiteral const&) = delete;
+ CLiteral& operator=(CLiteral const&) = delete;
+
+ OUString m_Value;
+ OUString m_Language;
+ css::uno::Reference< css::rdf::XURI > m_xDatatype;
+};
+
+CLiteral::CLiteral()
+{}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL CLiteral::getImplementationName()
+{
+ return "CLiteral";
+}
+
+sal_Bool SAL_CALL CLiteral::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL CLiteral::getSupportedServiceNames()
+{
+ return { "com.sun.star.rdf.Literal" };
+}
+
+// css::lang::XInitialization:
+void SAL_CALL CLiteral::initialize(const css::uno::Sequence< css::uno::Any > & aArguments)
+{
+ const sal_Int32 len( aArguments.getLength() );
+ if (len < 1 || len > 2) {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: must give 1 or 2 argument(s)", *this, 2);
+ }
+
+ OUString arg0;
+ if (!(aArguments[0] >>= arg0)) {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: argument must be string", *this, 0);
+ }
+ //FIXME: what is legal?
+ if (!(true)) {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: argument is not valid literal value", *this, 0);
+ }
+ m_Value = arg0;
+
+ if (len <= 1)
+ return;
+
+ OUString arg1;
+ css::uno::Reference< css::rdf::XURI > xURI;
+ if (aArguments[1] >>= arg1) {
+ if (arg1.isEmpty()) {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: argument is not valid language", *this, 1);
+ }
+ m_Language = arg1;
+ } else if (aArguments[1] >>= xURI) {
+ if (!xURI.is()) {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: argument is null", *this, 1);
+ }
+ m_xDatatype = xURI;
+ } else {
+ throw css::lang::IllegalArgumentException(
+ "CLiteral::initialize: argument must be string or URI", *this, 1);
+ }
+}
+
+// css::rdf::XNode:
+OUString SAL_CALL CLiteral::getStringValue()
+{
+ if (!m_Language.isEmpty()) {
+ return m_Value + "@" + m_Language;
+ } else if (m_xDatatype.is()) {
+ return m_Value + "^^" + m_xDatatype->getStringValue();
+ } else {
+ return m_Value;
+ }
+}
+
+// css::rdf::XLiteral:
+OUString SAL_CALL CLiteral::getValue()
+{
+ return m_Value;
+}
+
+OUString SAL_CALL CLiteral::getLanguage()
+{
+ return m_Language;
+}
+
+css::uno::Reference< css::rdf::XURI > SAL_CALL CLiteral::getDatatype()
+{
+ return m_xDatatype;
+}
+
+} // closing anonymous implementation namespace
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CLiteral_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new CLiteral());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/rdf/CURI.cxx b/unoxml/source/rdf/CURI.cxx
new file mode 100644
index 000000000..488aa3e90
--- /dev/null
+++ b/unoxml/source/rdf/CURI.cxx
@@ -0,0 +1,807 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/rdf/XURI.hpp>
+#include <com/sun/star/rdf/URIs.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+
+/// anonymous implementation namespace
+namespace {
+
+class CURI:
+ public ::cppu::WeakImplHelper<
+ css::lang::XServiceInfo,
+ css::lang::XInitialization,
+ css::rdf::XURI>
+{
+public:
+ explicit CURI();
+
+ // css::lang::XServiceInfo:
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString & ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::rdf::XNode:
+ virtual OUString SAL_CALL getStringValue() override;
+
+ // css::rdf::XURI:
+ virtual OUString SAL_CALL getLocalName() override;
+ virtual OUString SAL_CALL getNamespace() override;
+
+private:
+ CURI(CURI const&) = delete;
+ CURI& operator=(CURI const&) = delete;
+
+ /// handle css.rdf.URIs
+ void initFromConstant(const sal_Int16 i_Constant);
+
+ OUString m_Namespace;
+ OUString m_LocalName;
+};
+
+CURI::CURI()
+{}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL CURI::getImplementationName()
+{
+ return "CURI";
+}
+
+sal_Bool SAL_CALL CURI::supportsService(OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+css::uno::Sequence< OUString > SAL_CALL CURI::getSupportedServiceNames()
+{
+ return { "com.sun.star.rdf.URI" };
+}
+
+const char s_nsXSD [] = "http://www.w3.org/2001/XMLSchema-datatypes#";
+const char s_nsRDF [] = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+const char s_nsRDFs [] = "http://www.w3.org/2000/01/rdf-schema#";
+const char s_nsOWL [] = "http://www.w3.org/2002/07/owl#";
+const char s_nsPkg [] =
+ "http://docs.oasis-open.org/ns/office/1.2/meta/pkg#";
+const char s_nsODF [] =
+ "http://docs.oasis-open.org/ns/office/1.2/meta/odf#";
+const char s_nsLO_EXT [] =
+ "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0odf#";
+
+void CURI::initFromConstant(const sal_Int16 i_Constant)
+{
+ const char *ns(nullptr);
+ const char *ln(nullptr);
+ switch (i_Constant)
+ {
+ case css::rdf::URIs::XSD_NCNAME:
+ ns = s_nsXSD;
+ ln = "NCName";
+ break;
+
+ case css::rdf::URIs::XSD_STRING:
+ ns = s_nsXSD;
+ ln = "string";
+ break;
+
+ case css::rdf::URIs::XSD_NORMALIZEDSTRING:
+ ns = s_nsXSD;
+ ln = "normalizedString";
+ break;
+
+ case css::rdf::URIs::XSD_BOOLEAN:
+ ns = s_nsXSD;
+ ln = "boolean";
+ break;
+
+ case css::rdf::URIs::XSD_DECIMAL:
+ ns = s_nsXSD;
+ ln = "decimal";
+ break;
+
+ case css::rdf::URIs::XSD_FLOAT:
+ ns = s_nsXSD;
+ ln = "float";
+ break;
+
+ case css::rdf::URIs::XSD_DOUBLE:
+ ns = s_nsXSD;
+ ln = "double";
+ break;
+
+ case css::rdf::URIs::XSD_INTEGER:
+ ns = s_nsXSD;
+ ln = "integer";
+ break;
+
+ case css::rdf::URIs::XSD_NONNEGATIVEINTEGER:
+ ns = s_nsXSD;
+ ln = "nonNegativeInteger";
+ break;
+
+ case css::rdf::URIs::XSD_POSITIVEINTEGER:
+ ns = s_nsXSD;
+ ln = "positiveInteger";
+ break;
+
+ case css::rdf::URIs::XSD_NONPOSITIVEINTEGER:
+ ns = s_nsXSD;
+ ln = "nonPositiveInteger";
+ break;
+
+ case css::rdf::URIs::XSD_NEGATIVEINTEGER:
+ ns = s_nsXSD;
+ ln = "negativeInteger";
+ break;
+
+ case css::rdf::URIs::XSD_LONG:
+ ns = s_nsXSD;
+ ln = "long";
+ break;
+
+ case css::rdf::URIs::XSD_INT:
+ ns = s_nsXSD;
+ ln = "int";
+ break;
+
+ case css::rdf::URIs::XSD_SHORT:
+ ns = s_nsXSD;
+ ln = "short";
+ break;
+
+ case css::rdf::URIs::XSD_BYTE:
+ ns = s_nsXSD;
+ ln = "byte";
+ break;
+
+ case css::rdf::URIs::XSD_UNSIGNEDLONG:
+ ns = s_nsXSD;
+ ln = "unsignedLong";
+ break;
+
+ case css::rdf::URIs::XSD_UNSIGNEDINT:
+ ns = s_nsXSD;
+ ln = "unsignedInt";
+ break;
+
+ case css::rdf::URIs::XSD_UNSIGNEDSHORT:
+ ns = s_nsXSD;
+ ln = "unsignedShort";
+ break;
+
+ case css::rdf::URIs::XSD_UNSIGNEDBYTE:
+ ns = s_nsXSD;
+ ln = "unsignedByte";
+ break;
+
+ case css::rdf::URIs::XSD_HEXBINARY:
+ ns = s_nsXSD;
+ ln = "hexBinary";
+ break;
+
+ case css::rdf::URIs::XSD_BASE64BINARY:
+ ns = s_nsXSD;
+ ln = "base64Binary";
+ break;
+
+ case css::rdf::URIs::XSD_DATETIME:
+ ns = s_nsXSD;
+ ln = "dateTime";
+ break;
+
+ case css::rdf::URIs::XSD_TIME:
+ ns = s_nsXSD;
+ ln = "time";
+ break;
+
+ case css::rdf::URIs::XSD_DATE:
+ ns = s_nsXSD;
+ ln = "date";
+ break;
+
+ case css::rdf::URIs::XSD_GYEARMONTH:
+ ns = s_nsXSD;
+ ln = "gYearMonth";
+ break;
+
+ case css::rdf::URIs::XSD_GYEAR:
+ ns = s_nsXSD;
+ ln = "gYear";
+ break;
+
+ case css::rdf::URIs::XSD_GMONTHDAY:
+ ns = s_nsXSD;
+ ln = "gMonthDay";
+ break;
+
+ case css::rdf::URIs::XSD_GDAY:
+ ns = s_nsXSD;
+ ln = "gDay";
+ break;
+
+ case css::rdf::URIs::XSD_GMONTH:
+ ns = s_nsXSD;
+ ln = "gMonth";
+ break;
+
+ case css::rdf::URIs::XSD_ANYURI:
+ ns = s_nsXSD;
+ ln = "anyURI";
+ break;
+
+ case css::rdf::URIs::XSD_TOKEN:
+ ns = s_nsXSD;
+ ln = "token";
+ break;
+
+ case css::rdf::URIs::XSD_LANGUAGE:
+ ns = s_nsXSD;
+ ln = "language";
+ break;
+
+ case css::rdf::URIs::XSD_NMTOKEN:
+ ns = s_nsXSD;
+ ln = "NMTOKEN";
+ break;
+
+ case css::rdf::URIs::XSD_NAME:
+ ns = s_nsXSD;
+ ln = "Name";
+ break;
+
+ case css::rdf::URIs::XSD_DURATION:
+ ns = s_nsXSD;
+ ln = "duration";
+ break;
+
+ case css::rdf::URIs::XSD_QNAME:
+ ns = s_nsXSD;
+ ln = "QName";
+ break;
+
+ case css::rdf::URIs::XSD_NOTATION:
+ ns = s_nsXSD;
+ ln = "NOTATION";
+ break;
+
+ case css::rdf::URIs::XSD_NMTOKENS:
+ ns = s_nsXSD;
+ ln = "NMTOKENS";
+ break;
+
+ case css::rdf::URIs::XSD_ID:
+ ns = s_nsXSD;
+ ln = "ID";
+ break;
+
+ case css::rdf::URIs::XSD_IDREF:
+ ns = s_nsXSD;
+ ln = "IDREF";
+ break;
+
+ case css::rdf::URIs::XSD_IDREFS:
+ ns = s_nsXSD;
+ ln = "IDREFS";
+ break;
+
+ case css::rdf::URIs::XSD_ENTITY:
+ ns = s_nsXSD;
+ ln = "ENTITY";
+ break;
+
+ case css::rdf::URIs::XSD_ENTITIES:
+ ns = s_nsXSD;
+ ln = "ENTITIES";
+ break;
+
+ case css::rdf::URIs::RDF_TYPE:
+ ns = s_nsRDF;
+ ln = "type";
+ break;
+
+ case css::rdf::URIs::RDF_SUBJECT:
+ ns = s_nsRDF;
+ ln = "subject";
+ break;
+
+ case css::rdf::URIs::RDF_PREDICATE:
+ ns = s_nsRDF;
+ ln = "predicate";
+ break;
+
+ case css::rdf::URIs::RDF_OBJECT:
+ ns = s_nsRDF;
+ ln = "object";
+ break;
+
+ case css::rdf::URIs::RDF_PROPERTY:
+ ns = s_nsRDF;
+ ln = "Property";
+ break;
+
+ case css::rdf::URIs::RDF_STATEMENT:
+ ns = s_nsRDF;
+ ln = "Statement";
+ break;
+
+ case css::rdf::URIs::RDF_VALUE:
+ ns = s_nsRDF;
+ ln = "value";
+ break;
+
+ case css::rdf::URIs::RDF_FIRST:
+ ns = s_nsRDF;
+ ln = "first";
+ break;
+
+ case css::rdf::URIs::RDF_REST:
+ ns = s_nsRDF;
+ ln = "rest";
+ break;
+
+ case css::rdf::URIs::RDF_NIL:
+ ns = s_nsRDF;
+ ln = "nil";
+ break;
+
+ case css::rdf::URIs::RDF_XMLLITERAL:
+ ns = s_nsRDF;
+ ln = "XMLLiteral";
+ break;
+
+ case css::rdf::URIs::RDF_ALT:
+ ns = s_nsRDF;
+ ln = "Alt";
+ break;
+
+ case css::rdf::URIs::RDF_BAG:
+ ns = s_nsRDF;
+ ln = "Bag";
+ break;
+
+ case css::rdf::URIs::RDF_LIST:
+ ns = s_nsRDF;
+ ln = "List";
+ break;
+
+ case css::rdf::URIs::RDF_SEQ:
+ ns = s_nsRDF;
+ ln = "Seq";
+ break;
+
+ case css::rdf::URIs::RDF_1:
+ ns = s_nsRDF;
+ ln = "_1";
+ break;
+
+ case css::rdf::URIs::RDFS_COMMENT:
+ ns = s_nsRDFs;
+ ln = "comment";
+ break;
+
+ case css::rdf::URIs::RDFS_LABEL:
+ ns = s_nsRDFs;
+ ln = "label";
+ break;
+
+ case css::rdf::URIs::RDFS_DOMAIN:
+ ns = s_nsRDFs;
+ ln = "domain";
+ break;
+
+ case css::rdf::URIs::RDFS_RANGE:
+ ns = s_nsRDFs;
+ ln = "range";
+ break;
+
+ case css::rdf::URIs::RDFS_SUBCLASSOF:
+ ns = s_nsRDFs;
+ ln = "subClassOf";
+ break;
+
+ case css::rdf::URIs::RDFS_LITERAL:
+ ns = s_nsRDFs;
+ ln = "Literal";
+ break;
+
+ case css::rdf::URIs::OWL_CLASS:
+ ns = s_nsOWL;
+ ln = "Class";
+ break;
+
+ case css::rdf::URIs::OWL_OBJECTPROPERTY:
+ ns = s_nsOWL;
+ ln = "ObjectProperty";
+ break;
+
+ case css::rdf::URIs::OWL_DATATYPEPROPERTY:
+ ns = s_nsOWL;
+ ln = "DatatypeProperty";
+ break;
+
+ case css::rdf::URIs::OWL_FUNCTIONALPROPERTY:
+ ns = s_nsOWL;
+ ln = "FunctionalProperty";
+ break;
+
+ case css::rdf::URIs::OWL_THING:
+ ns = s_nsOWL;
+ ln = "Thing";
+ break;
+
+ case css::rdf::URIs::OWL_NOTHING:
+ ns = s_nsOWL;
+ ln = "Nothing";
+ break;
+
+ case css::rdf::URIs::OWL_INDIVIDUAL:
+ ns = s_nsOWL;
+ ln = "Individual";
+ break;
+
+ case css::rdf::URIs::OWL_EQUIVALENTCLASS:
+ ns = s_nsOWL;
+ ln = "equivalentClass";
+ break;
+
+ case css::rdf::URIs::OWL_EQUIVALENTPROPERTY:
+ ns = s_nsOWL;
+ ln = "equivalentProperty";
+ break;
+
+ case css::rdf::URIs::OWL_SAMEAS:
+ ns = s_nsOWL;
+ ln = "sameAs";
+ break;
+
+ case css::rdf::URIs::OWL_DIFFERENTFROM:
+ ns = s_nsOWL;
+ ln = "differentFrom";
+ break;
+
+ case css::rdf::URIs::OWL_ALLDIFFERENT:
+ ns = s_nsOWL;
+ ln = "AllDifferent";
+ break;
+
+ case css::rdf::URIs::OWL_DISTINCTMEMBERS:
+ ns = s_nsOWL;
+ ln = "distinctMembers";
+ break;
+
+ case css::rdf::URIs::OWL_INVERSEOF:
+ ns = s_nsOWL;
+ ln = "inverseOf";
+ break;
+
+ case css::rdf::URIs::OWL_TRANSITIVEPROPERTY:
+ ns = s_nsOWL;
+ ln = "TransitiveProperty";
+ break;
+
+ case css::rdf::URIs::OWL_SYMMETRICPROPERTY:
+ ns = s_nsOWL;
+ ln = "SymmetricProperty";
+ break;
+
+ case css::rdf::URIs::OWL_INVERSEFUNCTIONALPROPERTY:
+ ns = s_nsOWL;
+ ln = "InverseFunctionalProperty";
+ break;
+
+ case css::rdf::URIs::OWL_RESTRICTION:
+ ns = s_nsOWL;
+ ln = "Restriction";
+ break;
+
+ case css::rdf::URIs::OWL_ONPROPERTY:
+ ns = s_nsOWL;
+ ln = "onProperty";
+ break;
+
+ case css::rdf::URIs::OWL_ALLVALUESFROM:
+ ns = s_nsOWL;
+ ln = "allValuesFrom";
+ break;
+
+ case css::rdf::URIs::OWL_SOMEVALUESFROM:
+ ns = s_nsOWL;
+ ln = "someValuesFrom";
+ break;
+
+ case css::rdf::URIs::OWL_MINCARDINALITY:
+ ns = s_nsOWL;
+ ln = "minCardinality";
+ break;
+
+ case css::rdf::URIs::OWL_MAXCARDINALITY:
+ ns = s_nsOWL;
+ ln = "maxCardinality";
+ break;
+
+ case css::rdf::URIs::OWL_CARDINALITY:
+ ns = s_nsOWL;
+ ln = "cardinality";
+ break;
+
+ case css::rdf::URIs::OWL_ONTOLOGY:
+ ns = s_nsOWL;
+ ln = "Ontology";
+ break;
+
+ case css::rdf::URIs::OWL_IMPORTS:
+ ns = s_nsOWL;
+ ln = "imports";
+ break;
+
+ case css::rdf::URIs::OWL_VERSIONINFO:
+ ns = s_nsOWL;
+ ln = "versionInfo";
+ break;
+
+ case css::rdf::URIs::OWL_PRIORVERSION:
+ ns = s_nsOWL;
+ ln = "priorVersion";
+ break;
+
+ case css::rdf::URIs::OWL_BACKWARDCOMPATIBLEWITH:
+ ns = s_nsOWL;
+ ln = "backwardCompatibleWith";
+ break;
+
+ case css::rdf::URIs::OWL_INCOMPATIBLEWITH:
+ ns = s_nsOWL;
+ ln = "incompatibleWith";
+ break;
+
+ case css::rdf::URIs::OWL_DEPRECATEDCLASS:
+ ns = s_nsOWL;
+ ln = "DeprecatedClass";
+ break;
+
+ case css::rdf::URIs::OWL_DEPRECATEDPROPERTY:
+ ns = s_nsOWL;
+ ln = "DeprecatedProperty";
+ break;
+
+ case css::rdf::URIs::OWL_ANNOTATIONPROPERTY:
+ ns = s_nsOWL;
+ ln = "AnnotationProperty";
+ break;
+
+ case css::rdf::URIs::OWL_ONTOLOGYPROPERTY:
+ ns = s_nsOWL;
+ ln = "OntologyProperty";
+ break;
+
+ case css::rdf::URIs::OWL_ONEOF:
+ ns = s_nsOWL;
+ ln = "oneOf";
+ break;
+
+ case css::rdf::URIs::OWL_DATARANGE:
+ ns = s_nsOWL;
+ ln = "dataRange";
+ break;
+
+ case css::rdf::URIs::OWL_DISJOINTWITH:
+ ns = s_nsOWL;
+ ln = "disjointWith";
+ break;
+
+ case css::rdf::URIs::OWL_UNIONOF:
+ ns = s_nsOWL;
+ ln = "unionOf";
+ break;
+
+ case css::rdf::URIs::OWL_COMPLEMENTOF:
+ ns = s_nsOWL;
+ ln = "complementOf";
+ break;
+
+ case css::rdf::URIs::OWL_INTERSECTIONOF:
+ ns = s_nsOWL;
+ ln = "intersectionOf";
+ break;
+
+ case css::rdf::URIs::OWL_HASVALUE:
+ ns = s_nsOWL;
+ ln = "hasValue";
+ break;
+
+
+ case css::rdf::URIs::PKG_HASPART:
+ ns = s_nsPkg;
+ ln = "hasPart";
+ break;
+
+ case css::rdf::URIs::PKG_MIMETYPE:
+ ns = s_nsPkg;
+ ln = "mimeType";
+ break;
+
+ case css::rdf::URIs::PKG_PACKAGE:
+ ns = s_nsPkg;
+ ln = "Package";
+ break;
+
+ case css::rdf::URIs::PKG_ELEMENT:
+ ns = s_nsPkg;
+ ln = "Element";
+ break;
+
+ case css::rdf::URIs::PKG_FILE:
+ ns = s_nsPkg;
+ ln = "File";
+ break;
+
+ case css::rdf::URIs::PKG_METADATAFILE:
+ ns = s_nsPkg;
+ ln = "MetadataFile";
+ break;
+
+ case css::rdf::URIs::PKG_DOCUMENT:
+ ns = s_nsPkg;
+ ln = "Document";
+ break;
+
+ case css::rdf::URIs::ODF_PREFIX:
+ ns = s_nsODF;
+ ln = "prefix";
+ break;
+
+ case css::rdf::URIs::ODF_SUFFIX:
+ ns = s_nsODF;
+ ln = "suffix";
+ break;
+
+ case css::rdf::URIs::ODF_ELEMENT:
+ ns = s_nsODF;
+ ln = "Element";
+ break;
+
+ case css::rdf::URIs::ODF_CONTENTFILE:
+ ns = s_nsODF;
+ ln = "ContentFile";
+ break;
+
+ case css::rdf::URIs::ODF_STYLESFILE:
+ ns = s_nsODF;
+ ln = "StylesFile";
+ break;
+
+ case css::rdf::URIs::LO_EXT_SHADING:
+ ns = s_nsLO_EXT;
+ ln = "shading";
+ break;
+
+ default:
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: invalid URIs constant argument", *this, 0);
+ }
+ m_Namespace = OUString::createFromAscii(ns).intern();
+ m_LocalName = OUString::createFromAscii(ln).intern();
+}
+
+// css::lang::XInitialization:
+void SAL_CALL CURI::initialize(const css::uno::Sequence< css::uno::Any > & aArguments)
+{
+ sal_Int32 len = aArguments.getLength();
+ if ((len < 1) || (len > 2)) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: must give 1 or 2 argument(s)", *this, 2);
+ }
+
+ sal_Int16 arg(0);
+ OUString arg0;
+ OUString arg1;
+ if (aArguments[0] >>= arg) {
+ // integer argument: constant from rdf::URIs
+ if (len != 1) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: must give 1 int argument", *this, 1);
+ }
+ initFromConstant(arg);
+ return;
+ }
+ if (!(aArguments[0] >>= arg0)) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: argument must be string or short", *this, 0);
+ }
+ if (len > 1) {
+ if (!(aArguments[1] >>= arg1)) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: argument must be string", *this, 1);
+ }
+ // just append the parameters and then split them again; seems simplest
+ arg0 = arg0 + arg1;
+ arg1.clear();
+ }
+
+ // split parameter
+ sal_Int32 idx = arg0.indexOf('#');
+ if (idx < 0)
+ idx = arg0.lastIndexOf('/');
+ if (idx < 0)
+ idx = arg0.lastIndexOf(':');
+ if (idx < 0)
+ {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: argument not splittable: no separator [#/:]", *this, 0);
+ }
+ if (idx < arg0.getLength() - 1) {
+ arg1 = arg0.copy(idx+1);
+ arg0 = arg0.copy(0, idx+1);
+ }
+
+ //FIXME: what is legal?
+ if (arg0.isEmpty()) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: argument is not valid namespace", *this, 0);
+ }
+ m_Namespace = arg0;
+
+ //FIXME: what is legal?
+ if ((false)) {
+ throw css::lang::IllegalArgumentException(
+ "CURI::initialize: argument is not valid local name", *this, 1);
+ }
+ m_LocalName = arg1;
+}
+
+// css::rdf::XNode:
+OUString SAL_CALL CURI::getStringValue()
+{
+ return m_Namespace + m_LocalName;
+}
+
+// css::rdf::XURI:
+OUString SAL_CALL CURI::getNamespace()
+{
+ return m_Namespace;
+}
+
+OUString SAL_CALL CURI::getLocalName()
+{
+ return m_LocalName;
+}
+
+} // closing anonymous implementation namespace
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CURI_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new CURI());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/rdf/librdf_repository.cxx b/unoxml/source/rdf/librdf_repository.cxx
new file mode 100644
index 000000000..51c8317f3
--- /dev/null
+++ b/unoxml/source/rdf/librdf_repository.cxx
@@ -0,0 +1,2465 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <string.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <string_view>
+#include <iterator>
+#include <algorithm>
+#include <atomic>
+
+#include <optional>
+
+#include <libxslt/security.h>
+
+#include <redland.h>
+
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/rdf/ParseException.hpp>
+#include <com/sun/star/rdf/QueryException.hpp>
+#include <com/sun/star/rdf/RepositoryException.hpp>
+#include <com/sun/star/rdf/XDocumentRepository.hpp>
+#include <com/sun/star/rdf/XLiteral.hpp>
+#include <com/sun/star/rdf/FileFormat.hpp>
+#include <com/sun/star/rdf/BlankNode.hpp>
+#include <com/sun/star/rdf/URI.hpp>
+#include <com/sun/star/rdf/Literal.hpp>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <rtl/ustring.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/weakref.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/xmltools.hxx>
+
+#include <com/sun/star/embed/XEncryptionProtectedSource2.hpp>
+
+/**
+ Implementation of the service com.sun.star.rdf.Repository.
+
+ This implementation uses the Redland RDF library (librdf).
+
+ There are several classes involved:
+ librdf_TypeConverter: helper class to convert data types redland <-> uno
+ librdf_Repository: the main repository, does almost all the work
+ librdf_NamedGraph: the XNamedGraph, forwards everything to repository
+ librdf_GraphResult: an XEnumeration<Statement>
+ librdf_QuerySelectResult: an XEnumeration<sequence<XNode>>
+
+ */
+
+/// anonymous implementation namespace
+namespace {
+
+class librdf_NamedGraph;
+class librdf_Repository;
+
+using namespace ::com::sun::star;
+
+typedef std::map< OUString, ::rtl::Reference<librdf_NamedGraph> >
+ NamedGraphMap_t;
+
+const char s_sparql [] = "sparql";
+const char s_nsOOo [] = "http://openoffice.org/2004/office/rdfa/";
+
+
+//FIXME: this approach is not ideal. can we use blank nodes instead?
+bool isInternalContext(librdf_node *i_pNode) noexcept
+{
+ OSL_ENSURE(i_pNode, "isInternalContext: context null");
+ OSL_ENSURE(librdf_node_is_resource(i_pNode),
+ "isInternalContext: context not resource");
+ if (i_pNode) {
+ librdf_uri *pURI(librdf_node_get_uri(i_pNode));
+ OSL_ENSURE(pURI, "isInternalContext: URI null");
+ if (pURI) {
+ unsigned char *pContextURI(librdf_uri_as_string(pURI));
+ assert(pContextURI && "isInternalContext: URI string null");
+ // if prefix matches reserved uri, it is RDFa context
+ if (!strncmp(reinterpret_cast<char *>(pContextURI),
+ s_nsOOo, sizeof(s_nsOOo)-1)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+}
+
+
+// n.b.: librdf destructor functions dereference null pointers!
+// so they need to be wrapped to be usable with std::shared_ptr.
+void safe_librdf_free_world(librdf_world *const world)
+{
+ if (world) { librdf_free_world(world); }
+}
+void safe_librdf_free_model(librdf_model *const model)
+{
+ if (model) { librdf_free_model(model); }
+}
+void safe_librdf_free_node(librdf_node* node)
+{
+ if (node) { librdf_free_node(node); }
+}
+void safe_librdf_free_parser(librdf_parser *const parser)
+{
+ if (parser) { librdf_free_parser(parser); }
+}
+void safe_librdf_free_query(librdf_query *const query)
+{
+ if (query) { librdf_free_query(query); }
+}
+void
+safe_librdf_free_query_results(librdf_query_results *const query_results)
+{
+ if (query_results) { librdf_free_query_results(query_results); }
+}
+void safe_librdf_free_serializer(librdf_serializer *const serializer)
+{
+ if (serializer) { librdf_free_serializer(serializer); }
+}
+void safe_librdf_free_statement(librdf_statement *const statement)
+{
+ if (statement) { librdf_free_statement(statement); }
+}
+void safe_librdf_free_storage(librdf_storage *const storage)
+{
+ if (storage) { librdf_free_storage(storage); }
+}
+void safe_librdf_free_stream(librdf_stream *const stream)
+{
+ if (stream) { librdf_free_stream(stream); }
+}
+void safe_librdf_free_uri(librdf_uri *const uri)
+{
+ if (uri) { librdf_free_uri(uri); }
+}
+
+
+/** converts between librdf types and UNO API types.
+ */
+class librdf_TypeConverter
+{
+public:
+
+ // some wrapper classes to temporarily hold values of UNO XNodes
+ struct Node
+ {
+ virtual ~Node() {}
+ };
+ struct Resource : public Node { };
+ struct URI : public Resource
+ {
+ OString const value;
+ explicit URI(OString const& i_rValue)
+ : value(i_rValue)
+ { }
+ };
+ struct BlankNode : public Resource
+ {
+ OString const value;
+ explicit BlankNode(OString const& i_rValue)
+ : value(i_rValue)
+ { }
+ };
+ struct Literal : public Node
+ {
+ OString const value;
+ OString const language;
+ ::std::optional<OString> const type;
+ Literal(OString const& i_rValue, OString const& i_rLanguage,
+ ::std::optional<OString> const& i_rType)
+ : value(i_rValue)
+ , language(i_rLanguage)
+ , type(i_rType)
+ { }
+ };
+ struct Statement
+ {
+ std::shared_ptr<Resource> const pSubject;
+ std::shared_ptr<URI> const pPredicate;
+ std::shared_ptr<Node> const pObject;
+ Statement(std::shared_ptr<Resource> const& i_pSubject,
+ std::shared_ptr<URI> const& i_pPredicate,
+ std::shared_ptr<Node> const& i_pObject)
+ : pSubject(i_pSubject)
+ , pPredicate(i_pPredicate)
+ , pObject(i_pObject)
+ { }
+ };
+
+ librdf_TypeConverter(
+ uno::Reference< uno::XComponentContext > const & i_xContext,
+ librdf_Repository &i_rRep)
+ : m_xContext(i_xContext)
+ , m_rRep(i_rRep)
+ { };
+
+ librdf_world *createWorld_Lock() const;
+ librdf_storage *createStorage_Lock(librdf_world *i_pWorld) const;
+ librdf_model *createModel_Lock(librdf_world *i_pWorld,
+ librdf_storage * i_pStorage) const;
+ static librdf_uri* mkURI_Lock(librdf_world* i_pWorld,
+ const OString & i_rURI);
+ static librdf_node* mkResource_Lock(librdf_world* i_pWorld,
+ const Resource * i_pResource);
+ static librdf_node* mkNode_Lock(librdf_world* i_pWorld,
+ const Node * i_pNode);
+ static librdf_statement* mkStatement_Lock(librdf_world* i_pWorld,
+ Statement const& i_rStatement);
+ static std::shared_ptr<Resource> extractResource_NoLock(
+ const uno::Reference< rdf::XResource > & i_xResource);
+ static void extractResourceToCacheKey_NoLock(
+ const uno::Reference< rdf::XResource > & i_xResource,
+ OUStringBuffer& rBuf);
+ static std::shared_ptr<Node> extractNode_NoLock(
+ const uno::Reference< rdf::XNode > & i_xNode);
+ static void extractNodeToCacheKey_NoLock(
+ const uno::Reference< rdf::XNode > & i_xNode,
+ OUStringBuffer& rBuffer);
+ static Statement extractStatement_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject);
+ uno::Reference<rdf::XURI> convertToXURI(librdf_uri* i_pURI) const;
+ uno::Reference<rdf::XURI> convertToXURI(librdf_node* i_pURI) const;
+ uno::Reference<rdf::XResource>
+ convertToXResource(librdf_node* i_pNode) const;
+ uno::Reference<rdf::XNode> convertToXNode(librdf_node* i_pNode) const;
+ rdf::Statement
+ convertToStatement(librdf_statement* i_pStmt, librdf_node* i_pContext)
+ const;
+
+private:
+ uno::Reference< uno::XComponentContext > const m_xContext;
+ librdf_Repository & m_rRep;
+};
+
+
+/** implements the repository service.
+ */
+class librdf_Repository:
+// private ::cppu::BaseMutex,
+ public ::cppu::WeakImplHelper<
+ lang::XServiceInfo,
+ rdf::XDocumentRepository,
+ lang::XInitialization>
+{
+public:
+
+ explicit librdf_Repository(
+ uno::Reference< uno::XComponentContext > const & i_xContext);
+ virtual ~librdf_Repository() override;
+
+ // css::lang::XServiceInfo:
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(
+ const OUString & ServiceName) override;
+ virtual uno::Sequence< OUString > SAL_CALL
+ getSupportedServiceNames() override;
+
+ // css::rdf::XRepository:
+ virtual uno::Reference< rdf::XBlankNode > SAL_CALL createBlankNode() override;
+ virtual uno::Reference<rdf::XNamedGraph> SAL_CALL importGraph(
+ ::sal_Int16 i_Format,
+ const uno::Reference< io::XInputStream > & i_xInStream,
+ const uno::Reference< rdf::XURI > & i_xGraphName,
+ const uno::Reference< rdf::XURI > & i_xBaseURI) override;
+ virtual void SAL_CALL exportGraph(::sal_Int16 i_Format,
+ const uno::Reference< io::XOutputStream > & i_xOutStream,
+ const uno::Reference< rdf::XURI > & i_xGraphName,
+ const uno::Reference< rdf::XURI > & i_xBaseURI) override;
+ virtual uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
+ getGraphNames() override;
+ virtual uno::Reference< rdf::XNamedGraph > SAL_CALL getGraph(
+ const uno::Reference< rdf::XURI > & i_xGraphName) override;
+ virtual uno::Reference< rdf::XNamedGraph > SAL_CALL createGraph(
+ const uno::Reference< rdf::XURI > & i_xGraphName) override;
+ virtual void SAL_CALL destroyGraph(
+ const uno::Reference< rdf::XURI > & i_xGraphName) override;
+ virtual uno::Reference< container::XEnumeration > SAL_CALL getStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject) override;
+ virtual uno::Reference< rdf::XQuerySelectResult > SAL_CALL
+ querySelect(const OUString & i_rQuery) override;
+ virtual uno::Reference< container::XEnumeration > SAL_CALL
+ queryConstruct(const OUString & i_rQuery) override;
+ virtual sal_Bool SAL_CALL queryAsk(const OUString & i_rQuery) override;
+
+ // css::rdf::XDocumentRepository:
+ virtual void SAL_CALL setStatementRDFa(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Sequence< uno::Reference< rdf::XURI > > & i_rPredicates,
+ const uno::Reference< rdf::XMetadatable > & i_xObject,
+ const OUString & i_rRDFaContent,
+ const uno::Reference< rdf::XURI > & i_xRDFaDatatype) override;
+ virtual void SAL_CALL removeStatementRDFa(
+ const uno::Reference< rdf::XMetadatable > & i_xElement) override;
+ virtual beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool > SAL_CALL
+ getStatementRDFa(uno::Reference< rdf::XMetadatable > const& i_xElement) override;
+ virtual uno::Reference< container::XEnumeration > SAL_CALL
+ getStatementsRDFa(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject) override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(
+ const uno::Sequence< css::uno::Any > & i_rArguments) override;
+
+ // XNamedGraph forwards ---------------------------------------------
+ NamedGraphMap_t::iterator clearGraph_NoLock(
+ const OUString & i_rGraphName,
+ bool i_Internal = false );
+ NamedGraphMap_t::iterator clearGraph_Lock(
+ const OUString & i_rGraphName,
+ bool i_Internal);
+ void addStatementGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xName );
+// throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException);
+ void addStatementGraph_Lock(
+ librdf_TypeConverter::Statement const& i_rStatement,
+ OUString const& i_rGraphName,
+ bool i_Internal);
+ void removeStatementsGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xName );
+// throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException);
+ std::vector<rdf::Statement> getStatementsGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xName,
+ bool i_Internal = false );
+// throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException);
+
+ const librdf_TypeConverter& getTypeConverter() const { return m_TypeConverter; };
+
+private:
+
+ librdf_Repository(librdf_Repository const&) = delete;
+ librdf_Repository& operator=(librdf_Repository const&) = delete;
+
+ /// this is const, no need to lock m_aMutex to access it
+ uno::Reference< uno::XComponentContext > const m_xContext;
+
+ /// librdf global data
+ /** N.B.: The redland documentation gives the impression that you can have
+ as many librdf_worlds as you like. This is true in the same sense
+ that you can physically be in as many places as you like.
+ Well, you can, just not at the same time.
+ The ugly truth is that destroying a librdf_world kills a bunch
+ of static variables; other librdf_worlds become very unhappy
+ when they access these.
+ And of course this is not documented anywhere that I could find.
+ So we allocate a single world, and refcount that.
+ */
+ static std::shared_ptr<librdf_world> m_pWorld;
+ /// refcount
+ static sal_uInt32 m_NumInstances;
+ /// mutex for m_pWorld - redland is not as threadsafe as is often claimed
+ static std::mutex m_aMutex;
+
+ // NB: sequence of the shared pointers is important!
+ /// librdf repository storage
+ std::shared_ptr<librdf_storage> m_pStorage;
+ /// librdf repository model
+ std::shared_ptr<librdf_model> m_pModel;
+
+ /// all named graphs
+ NamedGraphMap_t m_NamedGraphs;
+
+ /// type conversion helper - stateless
+ librdf_TypeConverter m_TypeConverter;
+
+ /// set of xml:ids of elements with xhtml:content
+ ::std::set< OUString > m_RDFaXHTMLContentSet;
+};
+
+
+/** result of operations that return a graph, i.e.,
+ an XEnumeration of statements.
+ */
+class librdf_GraphResult:
+ public ::cppu::WeakImplHelper<
+ container::XEnumeration>
+{
+public:
+
+ librdf_GraphResult(librdf_Repository *i_pRepository,
+ std::mutex & i_rMutex,
+ std::shared_ptr<librdf_stream> const& i_pStream,
+ std::shared_ptr<librdf_node> const& i_pContext,
+ std::shared_ptr<librdf_query> const& i_pQuery =
+ std::shared_ptr<librdf_query>() )
+ : m_xRep(i_pRepository)
+ , m_rMutex(i_rMutex)
+ , m_pQuery(i_pQuery)
+ , m_pContext(i_pContext)
+ , m_pStream(i_pStream)
+ { };
+
+ virtual ~librdf_GraphResult() override
+ {
+ std::scoped_lock g(m_rMutex); // lock mutex when destroying members
+ const_cast<std::shared_ptr<librdf_stream>& >(m_pStream).reset();
+ const_cast<std::shared_ptr<librdf_node>& >(m_pContext).reset();
+ const_cast<std::shared_ptr<librdf_query>& >(m_pQuery).reset();
+ }
+
+ // css::container::XEnumeration:
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual uno::Any SAL_CALL nextElement() override;
+
+private:
+
+ librdf_GraphResult(librdf_GraphResult const&) = delete;
+ librdf_GraphResult& operator=(librdf_GraphResult const&) = delete;
+
+ // NB: this is not a weak pointer: streams _must_ be deleted before the
+ // storage they point into, so we keep the repository alive here
+ // also, sequence is important: the stream must be destroyed first.
+ ::rtl::Reference< librdf_Repository > m_xRep;
+ // needed for synchronizing access to librdf (it doesn't do win32 threading)
+ std::mutex & m_rMutex;
+ // the query (in case this is a result of a graph query)
+ // not that the redland documentation spells this out explicitly, but
+ // queries must be freed only after all the results are completely read
+ std::shared_ptr<librdf_query> const m_pQuery;
+ std::shared_ptr<librdf_node> const m_pContext;
+ std::shared_ptr<librdf_stream> const m_pStream;
+
+ librdf_node* getContext_Lock() const;
+};
+
+
+// css::container::XEnumeration:
+sal_Bool SAL_CALL
+librdf_GraphResult::hasMoreElements()
+{
+ std::scoped_lock g(m_rMutex);
+ return m_pStream && !librdf_stream_end(m_pStream.get());
+}
+
+librdf_node* librdf_GraphResult::getContext_Lock() const
+{
+ if (!m_pStream || librdf_stream_end(m_pStream.get()))
+ return nullptr;
+ librdf_node *pCtxt(
+#if LIBRDF_VERSION >= 10012
+ librdf_stream_get_context2(m_pStream.get()) );
+#else
+ static_cast<librdf_node *>(librdf_stream_get_context(m_pStream.get())) );
+#endif
+ if (pCtxt)
+ return pCtxt;
+ return m_pContext.get();
+}
+
+css::uno::Any SAL_CALL
+librdf_GraphResult::nextElement()
+{
+ std::scoped_lock g(m_rMutex);
+ if (m_pStream && librdf_stream_end(m_pStream.get())) {
+ throw container::NoSuchElementException();
+ }
+ librdf_node * pCtxt = getContext_Lock();
+
+ librdf_statement *pStmt( librdf_stream_get_object(m_pStream.get()) );
+ if (!pStmt) {
+ rdf::QueryException e(
+ "librdf_GraphResult::nextElement: "
+ "librdf_stream_get_object failed", *this);
+ throw lang::WrappedTargetException(
+ "librdf_GraphResult::nextElement: "
+ "librdf_stream_get_object failed", *this,
+ uno::Any(e));
+ }
+ // NB: pCtxt may be null here if this is result of a graph query
+ if (pCtxt && isInternalContext(pCtxt)) {
+ pCtxt = nullptr; // XML ID context is implementation detail!
+ }
+ rdf::Statement Stmt(
+ m_xRep->getTypeConverter().convertToStatement(pStmt, pCtxt) );
+ // NB: this will invalidate current item.
+ librdf_stream_next(m_pStream.get());
+ return uno::Any(Stmt);
+}
+
+
+/** result of operations that return a graph, i.e.,
+ an XEnumeration of statements.
+ */
+class librdf_GraphResult2:
+ public ::cppu::WeakImplHelper<
+ container::XEnumeration>
+{
+public:
+
+ librdf_GraphResult2(std::vector<rdf::Statement> statements)
+ : m_vStatements(std::move(statements))
+ { };
+
+ // css::container::XEnumeration:
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual uno::Any SAL_CALL nextElement() override;
+
+private:
+
+ std::vector<rdf::Statement> m_vStatements;
+ std::atomic<std::size_t> m_nIndex = 0;
+};
+
+
+// css::container::XEnumeration:
+sal_Bool SAL_CALL
+librdf_GraphResult2::hasMoreElements()
+{
+ return m_nIndex < m_vStatements.size();
+}
+
+css::uno::Any SAL_CALL
+librdf_GraphResult2::nextElement()
+{
+ std::size_t const n = m_nIndex++;
+ if (m_vStatements.size() <= n)
+ {
+ m_nIndex = m_vStatements.size(); // avoid overflow
+ throw container::NoSuchElementException();
+ }
+ return uno::Any(m_vStatements[n]);
+}
+
+/** result of tuple queries ("SELECT").
+ */
+class librdf_QuerySelectResult:
+ public ::cppu::WeakImplHelper<
+ rdf::XQuerySelectResult>
+{
+public:
+
+ librdf_QuerySelectResult(librdf_Repository *i_pRepository,
+ std::mutex & i_rMutex,
+ std::shared_ptr<librdf_query> const& i_pQuery,
+ std::shared_ptr<librdf_query_results> const& i_pQueryResult,
+ uno::Sequence< OUString > const& i_rBindingNames )
+ : m_xRep(i_pRepository)
+ , m_rMutex(i_rMutex)
+ , m_pQuery(i_pQuery)
+ , m_pQueryResult(i_pQueryResult)
+ , m_BindingNames(i_rBindingNames)
+ { };
+
+ virtual ~librdf_QuerySelectResult() override
+ {
+ std::scoped_lock g(m_rMutex); // lock mutex when destroying members
+ const_cast<std::shared_ptr<librdf_query_results>& >(m_pQueryResult)
+ .reset();
+ const_cast<std::shared_ptr<librdf_query>& >(m_pQuery).reset();
+ }
+
+ // css::container::XEnumeration:
+ virtual sal_Bool SAL_CALL hasMoreElements() override;
+ virtual uno::Any SAL_CALL nextElement() override;
+
+ // css::rdf::XQuerySelectResult:
+ virtual uno::Sequence< OUString > SAL_CALL getBindingNames() override;
+
+private:
+
+ librdf_QuerySelectResult(librdf_QuerySelectResult const&) = delete;
+ librdf_QuerySelectResult& operator=(librdf_QuerySelectResult const&) = delete;
+
+ // NB: this is not a weak pointer: streams _must_ be deleted before the
+ // storage they point into, so we keep the repository alive here
+ // also, sequence is important: the stream must be destroyed first.
+ ::rtl::Reference< librdf_Repository > m_xRep;
+ // needed for synchronizing access to librdf (it doesn't do win32 threading)
+ std::mutex & m_rMutex;
+ // not that the redland documentation spells this out explicitly, but
+ // queries must be freed only after all the results are completely read
+ std::shared_ptr<librdf_query> const m_pQuery;
+ std::shared_ptr<librdf_query_results> const m_pQueryResult;
+ uno::Sequence< OUString > const m_BindingNames;
+};
+
+
+// css::container::XEnumeration:
+sal_Bool SAL_CALL
+librdf_QuerySelectResult::hasMoreElements()
+{
+ std::scoped_lock g(m_rMutex);
+ return !librdf_query_results_finished(m_pQueryResult.get());
+}
+
+class NodeArray : private std::vector<librdf_node*>
+{
+public:
+ NodeArray(int cnt) : std::vector<librdf_node*>(cnt) {}
+
+ ~NodeArray() noexcept
+ {
+ std::for_each(begin(), end(), safe_librdf_free_node);
+ }
+
+ using std::vector<librdf_node*>::data;
+ using std::vector<librdf_node*>::operator[];
+};
+
+css::uno::Any SAL_CALL
+librdf_QuerySelectResult::nextElement()
+{
+ std::scoped_lock g(m_rMutex);
+ if (librdf_query_results_finished(m_pQueryResult.get())) {
+ throw container::NoSuchElementException();
+ }
+ sal_Int32 count(m_BindingNames.getLength());
+ OSL_ENSURE(count >= 0, "negative length?");
+ NodeArray aNodes(count);
+ if (librdf_query_results_get_bindings(m_pQueryResult.get(), nullptr,
+ aNodes.data()))
+ {
+ rdf::QueryException e(
+ "librdf_QuerySelectResult::nextElement: "
+ "librdf_query_results_get_bindings failed", *this);
+ throw lang::WrappedTargetException(
+ "librdf_QuerySelectResult::nextElement: "
+ "librdf_query_results_get_bindings failed", *this,
+ uno::Any(e));
+ }
+ uno::Sequence< uno::Reference< rdf::XNode > > ret(count);
+ auto retRange = asNonConstRange(ret);
+ for (int i = 0; i < count; ++i) {
+ retRange[i] = m_xRep->getTypeConverter().convertToXNode(aNodes[i]);
+ }
+ // NB: this will invalidate current item.
+ librdf_query_results_next(m_pQueryResult.get());
+ return uno::Any(ret);
+}
+
+// css::rdf::XQuerySelectResult:
+uno::Sequence< OUString > SAL_CALL
+librdf_QuerySelectResult::getBindingNames()
+{
+ // const - no lock needed
+ return m_BindingNames;
+}
+
+
+/** represents a named graph, and forwards all the work to repository.
+ */
+class librdf_NamedGraph:
+ public ::cppu::WeakImplHelper<
+ rdf::XNamedGraph>
+{
+public:
+ librdf_NamedGraph(librdf_Repository * i_pRep,
+ uno::Reference<rdf::XURI> const & i_xName)
+ : m_wRep(i_pRep)
+ , m_pRep(i_pRep)
+ , m_xName(i_xName)
+ { };
+
+ // css::rdf::XNode:
+ virtual OUString SAL_CALL getStringValue() override;
+
+ // css::rdf::XURI:
+ virtual OUString SAL_CALL getNamespace() override;
+ virtual OUString SAL_CALL getLocalName() override;
+
+ // css::rdf::XNamedGraph:
+ virtual uno::Reference<rdf::XURI> SAL_CALL getName() override;
+ virtual void SAL_CALL clear() override;
+ virtual void SAL_CALL addStatement(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject) override;
+ virtual void SAL_CALL removeStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject) override;
+ virtual uno::Reference< container::XEnumeration > SAL_CALL getStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject) override;
+
+private:
+
+ librdf_NamedGraph(librdf_NamedGraph const&) = delete;
+ librdf_NamedGraph& operator=(librdf_NamedGraph const&) = delete;
+
+ static OUString createCacheKey_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject);
+
+ /// weak reference: this is needed to check if m_pRep is valid
+ uno::WeakReference< rdf::XRepository > const m_wRep;
+ librdf_Repository *const m_pRep;
+ uno::Reference< rdf::XURI > const m_xName;
+
+ /// Querying is rather slow, so cache the results.
+ std::map<OUString, std::vector<rdf::Statement>> m_aStatementsCache;
+ std::mutex m_CacheMutex;
+};
+
+
+// css::rdf::XNode:
+OUString SAL_CALL librdf_NamedGraph::getStringValue()
+{
+ return m_xName->getStringValue();
+}
+
+// css::rdf::XURI:
+OUString SAL_CALL librdf_NamedGraph::getNamespace()
+{
+ return m_xName->getNamespace();
+}
+
+OUString SAL_CALL librdf_NamedGraph::getLocalName()
+{
+ return m_xName->getLocalName();
+}
+
+// css::rdf::XNamedGraph:
+uno::Reference< rdf::XURI > SAL_CALL librdf_NamedGraph::getName()
+{
+ return m_xName;
+}
+
+void SAL_CALL librdf_NamedGraph::clear()
+{
+ uno::Reference< rdf::XRepository > xRep( m_wRep );
+ if (!xRep.is()) {
+ throw rdf::RepositoryException(
+ "librdf_NamedGraph::clear: repository is gone", *this);
+ }
+ const OUString contextU( m_xName->getStringValue() );
+ try {
+ m_pRep->clearGraph_NoLock(contextU);
+ } catch (lang::IllegalArgumentException & ex) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException( ex.Message,
+ *this, anyEx );
+ }
+ std::unique_lock g(m_CacheMutex);
+ m_aStatementsCache.clear();
+}
+
+void SAL_CALL librdf_NamedGraph::addStatement(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ uno::Reference< rdf::XRepository > xRep( m_wRep );
+ if (!xRep.is()) {
+ throw rdf::RepositoryException(
+ "librdf_NamedGraph::addStatement: repository is gone", *this);
+ }
+ {
+ std::unique_lock g(m_CacheMutex);
+ m_aStatementsCache.clear();
+ }
+ m_pRep->addStatementGraph_NoLock(
+ i_xSubject, i_xPredicate, i_xObject, m_xName);
+}
+
+void SAL_CALL librdf_NamedGraph::removeStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ uno::Reference< rdf::XRepository > xRep( m_wRep );
+ if (!xRep.is()) {
+ throw rdf::RepositoryException(
+ "librdf_NamedGraph::removeStatements: repository is gone", *this);
+ }
+ {
+ std::unique_lock g(m_CacheMutex);
+ m_aStatementsCache.clear();
+ }
+ m_pRep->removeStatementsGraph_NoLock(
+ i_xSubject, i_xPredicate, i_xObject, m_xName);
+}
+
+OUString librdf_NamedGraph::createCacheKey_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ OUStringBuffer cacheKey(256);
+ librdf_TypeConverter::extractResourceToCacheKey_NoLock(i_xSubject, cacheKey);
+ cacheKey.append("\t");
+ librdf_TypeConverter::extractResourceToCacheKey_NoLock(i_xPredicate, cacheKey);
+ cacheKey.append("\t");
+ librdf_TypeConverter::extractNodeToCacheKey_NoLock(i_xObject, cacheKey);
+ return cacheKey.makeStringAndClear();
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+librdf_NamedGraph::getStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ OUString cacheKey = createCacheKey_NoLock(i_xSubject, i_xPredicate, i_xObject);
+ {
+ std::unique_lock g(m_CacheMutex);
+ auto it = m_aStatementsCache.find(cacheKey);
+ if (it != m_aStatementsCache.end()) {
+ return new librdf_GraphResult2(it->second);
+ }
+ }
+
+ uno::Reference< rdf::XRepository > xRep( m_wRep );
+ if (!xRep.is()) {
+ throw rdf::RepositoryException(
+ "librdf_NamedGraph::getStatements: repository is gone", *this);
+ }
+ std::vector<rdf::Statement> vStatements = m_pRep->getStatementsGraph_NoLock(
+ i_xSubject, i_xPredicate, i_xObject, m_xName);
+
+ {
+ std::unique_lock g(m_CacheMutex);
+ m_aStatementsCache.emplace(cacheKey, vStatements);
+ }
+ return new librdf_GraphResult2(std::move(vStatements));
+}
+
+
+std::shared_ptr<librdf_world> librdf_Repository::m_pWorld;
+sal_uInt32 librdf_Repository::m_NumInstances = 0;
+std::mutex librdf_Repository::m_aMutex;
+
+librdf_Repository::librdf_Repository(
+ uno::Reference< uno::XComponentContext > const & i_xContext)
+ : /*BaseMutex(),*/ m_xContext(i_xContext)
+// m_pWorld (static_cast<librdf_world *>(0), safe_librdf_free_world ),
+ , m_pStorage(static_cast<librdf_storage*>(nullptr), safe_librdf_free_storage)
+ , m_pModel (static_cast<librdf_model *>(nullptr), safe_librdf_free_model )
+ , m_TypeConverter(i_xContext, *this)
+{
+ OSL_ENSURE(i_xContext.is(), "librdf_Repository: null context");
+
+ std::scoped_lock g(m_aMutex);
+ if (!m_NumInstances++) {
+ m_pWorld.reset(m_TypeConverter.createWorld_Lock(),
+ safe_librdf_free_world);
+ }
+}
+
+librdf_Repository::~librdf_Repository()
+{
+ std::scoped_lock g(m_aMutex);
+
+ // must destroy these before world!
+ m_pModel.reset();
+ m_pStorage.reset();
+
+ // FIXME: so it turns out that calling librdf_free_world will
+ // (via raptor_sax2_finish) call xmlCleanupParser, which will
+ // free libxml2's globals! ARRRGH!!! => never call librdf_free_world
+#if 0
+ if (!--m_NumInstances) {
+ m_pWorld.reset();
+ }
+#endif
+}
+
+// com.sun.star.uno.XServiceInfo:
+OUString SAL_CALL librdf_Repository::getImplementationName()
+{
+ return "librdf_Repository";
+}
+
+sal_Bool SAL_CALL librdf_Repository::supportsService(
+ OUString const & serviceName)
+{
+ return cppu::supportsService(this, serviceName);
+}
+
+uno::Sequence< OUString > SAL_CALL
+librdf_Repository::getSupportedServiceNames()
+{
+ return { "com.sun.star.rdf.Repository" };
+}
+
+// css::rdf::XRepository:
+uno::Reference< rdf::XBlankNode > SAL_CALL librdf_Repository::createBlankNode()
+{
+ std::scoped_lock g(m_aMutex);
+ const std::shared_ptr<librdf_node> pNode(
+ librdf_new_node_from_blank_identifier(m_pWorld.get(), nullptr),
+ safe_librdf_free_node);
+ if (!pNode) {
+ throw uno::RuntimeException(
+ "librdf_Repository::createBlankNode: "
+ "librdf_new_node_from_blank_identifier failed", *this);
+ }
+ const unsigned char * id (librdf_node_get_blank_identifier(pNode.get()));
+ if (!id) {
+ throw uno::RuntimeException(
+ "librdf_Repository::createBlankNode: "
+ "librdf_node_get_blank_identifier failed", *this);
+ }
+ const OUString nodeID(OUString::createFromAscii(
+ reinterpret_cast<const char *>(id)));
+ try {
+ return rdf::BlankNode::create(m_xContext, nodeID);
+ } catch (const lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_Repository::createBlankNode: "
+ "illegal blank node label", *this, anyEx);
+ }
+}
+
+//void SAL_CALL
+uno::Reference<rdf::XNamedGraph> SAL_CALL
+librdf_Repository::importGraph(::sal_Int16 i_Format,
+ const uno::Reference< io::XInputStream > & i_xInStream,
+ const uno::Reference< rdf::XURI > & i_xGraphName,
+ const uno::Reference< rdf::XURI > & i_xBaseURI)
+{
+ if (!i_xInStream.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::importGraph: stream is null", *this, 1);
+ }
+ //FIXME: other formats
+ if (i_Format != rdf::FileFormat::RDF_XML) {
+ throw datatransfer::UnsupportedFlavorException(
+ "librdf_Repository::importGraph: file format not supported", *this);
+ }
+ if (!i_xGraphName.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::importGraph: graph name is null", *this, 2);
+ }
+ if (i_xGraphName->getStringValue().startsWith(s_nsOOo))
+ {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::importGraph: URI is reserved", *this, 0);
+ }
+ if (!i_xBaseURI.is()) { //FIXME: any i_Format that don't need a base URI?
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::importGraph: base URI is null", *this, 3);
+ }
+ OSL_ENSURE(i_xBaseURI.is(), "no base uri");
+ const OUString baseURIU( i_xBaseURI->getStringValue() );
+ if (baseURIU.indexOf('#') >= 0) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::importGraph: base URI is not absolute", *this, 3);
+ }
+
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ uno::Sequence<sal_Int8> buf;
+ uno::Reference<io::XSeekable> xSeekable(i_xInStream, uno::UNO_QUERY);
+ // UGLY: if only redland could read streams...
+ const sal_Int64 sz( xSeekable.is() ? xSeekable->getLength() : 1 << 20 );
+ // exceptions are propagated
+ i_xInStream->readBytes( buf, static_cast<sal_Int32>( sz ) );
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) {
+ throw container::ElementExistException(
+ "librdf_Repository::importGraph: graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::importGraph: librdf_new_node_from_uri_string failed", *this);
+ }
+
+ const OString baseURI(
+ OUStringToOString(baseURIU, RTL_TEXTENCODING_UTF8) );
+ const std::shared_ptr<librdf_uri> pBaseURI(
+ librdf_new_uri(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (baseURI.getStr())),
+ safe_librdf_free_uri);
+ if (!pBaseURI) {
+ throw uno::RuntimeException( "librdf_Repository::importGraph: librdf_new_uri failed", *this);
+ }
+
+ const std::shared_ptr<librdf_parser> pParser(
+ librdf_new_parser(m_pWorld.get(), "rdfxml", nullptr, nullptr),
+ safe_librdf_free_parser);
+ if (!pParser) {
+ throw uno::RuntimeException(
+ "librdf_Repository::importGraph: "
+ "librdf_new_parser failed", *this);
+ }
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_parser_parse_counted_string_as_stream(pParser.get(),
+ reinterpret_cast<const unsigned char*>(buf.getConstArray()),
+ buf.getLength(), pBaseURI.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::ParseException(
+ "librdf_Repository::importGraph: "
+ "librdf_parser_parse_counted_string_as_stream failed", *this);
+ }
+ rtl::Reference<librdf_NamedGraph> const pGraph(
+ new librdf_NamedGraph(this, i_xGraphName));
+ m_NamedGraphs.insert(std::make_pair(contextU, pGraph));
+ if (librdf_model_context_add_statements(m_pModel.get(),
+ pContext.get(), pStream.get())) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::importGraph: "
+ "librdf_model_context_add_statements failed", *this);
+ }
+
+ return pGraph;
+}
+
+void addChaffWhenEncryptedStorage(const uno::Reference< io::XOutputStream > &rStream, unsigned char* pBuffer, size_t length)
+{
+ if (!length)
+ return;
+
+ uno::Reference< embed::XEncryptionProtectedSource2 > xEncr(rStream,
+ uno::UNO_QUERY);
+
+ bool bAddChaff = xEncr.is() && xEncr->hasEncryptionData();
+
+ // exceptions are propagated
+ if (!bAddChaff)
+ {
+ const uno::Sequence<sal_Int8> buf(
+ reinterpret_cast<sal_Int8*>(pBuffer), length);
+ rStream->writeBytes(buf);
+ }
+ else
+ {
+ unsigned char *postcomment =
+ reinterpret_cast<unsigned char*>(strchr(reinterpret_cast<char*>(pBuffer), '\n'));
+ if (postcomment != nullptr)
+ {
+ ++postcomment;
+
+ size_t preamblelen = postcomment - pBuffer;
+
+ uno::Sequence<sal_Int8> buf(
+ reinterpret_cast<sal_Int8*>(pBuffer), preamblelen);
+ rStream->writeBytes(buf);
+
+ OString aComment =
+ "<!--" +
+ comphelper::xml::makeXMLChaff() +
+ "-->";
+
+ buf = uno::Sequence<sal_Int8>(
+ reinterpret_cast<const sal_Int8*>(aComment.getStr()), aComment.getLength());
+ rStream->writeBytes(buf);
+
+ buf = uno::Sequence<sal_Int8>(
+ reinterpret_cast<sal_Int8*>(postcomment), length-preamblelen);
+ rStream->writeBytes(buf);
+ }
+ }
+}
+
+void SAL_CALL
+librdf_Repository::exportGraph(::sal_Int16 i_Format,
+ const uno::Reference< io::XOutputStream > & i_xOutStream,
+ const uno::Reference< rdf::XURI > & i_xGraphName,
+ const uno::Reference< rdf::XURI > & i_xBaseURI)
+{
+ if (!i_xOutStream.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::exportGraph: stream is null", *this, 1);
+ }
+ // FIXME: other formats
+ if (i_Format != rdf::FileFormat::RDF_XML) {
+ throw datatransfer::UnsupportedFlavorException(
+ "librdf_Repository::exportGraph: "
+ "file format not supported", *this);
+ }
+ if (!i_xGraphName.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::exportGraph: "
+ "graph name is null", *this, 2);
+ }
+ if (!i_xBaseURI.is()) { //FIXME: any i_Format that don't need a base URI?
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::exportGraph: "
+ "base URI is null", *this, 3);
+ }
+ OSL_ENSURE(i_xBaseURI.is(), "no base uri");
+ const OUString baseURIU( i_xBaseURI->getStringValue() );
+ if (baseURIU.indexOf('#') >= 0) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::exportGraph: "
+ "base URI is not absolute", *this, 3);
+ }
+
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::unique_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ if (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) {
+ throw container::NoSuchElementException(
+ "librdf_Repository::exportGraph: "
+ "no graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_new_node_from_uri_string failed", *this);
+ }
+ const OString baseURI(
+ OUStringToOString(baseURIU, RTL_TEXTENCODING_UTF8) );
+ const std::shared_ptr<librdf_uri> pBaseURI(
+ librdf_new_uri(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (baseURI.getStr())),
+ safe_librdf_free_uri);
+ if (!pBaseURI) {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_new_uri failed", *this);
+ }
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_context_as_stream(m_pModel.get(), pContext.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::exportGraph: "
+ "librdf_model_context_as_stream failed", *this);
+ }
+ const char * const format("rdfxml");
+ // #i116443#: abbrev breaks when certain URIs are used as data types
+// const char *format("rdfxml-abbrev");
+ const std::shared_ptr<librdf_serializer> pSerializer(
+ librdf_new_serializer(m_pWorld.get(), format, nullptr, nullptr),
+ safe_librdf_free_serializer);
+ if (!pSerializer) {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_new_serializer failed", *this);
+ }
+
+ const std::shared_ptr<librdf_uri> pRelativeURI(
+ librdf_new_uri(m_pWorld.get(), reinterpret_cast<const unsigned char*>
+ ("http://feature.librdf.org/raptor-relativeURIs")),
+ safe_librdf_free_uri);
+ const std::shared_ptr<librdf_uri> pWriteBaseURI(
+ librdf_new_uri(m_pWorld.get(), reinterpret_cast<const unsigned char*>
+ ("http://feature.librdf.org/raptor-writeBaseURI")),
+ safe_librdf_free_uri);
+ const std::shared_ptr<librdf_node> p0(
+ librdf_new_node_from_literal(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> ("0"), nullptr, 0),
+ safe_librdf_free_node);
+ const std::shared_ptr<librdf_node> p1(
+ librdf_new_node_from_literal(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> ("1"), nullptr, 0),
+ safe_librdf_free_node);
+ if (!pWriteBaseURI || !pRelativeURI || !p0 || !p1) {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_new_uri or librdf_new_node_from_literal failed", *this);
+ }
+
+ // make URIs relative to base URI
+ if (librdf_serializer_set_feature(pSerializer.get(),
+ pRelativeURI.get(), p1.get()))
+ {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_serializer_set_feature relativeURIs failed", *this);
+ }
+ // but do not write the base URI to the file!
+ if (librdf_serializer_set_feature(pSerializer.get(),
+ pWriteBaseURI.get(), p0.get()))
+ {
+ throw uno::RuntimeException(
+ "librdf_Repository::exportGraph: "
+ "librdf_serializer_set_feature writeBaseURI failed", *this);
+ }
+
+ size_t length;
+ const std::shared_ptr<unsigned char> pBuf(
+ librdf_serializer_serialize_stream_to_counted_string(
+ pSerializer.get(), pBaseURI.get(), pStream.get(), &length), free);
+ if (!pBuf) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::exportGraph: "
+ "librdf_serializer_serialize_stream_to_counted_string failed",
+ *this);
+ }
+
+ g.unlock(); // release Mutex before calling i_xOutStream methods
+
+ addChaffWhenEncryptedStorage(i_xOutStream, pBuf.get(), length);
+}
+
+uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
+librdf_Repository::getGraphNames()
+{
+ std::scoped_lock g(m_aMutex);
+ ::std::vector< uno::Reference<rdf::XURI> > ret;
+ std::transform(m_NamedGraphs.begin(), m_NamedGraphs.end(),
+ std::back_inserter(ret),
+ [](std::pair<OUString, ::rtl::Reference<librdf_NamedGraph>> const& it)
+ { return it.second->getName(); });
+ return comphelper::containerToSequence(ret);
+}
+
+uno::Reference< rdf::XNamedGraph > SAL_CALL
+librdf_Repository::getGraph(const uno::Reference< rdf::XURI > & i_xGraphName)
+{
+ if (!i_xGraphName.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::getGraph: URI is null", *this, 0);
+ }
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::scoped_lock g(m_aMutex);
+ const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(contextU) );
+ if (iter != m_NamedGraphs.end()) {
+ return iter->second;
+ } else {
+ return nullptr;
+ }
+}
+
+uno::Reference< rdf::XNamedGraph > SAL_CALL
+librdf_Repository::createGraph(const uno::Reference< rdf::XURI > & i_xGraphName)
+{
+ if (!i_xGraphName.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::createGraph: URI is null", *this, 0);
+ }
+
+ const OUString contextU( i_xGraphName->getStringValue() );
+ if (contextU.startsWith(s_nsOOo))
+ {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::createGraph: URI is reserved", *this, 0);
+ }
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ // NB: librdf does not have a concept of graphs as such;
+ // a librdf named graph exists iff the model contains a statement with
+ // the graph name as context
+
+ if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) {
+ throw container::ElementExistException(
+ "librdf_Repository::createGraph: graph with given URI exists", *this);
+ }
+ m_NamedGraphs.insert(std::make_pair(contextU,
+ new librdf_NamedGraph(this, i_xGraphName)));
+ return m_NamedGraphs.find(contextU)->second;
+}
+
+void SAL_CALL
+librdf_Repository::destroyGraph(
+ const uno::Reference< rdf::XURI > & i_xGraphName)
+{
+ if (!i_xGraphName.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::destroyGraph: URI is null", *this, 0);
+ }
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ const NamedGraphMap_t::iterator iter( clearGraph_Lock(contextU, false) );
+ m_NamedGraphs.erase(iter);
+}
+
+bool isMetadatableWithoutMetadata(
+ uno::Reference<uno::XInterface> const & i_xNode)
+{
+ const uno::Reference<rdf::XMetadatable> xMeta( i_xNode, uno::UNO_QUERY );
+ return (xMeta.is() && xMeta->getMetadataReference().Second.isEmpty());
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+librdf_Repository::getStatements(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ if (isMetadatableWithoutMetadata(i_xSubject) ||
+ isMetadatableWithoutMetadata(i_xPredicate) ||
+ isMetadatableWithoutMetadata(i_xObject))
+ {
+ return new librdf_GraphResult(this, m_aMutex,
+ std::shared_ptr<librdf_stream>(),
+ std::shared_ptr<librdf_node>());
+ }
+
+ librdf_TypeConverter::Statement const stmt(
+ librdf_TypeConverter::extractStatement_NoLock(
+ i_xSubject, i_xPredicate, i_xObject));
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ const std::shared_ptr<librdf_statement> pStatement(
+ librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
+ safe_librdf_free_statement);
+ OSL_ENSURE(pStatement, "mkStatement failed");
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_find_statements(m_pModel.get(), pStatement.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::getStatements: "
+ "librdf_model_find_statements failed", *this);
+ }
+
+ return new librdf_GraphResult(this, m_aMutex, pStream,
+ std::shared_ptr<librdf_node>());
+}
+
+
+uno::Reference< rdf::XQuerySelectResult > SAL_CALL
+librdf_Repository::querySelect(const OUString & i_rQuery)
+{
+ std::scoped_lock g(m_aMutex);
+ const OString query(
+ OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
+ const std::shared_ptr<librdf_query> pQuery(
+ librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
+ reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
+ safe_librdf_free_query);
+ if (!pQuery) {
+ throw rdf::QueryException(
+ "librdf_Repository::querySelect: "
+ "librdf_new_query failed", *this);
+ }
+ const std::shared_ptr<librdf_query_results> pResults(
+ librdf_model_query_execute(m_pModel.get(), pQuery.get()),
+ safe_librdf_free_query_results);
+ if (!pResults || !librdf_query_results_is_bindings(pResults.get())) {
+ throw rdf::QueryException(
+ "librdf_Repository::querySelect: "
+ "query result is null or not bindings", *this);
+ }
+
+ const int count( librdf_query_results_get_bindings_count(pResults.get()) );
+ if (count < 0) {
+ throw rdf::QueryException(
+ "librdf_Repository::querySelect: "
+ "librdf_query_results_get_bindings_count failed", *this);
+ }
+ uno::Sequence< OUString > names(count);
+ auto namesRange = asNonConstRange(names);
+ for (int i = 0; i < count; ++i) {
+ const char* name( librdf_query_results_get_binding_name(
+ pResults.get(), i) );
+ if (!name) {
+ throw rdf::QueryException(
+ "librdf_Repository::querySelect: binding is null", *this);
+ }
+
+ namesRange[i] = OUString::createFromAscii(name);
+ }
+
+ return new librdf_QuerySelectResult(this, m_aMutex,
+ pQuery, pResults, names);
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+librdf_Repository::queryConstruct(const OUString & i_rQuery)
+{
+ std::scoped_lock g(m_aMutex);
+ const OString query(
+ OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
+ const std::shared_ptr<librdf_query> pQuery(
+ librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
+ reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
+ safe_librdf_free_query);
+ if (!pQuery) {
+ throw rdf::QueryException(
+ "librdf_Repository::queryConstruct: "
+ "librdf_new_query failed", *this);
+ }
+ const std::shared_ptr<librdf_query_results> pResults(
+ librdf_model_query_execute(m_pModel.get(), pQuery.get()),
+ safe_librdf_free_query_results);
+ if (!pResults || !librdf_query_results_is_graph(pResults.get())) {
+ throw rdf::QueryException(
+ "librdf_Repository::queryConstruct: "
+ "query result is null or not graph", *this);
+ }
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_query_results_as_stream(pResults.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::QueryException(
+ "librdf_Repository::queryConstruct: "
+ "librdf_query_results_as_stream failed", *this);
+ }
+
+ return new librdf_GraphResult(this, m_aMutex, pStream,
+ std::shared_ptr<librdf_node>(), pQuery);
+}
+
+sal_Bool SAL_CALL
+librdf_Repository::queryAsk(const OUString & i_rQuery)
+{
+ std::scoped_lock g(m_aMutex);
+
+ const OString query(
+ OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
+ const std::shared_ptr<librdf_query> pQuery(
+ librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
+ reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
+ safe_librdf_free_query);
+ if (!pQuery) {
+ throw rdf::QueryException(
+ "librdf_Repository::queryAsk: "
+ "librdf_new_query failed", *this);
+ }
+ const std::shared_ptr<librdf_query_results> pResults(
+ librdf_model_query_execute(m_pModel.get(), pQuery.get()),
+ safe_librdf_free_query_results);
+ if (!pResults || !librdf_query_results_is_boolean(pResults.get())) {
+ throw rdf::QueryException(
+ "librdf_Repository::queryAsk: "
+ "query result is null or not boolean", *this);
+ }
+ return bool(librdf_query_results_get_boolean(pResults.get()));
+}
+
+// css::rdf::XDocumentRepository:
+void SAL_CALL librdf_Repository::setStatementRDFa(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Sequence< uno::Reference< rdf::XURI > > & i_rPredicates,
+ const uno::Reference< rdf::XMetadatable > & i_xObject,
+ const OUString & i_rRDFaContent,
+ const uno::Reference< rdf::XURI > & i_xRDFaDatatype)
+{
+ if (!i_xSubject.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::setStatementRDFa: Subject is null", *this, 0);
+ }
+ if (!i_rPredicates.hasElements()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::setStatementRDFa: no Predicates",
+ *this, 1);
+ }
+ if (std::any_of(i_rPredicates.begin(), i_rPredicates.end(),
+ [](const uno::Reference< rdf::XURI >& rPredicate) { return !rPredicate.is(); })) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::setStatementRDFa: Predicate is null", *this, 1);
+ }
+ if (!i_xObject.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::setStatementRDFa: Object is null", *this, 2);
+ }
+ const uno::Reference<lang::XServiceInfo> xService(i_xObject,
+ uno::UNO_QUERY_THROW);
+ uno::Reference<text::XTextRange> xTextRange;
+ if (xService->supportsService("com.sun.star.table.Cell") ||
+ xService->supportsService("com.sun.star.text.CellProperties") || // for writer
+ xService->supportsService("com.sun.star.text.Paragraph"))
+ {
+ xTextRange.set(i_xObject, uno::UNO_QUERY_THROW);
+ }
+ else if (xService->supportsService("com.sun.star.text.Bookmark") ||
+ xService->supportsService("com.sun.star.text.InContentMetadata"))
+ {
+ const uno::Reference<text::XTextContent> xTextContent(i_xObject,
+ uno::UNO_QUERY_THROW);
+ xTextRange = xTextContent->getAnchor();
+ }
+ if (!xTextRange.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::setStatementRDFa: "
+ "Object does not support RDFa", *this, 2);
+ }
+ // ensure that the metadatable has an XML ID
+ i_xObject->ensureMetadataReference();
+ const beans::StringPair mdref( i_xObject->getMetadataReference() );
+ if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
+ throw uno::RuntimeException(
+ "librdf_Repository::setStatementRDFa: "
+ "ensureMetadataReference did not", *this);
+ }
+ OUString const sXmlId(mdref.First + "#" + mdref.Second);
+ OUString const sContext(s_nsOOo + sXmlId);
+ OUString const content( (i_rRDFaContent.isEmpty())
+ ? xTextRange->getString()
+ : i_rRDFaContent );
+ uno::Reference<rdf::XNode> xContent;
+ try {
+ if (i_xRDFaDatatype.is()) {
+ xContent.set(rdf::Literal::createWithType(m_xContext,
+ content, i_xRDFaDatatype),
+ uno::UNO_QUERY_THROW);
+ } else {
+ xContent.set(rdf::Literal::create(m_xContext, content),
+ uno::UNO_QUERY_THROW);
+ }
+ } catch (const lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_Repository::setStatementRDFa: "
+ "cannot create literal", *this, anyEx);
+ }
+
+ std::shared_ptr<librdf_TypeConverter::Resource> const pSubject(
+ librdf_TypeConverter::extractResource_NoLock(i_xSubject));
+ std::shared_ptr<librdf_TypeConverter::Node> const pContent(
+ librdf_TypeConverter::extractNode_NoLock(xContent));
+ ::std::vector< std::shared_ptr<librdf_TypeConverter::Resource> >
+ predicates;
+ ::std::transform(i_rPredicates.begin(), i_rPredicates.end(),
+ ::std::back_inserter(predicates),
+ [](uno::Reference<rdf::XURI> const& xURI)
+ { return librdf_TypeConverter::extractResource_NoLock(xURI); });
+
+ removeStatementRDFa(i_xObject); // not atomic with insertion?
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ if (i_rRDFaContent.isEmpty()) {
+ m_RDFaXHTMLContentSet.erase(sXmlId);
+ } else {
+ m_RDFaXHTMLContentSet.insert(sXmlId);
+ }
+ try
+ {
+ for (const auto& rPredicatePtr : predicates)
+ {
+ addStatementGraph_Lock(
+ librdf_TypeConverter::Statement(pSubject,
+ std::dynamic_pointer_cast<librdf_TypeConverter::URI>(rPredicatePtr),
+ pContent),
+ sContext, true);
+ }
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_Repository::setStatementRDFa: "
+ "cannot addStatementGraph", *this, anyEx);
+ }
+}
+
+void SAL_CALL librdf_Repository::removeStatementRDFa(
+ const uno::Reference< rdf::XMetadatable > & i_xElement)
+{
+ if (!i_xElement.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::removeStatementRDFa: Element is null",
+ *this, 0);
+ }
+
+ const beans::StringPair mdref( i_xElement->getMetadataReference() );
+ if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
+ return; // nothing to do...
+ }
+
+ OUString const sXmlId(s_nsOOo + mdref.First + "#" + mdref.Second);
+
+ clearGraph_NoLock(sXmlId, true);
+}
+
+beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool > SAL_CALL
+librdf_Repository::getStatementRDFa(
+ const uno::Reference< rdf::XMetadatable > & i_xElement)
+{
+ if (!i_xElement.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::getStatementRDFa: Element is null", *this, 0);
+ }
+ const beans::StringPair mdref( i_xElement->getMetadataReference() );
+ if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
+ return beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool >();
+ }
+ OUString const sXmlId(mdref.First + "#" + mdref.Second);
+ uno::Reference<rdf::XURI> xXmlId;
+ try {
+ xXmlId.set( rdf::URI::create(m_xContext, s_nsOOo + sXmlId),
+ uno::UNO_SET_THROW);
+ } catch (const lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_Repository::getStatementRDFa: "
+ "cannot create URI for XML ID", *this, anyEx);
+ }
+
+ ::std::vector< rdf::Statement > ret;
+ try
+ {
+ ret = getStatementsGraph_NoLock(nullptr, nullptr, nullptr, xXmlId, true);
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_Repository::getStatementRDFa: "
+ "cannot getStatementsGraph", *this, anyEx);
+ }
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ return beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool >(
+ comphelper::containerToSequence(ret), 0 != m_RDFaXHTMLContentSet.count(sXmlId));
+}
+
+extern "C"
+librdf_statement *rdfa_context_stream_map_handler(
+ librdf_stream *i_pStream, void *, librdf_statement *i_pStatement)
+{
+ OSL_ENSURE(i_pStream, "rdfa_context_stream_map_handler: stream null");
+ if (i_pStream) {
+ librdf_node *pCtxt(
+#if LIBRDF_VERSION >= 10012
+ librdf_stream_get_context2(i_pStream) );
+#else
+ static_cast<librdf_node *>(librdf_stream_get_context(i_pStream)) );
+#endif
+ OSL_ENSURE(pCtxt, "rdfa_context_stream_map_handler: context null");
+ if (pCtxt && isInternalContext(pCtxt)) {
+ return i_pStatement;
+ }
+ }
+ return nullptr;
+};
+
+uno::Reference< container::XEnumeration > SAL_CALL
+librdf_Repository::getStatementsRDFa(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ if (isMetadatableWithoutMetadata(i_xSubject) ||
+ isMetadatableWithoutMetadata(i_xPredicate) ||
+ isMetadatableWithoutMetadata(i_xObject))
+ {
+ return new librdf_GraphResult(this, m_aMutex,
+ std::shared_ptr<librdf_stream>(),
+ std::shared_ptr<librdf_node>());
+ }
+
+ librdf_TypeConverter::Statement const stmt(
+ librdf_TypeConverter::extractStatement_NoLock(
+ i_xSubject, i_xPredicate, i_xObject));
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ const std::shared_ptr<librdf_statement> pStatement(
+ librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
+ safe_librdf_free_statement);
+ OSL_ENSURE(pStatement, "mkStatement failed");
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_find_statements(m_pModel.get(), pStatement.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::getStatementsRDFa: "
+ "librdf_model_find_statements failed", *this);
+ }
+
+ if (librdf_stream_add_map(pStream.get(), rdfa_context_stream_map_handler,
+ nullptr, nullptr)) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::getStatementsRDFa: "
+ "librdf_stream_add_map failed", *this);
+ }
+
+ return new librdf_GraphResult(this, m_aMutex, pStream,
+ std::shared_ptr<librdf_node>());
+}
+
+// css::lang::XInitialization:
+void SAL_CALL librdf_Repository::initialize(
+ const uno::Sequence< css::uno::Any > &)
+{
+ std::scoped_lock g(m_aMutex);
+
+// m_pWorld.reset(m_TypeConverter.createWorld(), safe_librdf_free_world);
+ m_pStorage.reset(m_TypeConverter.createStorage_Lock(m_pWorld.get()),
+ safe_librdf_free_storage);
+ m_pModel.reset(m_TypeConverter.createModel_Lock(
+ m_pWorld.get(), m_pStorage.get()), safe_librdf_free_model);
+}
+
+NamedGraphMap_t::iterator librdf_Repository::clearGraph_NoLock(
+ OUString const& i_rGraphName, bool i_Internal)
+// throw (uno::RuntimeException, container::NoSuchElementException,
+// rdf::RepositoryException)
+{
+ std::scoped_lock g(m_aMutex);
+
+ return clearGraph_Lock(i_rGraphName, i_Internal);
+}
+
+NamedGraphMap_t::iterator librdf_Repository::clearGraph_Lock(
+ OUString const& i_rGraphName, bool i_Internal)
+{
+ // internal: must be called with mutex locked!
+ const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(i_rGraphName) );
+ if (!i_Internal && iter == m_NamedGraphs.end()) {
+ throw container::NoSuchElementException(
+ "librdf_Repository::clearGraph: "
+ "no graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::clearGraph: "
+ "librdf_new_node_from_uri_string failed", *this);
+ }
+ if (librdf_model_context_remove_statements(m_pModel.get(), pContext.get()))
+ {
+ throw rdf::RepositoryException(
+ "librdf_Repository::clearGraph: "
+ "librdf_model_context_remove_statements failed", *this);
+ }
+ return iter;
+}
+
+void librdf_Repository::addStatementGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xGraphName)
+//throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException)
+{
+ if (!i_xSubject.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::addStatement: Subject is null", *this, 0);
+ }
+ if (!i_xPredicate.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::addStatement: Predicate is null",
+ *this, 1);
+ }
+ if (!i_xObject.is()) {
+ throw lang::IllegalArgumentException(
+ "librdf_Repository::addStatement: Object is null", *this, 2);
+ }
+
+ librdf_TypeConverter::Statement const stmt(
+ librdf_TypeConverter::extractStatement_NoLock(
+ i_xSubject, i_xPredicate, i_xObject));
+
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ addStatementGraph_Lock(stmt, contextU, false/*i_Internal*/);
+}
+
+void librdf_Repository::addStatementGraph_Lock(
+ librdf_TypeConverter::Statement const& i_rStatement,
+ OUString const& i_rGraphName,
+ bool i_Internal)
+{
+ if (!i_Internal
+ && (m_NamedGraphs.find(i_rGraphName) == m_NamedGraphs.end()))
+ {
+ throw container::NoSuchElementException(
+ "librdf_Repository::addStatement: "
+ "no graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::addStatement: "
+ "librdf_new_node_from_uri_string failed", *this);
+ }
+ const std::shared_ptr<librdf_statement> pStatement(
+ librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), i_rStatement),
+ safe_librdf_free_statement);
+ OSL_ENSURE(pStatement, "mkStatement failed");
+
+ // Test for duplicate statement
+ // librdf_model_add_statement disallows duplicates while
+ // librdf_model_context_add_statement allows duplicates
+ {
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_find_statements_in_context(m_pModel.get(),
+ pStatement.get(), pContext.get()),
+ safe_librdf_free_stream);
+ if (pStream && !librdf_stream_end(pStream.get()))
+ return;
+ }
+
+ if (librdf_model_context_add_statement(m_pModel.get(),
+ pContext.get(), pStatement.get())) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::addStatement: "
+ "librdf_model_context_add_statement failed", *this);
+ }
+}
+
+void librdf_Repository::removeStatementsGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xGraphName)
+//throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException)
+{
+ if (isMetadatableWithoutMetadata(i_xSubject) ||
+ isMetadatableWithoutMetadata(i_xPredicate) ||
+ isMetadatableWithoutMetadata(i_xObject))
+ {
+ return;
+ }
+
+ librdf_TypeConverter::Statement const stmt(
+ librdf_TypeConverter::extractStatement_NoLock(
+ i_xSubject, i_xPredicate, i_xObject));
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ if (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) {
+ throw container::NoSuchElementException(
+ "librdf_Repository::removeStatements: "
+ "no graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::removeStatements: "
+ "librdf_new_node_from_uri_string failed", *this);
+ }
+ const std::shared_ptr<librdf_statement> pStatement(
+ librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
+ safe_librdf_free_statement);
+ OSL_ENSURE(pStatement, "mkStatement failed");
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_find_statements_in_context(m_pModel.get(),
+ pStatement.get(), pContext.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::removeStatements: "
+ "librdf_model_find_statements_in_context failed", *this);
+ }
+
+ if (librdf_stream_end(pStream.get()))
+ return;
+
+ do {
+ librdf_statement *pStmt( librdf_stream_get_object(pStream.get()) );
+ if (!pStmt) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::removeStatements: "
+ "librdf_stream_get_object failed", *this);
+ }
+ if (librdf_model_context_remove_statement(m_pModel.get(),
+ pContext.get(), pStmt)) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::removeStatements: "
+ "librdf_model_context_remove_statement failed", *this);
+ }
+ } while (!librdf_stream_next(pStream.get()));
+}
+
+std::vector<rdf::Statement>
+librdf_Repository::getStatementsGraph_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject,
+ const uno::Reference< rdf::XURI > & i_xGraphName,
+ bool i_Internal)
+//throw (uno::RuntimeException, lang::IllegalArgumentException,
+// container::NoSuchElementException, rdf::RepositoryException)
+{
+ std::vector<rdf::Statement> ret;
+
+ // N.B.: if any of subject, predicate, object is an XMetadatable, and
+ // has no metadata reference, then there cannot be any node in the graph
+ // representing it; in order to prevent side effect
+ // (ensureMetadataReference), check for this condition and return
+ if (isMetadatableWithoutMetadata(i_xSubject) ||
+ isMetadatableWithoutMetadata(i_xPredicate) ||
+ isMetadatableWithoutMetadata(i_xObject))
+ {
+ return ret;
+ }
+
+ librdf_TypeConverter::Statement const stmt(
+ librdf_TypeConverter::extractStatement_NoLock(
+ i_xSubject, i_xPredicate, i_xObject));
+ const OUString contextU( i_xGraphName->getStringValue() );
+
+ std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
+
+ if (!i_Internal && (m_NamedGraphs.find(contextU) == m_NamedGraphs.end())) {
+ throw container::NoSuchElementException(
+ "librdf_Repository::getStatements: "
+ "no graph with given URI exists", *this);
+ }
+ const OString context(
+ OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
+
+ const std::shared_ptr<librdf_node> pContext(
+ librdf_new_node_from_uri_string(m_pWorld.get(),
+ reinterpret_cast<const unsigned char*> (context.getStr())),
+ safe_librdf_free_node);
+ if (!pContext) {
+ throw uno::RuntimeException(
+ "librdf_Repository::getStatements: "
+ "librdf_new_node_from_uri_string failed", *this);
+ }
+ const std::shared_ptr<librdf_statement> pStatement(
+ librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
+ safe_librdf_free_statement);
+ OSL_ENSURE(pStatement, "mkStatement failed");
+
+ const std::shared_ptr<librdf_stream> pStream(
+ librdf_model_find_statements_in_context(m_pModel.get(),
+ pStatement.get(), pContext.get()),
+ safe_librdf_free_stream);
+ if (!pStream) {
+ throw rdf::RepositoryException(
+ "librdf_Repository::getStatements: "
+ "librdf_model_find_statements_in_context failed", *this);
+ }
+
+ librdf_node *pCtxt1(
+#if LIBRDF_VERSION >= 10012
+ librdf_stream_get_context2(pStream.get()) );
+#else
+ static_cast<librdf_node *>(librdf_stream_get_context(pStream.get())) );
+#endif
+ while (!librdf_stream_end(pStream.get()))
+ {
+ auto pCtxt = pCtxt1;
+ librdf_statement *pStmt( librdf_stream_get_object(pStream.get()) );
+ if (!pStmt) {
+ rdf::QueryException e(
+ "librdf_GraphResult::nextElement: "
+ "librdf_stream_get_object failed", *this);
+ throw lang::WrappedTargetException(
+ "librdf_GraphResult::nextElement: "
+ "librdf_stream_get_object failed", *this,
+ uno::Any(e));
+ }
+ // NB: pCtxt may be null here if this is result of a graph query
+ if (pCtxt && isInternalContext(pCtxt)) {
+ pCtxt = nullptr; // XML ID context is implementation detail!
+ }
+
+ ret.emplace_back(
+ getTypeConverter().convertToStatement(pStmt, pCtxt) );
+
+ // NB: this will invalidate current item.
+ librdf_stream_next(pStream.get());
+ }
+
+ return ret;
+}
+
+extern "C"
+void librdf_raptor_init(void* /*user_data*/, raptor_world* pRaptorWorld)
+{
+ // fdo#64672 prevent raptor from setting global libxml2 error handlers
+ raptor_world_set_flag(pRaptorWorld,
+ RAPTOR_WORLD_FLAG_LIBXML_STRUCTURED_ERROR_SAVE, 0);
+ raptor_world_set_flag(pRaptorWorld,
+ RAPTOR_WORLD_FLAG_LIBXML_GENERIC_ERROR_SAVE, 0);
+}
+
+librdf_world *librdf_TypeConverter::createWorld_Lock() const
+{
+ // create and initialize world
+ librdf_world *pWorld( librdf_new_world() );
+ if (!pWorld) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::createWorld: librdf_new_world failed",
+ m_rRep);
+ }
+ librdf_world_set_raptor_init_handler(pWorld, nullptr, &librdf_raptor_init);
+ //FIXME logger, digest, features?
+ xsltSecurityPrefsPtr origprefs = xsltGetDefaultSecurityPrefs();
+ librdf_world_open(pWorld);
+ xsltSecurityPrefsPtr newprefs = xsltGetDefaultSecurityPrefs();
+ if (newprefs != origprefs) {
+ // #i110523# restore libxslt global configuration
+ // (gratuitously overwritten by raptor_init_parser_grddl_common)
+ // (this is the only reason unordf is linked against libxslt)
+ xsltSetDefaultSecurityPrefs(origprefs);
+ }
+ return pWorld;
+}
+
+librdf_storage *
+librdf_TypeConverter::createStorage_Lock(librdf_world *i_pWorld) const
+{
+ librdf_storage *pStorage(
+// librdf_new_storage(i_pWorld, "memory", NULL, "contexts='yes'") );
+ librdf_new_storage(i_pWorld, "hashes", nullptr,
+ "contexts='yes',hash-type='memory'") );
+ if (!pStorage) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::createStorage: librdf_new_storage failed",
+ m_rRep);
+ }
+ return pStorage;
+}
+
+librdf_model *librdf_TypeConverter::createModel_Lock(
+ librdf_world *i_pWorld, librdf_storage * i_pStorage) const
+{
+ librdf_model *pRepository( librdf_new_model(i_pWorld, i_pStorage, nullptr) );
+ if (!pRepository) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::createModel: librdf_new_model failed",
+ m_rRep);
+ }
+ //FIXME
+#if 0
+ {
+ librdf_uri * ctxt = librdf_new_uri(i_pWorld, reinterpret_cast<const unsigned char *>(LIBRDF_MODEL_FEATURE_CONTEXTS));
+ librdf_node * contexts = librdf_model_get_feature(repository, ctxt);
+ if (!contexts)
+ throw;
+ std::cout << "value of contexts feature: ";
+ prtNode(contexts);
+ std::cout << std::endl;
+ // librdf_model_set_feature(repository, LIBRDF_FEATURE_CONTEXTS, ...);
+ safe_librdf_free_node(contexts);
+ safe_librdf_free_uri(ctxt);
+ }
+#endif
+ return pRepository;
+}
+
+// this does NOT create a node, only URI
+librdf_uri* librdf_TypeConverter::mkURI_Lock( librdf_world* i_pWorld,
+ OString const& i_rURI)
+{
+ librdf_uri *pURI( librdf_new_uri(i_pWorld,
+ reinterpret_cast<const unsigned char *>(i_rURI.getStr())));
+ if (!pURI) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::mkURI: librdf_new_uri failed", nullptr);
+ }
+ return pURI;
+}
+
+// extract blank or URI node - call without Mutex locked
+std::shared_ptr<librdf_TypeConverter::Resource>
+librdf_TypeConverter::extractResource_NoLock(
+ const uno::Reference< rdf::XResource > & i_xResource)
+{
+ if (!i_xResource.is()) {
+ return std::shared_ptr<Resource>();
+ }
+ uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY);
+ if (xBlankNode.is()) {
+ const OString label(
+ OUStringToOString(xBlankNode->getStringValue(),
+ RTL_TEXTENCODING_UTF8) );
+ return std::make_shared<BlankNode>(label);
+ } else { // assumption: everything else is URI
+ const OString uri(
+ OUStringToOString(i_xResource->getStringValue(),
+ RTL_TEXTENCODING_UTF8) );
+ return std::make_shared<URI>(uri);
+ }
+}
+
+void
+librdf_TypeConverter::extractResourceToCacheKey_NoLock(
+ const uno::Reference< rdf::XResource > & i_xResource, OUStringBuffer& rBuffer)
+{
+ if (!i_xResource.is()) {
+ return;
+ }
+ uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY);
+ if (xBlankNode.is()) {
+ rBuffer.append("BlankNode " + xBlankNode->getStringValue());
+ } else { // assumption: everything else is URI
+ rBuffer.append("URI " + i_xResource->getStringValue());
+ }
+}
+
+// create blank or URI node
+librdf_node* librdf_TypeConverter::mkResource_Lock( librdf_world* i_pWorld,
+ Resource const*const i_pResource)
+{
+ if (!i_pResource) return nullptr;
+ BlankNode const*const pBlankNode(
+ dynamic_cast<BlankNode const*>(i_pResource));
+ if (pBlankNode) {
+ librdf_node *pNode(
+ librdf_new_node_from_blank_identifier(i_pWorld,
+ reinterpret_cast<const unsigned char*>(
+ pBlankNode->value.getStr())));
+ if (!pNode) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::mkResource: "
+ "librdf_new_node_from_blank_identifier failed", nullptr);
+ }
+ return pNode;
+ } else { // assumption: everything else is URI
+ URI const*const pURI(dynamic_cast<URI const*>(i_pResource));
+ assert(pURI);
+ librdf_node *pNode(
+ librdf_new_node_from_uri_string(i_pWorld,
+ reinterpret_cast<const unsigned char*>(pURI->value.getStr())));
+ if (!pNode) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::mkResource: "
+ "librdf_new_node_from_uri_string failed", nullptr);
+ }
+ return pNode;
+ }
+}
+
+// extract blank or URI or literal node - call without Mutex locked
+std::shared_ptr<librdf_TypeConverter::Node>
+librdf_TypeConverter::extractNode_NoLock(
+ const uno::Reference< rdf::XNode > & i_xNode)
+{
+ if (!i_xNode.is()) {
+ return std::shared_ptr<Node>();
+ }
+ uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY);
+ if (xResource.is()) {
+ return extractResource_NoLock(xResource);
+ }
+ uno::Reference< rdf::XLiteral> xLiteral(i_xNode, uno::UNO_QUERY);
+ OSL_ENSURE(xLiteral.is(),
+ "mkNode: someone invented a new rdf.XNode and did not tell me");
+ if (!xLiteral.is()) {
+ return std::shared_ptr<Node>();
+ }
+ const OString val(
+ OUStringToOString(xLiteral->getValue(),
+ RTL_TEXTENCODING_UTF8) );
+ const OString lang(
+ OUStringToOString(xLiteral->getLanguage(),
+ RTL_TEXTENCODING_UTF8) );
+ const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype());
+ std::optional<OString> type;
+ if (xType.is())
+ {
+ type =
+ OUStringToOString(xType->getStringValue(), RTL_TEXTENCODING_UTF8);
+ }
+ return std::make_shared<Literal>(val, lang, type);
+}
+
+// extract blank or URI or literal node - call without Mutex locked
+void
+librdf_TypeConverter::extractNodeToCacheKey_NoLock(
+ const uno::Reference< rdf::XNode > & i_xNode,
+ OUStringBuffer& rBuffer)
+{
+ if (!i_xNode.is()) {
+ return;
+ }
+ uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY);
+ if (xResource.is()) {
+ return extractResourceToCacheKey_NoLock(xResource, rBuffer);
+ }
+ uno::Reference< rdf::XLiteral> xLiteral(i_xNode, uno::UNO_QUERY);
+ OSL_ENSURE(xLiteral.is(),
+ "mkNode: someone invented a new rdf.XNode and did not tell me");
+ if (!xLiteral.is()) {
+ return;
+ }
+ rBuffer.append("Literal " + xLiteral->getValue() + "\t" + xLiteral->getLanguage());
+ const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype());
+ if (xType.is())
+ rBuffer.append("\t" + xType->getStringValue());
+}
+
+// create blank or URI or literal node
+librdf_node* librdf_TypeConverter::mkNode_Lock( librdf_world* i_pWorld,
+ Node const*const i_pNode)
+{
+ if (!i_pNode) return nullptr;
+ Resource const*const pResource(dynamic_cast<Resource const*>(i_pNode));
+ if (pResource) {
+ return mkResource_Lock(i_pWorld, pResource);
+ }
+
+ Literal const*const pLiteral(dynamic_cast<Literal const*>(i_pNode));
+ assert(pLiteral);
+ librdf_node * ret(nullptr);
+ if (pLiteral->language.isEmpty()) {
+ if (!pLiteral->type) {
+ ret = librdf_new_node_from_literal(i_pWorld,
+ reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
+ , nullptr, 0);
+ } else {
+ const std::shared_ptr<librdf_uri> pDatatype(
+ mkURI_Lock(i_pWorld, *pLiteral->type),
+ safe_librdf_free_uri);
+ ret = librdf_new_node_from_typed_literal(i_pWorld,
+ reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
+ , nullptr, pDatatype.get());
+ }
+ } else {
+ if (!pLiteral->type) {
+ ret = librdf_new_node_from_literal(i_pWorld,
+ reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
+ , pLiteral->language.getStr(), 0);
+ } else {
+ OSL_FAIL("mkNode: invalid literal");
+ return nullptr;
+ }
+ }
+ if (!ret) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::mkNode: librdf_new_node_from_literal failed", nullptr);
+ }
+ return ret;
+}
+
+// extract statement - call without Mutex locked
+librdf_TypeConverter::Statement librdf_TypeConverter::extractStatement_NoLock(
+ const uno::Reference< rdf::XResource > & i_xSubject,
+ const uno::Reference< rdf::XURI > & i_xPredicate,
+ const uno::Reference< rdf::XNode > & i_xObject)
+{
+ std::shared_ptr<Resource> const pSubject(
+ extractResource_NoLock(i_xSubject));
+ std::shared_ptr<URI> const pPredicate(
+ std::dynamic_pointer_cast<URI>(extractResource_NoLock(i_xPredicate)));
+ std::shared_ptr<Node> const pObject(extractNode_NoLock(i_xObject));
+ return Statement(pSubject, pPredicate, pObject);
+}
+
+librdf_statement* librdf_TypeConverter::mkStatement_Lock(librdf_world* i_pWorld,
+ Statement const& i_rStatement)
+{
+ librdf_node *const pSubject(
+ mkResource_Lock(i_pWorld, i_rStatement.pSubject.get()) );
+ librdf_node* pPredicate(nullptr);
+ librdf_node* pObject(nullptr);
+ try {
+ pPredicate = mkResource_Lock(i_pWorld, i_rStatement.pPredicate.get());
+ try {
+ pObject = mkNode_Lock(i_pWorld, i_rStatement.pObject.get());
+ } catch (...) {
+ safe_librdf_free_node(pPredicate);
+ throw;
+ }
+ } catch (...) {
+ safe_librdf_free_node(pSubject);
+ throw;
+ }
+ // NB: this takes ownership of the nodes! (which is really ugly)
+ librdf_statement* pStatement( librdf_new_statement_from_nodes(i_pWorld,
+ pSubject, pPredicate, pObject) );
+ if (!pStatement) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::mkStatement: "
+ "librdf_new_statement_from_nodes failed", nullptr);
+ }
+ return pStatement;
+}
+
+uno::Reference<rdf::XURI>
+librdf_TypeConverter::convertToXURI(librdf_uri* i_pURI) const
+{
+ if (!i_pURI) return nullptr;
+ const unsigned char* uri( librdf_uri_as_string(i_pURI) );
+ if (!uri) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::convertToXURI: "
+ "librdf_uri_as_string failed", m_rRep);
+ }
+ OUString uriU( OStringToOUString(
+ std::string_view(reinterpret_cast<const char*>(uri)),
+ RTL_TEXTENCODING_UTF8) );
+ try {
+ return rdf::URI::create(m_xContext, uriU);
+ } catch (const lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_TypeConverter::convertToXURI: "
+ "illegal uri", m_rRep, anyEx);
+ }
+}
+
+uno::Reference<rdf::XURI>
+librdf_TypeConverter::convertToXURI(librdf_node* i_pNode) const
+{
+ if (!i_pNode) return nullptr;
+ if (librdf_node_is_resource(i_pNode)) {
+ librdf_uri* pURI( librdf_node_get_uri(i_pNode) );
+ if (!pURI) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::convertToXURI: "
+ "resource has no uri", m_rRep);
+ }
+ return convertToXURI(pURI);
+ } else {
+ OSL_FAIL("convertToXURI: unknown librdf_node");
+ return nullptr;
+ }
+}
+
+uno::Reference<rdf::XResource>
+librdf_TypeConverter::convertToXResource(librdf_node* i_pNode) const
+{
+ if (!i_pNode) return nullptr;
+ if (librdf_node_is_blank(i_pNode)) {
+ const unsigned char* label( librdf_node_get_blank_identifier(i_pNode) );
+ if (!label) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::convertToXResource: "
+ "blank node has no label", m_rRep);
+ }
+ OUString labelU( OStringToOUString(
+ std::string_view(reinterpret_cast<const char*>(label)),
+ RTL_TEXTENCODING_UTF8) );
+ try {
+ return rdf::BlankNode::create(m_xContext, labelU);
+ } catch (const lang::IllegalArgumentException &) {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "librdf_TypeConverter::convertToXResource: "
+ "illegal blank node label", m_rRep, anyEx);
+ }
+ } else {
+ return convertToXURI(i_pNode);
+ }
+}
+
+uno::Reference<rdf::XNode>
+librdf_TypeConverter::convertToXNode(librdf_node* i_pNode) const
+{
+ if (!i_pNode) return nullptr;
+ if (!librdf_node_is_literal(i_pNode)) {
+ return convertToXResource(i_pNode);
+ }
+ const unsigned char* value( librdf_node_get_literal_value(i_pNode) );
+ if (!value) {
+ throw uno::RuntimeException(
+ "librdf_TypeConverter::convertToXNode: "
+ "literal has no value", m_rRep);
+ }
+ const char * lang( librdf_node_get_literal_value_language(i_pNode) );
+ librdf_uri* pType(
+ librdf_node_get_literal_value_datatype_uri(i_pNode) );
+ OSL_ENSURE(!lang || !pType, "convertToXNode: invalid literal");
+ const OUString valueU( OStringToOUString(
+ std::string_view(reinterpret_cast<const char*>(value)),
+ RTL_TEXTENCODING_UTF8) );
+ if (lang) {
+ const OUString langU( OStringToOUString(
+ std::string_view(lang),
+ RTL_TEXTENCODING_UTF8) );
+ return rdf::Literal::createWithLanguage(m_xContext, valueU, langU);
+ } else if (pType) {
+ uno::Reference<rdf::XURI> xType(convertToXURI(pType));
+ OSL_ENSURE(xType.is(), "convertToXNode: null uri");
+ return rdf::Literal::createWithType(m_xContext, valueU, xType);
+ } else {
+ return rdf::Literal::create(m_xContext, valueU);
+ }
+}
+
+rdf::Statement
+librdf_TypeConverter::convertToStatement(librdf_statement* i_pStmt,
+ librdf_node* i_pContext) const
+{
+ if (!i_pStmt) {
+ throw uno::RuntimeException();
+ }
+ return rdf::Statement(
+ convertToXResource(librdf_statement_get_subject(i_pStmt)),
+ convertToXURI(librdf_statement_get_predicate(i_pStmt)),
+ convertToXNode(librdf_statement_get_object(i_pStmt)),
+ convertToXURI(i_pContext));
+}
+
+} // closing anonymous implementation namespace
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_rdfRepository_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new librdf_Repository(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/rdf/unordf.component b/unoxml/source/rdf/unordf.component
new file mode 100644
index 000000000..1b99b5786
--- /dev/null
+++ b/unoxml/source/rdf/unordf.component
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="CBlankNode" constructor="unoxml_CBlankNode_get_implementation">
+ <service name="com.sun.star.rdf.BlankNode"/>
+ </implementation>
+ <implementation name="CLiteral" constructor="unoxml_CLiteral_get_implementation">
+ <service name="com.sun.star.rdf.Literal"/>
+ </implementation>
+ <implementation name="CURI" constructor="unoxml_CURI_get_implementation">
+ <service name="com.sun.star.rdf.URI"/>
+ </implementation>
+ <implementation name="librdf_Repository"
+ constructor="unoxml_rdfRepository_get_implementation">
+ <service name="com.sun.star.rdf.Repository"/>
+ </implementation>
+</component>
diff --git a/unoxml/source/service/unoxml.component b/unoxml/source/service/unoxml.component
new file mode 100644
index 000000000..6591bde6a
--- /dev/null
+++ b/unoxml/source/service/unoxml.component
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ -->
+
+<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@"
+ xmlns="http://openoffice.org/2010/uno-components">
+ <implementation name="com.sun.star.comp.xml.dom.DocumentBuilder"
+ constructor="unoxml_CDocumentBuilder_get_implementation">
+ <service name="com.sun.star.xml.dom.DocumentBuilder"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.xml.dom.SAXDocumentBuilder"
+ constructor="unoxml_CSAXDocumentBuilder_get_implementation">
+ <service name="com.sun.star.xml.dom.SAXDocumentBuilder"/>
+ </implementation>
+ <implementation name="com.sun.star.comp.xml.xpath.XPathAPI"
+ constructor="unoxml_CXPathAPI_get_implementation">
+ <service name="com.sun.star.xml.xpath.XPathAPI"/>
+ </implementation>
+</component>
diff --git a/unoxml/source/xpath/nodelist.cxx b/unoxml/source/xpath/nodelist.cxx
new file mode 100644
index 000000000..1b306aabc
--- /dev/null
+++ b/unoxml/source/xpath/nodelist.cxx
@@ -0,0 +1,72 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "nodelist.hxx"
+
+#include "../dom/document.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+
+namespace XPath
+{
+ CNodeList::CNodeList(
+ ::rtl::Reference<DOM::CDocument> const& pDocument,
+ ::osl::Mutex & rMutex,
+ std::shared_ptr<xmlXPathObject> const& rxpathObj)
+ : m_pDocument(pDocument)
+ , m_rMutex(rMutex)
+ , m_pNodeSet(nullptr)
+ {
+ if (rxpathObj != nullptr && rxpathObj->type == XPATH_NODESET)
+ {
+ m_pNodeSet = rxpathObj->nodesetval;
+ m_pXPathObj = rxpathObj;
+ }
+ }
+
+ /**
+ The number of nodes in the list.
+ */
+ sal_Int32 SAL_CALL CNodeList::getLength()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ sal_Int32 value = 0;
+ if (m_pNodeSet != nullptr)
+ value = xmlXPathNodeSetGetLength(m_pNodeSet);
+ return value;
+ }
+
+ /**
+ Returns the indexth item in the collection.
+ */
+ Reference< XNode > SAL_CALL CNodeList::item(sal_Int32 index)
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ if (nullptr == m_pNodeSet) {
+ return nullptr;
+ }
+ xmlNodePtr const pNode = xmlXPathNodeSetItem(m_pNodeSet, index);
+ return m_pDocument->GetCNode(pNode);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/xpath/nodelist.hxx b/unoxml/source/xpath/nodelist.hxx
new file mode 100644
index 000000000..689510dea
--- /dev/null
+++ b/unoxml/source/xpath/nodelist.hxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+#include <rtl/ref.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+
+#include <libxml/xpath.h>
+
+#include "../dom/document.hxx"
+
+#include <memory>
+
+namespace DOM {
+ class CDocument;
+}
+
+namespace XPath
+{
+
+ class CNodeList : public cppu::WeakImplHelper< css::xml::dom::XNodeList >
+ {
+ private:
+ /// #i115995# keep document alive
+ ::rtl::Reference< DOM::CDocument > const m_pDocument;
+ ::osl::Mutex & m_rMutex;
+ /// retain the result set in case the CXPathObject is released
+ std::shared_ptr<xmlXPathObject> m_pXPathObj;
+ xmlNodeSetPtr m_pNodeSet;
+
+ public:
+ CNodeList(
+ ::rtl::Reference<DOM::CDocument> const& pDocument,
+ ::osl::Mutex & rMutex,
+ std::shared_ptr<xmlXPathObject> const& rxpathObj);
+ /**
+ The number of nodes in the list.
+ */
+ virtual sal_Int32 SAL_CALL getLength() override;
+ /**
+ Returns the indexth item in the collection.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL item(sal_Int32 index) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/xpath/xpathapi.cxx b/unoxml/source/xpath/xpathapi.cxx
new file mode 100644
index 000000000..f1968c208
--- /dev/null
+++ b/unoxml/source/xpath/xpathapi.cxx
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xpathapi.hxx"
+
+#include <stdarg.h>
+#include <string.h>
+
+#include <libxml/tree.h>
+#include <libxml/xmlerror.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+
+#include <com/sun/star/xml/xpath/XPathException.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+
+#include "xpathobject.hxx"
+
+#include <node.hxx>
+#include "../dom/document.hxx"
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace css::io;
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::xpath;
+
+namespace XPath
+{
+ // ctor
+ CXPathAPI::CXPathAPI(const Reference< XComponentContext >& rxContext)
+ : m_xContext(rxContext)
+ {
+ }
+
+ Sequence< OUString > SAL_CALL CXPathAPI::getSupportedServiceNames()
+ {
+ return { "com.sun.star.xml.xpath.XPathAPI" };
+ }
+
+ OUString SAL_CALL CXPathAPI::getImplementationName()
+ {
+ return "com.sun.star.comp.xml.xpath.XPathAPI";
+ }
+
+ sal_Bool SAL_CALL CXPathAPI::supportsService(const OUString& aServiceName)
+ {
+ return cppu::supportsService(this, aServiceName);
+ }
+
+ void SAL_CALL CXPathAPI::registerNS(
+ const OUString& aPrefix,
+ const OUString& aURI)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ m_nsmap.emplace(aPrefix, aURI);
+ }
+
+ void SAL_CALL CXPathAPI::unregisterNS(
+ const OUString& aPrefix,
+ const OUString& aURI)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ if ((m_nsmap.find(aPrefix))->second == aURI) {
+ m_nsmap.erase(aPrefix);
+ }
+ }
+
+ // register all namespaces stored in the namespace list for this object
+ // with the current xpath evaluation context
+ static void lcl_registerNamespaces(
+ xmlXPathContextPtr ctx,
+ const nsmap_t& nsmap)
+ {
+ OString oprefix, ouri;
+ for (const auto& rEntry : nsmap)
+ {
+ oprefix = OUStringToOString(rEntry.first, RTL_TEXTENCODING_UTF8);
+ ouri = OUStringToOString(rEntry.second, RTL_TEXTENCODING_UTF8);
+ xmlChar const *p = reinterpret_cast<xmlChar const *>(oprefix.getStr());
+ xmlChar const *u = reinterpret_cast<xmlChar const *>(ouri.getStr());
+ (void)xmlXPathRegisterNs(ctx, p, u);
+ }
+ }
+
+ // get all ns decls on a node (and parent nodes, if any)
+ static void lcl_collectNamespaces(
+ nsmap_t & rNamespaces, Reference< XNode > const& xNamespaceNode)
+ {
+ DOM::CNode *const pCNode(comphelper::getFromUnoTunnel<DOM::CNode>(xNamespaceNode));
+ if (!pCNode) { throw RuntimeException(); }
+
+ ::osl::MutexGuard const g(pCNode->GetOwnerDocument().GetMutex());
+
+ xmlNodePtr pNode = pCNode->GetNodePtr();
+ while (pNode != nullptr) {
+ xmlNsPtr curDef = pNode->nsDef;
+ while (curDef != nullptr) {
+ const xmlChar* pHref = curDef->href;
+ OUString aURI(reinterpret_cast<char const *>(pHref), strlen(reinterpret_cast<char const *>(pHref)), RTL_TEXTENCODING_UTF8);
+ const xmlChar* pPre = curDef->prefix;
+ OUString aPrefix(reinterpret_cast<char const *>(pPre), strlen(reinterpret_cast<char const *>(pPre)), RTL_TEXTENCODING_UTF8);
+ // we could already have this prefix from a child node
+ rNamespaces.emplace(aPrefix, aURI);
+ curDef = curDef->next;
+ }
+ pNode = pNode->parent;
+ }
+ }
+
+ static void lcl_collectRegisterNamespaces(
+ CXPathAPI & rAPI, Reference< XNode > const& xNamespaceNode)
+ {
+ nsmap_t namespaces;
+ lcl_collectNamespaces(namespaces, xNamespaceNode);
+ for (const auto& rEntry : namespaces)
+ {
+ rAPI.registerNS(rEntry.first, rEntry.second);
+ }
+ }
+
+ // register function and variable lookup functions with the current
+ // xpath evaluation context
+ static void lcl_registerExtensions(
+ xmlXPathContextPtr ctx,
+ const extensions_t& extensions)
+ {
+ for (const auto& rExtensionRef : extensions)
+ {
+ Libxml2ExtensionHandle aHandle = rExtensionRef->getLibxml2ExtensionHandle();
+ if ( aHandle.functionLookupFunction != 0 )
+ {
+ xmlXPathRegisterFuncLookup(ctx,
+ reinterpret_cast<xmlXPathFuncLookupFunc>(
+ sal::static_int_cast<sal_IntPtr>(aHandle.functionLookupFunction)),
+ reinterpret_cast<void*>(
+ sal::static_int_cast<sal_IntPtr>(aHandle.functionData)));
+ }
+ if ( aHandle.variableLookupFunction != 0 )
+ {
+ xmlXPathRegisterVariableLookup(ctx,
+ reinterpret_cast<xmlXPathVariableLookupFunc>(
+ sal::static_int_cast<sal_IntPtr>(aHandle.variableLookupFunction)),
+ reinterpret_cast<void*>(
+ sal::static_int_cast<sal_IntPtr>(aHandle.variableData)));
+ }
+ }
+ }
+
+ /**
+ * Use an XPath string to select a nodelist.
+ */
+ Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeList(
+ const Reference< XNode >& contextNode,
+ const OUString& expr)
+ {
+ Reference< XXPathObject > xobj = eval(contextNode, expr);
+ return xobj->getNodeList();
+ }
+
+ /**
+ * same as selectNodeList but registers all name space declarations found on namespaceNode
+ */
+ Reference< XNodeList > SAL_CALL CXPathAPI::selectNodeListNS(
+ const Reference< XNode >& contextNode,
+ const OUString& expr,
+ const Reference< XNode >& namespaceNode)
+ {
+ lcl_collectRegisterNamespaces(*this, namespaceNode);
+ return selectNodeList(contextNode, expr);
+ }
+
+ /**
+ * Same as selectNodeList but returns the first node (if any)
+ */
+ Reference< XNode > SAL_CALL CXPathAPI::selectSingleNode(
+ const Reference< XNode >& contextNode,
+ const OUString& expr)
+ {
+ Reference< XNodeList > aList = selectNodeList(contextNode, expr);
+ Reference< XNode > aNode = aList->item(0);
+ return aNode;
+ }
+
+ /**
+ * Same as selectSingleNode but registers all namespaces declared on
+ * namespaceNode
+ */
+ Reference< XNode > SAL_CALL CXPathAPI::selectSingleNodeNS(
+ const Reference< XNode >& contextNode,
+ const OUString& expr,
+ const Reference< XNode >& namespaceNode )
+ {
+ lcl_collectRegisterNamespaces(*this, namespaceNode);
+ return selectSingleNode(contextNode, expr);
+ }
+
+ static OUString make_error_message(xmlErrorPtr pError)
+ {
+ OUStringBuffer buf;
+ if (pError) {
+ if (pError->message) {
+ buf.appendAscii(pError->message);
+ }
+ int line = pError->line;
+ if (line) {
+ buf.append("Line: ");
+ buf.append(static_cast<sal_Int32>(line));
+ buf.append("\n");
+ }
+ int column = pError->int2;
+ if (column) {
+ buf.append("Column: ");
+ buf.append(static_cast<sal_Int32>(column));
+ buf.append("\n");
+ }
+ } else {
+ buf.append("no error argument!");
+ }
+ OUString msg = buf.makeStringAndClear();
+ return msg;
+ }
+
+ extern "C" {
+
+#if defined __GNUC__
+ __attribute__ ((format (printf, 2, 3)))
+#endif
+ static void generic_error_func(void *, const char *format, ...)
+ {
+ char str[1000];
+ va_list args;
+
+ va_start(args, format);
+#ifdef _WIN32
+#define vsnprintf _vsnprintf
+#endif
+ vsnprintf(str, sizeof(str), format, args);
+ va_end(args);
+
+ SAL_WARN("unoxml", "libxml2 error: " << str);
+ }
+
+ static void structured_error_func(void *, xmlErrorPtr error)
+ {
+ SAL_WARN("unoxml", "libxml2 error: " << make_error_message(error));
+ }
+
+ } // extern "C"
+
+ /**
+ * evaluates an XPath string. relative XPath expressions are evaluated relative to
+ * the context Node
+ */
+ Reference< XXPathObject > SAL_CALL CXPathAPI::eval(
+ Reference< XNode > const& xContextNode,
+ const OUString& expr)
+ {
+ if (!xContextNode.is()) { throw RuntimeException(); }
+
+ nsmap_t nsmap;
+ extensions_t extensions;
+
+ {
+ std::scoped_lock const g(m_Mutex);
+ nsmap = m_nsmap;
+ extensions = m_extensions;
+ }
+
+ // get the node and document
+ ::rtl::Reference<DOM::CDocument> const pCDoc(
+ dynamic_cast<DOM::CDocument*>( comphelper::getFromUnoTunnel<DOM::CNode>(
+ xContextNode->getOwnerDocument())));
+ if (!pCDoc.is()) { throw RuntimeException(); }
+
+ DOM::CNode *const pCNode = comphelper::getFromUnoTunnel<DOM::CNode>(xContextNode);
+ if (!pCNode) { throw RuntimeException(); }
+
+ ::osl::MutexGuard const g(pCDoc->GetMutex()); // lock the document!
+
+ xmlNodePtr const pNode = pCNode->GetNodePtr();
+ if (!pNode) { throw RuntimeException(); }
+ xmlDocPtr pDoc = pNode->doc;
+
+ /* NB: workaround for #i87252#:
+ libxml < 2.6.17 considers it an error if the context
+ node is the empty document (i.e. its xpathCtx->doc has no
+ children). libxml 2.6.17 does not consider it an error.
+ Unfortunately, old libxml prints an error message to stderr,
+ which (afaik) cannot be turned off in this case, so we handle it.
+ */
+ if (!pDoc->children) {
+ throw XPathException();
+ }
+
+ /* Create xpath evaluation context */
+ std::shared_ptr<xmlXPathContext> const xpathCtx(
+ xmlXPathNewContext(pDoc), xmlXPathFreeContext);
+ if (xpathCtx == nullptr) { throw XPathException(); }
+
+ // set context node
+ xpathCtx->node = pNode;
+ // error handling
+ xpathCtx->error = structured_error_func;
+ xmlSetGenericErrorFunc(nullptr, generic_error_func);
+
+ // register namespaces and extension
+ lcl_registerNamespaces(xpathCtx.get(), nsmap);
+ lcl_registerExtensions(xpathCtx.get(), extensions);
+
+ /* run the query */
+ OString o1 = OUStringToOString(expr, RTL_TEXTENCODING_UTF8);
+ xmlChar const *pStr = reinterpret_cast<xmlChar const *>(o1.getStr());
+ std::shared_ptr<xmlXPathObject> const xpathObj(
+ xmlXPathEval(pStr, xpathCtx.get()), xmlXPathFreeObject);
+ xmlSetGenericErrorFunc(nullptr, nullptr);
+ if (nullptr == xpathObj) {
+ // OSL_ENSURE(xpathCtx->lastError == NULL, xpathCtx->lastError->message);
+ throw XPathException();
+ }
+ Reference<XXPathObject> const xObj(
+ new CXPathObject(pCDoc, pCDoc->GetMutex(), xpathObj));
+ return xObj;
+ }
+
+ /**
+ * same as eval but registers all namespace declarations found on namespaceNode
+ */
+ Reference< XXPathObject > SAL_CALL CXPathAPI::evalNS(
+ const Reference< XNode >& contextNode,
+ const OUString& expr,
+ const Reference< XNode >& namespaceNode)
+ {
+ lcl_collectRegisterNamespaces(*this, namespaceNode);
+ return eval(contextNode, expr);
+ }
+
+ /**
+ * uses the service manager to create an instance of the service denoted by aName.
+ * If the returned object implements the XXPathExtension interface, it is added to the list
+ * of extensions that are used when evaluating XPath strings with this XPathAPI instance
+ */
+ void SAL_CALL CXPathAPI::registerExtension(
+ const OUString& aName)
+ {
+ std::scoped_lock const g(m_Mutex);
+
+ // get extension from service manager
+ Reference< XXPathExtension > const xExtension(
+ m_xContext->getServiceManager()->createInstanceWithContext(aName, m_xContext), UNO_QUERY_THROW);
+ m_extensions.push_back(xExtension);
+ }
+
+ /**
+ * registers the given extension instance to be used by XPath evaluations performed through this
+ * XPathAPI instance
+ */
+ void SAL_CALL CXPathAPI::registerExtensionInstance(
+ Reference< XXPathExtension> const& xExtension)
+ {
+ if (!xExtension.is()) {
+ throw RuntimeException();
+ }
+ std::scoped_lock const g(m_Mutex);
+ m_extensions.push_back( xExtension );
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+unoxml_CXPathAPI_get_implementation(
+ css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
+{
+ return cppu::acquire(new XPath::CXPathAPI(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/xpath/xpathapi.hxx b/unoxml/source/xpath/xpathapi.hxx
new file mode 100644
index 000000000..bb37922c8
--- /dev/null
+++ b/unoxml/source/xpath/xpathapi.hxx
@@ -0,0 +1,107 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <map>
+#include <mutex>
+#include <vector>
+
+#include <sal/types.h>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/uno/Sequence.h>
+
+#include <com/sun/star/xml/xpath/XXPathAPI.hpp>
+#include <com/sun/star/xml/dom/XNode.hpp>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/xpath/XXPathObject.hpp>
+#include <com/sun/star/xml/xpath/XXPathExtension.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace XPath
+{
+ typedef std::map<OUString, OUString> nsmap_t;
+ typedef std::vector< css::uno::Reference<css::xml::xpath::XXPathExtension> > extensions_t;
+
+ typedef ::cppu::WeakImplHelper
+ < css::xml::xpath::XXPathAPI
+ , css::lang::XServiceInfo
+ > CXPathAPI_Base;
+
+ class CXPathAPI
+ : public CXPathAPI_Base
+ {
+
+ private:
+ std::mutex m_Mutex;
+ nsmap_t m_nsmap;
+ const css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ extensions_t m_extensions;
+
+ public:
+ // ctor
+ explicit CXPathAPI( const css::uno::Reference< css::uno::XComponentContext >& );
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames () override;
+
+
+ // --- XXPathAPI ---
+
+ virtual void SAL_CALL registerNS(const OUString& aPrefix, const OUString& aURI) override;
+
+ virtual void SAL_CALL unregisterNS(const OUString& aPrefix, const OUString& aURI) override;
+
+ /**
+ Use an XPath string to select a nodelist.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL selectNodeList(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override;
+
+ /**
+ Use an XPath string to select a nodelist.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL selectNodeListNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override;
+
+ /**
+ Use an XPath string to select a single node.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL selectSingleNode(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override;
+
+ /**
+ Use an XPath string to select a single node.
+ */
+ virtual css::uno::Reference< css::xml::dom::XNode > SAL_CALL selectSingleNodeNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override;
+
+ virtual css::uno::Reference< css::xml::xpath::XXPathObject > SAL_CALL eval(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str) override;
+
+ virtual css::uno::Reference< css::xml::xpath::XXPathObject > SAL_CALL evalNS(const css::uno::Reference< css::xml::dom::XNode >& contextNode, const OUString& str, const css::uno::Reference< css::xml::dom::XNode >& namespaceNode) override;
+
+ virtual void SAL_CALL registerExtension(const OUString& aName) override;
+ virtual void SAL_CALL registerExtensionInstance(const css::uno::Reference< css::xml::xpath::XXPathExtension>& aExtension) override;
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/xpath/xpathobject.cxx b/unoxml/source/xpath/xpathobject.cxx
new file mode 100644
index 000000000..1184129a0
--- /dev/null
+++ b/unoxml/source/xpath/xpathobject.cxx
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "xpathobject.hxx"
+
+#include <string.h>
+
+#include "../dom/document.hxx"
+#include "nodelist.hxx"
+
+using namespace css::uno;
+using namespace css::xml::dom;
+using namespace css::xml::xpath;
+
+namespace XPath
+{
+ static XPathObjectType lcl_GetType(xmlXPathObjectPtr const pXPathObj)
+ {
+ switch (pXPathObj->type)
+ {
+ case XPATH_UNDEFINED:
+ return XPathObjectType_XPATH_UNDEFINED;
+ case XPATH_NODESET:
+ return XPathObjectType_XPATH_NODESET;
+ case XPATH_BOOLEAN:
+ return XPathObjectType_XPATH_BOOLEAN;
+ case XPATH_NUMBER:
+ return XPathObjectType_XPATH_NUMBER;
+ case XPATH_STRING:
+ return XPathObjectType_XPATH_STRING;
+#if LIBXML_VERSION < 21000 || defined(LIBXML_XPTR_LOCS_ENABLED)
+ case XPATH_POINT:
+ return XPathObjectType_XPATH_POINT;
+ case XPATH_RANGE:
+ return XPathObjectType_XPATH_RANGE;
+ case XPATH_LOCATIONSET:
+ return XPathObjectType_XPATH_LOCATIONSET;
+#endif
+ case XPATH_USERS:
+ return XPathObjectType_XPATH_USERS;
+ case XPATH_XSLT_TREE:
+ return XPathObjectType_XPATH_XSLT_TREE;
+ default:
+ return XPathObjectType_XPATH_UNDEFINED;
+ }
+ }
+
+ CXPathObject::CXPathObject(
+ ::rtl::Reference<DOM::CDocument> const& pDocument,
+ ::osl::Mutex & rMutex,
+ std::shared_ptr<xmlXPathObject> const& pXPathObj)
+ : m_pDocument(pDocument)
+ , m_rMutex(rMutex)
+ , m_pXPathObj(pXPathObj)
+ , m_XPathObjectType(lcl_GetType(pXPathObj.get()))
+ {
+ }
+
+ /**
+ get object type
+ */
+ XPathObjectType CXPathObject::getObjectType()
+ {
+ return m_XPathObjectType;
+ }
+
+ /**
+ get the nodes from a nodelist type object
+ */
+ Reference< XNodeList > SAL_CALL
+ CXPathObject::getNodeList()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ Reference< XNodeList > const xRet(
+ new CNodeList(m_pDocument, m_rMutex, m_pXPathObj));
+ return xRet;
+ }
+
+ /**
+ get value of a boolean object
+ */
+ sal_Bool SAL_CALL CXPathObject::getBoolean()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return xmlXPathCastToBoolean(m_pXPathObj.get()) != 0;
+ }
+
+ /**
+ get number as byte
+ */
+ sal_Int8 SAL_CALL CXPathObject::getByte()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return static_cast<sal_Int8>(xmlXPathCastToNumber(m_pXPathObj.get()));
+ }
+
+ /**
+ get number as short
+ */
+ sal_Int16 SAL_CALL CXPathObject::getShort()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return static_cast<sal_Int16>(xmlXPathCastToNumber(m_pXPathObj.get()));
+ }
+
+ /**
+ get number as long
+ */
+ sal_Int32 SAL_CALL CXPathObject::getLong()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return static_cast<sal_Int32>(xmlXPathCastToNumber(m_pXPathObj.get()));
+ }
+
+ /**
+ get number as hyper
+ */
+ sal_Int64 SAL_CALL CXPathObject::getHyper()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return static_cast<sal_Int64>(xmlXPathCastToNumber(m_pXPathObj.get()));
+ }
+
+ /**
+ get number as float
+ */
+ float SAL_CALL CXPathObject::getFloat()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return static_cast<float>(xmlXPathCastToNumber(m_pXPathObj.get()));
+ }
+
+ /**
+ get number as double
+ */
+ double SAL_CALL CXPathObject::getDouble()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ return xmlXPathCastToNumber(m_pXPathObj.get());
+ }
+
+ /**
+ get string value
+ */
+ OUString SAL_CALL CXPathObject::getString()
+ {
+ ::osl::MutexGuard const g(m_rMutex);
+
+ std::shared_ptr<xmlChar const> str(
+ xmlXPathCastToString(m_pXPathObj.get()), xmlFree);
+ char const*const pS(reinterpret_cast<char const*>(str.get()));
+ return OUString(pS, strlen(pS), RTL_TEXTENCODING_UTF8);
+ }
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/unoxml/source/xpath/xpathobject.hxx b/unoxml/source/xpath/xpathobject.hxx
new file mode 100644
index 000000000..41a8e45a0
--- /dev/null
+++ b/unoxml/source/xpath/xpathobject.hxx
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <libxml/xpath.h>
+
+#include <sal/types.h>
+#include <rtl/ref.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/uno/Reference.h>
+#include <com/sun/star/xml/dom/XNodeList.hpp>
+#include <com/sun/star/xml/xpath/XXPathObject.hpp>
+
+#include "../dom/document.hxx"
+
+namespace DOM {
+ class CDocument;
+}
+
+namespace XPath
+{
+ class CXPathObject : public cppu::WeakImplHelper< css::xml::xpath::XXPathObject >
+ {
+ private:
+ ::rtl::Reference< DOM::CDocument > const m_pDocument;
+ ::osl::Mutex & m_rMutex;
+ std::shared_ptr<xmlXPathObject> const m_pXPathObj;
+ css::xml::xpath::XPathObjectType const m_XPathObjectType;
+
+ public:
+ CXPathObject( ::rtl::Reference<DOM::CDocument> const& pDocument,
+ ::osl::Mutex & rMutex,
+ std::shared_ptr<xmlXPathObject> const& pXPathObj);
+
+ /**
+ get object type
+ */
+ virtual css::xml::xpath::XPathObjectType SAL_CALL getObjectType() override;
+
+ /**
+ get the nodes from a nodelist type object
+ */
+ virtual css::uno::Reference< css::xml::dom::XNodeList > SAL_CALL getNodeList() override;
+
+ /**
+ get value of a boolean object
+ */
+ virtual sal_Bool SAL_CALL getBoolean() override;
+
+ /**
+ get number as byte
+ */
+ virtual sal_Int8 SAL_CALL getByte() override;
+
+ /**
+ get number as short
+ */
+ virtual sal_Int16 SAL_CALL getShort() override;
+
+ /**
+ get number as long
+ */
+ virtual sal_Int32 SAL_CALL getLong() override;
+
+ /**
+ get number as hyper
+ */
+ virtual sal_Int64 SAL_CALL getHyper() override;
+
+ /**
+ get number as float
+ */
+ virtual float SAL_CALL getFloat() override;
+
+ /**
+ get number as double
+ */
+ virtual double SAL_CALL getDouble() override;
+
+ /**
+ get string value
+ */
+ virtual OUString SAL_CALL getString() override;
+
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */