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/task/ErrorCodeIOException.hpp>
29 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
30 #include <com/sun/star/rdf/FileFormat.hpp>
31 #include <com/sun/star/rdf/URIs.hpp>
32 #include <com/sun/star/rdf/Statement.hpp>
33 #include <com/sun/star/rdf/Literal.hpp>
34 #include <com/sun/star/rdf/URI.hpp>
35 #include <com/sun/star/rdf/Repository.hpp>
37 #include <rtl/ustrbuf.hxx>
38 #include <rtl/uri.hxx>
39 #include <rtl/bootstrap.hxx>
41 #include <comphelper/interaction.hxx>
42 #include <comphelper/makesequence.hxx>
43 #include <unotools/mediadescriptor.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <comphelper/storagehelper.hxx>
47 #include <sfx2/docfile.hxx>
48 #include <sfx2/XmlIdRegistry.hxx>
50 #include <libxml/tree.h>
52 #include <boost/bind.hpp>
53 #include <boost/shared_array.hpp>
54 #include <boost/tuple/tuple.hpp>
62 #include <unotools/ucbhelper.hxx>
63 #include <com/sun/star/uri/XUriReference.hpp>
64 #include <com/sun/star/uri/UriReferenceFactory.hpp>
65 #include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
69 Note: in the context of this implementation, all rdf.QueryExceptions and
70 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
72 This implementation assumes that it is only used with ODF documents, not mere
73 ODF packages. In other words, we enforce that metadata files must not be
74 called reserved names.
77 using namespace ::com::sun::star
;
82 bool isValidNCName(OUString
const & i_rIdref
)
85 OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
86 return !(xmlValidateNCName(
87 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
91 static const char s_content
[] = "content.xml";
92 static const char s_styles
[] = "styles.xml";
93 static const char s_meta
[] = "meta.xml";
94 static const char s_settings
[] = "settings.xml";
95 static const char s_manifest
[] = "manifest.rdf";
96 static const char s_rdfxml
[] = "application/rdf+xml";
97 static const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
100 static bool isContentFile(OUString
const & i_rPath
)
102 return i_rPath
== s_content
;
105 static bool isStylesFile (OUString
const & i_rPath
)
107 return i_rPath
== s_styles
;
110 bool isValidXmlId(OUString
const & i_rStreamName
,
111 OUString
const & i_rIdref
)
113 return isValidNCName(i_rIdref
)
114 && (isContentFile(i_rStreamName
) || isStylesFile(i_rStreamName
));
117 static bool isReservedFile(OUString
const & i_rPath
)
119 return isContentFile(i_rPath
) || isStylesFile(i_rPath
) || i_rPath
== s_meta
|| i_rPath
== s_settings
;
123 uno::Reference
<rdf::XURI
> createBaseURI(
124 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
125 uno::Reference
<embed::XStorage
> const & i_xStorage
,
126 OUString
const & i_rPkgURI
, OUString
const & i_rSubDocument
)
128 if (!i_xContext
.is() || !i_xStorage
.is() || i_rPkgURI
.isEmpty()) {
129 throw uno::RuntimeException();
132 // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
133 // this really should be done somewhere else, not here.
134 OUString
pkgURI(i_rPkgURI
);
135 if (pkgURI
.matchIgnoreAsciiCase("vnd.sun.star.expand:"))
137 // expand it here (makeAbsolute requires hierarchical URI)
138 pkgURI
= pkgURI
.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
139 if (!pkgURI
.isEmpty()) {
140 pkgURI
= ::rtl::Uri::decode(
141 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
142 if (pkgURI
.isEmpty()) {
143 throw uno::RuntimeException();
145 ::rtl::Bootstrap::expandMacros(pkgURI
);
149 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory
=
150 uri::UriReferenceFactory::create( i_xContext
);
151 uno::Reference
< uri::XUriReference
> xBaseURI
;
153 const uno::Reference
< uri::XUriReference
> xPkgURI(
154 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
155 xPkgURI
->clearFragment();
157 // need to know whether the storage is a FileSystemStorage
158 // XServiceInfo would be better, but it is not implemented
159 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
161 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
164 if (!xBaseURI
->getUriReference().endsWith("/"))
166 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
169 const OUString
last( xBaseURI
->getPathSegment(count
- 1) );
174 if (!i_rSubDocument
.isEmpty())
176 buf
.append(i_rSubDocument
);
179 const OUString
Path(buf
.makeStringAndClear());
182 const uno::Reference
< uri::XUriReference
> xPathURI(
183 xUriFactory
->parse(Path
), uno::UNO_SET_THROW
);
185 xUriFactory
->makeAbsolute(xBaseURI
, xPathURI
,
186 true, uri::RelativeUriExcessParentSegments_ERROR
),
190 return rdf::URI::create(i_xContext
, xBaseURI
->getUriReference());
194 struct DocumentMetadataAccess_Impl
196 // note: these are all initialized in constructor, and loadFromStorage
197 const uno::Reference
<uno::XComponentContext
> m_xContext
;
198 const IXmlIdRegistrySupplier
& m_rXmlIdRegistrySupplier
;
199 uno::Reference
<rdf::XURI
> m_xBaseURI
;
200 uno::Reference
<rdf::XRepository
> m_xRepository
;
201 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
202 DocumentMetadataAccess_Impl(
203 uno::Reference
<uno::XComponentContext
> const& i_xContext
,
204 IXmlIdRegistrySupplier
const & i_rRegistrySupplier
)
205 : m_xContext(i_xContext
)
206 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
211 OSL_ENSURE(m_xContext
.is(), "context null");
215 // this is... a hack.
216 template<sal_Int16 Constant
>
217 /*static*/ uno::Reference
<rdf::XURI
>
218 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
220 static uno::Reference
< rdf::XURI
> xURI(
221 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_QUERY_THROW
);
226 /** would storing the file to a XStorage succeed? */
227 static bool isFileNameValid(const OUString
& i_rFileName
)
229 if (i_rFileName
.isEmpty()) return false;
230 if (i_rFileName
[0] == '/') return false; // no absolute paths!
233 const OUString
segment(
234 i_rFileName
.getToken(0, static_cast<sal_Unicode
> ('/'), idx
) );
235 if (segment
.isEmpty() || // no empty segments
236 segment
== "." || // no . segments
237 segment
== ".." || // no .. segments
238 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
239 segment
, false)) // no invalid characters
245 /** split a uri hierarchy into first segment and rest */
247 splitPath(OUString
const & i_rPath
,
248 OUString
& o_rDir
, OUString
& o_rRest
)
250 const sal_Int32
idx(i_rPath
.indexOf(static_cast<sal_Unicode
>('/')));
251 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
255 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
256 // input must not start or end with '/'
259 o_rDir
= (i_rPath
.copy(0, idx
));
260 o_rRest
= (i_rPath
.copy(idx
+1));
266 splitXmlId(OUString
const & i_XmlId
,
267 OUString
& o_StreamName
, OUString
& o_Idref
)
269 const sal_Int32
idx(i_XmlId
.indexOf(static_cast<sal_Unicode
>('#')));
270 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
273 o_StreamName
= (i_XmlId
.copy(0, idx
));
274 o_Idref
= (i_XmlId
.copy(idx
+1));
275 return isValidXmlId(o_StreamName
, o_Idref
);
280 static uno::Reference
<rdf::XURI
>
281 getURIForStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
282 OUString
const& i_rPath
)
284 const uno::Reference
<rdf::XURI
> xURI(
285 rdf::URI::createNS( i_rImpl
.m_xContext
,
286 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
291 /** add statements declaring i_xResource to be a file of type i_xType with
292 path i_rPath to manifest, with optional additional types i_pTypes */
294 addFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
295 uno::Reference
<rdf::XURI
> const& i_xType
,
296 OUString
const & i_rPath
,
297 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
= 0)
300 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
303 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
304 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
306 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
307 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
310 for (sal_Int32 i
= 0; i
< i_pTypes
->getLength(); ++i
) {
311 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
312 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
313 (*i_pTypes
)[i
].get());
316 } catch (const uno::RuntimeException
&) {
318 } catch (const uno::Exception
& e
) {
319 throw lang::WrappedTargetRuntimeException(
320 "addFile: exception", /*this*/0, uno::makeAny(e
));
324 /** add content.xml or styles.xml to manifest */
326 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
327 const OUString
& i_rPath
)
329 uno::Reference
<rdf::XURI
> xType
;
330 if (isContentFile(i_rPath
)) {
331 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
332 } else if (isStylesFile(i_rPath
)) {
333 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
337 addFile(i_rImpl
, xType
.get(), i_rPath
);
341 /** add metadata file to manifest */
343 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
344 const OUString
& i_rPath
,
345 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
348 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
352 /** remove a file from the manifest */
354 removeFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
355 uno::Reference
<rdf::XURI
> const& i_xPart
)
357 if (!i_xPart
.is()) throw uno::RuntimeException();
359 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
.get(),
360 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
362 i_rImpl
.m_xManifest
->removeStatements(i_xPart
.get(),
363 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), 0);
364 } catch (const uno::RuntimeException
&) {
366 } catch (const uno::Exception
& e
) {
367 throw lang::WrappedTargetRuntimeException(
368 "removeFile: exception",
373 static ::std::vector
< uno::Reference
< rdf::XURI
> >
374 getAllParts(struct DocumentMetadataAccess_Impl
& i_rImpl
)
376 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
378 const uno::Reference
<container::XEnumeration
> xEnum(
379 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
.get(),
380 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), 0),
382 while (xEnum
->hasMoreElements()) {
384 if (!(xEnum
->nextElement() >>= stmt
)) {
385 throw uno::RuntimeException();
387 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
389 if (!xPart
.is()) continue;
390 ret
.push_back(xPart
);
393 } catch (const uno::RuntimeException
&) {
395 } catch (const uno::Exception
& e
) {
396 throw lang::WrappedTargetRuntimeException(
397 "getAllParts: exception",
403 isPartOfType(struct DocumentMetadataAccess_Impl
& i_rImpl
,
404 uno::Reference
<rdf::XURI
> const & i_xPart
,
405 uno::Reference
<rdf::XURI
> const & i_xType
)
407 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
409 const uno::Reference
<container::XEnumeration
> xEnum(
410 i_rImpl
.m_xManifest
->getStatements(i_xPart
.get(),
411 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
414 return (xEnum
->hasMoreElements());
415 } catch (const uno::RuntimeException
&) {
417 } catch (const uno::Exception
& e
) {
418 throw lang::WrappedTargetRuntimeException(
419 "isPartOfType: exception",
425 static ucb::InteractiveAugmentedIOException
426 mkException( OUString
const & i_rMessage
,
427 ucb::IOErrorCode
const i_ErrorCode
,
428 OUString
const & i_rUri
, OUString
const & i_rResource
)
430 ucb::InteractiveAugmentedIOException iaioe
;
431 iaioe
.Message
= i_rMessage
;
432 iaioe
.Classification
= task::InteractionClassification_ERROR
;
433 iaioe
.Code
= i_ErrorCode
;
435 const beans::PropertyValue
uriProp(OUString("Uri"),
436 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
437 const beans::PropertyValue
rnProp(
438 OUString("ResourceName"),
439 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
440 iaioe
.Arguments
= ::comphelper::makeSequence(
441 uno::makeAny(uriProp
), uno::makeAny(rnProp
));
445 /** error handling policy.
446 <p>If a handler is given, ask it how to proceed:
447 <ul><li>(default:) cancel import, raise exception</li>
448 <li>ignore the error and continue</li>
449 <li>retry the action that led to the error</li></ul></p>
450 N.B.: must not be called before DMA is fully initalized!
451 @returns true iff caller should retry
454 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
455 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
457 if (!i_xHandler
.is()) {
458 throw lang::WrappedTargetException(
459 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
460 /* *this*/ 0, uno::makeAny(i_rException
));
463 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
464 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
465 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
466 new ::comphelper::OInteractionRetry
);
467 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
468 new ::comphelper::OInteractionApprove
);
469 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
470 new ::comphelper::OInteractionAbort
);
472 pRequest
->addContinuation( pApprove
.get() );
473 pRequest
->addContinuation( pAbort
.get() );
474 // actually call the handler
475 i_xHandler
->handle( pRequest
.get() );
476 if (pRetry
->wasSelected()) {
478 } else if (pApprove
->wasSelected()) {
481 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
482 throw lang::WrappedTargetException(
483 "DocumentMetadataAccess::loadMetadataFromStorage: exception",
484 /* *this*/ 0, uno::makeAny(i_rException
));
488 /** check if storage has content.xml/styles.xml;
489 e.g. ODB files seem to only have content.xml */
491 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
492 const OUString
& i_Path
,
493 std::set
< OUString
> & o_rFiles
)
495 static OUString
content(s_content
);
496 static OUString
styles(s_styles
);
498 if (i_xStorage
->hasByName(content
) &&
499 i_xStorage
->isStreamElement(content
))
501 o_rFiles
.insert(i_Path
+ content
);
503 if (i_xStorage
->hasByName(styles
) &&
504 i_xStorage
->isStreamElement(styles
))
506 o_rFiles
.insert(i_Path
+ styles
);
508 } catch (const uno::Exception
&) {
509 OSL_TRACE("collectFilesFromStorage: exception?");
513 /** import a metadata file into repository */
515 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
516 uno::Reference
< embed::XStorage
> const & i_xStorage
,
517 OUString
const & i_rPath
,
518 OUString
const & i_rBaseURI
)
523 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
525 if (i_xStorage
->isStreamElement(i_rPath
)) {
526 const uno::Reference
<io::XStream
> xStream(
527 i_xStorage
->openStreamElement(i_rPath
,
528 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
529 const uno::Reference
<io::XInputStream
> xInStream(
530 xStream
->getInputStream(), uno::UNO_SET_THROW
);
531 const uno::Reference
<rdf::XURI
> xBaseURI(
532 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
533 const uno::Reference
<rdf::XURI
> xURI(
534 rdf::URI::createNS(i_rImpl
.m_xContext
,
535 i_rBaseURI
, i_rPath
));
536 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
537 xInStream
, xURI
, xBaseURI
);
540 "readStream: is not a stream",
541 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
544 if (i_xStorage
->isStorageElement(dir
)) {
545 const uno::Reference
<embed::XStorage
> xDir(
546 i_xStorage
->openStorageElement(dir
,
547 embed::ElementModes::READ
));
548 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
549 uno::UNO_QUERY_THROW
);
552 xDirProps
->getPropertyValue(
553 utl::MediaDescriptor::PROP_MEDIATYPE() )
555 if (mimeType
.startsWith(s_odfmime
)) {
556 OSL_TRACE("readStream: "
557 "refusing to recurse into embedded document");
560 } catch (const uno::Exception
&) { }
561 OUStringBuffer
buf(i_rBaseURI
);
562 buf
.append(dir
).append('/');
563 readStream(i_rImpl
, xDir
, rest
, buf
.makeStringAndClear() );
566 "readStream: is not a directory",
567 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
570 } catch (const container::NoSuchElementException
& e
) {
571 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
572 i_rBaseURI
+ i_rPath
, i_rPath
);
573 } catch (const io::IOException
& e
) {
574 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
575 i_rBaseURI
+ i_rPath
, i_rPath
);
576 } catch (const rdf::ParseException
& e
) {
577 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
578 i_rBaseURI
+ i_rPath
, i_rPath
);
582 /** import a metadata file into repository */
584 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
585 uno::Reference
<embed::XStorage
> const & i_xStorage
,
586 OUString
const & i_rBaseURI
,
587 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
588 const OUString
& i_rPath
)
592 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
593 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
594 if (handleError(e
, i_xHandler
)) goto retry
;
595 } catch (const uno::RuntimeException
&) {
597 } catch (const uno::Exception
& e
) {
598 throw lang::WrappedTargetRuntimeException(
599 "importFile: exception",
604 /** actually write a metadata file to the storage */
606 exportStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
607 uno::Reference
< embed::XStorage
> const & i_xStorage
,
608 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
609 OUString
const & i_rFileName
,
610 OUString
const & i_rBaseURI
)
612 const uno::Reference
<io::XStream
> xStream(
613 i_xStorage
->openStreamElement(i_rFileName
,
614 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
616 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
618 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
619 xStreamProps
->setPropertyValue(
620 OUString("MediaType"),
621 uno::makeAny(OUString(s_rdfxml
)));
623 const uno::Reference
<io::XOutputStream
> xOutStream(
624 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
625 const uno::Reference
<rdf::XURI
> xBaseURI(
626 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
627 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
628 xOutStream
, i_xGraphName
, xBaseURI
);
631 /** write a metadata file to the storage */
633 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
634 uno::Reference
< embed::XStorage
> const & i_xStorage
,
635 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
636 OUString
const & i_rPath
,
637 OUString
const & i_rBaseURI
)
641 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
644 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
647 const uno::Reference
<embed::XStorage
> xDir(
648 i_xStorage
->openStorageElement(dir
,
649 embed::ElementModes::WRITE
));
650 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
651 uno::UNO_QUERY_THROW
);
654 xDirProps
->getPropertyValue(
655 utl::MediaDescriptor::PROP_MEDIATYPE() )
657 if (mimeType
.startsWith(s_odfmime
)) {
658 OSL_TRACE("writeStream: "
659 "refusing to recurse into embedded document");
662 } catch (const uno::Exception
&) { }
663 OUStringBuffer
buf(i_rBaseURI
);
664 buf
.append(dir
).append('/');
665 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
,
666 buf
.makeStringAndClear());
667 uno::Reference
<embed::XTransactedObject
> const xTransaction(
668 xDir
, uno::UNO_QUERY
);
669 if (xTransaction
.is()) {
670 xTransaction
->commit();
673 } catch (const uno::RuntimeException
&) {
675 } catch (const io::IOException
&) {
681 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
682 const uno::Reference
< embed::XStorage
> & i_xStorage
,
683 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
684 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
688 i_rImpl
.m_xManifest
.clear();
690 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
693 i_rImpl
.m_xRepository
.clear();
694 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
697 const OUString
baseURI( i_xBaseURI
->getStringValue() );
698 // try to delay raising errors until after initialization is done
700 ucb::InteractiveAugmentedIOException iaioe
;
703 const uno::Reference
<rdf::XURI
> xManifest(
704 getURIForStream(i_rImpl
, s_manifest
));
706 readStream(i_rImpl
, i_xStorage
, s_manifest
, baseURI
);
707 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
708 // no manifest.rdf: this is not an error in ODF < 1.2
709 if (!(ucb::IOErrorCode_NOT_EXISTING_PATH
== e
.Code
)) {
713 } catch (const uno::Exception
& e
) {
717 // init manifest graph
718 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
719 i_rImpl
.m_xRepository
->getGraph(xManifest
));
720 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
721 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
722 const uno::Reference
<container::XEnumeration
> xEnum(
723 i_rImpl
.m_xManifest
->getStatements(0,
724 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
725 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get()));
727 // document statement
728 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
729 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
730 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
732 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
733 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
734 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
736 if (rterr
.hasValue()) {
737 throw lang::WrappedTargetRuntimeException(
739 "DocumentMetadataAccess::loadMetadataFromStorage: "
740 "exception"), 0, rterr
);
744 if (handleError(iaioe
, i_xHandler
)) goto retry
;
748 /** init Impl struct */
749 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
753 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
754 getURIForStream(i_rImpl
, s_manifest
)),
757 // insert the document statement
758 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
759 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
760 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
761 } catch (const uno::Exception
& e
) {
762 throw lang::WrappedTargetRuntimeException(
763 "init: unexpected exception", 0,
767 // add top-level content files
768 if (!addContentOrStylesFileImpl(i_rImpl
, s_content
)) {
769 throw uno::RuntimeException();
771 if (!addContentOrStylesFileImpl(i_rImpl
, s_styles
)) {
772 throw uno::RuntimeException();
778 DocumentMetadataAccess::DocumentMetadataAccess(
779 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
780 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
)
781 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
783 // no initalization: must call loadFrom...
786 DocumentMetadataAccess::DocumentMetadataAccess(
787 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
788 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
,
789 OUString
const & i_rURI
)
790 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
792 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
793 OSL_ENSURE(i_rURI
.endsWith("/"), "DMA::DMA: URI without / given!");
794 if (!i_rURI
.endsWith("/")) throw uno::RuntimeException();
795 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
796 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
802 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
803 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
804 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
807 DocumentMetadataAccess::~DocumentMetadataAccess()
811 // ::com::sun::star::rdf::XRepositorySupplier:
812 uno::Reference
< rdf::XRepository
> SAL_CALL
813 DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException
, std::exception
)
815 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
816 return m_pImpl
->m_xRepository
;
819 // ::com::sun::star::rdf::XNode:
821 DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException
, std::exception
)
823 return m_pImpl
->m_xBaseURI
->getStringValue();
826 // ::com::sun::star::rdf::XURI:
828 DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException
, std::exception
)
830 return m_pImpl
->m_xBaseURI
->getNamespace();
834 DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException
, std::exception
)
836 return m_pImpl
->m_xBaseURI
->getLocalName();
839 // ::com::sun::star::rdf::XDocumentMetadataAccess:
840 uno::Reference
< rdf::XMetadatable
> SAL_CALL
841 DocumentMetadataAccess::getElementByMetadataReference(
842 const ::com::sun::star::beans::StringPair
& i_rReference
)
843 throw (uno::RuntimeException
, std::exception
)
845 const IXmlIdRegistry
* pReg(
846 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
848 throw uno::RuntimeException(
849 "DocumentMetadataAccess::getElementByXmlId: no registry", *this);
851 return pReg
->GetElementByMetadataReference(i_rReference
);
854 uno::Reference
< rdf::XMetadatable
> SAL_CALL
855 DocumentMetadataAccess::getElementByURI(
856 const uno::Reference
< rdf::XURI
> & i_xURI
)
857 throw (uno::RuntimeException
, lang::IllegalArgumentException
, std::exception
)
860 throw lang::IllegalArgumentException(
861 "DocumentMetadataAccess::getElementByURI: URI is null", *this, 0);
864 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
865 const OUString
name( i_xURI
->getStringValue() );
866 if (!name
.match(baseURI
)) {
869 const OUString
relName( name
.copy(baseURI
.getLength()) );
872 if (!splitXmlId(relName
, path
, idref
)) {
876 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
880 uno::Sequence
< uno::Reference
< rdf::XURI
> > SAL_CALL
881 DocumentMetadataAccess::getMetadataGraphsWithType(
882 const uno::Reference
<rdf::XURI
> & i_xType
)
883 throw (uno::RuntimeException
, lang::IllegalArgumentException
, std::exception
)
886 throw lang::IllegalArgumentException(
887 "DocumentMetadataAccess::getMetadataGraphsWithType: "
888 "type is null", *this, 0);
891 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
892 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
893 getAllParts(*m_pImpl
) );
894 ::std::remove_copy_if(parts
.begin(), parts
.end(),
895 ::std::back_inserter(ret
),
897 ::std::logical_not
<bool>(),
898 ::boost::bind(&isPartOfType
, ::boost::ref(*m_pImpl
), _1
, i_xType
) ));
899 return ::comphelper::containerToSequence(ret
);
902 uno::Reference
<rdf::XURI
> SAL_CALL
903 DocumentMetadataAccess::addMetadataFile(const OUString
& i_rFileName
,
904 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
905 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
906 container::ElementExistException
, std::exception
)
908 if (!isFileNameValid(i_rFileName
)) {
909 throw lang::IllegalArgumentException(
910 "DocumentMetadataAccess::addMetadataFile: invalid FileName",
913 if (isReservedFile(i_rFileName
)) {
914 throw lang::IllegalArgumentException(
915 "DocumentMetadataAccess::addMetadataFile:"
916 "invalid FileName: reserved", *this, 0);
918 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
919 if (!i_rTypes
[i
].is()) {
920 throw lang::IllegalArgumentException(
921 "DocumentMetadataAccess::addMetadataFile: "
922 "null type", *this, 2);
926 const uno::Reference
<rdf::XURI
> xGraphName(
927 getURIForStream(*m_pImpl
, i_rFileName
) );
930 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
931 } catch (const rdf::RepositoryException
& e
) {
932 throw lang::WrappedTargetRuntimeException(
933 "DocumentMetadataAccess::addMetadataFile: exception",
934 *this, uno::makeAny(e
));
935 // note: all other exceptions are propagated
938 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
942 uno::Reference
<rdf::XURI
> SAL_CALL
943 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
944 const uno::Reference
< io::XInputStream
> & i_xInStream
,
945 const OUString
& i_rFileName
,
946 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
947 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
948 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
949 datatransfer::UnsupportedFlavorException
,
950 container::ElementExistException
, rdf::ParseException
, io::IOException
, std::exception
)
952 if (!isFileNameValid(i_rFileName
)) {
953 throw lang::IllegalArgumentException(
954 "DocumentMetadataAccess::importMetadataFile: invalid FileName",
957 if (isReservedFile(i_rFileName
)) {
958 throw lang::IllegalArgumentException(
959 "DocumentMetadataAccess::importMetadataFile:"
960 "invalid FileName: reserved", *this, 0);
962 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
963 if (!i_rTypes
[i
].is()) {
964 throw lang::IllegalArgumentException(
965 "DocumentMetadataAccess::importMetadataFile: null type",
970 const uno::Reference
<rdf::XURI
> xGraphName(
971 getURIForStream(*m_pImpl
, i_rFileName
) );
974 m_pImpl
->m_xRepository
->importGraph(
975 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
976 } catch (const rdf::RepositoryException
& e
) {
977 throw lang::WrappedTargetRuntimeException(
978 "DocumentMetadataAccess::importMetadataFile: "
979 "RepositoryException", *this, uno::makeAny(e
));
980 // note: all other exceptions are propagated
984 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
989 DocumentMetadataAccess::removeMetadataFile(
990 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
991 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
992 container::NoSuchElementException
, std::exception
)
995 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
996 } catch (const rdf::RepositoryException
& e
) {
997 throw lang::WrappedTargetRuntimeException(
998 "DocumentMetadataAccess::removeMetadataFile: "
999 "RepositoryException", *this, uno::makeAny(e
));
1000 // note: all other exceptions are propagated
1003 // remove file from manifest
1004 removeFile(*m_pImpl
, i_xGraphName
.get());
1008 DocumentMetadataAccess::addContentOrStylesFile(
1009 const OUString
& i_rFileName
)
1010 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1011 container::ElementExistException
, std::exception
)
1013 if (!isFileNameValid(i_rFileName
)) {
1014 throw lang::IllegalArgumentException(
1015 "DocumentMetadataAccess::addContentOrStylesFile: "
1016 "invalid FileName", *this, 0);
1019 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1020 throw lang::IllegalArgumentException(
1021 "DocumentMetadataAccess::addContentOrStylesFile: "
1022 "invalid FileName: must end with content.xml or styles.xml",
1028 DocumentMetadataAccess::removeContentOrStylesFile(
1029 const OUString
& i_rFileName
)
1030 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1031 container::NoSuchElementException
, std::exception
)
1033 if (!isFileNameValid(i_rFileName
)) {
1034 throw lang::IllegalArgumentException(
1035 "DocumentMetadataAccess::removeContentOrStylesFile: "
1036 "invalid FileName", *this, 0);
1040 const uno::Reference
<rdf::XURI
> xPart(
1041 getURIForStream(*m_pImpl
, i_rFileName
) );
1042 const uno::Reference
<container::XEnumeration
> xEnum(
1043 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
.get(),
1044 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1046 uno::UNO_SET_THROW
);
1047 if (!xEnum
->hasMoreElements()) {
1048 throw container::NoSuchElementException(
1049 "DocumentMetadataAccess::removeContentOrStylesFile: "
1050 "cannot find stream in manifest graph: " + i_rFileName
,
1054 // remove file from manifest
1055 removeFile(*m_pImpl
, xPart
);
1057 } catch (const uno::RuntimeException
&) {
1059 } catch (const uno::Exception
& e
) {
1060 throw lang::WrappedTargetRuntimeException(
1061 "DocumentMetadataAccess::removeContentOrStylesFile: exception",
1062 *this, uno::makeAny(e
));
1066 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1067 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1068 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1069 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1070 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1071 lang::WrappedTargetException
, std::exception
)
1073 if (!i_xStorage
.is()) {
1074 throw lang::IllegalArgumentException(
1075 "DocumentMetadataAccess::loadMetadataFromStorage: "
1076 "storage is null", *this, 0);
1078 if (!i_xBaseURI
.is()) {
1079 throw lang::IllegalArgumentException(
1080 "DocumentMetadataAccess::loadMetadataFromStorage: "
1081 "base URI is null", *this, 1);
1083 const OUString
baseURI( i_xBaseURI
->getStringValue());
1084 if (baseURI
.indexOf('#') >= 0) {
1085 throw lang::IllegalArgumentException(
1086 "DocumentMetadataAccess::loadMetadataFromStorage: "
1087 "base URI not absolute", *this, 1);
1089 if (!baseURI
.endsWith("/")) {
1090 throw lang::IllegalArgumentException(
1091 "DocumentMetadataAccess::loadMetadataFromStorage: "
1092 "base URI does not end with slash", *this, 1);
1095 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1097 std::set
< OUString
> StgFiles
;
1098 collectFilesFromStorage(i_xStorage
,
1099 OUString(""), StgFiles
);
1101 std::vector
< OUString
> MfstMetadataFiles
;
1104 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1105 getAllParts(*m_pImpl
) );
1106 const uno::Reference
<rdf::XURI
> xContentFile(
1107 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1108 const uno::Reference
<rdf::XURI
> xStylesFile(
1109 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1110 const uno::Reference
<rdf::XURI
> xMetadataFile(
1111 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1112 const sal_Int32
len( baseURI
.getLength() );
1113 for (::std::vector
< uno::Reference
< rdf::XURI
> >::const_iterator it
1115 it
!= parts
.end(); ++it
) {
1116 const OUString
name((*it
)->getStringValue());
1117 if (!name
.match(baseURI
)) {
1118 OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
1119 OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1123 const OUString
relName( name
.copy(len
) );
1124 if (relName
== s_manifest
) {
1125 OSL_TRACE("loadMetadataFromStorage: "
1126 "found ourselves a recursive manifest!");
1129 // remove found items from StgFiles
1130 StgFiles
.erase(relName
);
1131 if (isContentFile(relName
)) {
1132 if (!isPartOfType(*m_pImpl
, *it
, xContentFile
)) {
1133 const uno::Reference
<rdf::XURI
> xName(
1134 getURIForStream(*m_pImpl
, relName
) );
1135 // add missing type statement
1136 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1137 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1138 xContentFile
.get());
1140 } else if (isStylesFile(relName
)) {
1141 if (!isPartOfType(*m_pImpl
, *it
, xStylesFile
)) {
1142 const uno::Reference
<rdf::XURI
> xName(
1143 getURIForStream(*m_pImpl
, relName
) );
1144 // add missing type statement
1145 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1146 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1149 } else if (isReservedFile(relName
)) {
1150 OSL_TRACE("loadMetadataFromStorage: "
1151 "reserved file name in manifest");
1153 if (isPartOfType(*m_pImpl
, *it
, xMetadataFile
)) {
1154 MfstMetadataFiles
.push_back(relName
);
1156 // do not add statement for MetadataFile; it could be
1157 // something else! just ignore it...
1160 } catch (const uno::RuntimeException
&) {
1162 } catch (const uno::Exception
& e
) {
1163 throw lang::WrappedTargetRuntimeException(
1164 "DocumentMetadataAccess::loadMetadataFromStorage: "
1165 "exception", *this, uno::makeAny(e
));
1168 std::for_each(StgFiles
.begin(), StgFiles
.end(),
1169 boost::bind(addContentOrStylesFileImpl
, boost::ref(*m_pImpl
), _1
));
1171 std::for_each(MfstMetadataFiles
.begin(), MfstMetadataFiles
.end(),
1172 boost::bind(importFile
, boost::ref(*m_pImpl
),
1173 i_xStorage
, baseURI
, i_xHandler
, _1
));
1176 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1177 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1178 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1179 lang::WrappedTargetException
, std::exception
)
1181 if (!i_xStorage
.is()) {
1182 throw lang::IllegalArgumentException(
1183 "DocumentMetadataAccess::storeMetadataToStorage: "
1184 "storage is null", *this, 0);
1188 const uno::Reference
<rdf::XURI
> xManifest(
1189 getURIForStream(*m_pImpl
, s_manifest
) );
1190 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1192 writeStream(*m_pImpl
, i_xStorage
, xManifest
, s_manifest
, baseURI
);
1193 } catch (const uno::RuntimeException
&) {
1195 } catch (const io::IOException
& e
) {
1196 throw lang::WrappedTargetException(
1197 "storeMetadataToStorage: IO exception", *this, uno::makeAny(e
));
1198 } catch (const uno::Exception
& e
) {
1199 throw lang::WrappedTargetRuntimeException(
1200 "storeMetadataToStorage: exception", *this, uno::makeAny(e
));
1203 // export metadata streams
1205 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1206 m_pImpl
->m_xRepository
->getGraphNames());
1207 const sal_Int32
len( baseURI
.getLength() );
1208 for (sal_Int32 i
= 0; i
< graphs
.getLength(); ++i
) {
1209 const uno::Reference
<rdf::XURI
> xName(graphs
[i
]);
1210 const OUString
name(xName
->getStringValue());
1211 if (!name
.match(baseURI
)) {
1212 OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
1213 OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1217 const OUString
relName( name
.copy(len
) );
1218 if (relName
== s_manifest
) {
1221 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1222 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
1223 OUStringToOString(relName
, RTL_TEXTENCODING_UTF8
)
1228 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1229 } catch (const uno::RuntimeException
&) {
1231 } catch (const io::IOException
& e
) {
1232 throw lang::WrappedTargetException(
1233 "storeMetadataToStorage: IO exception",
1234 *this, uno::makeAny(e
));
1235 } catch (const uno::Exception
& e
) {
1236 throw lang::WrappedTargetRuntimeException(
1237 "storeMetadataToStorage: exception",
1238 *this, uno::makeAny(e
));
1241 } catch (const rdf::RepositoryException
& e
) {
1242 throw lang::WrappedTargetRuntimeException(
1243 "storeMetadataToStorage: exception", *this, uno::makeAny(e
));
1248 DocumentMetadataAccess::loadMetadataFromMedium(
1249 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1250 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1251 lang::WrappedTargetException
, std::exception
)
1253 uno::Reference
<io::XInputStream
> xIn
;
1254 utl::MediaDescriptor
md(i_rMedium
);
1256 md
[ utl::MediaDescriptor::PROP_URL() ] >>= URL
;
1258 md
[ utl::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL
;
1259 if (md
.addInputStream()) {
1260 md
[ utl::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1262 if (!xIn
.is() && URL
.isEmpty()) {
1263 throw lang::IllegalArgumentException(
1264 "DocumentMetadataAccess::loadMetadataFromMedium: "
1265 "inalid medium: no URL, no input stream", *this, 0);
1267 uno::Reference
<embed::XStorage
> xStorage
;
1270 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1271 xIn
, m_pImpl
->m_xContext
);
1272 } else { // fallback to url
1273 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1274 URL
, embed::ElementModes::READ
, m_pImpl
->m_xContext
);
1276 } catch (const uno::RuntimeException
&) {
1278 } catch (const io::IOException
&) {
1280 } catch (const uno::Exception
& e
) {
1281 throw lang::WrappedTargetException(
1282 "DocumentMetadataAccess::loadMetadataFromMedium: "
1283 "exception", *this, uno::makeAny(e
));
1285 if (!xStorage
.is()) {
1286 throw uno::RuntimeException(
1287 "DocumentMetadataAccess::loadMetadataFromMedium: "
1288 "cannot get Storage", *this);
1290 uno::Reference
<rdf::XURI
> xBaseURI
;
1292 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, BaseURL
);
1293 } catch (const uno::Exception
&) {
1296 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, URL
);
1297 } catch (const uno::Exception
&) {
1298 OSL_FAIL("cannot create base URI");
1301 uno::Reference
<task::XInteractionHandler
> xIH
;
1302 md
[ utl::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH
;
1303 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1307 DocumentMetadataAccess::storeMetadataToMedium(
1308 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1309 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1310 lang::WrappedTargetException
, std::exception
)
1312 utl::MediaDescriptor
md(i_rMedium
);
1314 md
[ utl::MediaDescriptor::PROP_URL() ] >>= URL
;
1315 if (URL
.isEmpty()) {
1316 throw lang::IllegalArgumentException(
1317 "DocumentMetadataAccess::storeMetadataToMedium: "
1318 "invalid medium: no URL", *this, 0);
1321 SfxMedium
aMedium(i_rMedium
);
1322 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1325 if (xStorage
.is()) {
1328 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1329 URL
, embed::ElementModes::WRITE
, m_pImpl
->m_xContext
);
1332 if (!xStorage
.is()) {
1333 throw uno::RuntimeException(
1334 "DocumentMetadataAccess::storeMetadataToMedium: "
1335 "cannot get Storage", *this);
1337 // set MIME type of the storage
1338 utl::MediaDescriptor::const_iterator iter
1339 = md
.find(utl::MediaDescriptor::PROP_MEDIATYPE());
1340 if (iter
!= md
.end()) {
1341 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1342 uno::UNO_QUERY_THROW
);
1344 // this is NOT supported in FileSystemStorage
1345 xProps
->setPropertyValue(
1346 utl::MediaDescriptor::PROP_MEDIATYPE(),
1348 } catch (const uno::Exception
&) { }
1350 storeMetadataToStorage(xStorage
);
1353 const bool bOk
= aMedium
.Commit();
1356 sal_uInt32 nError
= aMedium
.GetError();
1357 if ( nError
== ERRCODE_NONE
) {
1358 nError
= ERRCODE_IO_GENERAL
;
1360 task::ErrorCodeIOException
ex(
1361 ("DocumentMetadataAccess::storeMetadataToMedium Commit failed: "
1362 "0x" + OUString::number(nError
, 16)),
1363 uno::Reference
< uno::XInterface
>(), nError
);
1364 throw lang::WrappedTargetException(OUString(), *this,
1372 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */