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