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>
60 #include <com/sun/star/uri/XUriReference.hpp>
61 #include <com/sun/star/uri/UriReferenceFactory.hpp>
65 Note: in the context of this implementation, all rdf.QueryExceptions and
66 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
68 This implementation assumes that it is only used with ODF documents, not mere
69 ODF packages. In other words, we enforce that metadata files must not be
70 called reserved names.
73 using namespace ::com::sun::star
;
78 bool isValidNCName(OUString
const & i_rIdref
)
81 OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
82 return !(xmlValidateNCName(
83 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
87 const char s_content
[] = "content.xml";
88 const char s_styles
[] = "styles.xml";
89 const char s_manifest
[] = "manifest.rdf";
90 const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
93 static bool isContentFile(OUString
const & i_rPath
)
95 return i_rPath
== s_content
;
98 static bool isStylesFile (OUString
const & i_rPath
)
100 return i_rPath
== s_styles
;
103 bool isValidXmlId(OUString
const & i_rStreamName
,
104 OUString
const & i_rIdref
)
106 return isValidNCName(i_rIdref
)
107 && (isContentFile(i_rStreamName
) || isStylesFile(i_rStreamName
));
110 static bool isReservedFile(OUString
const & i_rPath
)
112 return isContentFile(i_rPath
) || isStylesFile(i_rPath
) || i_rPath
== "meta.xml" || i_rPath
== "settings.xml";
116 uno::Reference
<rdf::XURI
> createBaseURI(
117 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
118 uno::Reference
<frame::XModel
> const & i_xModel
,
119 OUString
const & i_rPkgURI
, OUString
const & i_rSubDocument
)
121 if (!i_xContext
.is() || (!i_xModel
.is() && i_rPkgURI
.isEmpty())) {
122 throw uno::RuntimeException();
125 OUString
pkgURI(i_rPkgURI
);
127 // tdf#123293 chicken/egg problem when loading from stream: there is no URI,
128 // and also the model doesn't have a storage yet, so we need to get the
129 // tdoc URI without a storage...
130 if (pkgURI
.isEmpty())
132 assert(i_xModel
.is());
133 uno::Reference
<frame::XTransientDocumentsDocumentContentIdentifierFactory
>
135 i_xContext
->getServiceManager()->createInstanceWithContext(
136 "com.sun.star.ucb.TransientDocumentsContentProvider",
138 uno::UNO_QUERY_THROW
);
139 uno::Reference
<ucb::XContentIdentifier
> const xContentId(
140 xTDDCIF
->createDocumentContentIdentifier(i_xModel
));
141 SAL_WARN_IF(!xContentId
.is(), "sfx", "createBaseURI: cannot create ContentIdentifier");
142 if (!xContentId
.is())
144 throw uno::RuntimeException("createBaseURI: cannot create ContentIdentifier");
146 pkgURI
= xContentId
->getContentIdentifier();
147 assert(!pkgURI
.isEmpty());
148 if (!pkgURI
.isEmpty() && !pkgURI
.endsWith("/"))
154 // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
155 // this really should be done somewhere else, not here.
156 if (pkgURI
.matchIgnoreAsciiCase("vnd.sun.star.expand:"))
158 // expand it here (makeAbsolute requires hierarchical URI)
159 pkgURI
= pkgURI
.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
160 if (!pkgURI
.isEmpty()) {
161 pkgURI
= ::rtl::Uri::decode(
162 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
163 if (pkgURI
.isEmpty()) {
164 throw uno::RuntimeException();
166 ::rtl::Bootstrap::expandMacros(pkgURI
);
170 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory
=
171 uri::UriReferenceFactory::create( i_xContext
);
172 uno::Reference
< uri::XUriReference
> xBaseURI
;
174 const uno::Reference
< uri::XUriReference
> xPkgURI(
175 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
176 xPkgURI
->clearFragment();
178 // need to know whether the storage is a FileSystemStorage
179 // XServiceInfo would be better, but it is not implemented
180 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
182 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
184 OUStringBuffer
buf(64);
185 if (!xBaseURI
->getUriReference().endsWith("/"))
187 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
190 buf
.append(xBaseURI
->getPathSegment(count
- 1));
194 if (!i_rSubDocument
.isEmpty())
196 buf
.append(i_rSubDocument
);
201 const uno::Reference
< uri::XUriReference
> xPathURI(
202 xUriFactory
->parse(buf
.makeStringAndClear()), uno::UNO_SET_THROW
);
204 xUriFactory
->makeAbsolute(xBaseURI
, xPathURI
,
205 true, uri::RelativeUriExcessParentSegments_ERROR
),
209 return rdf::URI::create(i_xContext
, xBaseURI
->getUriReference());
213 struct DocumentMetadataAccess_Impl
215 // note: these are all initialized in constructor, and loadFromStorage
216 const uno::Reference
<uno::XComponentContext
> m_xContext
;
217 const SfxObjectShell
& m_rXmlIdRegistrySupplier
;
218 uno::Reference
<rdf::XURI
> m_xBaseURI
;
219 uno::Reference
<rdf::XRepository
> m_xRepository
;
220 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
221 DocumentMetadataAccess_Impl(
222 uno::Reference
<uno::XComponentContext
> const& i_xContext
,
223 SfxObjectShell
const & i_rRegistrySupplier
)
224 : m_xContext(i_xContext
)
225 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
230 OSL_ENSURE(m_xContext
.is(), "context null");
234 // this is... a hack.
235 template<sal_Int16 Constant
>
236 static uno::Reference
<rdf::XURI
> const &
237 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
239 static uno::Reference
< rdf::XURI
> xURI(
240 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_SET_THROW
);
245 /** would storing the file to a XStorage succeed? */
246 static bool isFileNameValid(const OUString
& i_rFileName
)
248 if (i_rFileName
.isEmpty()) return false;
249 if (i_rFileName
[0] == '/') return false; // no absolute paths!
252 const OUString
segment(
253 i_rFileName
.getToken(0, u
'/', idx
) );
254 if (segment
.isEmpty() || // no empty segments
255 segment
== "." || // no . segments
256 segment
== ".." || // no .. segments
257 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
258 segment
, false)) // no invalid characters
264 /** split a uri hierarchy into first segment and rest */
266 splitPath(OUString
const & i_rPath
,
267 OUString
& o_rDir
, OUString
& o_rRest
)
269 const sal_Int32
idx(i_rPath
.indexOf(u
'/'));
270 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
274 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
275 // input must not start or end with '/'
278 o_rDir
= i_rPath
.copy(0, idx
);
279 o_rRest
= i_rPath
.copy(idx
+1);
285 splitXmlId(OUString
const & i_XmlId
,
286 OUString
& o_StreamName
, OUString
& o_Idref
)
288 const sal_Int32
idx(i_XmlId
.indexOf(u
'#'));
289 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
292 o_StreamName
= i_XmlId
.copy(0, idx
);
293 o_Idref
= i_XmlId
.copy(idx
+1);
294 return isValidXmlId(o_StreamName
, o_Idref
);
299 static uno::Reference
<rdf::XURI
>
300 getURIForStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
301 OUString
const& i_rPath
)
303 const uno::Reference
<rdf::XURI
> xURI(
304 rdf::URI::createNS( i_rImpl
.m_xContext
,
305 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
310 /** add statements declaring i_xResource to be a file of type i_xType with
311 path i_rPath to manifest, with optional additional types i_pTypes */
313 addFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
314 uno::Reference
<rdf::XURI
> const& i_xType
,
315 OUString
const & i_rPath
,
316 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
)
319 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
322 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
323 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
325 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
326 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
329 for (const auto& rType
: *i_pTypes
) {
330 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
331 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
335 } catch (const uno::RuntimeException
&) {
337 } catch (const uno::Exception
&) {
338 css::uno::Any anyEx
= cppu::getCaughtException();
339 throw lang::WrappedTargetRuntimeException(
340 "addFile: exception", /*this*/nullptr, anyEx
);
344 /** add content.xml or styles.xml to manifest */
346 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
347 const OUString
& i_rPath
)
349 uno::Reference
<rdf::XURI
> xType
;
350 if (isContentFile(i_rPath
)) {
351 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
352 } else if (isStylesFile(i_rPath
)) {
353 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
357 addFile(i_rImpl
, xType
.get(), i_rPath
, nullptr);
361 /** add metadata file to manifest */
363 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
364 const OUString
& i_rPath
,
365 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
368 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
372 /** remove a file from the manifest */
374 removeFile(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
375 uno::Reference
<rdf::XURI
> const& i_xPart
)
377 if (!i_xPart
.is()) throw uno::RuntimeException();
379 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
.get(),
380 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
382 i_rImpl
.m_xManifest
->removeStatements(i_xPart
.get(),
383 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), nullptr);
384 } catch (const uno::RuntimeException
&) {
386 } catch (const uno::Exception
&) {
387 css::uno::Any anyEx
= cppu::getCaughtException();
388 throw lang::WrappedTargetRuntimeException(
389 "removeFile: exception",
394 static ::std::vector
< uno::Reference
< rdf::XURI
> >
395 getAllParts(struct DocumentMetadataAccess_Impl
const & i_rImpl
)
397 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
399 const uno::Reference
<container::XEnumeration
> xEnum(
400 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
.get(),
401 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), nullptr),
403 while (xEnum
->hasMoreElements()) {
405 if (!(xEnum
->nextElement() >>= stmt
)) {
406 throw uno::RuntimeException();
408 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
410 if (!xPart
.is()) continue;
411 ret
.push_back(xPart
);
414 } catch (const uno::RuntimeException
&) {
416 } catch (const uno::Exception
&) {
417 css::uno::Any anyEx
= cppu::getCaughtException();
418 throw lang::WrappedTargetRuntimeException(
419 "getAllParts: exception",
425 isPartOfType(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
426 uno::Reference
<rdf::XURI
> const & i_xPart
,
427 uno::Reference
<rdf::XURI
> const & i_xType
)
429 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
431 const uno::Reference
<container::XEnumeration
> xEnum(
432 i_rImpl
.m_xManifest
->getStatements(i_xPart
.get(),
433 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
436 return xEnum
->hasMoreElements();
437 } catch (const uno::RuntimeException
&) {
439 } catch (const uno::Exception
&) {
440 css::uno::Any anyEx
= cppu::getCaughtException();
441 throw lang::WrappedTargetRuntimeException(
442 "isPartOfType: exception",
447 static ::std::vector
<uno::Reference
<rdf::XURI
>>
448 getAllParts(struct DocumentMetadataAccess_Impl
const& i_rImpl
,
449 const uno::Reference
<rdf::XURI
>& i_xType
)
451 ::std::vector
<uno::Reference
<rdf::XURI
>> ret
;
454 const uno::Reference
<container::XEnumeration
> xEnum(
455 i_rImpl
.m_xManifest
->getStatements(i_rImpl
.m_xBaseURI
.get(),
456 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
459 while (xEnum
->hasMoreElements())
462 if (!(xEnum
->nextElement() >>= stmt
))
464 throw uno::RuntimeException();
466 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
, uno::UNO_QUERY
);
470 const uno::Reference
<container::XEnumeration
> xEnum2(
471 i_rImpl
.m_xManifest
->getStatements(
472 xPart
.get(), getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), i_xType
.get()),
474 if (xEnum2
->hasMoreElements())
475 ret
.emplace_back(xPart
);
479 catch (const uno::RuntimeException
&)
483 catch (const uno::Exception
& e
)
485 throw lang::WrappedTargetRuntimeException("getAllParts: exception", nullptr,
490 static ucb::InteractiveAugmentedIOException
491 mkException( OUString
const & i_rMessage
,
492 ucb::IOErrorCode
const i_ErrorCode
,
493 OUString
const & i_rUri
, OUString
const & i_rResource
)
495 ucb::InteractiveAugmentedIOException iaioe
;
496 iaioe
.Message
= i_rMessage
;
497 iaioe
.Classification
= task::InteractionClassification_ERROR
;
498 iaioe
.Code
= i_ErrorCode
;
500 const beans::PropertyValue
uriProp("Uri",
501 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
502 const beans::PropertyValue
rnProp(
504 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
505 iaioe
.Arguments
= { uno::makeAny(uriProp
), uno::makeAny(rnProp
) };
509 /** error handling policy.
510 <p>If a handler is given, ask it how to proceed:
511 <ul><li>(default:) cancel import, raise exception</li>
512 <li>ignore the error and continue</li>
513 <li>retry the action that led to the error</li></ul></p>
514 N.B.: must not be called before DMA is fully initialized!
515 @returns true iff caller should retry
518 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
519 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
521 if (!i_xHandler
.is()) {
522 throw lang::WrappedTargetException(
523 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
524 /* *this*/ nullptr, uno::makeAny(i_rException
));
527 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
528 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
529 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
530 new ::comphelper::OInteractionRetry
);
531 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
532 new ::comphelper::OInteractionApprove
);
533 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
534 new ::comphelper::OInteractionAbort
);
536 pRequest
->addContinuation( pApprove
.get() );
537 pRequest
->addContinuation( pAbort
.get() );
538 // actually call the handler
539 i_xHandler
->handle( pRequest
.get() );
540 if (pRetry
->wasSelected()) {
542 } else if (pApprove
->wasSelected()) {
545 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
546 throw lang::WrappedTargetException(
547 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
548 /* *this*/ nullptr, uno::makeAny(i_rException
));
552 /** check if storage has content.xml/styles.xml;
553 e.g. ODB files seem to only have content.xml */
555 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
556 std::set
< OUString
> & o_rFiles
)
558 static OUString
content(s_content
);
559 static OUString
styles(s_styles
);
561 if (i_xStorage
->hasByName(content
) &&
562 i_xStorage
->isStreamElement(content
))
564 o_rFiles
.insert(content
);
566 if (i_xStorage
->hasByName(styles
) &&
567 i_xStorage
->isStreamElement(styles
))
569 o_rFiles
.insert(styles
);
571 } catch (const uno::Exception
&) {
572 TOOLS_WARN_EXCEPTION("sfx", "collectFilesFromStorage");
576 /** import a metadata file into repository */
578 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
579 uno::Reference
< embed::XStorage
> const & i_xStorage
,
580 OUString
const & i_rPath
,
581 OUString
const & i_rBaseURI
)
586 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
588 if (!i_xStorage
->isStreamElement(i_rPath
)) {
590 "readStream: is not a stream",
591 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
593 const uno::Reference
<io::XStream
> xStream(
594 i_xStorage
->openStreamElement(i_rPath
,
595 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
596 const uno::Reference
<io::XInputStream
> xInStream(
597 xStream
->getInputStream(), uno::UNO_SET_THROW
);
598 const uno::Reference
<rdf::XURI
> xBaseURI(
599 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
600 const uno::Reference
<rdf::XURI
> xURI(
601 rdf::URI::createNS(i_rImpl
.m_xContext
,
602 i_rBaseURI
, i_rPath
));
603 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
604 xInStream
, xURI
, xBaseURI
);
606 if (!i_xStorage
->isStorageElement(dir
)) {
608 "readStream: is not a directory",
609 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
611 const uno::Reference
<embed::XStorage
> xDir(
612 i_xStorage
->openStorageElement(dir
,
613 embed::ElementModes::READ
));
614 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
615 uno::UNO_QUERY_THROW
);
618 xDirProps
->getPropertyValue(
619 utl::MediaDescriptor::PROP_MEDIATYPE() )
621 if (mimeType
.startsWith(s_odfmime
)) {
622 SAL_WARN("sfx", "readStream: refusing to recurse into embedded document");
625 } catch (const uno::Exception
&) { }
626 readStream(i_rImpl
, xDir
, rest
, i_rBaseURI
+dir
+"/" );
628 } catch (const container::NoSuchElementException
& e
) {
629 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
630 i_rBaseURI
+ i_rPath
, i_rPath
);
631 } catch (const io::IOException
& e
) {
632 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
633 i_rBaseURI
+ i_rPath
, i_rPath
);
634 } catch (const rdf::ParseException
& e
) {
635 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
636 i_rBaseURI
+ i_rPath
, i_rPath
);
640 /** import a metadata file into repository */
642 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
643 uno::Reference
<embed::XStorage
> const & i_xStorage
,
644 OUString
const & i_rBaseURI
,
645 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
646 const OUString
& i_rPath
)
650 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
651 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
652 if (handleError(e
, i_xHandler
)) goto retry
;
653 } catch (const uno::RuntimeException
&) {
655 } catch (const uno::Exception
&) {
656 css::uno::Any anyEx
= cppu::getCaughtException();
657 throw lang::WrappedTargetRuntimeException(
658 "importFile: exception",
663 /** actually write a metadata file to the storage */
665 exportStream(struct DocumentMetadataAccess_Impl
const & i_rImpl
,
666 uno::Reference
< embed::XStorage
> const & i_xStorage
,
667 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
668 OUString
const & i_rFileName
,
669 OUString
const & i_rBaseURI
)
671 const uno::Reference
<io::XStream
> xStream(
672 i_xStorage
->openStreamElement(i_rFileName
,
673 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
675 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
677 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
678 xStreamProps
->setPropertyValue(
680 uno::makeAny(OUString("application/rdf+xml")));
682 const uno::Reference
<io::XOutputStream
> xOutStream(
683 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
684 const uno::Reference
<rdf::XURI
> xBaseURI(
685 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
686 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
687 xOutStream
, i_xGraphName
, xBaseURI
);
690 /** write a metadata file to the storage */
692 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
693 uno::Reference
< embed::XStorage
> const & i_xStorage
,
694 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
695 OUString
const & i_rPath
,
696 OUString
const & i_rBaseURI
)
700 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
703 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
706 const uno::Reference
<embed::XStorage
> xDir(
707 i_xStorage
->openStorageElement(dir
,
708 embed::ElementModes::WRITE
));
709 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
710 uno::UNO_QUERY_THROW
);
713 xDirProps
->getPropertyValue(
714 utl::MediaDescriptor::PROP_MEDIATYPE() )
716 if (mimeType
.startsWith(s_odfmime
)) {
717 SAL_WARN("sfx", "writeStream: refusing to recurse into embedded document");
720 } catch (const uno::Exception
&) { }
721 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
, i_rBaseURI
+dir
+"/");
722 uno::Reference
<embed::XTransactedObject
> const xTransaction(
723 xDir
, uno::UNO_QUERY
);
724 if (xTransaction
.is()) {
725 xTransaction
->commit();
728 } catch (const uno::RuntimeException
&) {
730 } catch (const io::IOException
&) {
736 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
737 const uno::Reference
< embed::XStorage
> & i_xStorage
,
738 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
739 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
743 i_rImpl
.m_xManifest
.clear();
745 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
748 i_rImpl
.m_xRepository
.clear();
749 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
752 // try to delay raising errors until after initialization is done
754 ucb::InteractiveAugmentedIOException iaioe
;
757 const uno::Reference
<rdf::XURI
> xManifest(
758 getURIForStream(i_rImpl
, s_manifest
));
760 readStream(i_rImpl
, i_xStorage
, s_manifest
, i_xBaseURI
->getStringValue());
761 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
762 // no manifest.rdf: this is not an error in ODF < 1.2
763 if (ucb::IOErrorCode_NOT_EXISTING_PATH
!= e
.Code
) {
767 } catch (const uno::Exception
& e
) {
771 // init manifest graph
772 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
773 i_rImpl
.m_xRepository
->getGraph(xManifest
));
774 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
775 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
777 // document statement
778 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
779 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
780 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
782 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
783 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
784 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
786 if (rterr
.hasValue()) {
787 throw lang::WrappedTargetRuntimeException(
788 "DocumentMetadataAccess::loadMetadataFromStorage: "
789 "exception", nullptr, rterr
);
792 if (err
&& handleError(iaioe
, i_xHandler
))
796 /** init Impl struct */
797 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
801 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
802 getURIForStream(i_rImpl
, s_manifest
)),
805 // insert the document statement
806 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
807 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
808 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
809 } catch (const uno::Exception
&) {
810 css::uno::Any anyEx
= cppu::getCaughtException();
811 throw lang::WrappedTargetRuntimeException(
812 "init: unexpected exception", nullptr,
816 // add top-level content files
817 if (!addContentOrStylesFileImpl(i_rImpl
, s_content
)) {
818 throw uno::RuntimeException();
820 if (!addContentOrStylesFileImpl(i_rImpl
, s_styles
)) {
821 throw uno::RuntimeException();
826 DocumentMetadataAccess::DocumentMetadataAccess(
827 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
828 const SfxObjectShell
& i_rRegistrySupplier
)
829 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
831 // no initialization: must call loadFrom...
834 DocumentMetadataAccess::DocumentMetadataAccess(
835 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
836 const SfxObjectShell
& i_rRegistrySupplier
,
837 OUString
const & i_rURI
)
838 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
840 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
841 OSL_ENSURE(i_rURI
.endsWith("/"), "DMA::DMA: URI without / given!");
842 if (!i_rURI
.endsWith("/")) throw uno::RuntimeException();
843 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
844 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
850 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
851 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
852 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
855 DocumentMetadataAccess::~DocumentMetadataAccess()
859 // css::rdf::XRepositorySupplier:
860 uno::Reference
< rdf::XRepository
> SAL_CALL
861 DocumentMetadataAccess::getRDFRepository()
863 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
864 return m_pImpl
->m_xRepository
;
869 DocumentMetadataAccess::getStringValue()
871 return m_pImpl
->m_xBaseURI
->getStringValue();
876 DocumentMetadataAccess::getNamespace()
878 return m_pImpl
->m_xBaseURI
->getNamespace();
882 DocumentMetadataAccess::getLocalName()
884 return m_pImpl
->m_xBaseURI
->getLocalName();
887 // css::rdf::XDocumentMetadataAccess:
888 uno::Reference
< rdf::XMetadatable
> SAL_CALL
889 DocumentMetadataAccess::getElementByMetadataReference(
890 const css::beans::StringPair
& i_rReference
)
892 const IXmlIdRegistry
* pReg(
893 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
895 throw uno::RuntimeException(
896 "DocumentMetadataAccess::getElementByXmlId: no registry", *this);
898 return pReg
->GetElementByMetadataReference(i_rReference
);
901 uno::Reference
< rdf::XMetadatable
> SAL_CALL
902 DocumentMetadataAccess::getElementByURI(
903 const uno::Reference
< rdf::XURI
> & i_xURI
)
906 throw lang::IllegalArgumentException(
907 "DocumentMetadataAccess::getElementByURI: URI is null", *this, 0);
910 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
911 const OUString
name( i_xURI
->getStringValue() );
912 if (!name
.match(baseURI
)) {
917 if (!splitXmlId(name
.copy(baseURI
.getLength()), path
, idref
)) {
921 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
924 uno::Sequence
<uno::Reference
<rdf::XURI
>> SAL_CALL
925 DocumentMetadataAccess::getMetadataGraphsWithType(const uno::Reference
<rdf::XURI
>& i_xType
)
929 throw lang::IllegalArgumentException("DocumentMetadataAccess::getMetadataGraphsWithType: "
934 return ::comphelper::containerToSequence(getAllParts(*m_pImpl
, i_xType
));
937 uno::Reference
<rdf::XURI
> SAL_CALL
938 DocumentMetadataAccess::addMetadataFile(const OUString
& i_rFileName
,
939 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
941 if (!isFileNameValid(i_rFileName
)) {
942 throw lang::IllegalArgumentException(
943 "DocumentMetadataAccess::addMetadataFile: invalid FileName",
946 if (isReservedFile(i_rFileName
)) {
947 throw lang::IllegalArgumentException(
948 "DocumentMetadataAccess::addMetadataFile:"
949 "invalid FileName: reserved", *this, 0);
951 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
952 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
953 throw lang::IllegalArgumentException(
954 "DocumentMetadataAccess::addMetadataFile: "
955 "null type", *this, 2);
958 const uno::Reference
<rdf::XURI
> xGraphName(
959 getURIForStream(*m_pImpl
, i_rFileName
) );
962 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
963 } catch (const rdf::RepositoryException
&) {
964 css::uno::Any anyEx
= cppu::getCaughtException();
965 throw lang::WrappedTargetRuntimeException(
966 "DocumentMetadataAccess::addMetadataFile: exception",
968 // note: all other exceptions are propagated
971 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
975 uno::Reference
<rdf::XURI
> SAL_CALL
976 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
977 const uno::Reference
< io::XInputStream
> & i_xInStream
,
978 const OUString
& i_rFileName
,
979 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
980 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
982 if (!isFileNameValid(i_rFileName
)) {
983 throw lang::IllegalArgumentException(
984 "DocumentMetadataAccess::importMetadataFile: invalid FileName",
987 if (isReservedFile(i_rFileName
)) {
988 throw lang::IllegalArgumentException(
989 "DocumentMetadataAccess::importMetadataFile:"
990 "invalid FileName: reserved", *this, 0);
992 if (std::any_of(i_rTypes
.begin(), i_rTypes
.end(),
993 [](const uno::Reference
< rdf::XURI
>& rType
) { return !rType
.is(); })) {
994 throw lang::IllegalArgumentException(
995 "DocumentMetadataAccess::importMetadataFile: null type",
999 const uno::Reference
<rdf::XURI
> xGraphName(
1000 getURIForStream(*m_pImpl
, i_rFileName
) );
1003 m_pImpl
->m_xRepository
->importGraph(
1004 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
1005 } catch (const rdf::RepositoryException
&) {
1006 css::uno::Any anyEx
= cppu::getCaughtException();
1007 throw lang::WrappedTargetRuntimeException(
1008 "DocumentMetadataAccess::importMetadataFile: "
1009 "RepositoryException", *this, anyEx
);
1010 // note: all other exceptions are propagated
1014 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1019 DocumentMetadataAccess::removeMetadataFile(
1020 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1023 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1024 } catch (const rdf::RepositoryException
&) {
1025 css::uno::Any anyEx
= cppu::getCaughtException();
1026 throw lang::WrappedTargetRuntimeException(
1027 "DocumentMetadataAccess::removeMetadataFile: "
1028 "RepositoryException", *this, anyEx
);
1029 // note: all other exceptions are propagated
1032 // remove file from manifest
1033 removeFile(*m_pImpl
, i_xGraphName
.get());
1037 DocumentMetadataAccess::addContentOrStylesFile(
1038 const OUString
& i_rFileName
)
1040 if (!isFileNameValid(i_rFileName
)) {
1041 throw lang::IllegalArgumentException(
1042 "DocumentMetadataAccess::addContentOrStylesFile: "
1043 "invalid FileName", *this, 0);
1046 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1047 throw lang::IllegalArgumentException(
1048 "DocumentMetadataAccess::addContentOrStylesFile: "
1049 "invalid FileName: must end with content.xml or styles.xml",
1055 DocumentMetadataAccess::removeContentOrStylesFile(
1056 const OUString
& i_rFileName
)
1058 if (!isFileNameValid(i_rFileName
)) {
1059 throw lang::IllegalArgumentException(
1060 "DocumentMetadataAccess::removeContentOrStylesFile: "
1061 "invalid FileName", *this, 0);
1065 const uno::Reference
<rdf::XURI
> xPart(
1066 getURIForStream(*m_pImpl
, i_rFileName
) );
1067 const uno::Reference
<container::XEnumeration
> xEnum(
1068 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
.get(),
1069 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1071 uno::UNO_SET_THROW
);
1072 if (!xEnum
->hasMoreElements()) {
1073 throw container::NoSuchElementException(
1074 "DocumentMetadataAccess::removeContentOrStylesFile: "
1075 "cannot find stream in manifest graph: " + i_rFileName
,
1079 // remove file from manifest
1080 removeFile(*m_pImpl
, xPart
);
1082 } catch (const uno::RuntimeException
&) {
1084 } catch (const uno::Exception
&) {
1085 css::uno::Any anyEx
= cppu::getCaughtException();
1086 throw lang::WrappedTargetRuntimeException(
1087 "DocumentMetadataAccess::removeContentOrStylesFile: exception",
1092 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1093 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1094 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1095 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1097 if (!i_xStorage
.is()) {
1098 throw lang::IllegalArgumentException(
1099 "DocumentMetadataAccess::loadMetadataFromStorage: "
1100 "storage is null", *this, 0);
1102 if (!i_xBaseURI
.is()) {
1103 throw lang::IllegalArgumentException(
1104 "DocumentMetadataAccess::loadMetadataFromStorage: "
1105 "base URI is null", *this, 1);
1107 const OUString
baseURI( i_xBaseURI
->getStringValue());
1108 if (baseURI
.indexOf('#') >= 0) {
1109 throw lang::IllegalArgumentException(
1110 "DocumentMetadataAccess::loadMetadataFromStorage: "
1111 "base URI not absolute", *this, 1);
1113 if (!baseURI
.endsWith("/")) {
1114 throw lang::IllegalArgumentException(
1115 "DocumentMetadataAccess::loadMetadataFromStorage: "
1116 "base URI does not end with slash", *this, 1);
1119 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1121 std::set
< OUString
> StgFiles
;
1122 collectFilesFromStorage(i_xStorage
, StgFiles
);
1124 std::vector
< OUString
> MfstMetadataFiles
;
1127 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1128 getAllParts(*m_pImpl
) );
1129 const uno::Reference
<rdf::XURI
>& xContentFile(
1130 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1131 const uno::Reference
<rdf::XURI
>& xStylesFile(
1132 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1133 const uno::Reference
<rdf::XURI
>& xMetadataFile(
1134 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1135 const sal_Int32
len( baseURI
.getLength() );
1136 for (const auto& rxPart
: parts
) {
1137 const OUString
name(rxPart
->getStringValue());
1138 if (!name
.match(baseURI
)) {
1139 SAL_WARN("sfx", "loadMetadataFromStorage: graph not in document: " << name
);
1142 const OUString
relName( name
.copy(len
) );
1143 if (relName
== s_manifest
) {
1144 SAL_WARN("sfx", "loadMetadataFromStorage: found ourselves a recursive manifest!");
1147 // remove found items from StgFiles
1148 StgFiles
.erase(relName
);
1149 if (isContentFile(relName
)) {
1150 if (!isPartOfType(*m_pImpl
, rxPart
, xContentFile
)) {
1151 const uno::Reference
<rdf::XURI
> xName(
1152 getURIForStream(*m_pImpl
, relName
) );
1153 // add missing type statement
1154 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1155 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1156 xContentFile
.get());
1158 } else if (isStylesFile(relName
)) {
1159 if (!isPartOfType(*m_pImpl
, rxPart
, xStylesFile
)) {
1160 const uno::Reference
<rdf::XURI
> xName(
1161 getURIForStream(*m_pImpl
, relName
) );
1162 // add missing type statement
1163 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1164 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1167 } else if (isReservedFile(relName
)) {
1168 SAL_WARN("sfx", "loadMetadataFromStorage: reserved file name in manifest");
1170 if (isPartOfType(*m_pImpl
, rxPart
, xMetadataFile
)) {
1171 MfstMetadataFiles
.push_back(relName
);
1173 // do not add statement for MetadataFile; it could be
1174 // something else! just ignore it...
1177 } catch (const uno::RuntimeException
&) {
1179 } catch (const uno::Exception
&) {
1180 css::uno::Any anyEx
= cppu::getCaughtException();
1181 throw lang::WrappedTargetRuntimeException(
1182 "DocumentMetadataAccess::loadMetadataFromStorage: "
1183 "exception", *this, anyEx
);
1186 for (const auto& aStgFile
: StgFiles
)
1187 addContentOrStylesFileImpl(*m_pImpl
, aStgFile
);
1189 for (const auto& aMfstMetadataFile
: MfstMetadataFiles
)
1190 importFile(*m_pImpl
, i_xStorage
, baseURI
, i_xHandler
, aMfstMetadataFile
);
1193 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1194 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1196 if (!i_xStorage
.is()) {
1197 throw lang::IllegalArgumentException(
1198 "DocumentMetadataAccess::storeMetadataToStorage: "
1199 "storage is null", *this, 0);
1203 const uno::Reference
<rdf::XURI
> xManifest(
1204 getURIForStream(*m_pImpl
, s_manifest
) );
1205 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1207 writeStream(*m_pImpl
, i_xStorage
, xManifest
, s_manifest
, baseURI
);
1208 } catch (const uno::RuntimeException
&) {
1210 } catch (const io::IOException
&) {
1211 css::uno::Any anyEx
= cppu::getCaughtException();
1212 throw lang::WrappedTargetException(
1213 "storeMetadataToStorage: IO exception", *this, anyEx
);
1214 } catch (const uno::Exception
&) {
1215 css::uno::Any anyEx
= cppu::getCaughtException();
1216 throw lang::WrappedTargetRuntimeException(
1217 "storeMetadataToStorage: exception", *this, anyEx
);
1220 // export metadata streams
1222 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1223 m_pImpl
->m_xRepository
->getGraphNames());
1224 const sal_Int32
len( baseURI
.getLength() );
1225 for (const uno::Reference
<rdf::XURI
>& xName
: graphs
) {
1226 const OUString
name(xName
->getStringValue());
1227 if (!name
.match(baseURI
)) {
1228 SAL_WARN("sfx", "storeMetadataToStorage: graph not in document: " << name
);
1231 const OUString
relName( name
.copy(len
) );
1232 if (relName
== s_manifest
) {
1235 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1236 SAL_WARN("sfx", "storeMetadataToStorage: invalid file name: " << relName
);
1240 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1241 } catch (const uno::RuntimeException
&) {
1243 } catch (const io::IOException
&) {
1244 css::uno::Any anyEx
= cppu::getCaughtException();
1245 throw lang::WrappedTargetException(
1246 "storeMetadataToStorage: IO exception",
1248 } catch (const uno::Exception
&) {
1249 css::uno::Any anyEx
= cppu::getCaughtException();
1250 throw lang::WrappedTargetRuntimeException(
1251 "storeMetadataToStorage: exception",
1255 } catch (const rdf::RepositoryException
&) {
1256 css::uno::Any anyEx
= cppu::getCaughtException();
1257 throw lang::WrappedTargetRuntimeException(
1258 "storeMetadataToStorage: exception", *this, anyEx
);
1263 DocumentMetadataAccess::loadMetadataFromMedium(
1264 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1266 uno::Reference
<io::XInputStream
> xIn
;
1267 utl::MediaDescriptor
md(i_rMedium
);
1269 md
[ utl::MediaDescriptor::PROP_URL() ] >>= URL
;
1271 md
[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL
;
1272 if (md
.addInputStream()) {
1273 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1275 if (!xIn
.is() && URL
.isEmpty()) {
1276 throw lang::IllegalArgumentException(
1277 "DocumentMetadataAccess::loadMetadataFromMedium: "
1278 "invalid medium: no URL, no input stream", *this, 0);
1280 uno::Reference
<embed::XStorage
> xStorage
;
1283 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1284 xIn
, m_pImpl
->m_xContext
);
1285 } else { // fallback to url
1286 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1287 URL
, embed::ElementModes::READ
, m_pImpl
->m_xContext
);
1289 } catch (const uno::RuntimeException
&) {
1291 } catch (const io::IOException
&) {
1293 } catch (const uno::Exception
&) {
1294 css::uno::Any anyEx
= cppu::getCaughtException();
1295 throw lang::WrappedTargetException(
1296 "DocumentMetadataAccess::loadMetadataFromMedium: "
1297 "exception", *this, anyEx
);
1299 if (!xStorage
.is()) {
1300 throw uno::RuntimeException(
1301 "DocumentMetadataAccess::loadMetadataFromMedium: "
1302 "cannot get Storage", *this);
1304 uno::Reference
<rdf::XURI
> xBaseURI
;
1306 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, BaseURL
);
1307 } catch (const uno::Exception
&) {
1310 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, nullptr, URL
);
1311 } catch (const uno::Exception
&) {
1312 OSL_FAIL("cannot create base URI");
1315 uno::Reference
<task::XInteractionHandler
> xIH
;
1316 md
[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH
;
1317 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1321 DocumentMetadataAccess::storeMetadataToMedium(
1322 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1324 utl::MediaDescriptor
md(i_rMedium
);
1326 md
[ utl::MediaDescriptor::PROP_URL() ] >>= URL
;
1327 if (URL
.isEmpty()) {
1328 throw lang::IllegalArgumentException(
1329 "DocumentMetadataAccess::storeMetadataToMedium: "
1330 "invalid medium: no URL", *this, 0);
1333 SfxMedium
aMedium(i_rMedium
);
1334 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1337 if (xStorage
.is()) {
1340 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1341 URL
, embed::ElementModes::WRITE
, m_pImpl
->m_xContext
);
1344 if (!xStorage
.is()) {
1345 throw uno::RuntimeException(
1346 "DocumentMetadataAccess::storeMetadataToMedium: "
1347 "cannot get Storage", *this);
1349 // set MIME type of the storage
1350 utl::MediaDescriptor::const_iterator iter
1351 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE());
1352 if (iter
!= md
.end()) {
1353 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1354 uno::UNO_QUERY_THROW
);
1356 // this is NOT supported in FileSystemStorage
1357 xProps
->setPropertyValue(
1358 utl::MediaDescriptor::PROP_MEDIATYPE(),
1360 } catch (const uno::Exception
&) { }
1362 storeMetadataToStorage(xStorage
);
1367 const bool bOk
= aMedium
.Commit();
1370 ErrCode nError
= aMedium
.GetError();
1371 if ( nError
== ERRCODE_NONE
) {
1372 nError
= ERRCODE_IO_GENERAL
;
1374 task::ErrorCodeIOException
ex(
1375 "DocumentMetadataAccess::storeMetadataToMedium Commit failed: " + nError
.toHexString(),
1376 uno::Reference
< uno::XInterface
>(), sal_uInt32(nError
));
1377 throw lang::WrappedTargetException(OUString(), *this,
1384 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */