From ed5640d8b587fbcfed7dd7967f3de04b37a76f26 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 11:06:44 +0200 Subject: Adding upstream version 4:7.4.7. Signed-off-by: Daniel Baumann --- unoxml/source/rdf/CBlankNode.cxx | 117 ++ unoxml/source/rdf/CLiteral.cxx | 167 +++ unoxml/source/rdf/CURI.cxx | 807 ++++++++++ unoxml/source/rdf/librdf_repository.cxx | 2465 +++++++++++++++++++++++++++++++ unoxml/source/rdf/unordf.component | 35 + 5 files changed, 3591 insertions(+) create mode 100644 unoxml/source/rdf/CBlankNode.cxx create mode 100644 unoxml/source/rdf/CLiteral.cxx create mode 100644 unoxml/source/rdf/CURI.cxx create mode 100644 unoxml/source/rdf/librdf_repository.cxx create mode 100644 unoxml/source/rdf/unordf.component (limited to 'unoxml/source/rdf') 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 +#include +#include +#include +#include +#include + +#include + + +/// 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 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 +#include +#include +#include +#include +#include + +#include + + +/// 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 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 +#include +#include +#include +#include +#include +#include + +#include + + +/// 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 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +/** + 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 + librdf_QuerySelectResult: an XEnumeration> + + */ + +/// anonymous implementation namespace +namespace { + +class librdf_NamedGraph; +class librdf_Repository; + +using namespace ::com::sun::star; + +typedef std::map< OUString, ::rtl::Reference > + 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(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 const type; + Literal(OString const& i_rValue, OString const& i_rLanguage, + ::std::optional const& i_rType) + : value(i_rValue) + , language(i_rLanguage) + , type(i_rType) + { } + }; + struct Statement + { + std::shared_ptr const pSubject; + std::shared_ptr const pPredicate; + std::shared_ptr const pObject; + Statement(std::shared_ptr const& i_pSubject, + std::shared_ptr const& i_pPredicate, + std::shared_ptr 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 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 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 convertToXURI(librdf_uri* i_pURI) const; + uno::Reference convertToXURI(librdf_node* i_pURI) const; + uno::Reference + convertToXResource(librdf_node* i_pNode) const; + uno::Reference 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 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, 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 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 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 m_pStorage; + /// librdf repository model + std::shared_ptr 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 const& i_pStream, + std::shared_ptr const& i_pContext, + std::shared_ptr const& i_pQuery = + std::shared_ptr() ) + : 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& >(m_pStream).reset(); + const_cast& >(m_pContext).reset(); + const_cast& >(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 const m_pQuery; + std::shared_ptr const m_pContext; + std::shared_ptr 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_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 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 m_vStatements; + std::atomic 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 const& i_pQuery, + std::shared_ptr 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& >(m_pQueryResult) + .reset(); + const_cast& >(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 const m_pQuery; + std::shared_ptr 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 +{ +public: + NodeArray(int cnt) : std::vector(cnt) {} + + ~NodeArray() noexcept + { + std::for_each(begin(), end(), safe_librdf_free_node); + } + + using std::vector::data; + using std::vector::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 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 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> 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 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_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(0), safe_librdf_free_world ), + , m_pStorage(static_cast(nullptr), safe_librdf_free_storage) + , m_pModel (static_cast(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 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(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 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 buf; + uno::Reference 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( 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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 pBaseURI( + librdf_new_uri(m_pWorld.get(), + reinterpret_cast (baseURI.getStr())), + safe_librdf_free_uri); + if (!pBaseURI) { + throw uno::RuntimeException( "librdf_Repository::importGraph: librdf_new_uri failed", *this); + } + + const std::shared_ptr 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 pStream( + librdf_parser_parse_counted_string_as_stream(pParser.get(), + reinterpret_cast(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 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 buf( + reinterpret_cast(pBuffer), length); + rStream->writeBytes(buf); + } + else + { + unsigned char *postcomment = + reinterpret_cast(strchr(reinterpret_cast(pBuffer), '\n')); + if (postcomment != nullptr) + { + ++postcomment; + + size_t preamblelen = postcomment - pBuffer; + + uno::Sequence buf( + reinterpret_cast(pBuffer), preamblelen); + rStream->writeBytes(buf); + + OString aComment = + ""; + + buf = uno::Sequence( + reinterpret_cast(aComment.getStr()), aComment.getLength()); + rStream->writeBytes(buf); + + buf = uno::Sequence( + reinterpret_cast(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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 pBaseURI( + librdf_new_uri(m_pWorld.get(), + reinterpret_cast (baseURI.getStr())), + safe_librdf_free_uri); + if (!pBaseURI) { + throw uno::RuntimeException( + "librdf_Repository::exportGraph: " + "librdf_new_uri failed", *this); + } + + const std::shared_ptr 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 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 pRelativeURI( + librdf_new_uri(m_pWorld.get(), reinterpret_cast + ("http://feature.librdf.org/raptor-relativeURIs")), + safe_librdf_free_uri); + const std::shared_ptr pWriteBaseURI( + librdf_new_uri(m_pWorld.get(), reinterpret_cast + ("http://feature.librdf.org/raptor-writeBaseURI")), + safe_librdf_free_uri); + const std::shared_ptr p0( + librdf_new_node_from_literal(m_pWorld.get(), + reinterpret_cast ("0"), nullptr, 0), + safe_librdf_free_node); + const std::shared_ptr p1( + librdf_new_node_from_literal(m_pWorld.get(), + reinterpret_cast ("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 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 > ret; + std::transform(m_NamedGraphs.begin(), m_NamedGraphs.end(), + std::back_inserter(ret), + [](std::pair> 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 const & i_xNode) +{ + const uno::Reference 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(), + std::shared_ptr()); + } + + 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 pStatement( + librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt), + safe_librdf_free_statement); + OSL_ENSURE(pStatement, "mkStatement failed"); + + const std::shared_ptr 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()); +} + + +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 pQuery( + librdf_new_query(m_pWorld.get(), s_sparql, nullptr, + reinterpret_cast (query.getStr()), nullptr), + safe_librdf_free_query); + if (!pQuery) { + throw rdf::QueryException( + "librdf_Repository::querySelect: " + "librdf_new_query failed", *this); + } + const std::shared_ptr 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 pQuery( + librdf_new_query(m_pWorld.get(), s_sparql, nullptr, + reinterpret_cast (query.getStr()), nullptr), + safe_librdf_free_query); + if (!pQuery) { + throw rdf::QueryException( + "librdf_Repository::queryConstruct: " + "librdf_new_query failed", *this); + } + const std::shared_ptr 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 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(), 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 pQuery( + librdf_new_query(m_pWorld.get(), s_sparql, nullptr, + reinterpret_cast (query.getStr()), nullptr), + safe_librdf_free_query); + if (!pQuery) { + throw rdf::QueryException( + "librdf_Repository::queryAsk: " + "librdf_new_query failed", *this); + } + const std::shared_ptr 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 xService(i_xObject, + uno::UNO_QUERY_THROW); + uno::Reference 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 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 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 const pSubject( + librdf_TypeConverter::extractResource_NoLock(i_xSubject)); + std::shared_ptr const pContent( + librdf_TypeConverter::extractNode_NoLock(xContent)); + ::std::vector< std::shared_ptr > + predicates; + ::std::transform(i_rPredicates.begin(), i_rPredicates.end(), + ::std::back_inserter(predicates), + [](uno::Reference 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(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, 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, sal_Bool >(); + } + OUString const sXmlId(mdref.First + "#" + mdref.Second); + uno::Reference 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, 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_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(), + std::shared_ptr()); + } + + 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 pStatement( + librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt), + safe_librdf_free_statement); + OSL_ENSURE(pStatement, "mkStatement failed"); + + const std::shared_ptr 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()); +} + +// 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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 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 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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 pStatement( + librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt), + safe_librdf_free_statement); + OSL_ENSURE(pStatement, "mkStatement failed"); + + const std::shared_ptr 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 +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 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 pContext( + librdf_new_node_from_uri_string(m_pWorld.get(), + reinterpret_cast (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 pStatement( + librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt), + safe_librdf_free_statement); + OSL_ENSURE(pStatement, "mkStatement failed"); + + const std::shared_ptr 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_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(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(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::extractResource_NoLock( + const uno::Reference< rdf::XResource > & i_xResource) +{ + if (!i_xResource.is()) { + return std::shared_ptr(); + } + 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(label); + } else { // assumption: everything else is URI + const OString uri( + OUStringToOString(i_xResource->getStringValue(), + RTL_TEXTENCODING_UTF8) ); + return std::make_shared(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(i_pResource)); + if (pBlankNode) { + librdf_node *pNode( + librdf_new_node_from_blank_identifier(i_pWorld, + reinterpret_cast( + 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(i_pResource)); + assert(pURI); + librdf_node *pNode( + librdf_new_node_from_uri_string(i_pWorld, + reinterpret_cast(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::extractNode_NoLock( + const uno::Reference< rdf::XNode > & i_xNode) +{ + if (!i_xNode.is()) { + return std::shared_ptr(); + } + 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(); + } + 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 type; + if (xType.is()) + { + type = + OUStringToOString(xType->getStringValue(), RTL_TEXTENCODING_UTF8); + } + return std::make_shared(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(i_pNode)); + if (pResource) { + return mkResource_Lock(i_pWorld, pResource); + } + + Literal const*const pLiteral(dynamic_cast(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(pLiteral->value.getStr()) + , nullptr, 0); + } else { + const std::shared_ptr pDatatype( + mkURI_Lock(i_pWorld, *pLiteral->type), + safe_librdf_free_uri); + ret = librdf_new_node_from_typed_literal(i_pWorld, + reinterpret_cast(pLiteral->value.getStr()) + , nullptr, pDatatype.get()); + } + } else { + if (!pLiteral->type) { + ret = librdf_new_node_from_literal(i_pWorld, + reinterpret_cast(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 const pSubject( + extractResource_NoLock(i_xSubject)); + std::shared_ptr const pPredicate( + std::dynamic_pointer_cast(extractResource_NoLock(i_xPredicate))); + std::shared_ptr 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 +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(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 +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 +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(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 +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(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 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 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 @@ + + + + + + + + + + + + + + + + + -- cgit v1.2.3