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>
50 #include <sfx2/docfile.hxx>
51 #include <sfx2/XmlIdRegistry.hxx>
52 #include <sfx2/objsh.hxx>
53 #include <tools/diagnose_ex.h>
55 #include <libxml/tree.h>
59 #include <string_view>
61 #include <com/sun/star/uri/XUriReference.hpp>
62 #include <com/sun/star/uri/UriReferenceFactory.hpp>
66 Note: in the context of this implementation, all rdf.QueryExceptions and
67 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
69 This implementation assumes that it is only used with ODF documents, not mere
70 ODF packages. In other words, we enforce that metadata files must not be
71 called reserved names.
74 using namespace ::com::sun::star
;
79 bool isValidNCName(std::u16string_view i_rIdref
)
82 OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
83 return !(xmlValidateNCName(
84 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
88 constexpr OUStringLiteral s_content
= u
"content.xml";
89 constexpr OUStringLiteral s_styles
= u
"styles.xml";
90 constexpr OUStringLiteral s_manifest
= u
"manifest.rdf";
91 const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
94 static bool isContentFile(std::u16string_view i_rPath
)
96 return i_rPath
== s_content
;
99 static bool isStylesFile (std::u16string_view i_rPath
)
101 return i_rPath
== s_styles
;
104 bool isValidXmlId(std::u16string_view i_rStreamName
,
105 std::u16string_view i_rIdref
)
107 return isValidNCName(i_rIdref
)
108 && (isContentFile(i_rStreamName
) || isStylesFile(i_rStreamName
));
111 static bool isReservedFile(std::u16string_view i_rPath
)
113 return isContentFile(i_rPath
) || isStylesFile(i_rPath
) || i_rPath
== u
"meta.xml" || i_rPath
== u
"settings.xml";
117 uno::Reference
<rdf::XURI
> createBaseURI(
118 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
119 uno::Reference
<frame::XModel
> const & i_xModel
,
120 OUString
const & i_rPkgURI
, std::u16string_view i_rSubDocument
)
122 if (!i_xContext
.is() || (!i_xModel
.is() && i_rPkgURI
.isEmpty())) {
123 throw uno::RuntimeException();
126 OUString
pkgURI(i_rPkgURI
);
128 // tdf#123293 chicken/egg problem when loading from stream: there is no URI,
129 // and also the model doesn't have a storage yet, so we need to get the
130 // tdoc URI without a storage...
131 if (pkgURI
.isEmpty())
133 assert(i_xModel
.is());
134 uno::Reference
<frame::XTransientDocumentsDocumentContentIdentifierFactory
>
136 i_xContext
->getServiceManager()->createInstanceWithContext(
137 "com.sun.star.ucb.TransientDocumentsContentProvider",
139 uno::UNO_QUERY_THROW
);
140 uno::Reference
<ucb::XContentIdentifier
> const xContentId(
141 xTDDCIF
->createDocumentContentIdentifier(i_xModel
));
142 SAL_WARN_IF(!xContentId
.is(), "sfx", "createBaseURI: cannot create ContentIdentifier");
143 if (!xContentId
.is())
145 throw uno::RuntimeException("createBaseURI: cannot create ContentIdentifier");
147 pkgURI
= xContentId
->getContentIdentifier();
148 assert(!pkgURI
.isEmpty());
149 if (!pkgURI
.isEmpty() && !pkgURI
.endsWith("/"))
155 // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
156 // this really should be done somewhere else, not here.
157 if (pkgURI
.matchIgnoreAsciiCase("vnd.sun.star.expand:"))
159 // expand it here (makeAbsolute requires hierarchical URI)
160 pkgURI
= pkgURI
.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
161 if (!pkgURI
.isEmpty()) {
162 pkgURI
= ::rtl::Uri::decode(
163 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
164 if (pkgURI
.isEmpty()) {
165 throw uno::RuntimeException();
167 ::rtl::Bootstrap::expandMacros(pkgURI
);
171 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory
=
172 uri::UriReferenceFactory::create( i_xContext
);
173 uno::Reference
< uri::XUriReference
> xBaseURI
;
175 const uno::Reference
< uri::XUriReference
> xPkgURI(
176 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
177 xPkgURI
->clearFragment();
179 // need to know whether the storage is a FileSystemStorage
180 // XServiceInfo would be better, but it is not implemented
181 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
183 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
185 OUStringBuffer
buf(64);
186 if (!xBaseURI
->getUriReference().endsWith("/"))
188 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
191 buf
.append(xBaseURI
->getPathSegment(count
- 1));
195 if (!i_rSubDocument
.empty())
197 buf
.append(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
> const& i_xContext
,
224 SfxObjectShell
const & i_rRegistrySupplier
)
225 : m_xContext(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(const OUString
& i_rFileName
)
246 if (i_rFileName
.isEmpty()) return false;
247 if (i_rFileName
[0] == '/') return false; // no absolute paths!
250 const OUString
segment(
251 i_rFileName
.getToken(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(OUString
const & i_XmlId
,
284 OUString
& o_StreamName
, OUString
& o_Idref
)
286 const sal_Int32
idx(i_XmlId
.indexOf(u
'#'));
287 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
290 o_StreamName
= i_XmlId
.copy(0, idx
);
291 o_Idref
= i_XmlId
.copy(idx
+1);
292 return isValidXmlId(o_StreamName
, o_Idref
);
297 static uno::Reference
<rdf::XURI
>
298 getURIForStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
299 OUString
const& i_rPath
)
301 const uno::Reference
<rdf::XURI
> xURI(
302 rdf::URI::createNS( i_rImpl
.m_xContext
,
303 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
308 /** add statements declaring i_xResource to be a file of type i_xType with
309 path i_rPath to manifest, with optional additional types i_pTypes */
311 addFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
312 uno::Reference
<rdf::XURI
> const& i_xType
,
313 OUString
const & i_rPath
,
314 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
)
317 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
320 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
321 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
323 i_rImpl
.m_xManifest
->addStatement(xURI
,
324 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
327 for (const auto& rType
: *i_pTypes
) {
328 i_rImpl
.m_xManifest
->addStatement(xURI
,
329 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
333 } catch (const uno::RuntimeException
&) {
335 } catch (const uno::Exception
&) {
336 css::uno::Any anyEx
= cppu::getCaughtException();
337 throw lang::WrappedTargetRuntimeException(
338 "addFile: exception", /*this*/nullptr, anyEx
);
342 /** add content.xml or styles.xml to manifest */
344 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
345 const OUString
& i_rPath
)
347 uno::Reference
<rdf::XURI
> xType
;
348 if (isContentFile(i_rPath
)) {
349 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
350 } else if (isStylesFile(i_rPath
)) {
351 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
355 addFile(i_rImpl
, xType
, i_rPath
, nullptr);
359 /** add metadata file to manifest */
361 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
362 const OUString
& i_rPath
,
363 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
366 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
370 /** remove a file from the manifest */
372 removeFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
373 uno::Reference
<rdf::XURI
> const& i_xPart
)
375 if (!i_xPart
.is()) throw uno::RuntimeException();
377 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
,
378 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
380 i_rImpl
.m_xManifest
->removeStatements(i_xPart
,
381 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), nullptr);
382 } catch (const uno::RuntimeException
&) {
384 } catch (const uno::Exception
&) {
385 css::uno::Any anyEx
= cppu::getCaughtException();
386 throw lang::WrappedTargetRuntimeException(
387 "removeFile: exception",
392 static ::std::vector
< uno::Reference
< rdf::XURI
> >
393 getAllParts(struct DocumentMetadataAccess_Impl
const & i_rImpl
)
395 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
397 const uno::Reference
<container::XEnumeration
> xEnum(
398 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
,
399 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), nullptr),
401 while (xEnum
->hasMoreElements()) {
403 if (!(xEnum
->nextElement() >>= stmt
)) {
404 throw uno::RuntimeException();
406 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
408 if (!xPart
.is()) continue;
409 ret
.push_back(xPart
);
412 } catch (const uno::RuntimeException
&) {
414 } catch (const uno::Exception
&) {
415 css::uno::Any anyEx
= cppu::getCaughtException();
416 throw lang::WrappedTargetRuntimeException(
417 "getAllParts: exception",
423 isPartOfType(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
424 uno::Reference
<rdf::XURI
> const & i_xPart
,
425 uno::Reference
<rdf::XURI
> const & i_xType
)
427 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
429 const uno::Reference
<container::XEnumeration
> xEnum(
430 i_rImpl
.m_xManifest
->getStatements(i_xPart
,
431 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
434 return xEnum
->hasMoreElements();
435 } catch (const uno::RuntimeException
&) {
437 } catch (const uno::Exception
&) {
438 css::uno::Any anyEx
= cppu::getCaughtException();
439 throw lang::WrappedTargetRuntimeException(
440 "isPartOfType: exception",
445 static ::std::vector
<uno::Reference
<rdf::XURI
>>
446 getAllParts(struct DocumentMetadataAccess_Impl
const& i_rImpl
,
447 const uno::Reference
<rdf::XURI
>& i_xType
)
449 ::std::vector
<uno::Reference
<rdf::XURI
>> ret
;
452 const uno::Reference
<container::XEnumeration
> xEnum(
453 i_rImpl
.m_xManifest
->getStatements(i_rImpl
.m_xBaseURI
,
454 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
457 while (xEnum
->hasMoreElements())
460 if (!(xEnum
->nextElement() >>= stmt
))
462 throw uno::RuntimeException();
464 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
, uno::UNO_QUERY
);
468 const uno::Reference
<container::XEnumeration
> xEnum2(
469 i_rImpl
.m_xManifest
->getStatements(
470 xPart
, getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), i_xType
),
472 if (xEnum2
->hasMoreElements())
473 ret
.emplace_back(xPart
);
477 catch (const uno::RuntimeException
&)
481 catch (const uno::Exception
& e
)
483 throw lang::WrappedTargetRuntimeException("getAllParts: exception", nullptr,
488 static ucb::InteractiveAugmentedIOException
489 mkException( OUString
const & i_rMessage
,
490 ucb::IOErrorCode
const i_ErrorCode
,
491 OUString
const & i_rUri
, OUString
const & i_rResource
)
493 ucb::InteractiveAugmentedIOException iaioe
;
494 iaioe
.Message
= i_rMessage
;
495 iaioe
.Classification
= task::InteractionClassification_ERROR
;
496 iaioe
.Code
= i_ErrorCode
;
498 const beans::PropertyValue
uriProp("Uri",
499 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
500 const beans::PropertyValue
rnProp(
502 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
503 iaioe
.Arguments
= { uno::makeAny(uriProp
), uno::makeAny(rnProp
) };
507 /** error handling policy.
508 <p>If a handler is given, ask it how to proceed:
509 <ul><li>(default:) cancel import, raise exception</li>
510 <li>ignore the error and continue</li>
511 <li>retry the action that led to the error</li></ul></p>
512 N.B.: must not be called before DMA is fully initialized!
513 @returns true iff caller should retry
516 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
517 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
519 if (!i_xHandler
.is()) {
520 throw lang::WrappedTargetException(
521 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
522 /* *this*/ nullptr, uno::makeAny(i_rException
));
525 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
526 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
527 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
528 new ::comphelper::OInteractionRetry
);
529 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
530 new ::comphelper::OInteractionApprove
);
531 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
532 new ::comphelper::OInteractionAbort
);
534 pRequest
->addContinuation( pApprove
);
535 pRequest
->addContinuation( pAbort
);
536 // actually call the handler
537 i_xHandler
->handle( pRequest
);
538 if (pRetry
->wasSelected()) {
540 } else if (pApprove
->wasSelected()) {
543 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
544 throw lang::WrappedTargetException(
545 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
546 /* *this*/ nullptr, uno::makeAny(i_rException
));
550 /** check if storage has content.xml/styles.xml;
551 e.g. ODB files seem to only have content.xml */
553 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
554 std::set
< OUString
> & o_rFiles
)
557 if (i_xStorage
->hasByName(s_content
) &&
558 i_xStorage
->isStreamElement(s_content
))
560 o_rFiles
.insert(s_content
);
562 if (i_xStorage
->hasByName(s_styles
) &&
563 i_xStorage
->isStreamElement(s_styles
))
565 o_rFiles
.insert(s_styles
);
567 } catch (const uno::Exception
&) {
568 TOOLS_WARN_EXCEPTION("sfx", "collectFilesFromStorage");
572 /** import a metadata file into repository */
574 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
575 uno::Reference
< embed::XStorage
> const & i_xStorage
,
576 OUString
const & i_rPath
,
577 OUString
const & i_rBaseURI
)
582 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
584 if (!i_xStorage
->isStreamElement(i_rPath
)) {
586 "readStream: is not a stream",
587 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
589 const uno::Reference
<io::XStream
> xStream(
590 i_xStorage
->openStreamElement(i_rPath
,
591 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
592 const uno::Reference
<io::XInputStream
> xInStream(
593 xStream
->getInputStream(), uno::UNO_SET_THROW
);
594 const uno::Reference
<rdf::XURI
> xBaseURI(
595 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
596 const uno::Reference
<rdf::XURI
> xURI(
597 rdf::URI::createNS(i_rImpl
.m_xContext
,
598 i_rBaseURI
, i_rPath
));
599 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
600 xInStream
, xURI
, xBaseURI
);
602 if (!i_xStorage
->isStorageElement(dir
)) {
604 "readStream: is not a directory",
605 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
607 const uno::Reference
<embed::XStorage
> xDir(
608 i_xStorage
->openStorageElement(dir
,
609 embed::ElementModes::READ
));
610 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
611 uno::UNO_QUERY_THROW
);
614 xDirProps
->getPropertyValue(
615 utl::MediaDescriptor::PROP_MEDIATYPE
)
617 if (mimeType
.startsWith(s_odfmime
)) {
618 SAL_WARN("sfx", "readStream: refusing to recurse into embedded document");
621 } catch (const uno::Exception
&) { }
622 readStream(i_rImpl
, xDir
, rest
, i_rBaseURI
+dir
+"/" );
624 } catch (const container::NoSuchElementException
& e
) {
625 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
626 i_rBaseURI
+ i_rPath
, i_rPath
);
627 } catch (const io::IOException
& e
) {
628 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
629 i_rBaseURI
+ i_rPath
, i_rPath
);
630 } catch (const rdf::ParseException
& e
) {
631 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
632 i_rBaseURI
+ i_rPath
, i_rPath
);
636 /** import a metadata file into repository */
638 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
639 uno::Reference
<embed::XStorage
> const & i_xStorage
,
640 OUString
const & i_rBaseURI
,
641 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
642 const OUString
& i_rPath
)
646 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
647 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
648 if (handleError(e
, i_xHandler
)) goto retry
;
649 } catch (const uno::RuntimeException
&) {
651 } catch (const uno::Exception
&) {
652 css::uno::Any anyEx
= cppu::getCaughtException();
653 throw lang::WrappedTargetRuntimeException(
654 "importFile: exception",
659 /** actually write a metadata file to the storage */
661 exportStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
662 uno::Reference
< embed::XStorage
> const & i_xStorage
,
663 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
664 OUString
const & i_rFileName
,
665 OUString
const & i_rBaseURI
)
667 const uno::Reference
<io::XStream
> xStream(
668 i_xStorage
->openStreamElement(i_rFileName
,
669 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
671 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
673 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
674 xStreamProps
->setPropertyValue(
676 uno::makeAny(OUString("application/rdf+xml")));
678 const uno::Reference
<io::XOutputStream
> xOutStream(
679 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
680 const uno::Reference
<rdf::XURI
> xBaseURI(
681 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
682 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
683 xOutStream
, i_xGraphName
, xBaseURI
);
686 /** write a metadata file to the storage */
688 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
689 uno::Reference
< embed::XStorage
> const & i_xStorage
,
690 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
691 OUString
const & i_rPath
,
692 OUString
const & i_rBaseURI
)
696 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
699 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
702 const uno::Reference
<embed::XStorage
> xDir(
703 i_xStorage
->openStorageElement(dir
,
704 embed::ElementModes::WRITE
));
705 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
706 uno::UNO_QUERY_THROW
);
709 xDirProps
->getPropertyValue(
710 utl::MediaDescriptor::PROP_MEDIATYPE
)
712 if (mimeType
.startsWith(s_odfmime
)) {
713 SAL_WARN("sfx", "writeStream: refusing to recurse into embedded document");
716 } catch (const uno::Exception
&) { }
717 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
, i_rBaseURI
+dir
+"/");
718 uno::Reference
<embed::XTransactedObject
> const xTransaction(
719 xDir
, uno::UNO_QUERY
);
720 if (xTransaction
.is()) {
721 xTransaction
->commit();
724 } catch (const uno::RuntimeException
&) {
726 } catch (const io::IOException
&) {
732 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
733 const uno::Reference
< embed::XStorage
> & i_xStorage
,
734 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
735 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
739 i_rImpl
.m_xManifest
.clear();
741 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
744 i_rImpl
.m_xRepository
.clear();
745 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
748 // try to delay raising errors until after initialization is done
750 ucb::InteractiveAugmentedIOException iaioe
;
753 const uno::Reference
<rdf::XURI
> xManifest(
754 getURIForStream(i_rImpl
, s_manifest
));
756 readStream(i_rImpl
, i_xStorage
, s_manifest
, i_xBaseURI
->getStringValue());
757 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
758 // no manifest.rdf: this is not an error in ODF < 1.2
759 if (ucb::IOErrorCode_NOT_EXISTING_PATH
!= e
.Code
) {
763 } catch (const uno::Exception
& e
) {
767 // init manifest graph
768 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
769 i_rImpl
.m_xRepository
->getGraph(xManifest
));
770 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
771 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
773 // document statement
774 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
775 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
776 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
));
778 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
779 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
780 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
782 if (rterr
.hasValue()) {
783 throw lang::WrappedTargetRuntimeException(
784 "DocumentMetadataAccess::loadMetadataFromStorage: "
785 "exception", nullptr, rterr
);
788 if (err
&& handleError(iaioe
, i_xHandler
))
792 /** init Impl struct */
793 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
797 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
798 getURIForStream(i_rImpl
, s_manifest
)),
801 // insert the document statement
802 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
,
803 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
804 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
));
805 } catch (const uno::Exception
&) {
806 css::uno::Any anyEx
= cppu::getCaughtException();
807 throw lang::WrappedTargetRuntimeException(
808 "init: unexpected exception", nullptr,
812 // add top-level content files
813 if (!addContentOrStylesFileImpl(i_rImpl
, s_content
)) {
814 throw uno::RuntimeException();
816 if (!addContentOrStylesFileImpl(i_rImpl
, s_styles
)) {
817 throw uno::RuntimeException();
822 DocumentMetadataAccess::DocumentMetadataAccess(
823 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
824 const SfxObjectShell
& i_rRegistrySupplier
)
825 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
827 // no initialization: must call loadFrom...
830 DocumentMetadataAccess::DocumentMetadataAccess(
831 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
832 const SfxObjectShell
& i_rRegistrySupplier
,
833 OUString
const & i_rURI
)
834 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
836 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
837 OSL_ENSURE(i_rURI
.endsWith("/"), "DMA::DMA: URI without / given!");
838 if (!i_rURI
.endsWith("/")) throw uno::RuntimeException();
839 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
840 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
846 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
847 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
848 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
851 DocumentMetadataAccess::~DocumentMetadataAccess()
855 // css::rdf::XRepositorySupplier:
856 uno::Reference
< rdf::XRepository
> SAL_CALL
857 DocumentMetadataAccess::getRDFRepository()
859 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
860 return m_pImpl
->m_xRepository
;
865 DocumentMetadataAccess::getStringValue()
867 return m_pImpl
->m_xBaseURI
->getStringValue();
872 DocumentMetadataAccess::getNamespace()
874 return m_pImpl
->m_xBaseURI
->getNamespace();
878 DocumentMetadataAccess::getLocalName()
880 return m_pImpl
->m_xBaseURI
->getLocalName();
883 // css::rdf::XDocumentMetadataAccess:
884 uno::Reference
< rdf::XMetadatable
> SAL_CALL
885 DocumentMetadataAccess::getElementByMetadataReference(
886 const css::beans::StringPair
& i_rReference
)
888 const IXmlIdRegistry
* pReg(
889 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
891 throw uno::RuntimeException(
892 "DocumentMetadataAccess::getElementByXmlId: no registry", *this);
894 return pReg
->GetElementByMetadataReference(i_rReference
);
897 uno::Reference
< rdf::XMetadatable
> SAL_CALL
898 DocumentMetadataAccess::getElementByURI(
899 const uno::Reference
< rdf::XURI
> & i_xURI
)
902 throw lang::IllegalArgumentException(
903 "DocumentMetadataAccess::getElementByURI: URI is null", *this, 0);
906 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
907 const OUString
name( i_xURI
->getStringValue() );
908 if (!name
.match(baseURI
)) {
913 if (!splitXmlId(name
.copy(baseURI
.getLength()), path
, idref
)) {
917 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
920 uno::Sequence
<uno::Reference
<rdf::XURI
>> SAL_CALL
921 DocumentMetadataAccess::getMetadataGraphsWithType(const uno::Reference
<rdf::XURI
>& i_xType
)
925 throw lang::IllegalArgumentException("DocumentMetadataAccess::getMetadataGraphsWithType: "
930 return ::comphelper::containerToSequence(getAllParts(*m_pImpl
, i_xType
));
933 uno::Reference
<rdf::XURI
> SAL_CALL
934 DocumentMetadataAccess::addMetadataFile(const OUString
& i_rFileName
,
935 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
937 if (!isFileNameValid(i_rFileName
)) {
938 throw lang::IllegalArgumentException(
939 "DocumentMetadataAccess::addMetadataFile: invalid FileName",
942 if (isReservedFile(i_rFileName
)) {
943 throw lang::IllegalArgumentException(
944 "DocumentMetadataAccess::addMetadataFile:"
945 "invalid FileName: reserved", *this, 0);
947 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
948 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
949 throw lang::IllegalArgumentException(
950 "DocumentMetadataAccess::addMetadataFile: "
951 "null type", *this, 2);
954 const uno::Reference
<rdf::XURI
> xGraphName(
955 getURIForStream(*m_pImpl
, i_rFileName
) );
958 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
959 } catch (const rdf::RepositoryException
&) {
960 css::uno::Any anyEx
= cppu::getCaughtException();
961 throw lang::WrappedTargetRuntimeException(
962 "DocumentMetadataAccess::addMetadataFile: exception",
964 // note: all other exceptions are propagated
967 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
971 uno::Reference
<rdf::XURI
> SAL_CALL
972 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
973 const uno::Reference
< io::XInputStream
> & i_xInStream
,
974 const OUString
& i_rFileName
,
975 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
976 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
978 if (!isFileNameValid(i_rFileName
)) {
979 throw lang::IllegalArgumentException(
980 "DocumentMetadataAccess::importMetadataFile: invalid FileName",
983 if (isReservedFile(i_rFileName
)) {
984 throw lang::IllegalArgumentException(
985 "DocumentMetadataAccess::importMetadataFile:"
986 "invalid FileName: reserved", *this, 0);
988 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
989 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
990 throw lang::IllegalArgumentException(
991 "DocumentMetadataAccess::importMetadataFile: null type",
995 const uno::Reference
<rdf::XURI
> xGraphName(
996 getURIForStream(*m_pImpl
, i_rFileName
) );
999 m_pImpl
->m_xRepository
->importGraph(
1000 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
1001 } catch (const rdf::RepositoryException
&) {
1002 css::uno::Any anyEx
= cppu::getCaughtException();
1003 throw lang::WrappedTargetRuntimeException(
1004 "DocumentMetadataAccess::importMetadataFile: "
1005 "RepositoryException", *this, anyEx
);
1006 // note: all other exceptions are propagated
1010 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1015 DocumentMetadataAccess::removeMetadataFile(
1016 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1019 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1020 } catch (const rdf::RepositoryException
&) {
1021 css::uno::Any anyEx
= cppu::getCaughtException();
1022 throw lang::WrappedTargetRuntimeException(
1023 "DocumentMetadataAccess::removeMetadataFile: "
1024 "RepositoryException", *this, anyEx
);
1025 // note: all other exceptions are propagated
1028 // remove file from manifest
1029 removeFile(*m_pImpl
, i_xGraphName
);
1033 DocumentMetadataAccess::addContentOrStylesFile(
1034 const OUString
& i_rFileName
)
1036 if (!isFileNameValid(i_rFileName
)) {
1037 throw lang::IllegalArgumentException(
1038 "DocumentMetadataAccess::addContentOrStylesFile: "
1039 "invalid FileName", *this, 0);
1042 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1043 throw lang::IllegalArgumentException(
1044 "DocumentMetadataAccess::addContentOrStylesFile: "
1045 "invalid FileName: must end with content.xml or styles.xml",
1051 DocumentMetadataAccess::removeContentOrStylesFile(
1052 const OUString
& i_rFileName
)
1054 if (!isFileNameValid(i_rFileName
)) {
1055 throw lang::IllegalArgumentException(
1056 "DocumentMetadataAccess::removeContentOrStylesFile: "
1057 "invalid FileName", *this, 0);
1061 const uno::Reference
<rdf::XURI
> xPart(
1062 getURIForStream(*m_pImpl
, i_rFileName
) );
1063 const uno::Reference
<container::XEnumeration
> xEnum(
1064 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
,
1065 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1067 uno::UNO_SET_THROW
);
1068 if (!xEnum
->hasMoreElements()) {
1069 throw container::NoSuchElementException(
1070 "DocumentMetadataAccess::removeContentOrStylesFile: "
1071 "cannot find stream in manifest graph: " + i_rFileName
,
1075 // remove file from manifest
1076 removeFile(*m_pImpl
, xPart
);
1078 } catch (const uno::RuntimeException
&) {
1080 } catch (const uno::Exception
&) {
1081 css::uno::Any anyEx
= cppu::getCaughtException();
1082 throw lang::WrappedTargetRuntimeException(
1083 "DocumentMetadataAccess::removeContentOrStylesFile: exception",
1088 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1089 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1090 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1091 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1093 if (!i_xStorage
.is()) {
1094 throw lang::IllegalArgumentException(
1095 "DocumentMetadataAccess::loadMetadataFromStorage: "
1096 "storage is null", *this, 0);
1098 if (!i_xBaseURI
.is()) {
1099 throw lang::IllegalArgumentException(
1100 "DocumentMetadataAccess::loadMetadataFromStorage: "
1101 "base URI is null", *this, 1);
1103 const OUString
baseURI( i_xBaseURI
->getStringValue());
1104 if (baseURI
.indexOf('#') >= 0) {
1105 throw lang::IllegalArgumentException(
1106 "DocumentMetadataAccess::loadMetadataFromStorage: "
1107 "base URI not absolute", *this, 1);
1109 if (!baseURI
.endsWith("/")) {
1110 throw lang::IllegalArgumentException(
1111 "DocumentMetadataAccess::loadMetadataFromStorage: "
1112 "base URI does not end with slash", *this, 1);
1115 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1117 std::set
< OUString
> StgFiles
;
1118 collectFilesFromStorage(i_xStorage
, StgFiles
);
1120 std::vector
< OUString
> MfstMetadataFiles
;
1123 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1124 getAllParts(*m_pImpl
) );
1125 const uno::Reference
<rdf::XURI
>& xContentFile(
1126 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1127 const uno::Reference
<rdf::XURI
>& xStylesFile(
1128 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1129 const uno::Reference
<rdf::XURI
>& xMetadataFile(
1130 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1131 const sal_Int32
len( baseURI
.getLength() );
1132 for (const auto& rxPart
: parts
) {
1133 const OUString
name(rxPart
->getStringValue());
1134 if (!name
.match(baseURI
)) {
1135 SAL_WARN("sfx", "loadMetadataFromStorage: graph not in document: " << name
);
1138 const OUString
relName( name
.copy(len
) );
1139 if (relName
== s_manifest
) {
1140 SAL_WARN("sfx", "loadMetadataFromStorage: found ourselves a recursive manifest!");
1143 // remove found items from StgFiles
1144 StgFiles
.erase(relName
);
1145 if (isContentFile(relName
)) {
1146 if (!isPartOfType(*m_pImpl
, rxPart
, xContentFile
)) {
1147 const uno::Reference
<rdf::XURI
> xName(
1148 getURIForStream(*m_pImpl
, relName
) );
1149 // add missing type statement
1150 m_pImpl
->m_xManifest
->addStatement(xName
,
1151 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1154 } else if (isStylesFile(relName
)) {
1155 if (!isPartOfType(*m_pImpl
, rxPart
, xStylesFile
)) {
1156 const uno::Reference
<rdf::XURI
> xName(
1157 getURIForStream(*m_pImpl
, relName
) );
1158 // add missing type statement
1159 m_pImpl
->m_xManifest
->addStatement(xName
,
1160 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1163 } else if (isReservedFile(relName
)) {
1164 SAL_WARN("sfx", "loadMetadataFromStorage: reserved file name in manifest");
1166 if (isPartOfType(*m_pImpl
, rxPart
, xMetadataFile
)) {
1167 MfstMetadataFiles
.push_back(relName
);
1169 // do not add statement for MetadataFile; it could be
1170 // something else! just ignore it...
1173 } catch (const uno::RuntimeException
&) {
1175 } catch (const uno::Exception
&) {
1176 css::uno::Any anyEx
= cppu::getCaughtException();
1177 throw lang::WrappedTargetRuntimeException(
1178 "DocumentMetadataAccess::loadMetadataFromStorage: "
1179 "exception", *this, anyEx
);
1182 for (const auto& aStgFile
: StgFiles
)
1183 addContentOrStylesFileImpl(*m_pImpl
, aStgFile
);
1185 for (const auto& aMfstMetadataFile
: MfstMetadataFiles
)
1186 importFile(*m_pImpl
, i_xStorage
, baseURI
, i_xHandler
, aMfstMetadataFile
);
1189 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1190 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1192 if (!i_xStorage
.is()) {
1193 throw lang::IllegalArgumentException(
1194 "DocumentMetadataAccess::storeMetadataToStorage: "
1195 "storage is null", *this, 0);
1199 const uno::Reference
<rdf::XURI
> xManifest(
1200 getURIForStream(*m_pImpl
, s_manifest
) );
1201 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1203 writeStream(*m_pImpl
, i_xStorage
, xManifest
, s_manifest
, baseURI
);
1204 } catch (const uno::RuntimeException
&) {
1206 } catch (const io::IOException
&) {
1207 css::uno::Any anyEx
= cppu::getCaughtException();
1208 throw lang::WrappedTargetException(
1209 "storeMetadataToStorage: IO exception", *this, anyEx
);
1210 } catch (const uno::Exception
&) {
1211 css::uno::Any anyEx
= cppu::getCaughtException();
1212 throw lang::WrappedTargetRuntimeException(
1213 "storeMetadataToStorage: exception", *this, anyEx
);
1216 // export metadata streams
1218 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1219 m_pImpl
->m_xRepository
->getGraphNames());
1220 const sal_Int32
len( baseURI
.getLength() );
1221 for (const uno::Reference
<rdf::XURI
>& xName
: graphs
) {
1222 const OUString
name(xName
->getStringValue());
1223 if (!name
.match(baseURI
)) {
1224 SAL_WARN("sfx", "storeMetadataToStorage: graph not in document: " << name
);
1227 const OUString
relName( name
.copy(len
) );
1228 if (relName
== s_manifest
) {
1231 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1232 SAL_WARN("sfx", "storeMetadataToStorage: invalid file name: " << relName
);
1236 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1237 } catch (const uno::RuntimeException
&) {
1239 } catch (const io::IOException
&) {
1240 css::uno::Any anyEx
= cppu::getCaughtException();
1241 throw lang::WrappedTargetException(
1242 "storeMetadataToStorage: IO exception",
1244 } catch (const uno::Exception
&) {
1245 css::uno::Any anyEx
= cppu::getCaughtException();
1246 throw lang::WrappedTargetRuntimeException(
1247 "storeMetadataToStorage: exception",
1251 } catch (const rdf::RepositoryException
&) {
1252 css::uno::Any anyEx
= cppu::getCaughtException();
1253 throw lang::WrappedTargetRuntimeException(
1254 "storeMetadataToStorage: exception", *this, anyEx
);
1259 DocumentMetadataAccess::loadMetadataFromMedium(
1260 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1262 uno::Reference
<io::XInputStream
> xIn
;
1263 utl::MediaDescriptor
md(i_rMedium
);
1265 md
[ utl::MediaDescriptor::PROP_URL
] >>= URL
;
1267 md
[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL
] >>= BaseURL
;
1268 if (md
.addInputStream()) {
1269 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM
] >>= xIn
;
1271 if (!xIn
.is() && URL
.isEmpty()) {
1272 throw lang::IllegalArgumentException(
1273 "DocumentMetadataAccess::loadMetadataFromMedium: "
1274 "invalid medium: no URL, no input stream", *this, 0);
1276 uno::Reference
<embed::XStorage
> xStorage
;
1279 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1280 xIn
, m_pImpl
->m_xContext
);
1281 } else { // fallback to url
1282 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1283 URL
, embed::ElementModes::READ
, m_pImpl
->m_xContext
);
1285 } catch (const uno::RuntimeException
&) {
1287 } catch (const io::IOException
&) {
1289 } catch (const uno::Exception
&) {
1290 css::uno::Any anyEx
= cppu::getCaughtException();
1291 throw lang::WrappedTargetException(
1292 "DocumentMetadataAccess::loadMetadataFromMedium: "
1293 "exception", *this, anyEx
);
1295 if (!xStorage
.is()) {
1296 throw uno::RuntimeException(
1297 "DocumentMetadataAccess::loadMetadataFromMedium: "
1298 "cannot get Storage", *this);
1300 uno::Reference
<rdf::XURI
> xBaseURI
;
1302 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, BaseURL
);
1303 } catch (const uno::Exception
&) {
1306 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, URL
);
1307 } catch (const uno::Exception
&) {
1308 OSL_FAIL("cannot create base URI");
1311 uno::Reference
<task::XInteractionHandler
> xIH
;
1312 md
[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER
] >>= xIH
;
1313 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1317 DocumentMetadataAccess::storeMetadataToMedium(
1318 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1320 utl::MediaDescriptor
md(i_rMedium
);
1322 md
[ utl::MediaDescriptor::PROP_URL
] >>= URL
;
1323 if (URL
.isEmpty()) {
1324 throw lang::IllegalArgumentException(
1325 "DocumentMetadataAccess::storeMetadataToMedium: "
1326 "invalid medium: no URL", *this, 0);
1329 SfxMedium
aMedium(i_rMedium
);
1330 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1333 if (xStorage
.is()) {
1336 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1337 URL
, embed::ElementModes::WRITE
, m_pImpl
->m_xContext
);
1340 if (!xStorage
.is()) {
1341 throw uno::RuntimeException(
1342 "DocumentMetadataAccess::storeMetadataToMedium: "
1343 "cannot get Storage", *this);
1345 // set MIME type of the storage
1346 utl::MediaDescriptor::const_iterator iter
1347 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE
);
1348 if (iter
!= md
.end()) {
1349 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1350 uno::UNO_QUERY_THROW
);
1352 // this is NOT supported in FileSystemStorage
1353 xProps
->setPropertyValue(
1354 utl::MediaDescriptor::PROP_MEDIATYPE
,
1356 } catch (const uno::Exception
&) { }
1358 storeMetadataToStorage(xStorage
);
1363 const bool bOk
= aMedium
.Commit();
1366 ErrCode nError
= aMedium
.GetError();
1367 if ( nError
== ERRCODE_NONE
) {
1368 nError
= ERRCODE_IO_GENERAL
;
1370 task::ErrorCodeIOException
ex(
1371 "DocumentMetadataAccess::storeMetadataToMedium Commit failed: " + nError
.toHexString(),
1372 uno::Reference
< uno::XInterface
>(), sal_uInt32(nError
));
1373 throw lang::WrappedTargetException(OUString(), *this,
1380 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */