1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <sfx2/DocumentMetadataAccess.hxx>
23 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/embed/ElementModes.hpp>
26 #include <com/sun/star/embed/XStorage.hpp>
27 #include <com/sun/star/embed/XTransactedObject.hpp>
28 #include <com/sun/star/frame/XTransientDocumentsDocumentContentIdentifierFactory.hpp>
29 #include <com/sun/star/task/ErrorCodeIOException.hpp>
30 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
31 #include <com/sun/star/rdf/FileFormat.hpp>
32 #include <com/sun/star/rdf/ParseException.hpp>
33 #include <com/sun/star/rdf/RepositoryException.hpp>
34 #include <com/sun/star/rdf/URIs.hpp>
35 #include <com/sun/star/rdf/Statement.hpp>
36 #include <com/sun/star/rdf/URI.hpp>
37 #include <com/sun/star/rdf/Repository.hpp>
39 #include <rtl/ustrbuf.hxx>
40 #include <rtl/uri.hxx>
41 #include <rtl/bootstrap.hxx>
42 #include <sal/log.hxx>
44 #include <comphelper/interaction.hxx>
45 #include <unotools/mediadescriptor.hxx>
46 #include <comphelper/sequence.hxx>
47 #include <comphelper/storagehelper.hxx>
48 #include <cppuhelper/exc_hlp.hxx>
49 #include <o3tl/string_view.hxx>
51 #include <sfx2/docfile.hxx>
52 #include <sfx2/XmlIdRegistry.hxx>
53 #include <sfx2/objsh.hxx>
54 #include <comphelper/diagnose_ex.hxx>
56 #include <libxml/tree.h>
61 #include <string_view>
63 #include <com/sun/star/uri/XUriReference.hpp>
64 #include <com/sun/star/uri/UriReferenceFactory.hpp>
68 Note: in the context of this implementation, all rdf.QueryExceptions and
69 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
71 This implementation assumes that it is only used with ODF documents, not mere
72 ODF packages. In other words, we enforce that metadata files must not be
73 called reserved names.
76 using namespace ::com::sun::star
;
81 bool isValidNCName(std::u16string_view i_rIdref
)
84 OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
85 return !(xmlValidateNCName(
86 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
90 constexpr OUString s_content
= u
"content.xml"_ustr
;
91 constexpr OUString s_styles
= u
"styles.xml"_ustr
;
92 constexpr OUString s_manifest
= u
"manifest.rdf"_ustr
;
93 const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
96 static bool isContentFile(std::u16string_view i_rPath
)
98 return i_rPath
== s_content
;
101 static bool isStylesFile (std::u16string_view i_rPath
)
103 return i_rPath
== s_styles
;
106 bool isValidXmlId(std::u16string_view i_rStreamName
,
107 std::u16string_view i_rIdref
)
109 return isValidNCName(i_rIdref
)
110 && (isContentFile(i_rStreamName
) || isStylesFile(i_rStreamName
));
113 static bool isReservedFile(std::u16string_view i_rPath
)
115 return isContentFile(i_rPath
) || isStylesFile(i_rPath
) || i_rPath
== u
"meta.xml" || i_rPath
== u
"settings.xml";
119 uno::Reference
<rdf::XURI
> createBaseURI(
120 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
121 uno::Reference
<frame::XModel
> const & i_xModel
,
122 OUString
const & i_rPkgURI
, std::u16string_view i_rSubDocument
)
124 if (!i_xContext
.is() || (!i_xModel
.is() && i_rPkgURI
.isEmpty())) {
125 throw uno::RuntimeException();
128 OUString
pkgURI(i_rPkgURI
);
130 // tdf#123293 chicken/egg problem when loading from stream: there is no URI,
131 // and also the model doesn't have a storage yet, so we need to get the
132 // tdoc URI without a storage...
133 if (pkgURI
.isEmpty())
135 assert(i_xModel
.is());
136 uno::Reference
<frame::XTransientDocumentsDocumentContentIdentifierFactory
>
138 i_xContext
->getServiceManager()->createInstanceWithContext(
139 u
"com.sun.star.ucb.TransientDocumentsContentProvider"_ustr
,
141 uno::UNO_QUERY_THROW
);
142 uno::Reference
<ucb::XContentIdentifier
> const xContentId(
143 xTDDCIF
->createDocumentContentIdentifier(i_xModel
));
144 SAL_WARN_IF(!xContentId
.is(), "sfx", "createBaseURI: cannot create ContentIdentifier");
145 if (!xContentId
.is())
147 throw uno::RuntimeException(u
"createBaseURI: cannot create ContentIdentifier"_ustr
);
149 pkgURI
= xContentId
->getContentIdentifier();
150 assert(!pkgURI
.isEmpty());
151 if (!pkgURI
.isEmpty() && !pkgURI
.endsWith("/"))
157 // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
158 // this really should be done somewhere else, not here.
159 if (pkgURI
.startsWithIgnoreAsciiCase("vnd.sun.star.expand:", &pkgURI
))
161 // expand it here (makeAbsolute requires hierarchical URI)
162 if (!pkgURI
.isEmpty()) {
163 pkgURI
= ::rtl::Uri::decode(
164 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
165 if (pkgURI
.isEmpty()) {
166 throw uno::RuntimeException();
168 ::rtl::Bootstrap::expandMacros(pkgURI
);
172 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory
=
173 uri::UriReferenceFactory::create( i_xContext
);
174 uno::Reference
< uri::XUriReference
> xBaseURI
;
176 const uno::Reference
< uri::XUriReference
> xPkgURI(
177 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
178 xPkgURI
->clearFragment();
180 // need to know whether the storage is a FileSystemStorage
181 // XServiceInfo would be better, but it is not implemented
182 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
184 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
186 OUStringBuffer
buf(64);
187 if (!xBaseURI
->getUriReference().endsWith("/"))
189 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
192 buf
.append(xBaseURI
->getPathSegment(count
- 1));
196 if (!i_rSubDocument
.empty())
198 buf
.append(OUString::Concat(i_rSubDocument
) + "/");
202 const uno::Reference
< uri::XUriReference
> xPathURI(
203 xUriFactory
->parse(buf
.makeStringAndClear()), uno::UNO_SET_THROW
);
205 xUriFactory
->makeAbsolute(xBaseURI
, xPathURI
,
206 true, uri::RelativeUriExcessParentSegments_ERROR
),
210 return rdf::URI::create(i_xContext
, xBaseURI
->getUriReference());
214 struct DocumentMetadataAccess_Impl
216 // note: these are all initialized in constructor, and loadFromStorage
217 const uno::Reference
<uno::XComponentContext
> m_xContext
;
218 const SfxObjectShell
& m_rXmlIdRegistrySupplier
;
219 uno::Reference
<rdf::XURI
> m_xBaseURI
;
220 uno::Reference
<rdf::XRepository
> m_xRepository
;
221 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
222 DocumentMetadataAccess_Impl(
223 uno::Reference
<uno::XComponentContext
> i_xContext
,
224 SfxObjectShell
const & i_rRegistrySupplier
)
225 : m_xContext(std::move(i_xContext
))
226 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
228 OSL_ENSURE(m_xContext
.is(), "context null");
232 // this is... a hack.
233 template<sal_Int16 Constant
>
234 static uno::Reference
<rdf::XURI
> const &
235 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
237 static uno::Reference
< rdf::XURI
> xURI(
238 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_SET_THROW
);
243 /** would storing the file to a XStorage succeed? */
244 static bool isFileNameValid(std::u16string_view i_rFileName
)
246 if (i_rFileName
.empty()) return false;
247 if (i_rFileName
[0] == '/') return false; // no absolute paths!
250 const OUString
segment(
251 o3tl::getToken(i_rFileName
, 0, u
'/', idx
) );
252 if (segment
.isEmpty() || // no empty segments
253 segment
== "." || // no . segments
254 segment
== ".." || // no .. segments
255 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
256 segment
, false)) // no invalid characters
262 /** split a uri hierarchy into first segment and rest */
264 splitPath(OUString
const & i_rPath
,
265 OUString
& o_rDir
, OUString
& o_rRest
)
267 const sal_Int32
idx(i_rPath
.indexOf(u
'/'));
268 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
272 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
273 // input must not start or end with '/'
276 o_rDir
= i_rPath
.copy(0, idx
);
277 o_rRest
= i_rPath
.copy(idx
+1);
283 splitXmlId(std::u16string_view i_XmlId
,
284 OUString
& o_StreamName
, OUString
& o_Idref
)
286 const size_t idx(i_XmlId
.find(u
'#'));
287 if (idx
== std::u16string_view::npos
)
289 o_StreamName
= i_XmlId
.substr(0, idx
);
290 o_Idref
= i_XmlId
.substr(idx
+1);
291 return isValidXmlId(o_StreamName
, o_Idref
);
295 static uno::Reference
<rdf::XURI
>
296 getURIForStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
297 OUString
const& i_rPath
)
299 const uno::Reference
<rdf::XURI
> xURI(
300 rdf::URI::createNS( i_rImpl
.m_xContext
,
301 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
306 /** add statements declaring i_xResource to be a file of type i_xType with
307 path i_rPath to manifest, with optional additional types i_pTypes */
309 addFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
310 uno::Reference
<rdf::XURI
> const& i_xType
,
311 OUString
const & i_rPath
,
312 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
)
315 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
318 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
319 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
321 i_rImpl
.m_xManifest
->addStatement(xURI
,
322 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
325 for (const auto& rType
: *i_pTypes
) {
326 i_rImpl
.m_xManifest
->addStatement(xURI
,
327 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
331 } catch (const uno::RuntimeException
&) {
333 } catch (const uno::Exception
&) {
334 css::uno::Any anyEx
= cppu::getCaughtException();
335 throw lang::WrappedTargetRuntimeException(
336 u
"addFile: exception"_ustr
, /*this*/nullptr, anyEx
);
340 /** add content.xml or styles.xml to manifest */
342 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
343 const OUString
& i_rPath
)
345 uno::Reference
<rdf::XURI
> xType
;
346 if (isContentFile(i_rPath
)) {
347 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
348 } else if (isStylesFile(i_rPath
)) {
349 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
353 addFile(i_rImpl
, xType
, i_rPath
, nullptr);
357 /** add metadata file to manifest */
359 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
360 const OUString
& i_rPath
,
361 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
364 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
368 /** remove a file from the manifest */
370 removeFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
371 uno::Reference
<rdf::XURI
> const& i_xPart
)
373 if (!i_xPart
.is()) throw uno::RuntimeException();
375 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
,
376 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
378 i_rImpl
.m_xManifest
->removeStatements(i_xPart
,
379 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), nullptr);
380 } catch (const uno::RuntimeException
&) {
382 } catch (const uno::Exception
&) {
383 css::uno::Any anyEx
= cppu::getCaughtException();
384 throw lang::WrappedTargetRuntimeException(
385 u
"removeFile: exception"_ustr
,
390 static ::std::vector
< uno::Reference
< rdf::XURI
> >
391 getAllParts(struct DocumentMetadataAccess_Impl
const & i_rImpl
)
393 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
395 const uno::Reference
<container::XEnumeration
> xEnum(
396 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
,
397 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), nullptr),
399 while (xEnum
->hasMoreElements()) {
401 if (!(xEnum
->nextElement() >>= stmt
)) {
402 throw uno::RuntimeException();
404 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
406 if (!xPart
.is()) continue;
407 ret
.push_back(xPart
);
410 } catch (const uno::RuntimeException
&) {
412 } catch (const uno::Exception
&) {
413 css::uno::Any anyEx
= cppu::getCaughtException();
414 throw lang::WrappedTargetRuntimeException(
415 u
"getAllParts: exception"_ustr
,
421 isPartOfType(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
422 uno::Reference
<rdf::XURI
> const & i_xPart
,
423 uno::Reference
<rdf::XURI
> const & i_xType
)
425 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
427 const uno::Reference
<container::XEnumeration
> xEnum(
428 i_rImpl
.m_xManifest
->getStatements(i_xPart
,
429 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
432 return xEnum
->hasMoreElements();
433 } catch (const uno::RuntimeException
&) {
435 } catch (const uno::Exception
&) {
436 css::uno::Any anyEx
= cppu::getCaughtException();
437 throw lang::WrappedTargetRuntimeException(
438 u
"isPartOfType: exception"_ustr
,
443 static ::std::vector
<uno::Reference
<rdf::XURI
>>
444 getAllParts(struct DocumentMetadataAccess_Impl
const& i_rImpl
,
445 const uno::Reference
<rdf::XURI
>& i_xType
)
447 ::std::vector
<uno::Reference
<rdf::XURI
>> ret
;
450 const uno::Reference
<container::XEnumeration
> xEnum(
451 i_rImpl
.m_xManifest
->getStatements(i_rImpl
.m_xBaseURI
,
452 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
455 while (xEnum
->hasMoreElements())
458 if (!(xEnum
->nextElement() >>= stmt
))
460 throw uno::RuntimeException();
462 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
, uno::UNO_QUERY
);
466 const uno::Reference
<container::XEnumeration
> xEnum2(
467 i_rImpl
.m_xManifest
->getStatements(
468 xPart
, getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), i_xType
),
470 if (xEnum2
->hasMoreElements())
471 ret
.emplace_back(xPart
);
475 catch (const uno::RuntimeException
&)
479 catch (const uno::Exception
& e
)
481 throw lang::WrappedTargetRuntimeException(u
"getAllParts: exception"_ustr
, nullptr,
486 static ucb::InteractiveAugmentedIOException
487 mkException( OUString
const & i_rMessage
,
488 ucb::IOErrorCode
const i_ErrorCode
,
489 OUString
const & i_rUri
, OUString
const & i_rResource
)
491 const beans::PropertyValue
uriProp(u
"Uri"_ustr
,
492 -1, uno::Any(i_rUri
), static_cast<beans::PropertyState
>(0));
493 const beans::PropertyValue
rnProp(
494 u
"ResourceName"_ustr
,
495 -1, uno::Any(i_rResource
), static_cast<beans::PropertyState
>(0));
496 return ucb::InteractiveAugmentedIOException(i_rMessage
, {},
497 task::InteractionClassification_ERROR
, i_ErrorCode
,
498 { uno::Any(uriProp
), uno::Any(rnProp
) });
501 /** error handling policy.
502 <p>If a handler is given, ask it how to proceed:
503 <ul><li>(default:) cancel import, raise exception</li>
504 <li>ignore the error and continue</li>
505 <li>retry the action that led to the error</li></ul></p>
506 N.B.: must not be called before DMA is fully initialized!
507 @returns true iff caller should retry
510 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
511 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
513 if (!i_xHandler
.is()) {
514 throw lang::WrappedTargetException(
515 u
"DocumentMetadataAccess::loadMetadataFromStorage: exception"_ustr
,
516 /* *this*/ nullptr, uno::Any(i_rException
));
519 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
520 new ::comphelper::OInteractionRequest(uno::Any(i_rException
)) );
521 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
522 new ::comphelper::OInteractionRetry
);
523 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
524 new ::comphelper::OInteractionApprove
);
525 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
526 new ::comphelper::OInteractionAbort
);
528 pRequest
->addContinuation( pApprove
);
529 pRequest
->addContinuation( pAbort
);
530 // actually call the handler
531 i_xHandler
->handle( pRequest
);
532 if (pRetry
->wasSelected()) {
534 } else if (pApprove
->wasSelected()) {
537 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
538 throw lang::WrappedTargetException(
539 u
"DocumentMetadataAccess::loadMetadataFromStorage: exception"_ustr
,
540 /* *this*/ nullptr, uno::Any(i_rException
));
544 /** check if storage has content.xml/styles.xml;
545 e.g. ODB files seem to only have content.xml */
547 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
548 std::set
< OUString
> & o_rFiles
)
551 if (i_xStorage
->hasByName(s_content
) &&
552 i_xStorage
->isStreamElement(s_content
))
554 o_rFiles
.insert(s_content
);
556 if (i_xStorage
->hasByName(s_styles
) &&
557 i_xStorage
->isStreamElement(s_styles
))
559 o_rFiles
.insert(s_styles
);
561 } catch (const uno::Exception
&) {
562 TOOLS_WARN_EXCEPTION("sfx", "collectFilesFromStorage");
566 /** import a metadata file into repository */
568 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
569 uno::Reference
< embed::XStorage
> const & i_xStorage
,
570 OUString
const & i_rPath
,
571 OUString
const & i_rBaseURI
)
576 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
578 if (!i_xStorage
->isStreamElement(i_rPath
)) {
580 u
"readStream: is not a stream"_ustr
,
581 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
583 const uno::Reference
<io::XStream
> xStream(
584 i_xStorage
->openStreamElement(i_rPath
,
585 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
586 const uno::Reference
<io::XInputStream
> xInStream(
587 xStream
->getInputStream(), uno::UNO_SET_THROW
);
588 const uno::Reference
<rdf::XURI
> xBaseURI(
589 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
590 const uno::Reference
<rdf::XURI
> xURI(
591 rdf::URI::createNS(i_rImpl
.m_xContext
,
592 i_rBaseURI
, i_rPath
));
593 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
594 xInStream
, xURI
, xBaseURI
);
596 if (!i_xStorage
->isStorageElement(dir
)) {
598 u
"readStream: is not a directory"_ustr
,
599 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
601 const uno::Reference
<embed::XStorage
> xDir(
602 i_xStorage
->openStorageElement(dir
,
603 embed::ElementModes::READ
));
604 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
605 uno::UNO_QUERY_THROW
);
608 xDirProps
->getPropertyValue(
609 utl::MediaDescriptor::PROP_MEDIATYPE
)
611 if (mimeType
.startsWith(s_odfmime
)) {
612 SAL_WARN("sfx", "readStream: refusing to recurse into embedded document");
615 } catch (const uno::Exception
&) { }
616 readStream(i_rImpl
, xDir
, rest
, i_rBaseURI
+dir
+"/" );
618 } catch (const container::NoSuchElementException
& e
) {
619 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
620 i_rBaseURI
+ i_rPath
, i_rPath
);
621 } catch (const io::IOException
& e
) {
622 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
623 i_rBaseURI
+ i_rPath
, i_rPath
);
624 } catch (const rdf::ParseException
& e
) {
625 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
626 i_rBaseURI
+ i_rPath
, i_rPath
);
630 /** import a metadata file into repository */
632 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
633 uno::Reference
<embed::XStorage
> const & i_xStorage
,
634 OUString
const & i_rBaseURI
,
635 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
636 const OUString
& i_rPath
)
640 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
641 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
642 if (handleError(e
, i_xHandler
)) goto retry
;
643 } catch (const uno::RuntimeException
&) {
645 } catch (const uno::Exception
&) {
646 css::uno::Any anyEx
= cppu::getCaughtException();
647 throw lang::WrappedTargetRuntimeException(
648 u
"importFile: exception"_ustr
,
653 /** actually write a metadata file to the storage */
655 exportStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
656 uno::Reference
< embed::XStorage
> const & i_xStorage
,
657 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
658 OUString
const & i_rFileName
,
659 OUString
const & i_rBaseURI
)
661 const uno::Reference
<io::XStream
> xStream(
662 i_xStorage
->openStreamElement(i_rFileName
,
663 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
665 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
667 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
668 xStreamProps
->setPropertyValue(
670 uno::Any(u
"application/rdf+xml"_ustr
));
672 const uno::Reference
<io::XOutputStream
> xOutStream(
673 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
674 const uno::Reference
<rdf::XURI
> xBaseURI(
675 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
676 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
677 xOutStream
, i_xGraphName
, xBaseURI
);
680 /** write a metadata file to the storage */
682 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
683 uno::Reference
< embed::XStorage
> const & i_xStorage
,
684 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
685 OUString
const & i_rPath
,
686 OUString
const & i_rBaseURI
)
690 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
693 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
696 const uno::Reference
<embed::XStorage
> xDir(
697 i_xStorage
->openStorageElement(dir
,
698 embed::ElementModes::WRITE
));
699 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
700 uno::UNO_QUERY_THROW
);
703 xDirProps
->getPropertyValue(
704 utl::MediaDescriptor::PROP_MEDIATYPE
)
706 if (mimeType
.startsWith(s_odfmime
)) {
707 SAL_WARN("sfx", "writeStream: refusing to recurse into embedded document");
710 } catch (const uno::Exception
&) { }
711 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
, i_rBaseURI
+dir
+"/");
712 uno::Reference
<embed::XTransactedObject
> const xTransaction(
713 xDir
, uno::UNO_QUERY
);
714 if (xTransaction
.is()) {
715 xTransaction
->commit();
718 } catch (const uno::RuntimeException
&) {
720 } catch (const io::IOException
&) {
726 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
727 const uno::Reference
< embed::XStorage
> & i_xStorage
,
728 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
729 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
733 i_rImpl
.m_xManifest
.clear();
735 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
738 i_rImpl
.m_xRepository
.clear();
739 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
742 // try to delay raising errors until after initialization is done
744 ucb::InteractiveAugmentedIOException iaioe
;
747 const uno::Reference
<rdf::XURI
> xManifest(
748 getURIForStream(i_rImpl
, s_manifest
));
750 readStream(i_rImpl
, i_xStorage
, s_manifest
, i_xBaseURI
->getStringValue());
751 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
752 // no manifest.rdf: this is not an error in ODF < 1.2
753 if (ucb::IOErrorCode_NOT_EXISTING_PATH
!= e
.Code
) {
757 } catch (const uno::Exception
& e
) {
761 // init manifest graph
762 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
763 i_rImpl
.m_xRepository
->getGraph(xManifest
));
764 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
765 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
767 // document statement
768 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
769 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
770 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
));
772 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
773 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
774 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
776 if (rterr
.hasValue()) {
777 throw lang::WrappedTargetRuntimeException(
778 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
779 "exception"_ustr
, nullptr, rterr
);
782 if (err
&& handleError(iaioe
, i_xHandler
))
786 /** init Impl struct */
787 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
791 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
792 getURIForStream(i_rImpl
, s_manifest
)),
795 // insert the document statement
796 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
797 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
798 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
));
799 } catch (const uno::Exception
&) {
800 css::uno::Any anyEx
= cppu::getCaughtException();
801 throw lang::WrappedTargetRuntimeException(
802 u
"init: unexpected exception"_ustr
, nullptr,
806 // add top-level content files
807 if (!addContentOrStylesFileImpl(i_rImpl
, s_content
)) {
808 throw uno::RuntimeException();
810 if (!addContentOrStylesFileImpl(i_rImpl
, s_styles
)) {
811 throw uno::RuntimeException();
816 DocumentMetadataAccess::DocumentMetadataAccess(
817 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
818 const SfxObjectShell
& i_rRegistrySupplier
)
819 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
821 // no initialization: must call loadFrom...
824 DocumentMetadataAccess::DocumentMetadataAccess(
825 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
826 const SfxObjectShell
& i_rRegistrySupplier
,
827 OUString
const & i_rURI
)
828 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
830 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
831 OSL_ENSURE(i_rURI
.endsWith("/"), "DMA::DMA: URI without / given!");
832 if (!i_rURI
.endsWith("/")) throw uno::RuntimeException();
833 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
834 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
840 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
841 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
842 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
845 DocumentMetadataAccess::~DocumentMetadataAccess()
849 // css::rdf::XRepositorySupplier:
850 uno::Reference
< rdf::XRepository
> SAL_CALL
851 DocumentMetadataAccess::getRDFRepository()
853 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
854 return m_pImpl
->m_xRepository
;
859 DocumentMetadataAccess::getStringValue()
861 return m_pImpl
->m_xBaseURI
->getStringValue();
866 DocumentMetadataAccess::getNamespace()
868 return m_pImpl
->m_xBaseURI
->getNamespace();
872 DocumentMetadataAccess::getLocalName()
874 return m_pImpl
->m_xBaseURI
->getLocalName();
877 // css::rdf::XDocumentMetadataAccess:
878 uno::Reference
< rdf::XMetadatable
> SAL_CALL
879 DocumentMetadataAccess::getElementByMetadataReference(
880 const css::beans::StringPair
& i_rReference
)
882 const IXmlIdRegistry
* pReg(
883 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
885 throw uno::RuntimeException(
886 u
"DocumentMetadataAccess::getElementByXmlId: no registry"_ustr
, *this);
888 return pReg
->GetElementByMetadataReference(i_rReference
);
891 uno::Reference
< rdf::XMetadatable
> SAL_CALL
892 DocumentMetadataAccess::getElementByURI(
893 const uno::Reference
< rdf::XURI
> & i_xURI
)
896 throw lang::IllegalArgumentException(
897 u
"DocumentMetadataAccess::getElementByURI: URI is null"_ustr
, *this, 0);
900 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
901 const OUString
name( i_xURI
->getStringValue() );
902 if (!name
.match(baseURI
)) {
907 if (!splitXmlId(name
.subView(baseURI
.getLength()), path
, idref
)) {
911 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
914 uno::Sequence
<uno::Reference
<rdf::XURI
>> SAL_CALL
915 DocumentMetadataAccess::getMetadataGraphsWithType(const uno::Reference
<rdf::XURI
>& i_xType
)
919 throw lang::IllegalArgumentException(u
"DocumentMetadataAccess::getMetadataGraphsWithType: "
924 return ::comphelper::containerToSequence(getAllParts(*m_pImpl
, i_xType
));
927 uno::Reference
<rdf::XURI
> SAL_CALL
928 DocumentMetadataAccess::addMetadataFile(const OUString
& i_rFileName
,
929 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
931 if (!isFileNameValid(i_rFileName
)) {
932 throw lang::IllegalArgumentException(
933 u
"DocumentMetadataAccess::addMetadataFile: invalid FileName"_ustr
,
936 if (isReservedFile(i_rFileName
)) {
937 throw lang::IllegalArgumentException(
938 u
"DocumentMetadataAccess::addMetadataFile:"
939 "invalid FileName: reserved"_ustr
, *this, 0);
941 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
942 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
943 throw lang::IllegalArgumentException(
944 u
"DocumentMetadataAccess::addMetadataFile: "
945 "null type"_ustr
, *this, 2);
948 const uno::Reference
<rdf::XURI
> xGraphName(
949 getURIForStream(*m_pImpl
, i_rFileName
) );
952 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
953 } catch (const rdf::RepositoryException
&) {
954 css::uno::Any anyEx
= cppu::getCaughtException();
955 throw lang::WrappedTargetRuntimeException(
956 u
"DocumentMetadataAccess::addMetadataFile: exception"_ustr
,
958 // note: all other exceptions are propagated
961 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
965 uno::Reference
<rdf::XURI
> SAL_CALL
966 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
967 const uno::Reference
< io::XInputStream
> & i_xInStream
,
968 const OUString
& i_rFileName
,
969 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
970 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
972 if (!isFileNameValid(i_rFileName
)) {
973 throw lang::IllegalArgumentException(
974 u
"DocumentMetadataAccess::importMetadataFile: invalid FileName"_ustr
,
977 if (isReservedFile(i_rFileName
)) {
978 throw lang::IllegalArgumentException(
979 u
"DocumentMetadataAccess::importMetadataFile:"
980 "invalid FileName: reserved"_ustr
, *this, 0);
982 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
983 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
984 throw lang::IllegalArgumentException(
985 u
"DocumentMetadataAccess::importMetadataFile: null type"_ustr
,
989 const uno::Reference
<rdf::XURI
> xGraphName(
990 getURIForStream(*m_pImpl
, i_rFileName
) );
993 m_pImpl
->m_xRepository
->importGraph(
994 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
995 } catch (const rdf::RepositoryException
&) {
996 css::uno::Any anyEx
= cppu::getCaughtException();
997 throw lang::WrappedTargetRuntimeException(
998 u
"DocumentMetadataAccess::importMetadataFile: "
999 "RepositoryException"_ustr
, *this, anyEx
);
1000 // note: all other exceptions are propagated
1004 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1009 DocumentMetadataAccess::removeMetadataFile(
1010 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1013 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1014 } catch (const rdf::RepositoryException
&) {
1015 css::uno::Any anyEx
= cppu::getCaughtException();
1016 throw lang::WrappedTargetRuntimeException(
1017 u
"DocumentMetadataAccess::removeMetadataFile: "
1018 "RepositoryException"_ustr
, *this, anyEx
);
1019 // note: all other exceptions are propagated
1022 // remove file from manifest
1023 removeFile(*m_pImpl
, i_xGraphName
);
1027 DocumentMetadataAccess::addContentOrStylesFile(
1028 const OUString
& i_rFileName
)
1030 if (!isFileNameValid(i_rFileName
)) {
1031 throw lang::IllegalArgumentException(
1032 u
"DocumentMetadataAccess::addContentOrStylesFile: "
1033 "invalid FileName"_ustr
, *this, 0);
1036 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1037 throw lang::IllegalArgumentException(
1038 u
"DocumentMetadataAccess::addContentOrStylesFile: "
1039 "invalid FileName: must end with content.xml or styles.xml"_ustr
,
1045 DocumentMetadataAccess::removeContentOrStylesFile(
1046 const OUString
& i_rFileName
)
1048 if (!isFileNameValid(i_rFileName
)) {
1049 throw lang::IllegalArgumentException(
1050 u
"DocumentMetadataAccess::removeContentOrStylesFile: "
1051 "invalid FileName"_ustr
, *this, 0);
1055 const uno::Reference
<rdf::XURI
> xPart(
1056 getURIForStream(*m_pImpl
, i_rFileName
) );
1057 const uno::Reference
<container::XEnumeration
> xEnum(
1058 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
,
1059 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1061 uno::UNO_SET_THROW
);
1062 if (!xEnum
->hasMoreElements()) {
1063 throw container::NoSuchElementException(
1064 "DocumentMetadataAccess::removeContentOrStylesFile: "
1065 "cannot find stream in manifest graph: " + i_rFileName
,
1069 // remove file from manifest
1070 removeFile(*m_pImpl
, xPart
);
1072 } catch (const uno::RuntimeException
&) {
1074 } catch (const uno::Exception
&) {
1075 css::uno::Any anyEx
= cppu::getCaughtException();
1076 throw lang::WrappedTargetRuntimeException(
1077 u
"DocumentMetadataAccess::removeContentOrStylesFile: exception"_ustr
,
1082 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1083 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1084 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1085 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1087 if (!i_xStorage
.is()) {
1088 throw lang::IllegalArgumentException(
1089 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
1090 "storage is null"_ustr
, *this, 0);
1092 if (!i_xBaseURI
.is()) {
1093 throw lang::IllegalArgumentException(
1094 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
1095 "base URI is null"_ustr
, *this, 1);
1097 const OUString
baseURI( i_xBaseURI
->getStringValue());
1098 if (baseURI
.indexOf('#') >= 0) {
1099 throw lang::IllegalArgumentException(
1100 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
1101 "base URI not absolute"_ustr
, *this, 1);
1103 if (!baseURI
.endsWith("/")) {
1104 throw lang::IllegalArgumentException(
1105 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
1106 "base URI does not end with slash"_ustr
, *this, 1);
1109 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1111 std::set
< OUString
> StgFiles
;
1112 collectFilesFromStorage(i_xStorage
, StgFiles
);
1114 std::vector
< OUString
> MfstMetadataFiles
;
1117 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1118 getAllParts(*m_pImpl
) );
1119 const uno::Reference
<rdf::XURI
>& xContentFile(
1120 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1121 const uno::Reference
<rdf::XURI
>& xStylesFile(
1122 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1123 const uno::Reference
<rdf::XURI
>& xMetadataFile(
1124 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1125 const sal_Int32
len( baseURI
.getLength() );
1126 for (const auto& rxPart
: parts
) {
1127 const OUString
name(rxPart
->getStringValue());
1128 if (!name
.match(baseURI
)) {
1129 SAL_WARN("sfx", "loadMetadataFromStorage: graph not in document: " << name
);
1132 const OUString
relName( name
.copy(len
) );
1133 if (relName
== s_manifest
) {
1134 SAL_WARN("sfx", "loadMetadataFromStorage: found ourselves a recursive manifest!");
1137 // remove found items from StgFiles
1138 StgFiles
.erase(relName
);
1139 if (isContentFile(relName
)) {
1140 if (!isPartOfType(*m_pImpl
, rxPart
, xContentFile
)) {
1141 const uno::Reference
<rdf::XURI
> xName(
1142 getURIForStream(*m_pImpl
, relName
) );
1143 // add missing type statement
1144 m_pImpl
->m_xManifest
->addStatement(xName
,
1145 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1148 } else if (isStylesFile(relName
)) {
1149 if (!isPartOfType(*m_pImpl
, rxPart
, xStylesFile
)) {
1150 const uno::Reference
<rdf::XURI
> xName(
1151 getURIForStream(*m_pImpl
, relName
) );
1152 // add missing type statement
1153 m_pImpl
->m_xManifest
->addStatement(xName
,
1154 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1157 } else if (isReservedFile(relName
)) {
1158 SAL_WARN("sfx", "loadMetadataFromStorage: reserved file name in manifest");
1160 if (isPartOfType(*m_pImpl
, rxPart
, xMetadataFile
)) {
1161 MfstMetadataFiles
.push_back(relName
);
1163 // do not add statement for MetadataFile; it could be
1164 // something else! just ignore it...
1167 } catch (const uno::RuntimeException
&) {
1169 } catch (const uno::Exception
&) {
1170 css::uno::Any anyEx
= cppu::getCaughtException();
1171 throw lang::WrappedTargetRuntimeException(
1172 u
"DocumentMetadataAccess::loadMetadataFromStorage: "
1173 "exception"_ustr
, *this, anyEx
);
1176 for (const auto& aStgFile
: StgFiles
)
1177 addContentOrStylesFileImpl(*m_pImpl
, aStgFile
);
1179 for (const auto& aMfstMetadataFile
: MfstMetadataFiles
)
1180 importFile(*m_pImpl
, i_xStorage
, baseURI
, i_xHandler
, aMfstMetadataFile
);
1183 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1184 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1186 if (!i_xStorage
.is()) {
1187 throw lang::IllegalArgumentException(
1188 u
"DocumentMetadataAccess::storeMetadataToStorage: "
1189 "storage is null"_ustr
, *this, 0);
1193 const uno::Reference
<rdf::XURI
> xManifest(
1194 getURIForStream(*m_pImpl
, s_manifest
) );
1195 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1197 writeStream(*m_pImpl
, i_xStorage
, xManifest
, s_manifest
, baseURI
);
1198 } catch (const uno::RuntimeException
&) {
1200 } catch (const io::IOException
&) {
1201 css::uno::Any anyEx
= cppu::getCaughtException();
1202 throw lang::WrappedTargetException(
1203 u
"storeMetadataToStorage: IO exception"_ustr
, *this, anyEx
);
1204 } catch (const uno::Exception
&) {
1205 css::uno::Any anyEx
= cppu::getCaughtException();
1206 throw lang::WrappedTargetRuntimeException(
1207 u
"storeMetadataToStorage: exception"_ustr
, *this, anyEx
);
1210 // export metadata streams
1212 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1213 m_pImpl
->m_xRepository
->getGraphNames());
1214 const sal_Int32
len( baseURI
.getLength() );
1215 for (const uno::Reference
<rdf::XURI
>& xName
: graphs
) {
1216 const OUString
name(xName
->getStringValue());
1217 if (!name
.match(baseURI
)) {
1218 SAL_WARN("sfx", "storeMetadataToStorage: graph not in document: " << name
);
1221 const OUString
relName( name
.copy(len
) );
1222 if (relName
== s_manifest
) {
1225 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1226 SAL_WARN("sfx", "storeMetadataToStorage: invalid file name: " << relName
);
1230 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1231 } catch (const uno::RuntimeException
&) {
1233 } catch (const io::IOException
&) {
1234 css::uno::Any anyEx
= cppu::getCaughtException();
1235 throw lang::WrappedTargetException(
1236 u
"storeMetadataToStorage: IO exception"_ustr
,
1238 } catch (const uno::Exception
&) {
1239 css::uno::Any anyEx
= cppu::getCaughtException();
1240 throw lang::WrappedTargetRuntimeException(
1241 u
"storeMetadataToStorage: exception"_ustr
,
1245 } catch (const rdf::RepositoryException
&) {
1246 css::uno::Any anyEx
= cppu::getCaughtException();
1247 throw lang::WrappedTargetRuntimeException(
1248 u
"storeMetadataToStorage: exception"_ustr
, *this, anyEx
);
1253 DocumentMetadataAccess::loadMetadataFromMedium(
1254 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1256 uno::Reference
<io::XInputStream
> xIn
;
1257 utl::MediaDescriptor
md(i_rMedium
);
1259 md
[ utl::MediaDescriptor::PROP_URL
] >>= URL
;
1261 md
[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL
] >>= BaseURL
;
1262 if (md
.addInputStream()) {
1263 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM
] >>= xIn
;
1265 if (!xIn
.is() && URL
.isEmpty()) {
1266 throw lang::IllegalArgumentException(
1267 u
"DocumentMetadataAccess::loadMetadataFromMedium: "
1268 "invalid medium: no URL, no input stream"_ustr
, *this, 0);
1270 uno::Reference
<embed::XStorage
> xStorage
;
1273 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1274 xIn
, m_pImpl
->m_xContext
);
1275 } else { // fallback to url
1276 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1277 URL
, embed::ElementModes::READ
, m_pImpl
->m_xContext
);
1279 } catch (const uno::RuntimeException
&) {
1281 } catch (const io::IOException
&) {
1283 } catch (const uno::Exception
&) {
1284 css::uno::Any anyEx
= cppu::getCaughtException();
1285 throw lang::WrappedTargetException(
1286 u
"DocumentMetadataAccess::loadMetadataFromMedium: "
1287 "exception"_ustr
, *this, anyEx
);
1289 if (!xStorage
.is()) {
1290 throw uno::RuntimeException(
1291 u
"DocumentMetadataAccess::loadMetadataFromMedium: "
1292 "cannot get Storage"_ustr
, *this);
1294 uno::Reference
<rdf::XURI
> xBaseURI
;
1296 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, BaseURL
);
1297 } catch (const uno::Exception
&) {
1300 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, URL
);
1301 } catch (const uno::Exception
&) {
1302 OSL_FAIL("cannot create base URI");
1305 uno::Reference
<task::XInteractionHandler
> xIH
;
1306 md
[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER
] >>= xIH
;
1307 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1311 DocumentMetadataAccess::storeMetadataToMedium(
1312 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1314 utl::MediaDescriptor
md(i_rMedium
);
1316 md
[ utl::MediaDescriptor::PROP_URL
] >>= URL
;
1317 if (URL
.isEmpty()) {
1318 throw lang::IllegalArgumentException(
1319 u
"DocumentMetadataAccess::storeMetadataToMedium: "
1320 "invalid medium: no URL"_ustr
, *this, 0);
1323 SfxMedium
aMedium(i_rMedium
);
1324 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1327 if (xStorage
.is()) {
1330 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1331 URL
, embed::ElementModes::WRITE
, m_pImpl
->m_xContext
);
1334 if (!xStorage
.is()) {
1335 throw uno::RuntimeException(
1336 u
"DocumentMetadataAccess::storeMetadataToMedium: "
1337 "cannot get Storage"_ustr
, *this);
1339 // set MIME type of the storage
1340 utl::MediaDescriptor::const_iterator iter
1341 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE
);
1342 if (iter
!= md
.end()) {
1343 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1344 uno::UNO_QUERY_THROW
);
1346 // this is NOT supported in FileSystemStorage
1347 xProps
->setPropertyValue(
1348 utl::MediaDescriptor::PROP_MEDIATYPE
,
1350 } catch (const uno::Exception
&) { }
1352 storeMetadataToStorage(xStorage
);
1357 const bool bOk
= aMedium
.Commit();
1360 ErrCodeMsg nError
= aMedium
.GetErrorIgnoreWarning();
1361 if ( nError
== ERRCODE_NONE
) {
1362 nError
= ERRCODE_IO_GENERAL
;
1364 task::ErrorCodeIOException
ex(
1365 "DocumentMetadataAccess::storeMetadataToMedium Commit failed: " + nError
.toString(),
1366 uno::Reference
< uno::XInterface
>(), sal_uInt32(nError
.GetCode()));
1367 throw lang::WrappedTargetException(OUString(), *this,
1374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */