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 <comphelper/mediadescriptor.hxx>
44 #include <comphelper/sequenceasvector.hxx>
45 #include <comphelper/storagehelper.hxx>
47 #include <sfx2/docfile.hxx>
48 #include <sfx2/XmlIdRegistry.hxx>
50 #include <libxml/tree.h> // for xmlValidateNCName
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
.matchIgnoreAsciiCaseAsciiL(
136 RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:")))
138 // expand it here (makeAbsolute requires hierarchical URI)
139 pkgURI
= pkgURI
.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
140 if (!pkgURI
.isEmpty()) {
141 pkgURI
= ::rtl::Uri::decode(
142 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
143 if (pkgURI
.isEmpty()) {
144 throw uno::RuntimeException();
146 ::rtl::Bootstrap::expandMacros(pkgURI
);
150 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory
=
151 uri::UriReferenceFactory::create( i_xContext
);
152 uno::Reference
< uri::XUriReference
> xBaseURI
;
154 const uno::Reference
< uri::XUriReference
> xPkgURI(
155 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
156 xPkgURI
->clearFragment();
158 // need to know whether the storage is a FileSystemStorage
159 // XServiceInfo would be better, but it is not implemented
160 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
162 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
165 if (!xBaseURI
->getUriReference().endsWithAsciiL("/", 1))
167 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
170 const OUString
last( xBaseURI
->getPathSegment(count
- 1) );
173 buf
.append(static_cast<sal_Unicode
>('/'));
175 if (!i_rSubDocument
.isEmpty())
177 buf
.append(i_rSubDocument
);
178 buf
.append(static_cast<sal_Unicode
>('/'));
180 const OUString
Path(buf
.makeStringAndClear());
183 const uno::Reference
< uri::XUriReference
> xPathURI(
184 xUriFactory
->parse(Path
), uno::UNO_SET_THROW
);
186 xUriFactory
->makeAbsolute(xBaseURI
, xPathURI
,
187 true, uri::RelativeUriExcessParentSegments_ERROR
),
191 return rdf::URI::create(i_xContext
, xBaseURI
->getUriReference());
195 struct DocumentMetadataAccess_Impl
197 // note: these are all initialized in constructor, and loadFromStorage
198 const uno::Reference
<uno::XComponentContext
> m_xContext
;
199 const IXmlIdRegistrySupplier
& m_rXmlIdRegistrySupplier
;
200 uno::Reference
<rdf::XURI
> m_xBaseURI
;
201 uno::Reference
<rdf::XRepository
> m_xRepository
;
202 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
203 DocumentMetadataAccess_Impl(
204 uno::Reference
<uno::XComponentContext
> const& i_xContext
,
205 IXmlIdRegistrySupplier
const & i_rRegistrySupplier
)
206 : m_xContext(i_xContext
)
207 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
212 OSL_ENSURE(m_xContext
.is(), "context null");
216 // this is... a hack.
217 template<sal_Int16 Constant
>
218 /*static*/ uno::Reference
<rdf::XURI
>
219 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
221 static uno::Reference
< rdf::XURI
> xURI(
222 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_QUERY_THROW
);
227 /** would storing the file to a XStorage succeed? */
228 static bool isFileNameValid(const OUString
& i_rFileName
)
230 if (i_rFileName
.isEmpty()) return false;
231 if (i_rFileName
[0] == '/') return false; // no absolute paths!
234 const OUString
segment(
235 i_rFileName
.getToken(0, static_cast<sal_Unicode
> ('/'), idx
) );
236 if (segment
.isEmpty() || // no empty segments
237 segment
== "." || // no . segments
238 segment
== ".." || // no .. segments
239 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
240 segment
, sal_False
)) // no invalid characters
246 /** split a uri hierarchy into first segment and rest */
248 splitPath(OUString
const & i_rPath
,
249 OUString
& o_rDir
, OUString
& o_rRest
)
251 const sal_Int32
idx(i_rPath
.indexOf(static_cast<sal_Unicode
>('/')));
252 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
256 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
257 // input must not start or end with '/'
260 o_rDir
= (i_rPath
.copy(0, idx
));
261 o_rRest
= (i_rPath
.copy(idx
+1));
267 splitXmlId(OUString
const & i_XmlId
,
268 OUString
& o_StreamName
, OUString
& o_Idref
)
270 const sal_Int32
idx(i_XmlId
.indexOf(static_cast<sal_Unicode
>('#')));
271 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
274 o_StreamName
= (i_XmlId
.copy(0, idx
));
275 o_Idref
= (i_XmlId
.copy(idx
+1));
276 return isValidXmlId(o_StreamName
, o_Idref
);
281 static uno::Reference
<rdf::XURI
>
282 getURIForStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
283 OUString
const& i_rPath
)
285 const uno::Reference
<rdf::XURI
> xURI(
286 rdf::URI::createNS( i_rImpl
.m_xContext
,
287 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
292 /** add statements declaring i_xResource to be a file of type i_xType with
293 path i_rPath to manifest, with optional additional types i_pTypes */
295 addFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
296 uno::Reference
<rdf::XURI
> const& i_xType
,
297 OUString
const & i_rPath
,
298 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
= 0)
301 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
304 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
305 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
307 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
308 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
311 for (sal_Int32 i
= 0; i
< i_pTypes
->getLength(); ++i
) {
312 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
313 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
314 (*i_pTypes
)[i
].get());
317 } catch (const uno::RuntimeException
&) {
319 } catch (const uno::Exception
& e
) {
320 throw lang::WrappedTargetRuntimeException(
322 "addFile: exception"), /*this*/0, uno::makeAny(e
));
326 /** add content.xml or styles.xml to manifest */
328 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
329 const OUString
& i_rPath
)
331 uno::Reference
<rdf::XURI
> xType
;
332 if (isContentFile(i_rPath
)) {
333 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
334 } else if (isStylesFile(i_rPath
)) {
335 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
339 addFile(i_rImpl
, xType
.get(), i_rPath
);
343 /** add metadata file to manifest */
345 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
346 const OUString
& i_rPath
,
347 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
350 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
354 /** remove a file from the manifest */
356 removeFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
357 uno::Reference
<rdf::XURI
> const& i_xPart
)
359 if (!i_xPart
.is()) throw uno::RuntimeException();
361 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
.get(),
362 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
364 i_rImpl
.m_xManifest
->removeStatements(i_xPart
.get(),
365 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), 0);
366 } catch (const uno::RuntimeException
&) {
368 } catch (const uno::Exception
& e
) {
369 throw lang::WrappedTargetRuntimeException(
370 OUString("removeFile: exception"),
375 static ::std::vector
< uno::Reference
< rdf::XURI
> >
376 getAllParts(struct DocumentMetadataAccess_Impl
& i_rImpl
)
378 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
380 const uno::Reference
<container::XEnumeration
> xEnum(
381 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
.get(),
382 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), 0),
384 while (xEnum
->hasMoreElements()) {
386 if (!(xEnum
->nextElement() >>= stmt
)) {
387 throw uno::RuntimeException();
389 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
391 if (!xPart
.is()) continue;
392 ret
.push_back(xPart
);
395 } catch (const uno::RuntimeException
&) {
397 } catch (const uno::Exception
& e
) {
398 throw lang::WrappedTargetRuntimeException(
399 OUString("getAllParts: exception"),
405 isPartOfType(struct DocumentMetadataAccess_Impl
& i_rImpl
,
406 uno::Reference
<rdf::XURI
> const & i_xPart
,
407 uno::Reference
<rdf::XURI
> const & i_xType
)
409 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
411 const uno::Reference
<container::XEnumeration
> xEnum(
412 i_rImpl
.m_xManifest
->getStatements(i_xPart
.get(),
413 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
416 return (xEnum
->hasMoreElements());
417 } catch (const uno::RuntimeException
&) {
419 } catch (const uno::Exception
& e
) {
420 throw lang::WrappedTargetRuntimeException(
421 OUString("isPartOfType: exception"),
427 static ucb::InteractiveAugmentedIOException
428 mkException( OUString
const & i_rMessage
,
429 ucb::IOErrorCode
const i_ErrorCode
,
430 OUString
const & i_rUri
, OUString
const & i_rResource
)
432 ucb::InteractiveAugmentedIOException iaioe
;
433 iaioe
.Message
= i_rMessage
;
434 iaioe
.Classification
= task::InteractionClassification_ERROR
;
435 iaioe
.Code
= i_ErrorCode
;
437 const beans::PropertyValue
uriProp(OUString("Uri"),
438 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
439 const beans::PropertyValue
rnProp(
440 OUString("ResourceName"),
441 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
442 iaioe
.Arguments
= ::comphelper::makeSequence(
443 uno::makeAny(uriProp
), uno::makeAny(rnProp
));
447 /** error handling policy.
448 <p>If a handler is given, ask it how to proceed:
449 <ul><li>(default:) cancel import, raise exception</li>
450 <li>ignore the error and continue</li>
451 <li>retry the action that led to the error</li></ul></p>
452 N.B.: must not be called before DMA is fully initalized!
453 @returns true iff caller should retry
456 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
457 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
459 if (!i_xHandler
.is()) {
460 throw lang::WrappedTargetException(OUString(
461 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
462 /* *this*/ 0, uno::makeAny(i_rException
));
465 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
466 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
467 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
468 new ::comphelper::OInteractionRetry
);
469 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
470 new ::comphelper::OInteractionApprove
);
471 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
472 new ::comphelper::OInteractionAbort
);
474 pRequest
->addContinuation( pApprove
.get() );
475 pRequest
->addContinuation( pAbort
.get() );
476 // actually call the handler
477 i_xHandler
->handle( pRequest
.get() );
478 if (pRetry
->wasSelected()) {
480 } else if (pApprove
->wasSelected()) {
483 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
484 throw lang::WrappedTargetException(OUString(
485 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
486 /* *this*/ 0, uno::makeAny(i_rException
));
490 /** check if storage has content.xml/styles.xml;
491 e.g. ODB files seem to only have content.xml */
493 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
495 std::set
< OUString
> & o_rFiles
)
497 static OUString
content(s_content
);
498 static OUString
styles(s_styles
);
500 if (i_xStorage
->hasByName(content
) &&
501 i_xStorage
->isStreamElement(content
))
503 o_rFiles
.insert(i_Path
+ content
);
505 if (i_xStorage
->hasByName(styles
) &&
506 i_xStorage
->isStreamElement(styles
))
508 o_rFiles
.insert(i_Path
+ styles
);
510 } catch (const uno::Exception
&) {
511 OSL_TRACE("collectFilesFromStorage: exception?");
515 /** import a metadata file into repository */
517 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
518 uno::Reference
< embed::XStorage
> const & i_xStorage
,
519 OUString
const & i_rPath
,
520 OUString
const & i_rBaseURI
)
525 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
527 if (i_xStorage
->isStreamElement(i_rPath
)) {
528 const uno::Reference
<io::XStream
> xStream(
529 i_xStorage
->openStreamElement(i_rPath
,
530 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
531 const uno::Reference
<io::XInputStream
> xInStream(
532 xStream
->getInputStream(), uno::UNO_SET_THROW
);
533 const uno::Reference
<rdf::XURI
> xBaseURI(
534 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
535 const uno::Reference
<rdf::XURI
> xURI(
536 rdf::URI::createNS(i_rImpl
.m_xContext
,
537 i_rBaseURI
, i_rPath
));
538 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
539 xInStream
, xURI
, xBaseURI
);
541 throw mkException(OUString(
542 "readStream: is not a stream"),
543 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
546 if (i_xStorage
->isStorageElement(dir
)) {
547 const uno::Reference
<embed::XStorage
> xDir(
548 i_xStorage
->openStorageElement(dir
,
549 embed::ElementModes::READ
));
550 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
551 uno::UNO_QUERY_THROW
);
554 xDirProps
->getPropertyValue(
555 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
557 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1))
559 OSL_TRACE("readStream: "
560 "refusing to recurse into embedded document");
563 } catch (const uno::Exception
&) { }
564 OUStringBuffer
buf(i_rBaseURI
);
565 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
566 readStream(i_rImpl
, xDir
, rest
, buf
.makeStringAndClear() );
568 throw mkException(OUString(
569 "readStream: is not a directory"),
570 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
573 } catch (const container::NoSuchElementException
& e
) {
574 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
575 i_rBaseURI
+ i_rPath
, i_rPath
);
576 } catch (const io::IOException
& e
) {
577 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
578 i_rBaseURI
+ i_rPath
, i_rPath
);
579 } catch (const rdf::ParseException
& e
) {
580 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
581 i_rBaseURI
+ i_rPath
, i_rPath
);
585 /** import a metadata file into repository */
587 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
588 uno::Reference
<embed::XStorage
> const & i_xStorage
,
589 OUString
const & i_rBaseURI
,
590 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
595 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
596 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
597 if (handleError(e
, i_xHandler
)) goto retry
;
598 } catch (const uno::RuntimeException
&) {
600 } catch (const uno::Exception
& e
) {
601 throw lang::WrappedTargetRuntimeException(
602 OUString("importFile: exception"),
607 /** actually write a metadata file to the storage */
609 exportStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
610 uno::Reference
< embed::XStorage
> const & i_xStorage
,
611 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
612 OUString
const & i_rFileName
,
613 OUString
const & i_rBaseURI
)
615 const uno::Reference
<io::XStream
> xStream(
616 i_xStorage
->openStreamElement(i_rFileName
,
617 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
619 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
621 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
622 xStreamProps
->setPropertyValue(
623 OUString("MediaType"),
624 uno::makeAny(OUString(s_rdfxml
)));
626 const uno::Reference
<io::XOutputStream
> xOutStream(
627 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
628 const uno::Reference
<rdf::XURI
> xBaseURI(
629 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
630 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
631 xOutStream
, i_xGraphName
, xBaseURI
);
634 /** write a metadata file to the storage */
636 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
637 uno::Reference
< embed::XStorage
> const & i_xStorage
,
638 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
639 OUString
const & i_rPath
,
640 OUString
const & i_rBaseURI
)
644 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
647 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
650 const uno::Reference
<embed::XStorage
> xDir(
651 i_xStorage
->openStorageElement(dir
,
652 embed::ElementModes::WRITE
));
653 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
654 uno::UNO_QUERY_THROW
);
657 xDirProps
->getPropertyValue(
658 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
660 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1)) {
661 OSL_TRACE("writeStream: "
662 "refusing to recurse into embedded document");
665 } catch (const uno::Exception
&) { }
666 OUStringBuffer
buf(i_rBaseURI
);
667 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
668 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
,
669 buf
.makeStringAndClear());
670 uno::Reference
<embed::XTransactedObject
> const xTransaction(
671 xDir
, uno::UNO_QUERY
);
672 if (xTransaction
.is()) {
673 xTransaction
->commit();
676 } catch (const uno::RuntimeException
&) {
678 } catch (const io::IOException
&) {
684 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
685 const uno::Reference
< embed::XStorage
> & i_xStorage
,
686 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
687 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
691 i_rImpl
.m_xManifest
.clear();
693 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
696 i_rImpl
.m_xRepository
.clear();
697 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
700 const OUString
manifest (
701 OUString::createFromAscii(s_manifest
));
702 const OUString
baseURI( i_xBaseURI
->getStringValue() );
703 // try to delay raising errors until after initialization is done
705 ucb::InteractiveAugmentedIOException iaioe
;
708 const uno::Reference
<rdf::XURI
> xManifest(
709 getURIForStream(i_rImpl
, manifest
));
711 readStream(i_rImpl
, i_xStorage
, manifest
, baseURI
);
712 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
713 // no manifest.rdf: this is not an error in ODF < 1.2
714 if (!(ucb::IOErrorCode_NOT_EXISTING_PATH
== e
.Code
)) {
718 } catch (const uno::Exception
& e
) {
722 // init manifest graph
723 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
724 i_rImpl
.m_xRepository
->getGraph(xManifest
));
725 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
726 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
727 const uno::Reference
<container::XEnumeration
> xEnum(
728 i_rImpl
.m_xManifest
->getStatements(0,
729 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
730 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get()));
732 // document statement
733 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
734 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
735 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
737 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
738 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
739 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
741 if (rterr
.hasValue()) {
742 throw lang::WrappedTargetRuntimeException(
744 "DocumentMetadataAccess::loadMetadataFromStorage: "
745 "exception"), 0, rterr
);
749 if (handleError(iaioe
, i_xHandler
)) goto retry
;
753 /** init Impl struct */
754 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
758 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
759 getURIForStream(i_rImpl
,
760 OUString::createFromAscii(s_manifest
))),
763 // insert the document statement
764 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
765 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
766 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
767 } catch (const uno::Exception
& e
) {
768 throw lang::WrappedTargetRuntimeException(
769 OUString("init: unexpected exception"), 0,
773 // add top-level content files
774 if (!addContentOrStylesFileImpl(i_rImpl
,
775 OUString::createFromAscii(s_content
))) {
776 throw uno::RuntimeException();
778 if (!addContentOrStylesFileImpl(i_rImpl
,
779 OUString::createFromAscii(s_styles
))) {
780 throw uno::RuntimeException();
786 DocumentMetadataAccess::DocumentMetadataAccess(
787 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
788 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
)
789 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
791 // no initalization: must call loadFrom...
794 DocumentMetadataAccess::DocumentMetadataAccess(
795 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
796 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
,
797 OUString
const & i_rURI
)
798 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
800 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
801 OSL_ENSURE(i_rURI
.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!");
802 if (!i_rURI
.endsWithAsciiL("/", 1)) throw uno::RuntimeException();
803 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
804 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
810 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
811 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
812 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
815 DocumentMetadataAccess::~DocumentMetadataAccess()
819 // ::com::sun::star::rdf::XRepositorySupplier:
820 uno::Reference
< rdf::XRepository
> SAL_CALL
821 DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException
)
823 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
824 return m_pImpl
->m_xRepository
;
827 // ::com::sun::star::rdf::XNode:
829 DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException
)
831 return m_pImpl
->m_xBaseURI
->getStringValue();
834 // ::com::sun::star::rdf::XURI:
836 DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException
)
838 return m_pImpl
->m_xBaseURI
->getNamespace();
842 DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException
)
844 return m_pImpl
->m_xBaseURI
->getLocalName();
847 // ::com::sun::star::rdf::XDocumentMetadataAccess:
848 uno::Reference
< rdf::XMetadatable
> SAL_CALL
849 DocumentMetadataAccess::getElementByMetadataReference(
850 const ::com::sun::star::beans::StringPair
& i_rReference
)
851 throw (uno::RuntimeException
)
853 const IXmlIdRegistry
* pReg(
854 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
856 throw uno::RuntimeException(OUString(
857 "DocumentMetadataAccess::getElementByXmlId: no registry"), *this);
859 return pReg
->GetElementByMetadataReference(i_rReference
);
862 uno::Reference
< rdf::XMetadatable
> SAL_CALL
863 DocumentMetadataAccess::getElementByURI(
864 const uno::Reference
< rdf::XURI
> & i_xURI
)
865 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
868 throw lang::IllegalArgumentException(OUString(
869 "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0);
872 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
873 const OUString
name( i_xURI
->getStringValue() );
874 if (!name
.match(baseURI
)) {
877 const OUString
relName( name
.copy(baseURI
.getLength()) );
880 if (!splitXmlId(relName
, path
, idref
)) {
884 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
888 uno::Sequence
< uno::Reference
< rdf::XURI
> > SAL_CALL
889 DocumentMetadataAccess::getMetadataGraphsWithType(
890 const uno::Reference
<rdf::XURI
> & i_xType
)
891 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
894 throw lang::IllegalArgumentException(OUString(
895 "DocumentMetadataAccess::getMetadataGraphsWithType: "
896 "type is null"), *this, 0);
899 ::comphelper::SequenceAsVector
< uno::Reference
< rdf::XURI
> > ret
;
900 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
901 getAllParts(*m_pImpl
) );
902 ::std::remove_copy_if(parts
.begin(), parts
.end(),
903 ::std::back_inserter(ret
),
905 ::std::logical_not
<bool>(),
906 ::boost::bind(&isPartOfType
, ::boost::ref(*m_pImpl
), _1
, i_xType
) ));
907 return ret
.getAsConstList();
910 uno::Reference
<rdf::XURI
> SAL_CALL
911 DocumentMetadataAccess::addMetadataFile(const OUString
& i_rFileName
,
912 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
913 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
914 container::ElementExistException
)
916 if (!isFileNameValid(i_rFileName
)) {
917 throw lang::IllegalArgumentException(OUString(
918 "DocumentMetadataAccess::addMetadataFile: invalid FileName"),
921 if (isReservedFile(i_rFileName
)) {
922 throw lang::IllegalArgumentException(OUString(
923 "DocumentMetadataAccess::addMetadataFile:"
924 "invalid FileName: reserved"), *this, 0);
926 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
927 if (!i_rTypes
[i
].is()) {
928 throw lang::IllegalArgumentException(
930 "DocumentMetadataAccess::addMetadataFile: "
931 "null type"), *this, 2);
935 const uno::Reference
<rdf::XURI
> xGraphName(
936 getURIForStream(*m_pImpl
, i_rFileName
) );
939 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
940 } catch (const rdf::RepositoryException
& e
) {
941 throw lang::WrappedTargetRuntimeException(
943 "DocumentMetadataAccess::addMetadataFile: exception"),
944 *this, uno::makeAny(e
));
945 // note: all other exceptions are propagated
948 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
952 uno::Reference
<rdf::XURI
> SAL_CALL
953 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
954 const uno::Reference
< io::XInputStream
> & i_xInStream
,
955 const OUString
& i_rFileName
,
956 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
957 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
958 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
959 datatransfer::UnsupportedFlavorException
,
960 container::ElementExistException
, rdf::ParseException
, io::IOException
)
962 if (!isFileNameValid(i_rFileName
)) {
963 throw lang::IllegalArgumentException(OUString(
964 "DocumentMetadataAccess::importMetadataFile: invalid FileName"),
967 if (isReservedFile(i_rFileName
)) {
968 throw lang::IllegalArgumentException(OUString(
969 "DocumentMetadataAccess::importMetadataFile:"
970 "invalid FileName: reserved"), *this, 0);
972 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
973 if (!i_rTypes
[i
].is()) {
974 throw lang::IllegalArgumentException(
976 "DocumentMetadataAccess::importMetadataFile: null type"),
981 const uno::Reference
<rdf::XURI
> xGraphName(
982 getURIForStream(*m_pImpl
, i_rFileName
) );
985 m_pImpl
->m_xRepository
->importGraph(
986 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
987 } catch (const rdf::RepositoryException
& e
) {
988 throw lang::WrappedTargetRuntimeException(
990 "DocumentMetadataAccess::importMetadataFile: "
991 "RepositoryException"), *this, uno::makeAny(e
));
992 // note: all other exceptions are propagated
996 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1001 DocumentMetadataAccess::removeMetadataFile(
1002 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1003 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1004 container::NoSuchElementException
)
1007 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1008 } catch (const rdf::RepositoryException
& e
) {
1009 throw lang::WrappedTargetRuntimeException(
1011 "DocumentMetadataAccess::removeMetadataFile: "
1012 "RepositoryException"), *this, uno::makeAny(e
));
1013 // note: all other exceptions are propagated
1016 // remove file from manifest
1017 removeFile(*m_pImpl
, i_xGraphName
.get());
1021 DocumentMetadataAccess::addContentOrStylesFile(
1022 const OUString
& i_rFileName
)
1023 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1024 container::ElementExistException
)
1026 if (!isFileNameValid(i_rFileName
)) {
1027 throw lang::IllegalArgumentException(OUString(
1028 "DocumentMetadataAccess::addContentOrStylesFile: "
1029 "invalid FileName"), *this, 0);
1032 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1033 throw lang::IllegalArgumentException(OUString(
1034 "DocumentMetadataAccess::addContentOrStylesFile: "
1035 "invalid FileName: must end with content.xml or styles.xml"),
1041 DocumentMetadataAccess::removeContentOrStylesFile(
1042 const OUString
& i_rFileName
)
1043 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1044 container::NoSuchElementException
)
1046 if (!isFileNameValid(i_rFileName
)) {
1047 throw lang::IllegalArgumentException(OUString(
1048 "DocumentMetadataAccess::removeContentOrStylesFile: "
1049 "invalid FileName"), *this, 0);
1053 const uno::Reference
<rdf::XURI
> xPart(
1054 getURIForStream(*m_pImpl
, i_rFileName
) );
1055 const uno::Reference
<container::XEnumeration
> xEnum(
1056 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
.get(),
1057 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1059 uno::UNO_SET_THROW
);
1060 if (!xEnum
->hasMoreElements()) {
1061 throw container::NoSuchElementException(
1063 "DocumentMetadataAccess::removeContentOrStylesFile: "
1064 "cannot find stream in manifest graph: ") + i_rFileName
,
1068 // remove file from manifest
1069 removeFile(*m_pImpl
, xPart
);
1071 } catch (const uno::RuntimeException
&) {
1073 } catch (const uno::Exception
& e
) {
1074 throw lang::WrappedTargetRuntimeException(
1076 "DocumentMetadataAccess::removeContentOrStylesFile: exception"),
1077 *this, uno::makeAny(e
));
1081 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1082 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1083 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1084 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1085 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1086 lang::WrappedTargetException
)
1088 if (!i_xStorage
.is()) {
1089 throw lang::IllegalArgumentException(OUString(
1090 "DocumentMetadataAccess::loadMetadataFromStorage: "
1091 "storage is null"), *this, 0);
1093 if (!i_xBaseURI
.is()) {
1094 throw lang::IllegalArgumentException(OUString(
1095 "DocumentMetadataAccess::loadMetadataFromStorage: "
1096 "base URI is null"), *this, 1);
1098 const OUString
baseURI( i_xBaseURI
->getStringValue());
1099 if (baseURI
.indexOf('#') >= 0) {
1100 throw lang::IllegalArgumentException(OUString(
1101 "DocumentMetadataAccess::loadMetadataFromStorage: "
1102 "base URI not absolute"), *this, 1);
1104 if (baseURI
.isEmpty() || !baseURI
.endsWithAsciiL("/", 1)) {
1105 throw lang::IllegalArgumentException(OUString(
1106 "DocumentMetadataAccess::loadMetadataFromStorage: "
1107 "base URI does not end with slash"), *this, 1);
1110 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1112 std::set
< OUString
> StgFiles
;
1113 collectFilesFromStorage(i_xStorage
,
1114 OUString(""), StgFiles
);
1116 std::vector
< OUString
> MfstMetadataFiles
;
1119 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1120 getAllParts(*m_pImpl
) );
1121 const uno::Reference
<rdf::XURI
> xContentFile(
1122 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1123 const uno::Reference
<rdf::XURI
> xStylesFile(
1124 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1125 const uno::Reference
<rdf::XURI
> xMetadataFile(
1126 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1127 const sal_Int32
len( baseURI
.getLength() );
1128 const OUString
manifest (
1129 OUString::createFromAscii(s_manifest
));
1130 for (::std::vector
< uno::Reference
< rdf::XURI
> >::const_iterator it
1132 it
!= parts
.end(); ++it
) {
1133 const OUString
name((*it
)->getStringValue());
1134 if (!name
.match(baseURI
)) {
1135 OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
1136 OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1140 const OUString
relName( name
.copy(len
) );
1141 if (relName
== manifest
) {
1142 OSL_TRACE("loadMetadataFromStorage: "
1143 "found ourselves a recursive manifest!");
1146 // remove found items from StgFiles
1147 StgFiles
.erase(relName
);
1148 if (isContentFile(relName
)) {
1149 if (!isPartOfType(*m_pImpl
, *it
, xContentFile
)) {
1150 const uno::Reference
<rdf::XURI
> xName(
1151 getURIForStream(*m_pImpl
, relName
) );
1152 // add missing type statement
1153 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1154 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1155 xContentFile
.get());
1157 } else if (isStylesFile(relName
)) {
1158 if (!isPartOfType(*m_pImpl
, *it
, xStylesFile
)) {
1159 const uno::Reference
<rdf::XURI
> xName(
1160 getURIForStream(*m_pImpl
, relName
) );
1161 // add missing type statement
1162 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1163 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1166 } else if (isReservedFile(relName
)) {
1167 OSL_TRACE("loadMetadataFromStorage: "
1168 "reserved file name in manifest");
1170 if (isPartOfType(*m_pImpl
, *it
, 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
& e
) {
1180 throw lang::WrappedTargetRuntimeException(
1182 "DocumentMetadataAccess::loadMetadataFromStorage: "
1183 "exception"), *this, uno::makeAny(e
));
1186 std::for_each(StgFiles
.begin(), StgFiles
.end(),
1187 boost::bind(addContentOrStylesFileImpl
, boost::ref(*m_pImpl
), _1
));
1189 std::for_each(MfstMetadataFiles
.begin(), MfstMetadataFiles
.end(),
1190 boost::bind(importFile
, boost::ref(*m_pImpl
),
1191 i_xStorage
, baseURI
, i_xHandler
, _1
));
1194 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1195 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1196 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1197 lang::WrappedTargetException
)
1199 if (!i_xStorage
.is()) {
1200 throw lang::IllegalArgumentException(OUString(
1201 "DocumentMetadataAccess::storeMetadataToStorage: "
1202 "storage is null"), *this, 0);
1206 const OUString
manifest (
1207 OUString::createFromAscii(s_manifest
));
1208 const uno::Reference
<rdf::XURI
> xManifest(
1209 getURIForStream(*m_pImpl
, manifest
) );
1210 const OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1212 writeStream(*m_pImpl
, i_xStorage
, xManifest
, manifest
, baseURI
);
1213 } catch (const uno::RuntimeException
&) {
1215 } catch (const io::IOException
& e
) {
1216 throw lang::WrappedTargetException( OUString(
1217 "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e
));
1218 } catch (const uno::Exception
& e
) {
1219 throw lang::WrappedTargetRuntimeException(
1221 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1224 // export metadata streams
1226 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1227 m_pImpl
->m_xRepository
->getGraphNames());
1228 const sal_Int32
len( baseURI
.getLength() );
1229 for (sal_Int32 i
= 0; i
< graphs
.getLength(); ++i
) {
1230 const uno::Reference
<rdf::XURI
> xName(graphs
[i
]);
1231 const OUString
name(xName
->getStringValue());
1232 if (!name
.match(baseURI
)) {
1233 OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
1234 OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1238 const OUString
relName( name
.copy(len
) );
1239 if (relName
== manifest
) {
1242 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1243 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
1244 OUStringToOString(relName
, RTL_TEXTENCODING_UTF8
)
1249 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1250 } catch (const uno::RuntimeException
&) {
1252 } catch (const io::IOException
& e
) {
1253 throw lang::WrappedTargetException(
1255 "storeMetadataToStorage: IO exception"),
1256 *this, uno::makeAny(e
));
1257 } catch (const uno::Exception
& e
) {
1258 throw lang::WrappedTargetRuntimeException(
1260 "storeMetadataToStorage: exception"),
1261 *this, uno::makeAny(e
));
1264 } catch (const rdf::RepositoryException
& e
) {
1265 throw lang::WrappedTargetRuntimeException(
1267 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1272 DocumentMetadataAccess::loadMetadataFromMedium(
1273 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1274 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1275 lang::WrappedTargetException
)
1277 uno::Reference
<io::XInputStream
> xIn
;
1278 ::comphelper::MediaDescriptor
md(i_rMedium
);
1280 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1282 md
[ ::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL
;
1283 if (md
.addInputStream()) {
1284 md
[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1286 if (!xIn
.is() && URL
.isEmpty()) {
1287 throw lang::IllegalArgumentException(OUString(
1288 "DocumentMetadataAccess::loadMetadataFromMedium: "
1289 "inalid medium: no URL, no input stream"), *this, 0);
1291 uno::Reference
<embed::XStorage
> xStorage
;
1294 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1295 xIn
, m_pImpl
->m_xContext
);
1296 } else { // fallback to url
1297 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1298 URL
, embed::ElementModes::READ
, m_pImpl
->m_xContext
);
1300 } catch (const uno::RuntimeException
&) {
1302 } catch (const io::IOException
&) {
1304 } catch (const uno::Exception
& e
) {
1305 throw lang::WrappedTargetException(
1307 "DocumentMetadataAccess::loadMetadataFromMedium: "
1308 "exception"), *this, uno::makeAny(e
));
1310 if (!xStorage
.is()) {
1311 throw uno::RuntimeException(OUString(
1312 "DocumentMetadataAccess::loadMetadataFromMedium: "
1313 "cannot get Storage"), *this);
1315 uno::Reference
<rdf::XURI
> xBaseURI
;
1317 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, BaseURL
);
1318 } catch (const uno::Exception
&) {
1321 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, URL
);
1322 } catch (const uno::Exception
&) {
1323 OSL_FAIL("cannot create base URI");
1326 uno::Reference
<task::XInteractionHandler
> xIH
;
1327 md
[ ::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH
;
1328 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1332 DocumentMetadataAccess::storeMetadataToMedium(
1333 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1334 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1335 lang::WrappedTargetException
)
1337 ::comphelper::MediaDescriptor
md(i_rMedium
);
1339 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1340 if (URL
.isEmpty()) {
1341 throw lang::IllegalArgumentException(OUString(
1342 "DocumentMetadataAccess::storeMetadataToMedium: "
1343 "invalid medium: no URL"), *this, 0);
1346 SfxMedium
aMedium(i_rMedium
);
1347 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1350 if (xStorage
.is()) {
1353 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1354 URL
, embed::ElementModes::WRITE
, m_pImpl
->m_xContext
);
1357 if (!xStorage
.is()) {
1358 throw uno::RuntimeException(OUString(
1359 "DocumentMetadataAccess::storeMetadataToMedium: "
1360 "cannot get Storage"), *this);
1362 // set MIME type of the storage
1363 ::comphelper::MediaDescriptor::const_iterator iter
1364 = md
.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE());
1365 if (iter
!= md
.end()) {
1366 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1367 uno::UNO_QUERY_THROW
);
1369 // this is NOT supported in FileSystemStorage
1370 xProps
->setPropertyValue(
1371 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
1373 } catch (const uno::Exception
&) { }
1375 storeMetadataToStorage(xStorage
);
1378 const sal_Bool bOk
= aMedium
.Commit();
1381 sal_uInt32 nError
= aMedium
.GetError();
1382 if ( nError
== ERRCODE_NONE
) {
1383 nError
= ERRCODE_IO_GENERAL
;
1385 task::ErrorCodeIOException
ex( OUString(),
1386 uno::Reference
< uno::XInterface
>(), nError
);
1387 throw lang::WrappedTargetException(OUString(), *this,
1395 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */