Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/unoxml/source/rdf/librdf_repository.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <string.h>
21
22
#include <map>
23
#include <memory>
24
#include <mutex>
25
#include <set>
26
#include <string_view>
27
#include <iterator>
28
#include <algorithm>
29
#include <atomic>
30
31
#include <optional>
32
33
#include <libxslt/security.h>
34
35
#include <redland.h>
36
37
#include <com/sun/star/container/ElementExistException.hpp>
38
#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
39
#include <com/sun/star/lang/XServiceInfo.hpp>
40
#include <com/sun/star/lang/XInitialization.hpp>
41
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
42
#include <com/sun/star/lang/IllegalArgumentException.hpp>
43
#include <com/sun/star/io/XSeekable.hpp>
44
#include <com/sun/star/text/XTextRange.hpp>
45
#include <com/sun/star/rdf/ParseException.hpp>
46
#include <com/sun/star/rdf/QueryException.hpp>
47
#include <com/sun/star/rdf/RepositoryException.hpp>
48
#include <com/sun/star/rdf/XDocumentRepository.hpp>
49
#include <com/sun/star/rdf/XLiteral.hpp>
50
#include <com/sun/star/rdf/FileFormat.hpp>
51
#include <com/sun/star/rdf/BlankNode.hpp>
52
#include <com/sun/star/rdf/URI.hpp>
53
#include <com/sun/star/rdf/Literal.hpp>
54
55
#include <rtl/ref.hxx>
56
#include <rtl/ustrbuf.hxx>
57
#include <rtl/ustring.hxx>
58
#include <osl/diagnose.h>
59
#include <cppuhelper/exc_hlp.hxx>
60
#include <cppuhelper/implbase.hxx>
61
#include <cppuhelper/supportsservice.hxx>
62
#include <unotools/weakref.hxx>
63
64
#include <comphelper/sequence.hxx>
65
#include <comphelper/xmltools.hxx>
66
67
#include <com/sun/star/embed/XEncryptionProtectedSource2.hpp>
68
#include <utility>
69
70
/**
71
    Implementation of the service com.sun.star.rdf.Repository.
72
73
    This implementation uses the Redland RDF library (librdf).
74
75
    There are several classes involved:
76
    librdf_TypeConverter:   helper class to convert data types redland <-> uno
77
    librdf_Repository:      the main repository, does almost all the work
78
    librdf_NamedGraph:      the XNamedGraph, forwards everything to repository
79
    librdf_GraphResult:     an XEnumeration<Statement>
80
    librdf_QuerySelectResult:   an XEnumeration<sequence<XNode>>
81
82
 */
83
84
/// anonymous implementation namespace
85
namespace {
86
87
class librdf_NamedGraph;
88
class librdf_Repository;
89
90
using namespace ::com::sun::star;
91
92
typedef std::map< OUString, ::rtl::Reference<librdf_NamedGraph> >
93
    NamedGraphMap_t;
94
95
const char s_sparql [] = "sparql";
96
const char s_nsOOo  [] = "http://openoffice.org/2004/office/rdfa/";
97
98
99
//FIXME: this approach is not ideal. can we use blank nodes instead?
100
bool isInternalContext(librdf_node *i_pNode) noexcept
101
0
{
102
0
    OSL_ENSURE(i_pNode, "isInternalContext: context null");
103
0
    OSL_ENSURE(librdf_node_is_resource(i_pNode),
104
0
        "isInternalContext: context not resource");
105
0
    if (i_pNode) {
106
0
        librdf_uri *pURI(librdf_node_get_uri(i_pNode));
107
0
        OSL_ENSURE(pURI, "isInternalContext: URI null");
108
0
        if (pURI) {
109
0
            unsigned char *pContextURI(librdf_uri_as_string(pURI));
110
0
            assert(pContextURI && "isInternalContext: URI string null");
111
            // if prefix matches reserved uri, it is RDFa context
112
0
            if (!strncmp(reinterpret_cast<char *>(pContextURI),
113
0
                    s_nsOOo, sizeof(s_nsOOo)-1)) {
114
0
                return true;
115
0
            }
116
0
        }
117
0
        return false;
118
0
    }
119
0
    return true;
120
0
}
121
122
123
// n.b.: librdf destructor functions dereference null pointers!
124
//       so they need to be wrapped to be usable with std::shared_ptr.
125
void safe_librdf_free_world(librdf_world *const world)
126
0
{
127
0
    if (world) { librdf_free_world(world); }
128
0
}
129
void safe_librdf_free_model(librdf_model *const model)
130
13.4k
{
131
13.4k
    if (model) { librdf_free_model(model); }
132
13.4k
}
133
void safe_librdf_free_node(librdf_node* node)
134
13.4k
{
135
13.4k
    if (node) { librdf_free_node(node); }
136
13.4k
}
137
void safe_librdf_free_parser(librdf_parser *const parser)
138
0
{
139
0
    if (parser) { librdf_free_parser(parser); }
140
0
}
141
void safe_librdf_free_query(librdf_query *const query)
142
0
{
143
0
    if (query) { librdf_free_query(query); }
144
0
}
145
void
146
safe_librdf_free_query_results(librdf_query_results *const query_results)
147
0
{
148
0
    if (query_results) { librdf_free_query_results(query_results); }
149
0
}
150
void safe_librdf_free_serializer(librdf_serializer *const serializer)
151
0
{
152
0
    if (serializer) { librdf_free_serializer(serializer); }
153
0
}
154
void safe_librdf_free_statement(librdf_statement *const statement)
155
13.4k
{
156
13.4k
    if (statement) { librdf_free_statement(statement); }
157
13.4k
}
158
void safe_librdf_free_storage(librdf_storage *const storage)
159
13.4k
{
160
13.4k
    if (storage) { librdf_free_storage(storage); }
161
13.4k
}
162
void safe_librdf_free_stream(librdf_stream *const stream)
163
13.4k
{
164
13.4k
    if (stream) { librdf_free_stream(stream); }
165
13.4k
}
166
void safe_librdf_free_uri(librdf_uri *const uri)
167
0
{
168
0
    if (uri) { librdf_free_uri(uri); }
169
0
}
170
171
172
/** converts between librdf types and UNO API types.
173
 */
174
class librdf_TypeConverter
175
{
176
public:
177
178
    // some wrapper classes to temporarily hold values of UNO XNodes
179
    struct Node
180
    {
181
33.6k
        virtual ~Node() {}
182
    };
183
    struct Resource : public Node { };
184
    struct URI : public Resource
185
    {
186
        OString const value;
187
        explicit URI(OString i_Value)
188
33.6k
            : value(std::move(i_Value))
189
33.6k
        { }
190
    };
191
    struct BlankNode : public Resource
192
    {
193
        OString const value;
194
        explicit BlankNode(OString i_Value)
195
0
            : value(std::move(i_Value))
196
0
        { }
197
    };
198
    struct Literal : public Node
199
    {
200
        OString const value;
201
        OString const language;
202
        ::std::optional<OString> const type;
203
        Literal(OString  i_rValue, OString i_Language,
204
                ::std::optional<OString> i_Type)
205
0
            : value(std::move(i_rValue))
206
0
            , language(std::move(i_Language))
207
0
            , type(std::move(i_Type))
208
0
        { }
209
    };
210
    struct Statement
211
    {
212
        std::shared_ptr<Resource> const pSubject;
213
        std::shared_ptr<URI> const pPredicate;
214
        std::shared_ptr<Node> const pObject;
215
        Statement(std::shared_ptr<Resource> i_pSubject,
216
                  std::shared_ptr<URI> i_pPredicate,
217
                  std::shared_ptr<Node> i_pObject)
218
13.4k
            : pSubject(std::move(i_pSubject))
219
13.4k
            , pPredicate(std::move(i_pPredicate))
220
13.4k
            , pObject(std::move(i_pObject))
221
13.4k
        { }
222
    };
223
224
    librdf_TypeConverter(
225
            uno::Reference< uno::XComponentContext > i_xContext,
226
            librdf_Repository &i_rRep)
227
6.73k
        : m_xContext(std::move(i_xContext))
228
6.73k
        , m_rRep(i_rRep)
229
6.73k
    { };
230
231
    librdf_world *createWorld_Lock() const;
232
    librdf_storage *createStorage_Lock(librdf_world *i_pWorld) const;
233
    librdf_model *createModel_Lock(librdf_world *i_pWorld,
234
        librdf_storage * i_pStorage) const;
235
    static librdf_uri* mkURI_Lock(librdf_world* i_pWorld,
236
        const OString & i_rURI);
237
    static librdf_node* mkResource_Lock(librdf_world* i_pWorld,
238
        const Resource * i_pResource);
239
    static librdf_node* mkNode_Lock(librdf_world* i_pWorld,
240
        const Node * i_pNode);
241
    static librdf_statement* mkStatement_Lock(librdf_world* i_pWorld,
242
        Statement const& i_rStatement);
243
    static std::shared_ptr<Resource> extractResource_NoLock(
244
        const uno::Reference< rdf::XResource > & i_xResource);
245
    static void extractResourceToCacheKey_NoLock(
246
        const uno::Reference< rdf::XResource > & i_xResource,
247
        OUStringBuffer& rBuf);
248
    static std::shared_ptr<Node> extractNode_NoLock(
249
        const uno::Reference< rdf::XNode > & i_xNode);
250
    static void extractNodeToCacheKey_NoLock(
251
        const uno::Reference< rdf::XNode > & i_xNode,
252
        OUStringBuffer& rBuffer);
253
    static Statement extractStatement_NoLock(
254
        const uno::Reference< rdf::XResource > & i_xSubject,
255
        const uno::Reference< rdf::XURI > & i_xPredicate,
256
        const uno::Reference< rdf::XNode > & i_xObject);
257
    uno::Reference<rdf::XURI> convertToXURI(librdf_uri* i_pURI) const;
258
    uno::Reference<rdf::XURI> convertToXURI(librdf_node* i_pURI) const;
259
    uno::Reference<rdf::XResource>
260
        convertToXResource(librdf_node* i_pNode) const;
261
    uno::Reference<rdf::XNode> convertToXNode(librdf_node* i_pNode) const;
262
    rdf::Statement
263
        convertToStatement(librdf_statement* i_pStmt, librdf_node* i_pContext)
264
        const;
265
266
private:
267
    uno::Reference< uno::XComponentContext > const m_xContext;
268
    librdf_Repository & m_rRep;
269
};
270
271
272
/** implements the repository service.
273
 */
274
class librdf_Repository:
275
//    private ::cppu::BaseMutex,
276
    public ::cppu::WeakImplHelper<
277
        lang::XServiceInfo,
278
        rdf::XDocumentRepository,
279
        lang::XInitialization>
280
{
281
public:
282
283
    explicit librdf_Repository(
284
        uno::Reference< uno::XComponentContext > const & i_xContext);
285
    virtual ~librdf_Repository() override;
286
287
    // css::lang::XServiceInfo:
288
    virtual OUString SAL_CALL getImplementationName() override;
289
    virtual sal_Bool SAL_CALL supportsService(
290
            const OUString & ServiceName) override;
291
    virtual uno::Sequence< OUString > SAL_CALL
292
        getSupportedServiceNames() override;
293
294
    // css::rdf::XRepository:
295
    virtual uno::Reference< rdf::XBlankNode > SAL_CALL createBlankNode() override;
296
    virtual uno::Reference<rdf::XNamedGraph> SAL_CALL importGraph(
297
            ::sal_Int16 i_Format,
298
            const uno::Reference< io::XInputStream > & i_xInStream,
299
            const uno::Reference< rdf::XURI > & i_xGraphName,
300
            const uno::Reference< rdf::XURI > & i_xBaseURI) override;
301
    virtual void SAL_CALL exportGraph(::sal_Int16 i_Format,
302
            const uno::Reference< io::XOutputStream > & i_xOutStream,
303
            const uno::Reference< rdf::XURI > & i_xGraphName,
304
            const uno::Reference< rdf::XURI > & i_xBaseURI) override;
305
    virtual uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
306
        getGraphNames() override;
307
    virtual uno::Reference< rdf::XNamedGraph > SAL_CALL getGraph(
308
            const uno::Reference< rdf::XURI > & i_xGraphName) override;
309
    virtual uno::Reference< rdf::XNamedGraph > SAL_CALL createGraph(
310
            const uno::Reference< rdf::XURI > & i_xGraphName) override;
311
    virtual void SAL_CALL destroyGraph(
312
            const uno::Reference< rdf::XURI > & i_xGraphName) override;
313
    virtual uno::Reference< container::XEnumeration > SAL_CALL getStatements(
314
            const uno::Reference< rdf::XResource > & i_xSubject,
315
            const uno::Reference< rdf::XURI > & i_xPredicate,
316
            const uno::Reference< rdf::XNode > & i_xObject) override;
317
    virtual uno::Reference< rdf::XQuerySelectResult > SAL_CALL
318
            querySelect(const OUString & i_rQuery) override;
319
    virtual uno::Reference< container::XEnumeration > SAL_CALL
320
        queryConstruct(const OUString & i_rQuery) override;
321
    virtual sal_Bool SAL_CALL queryAsk(const OUString & i_rQuery) override;
322
323
    // css::rdf::XDocumentRepository:
324
    virtual void SAL_CALL setStatementRDFa(
325
            const uno::Reference< rdf::XResource > & i_xSubject,
326
            const uno::Sequence< uno::Reference< rdf::XURI > > & i_rPredicates,
327
            const uno::Reference< rdf::XMetadatable > & i_xObject,
328
            const OUString & i_rRDFaContent,
329
            const uno::Reference< rdf::XURI > & i_xRDFaDatatype) override;
330
    virtual void SAL_CALL removeStatementRDFa(
331
            const uno::Reference< rdf::XMetadatable > & i_xElement) override;
332
    virtual beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool > SAL_CALL
333
        getStatementRDFa(uno::Reference< rdf::XMetadatable > const& i_xElement) override;
334
    virtual uno::Reference< container::XEnumeration > SAL_CALL
335
        getStatementsRDFa(
336
            const uno::Reference< rdf::XResource > & i_xSubject,
337
            const uno::Reference< rdf::XURI > & i_xPredicate,
338
            const uno::Reference< rdf::XNode > & i_xObject) override;
339
340
    // css::lang::XInitialization:
341
    virtual void SAL_CALL initialize(
342
            const uno::Sequence< css::uno::Any > & i_rArguments) override;
343
344
    // XNamedGraph forwards ---------------------------------------------
345
    NamedGraphMap_t::iterator clearGraph_NoLock(
346
            const OUString & i_rGraphName,
347
            bool i_Internal = false );
348
    NamedGraphMap_t::iterator clearGraph_Lock(
349
            const OUString & i_rGraphName,
350
            bool i_Internal);
351
    void addStatementGraph_NoLock(
352
            const uno::Reference< rdf::XResource > & i_xSubject,
353
            const uno::Reference< rdf::XURI > & i_xPredicate,
354
            const uno::Reference< rdf::XNode > & i_xObject,
355
            const uno::Reference< rdf::XURI > & i_xName );
356
//        throw (uno::RuntimeException, lang::IllegalArgumentException,
357
//            container::NoSuchElementException, rdf::RepositoryException);
358
    void addStatementGraph_Lock(
359
        librdf_TypeConverter::Statement const& i_rStatement,
360
        OUString const& i_rGraphName,
361
        bool i_Internal);
362
    void removeStatementsGraph_NoLock(
363
            const uno::Reference< rdf::XResource > & i_xSubject,
364
            const uno::Reference< rdf::XURI > & i_xPredicate,
365
            const uno::Reference< rdf::XNode > & i_xObject,
366
            const uno::Reference< rdf::XURI > & i_xName );
367
//        throw (uno::RuntimeException, lang::IllegalArgumentException,
368
//            container::NoSuchElementException, rdf::RepositoryException);
369
    std::vector<rdf::Statement> getStatementsGraph_NoLock(
370
            const uno::Reference< rdf::XResource > & i_xSubject,
371
            const uno::Reference< rdf::XURI > & i_xPredicate,
372
            const uno::Reference< rdf::XNode > & i_xObject,
373
            const uno::Reference< rdf::XURI > & i_xName,
374
            bool i_Internal = false );
375
//        throw (uno::RuntimeException, lang::IllegalArgumentException,
376
//            container::NoSuchElementException, rdf::RepositoryException);
377
378
0
    const librdf_TypeConverter& getTypeConverter() const { return m_TypeConverter; };
379
380
private:
381
382
    librdf_Repository(librdf_Repository const&) = delete;
383
    librdf_Repository& operator=(librdf_Repository const&) = delete;
384
385
    /// this is const, no need to lock m_aMutex to access it
386
    uno::Reference< uno::XComponentContext > const m_xContext;
387
388
    /// librdf global data
389
    /** N.B.: The redland documentation gives the impression that you can have
390
              as many librdf_worlds as you like. This is true in the same sense
391
              that you can physically be in as many places as you like.
392
              Well, you can, just not at the same time.
393
              The ugly truth is that destroying a librdf_world kills a bunch
394
              of static variables; other librdf_worlds become very unhappy
395
              when they access these.
396
              And of course this is not documented anywhere that I could find.
397
              So we allocate a single world, and refcount that.
398
     */
399
    static std::shared_ptr<librdf_world> m_pWorld;
400
    /// refcount
401
    static sal_uInt32 m_NumInstances;
402
    /// mutex for m_pWorld - redland is not as threadsafe as is often claimed
403
    static std::mutex m_aMutex;
404
405
    // NB: sequence of the shared pointers is important!
406
    /// librdf repository storage
407
    std::shared_ptr<librdf_storage> m_pStorage;
408
    /// librdf repository model
409
    std::shared_ptr<librdf_model> m_pModel;
410
411
    /// all named graphs
412
    NamedGraphMap_t m_NamedGraphs;
413
414
    /// type conversion helper - stateless
415
    librdf_TypeConverter m_TypeConverter;
416
417
    /// set of xml:ids of elements with xhtml:content
418
    ::std::set< OUString > m_RDFaXHTMLContentSet;
419
};
420
421
422
/** result of operations that return a graph, i.e.,
423
    an XEnumeration of statements.
424
 */
425
class librdf_GraphResult:
426
    public ::cppu::WeakImplHelper<
427
        container::XEnumeration>
428
{
429
public:
430
431
    librdf_GraphResult(librdf_Repository *i_pRepository,
432
            std::mutex & i_rMutex,
433
            std::shared_ptr<librdf_stream> i_pStream,
434
            std::shared_ptr<librdf_node> i_pContext,
435
            std::shared_ptr<librdf_query> i_pQuery =
436
                std::shared_ptr<librdf_query>() )
437
24
        : m_xRep(i_pRepository)
438
24
        , m_rMutex(i_rMutex)
439
24
        , m_pQuery(std::move(i_pQuery))
440
24
        , m_pContext(std::move(i_pContext))
441
24
        , m_pStream(std::move(i_pStream))
442
24
    { };
443
444
    virtual ~librdf_GraphResult() override
445
24
    {
446
24
        std::scoped_lock g(m_rMutex); // lock mutex when destroying members
447
24
        const_cast<std::shared_ptr<librdf_stream>& >(m_pStream).reset();
448
24
        const_cast<std::shared_ptr<librdf_node>& >(m_pContext).reset();
449
24
        const_cast<std::shared_ptr<librdf_query>& >(m_pQuery).reset();
450
24
    }
451
452
    // css::container::XEnumeration:
453
    virtual sal_Bool SAL_CALL hasMoreElements() override;
454
    virtual uno::Any SAL_CALL nextElement() override;
455
456
private:
457
458
    librdf_GraphResult(librdf_GraphResult const&) = delete;
459
    librdf_GraphResult& operator=(librdf_GraphResult const&) = delete;
460
461
    // NB: this is not a weak pointer: streams _must_ be deleted before the
462
    //     storage they point into, so we keep the repository alive here
463
    // also, sequence is important: the stream must be destroyed first.
464
    ::rtl::Reference< librdf_Repository > m_xRep;
465
    // needed for synchronizing access to librdf (it doesn't do win32 threading)
466
    std::mutex & m_rMutex;
467
    // the query (in case this is a result of a graph query)
468
    // not that the redland documentation spells this out explicitly, but
469
    // queries must be freed only after all the results are completely read
470
    std::shared_ptr<librdf_query>  const m_pQuery;
471
    std::shared_ptr<librdf_node>   const m_pContext;
472
    std::shared_ptr<librdf_stream> const m_pStream;
473
474
    librdf_node* getContext_Lock() const;
475
};
476
477
478
// css::container::XEnumeration:
479
sal_Bool SAL_CALL
480
librdf_GraphResult::hasMoreElements()
481
24
{
482
24
    std::scoped_lock g(m_rMutex);
483
24
    return m_pStream && !librdf_stream_end(m_pStream.get());
484
24
}
485
486
librdf_node* librdf_GraphResult::getContext_Lock() const
487
0
{
488
0
    if (!m_pStream || librdf_stream_end(m_pStream.get()))
489
0
        return nullptr;
490
0
    librdf_node *pCtxt(
491
0
#if LIBRDF_VERSION >= 10012
492
0
        librdf_stream_get_context2(m_pStream.get()) );
493
#else
494
        static_cast<librdf_node *>(librdf_stream_get_context(m_pStream.get())) );
495
#endif
496
0
    if (pCtxt)
497
0
        return pCtxt;
498
0
    return m_pContext.get();
499
0
}
500
501
css::uno::Any SAL_CALL
502
librdf_GraphResult::nextElement()
503
0
{
504
0
    std::scoped_lock g(m_rMutex);
505
0
    if (m_pStream && librdf_stream_end(m_pStream.get())) {
506
0
        throw container::NoSuchElementException();
507
0
    }
508
0
    librdf_node * pCtxt = getContext_Lock();
509
510
0
    librdf_statement *pStmt( librdf_stream_get_object(m_pStream.get()) );
511
0
    if (!pStmt) {
512
0
        rdf::QueryException e(
513
0
            u"librdf_GraphResult::nextElement: "
514
0
            "librdf_stream_get_object failed"_ustr, *this);
515
0
        throw lang::WrappedTargetException(
516
0
            u"librdf_GraphResult::nextElement: "
517
0
            "librdf_stream_get_object failed"_ustr, *this,
518
0
                uno::Any(e));
519
0
    }
520
    // NB: pCtxt may be null here if this is result of a graph query
521
0
    if (pCtxt && isInternalContext(pCtxt)) {
522
0
        pCtxt = nullptr; // XML ID context is implementation detail!
523
0
    }
524
0
    rdf::Statement Stmt(
525
0
        m_xRep->getTypeConverter().convertToStatement(pStmt, pCtxt) );
526
    // NB: this will invalidate current item.
527
0
    librdf_stream_next(m_pStream.get());
528
0
    return uno::Any(Stmt);
529
0
}
530
531
532
/** result of operations that return a graph, i.e.,
533
    an XEnumeration of statements.
534
 */
535
class librdf_GraphResult2:
536
    public ::cppu::WeakImplHelper<
537
        container::XEnumeration>
538
{
539
public:
540
541
    librdf_GraphResult2(std::vector<rdf::Statement> statements)
542
7.81k
        : m_vStatements(std::move(statements))
543
7.81k
    { };
544
545
    // css::container::XEnumeration:
546
    virtual sal_Bool SAL_CALL hasMoreElements() override;
547
    virtual uno::Any SAL_CALL nextElement() override;
548
549
private:
550
551
    std::vector<rdf::Statement> m_vStatements;
552
    std::atomic<std::size_t> m_nIndex = 0;
553
};
554
555
556
// css::container::XEnumeration:
557
sal_Bool SAL_CALL
558
librdf_GraphResult2::hasMoreElements()
559
7.81k
{
560
7.81k
    return m_nIndex < m_vStatements.size();
561
7.81k
}
562
563
css::uno::Any SAL_CALL
564
librdf_GraphResult2::nextElement()
565
0
{
566
0
    std::size_t const n = m_nIndex++;
567
0
    if (m_vStatements.size() <= n)
568
0
    {
569
0
        m_nIndex = m_vStatements.size(); // avoid overflow
570
0
        throw container::NoSuchElementException();
571
0
    }
572
0
    return uno::Any(m_vStatements[n]);
573
0
}
574
575
/** result of tuple queries ("SELECT").
576
 */
577
class librdf_QuerySelectResult:
578
    public ::cppu::WeakImplHelper<
579
        rdf::XQuerySelectResult>
580
{
581
public:
582
583
    librdf_QuerySelectResult(librdf_Repository *i_pRepository,
584
            std::mutex & i_rMutex,
585
            std::shared_ptr<librdf_query> i_pQuery,
586
            std::shared_ptr<librdf_query_results> i_pQueryResult,
587
            uno::Sequence< OUString > const& i_rBindingNames )
588
0
        : m_xRep(i_pRepository)
589
0
        , m_rMutex(i_rMutex)
590
0
        , m_pQuery(std::move(i_pQuery))
591
0
        , m_pQueryResult(std::move(i_pQueryResult))
592
0
        , m_BindingNames(i_rBindingNames)
593
0
    { };
594
595
    virtual ~librdf_QuerySelectResult() override
596
0
    {
597
0
        std::scoped_lock g(m_rMutex); // lock mutex when destroying members
598
0
        const_cast<std::shared_ptr<librdf_query_results>& >(m_pQueryResult)
599
0
            .reset();
600
0
        const_cast<std::shared_ptr<librdf_query>& >(m_pQuery).reset();
601
0
    }
602
603
    // css::container::XEnumeration:
604
    virtual sal_Bool SAL_CALL hasMoreElements() override;
605
    virtual uno::Any SAL_CALL nextElement() override;
606
607
    // css::rdf::XQuerySelectResult:
608
    virtual uno::Sequence< OUString > SAL_CALL getBindingNames() override;
609
610
private:
611
612
    librdf_QuerySelectResult(librdf_QuerySelectResult const&) = delete;
613
    librdf_QuerySelectResult& operator=(librdf_QuerySelectResult const&) = delete;
614
615
    // NB: this is not a weak pointer: streams _must_ be deleted before the
616
    //     storage they point into, so we keep the repository alive here
617
    // also, sequence is important: the stream must be destroyed first.
618
    ::rtl::Reference< librdf_Repository > m_xRep;
619
    // needed for synchronizing access to librdf (it doesn't do win32 threading)
620
    std::mutex & m_rMutex;
621
    // not that the redland documentation spells this out explicitly, but
622
    // queries must be freed only after all the results are completely read
623
    std::shared_ptr<librdf_query> const m_pQuery;
624
    std::shared_ptr<librdf_query_results> const m_pQueryResult;
625
    uno::Sequence< OUString > const m_BindingNames;
626
};
627
628
629
// css::container::XEnumeration:
630
sal_Bool SAL_CALL
631
librdf_QuerySelectResult::hasMoreElements()
632
0
{
633
0
    std::scoped_lock g(m_rMutex);
634
0
    return !librdf_query_results_finished(m_pQueryResult.get());
635
0
}
636
637
class NodeArray : private std::vector<librdf_node*>
638
{
639
public:
640
0
    NodeArray(int cnt) : std::vector<librdf_node*>(cnt) {}
641
642
    ~NodeArray() noexcept
643
0
    {
644
0
        std::for_each(begin(), end(), safe_librdf_free_node);
645
0
    }
646
647
    using std::vector<librdf_node*>::data;
648
    using std::vector<librdf_node*>::operator[];
649
};
650
651
css::uno::Any SAL_CALL
652
librdf_QuerySelectResult::nextElement()
653
0
{
654
0
    std::scoped_lock g(m_rMutex);
655
0
    if (librdf_query_results_finished(m_pQueryResult.get())) {
656
0
        throw container::NoSuchElementException();
657
0
    }
658
0
    sal_Int32 count(m_BindingNames.getLength());
659
0
    OSL_ENSURE(count >= 0, "negative length?");
660
0
    NodeArray aNodes(count);
661
0
    if (librdf_query_results_get_bindings(m_pQueryResult.get(), nullptr,
662
0
                aNodes.data()))
663
0
    {
664
0
        rdf::QueryException e(
665
0
            u"librdf_QuerySelectResult::nextElement: "
666
0
            "librdf_query_results_get_bindings failed"_ustr, *this);
667
0
        throw lang::WrappedTargetException(
668
0
            u"librdf_QuerySelectResult::nextElement: "
669
0
            "librdf_query_results_get_bindings failed"_ustr, *this,
670
0
            uno::Any(e));
671
0
    }
672
0
    uno::Sequence< uno::Reference< rdf::XNode > > ret(count);
673
0
    auto retRange = asNonConstRange(ret);
674
0
    for (int i = 0; i < count; ++i) {
675
0
        retRange[i] = m_xRep->getTypeConverter().convertToXNode(aNodes[i]);
676
0
    }
677
    // NB: this will invalidate current item.
678
0
    librdf_query_results_next(m_pQueryResult.get());
679
0
    return uno::Any(ret);
680
0
}
681
682
// css::rdf::XQuerySelectResult:
683
uno::Sequence< OUString > SAL_CALL
684
librdf_QuerySelectResult::getBindingNames()
685
0
{
686
    // const - no lock needed
687
0
    return m_BindingNames;
688
0
}
689
690
691
/** represents a named graph, and forwards all the work to repository.
692
 */
693
class librdf_NamedGraph:
694
    public ::cppu::WeakImplHelper<
695
        rdf::XNamedGraph>
696
{
697
public:
698
    librdf_NamedGraph(librdf_Repository * i_pRep,
699
            uno::Reference<rdf::XURI> i_xName)
700
6.73k
        : m_wRep(i_pRep)
701
6.73k
        , m_xName(std::move(i_xName))
702
6.73k
    { };
703
704
    // css::rdf::XNode:
705
    virtual OUString SAL_CALL getStringValue() override;
706
707
    // css::rdf::XURI:
708
    virtual OUString SAL_CALL getNamespace() override;
709
    virtual OUString SAL_CALL getLocalName() override;
710
711
    // css::rdf::XNamedGraph:
712
    virtual uno::Reference<rdf::XURI> SAL_CALL getName() override;
713
    virtual void SAL_CALL clear() override;
714
    virtual void SAL_CALL addStatement(
715
            const uno::Reference< rdf::XResource > & i_xSubject,
716
            const uno::Reference< rdf::XURI > & i_xPredicate,
717
            const uno::Reference< rdf::XNode > & i_xObject) override;
718
    virtual void SAL_CALL removeStatements(
719
            const uno::Reference< rdf::XResource > & i_xSubject,
720
            const uno::Reference< rdf::XURI > & i_xPredicate,
721
            const uno::Reference< rdf::XNode > & i_xObject) override;
722
    virtual uno::Reference< container::XEnumeration > SAL_CALL getStatements(
723
            const uno::Reference< rdf::XResource > & i_xSubject,
724
            const uno::Reference< rdf::XURI > & i_xPredicate,
725
            const uno::Reference< rdf::XNode > & i_xObject) override;
726
727
private:
728
729
    librdf_NamedGraph(librdf_NamedGraph const&) = delete;
730
    librdf_NamedGraph& operator=(librdf_NamedGraph const&) = delete;
731
732
    static OUString createCacheKey_NoLock(
733
        const uno::Reference< rdf::XResource > & i_xSubject,
734
        const uno::Reference< rdf::XURI > & i_xPredicate,
735
        const uno::Reference< rdf::XNode > & i_xObject);
736
737
    /// weak reference: this is needed to check if m_pRep is valid
738
    unotools::WeakReference< librdf_Repository > const m_wRep;
739
    uno::Reference< rdf::XURI > const m_xName;
740
741
    /// Querying is rather slow, so cache the results.
742
    std::map<OUString, std::vector<rdf::Statement>> m_aStatementsCache;
743
    std::mutex m_CacheMutex;
744
};
745
746
747
// css::rdf::XNode:
748
OUString SAL_CALL librdf_NamedGraph::getStringValue()
749
0
{
750
0
    return m_xName->getStringValue();
751
0
}
752
753
// css::rdf::XURI:
754
OUString SAL_CALL librdf_NamedGraph::getNamespace()
755
0
{
756
0
    return m_xName->getNamespace();
757
0
}
758
759
OUString SAL_CALL librdf_NamedGraph::getLocalName()
760
0
{
761
0
    return m_xName->getLocalName();
762
0
}
763
764
// css::rdf::XNamedGraph:
765
uno::Reference< rdf::XURI > SAL_CALL librdf_NamedGraph::getName()
766
0
{
767
0
    return m_xName;
768
0
}
769
770
void SAL_CALL librdf_NamedGraph::clear()
771
0
{
772
0
    rtl::Reference< librdf_Repository > xRep( m_wRep );
773
0
    if (!xRep.is()) {
774
0
        throw rdf::RepositoryException(
775
0
            u"librdf_NamedGraph::clear: repository is gone"_ustr, *this);
776
0
    }
777
0
    const OUString contextU( m_xName->getStringValue() );
778
0
    try {
779
0
        xRep->clearGraph_NoLock(contextU);
780
0
    } catch (lang::IllegalArgumentException & ex) {
781
0
        css::uno::Any anyEx = cppu::getCaughtException();
782
0
        throw lang::WrappedTargetRuntimeException( ex.Message,
783
0
                        *this, anyEx );
784
0
    }
785
0
    std::unique_lock g(m_CacheMutex);
786
0
    m_aStatementsCache.clear();
787
0
}
788
789
void SAL_CALL librdf_NamedGraph::addStatement(
790
    const uno::Reference< rdf::XResource > & i_xSubject,
791
    const uno::Reference< rdf::XURI > & i_xPredicate,
792
    const uno::Reference< rdf::XNode > & i_xObject)
793
6.73k
{
794
6.73k
    rtl::Reference< librdf_Repository > xRep( m_wRep );
795
6.73k
    if (!xRep.is()) {
796
0
        throw rdf::RepositoryException(
797
0
            u"librdf_NamedGraph::addStatement: repository is gone"_ustr, *this);
798
0
    }
799
6.73k
    {
800
6.73k
        std::unique_lock g(m_CacheMutex);
801
6.73k
        m_aStatementsCache.clear();
802
6.73k
    }
803
6.73k
    xRep->addStatementGraph_NoLock(
804
6.73k
            i_xSubject, i_xPredicate, i_xObject, m_xName);
805
6.73k
}
806
807
void SAL_CALL librdf_NamedGraph::removeStatements(
808
    const uno::Reference< rdf::XResource > & i_xSubject,
809
    const uno::Reference< rdf::XURI > & i_xPredicate,
810
    const uno::Reference< rdf::XNode > & i_xObject)
811
0
{
812
0
    rtl::Reference< librdf_Repository > xRep( m_wRep );
813
0
    if (!xRep.is()) {
814
0
        throw rdf::RepositoryException(
815
0
            u"librdf_NamedGraph::removeStatements: repository is gone"_ustr, *this);
816
0
    }
817
0
    {
818
0
        std::unique_lock g(m_CacheMutex);
819
0
        m_aStatementsCache.clear();
820
0
    }
821
0
    xRep->removeStatementsGraph_NoLock(
822
0
            i_xSubject, i_xPredicate, i_xObject, m_xName);
823
0
}
824
825
OUString librdf_NamedGraph::createCacheKey_NoLock(
826
    const uno::Reference< rdf::XResource > & i_xSubject,
827
    const uno::Reference< rdf::XURI > & i_xPredicate,
828
    const uno::Reference< rdf::XNode > & i_xObject)
829
7.81k
{
830
7.81k
    OUStringBuffer cacheKey(256);
831
7.81k
    librdf_TypeConverter::extractResourceToCacheKey_NoLock(i_xSubject, cacheKey);
832
7.81k
    cacheKey.append("\t");
833
7.81k
    librdf_TypeConverter::extractResourceToCacheKey_NoLock(i_xPredicate, cacheKey);
834
7.81k
    cacheKey.append("\t");
835
7.81k
    librdf_TypeConverter::extractNodeToCacheKey_NoLock(i_xObject, cacheKey);
836
7.81k
    return cacheKey.makeStringAndClear();
837
7.81k
}
838
839
uno::Reference< container::XEnumeration > SAL_CALL
840
librdf_NamedGraph::getStatements(
841
    const uno::Reference< rdf::XResource > & i_xSubject,
842
    const uno::Reference< rdf::XURI > & i_xPredicate,
843
    const uno::Reference< rdf::XNode > & i_xObject)
844
7.81k
{
845
7.81k
    OUString cacheKey = createCacheKey_NoLock(i_xSubject, i_xPredicate, i_xObject);
846
7.81k
    {
847
7.81k
        std::unique_lock g(m_CacheMutex);
848
7.81k
        auto it = m_aStatementsCache.find(cacheKey);
849
7.81k
        if (it != m_aStatementsCache.end()) {
850
1.07k
            return new librdf_GraphResult2(it->second);
851
1.07k
        }
852
7.81k
    }
853
854
6.73k
    rtl::Reference< librdf_Repository > xRep( m_wRep );
855
6.73k
    if (!xRep.is()) {
856
0
        throw rdf::RepositoryException(
857
0
            u"librdf_NamedGraph::getStatements: repository is gone"_ustr, *this);
858
0
    }
859
6.73k
    std::vector<rdf::Statement> vStatements = xRep->getStatementsGraph_NoLock(
860
6.73k
            i_xSubject, i_xPredicate, i_xObject, m_xName);
861
862
6.73k
    {
863
6.73k
        std::unique_lock g(m_CacheMutex);
864
6.73k
        m_aStatementsCache.emplace(cacheKey, vStatements);
865
6.73k
    }
866
6.73k
    return new librdf_GraphResult2(std::move(vStatements));
867
6.73k
}
868
869
870
std::shared_ptr<librdf_world> librdf_Repository::m_pWorld;
871
sal_uInt32 librdf_Repository::m_NumInstances = 0;
872
std::mutex librdf_Repository::m_aMutex;
873
874
librdf_Repository::librdf_Repository(
875
        uno::Reference< uno::XComponentContext > const & i_xContext)
876
6.73k
    : /*BaseMutex(),*/ m_xContext(i_xContext)
877
//    m_pWorld  (static_cast<librdf_world  *>(0), safe_librdf_free_world  ),
878
6.73k
    , m_pStorage(static_cast<librdf_storage*>(nullptr), safe_librdf_free_storage)
879
6.73k
    , m_pModel  (static_cast<librdf_model  *>(nullptr), safe_librdf_free_model  )
880
6.73k
    , m_TypeConverter(i_xContext, *this)
881
6.73k
{
882
6.73k
    OSL_ENSURE(i_xContext.is(), "librdf_Repository: null context");
883
884
6.73k
    std::scoped_lock g(m_aMutex);
885
6.73k
    if (!m_NumInstances++) {
886
2
        m_pWorld.reset(m_TypeConverter.createWorld_Lock(),
887
2
                safe_librdf_free_world);
888
2
    }
889
6.73k
}
890
891
librdf_Repository::~librdf_Repository()
892
6.73k
{
893
6.73k
    std::scoped_lock g(m_aMutex);
894
895
    // must destroy these before world!
896
6.73k
    m_pModel.reset();
897
6.73k
    m_pStorage.reset();
898
899
    // FIXME: so it turns out that calling librdf_free_world will
900
    //   (via raptor_sax2_finish) call xmlCleanupParser, which will
901
    //   free libxml2's globals! ARRRGH!!! => never call librdf_free_world
902
#if 0
903
    if (!--m_NumInstances) {
904
        m_pWorld.reset();
905
    }
906
#endif
907
6.73k
}
908
909
// com.sun.star.uno.XServiceInfo:
910
OUString SAL_CALL librdf_Repository::getImplementationName()
911
0
{
912
0
    return u"librdf_Repository"_ustr;
913
0
}
914
915
sal_Bool SAL_CALL librdf_Repository::supportsService(
916
    OUString const & serviceName)
917
0
{
918
0
    return cppu::supportsService(this, serviceName);
919
0
}
920
921
uno::Sequence< OUString > SAL_CALL
922
librdf_Repository::getSupportedServiceNames()
923
0
{
924
0
    return { u"com.sun.star.rdf.Repository"_ustr };
925
0
}
926
927
// css::rdf::XRepository:
928
uno::Reference< rdf::XBlankNode > SAL_CALL librdf_Repository::createBlankNode()
929
0
{
930
0
    std::scoped_lock g(m_aMutex);
931
0
    const std::shared_ptr<librdf_node> pNode(
932
0
        librdf_new_node_from_blank_identifier(m_pWorld.get(), nullptr),
933
0
        safe_librdf_free_node);
934
0
    if (!pNode) {
935
0
        throw uno::RuntimeException(
936
0
            u"librdf_Repository::createBlankNode: "
937
0
            "librdf_new_node_from_blank_identifier failed"_ustr, *this);
938
0
    }
939
0
    const unsigned char * id (librdf_node_get_blank_identifier(pNode.get()));
940
0
    if (!id) {
941
0
        throw uno::RuntimeException(
942
0
            u"librdf_Repository::createBlankNode: "
943
0
            "librdf_node_get_blank_identifier failed"_ustr, *this);
944
0
    }
945
0
    const OUString nodeID(OUString::createFromAscii(
946
0
        reinterpret_cast<const char *>(id)));
947
0
    try {
948
0
        return rdf::BlankNode::create(m_xContext, nodeID);
949
0
    } catch (const lang::IllegalArgumentException &) {
950
0
        css::uno::Any anyEx = cppu::getCaughtException();
951
0
        throw lang::WrappedTargetRuntimeException(
952
0
                u"librdf_Repository::createBlankNode: "
953
0
                "illegal blank node label"_ustr, *this, anyEx);
954
0
    }
955
0
}
956
957
//void SAL_CALL
958
uno::Reference<rdf::XNamedGraph> SAL_CALL
959
librdf_Repository::importGraph(::sal_Int16 i_Format,
960
    const uno::Reference< io::XInputStream > & i_xInStream,
961
    const uno::Reference< rdf::XURI > & i_xGraphName,
962
    const uno::Reference< rdf::XURI > & i_xBaseURI)
963
0
{
964
0
    if (!i_xInStream.is()) {
965
0
        throw lang::IllegalArgumentException(
966
0
            u"librdf_Repository::importGraph: stream is null"_ustr, *this, 1);
967
0
    }
968
    //FIXME: other formats
969
0
    if (i_Format != rdf::FileFormat::RDF_XML) {
970
0
        throw datatransfer::UnsupportedFlavorException(
971
0
                u"librdf_Repository::importGraph: file format not supported"_ustr, *this);
972
0
    }
973
0
    if (!i_xGraphName.is()) {
974
0
        throw lang::IllegalArgumentException(
975
0
                u"librdf_Repository::importGraph: graph name is null"_ustr, *this, 2);
976
0
    }
977
0
    if (i_xGraphName->getStringValue().startsWith(s_nsOOo))
978
0
    {
979
0
        throw lang::IllegalArgumentException(
980
0
                u"librdf_Repository::importGraph: URI is reserved"_ustr, *this, 0);
981
0
    }
982
0
    if (!i_xBaseURI.is()) { //FIXME: any i_Format that don't need a base URI?
983
0
        throw lang::IllegalArgumentException(
984
0
                u"librdf_Repository::importGraph: base URI is null"_ustr, *this, 3);
985
0
    }
986
0
    OSL_ENSURE(i_xBaseURI.is(), "no base uri");
987
0
    const OUString baseURIU( i_xBaseURI->getStringValue() );
988
0
    if (baseURIU.indexOf('#') >= 0) {
989
0
        throw lang::IllegalArgumentException(
990
0
                u"librdf_Repository::importGraph: base URI is not absolute"_ustr, *this, 3);
991
0
    }
992
993
0
    const OUString contextU( i_xGraphName->getStringValue() );
994
995
0
    uno::Sequence<sal_Int8> buf;
996
0
    uno::Reference<io::XSeekable> xSeekable(i_xInStream, uno::UNO_QUERY);
997
    // UGLY: if only redland could read streams...
998
0
    const sal_Int64 sz( xSeekable.is() ? xSeekable->getLength() : 1 << 20 );
999
    // exceptions are propagated
1000
0
    i_xInStream->readBytes( buf, static_cast<sal_Int32>( sz ) );
1001
1002
0
    if (buf.getLength() == 0) {
1003
0
        throw rdf::ParseException(
1004
0
            u"librdf_Repository::importGraph: stream is empty"_ustr, *this);
1005
0
    }
1006
1007
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1008
1009
0
    if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) {
1010
0
        throw container::ElementExistException(
1011
0
                u"librdf_Repository::importGraph: graph with given URI exists"_ustr, *this);
1012
0
    }
1013
0
    const OString context(
1014
0
        OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
1015
1016
0
    const std::shared_ptr<librdf_node> pContext(
1017
0
        librdf_new_node_from_uri_string(m_pWorld.get(),
1018
0
            reinterpret_cast<const unsigned char*> (context.getStr())),
1019
0
        safe_librdf_free_node);
1020
0
    if (!pContext) {
1021
0
        throw uno::RuntimeException(
1022
0
            u"librdf_Repository::importGraph: librdf_new_node_from_uri_string failed"_ustr, *this);
1023
0
    }
1024
1025
0
    const OString baseURI(
1026
0
        OUStringToOString(baseURIU, RTL_TEXTENCODING_UTF8) );
1027
0
    const std::shared_ptr<librdf_uri> pBaseURI(
1028
0
        librdf_new_uri(m_pWorld.get(),
1029
0
            reinterpret_cast<const unsigned char*> (baseURI.getStr())),
1030
0
        safe_librdf_free_uri);
1031
0
    if (!pBaseURI) {
1032
0
        throw uno::RuntimeException( u"librdf_Repository::importGraph: librdf_new_uri failed"_ustr, *this);
1033
0
    }
1034
1035
0
    const std::shared_ptr<librdf_parser> pParser(
1036
0
        librdf_new_parser(m_pWorld.get(), "rdfxml", nullptr, nullptr),
1037
0
        safe_librdf_free_parser);
1038
0
    if (!pParser) {
1039
0
        throw uno::RuntimeException(
1040
0
                u"librdf_Repository::importGraph: "
1041
0
                "librdf_new_parser failed"_ustr, *this);
1042
0
    }
1043
1044
0
    const std::shared_ptr<librdf_stream> pStream(
1045
0
        librdf_parser_parse_counted_string_as_stream(pParser.get(),
1046
0
            reinterpret_cast<const unsigned char*>(buf.getConstArray()),
1047
0
            buf.getLength(), pBaseURI.get()),
1048
0
        safe_librdf_free_stream);
1049
0
    if (!pStream) {
1050
0
        throw rdf::ParseException(
1051
0
            u"librdf_Repository::importGraph: "
1052
0
            "librdf_parser_parse_counted_string_as_stream failed"_ustr, *this);
1053
0
    }
1054
0
    rtl::Reference<librdf_NamedGraph> const pGraph(
1055
0
        new librdf_NamedGraph(this, i_xGraphName));
1056
0
    m_NamedGraphs.insert(std::make_pair(contextU, pGraph));
1057
0
    if (librdf_model_context_add_statements(m_pModel.get(),
1058
0
            pContext.get(), pStream.get())) {
1059
0
        throw rdf::RepositoryException(
1060
0
            u"librdf_Repository::importGraph: "
1061
0
            "librdf_model_context_add_statements failed"_ustr, *this);
1062
0
    }
1063
1064
0
    return pGraph;
1065
0
}
1066
1067
void addChaffWhenEncryptedStorage(const uno::Reference< io::XOutputStream > &rStream, unsigned char* pBuffer, size_t length)
1068
0
{
1069
0
    if (!length)
1070
0
        return;
1071
1072
0
    uno::Reference< embed::XEncryptionProtectedSource2 > xEncr(rStream,
1073
0
        uno::UNO_QUERY);
1074
1075
0
    bool bAddChaff = xEncr.is() && xEncr->hasEncryptionData();
1076
1077
    // exceptions are propagated
1078
0
    if (!bAddChaff)
1079
0
    {
1080
0
        const uno::Sequence<sal_Int8> buf(
1081
0
            reinterpret_cast<sal_Int8*>(pBuffer), length);
1082
0
        rStream->writeBytes(buf);
1083
0
    }
1084
0
    else
1085
0
    {
1086
0
        unsigned char *postcomment =
1087
0
            reinterpret_cast<unsigned char*>(strchr(reinterpret_cast<char*>(pBuffer), '\n'));
1088
0
        if (postcomment != nullptr)
1089
0
        {
1090
0
            ++postcomment;
1091
1092
0
            size_t preamblelen = postcomment - pBuffer;
1093
1094
0
            uno::Sequence<sal_Int8> buf(
1095
0
                reinterpret_cast<sal_Int8*>(pBuffer), preamblelen);
1096
0
            rStream->writeBytes(buf);
1097
1098
0
            OString aComment =
1099
0
                "<!--" +
1100
0
                comphelper::xml::makeXMLChaff() +
1101
0
                "-->";
1102
1103
0
            buf = uno::Sequence<sal_Int8>(
1104
0
                reinterpret_cast<const sal_Int8*>(aComment.getStr()), aComment.getLength());
1105
0
            rStream->writeBytes(buf);
1106
1107
0
            buf = uno::Sequence<sal_Int8>(
1108
0
                reinterpret_cast<sal_Int8*>(postcomment), length-preamblelen);
1109
0
            rStream->writeBytes(buf);
1110
0
        }
1111
0
    }
1112
0
}
1113
1114
void SAL_CALL
1115
librdf_Repository::exportGraph(::sal_Int16 i_Format,
1116
    const uno::Reference< io::XOutputStream > & i_xOutStream,
1117
    const uno::Reference< rdf::XURI > & i_xGraphName,
1118
    const uno::Reference< rdf::XURI > & i_xBaseURI)
1119
0
{
1120
0
    if (!i_xOutStream.is()) {
1121
0
        throw lang::IllegalArgumentException(
1122
0
                u"librdf_Repository::exportGraph: stream is null"_ustr, *this, 1);
1123
0
    }
1124
    // FIXME: other formats
1125
0
    if (i_Format != rdf::FileFormat::RDF_XML) {
1126
0
        throw datatransfer::UnsupportedFlavorException(
1127
0
                u"librdf_Repository::exportGraph: "
1128
0
                "file format not supported"_ustr, *this);
1129
0
    }
1130
0
    if (!i_xGraphName.is()) {
1131
0
        throw lang::IllegalArgumentException(
1132
0
                u"librdf_Repository::exportGraph: "
1133
0
                "graph name is null"_ustr, *this, 2);
1134
0
    }
1135
0
    if (!i_xBaseURI.is()) { //FIXME: any i_Format that don't need a base URI?
1136
0
        throw lang::IllegalArgumentException(
1137
0
                u"librdf_Repository::exportGraph: "
1138
0
                "base URI is null"_ustr, *this, 3);
1139
0
    }
1140
0
    OSL_ENSURE(i_xBaseURI.is(), "no base uri");
1141
0
    const OUString baseURIU( i_xBaseURI->getStringValue() );
1142
0
    if (baseURIU.indexOf('#') >= 0) {
1143
0
        throw lang::IllegalArgumentException(
1144
0
                u"librdf_Repository::exportGraph: "
1145
0
                "base URI is not absolute"_ustr, *this, 3);
1146
0
    }
1147
1148
0
    const OUString contextU( i_xGraphName->getStringValue() );
1149
1150
0
    std::unique_lock g(m_aMutex); // don't call i_x* with mutex locked
1151
1152
0
    if (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) {
1153
0
        throw container::NoSuchElementException(
1154
0
                u"librdf_Repository::exportGraph: "
1155
0
                "no graph with given URI exists"_ustr, *this);
1156
0
    }
1157
0
    const OString context(
1158
0
        OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
1159
1160
0
    const std::shared_ptr<librdf_node> pContext(
1161
0
        librdf_new_node_from_uri_string(m_pWorld.get(),
1162
0
            reinterpret_cast<const unsigned char*> (context.getStr())),
1163
0
        safe_librdf_free_node);
1164
0
    if (!pContext) {
1165
0
        throw uno::RuntimeException(
1166
0
            u"librdf_Repository::exportGraph: "
1167
0
            "librdf_new_node_from_uri_string failed"_ustr, *this);
1168
0
    }
1169
0
    const OString baseURI(
1170
0
        OUStringToOString(baseURIU, RTL_TEXTENCODING_UTF8) );
1171
0
    const std::shared_ptr<librdf_uri> pBaseURI(
1172
0
        librdf_new_uri(m_pWorld.get(),
1173
0
            reinterpret_cast<const unsigned char*> (baseURI.getStr())),
1174
0
        safe_librdf_free_uri);
1175
0
    if (!pBaseURI) {
1176
0
        throw uno::RuntimeException(
1177
0
            u"librdf_Repository::exportGraph: "
1178
0
            "librdf_new_uri failed"_ustr, *this);
1179
0
    }
1180
1181
0
    const std::shared_ptr<librdf_stream> pStream(
1182
0
        librdf_model_context_as_stream(m_pModel.get(), pContext.get()),
1183
0
        safe_librdf_free_stream);
1184
0
    if (!pStream) {
1185
0
        throw rdf::RepositoryException(
1186
0
            u"librdf_Repository::exportGraph: "
1187
0
            "librdf_model_context_as_stream failed"_ustr, *this);
1188
0
    }
1189
0
    const char * const format("rdfxml");
1190
    // #i116443#: abbrev breaks when certain URIs are used as data types
1191
//    const char *format("rdfxml-abbrev");
1192
0
    const std::shared_ptr<librdf_serializer> pSerializer(
1193
0
        librdf_new_serializer(m_pWorld.get(), format, nullptr, nullptr),
1194
0
        safe_librdf_free_serializer);
1195
0
    if (!pSerializer) {
1196
0
        throw uno::RuntimeException(
1197
0
            u"librdf_Repository::exportGraph: "
1198
0
            "librdf_new_serializer failed"_ustr, *this);
1199
0
    }
1200
1201
0
    const std::shared_ptr<librdf_uri> pRelativeURI(
1202
0
        librdf_new_uri(m_pWorld.get(), reinterpret_cast<const unsigned char*>
1203
0
                ("http://feature.librdf.org/raptor-relativeURIs")),
1204
0
                 safe_librdf_free_uri);
1205
0
    const std::shared_ptr<librdf_uri> pWriteBaseURI(
1206
0
        librdf_new_uri(m_pWorld.get(), reinterpret_cast<const unsigned char*>
1207
0
            ("http://feature.librdf.org/raptor-writeBaseURI")),
1208
0
             safe_librdf_free_uri);
1209
0
    const std::shared_ptr<librdf_node> p0(
1210
0
        librdf_new_node_from_literal(m_pWorld.get(),
1211
0
            reinterpret_cast<const unsigned char*> ("0"), nullptr, 0),
1212
0
        safe_librdf_free_node);
1213
0
    const std::shared_ptr<librdf_node> p1(
1214
0
        librdf_new_node_from_literal(m_pWorld.get(),
1215
0
            reinterpret_cast<const unsigned char*> ("1"), nullptr, 0),
1216
0
        safe_librdf_free_node);
1217
0
    if (!pWriteBaseURI || !pRelativeURI || !p0 || !p1) {
1218
0
        throw uno::RuntimeException(
1219
0
            u"librdf_Repository::exportGraph: "
1220
0
            "librdf_new_uri or librdf_new_node_from_literal failed"_ustr, *this);
1221
0
    }
1222
1223
    // make URIs relative to base URI
1224
0
    if (librdf_serializer_set_feature(pSerializer.get(),
1225
0
        pRelativeURI.get(), p1.get()))
1226
0
    {
1227
0
        throw uno::RuntimeException(
1228
0
            u"librdf_Repository::exportGraph: "
1229
0
            "librdf_serializer_set_feature relativeURIs failed"_ustr, *this);
1230
0
    }
1231
    // but do not write the base URI to the file!
1232
0
    if (librdf_serializer_set_feature(pSerializer.get(),
1233
0
        pWriteBaseURI.get(), p0.get()))
1234
0
    {
1235
0
        throw uno::RuntimeException(
1236
0
            u"librdf_Repository::exportGraph: "
1237
0
            "librdf_serializer_set_feature writeBaseURI failed"_ustr, *this);
1238
0
    }
1239
1240
0
    size_t length;
1241
0
    const std::shared_ptr<unsigned char> pBuf(
1242
0
        librdf_serializer_serialize_stream_to_counted_string(
1243
0
            pSerializer.get(), pBaseURI.get(), pStream.get(), &length), free);
1244
0
    if (!pBuf) {
1245
0
        throw rdf::RepositoryException(
1246
0
            u"librdf_Repository::exportGraph: "
1247
0
            "librdf_serializer_serialize_stream_to_counted_string failed"_ustr,
1248
0
            *this);
1249
0
    }
1250
1251
0
    g.unlock(); // release Mutex before calling i_xOutStream methods
1252
1253
0
    addChaffWhenEncryptedStorage(i_xOutStream, pBuf.get(), length);
1254
0
}
1255
1256
uno::Sequence< uno::Reference< rdf::XURI > > SAL_CALL
1257
librdf_Repository::getGraphNames()
1258
0
{
1259
0
    std::scoped_lock g(m_aMutex);
1260
0
    ::std::vector< uno::Reference<rdf::XURI> > ret;
1261
0
    std::transform(m_NamedGraphs.begin(), m_NamedGraphs.end(),
1262
0
        std::back_inserter(ret),
1263
0
        [](std::pair<OUString, ::rtl::Reference<librdf_NamedGraph>> const& it)
1264
0
            { return it.second->getName(); });
1265
0
    return comphelper::containerToSequence(ret);
1266
0
}
1267
1268
uno::Reference< rdf::XNamedGraph > SAL_CALL
1269
librdf_Repository::getGraph(const uno::Reference< rdf::XURI > & i_xGraphName)
1270
6.73k
{
1271
6.73k
    if (!i_xGraphName.is()) {
1272
0
        throw lang::IllegalArgumentException(
1273
0
                u"librdf_Repository::getGraph: URI is null"_ustr, *this, 0);
1274
0
    }
1275
6.73k
    const OUString contextU( i_xGraphName->getStringValue() );
1276
1277
6.73k
    std::scoped_lock g(m_aMutex);
1278
6.73k
    const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(contextU) );
1279
6.73k
    if (iter != m_NamedGraphs.end()) {
1280
0
        return iter->second;
1281
6.73k
    } else {
1282
6.73k
        return nullptr;
1283
6.73k
    }
1284
6.73k
}
1285
1286
uno::Reference< rdf::XNamedGraph > SAL_CALL
1287
librdf_Repository::createGraph(const uno::Reference< rdf::XURI > & i_xGraphName)
1288
6.73k
{
1289
6.73k
    if (!i_xGraphName.is()) {
1290
0
        throw lang::IllegalArgumentException(
1291
0
                u"librdf_Repository::createGraph: URI is null"_ustr, *this, 0);
1292
0
    }
1293
1294
6.73k
    const OUString contextU( i_xGraphName->getStringValue() );
1295
6.73k
    if (contextU.startsWith(s_nsOOo))
1296
0
    {
1297
0
        throw lang::IllegalArgumentException(
1298
0
                u"librdf_Repository::createGraph: URI is reserved"_ustr, *this, 0);
1299
0
    }
1300
1301
6.73k
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1302
1303
    // NB: librdf does not have a concept of graphs as such;
1304
    //     a librdf named graph exists iff the model contains a statement with
1305
    //     the graph name as context
1306
1307
6.73k
    if (m_NamedGraphs.find(contextU) != m_NamedGraphs.end()) {
1308
0
        throw container::ElementExistException(
1309
0
                u"librdf_Repository::createGraph: graph with given URI exists"_ustr, *this);
1310
0
    }
1311
6.73k
    m_NamedGraphs.insert(std::make_pair(contextU,
1312
6.73k
        new librdf_NamedGraph(this, i_xGraphName)));
1313
6.73k
    return m_NamedGraphs.find(contextU)->second;
1314
6.73k
}
1315
1316
void SAL_CALL
1317
librdf_Repository::destroyGraph(
1318
        const uno::Reference< rdf::XURI > & i_xGraphName)
1319
0
{
1320
0
    if (!i_xGraphName.is()) {
1321
0
        throw lang::IllegalArgumentException(
1322
0
                u"librdf_Repository::destroyGraph: URI is null"_ustr, *this, 0);
1323
0
    }
1324
0
    const OUString contextU( i_xGraphName->getStringValue() );
1325
1326
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1327
1328
0
    const NamedGraphMap_t::iterator iter( clearGraph_Lock(contextU, false) );
1329
0
    m_NamedGraphs.erase(iter);
1330
0
}
1331
1332
bool isMetadatableWithoutMetadata(
1333
    uno::Reference<uno::XInterface> const & i_xNode)
1334
20.2k
{
1335
20.2k
    const uno::Reference<rdf::XMetadatable> xMeta( i_xNode, uno::UNO_QUERY );
1336
20.2k
    return (xMeta.is() && xMeta->getMetadataReference().Second.isEmpty());
1337
20.2k
}
1338
1339
uno::Reference< container::XEnumeration > SAL_CALL
1340
librdf_Repository::getStatements(
1341
    const uno::Reference< rdf::XResource > & i_xSubject,
1342
    const uno::Reference< rdf::XURI > & i_xPredicate,
1343
    const uno::Reference< rdf::XNode > & i_xObject)
1344
24
{
1345
24
    if (isMetadatableWithoutMetadata(i_xSubject)   ||
1346
0
        isMetadatableWithoutMetadata(i_xPredicate) ||
1347
0
        isMetadatableWithoutMetadata(i_xObject))
1348
24
    {
1349
24
        return new librdf_GraphResult(this, m_aMutex,
1350
24
            std::shared_ptr<librdf_stream>(),
1351
24
            std::shared_ptr<librdf_node>());
1352
24
    }
1353
1354
0
    librdf_TypeConverter::Statement const stmt(
1355
0
        librdf_TypeConverter::extractStatement_NoLock(
1356
0
            i_xSubject, i_xPredicate, i_xObject));
1357
1358
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1359
1360
0
    const std::shared_ptr<librdf_statement> pStatement(
1361
0
        librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
1362
0
        safe_librdf_free_statement);
1363
0
    OSL_ENSURE(pStatement, "mkStatement failed");
1364
1365
0
    std::shared_ptr<librdf_stream> pStream(
1366
0
        librdf_model_find_statements(m_pModel.get(), pStatement.get()),
1367
0
        safe_librdf_free_stream);
1368
0
    if (!pStream) {
1369
0
        throw rdf::RepositoryException(
1370
0
            u"librdf_Repository::getStatements: "
1371
0
            "librdf_model_find_statements failed"_ustr, *this);
1372
0
    }
1373
1374
0
    return new librdf_GraphResult(this, m_aMutex, std::move(pStream),
1375
0
        std::shared_ptr<librdf_node>());
1376
0
}
1377
1378
1379
uno::Reference< rdf::XQuerySelectResult > SAL_CALL
1380
librdf_Repository::querySelect(const OUString & i_rQuery)
1381
0
{
1382
0
    std::scoped_lock g(m_aMutex);
1383
0
    const OString query(
1384
0
        OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
1385
0
    std::shared_ptr<librdf_query> pQuery(
1386
0
        librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
1387
0
            reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
1388
0
        safe_librdf_free_query);
1389
0
    if (!pQuery) {
1390
0
        throw rdf::QueryException(
1391
0
            u"librdf_Repository::querySelect: "
1392
0
            "librdf_new_query failed"_ustr, *this);
1393
0
    }
1394
0
    std::shared_ptr<librdf_query_results> pResults(
1395
0
        librdf_model_query_execute(m_pModel.get(), pQuery.get()),
1396
0
        safe_librdf_free_query_results);
1397
0
    if (!pResults || !librdf_query_results_is_bindings(pResults.get())) {
1398
0
        throw rdf::QueryException(
1399
0
            u"librdf_Repository::querySelect: "
1400
0
            "query result is null or not bindings"_ustr, *this);
1401
0
    }
1402
1403
0
    const int count( librdf_query_results_get_bindings_count(pResults.get()) );
1404
0
    if (count < 0) {
1405
0
        throw rdf::QueryException(
1406
0
            u"librdf_Repository::querySelect: "
1407
0
            "librdf_query_results_get_bindings_count failed"_ustr, *this);
1408
0
    }
1409
0
    uno::Sequence< OUString > names(count);
1410
0
    auto namesRange = asNonConstRange(names);
1411
0
    for (int i = 0; i < count; ++i) {
1412
0
        const char* name( librdf_query_results_get_binding_name(
1413
0
            pResults.get(), i) );
1414
0
        if (!name) {
1415
0
            throw rdf::QueryException(
1416
0
                u"librdf_Repository::querySelect: binding is null"_ustr, *this);
1417
0
        }
1418
1419
0
        namesRange[i] = OUString::createFromAscii(name);
1420
0
    }
1421
1422
0
    return new librdf_QuerySelectResult(this, m_aMutex,
1423
0
        std::move(pQuery), std::move(pResults), names);
1424
0
}
1425
1426
uno::Reference< container::XEnumeration > SAL_CALL
1427
librdf_Repository::queryConstruct(const OUString & i_rQuery)
1428
0
{
1429
0
    std::scoped_lock g(m_aMutex);
1430
0
    const OString query(
1431
0
        OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
1432
0
    std::shared_ptr<librdf_query> pQuery(
1433
0
        librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
1434
0
            reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
1435
0
        safe_librdf_free_query);
1436
0
    if (!pQuery) {
1437
0
        throw rdf::QueryException(
1438
0
            u"librdf_Repository::queryConstruct: "
1439
0
            "librdf_new_query failed"_ustr, *this);
1440
0
    }
1441
0
    const std::shared_ptr<librdf_query_results> pResults(
1442
0
        librdf_model_query_execute(m_pModel.get(), pQuery.get()),
1443
0
        safe_librdf_free_query_results);
1444
0
    if (!pResults || !librdf_query_results_is_graph(pResults.get())) {
1445
0
        throw rdf::QueryException(
1446
0
            u"librdf_Repository::queryConstruct: "
1447
0
            "query result is null or not graph"_ustr, *this);
1448
0
    }
1449
0
    std::shared_ptr<librdf_stream> pStream(
1450
0
        librdf_query_results_as_stream(pResults.get()),
1451
0
        safe_librdf_free_stream);
1452
0
    if (!pStream) {
1453
0
        throw rdf::QueryException(
1454
0
            u"librdf_Repository::queryConstruct: "
1455
0
            "librdf_query_results_as_stream failed"_ustr, *this);
1456
0
    }
1457
1458
0
    return new librdf_GraphResult(this, m_aMutex, std::move(pStream),
1459
0
                                  std::shared_ptr<librdf_node>(),
1460
0
                                  std::move(pQuery));
1461
0
}
1462
1463
sal_Bool SAL_CALL
1464
librdf_Repository::queryAsk(const OUString & i_rQuery)
1465
0
{
1466
0
    std::scoped_lock g(m_aMutex);
1467
1468
0
    const OString query(
1469
0
        OUStringToOString(i_rQuery, RTL_TEXTENCODING_UTF8) );
1470
0
    const std::shared_ptr<librdf_query> pQuery(
1471
0
        librdf_new_query(m_pWorld.get(), s_sparql, nullptr,
1472
0
            reinterpret_cast<const unsigned char*> (query.getStr()), nullptr),
1473
0
        safe_librdf_free_query);
1474
0
    if (!pQuery) {
1475
0
        throw rdf::QueryException(
1476
0
            u"librdf_Repository::queryAsk: "
1477
0
            "librdf_new_query failed"_ustr, *this);
1478
0
    }
1479
0
    const std::shared_ptr<librdf_query_results> pResults(
1480
0
        librdf_model_query_execute(m_pModel.get(), pQuery.get()),
1481
0
        safe_librdf_free_query_results);
1482
0
    if (!pResults || !librdf_query_results_is_boolean(pResults.get())) {
1483
0
        throw rdf::QueryException(
1484
0
            u"librdf_Repository::queryAsk: "
1485
0
            "query result is null or not boolean"_ustr, *this);
1486
0
    }
1487
0
    return bool(librdf_query_results_get_boolean(pResults.get()));
1488
0
}
1489
1490
// css::rdf::XDocumentRepository:
1491
void SAL_CALL librdf_Repository::setStatementRDFa(
1492
    const uno::Reference< rdf::XResource > & i_xSubject,
1493
    const uno::Sequence< uno::Reference< rdf::XURI > > & i_rPredicates,
1494
    const uno::Reference< rdf::XMetadatable > & i_xObject,
1495
    const OUString & i_rRDFaContent,
1496
    const uno::Reference< rdf::XURI > & i_xRDFaDatatype)
1497
0
{
1498
0
    if (!i_xSubject.is()) {
1499
0
        throw lang::IllegalArgumentException(
1500
0
            u"librdf_Repository::setStatementRDFa: Subject is null"_ustr, *this, 0);
1501
0
    }
1502
0
    if (!i_rPredicates.hasElements()) {
1503
0
        throw lang::IllegalArgumentException(
1504
0
            u"librdf_Repository::setStatementRDFa: no Predicates"_ustr,
1505
0
            *this, 1);
1506
0
    }
1507
0
    if (std::any_of(i_rPredicates.begin(), i_rPredicates.end(),
1508
0
            [](const uno::Reference< rdf::XURI >& rPredicate) { return !rPredicate.is(); })) {
1509
0
        throw lang::IllegalArgumentException(
1510
0
            u"librdf_Repository::setStatementRDFa: Predicate is null"_ustr, *this, 1);
1511
0
    }
1512
0
    if (!i_xObject.is()) {
1513
0
        throw lang::IllegalArgumentException(
1514
0
            u"librdf_Repository::setStatementRDFa: Object is null"_ustr, *this, 2);
1515
0
    }
1516
0
    const uno::Reference<lang::XServiceInfo> xService(i_xObject,
1517
0
        uno::UNO_QUERY_THROW);
1518
0
    uno::Reference<text::XTextRange> xTextRange;
1519
0
    if (xService->supportsService(u"com.sun.star.table.Cell"_ustr) ||
1520
0
        xService->supportsService(u"com.sun.star.text.CellProperties"_ustr) || // for writer
1521
0
        xService->supportsService(u"com.sun.star.text.Paragraph"_ustr))
1522
0
    {
1523
0
        xTextRange.set(i_xObject, uno::UNO_QUERY_THROW);
1524
0
    }
1525
0
    else if (xService->supportsService(u"com.sun.star.text.Bookmark"_ustr) ||
1526
0
             xService->supportsService(u"com.sun.star.text.InContentMetadata"_ustr))
1527
0
    {
1528
0
        const uno::Reference<text::XTextContent> xTextContent(i_xObject,
1529
0
            uno::UNO_QUERY_THROW);
1530
0
        xTextRange = xTextContent->getAnchor();
1531
0
    }
1532
0
    if (!xTextRange.is()) {
1533
0
        throw lang::IllegalArgumentException(
1534
0
            u"librdf_Repository::setStatementRDFa: "
1535
0
            "Object does not support RDFa"_ustr, *this, 2);
1536
0
    }
1537
    // ensure that the metadatable has an XML ID
1538
0
    i_xObject->ensureMetadataReference();
1539
0
    const beans::StringPair mdref( i_xObject->getMetadataReference() );
1540
0
    if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
1541
0
        throw uno::RuntimeException(
1542
0
                u"librdf_Repository::setStatementRDFa: "
1543
0
                "ensureMetadataReference did not"_ustr, *this);
1544
0
    }
1545
0
    OUString const sXmlId(mdref.First + "#" + mdref.Second);
1546
0
    OUString const sContext(s_nsOOo + sXmlId);
1547
0
    OUString const content( (i_rRDFaContent.isEmpty())
1548
0
            ? xTextRange->getString()
1549
0
            : i_rRDFaContent );
1550
0
    uno::Reference<rdf::XNode> xContent;
1551
0
    try {
1552
0
        if (i_xRDFaDatatype.is()) {
1553
0
            xContent.set(rdf::Literal::createWithType(m_xContext,
1554
0
                    content, i_xRDFaDatatype),
1555
0
                uno::UNO_QUERY_THROW);
1556
0
        } else {
1557
0
            xContent.set(rdf::Literal::create(m_xContext, content),
1558
0
                uno::UNO_QUERY_THROW);
1559
0
        }
1560
0
    } catch (const lang::IllegalArgumentException &) {
1561
0
        css::uno::Any anyEx = cppu::getCaughtException();
1562
0
        throw lang::WrappedTargetRuntimeException(
1563
0
                u"librdf_Repository::setStatementRDFa: "
1564
0
                "cannot create literal"_ustr, *this, anyEx);
1565
0
    }
1566
1567
0
    std::shared_ptr<librdf_TypeConverter::Resource> const pSubject(
1568
0
        librdf_TypeConverter::extractResource_NoLock(i_xSubject));
1569
0
    std::shared_ptr<librdf_TypeConverter::Node> const pContent(
1570
0
        librdf_TypeConverter::extractNode_NoLock(xContent));
1571
0
    ::std::vector< std::shared_ptr<librdf_TypeConverter::Resource> >
1572
0
        predicates;
1573
0
    ::std::transform(i_rPredicates.begin(), i_rPredicates.end(),
1574
0
        ::std::back_inserter(predicates),
1575
0
        [](uno::Reference<rdf::XURI> const& xURI)
1576
0
            { return librdf_TypeConverter::extractResource_NoLock(xURI); });
1577
1578
0
    removeStatementRDFa(i_xObject); // not atomic with insertion?
1579
1580
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1581
1582
0
    if (i_rRDFaContent.isEmpty()) {
1583
0
        m_RDFaXHTMLContentSet.erase(sXmlId);
1584
0
    } else {
1585
0
        m_RDFaXHTMLContentSet.insert(sXmlId);
1586
0
    }
1587
0
    try
1588
0
    {
1589
0
        for (const auto& rPredicatePtr : predicates)
1590
0
        {
1591
0
            addStatementGraph_Lock(
1592
0
                librdf_TypeConverter::Statement(pSubject,
1593
0
                    std::dynamic_pointer_cast<librdf_TypeConverter::URI>(rPredicatePtr),
1594
0
                    pContent),
1595
0
                sContext, true);
1596
0
        }
1597
0
    }
1598
0
    catch (const container::NoSuchElementException&)
1599
0
    {
1600
0
        css::uno::Any anyEx = cppu::getCaughtException();
1601
0
        throw lang::WrappedTargetRuntimeException(
1602
0
                u"librdf_Repository::setStatementRDFa: "
1603
0
                "cannot addStatementGraph"_ustr, *this, anyEx);
1604
0
    }
1605
0
}
1606
1607
void SAL_CALL librdf_Repository::removeStatementRDFa(
1608
    const uno::Reference< rdf::XMetadatable > & i_xElement)
1609
0
{
1610
0
    if (!i_xElement.is()) {
1611
0
        throw lang::IllegalArgumentException(
1612
0
            u"librdf_Repository::removeStatementRDFa: Element is null"_ustr,
1613
0
            *this, 0);
1614
0
    }
1615
1616
0
    const beans::StringPair mdref( i_xElement->getMetadataReference() );
1617
0
    if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
1618
0
        return; // nothing to do...
1619
0
    }
1620
1621
0
    OUString const sXmlId(s_nsOOo + mdref.First + "#" + mdref.Second);
1622
1623
0
    clearGraph_NoLock(sXmlId, true);
1624
0
}
1625
1626
beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool > SAL_CALL
1627
librdf_Repository::getStatementRDFa(
1628
    const uno::Reference< rdf::XMetadatable > & i_xElement)
1629
0
{
1630
0
    if (!i_xElement.is()) {
1631
0
        throw lang::IllegalArgumentException(
1632
0
            u"librdf_Repository::getStatementRDFa: Element is null"_ustr, *this, 0);
1633
0
    }
1634
0
    const beans::StringPair mdref( i_xElement->getMetadataReference() );
1635
0
    if ((mdref.First.isEmpty()) || (mdref.Second.isEmpty())) {
1636
0
        return beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool >();
1637
0
    }
1638
0
    OUString const sXmlId(mdref.First + "#" + mdref.Second);
1639
0
    uno::Reference<rdf::XURI> xXmlId;
1640
0
    try {
1641
0
        xXmlId.set( rdf::URI::create(m_xContext, s_nsOOo + sXmlId),
1642
0
            uno::UNO_SET_THROW);
1643
0
    } catch (const lang::IllegalArgumentException &) {
1644
0
        css::uno::Any anyEx = cppu::getCaughtException();
1645
0
        throw lang::WrappedTargetRuntimeException(
1646
0
                u"librdf_Repository::getStatementRDFa: "
1647
0
                "cannot create URI for XML ID"_ustr, *this, anyEx);
1648
0
    }
1649
1650
0
    ::std::vector< rdf::Statement > ret;
1651
0
    try
1652
0
    {
1653
0
        ret = getStatementsGraph_NoLock(nullptr, nullptr, nullptr, xXmlId, true);
1654
0
    }
1655
0
    catch (const container::NoSuchElementException&)
1656
0
    {
1657
0
        css::uno::Any anyEx = cppu::getCaughtException();
1658
0
        throw lang::WrappedTargetRuntimeException(
1659
0
                u"librdf_Repository::getStatementRDFa: "
1660
0
                "cannot getStatementsGraph"_ustr, *this, anyEx);
1661
0
    }
1662
1663
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1664
1665
0
    return beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool >(
1666
0
            comphelper::containerToSequence(ret), 0 != m_RDFaXHTMLContentSet.count(sXmlId));
1667
0
}
1668
1669
extern "C"
1670
librdf_statement *rdfa_context_stream_map_handler(
1671
    librdf_stream *i_pStream, void *, librdf_statement *i_pStatement)
1672
0
{
1673
0
    OSL_ENSURE(i_pStream, "rdfa_context_stream_map_handler: stream null");
1674
0
    if (i_pStream) {
1675
0
        librdf_node *pCtxt(
1676
0
#if LIBRDF_VERSION >= 10012
1677
0
            librdf_stream_get_context2(i_pStream) );
1678
#else
1679
            static_cast<librdf_node *>(librdf_stream_get_context(i_pStream)) );
1680
#endif
1681
0
        OSL_ENSURE(pCtxt, "rdfa_context_stream_map_handler: context null");
1682
0
        if (pCtxt && isInternalContext(pCtxt)) {
1683
0
            return i_pStatement;
1684
0
        }
1685
0
    }
1686
0
    return nullptr;
1687
0
};
1688
1689
uno::Reference< container::XEnumeration > SAL_CALL
1690
librdf_Repository::getStatementsRDFa(
1691
    const uno::Reference< rdf::XResource > & i_xSubject,
1692
    const uno::Reference< rdf::XURI > & i_xPredicate,
1693
    const uno::Reference< rdf::XNode > & i_xObject)
1694
0
{
1695
0
    if (isMetadatableWithoutMetadata(i_xSubject)   ||
1696
0
        isMetadatableWithoutMetadata(i_xPredicate) ||
1697
0
        isMetadatableWithoutMetadata(i_xObject))
1698
0
    {
1699
0
        return new librdf_GraphResult(this, m_aMutex,
1700
0
            std::shared_ptr<librdf_stream>(),
1701
0
            std::shared_ptr<librdf_node>());
1702
0
    }
1703
1704
0
    librdf_TypeConverter::Statement const stmt(
1705
0
        librdf_TypeConverter::extractStatement_NoLock(
1706
0
            i_xSubject, i_xPredicate, i_xObject));
1707
1708
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1709
1710
0
    const std::shared_ptr<librdf_statement> pStatement(
1711
0
        librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
1712
0
        safe_librdf_free_statement);
1713
0
    OSL_ENSURE(pStatement, "mkStatement failed");
1714
1715
0
    std::shared_ptr<librdf_stream> pStream(
1716
0
        librdf_model_find_statements(m_pModel.get(), pStatement.get()),
1717
0
        safe_librdf_free_stream);
1718
0
    if (!pStream) {
1719
0
        throw rdf::RepositoryException(
1720
0
            u"librdf_Repository::getStatementsRDFa: "
1721
0
            "librdf_model_find_statements failed"_ustr, *this);
1722
0
    }
1723
1724
0
    if (librdf_stream_add_map(pStream.get(), rdfa_context_stream_map_handler,
1725
0
                nullptr, nullptr)) {
1726
0
        throw rdf::RepositoryException(
1727
0
            u"librdf_Repository::getStatementsRDFa: "
1728
0
            "librdf_stream_add_map failed"_ustr, *this);
1729
0
    }
1730
1731
0
    return new librdf_GraphResult(this, m_aMutex, std::move(pStream),
1732
0
                                  std::shared_ptr<librdf_node>());
1733
0
}
1734
1735
// css::lang::XInitialization:
1736
void SAL_CALL librdf_Repository::initialize(
1737
    const uno::Sequence< css::uno::Any > &)
1738
6.73k
{
1739
6.73k
    std::scoped_lock g(m_aMutex);
1740
1741
//    m_pWorld.reset(m_TypeConverter.createWorld(), safe_librdf_free_world);
1742
6.73k
    m_pStorage.reset(m_TypeConverter.createStorage_Lock(m_pWorld.get()),
1743
6.73k
        safe_librdf_free_storage);
1744
6.73k
    m_pModel.reset(m_TypeConverter.createModel_Lock(
1745
6.73k
        m_pWorld.get(), m_pStorage.get()), safe_librdf_free_model);
1746
6.73k
}
1747
1748
NamedGraphMap_t::iterator librdf_Repository::clearGraph_NoLock(
1749
        OUString const& i_rGraphName, bool i_Internal)
1750
//    throw (uno::RuntimeException, container::NoSuchElementException,
1751
//        rdf::RepositoryException)
1752
0
{
1753
0
    std::scoped_lock g(m_aMutex);
1754
1755
0
    return clearGraph_Lock(i_rGraphName, i_Internal);
1756
0
}
1757
1758
NamedGraphMap_t::iterator librdf_Repository::clearGraph_Lock(
1759
        OUString const& i_rGraphName, bool i_Internal)
1760
0
{
1761
    // internal: must be called with mutex locked!
1762
0
    const NamedGraphMap_t::iterator iter( m_NamedGraphs.find(i_rGraphName) );
1763
0
    if (!i_Internal && iter == m_NamedGraphs.end()) {
1764
0
        throw container::NoSuchElementException(
1765
0
                u"librdf_Repository::clearGraph: "
1766
0
                "no graph with given URI exists"_ustr, *this);
1767
0
    }
1768
0
    const OString context(
1769
0
        OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) );
1770
1771
0
    const std::shared_ptr<librdf_node> pContext(
1772
0
        librdf_new_node_from_uri_string(m_pWorld.get(),
1773
0
            reinterpret_cast<const unsigned char*> (context.getStr())),
1774
0
        safe_librdf_free_node);
1775
0
    if (!pContext) {
1776
0
        throw uno::RuntimeException(
1777
0
            u"librdf_Repository::clearGraph: "
1778
0
            "librdf_new_node_from_uri_string failed"_ustr, *this);
1779
0
    }
1780
0
    if (librdf_model_context_remove_statements(m_pModel.get(), pContext.get()))
1781
0
    {
1782
0
        throw rdf::RepositoryException(
1783
0
            u"librdf_Repository::clearGraph: "
1784
0
            "librdf_model_context_remove_statements failed"_ustr, *this);
1785
0
    }
1786
0
    return iter;
1787
0
}
1788
1789
void librdf_Repository::addStatementGraph_NoLock(
1790
    const uno::Reference< rdf::XResource > & i_xSubject,
1791
    const uno::Reference< rdf::XURI > & i_xPredicate,
1792
    const uno::Reference< rdf::XNode > & i_xObject,
1793
    const uno::Reference< rdf::XURI > & i_xGraphName)
1794
//throw (uno::RuntimeException, lang::IllegalArgumentException,
1795
//    container::NoSuchElementException, rdf::RepositoryException)
1796
6.73k
{
1797
6.73k
    if (!i_xSubject.is()) {
1798
0
        throw lang::IllegalArgumentException(
1799
0
            u"librdf_Repository::addStatement: Subject is null"_ustr, *this, 0);
1800
0
    }
1801
6.73k
    if (!i_xPredicate.is()) {
1802
0
        throw lang::IllegalArgumentException(
1803
0
            u"librdf_Repository::addStatement: Predicate is null"_ustr,
1804
0
            *this, 1);
1805
0
    }
1806
6.73k
    if (!i_xObject.is()) {
1807
0
        throw lang::IllegalArgumentException(
1808
0
            u"librdf_Repository::addStatement: Object is null"_ustr, *this, 2);
1809
0
    }
1810
1811
6.73k
    librdf_TypeConverter::Statement const stmt(
1812
6.73k
        librdf_TypeConverter::extractStatement_NoLock(
1813
6.73k
            i_xSubject, i_xPredicate, i_xObject));
1814
1815
6.73k
    const OUString contextU( i_xGraphName->getStringValue() );
1816
1817
6.73k
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1818
1819
6.73k
    addStatementGraph_Lock(stmt, contextU, false/*i_Internal*/);
1820
6.73k
}
1821
1822
void librdf_Repository::addStatementGraph_Lock(
1823
    librdf_TypeConverter::Statement const& i_rStatement,
1824
    OUString const& i_rGraphName,
1825
    bool i_Internal)
1826
6.73k
{
1827
6.73k
    if (!i_Internal
1828
6.73k
        && (m_NamedGraphs.find(i_rGraphName) == m_NamedGraphs.end()))
1829
0
    {
1830
0
        throw container::NoSuchElementException(
1831
0
                u"librdf_Repository::addStatement: "
1832
0
                "no graph with given URI exists"_ustr, *this);
1833
0
    }
1834
6.73k
    const OString context(
1835
6.73k
        OUStringToOString(i_rGraphName, RTL_TEXTENCODING_UTF8) );
1836
1837
6.73k
    const std::shared_ptr<librdf_node> pContext(
1838
6.73k
        librdf_new_node_from_uri_string(m_pWorld.get(),
1839
6.73k
            reinterpret_cast<const unsigned char*> (context.getStr())),
1840
6.73k
        safe_librdf_free_node);
1841
6.73k
    if (!pContext) {
1842
0
        throw uno::RuntimeException(
1843
0
            u"librdf_Repository::addStatement: "
1844
0
            "librdf_new_node_from_uri_string failed"_ustr, *this);
1845
0
    }
1846
6.73k
    const std::shared_ptr<librdf_statement> pStatement(
1847
6.73k
        librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), i_rStatement),
1848
6.73k
        safe_librdf_free_statement);
1849
6.73k
    OSL_ENSURE(pStatement, "mkStatement failed");
1850
1851
    // Test for duplicate statement
1852
    // librdf_model_add_statement disallows duplicates while
1853
    // librdf_model_context_add_statement allows duplicates
1854
6.73k
    {
1855
6.73k
        const std::shared_ptr<librdf_stream> pStream(
1856
6.73k
            librdf_model_find_statements_in_context(m_pModel.get(),
1857
6.73k
                pStatement.get(), pContext.get()),
1858
6.73k
            safe_librdf_free_stream);
1859
6.73k
        if (pStream && !librdf_stream_end(pStream.get()))
1860
0
            return;
1861
6.73k
    }
1862
1863
6.73k
    if (librdf_model_context_add_statement(m_pModel.get(),
1864
6.73k
            pContext.get(), pStatement.get())) {
1865
0
        throw rdf::RepositoryException(
1866
0
            u"librdf_Repository::addStatement: "
1867
0
            "librdf_model_context_add_statement failed"_ustr, *this);
1868
0
    }
1869
6.73k
}
1870
1871
void librdf_Repository::removeStatementsGraph_NoLock(
1872
    const uno::Reference< rdf::XResource > & i_xSubject,
1873
    const uno::Reference< rdf::XURI > & i_xPredicate,
1874
    const uno::Reference< rdf::XNode > & i_xObject,
1875
    const uno::Reference< rdf::XURI > & i_xGraphName)
1876
//throw (uno::RuntimeException, lang::IllegalArgumentException,
1877
//    container::NoSuchElementException, rdf::RepositoryException)
1878
0
{
1879
0
    if (isMetadatableWithoutMetadata(i_xSubject)   ||
1880
0
        isMetadatableWithoutMetadata(i_xPredicate) ||
1881
0
        isMetadatableWithoutMetadata(i_xObject))
1882
0
    {
1883
0
        return;
1884
0
    }
1885
1886
0
    librdf_TypeConverter::Statement const stmt(
1887
0
        librdf_TypeConverter::extractStatement_NoLock(
1888
0
            i_xSubject, i_xPredicate, i_xObject));
1889
0
    const OUString contextU( i_xGraphName->getStringValue() );
1890
1891
0
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1892
1893
0
    if (m_NamedGraphs.find(contextU) == m_NamedGraphs.end()) {
1894
0
        throw container::NoSuchElementException(
1895
0
                u"librdf_Repository::removeStatements: "
1896
0
                "no graph with given URI exists"_ustr, *this);
1897
0
    }
1898
0
    const OString context(
1899
0
        OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
1900
1901
0
    const std::shared_ptr<librdf_node> pContext(
1902
0
        librdf_new_node_from_uri_string(m_pWorld.get(),
1903
0
            reinterpret_cast<const unsigned char*> (context.getStr())),
1904
0
        safe_librdf_free_node);
1905
0
    if (!pContext) {
1906
0
        throw uno::RuntimeException(
1907
0
            u"librdf_Repository::removeStatements: "
1908
0
            "librdf_new_node_from_uri_string failed"_ustr, *this);
1909
0
    }
1910
0
    const std::shared_ptr<librdf_statement> pStatement(
1911
0
        librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
1912
0
        safe_librdf_free_statement);
1913
0
    OSL_ENSURE(pStatement, "mkStatement failed");
1914
1915
0
    const std::shared_ptr<librdf_stream> pStream(
1916
0
        librdf_model_find_statements_in_context(m_pModel.get(),
1917
0
            pStatement.get(), pContext.get()),
1918
0
        safe_librdf_free_stream);
1919
0
    if (!pStream) {
1920
0
        throw rdf::RepositoryException(
1921
0
            u"librdf_Repository::removeStatements: "
1922
0
            "librdf_model_find_statements_in_context failed"_ustr, *this);
1923
0
    }
1924
1925
0
    if (librdf_stream_end(pStream.get()))
1926
0
        return;
1927
1928
0
    do {
1929
0
        librdf_statement *pStmt( librdf_stream_get_object(pStream.get()) );
1930
0
        if (!pStmt) {
1931
0
            throw rdf::RepositoryException(
1932
0
                u"librdf_Repository::removeStatements: "
1933
0
                "librdf_stream_get_object failed"_ustr, *this);
1934
0
        }
1935
0
        if (librdf_model_context_remove_statement(m_pModel.get(),
1936
0
                pContext.get(), pStmt)) {
1937
0
            throw rdf::RepositoryException(
1938
0
                u"librdf_Repository::removeStatements: "
1939
0
                "librdf_model_context_remove_statement failed"_ustr, *this);
1940
0
        }
1941
0
    } while (!librdf_stream_next(pStream.get()));
1942
0
}
1943
1944
std::vector<rdf::Statement>
1945
librdf_Repository::getStatementsGraph_NoLock(
1946
    const uno::Reference< rdf::XResource > & i_xSubject,
1947
    const uno::Reference< rdf::XURI > & i_xPredicate,
1948
    const uno::Reference< rdf::XNode > & i_xObject,
1949
    const uno::Reference< rdf::XURI > & i_xGraphName,
1950
    bool i_Internal)
1951
//throw (uno::RuntimeException, lang::IllegalArgumentException,
1952
//    container::NoSuchElementException, rdf::RepositoryException)
1953
6.73k
{
1954
6.73k
    std::vector<rdf::Statement> ret;
1955
1956
    // N.B.: if any of subject, predicate, object is an XMetadatable, and
1957
    // has no metadata reference, then there cannot be any node in the graph
1958
    // representing it; in order to prevent side effect
1959
    // (ensureMetadataReference), check for this condition and return
1960
6.73k
    if (isMetadatableWithoutMetadata(i_xSubject)   ||
1961
6.73k
        isMetadatableWithoutMetadata(i_xPredicate) ||
1962
6.73k
        isMetadatableWithoutMetadata(i_xObject))
1963
0
    {
1964
0
        return ret;
1965
0
    }
1966
1967
6.73k
    librdf_TypeConverter::Statement const stmt(
1968
6.73k
        librdf_TypeConverter::extractStatement_NoLock(
1969
6.73k
            i_xSubject, i_xPredicate, i_xObject));
1970
6.73k
    const OUString contextU( i_xGraphName->getStringValue() );
1971
1972
6.73k
    std::scoped_lock g(m_aMutex); // don't call i_x* with mutex locked
1973
1974
6.73k
    if (!i_Internal && (m_NamedGraphs.find(contextU) == m_NamedGraphs.end())) {
1975
0
        throw container::NoSuchElementException(
1976
0
                u"librdf_Repository::getStatements: "
1977
0
                "no graph with given URI exists"_ustr, *this);
1978
0
    }
1979
6.73k
    const OString context(
1980
6.73k
        OUStringToOString(contextU, RTL_TEXTENCODING_UTF8) );
1981
1982
6.73k
    const std::shared_ptr<librdf_node> pContext(
1983
6.73k
        librdf_new_node_from_uri_string(m_pWorld.get(),
1984
6.73k
            reinterpret_cast<const unsigned char*> (context.getStr())),
1985
6.73k
        safe_librdf_free_node);
1986
6.73k
    if (!pContext) {
1987
0
        throw uno::RuntimeException(
1988
0
            u"librdf_Repository::getStatements: "
1989
0
            "librdf_new_node_from_uri_string failed"_ustr, *this);
1990
0
    }
1991
6.73k
    const std::shared_ptr<librdf_statement> pStatement(
1992
6.73k
        librdf_TypeConverter::mkStatement_Lock(m_pWorld.get(), stmt),
1993
6.73k
        safe_librdf_free_statement);
1994
6.73k
    OSL_ENSURE(pStatement, "mkStatement failed");
1995
1996
6.73k
    const std::shared_ptr<librdf_stream> pStream(
1997
6.73k
        librdf_model_find_statements_in_context(m_pModel.get(),
1998
6.73k
            pStatement.get(), pContext.get()),
1999
6.73k
        safe_librdf_free_stream);
2000
6.73k
    if (!pStream) {
2001
0
        throw rdf::RepositoryException(
2002
0
            u"librdf_Repository::getStatements: "
2003
0
            "librdf_model_find_statements_in_context failed"_ustr, *this);
2004
0
    }
2005
2006
6.73k
    librdf_node *pCtxt1(
2007
6.73k
#if LIBRDF_VERSION >= 10012
2008
6.73k
        librdf_stream_get_context2(pStream.get()) );
2009
#else
2010
        static_cast<librdf_node *>(librdf_stream_get_context(pStream.get())) );
2011
#endif
2012
6.73k
    while (!librdf_stream_end(pStream.get()))
2013
0
    {
2014
0
        auto pCtxt = pCtxt1;
2015
0
        librdf_statement *pStmt( librdf_stream_get_object(pStream.get()) );
2016
0
        if (!pStmt) {
2017
0
            rdf::QueryException e(
2018
0
                u"librdf_GraphResult::nextElement: "
2019
0
                "librdf_stream_get_object failed"_ustr, *this);
2020
0
            throw lang::WrappedTargetException(
2021
0
                u"librdf_GraphResult::nextElement: "
2022
0
                "librdf_stream_get_object failed"_ustr, *this,
2023
0
                    uno::Any(e));
2024
0
        }
2025
        // NB: pCtxt may be null here if this is result of a graph query
2026
0
        if (pCtxt && isInternalContext(pCtxt)) {
2027
0
            pCtxt = nullptr; // XML ID context is implementation detail!
2028
0
        }
2029
2030
0
        ret.emplace_back(
2031
0
            getTypeConverter().convertToStatement(pStmt, pCtxt) );
2032
2033
        // NB: this will invalidate current item.
2034
0
        librdf_stream_next(pStream.get());
2035
0
    }
2036
2037
6.73k
    return ret;
2038
6.73k
}
2039
2040
extern "C"
2041
void librdf_raptor_init(void* /*user_data*/, raptor_world* pRaptorWorld)
2042
2
{
2043
    // fdo#64672 prevent raptor from setting global libxml2 error handlers
2044
2
    raptor_world_set_flag(pRaptorWorld,
2045
2
            RAPTOR_WORLD_FLAG_LIBXML_STRUCTURED_ERROR_SAVE, 0);
2046
2
    raptor_world_set_flag(pRaptorWorld,
2047
2
            RAPTOR_WORLD_FLAG_LIBXML_GENERIC_ERROR_SAVE, 0);
2048
2
}
2049
2050
librdf_world *librdf_TypeConverter::createWorld_Lock() const
2051
2
{
2052
    // create and initialize world
2053
2
    librdf_world *pWorld( librdf_new_world() );
2054
2
    if (!pWorld) {
2055
0
        throw uno::RuntimeException(
2056
0
            u"librdf_TypeConverter::createWorld: librdf_new_world failed"_ustr,
2057
0
            m_rRep);
2058
0
    }
2059
2
    librdf_world_set_raptor_init_handler(pWorld, nullptr, &librdf_raptor_init);
2060
    //FIXME logger, digest, features?
2061
2
    xsltSecurityPrefsPtr origprefs = xsltGetDefaultSecurityPrefs();
2062
2
    librdf_world_open(pWorld);
2063
2
    xsltSecurityPrefsPtr newprefs = xsltGetDefaultSecurityPrefs();
2064
2
    if (newprefs != origprefs) {
2065
        // #i110523# restore libxslt global configuration
2066
        // (gratuitously overwritten by raptor_init_parser_grddl_common)
2067
        // (this is the only reason unordf is linked against libxslt)
2068
0
        xsltSetDefaultSecurityPrefs(origprefs);
2069
0
    }
2070
2
    return pWorld;
2071
2
}
2072
2073
librdf_storage *
2074
librdf_TypeConverter::createStorage_Lock(librdf_world *i_pWorld) const
2075
6.73k
{
2076
6.73k
    librdf_storage *pStorage(
2077
//        librdf_new_storage(i_pWorld, "memory", NULL, "contexts='yes'") );
2078
6.73k
        librdf_new_storage(i_pWorld, "hashes", nullptr,
2079
6.73k
            "contexts='yes',hash-type='memory'") );
2080
6.73k
    if (!pStorage) {
2081
0
        throw uno::RuntimeException(
2082
0
            u"librdf_TypeConverter::createStorage: librdf_new_storage failed"_ustr,
2083
0
            m_rRep);
2084
0
    }
2085
6.73k
    return pStorage;
2086
6.73k
}
2087
2088
librdf_model *librdf_TypeConverter::createModel_Lock(
2089
    librdf_world *i_pWorld, librdf_storage * i_pStorage) const
2090
6.73k
{
2091
6.73k
    librdf_model *pRepository( librdf_new_model(i_pWorld, i_pStorage, nullptr) );
2092
6.73k
    if (!pRepository) {
2093
0
        throw uno::RuntimeException(
2094
0
            u"librdf_TypeConverter::createModel: librdf_new_model failed"_ustr,
2095
0
            m_rRep);
2096
0
    }
2097
    //FIXME
2098
#if 0
2099
    {
2100
        librdf_uri * ctxt = librdf_new_uri(i_pWorld, reinterpret_cast<const unsigned char *>(LIBRDF_MODEL_FEATURE_CONTEXTS));
2101
        librdf_node * contexts = librdf_model_get_feature(repository, ctxt);
2102
        if (!contexts)
2103
            throw;
2104
        std::cout << "value of contexts feature: ";
2105
        prtNode(contexts);
2106
        std::cout << std::endl;
2107
        // librdf_model_set_feature(repository, LIBRDF_FEATURE_CONTEXTS, ...);
2108
        safe_librdf_free_node(contexts);
2109
        safe_librdf_free_uri(ctxt);
2110
    }
2111
#endif
2112
6.73k
    return pRepository;
2113
6.73k
}
2114
2115
// this does NOT create a node, only URI
2116
librdf_uri* librdf_TypeConverter::mkURI_Lock( librdf_world* i_pWorld,
2117
    OString const& i_rURI)
2118
0
{
2119
0
    librdf_uri *pURI( librdf_new_uri(i_pWorld,
2120
0
        reinterpret_cast<const unsigned char *>(i_rURI.getStr())));
2121
0
    if (!pURI) {
2122
0
        throw uno::RuntimeException(
2123
0
            u"librdf_TypeConverter::mkURI: librdf_new_uri failed"_ustr, nullptr);
2124
0
    }
2125
0
    return pURI;
2126
0
}
2127
2128
// extract blank or URI node - call without Mutex locked
2129
std::shared_ptr<librdf_TypeConverter::Resource>
2130
librdf_TypeConverter::extractResource_NoLock(
2131
    const uno::Reference< rdf::XResource > & i_xResource)
2132
33.6k
{
2133
33.6k
    if (!i_xResource.is()) {
2134
0
        return std::shared_ptr<Resource>();
2135
0
    }
2136
33.6k
    uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY);
2137
33.6k
    if (xBlankNode.is()) {
2138
0
        const OString label(
2139
0
            OUStringToOString(xBlankNode->getStringValue(),
2140
0
            RTL_TEXTENCODING_UTF8) );
2141
0
        return std::make_shared<BlankNode>(label);
2142
33.6k
    } else { // assumption: everything else is URI
2143
33.6k
        const OString uri(
2144
33.6k
            OUStringToOString(i_xResource->getStringValue(),
2145
33.6k
            RTL_TEXTENCODING_UTF8) );
2146
33.6k
        return std::make_shared<URI>(uri);
2147
33.6k
    }
2148
33.6k
}
2149
2150
void
2151
librdf_TypeConverter::extractResourceToCacheKey_NoLock(
2152
    const uno::Reference< rdf::XResource > & i_xResource, OUStringBuffer& rBuffer)
2153
15.6k
{
2154
15.6k
    if (!i_xResource.is()) {
2155
0
        return;
2156
0
    }
2157
15.6k
    uno::Reference< rdf::XBlankNode > xBlankNode(i_xResource, uno::UNO_QUERY);
2158
15.6k
    if (xBlankNode.is()) {
2159
0
        rBuffer.append("BlankNode " + xBlankNode->getStringValue());
2160
15.6k
    } else { // assumption: everything else is URI
2161
15.6k
        rBuffer.append("URI " + i_xResource->getStringValue());
2162
15.6k
    }
2163
15.6k
}
2164
2165
// create blank or URI node
2166
librdf_node* librdf_TypeConverter::mkResource_Lock( librdf_world* i_pWorld,
2167
    Resource const*const i_pResource)
2168
33.6k
{
2169
33.6k
    if (!i_pResource) return nullptr;
2170
33.6k
    BlankNode const*const pBlankNode(
2171
33.6k
            dynamic_cast<BlankNode const*>(i_pResource));
2172
33.6k
    if (pBlankNode) {
2173
0
        librdf_node *pNode(
2174
0
            librdf_new_node_from_blank_identifier(i_pWorld,
2175
0
                reinterpret_cast<const unsigned char*>(
2176
0
                    pBlankNode->value.getStr())));
2177
0
        if (!pNode) {
2178
0
            throw uno::RuntimeException(
2179
0
                u"librdf_TypeConverter::mkResource: "
2180
0
                "librdf_new_node_from_blank_identifier failed"_ustr, nullptr);
2181
0
        }
2182
0
        return pNode;
2183
33.6k
    } else { // assumption: everything else is URI
2184
33.6k
        URI const*const pURI(dynamic_cast<URI const*>(i_pResource));
2185
33.6k
        assert(pURI);
2186
33.6k
        librdf_node *pNode(
2187
33.6k
            librdf_new_node_from_uri_string(i_pWorld,
2188
33.6k
                reinterpret_cast<const unsigned char*>(pURI->value.getStr())));
2189
33.6k
        if (!pNode) {
2190
0
            throw uno::RuntimeException(
2191
0
                u"librdf_TypeConverter::mkResource: "
2192
0
                "librdf_new_node_from_uri_string failed"_ustr, nullptr);
2193
0
        }
2194
33.6k
        return pNode;
2195
33.6k
    }
2196
33.6k
}
2197
2198
// extract blank or URI or literal node - call without Mutex locked
2199
std::shared_ptr<librdf_TypeConverter::Node>
2200
librdf_TypeConverter::extractNode_NoLock(
2201
    const uno::Reference< rdf::XNode > & i_xNode)
2202
13.4k
{
2203
13.4k
    if (!i_xNode.is()) {
2204
6.73k
        return std::shared_ptr<Node>();
2205
6.73k
    }
2206
6.73k
    uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY);
2207
6.73k
    if (xResource.is()) {
2208
6.73k
        return extractResource_NoLock(xResource);
2209
6.73k
    }
2210
0
    uno::Reference< rdf::XLiteral> xLiteral(i_xNode, uno::UNO_QUERY);
2211
0
    OSL_ENSURE(xLiteral.is(),
2212
0
        "mkNode: someone invented a new rdf.XNode and did not tell me");
2213
0
    if (!xLiteral.is()) {
2214
0
        return std::shared_ptr<Node>();
2215
0
    }
2216
0
    const OString val(
2217
0
        OUStringToOString(xLiteral->getValue(),
2218
0
        RTL_TEXTENCODING_UTF8) );
2219
0
    const OString lang(
2220
0
        OUStringToOString(xLiteral->getLanguage(),
2221
0
        RTL_TEXTENCODING_UTF8) );
2222
0
    const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype());
2223
0
    std::optional<OString> type;
2224
0
    if (xType.is())
2225
0
    {
2226
0
        type =
2227
0
            OUStringToOString(xType->getStringValue(), RTL_TEXTENCODING_UTF8);
2228
0
    }
2229
0
    return std::make_shared<Literal>(val, lang, type);
2230
0
}
2231
2232
// extract blank or URI or literal node - call without Mutex locked
2233
void
2234
librdf_TypeConverter::extractNodeToCacheKey_NoLock(
2235
    const uno::Reference< rdf::XNode > & i_xNode,
2236
    OUStringBuffer& rBuffer)
2237
7.81k
{
2238
7.81k
    if (!i_xNode.is()) {
2239
7.81k
        return;
2240
7.81k
    }
2241
0
    uno::Reference< rdf::XResource > xResource(i_xNode, uno::UNO_QUERY);
2242
0
    if (xResource.is()) {
2243
0
        return extractResourceToCacheKey_NoLock(xResource, rBuffer);
2244
0
    }
2245
0
    uno::Reference< rdf::XLiteral> xLiteral(i_xNode, uno::UNO_QUERY);
2246
0
    OSL_ENSURE(xLiteral.is(),
2247
0
        "mkNode: someone invented a new rdf.XNode and did not tell me");
2248
0
    if (!xLiteral.is()) {
2249
0
        return;
2250
0
    }
2251
0
    rBuffer.append("Literal " + xLiteral->getValue() + "\t" + xLiteral->getLanguage());
2252
0
    const uno::Reference< rdf::XURI > xType(xLiteral->getDatatype());
2253
0
    if (xType.is())
2254
0
        rBuffer.append("\t" + xType->getStringValue());
2255
0
}
2256
2257
// create blank or URI or literal node
2258
librdf_node* librdf_TypeConverter::mkNode_Lock( librdf_world* i_pWorld,
2259
    Node const*const i_pNode)
2260
13.4k
{
2261
13.4k
    if (!i_pNode) return nullptr;
2262
6.73k
    Resource const*const pResource(dynamic_cast<Resource const*>(i_pNode));
2263
6.73k
    if (pResource) {
2264
6.73k
        return mkResource_Lock(i_pWorld, pResource);
2265
6.73k
    }
2266
2267
0
    Literal const*const pLiteral(dynamic_cast<Literal const*>(i_pNode));
2268
0
    assert(pLiteral);
2269
0
    librdf_node * ret(nullptr);
2270
0
    if (pLiteral->language.isEmpty()) {
2271
0
        if (!pLiteral->type) {
2272
0
            ret = librdf_new_node_from_literal(i_pWorld,
2273
0
                reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
2274
0
                , nullptr, 0);
2275
0
        } else {
2276
0
            const std::shared_ptr<librdf_uri> pDatatype(
2277
0
                mkURI_Lock(i_pWorld, *pLiteral->type),
2278
0
                safe_librdf_free_uri);
2279
0
            ret = librdf_new_node_from_typed_literal(i_pWorld,
2280
0
                reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
2281
0
                , nullptr, pDatatype.get());
2282
0
        }
2283
0
    } else {
2284
0
        if (!pLiteral->type) {
2285
0
            ret = librdf_new_node_from_literal(i_pWorld,
2286
0
                reinterpret_cast<const unsigned char*>(pLiteral->value.getStr())
2287
0
                , pLiteral->language.getStr(), 0);
2288
0
        } else {
2289
0
            OSL_FAIL("mkNode: invalid literal");
2290
0
            return nullptr;
2291
0
        }
2292
0
    }
2293
0
    if (!ret) {
2294
0
        throw uno::RuntimeException(
2295
0
            u"librdf_TypeConverter::mkNode: librdf_new_node_from_literal failed"_ustr, nullptr);
2296
0
    }
2297
0
    return ret;
2298
0
}
2299
2300
// extract statement - call without Mutex locked
2301
librdf_TypeConverter::Statement librdf_TypeConverter::extractStatement_NoLock(
2302
    const uno::Reference< rdf::XResource > & i_xSubject,
2303
    const uno::Reference< rdf::XURI > & i_xPredicate,
2304
    const uno::Reference< rdf::XNode > & i_xObject)
2305
13.4k
{
2306
13.4k
    std::shared_ptr<Resource> pSubject(
2307
13.4k
            extractResource_NoLock(i_xSubject));
2308
13.4k
    std::shared_ptr<URI> pPredicate(
2309
13.4k
        std::dynamic_pointer_cast<URI>(extractResource_NoLock(i_xPredicate)));
2310
13.4k
    std::shared_ptr<Node> pObject(extractNode_NoLock(i_xObject));
2311
13.4k
    return Statement(std::move(pSubject), std::move(pPredicate), std::move(pObject));
2312
13.4k
}
2313
2314
librdf_statement* librdf_TypeConverter::mkStatement_Lock(librdf_world* i_pWorld,
2315
    Statement const& i_rStatement)
2316
13.4k
{
2317
13.4k
    librdf_node *const pSubject(
2318
13.4k
            mkResource_Lock(i_pWorld, i_rStatement.pSubject.get()) );
2319
13.4k
    librdf_node* pPredicate(nullptr);
2320
13.4k
    librdf_node* pObject(nullptr);
2321
13.4k
    try {
2322
13.4k
        pPredicate = mkResource_Lock(i_pWorld, i_rStatement.pPredicate.get());
2323
13.4k
        try {
2324
13.4k
            pObject = mkNode_Lock(i_pWorld, i_rStatement.pObject.get());
2325
13.4k
        } catch (...) {
2326
0
            safe_librdf_free_node(pPredicate);
2327
0
            throw;
2328
0
        }
2329
13.4k
    } catch (...) {
2330
0
        safe_librdf_free_node(pSubject);
2331
0
        throw;
2332
0
    }
2333
    // NB: this takes ownership of the nodes! (which is really ugly)
2334
13.4k
    librdf_statement* pStatement( librdf_new_statement_from_nodes(i_pWorld,
2335
13.4k
        pSubject, pPredicate, pObject) );
2336
13.4k
    if (!pStatement) {
2337
0
        throw uno::RuntimeException(
2338
0
            u"librdf_TypeConverter::mkStatement: "
2339
0
            "librdf_new_statement_from_nodes failed"_ustr, nullptr);
2340
0
    }
2341
13.4k
    return pStatement;
2342
13.4k
}
2343
2344
uno::Reference<rdf::XURI>
2345
librdf_TypeConverter::convertToXURI(librdf_uri* i_pURI) const
2346
0
{
2347
0
    if (!i_pURI) return nullptr;
2348
0
    const unsigned char* uri( librdf_uri_as_string(i_pURI) );
2349
0
    if (!uri) {
2350
0
        throw uno::RuntimeException(
2351
0
            u"librdf_TypeConverter::convertToXURI: "
2352
0
            "librdf_uri_as_string failed"_ustr, m_rRep);
2353
0
    }
2354
0
    OUString uriU( OStringToOUString(
2355
0
        std::string_view(reinterpret_cast<const char*>(uri)),
2356
0
        RTL_TEXTENCODING_UTF8) );
2357
0
    try {
2358
0
        return rdf::URI::create(m_xContext, uriU);
2359
0
    } catch (const lang::IllegalArgumentException &) {
2360
0
        css::uno::Any anyEx = cppu::getCaughtException();
2361
0
        throw lang::WrappedTargetRuntimeException(
2362
0
                u"librdf_TypeConverter::convertToXURI: "
2363
0
                "illegal uri"_ustr, m_rRep, anyEx);
2364
0
    }
2365
0
}
2366
2367
uno::Reference<rdf::XURI>
2368
librdf_TypeConverter::convertToXURI(librdf_node* i_pNode) const
2369
0
{
2370
0
    if (!i_pNode) return nullptr;
2371
0
    if (librdf_node_is_resource(i_pNode)) {
2372
0
        librdf_uri* pURI( librdf_node_get_uri(i_pNode) );
2373
0
        if (!pURI) {
2374
0
            throw uno::RuntimeException(
2375
0
                u"librdf_TypeConverter::convertToXURI: "
2376
0
                "resource has no uri"_ustr, m_rRep);
2377
0
        }
2378
0
        return convertToXURI(pURI);
2379
0
    } else {
2380
0
        OSL_FAIL("convertToXURI: unknown librdf_node");
2381
0
        return nullptr;
2382
0
    }
2383
0
}
2384
2385
uno::Reference<rdf::XResource>
2386
librdf_TypeConverter::convertToXResource(librdf_node* i_pNode) const
2387
0
{
2388
0
    if (!i_pNode) return nullptr;
2389
0
    if (librdf_node_is_blank(i_pNode)) {
2390
0
        const unsigned char* label( librdf_node_get_blank_identifier(i_pNode) );
2391
0
        if (!label) {
2392
0
            throw uno::RuntimeException(
2393
0
                u"librdf_TypeConverter::convertToXResource: "
2394
0
                "blank node has no label"_ustr, m_rRep);
2395
0
        }
2396
0
        OUString labelU( OStringToOUString(
2397
0
            std::string_view(reinterpret_cast<const char*>(label)),
2398
0
            RTL_TEXTENCODING_UTF8) );
2399
0
        try {
2400
0
            return rdf::BlankNode::create(m_xContext, labelU);
2401
0
        } catch (const lang::IllegalArgumentException &) {
2402
0
            css::uno::Any anyEx = cppu::getCaughtException();
2403
0
            throw lang::WrappedTargetRuntimeException(
2404
0
                    u"librdf_TypeConverter::convertToXResource: "
2405
0
                    "illegal blank node label"_ustr, m_rRep, anyEx);
2406
0
        }
2407
0
    } else {
2408
0
        return convertToXURI(i_pNode);
2409
0
    }
2410
0
}
2411
2412
uno::Reference<rdf::XNode>
2413
librdf_TypeConverter::convertToXNode(librdf_node* i_pNode) const
2414
0
{
2415
0
    if (!i_pNode) return nullptr;
2416
0
    if (!librdf_node_is_literal(i_pNode)) {
2417
0
        return convertToXResource(i_pNode);
2418
0
    }
2419
0
    const unsigned char* value( librdf_node_get_literal_value(i_pNode) );
2420
0
    if (!value) {
2421
0
        throw uno::RuntimeException(
2422
0
            u"librdf_TypeConverter::convertToXNode: "
2423
0
            "literal has no value"_ustr, m_rRep);
2424
0
    }
2425
0
    const char * lang( librdf_node_get_literal_value_language(i_pNode) );
2426
0
    librdf_uri* pType(
2427
0
        librdf_node_get_literal_value_datatype_uri(i_pNode) );
2428
0
    OSL_ENSURE(!lang || !pType, "convertToXNode: invalid literal");
2429
0
    const OUString valueU( OStringToOUString(
2430
0
        std::string_view(reinterpret_cast<const char*>(value)),
2431
0
        RTL_TEXTENCODING_UTF8) );
2432
0
    if (lang) {
2433
0
        const OUString langU( OStringToOUString(
2434
0
            std::string_view(lang),
2435
0
            RTL_TEXTENCODING_UTF8) );
2436
0
        return rdf::Literal::createWithLanguage(m_xContext, valueU, langU);
2437
0
    } else if (pType) {
2438
0
        uno::Reference<rdf::XURI> xType(convertToXURI(pType));
2439
0
        OSL_ENSURE(xType.is(), "convertToXNode: null uri");
2440
0
        return rdf::Literal::createWithType(m_xContext, valueU, xType);
2441
0
    } else {
2442
0
        return rdf::Literal::create(m_xContext, valueU);
2443
0
    }
2444
0
}
2445
2446
rdf::Statement
2447
librdf_TypeConverter::convertToStatement(librdf_statement* i_pStmt,
2448
    librdf_node* i_pContext) const
2449
0
{
2450
0
    if (!i_pStmt) {
2451
0
        throw uno::RuntimeException();
2452
0
    }
2453
0
    return rdf::Statement(
2454
0
        convertToXResource(librdf_statement_get_subject(i_pStmt)),
2455
0
        convertToXURI(librdf_statement_get_predicate(i_pStmt)),
2456
0
        convertToXNode(librdf_statement_get_object(i_pStmt)),
2457
0
        convertToXURI(i_pContext));
2458
0
}
2459
2460
} // closing anonymous implementation namespace
2461
2462
2463
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
2464
unoxml_rdfRepository_get_implementation(
2465
    css::uno::XComponentContext* context , css::uno::Sequence<css::uno::Any> const&)
2466
6.73k
{
2467
6.73k
    return cppu::acquire(new librdf_Repository(context));
2468
6.73k
}
2469
2470
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */