1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <sfx2/DocumentMetadataAccess.hxx>
32 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/embed/ElementModes.hpp>
35 #include <com/sun/star/embed/XStorage.hpp>
36 #include <com/sun/star/embed/XTransactedObject.hpp>
37 #include <com/sun/star/task/ErrorCodeIOException.hpp>
38 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
39 #include <com/sun/star/rdf/FileFormat.hpp>
40 #include <com/sun/star/rdf/URIs.hpp>
41 #include <com/sun/star/rdf/Statement.hpp>
42 #include <com/sun/star/rdf/Literal.hpp>
43 #include <com/sun/star/rdf/URI.hpp>
44 #include <com/sun/star/rdf/Repository.hpp>
46 #include <rtl/ustrbuf.hxx>
47 #include <rtl/uri.hxx>
48 #include <rtl/bootstrap.hxx>
50 #include <comphelper/interaction.hxx>
51 #include <comphelper/makesequence.hxx>
52 #include <comphelper/mediadescriptor.hxx>
53 #include <comphelper/sequenceasvector.hxx>
54 #include <comphelper/storagehelper.hxx>
56 #include <sfx2/docfile.hxx>
57 #include <sfx2/XmlIdRegistry.hxx>
59 #include <libxml/tree.h> // for xmlValidateNCName
61 #include <boost/bind.hpp>
62 #include <boost/shared_array.hpp>
63 #include <boost/tuple/tuple.hpp>
71 #include <unotools/ucbhelper.hxx>
72 #include <com/sun/star/uri/XUriReference.hpp>
73 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
74 #include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
78 Note: in the context of this implementation, all rdf.QueryExceptions and
79 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
81 This implementation assumes that it is only used with ODF documents, not mere
82 ODF packages. In other words, we enforce that metadata files must not be
83 called reserved names.
86 using namespace ::com::sun::star
;
91 bool isValidNCName(::rtl::OUString
const & i_rIdref
)
93 const ::rtl::OString
id(
94 ::rtl::OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
95 return !(xmlValidateNCName(
96 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
100 static const char s_content
[] = "content.xml";
101 static const char s_styles
[] = "styles.xml";
102 static const char s_meta
[] = "meta.xml";
103 static const char s_settings
[] = "settings.xml";
104 static const char s_manifest
[] = "manifest.rdf";
105 static const char s_rdfxml
[] = "application/rdf+xml";
106 static const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
109 static bool isContentFile(::rtl::OUString
const & i_rPath
)
111 return i_rPath
== s_content
;
114 static bool isStylesFile (::rtl::OUString
const & i_rPath
)
116 return i_rPath
== s_styles
;
119 static bool isReservedFile(::rtl::OUString
const & i_rPath
)
121 return isContentFile(i_rPath
) || isStylesFile(i_rPath
) || i_rPath
== s_meta
|| i_rPath
== s_settings
;
125 uno::Reference
<rdf::XURI
> createBaseURI(
126 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
127 uno::Reference
<embed::XStorage
> const & i_xStorage
,
128 ::rtl::OUString
const & i_rPkgURI
, ::rtl::OUString
const & i_rSubDocument
)
130 if (!i_xContext
.is() || !i_xStorage
.is() || i_rPkgURI
.isEmpty()) {
131 throw uno::RuntimeException();
134 // #i108078# workaround non-hierarchical vnd.sun.star.expand URIs
135 // this really should be done somewhere else, not here.
136 ::rtl::OUString
pkgURI(i_rPkgURI
);
137 if (pkgURI
.matchIgnoreAsciiCaseAsciiL(
138 RTL_CONSTASCII_STRINGPARAM("vnd.sun.star.expand:")))
140 // expand it here (makeAbsolute requires hierarchical URI)
141 pkgURI
= pkgURI
.copy( RTL_CONSTASCII_LENGTH("vnd.sun.star.expand:") );
142 if (!pkgURI
.isEmpty()) {
143 pkgURI
= ::rtl::Uri::decode(
144 pkgURI
, rtl_UriDecodeStrict
, RTL_TEXTENCODING_UTF8
);
145 if (pkgURI
.isEmpty()) {
146 throw uno::RuntimeException();
148 ::rtl::Bootstrap::expandMacros(pkgURI
);
152 const uno::Reference
<lang::XMultiComponentFactory
> xServiceFactory(
153 i_xContext
->getServiceManager(), uno::UNO_SET_THROW
);
154 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory(
155 xServiceFactory
->createInstanceWithContext(
157 "com.sun.star.uri.UriReferenceFactory"), i_xContext
),
158 uno::UNO_QUERY_THROW
);
159 uno::Reference
< uri::XUriReference
> xBaseURI
;
161 const uno::Reference
< uri::XUriReference
> xPkgURI(
162 xUriFactory
->parse(pkgURI
), uno::UNO_SET_THROW
);
163 xPkgURI
->clearFragment();
165 // need to know whether the storage is a FileSystemStorage
166 // XServiceInfo would be better, but it is not implemented
167 // if ( pkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(pkgURI) )
169 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
171 ::rtl::OUStringBuffer buf
;
172 if (!xBaseURI
->getUriReference().endsWithAsciiL("/", 1))
174 const sal_Int32
count( xBaseURI
->getPathSegmentCount() );
177 const ::rtl::OUString
last( xBaseURI
->getPathSegment(count
- 1) );
180 buf
.append(static_cast<sal_Unicode
>('/'));
182 if (!i_rSubDocument
.isEmpty())
184 buf
.append(i_rSubDocument
);
185 buf
.append(static_cast<sal_Unicode
>('/'));
187 const ::rtl::OUString
Path(buf
.makeStringAndClear());
190 const uno::Reference
< uri::XUriReference
> xPathURI(
191 xUriFactory
->parse(Path
), uno::UNO_SET_THROW
);
193 xUriFactory
->makeAbsolute(xBaseURI
, xPathURI
,
194 true, uri::RelativeUriExcessParentSegments_ERROR
),
198 return rdf::URI::create(i_xContext
, xBaseURI
->getUriReference());
202 struct DocumentMetadataAccess_Impl
204 // note: these are all initialized in constructor, and loadFromStorage
205 const uno::Reference
<uno::XComponentContext
> m_xContext
;
206 const IXmlIdRegistrySupplier
& m_rXmlIdRegistrySupplier
;
207 uno::Reference
<rdf::XURI
> m_xBaseURI
;
208 uno::Reference
<rdf::XRepository
> m_xRepository
;
209 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
210 DocumentMetadataAccess_Impl(
211 uno::Reference
<uno::XComponentContext
> const& i_xContext
,
212 IXmlIdRegistrySupplier
const & i_rRegistrySupplier
)
213 : m_xContext(i_xContext
)
214 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
219 OSL_ENSURE(m_xContext
.is(), "context null");
223 // this is... a hack.
224 template<sal_Int16 Constant
>
225 /*static*/ uno::Reference
<rdf::XURI
>
226 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
228 static uno::Reference
< rdf::XURI
> xURI(
229 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_QUERY_THROW
);
234 /** would storing the file to a XStorage succeed? */
235 static bool isFileNameValid(const ::rtl::OUString
& i_rFileName
)
237 if (i_rFileName
.isEmpty()) return false;
238 if (i_rFileName
[0] == '/') return false; // no absolute paths!
241 const ::rtl::OUString
segment(
242 i_rFileName
.getToken(0, static_cast<sal_Unicode
> ('/'), idx
) );
243 if (segment
.isEmpty() || // no empty segments
244 segment
== "." || // no . segments
245 segment
== ".." || // no .. segments
246 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
247 segment
, sal_False
)) // no invalid characters
253 /** split a uri hierarchy into first segment and rest */
255 splitPath(::rtl::OUString
const & i_rPath
,
256 ::rtl::OUString
& o_rDir
, ::rtl::OUString
& o_rRest
)
258 const sal_Int32
idx(i_rPath
.indexOf(static_cast<sal_Unicode
>('/')));
259 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
260 o_rDir
= ::rtl::OUString();
263 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
264 // input must not start or end with '/'
267 o_rDir
= (i_rPath
.copy(0, idx
));
268 o_rRest
= (i_rPath
.copy(idx
+1));
274 splitXmlId(::rtl::OUString
const & i_XmlId
,
275 ::rtl::OUString
& o_StreamName
, ::rtl::OUString
& o_Idref
)
277 const sal_Int32
idx(i_XmlId
.indexOf(static_cast<sal_Unicode
>('#')));
278 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
281 o_StreamName
= (i_XmlId
.copy(0, idx
));
282 o_Idref
= (i_XmlId
.copy(idx
+1));
283 return isValidXmlId(o_StreamName
, o_Idref
);
288 static uno::Reference
<rdf::XURI
>
289 getURIForStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
290 ::rtl::OUString
const& i_rPath
)
292 const uno::Reference
<rdf::XURI
> xURI(
293 rdf::URI::createNS( i_rImpl
.m_xContext
,
294 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
299 /** add statements declaring i_xResource to be a file of type i_xType with
300 path i_rPath to manifest, with optional additional types i_pTypes */
302 addFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
303 uno::Reference
<rdf::XURI
> const& i_xType
,
304 ::rtl::OUString
const & i_rPath
,
305 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
= 0)
308 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
311 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
312 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
314 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
315 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
318 for (sal_Int32 i
= 0; i
< i_pTypes
->getLength(); ++i
) {
319 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
320 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
321 (*i_pTypes
)[i
].get());
324 } catch (const uno::RuntimeException
&) {
326 } catch (const uno::Exception
& e
) {
327 throw lang::WrappedTargetRuntimeException(
329 "addFile: exception"), /*this*/0, uno::makeAny(e
));
333 /** add content.xml or styles.xml to manifest */
335 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
336 const ::rtl::OUString
& i_rPath
)
338 uno::Reference
<rdf::XURI
> xType
;
339 if (isContentFile(i_rPath
)) {
340 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
341 } else if (isStylesFile(i_rPath
)) {
342 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
346 addFile(i_rImpl
, xType
.get(), i_rPath
);
350 /** add metadata file to manifest */
352 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
353 const ::rtl::OUString
& i_rPath
,
354 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
357 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
361 /** remove a file from the manifest */
363 removeFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
364 uno::Reference
<rdf::XURI
> const& i_xPart
)
366 if (!i_xPart
.is()) throw uno::RuntimeException();
368 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
.get(),
369 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
371 i_rImpl
.m_xManifest
->removeStatements(i_xPart
.get(),
372 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), 0);
373 } catch (const uno::RuntimeException
&) {
375 } catch (const uno::Exception
& e
) {
376 throw lang::WrappedTargetRuntimeException(
377 ::rtl::OUString("removeFile: exception"),
382 static ::std::vector
< uno::Reference
< rdf::XURI
> >
383 getAllParts(struct DocumentMetadataAccess_Impl
& i_rImpl
)
385 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
387 const uno::Reference
<container::XEnumeration
> xEnum(
388 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
.get(),
389 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), 0),
391 while (xEnum
->hasMoreElements()) {
393 if (!(xEnum
->nextElement() >>= stmt
)) {
394 throw uno::RuntimeException();
396 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
398 if (!xPart
.is()) continue;
399 ret
.push_back(xPart
);
402 } catch (const uno::RuntimeException
&) {
404 } catch (const uno::Exception
& e
) {
405 throw lang::WrappedTargetRuntimeException(
406 ::rtl::OUString("getAllParts: exception"),
412 isPartOfType(struct DocumentMetadataAccess_Impl
& i_rImpl
,
413 uno::Reference
<rdf::XURI
> const & i_xPart
,
414 uno::Reference
<rdf::XURI
> const & i_xType
)
416 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
418 const uno::Reference
<container::XEnumeration
> xEnum(
419 i_rImpl
.m_xManifest
->getStatements(i_xPart
.get(),
420 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
423 return (xEnum
->hasMoreElements());
424 } catch (const uno::RuntimeException
&) {
426 } catch (const uno::Exception
& e
) {
427 throw lang::WrappedTargetRuntimeException(
428 ::rtl::OUString("isPartOfType: exception"),
434 static ucb::InteractiveAugmentedIOException
435 mkException( ::rtl::OUString
const & i_rMessage
,
436 ucb::IOErrorCode
const i_ErrorCode
,
437 ::rtl::OUString
const & i_rUri
, ::rtl::OUString
const & i_rResource
)
439 ucb::InteractiveAugmentedIOException iaioe
;
440 iaioe
.Message
= i_rMessage
;
441 iaioe
.Classification
= task::InteractionClassification_ERROR
;
442 iaioe
.Code
= i_ErrorCode
;
444 const beans::PropertyValue
uriProp(::rtl::OUString("Uri"),
445 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
446 const beans::PropertyValue
rnProp(
447 ::rtl::OUString("ResourceName"),
448 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
449 iaioe
.Arguments
= ::comphelper::makeSequence(
450 uno::makeAny(uriProp
), uno::makeAny(rnProp
));
454 /** error handling policy.
455 <p>If a handler is given, ask it how to proceed:
456 <ul><li>(default:) cancel import, raise exception</li>
457 <li>ignore the error and continue</li>
458 <li>retry the action that led to the error</li></ul></p>
459 N.B.: must not be called before DMA is fully initalized!
460 @returns true iff caller should retry
463 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
464 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
466 if (!i_xHandler
.is()) {
467 throw lang::WrappedTargetException(::rtl::OUString(
468 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
469 /* *this*/ 0, uno::makeAny(i_rException
));
472 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
473 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
474 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
475 new ::comphelper::OInteractionRetry
);
476 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
477 new ::comphelper::OInteractionApprove
);
478 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
479 new ::comphelper::OInteractionAbort
);
481 pRequest
->addContinuation( pApprove
.get() );
482 pRequest
->addContinuation( pAbort
.get() );
483 // actually call the handler
484 i_xHandler
->handle( pRequest
.get() );
485 if (pRetry
->wasSelected()) {
487 } else if (pApprove
->wasSelected()) {
490 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
491 throw lang::WrappedTargetException(::rtl::OUString(
492 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
493 /* *this*/ 0, uno::makeAny(i_rException
));
497 /** check if storage has content.xml/styles.xml;
498 e.g. ODB files seem to only have content.xml */
500 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
501 ::rtl::OUString i_Path
,
502 std::set
< ::rtl::OUString
> & o_rFiles
)
504 static ::rtl::OUString
content(s_content
);
505 static ::rtl::OUString
styles(s_styles
);
507 if (i_xStorage
->hasByName(content
) &&
508 i_xStorage
->isStreamElement(content
))
510 o_rFiles
.insert(i_Path
+ content
);
512 if (i_xStorage
->hasByName(styles
) &&
513 i_xStorage
->isStreamElement(styles
))
515 o_rFiles
.insert(i_Path
+ styles
);
517 } catch (const uno::Exception
&) {
518 OSL_TRACE("collectFilesFromStorage: exception?");
522 /** import a metadata file into repository */
524 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
525 uno::Reference
< embed::XStorage
> const & i_xStorage
,
526 ::rtl::OUString
const & i_rPath
,
527 ::rtl::OUString
const & i_rBaseURI
)
530 ::rtl::OUString rest
;
532 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
534 if (i_xStorage
->isStreamElement(i_rPath
)) {
535 const uno::Reference
<io::XStream
> xStream(
536 i_xStorage
->openStreamElement(i_rPath
,
537 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
538 const uno::Reference
<io::XInputStream
> xInStream(
539 xStream
->getInputStream(), uno::UNO_SET_THROW
);
540 const uno::Reference
<rdf::XURI
> xBaseURI(
541 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
542 const uno::Reference
<rdf::XURI
> xURI(
543 rdf::URI::createNS(i_rImpl
.m_xContext
,
544 i_rBaseURI
, i_rPath
));
545 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
546 xInStream
, xURI
, xBaseURI
);
548 throw mkException(::rtl::OUString(
549 "readStream: is not a stream"),
550 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
553 if (i_xStorage
->isStorageElement(dir
)) {
554 const uno::Reference
<embed::XStorage
> xDir(
555 i_xStorage
->openStorageElement(dir
,
556 embed::ElementModes::READ
));
557 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
558 uno::UNO_QUERY_THROW
);
560 ::rtl::OUString mimeType
;
561 xDirProps
->getPropertyValue(
562 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
564 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1))
566 OSL_TRACE("readStream: "
567 "refusing to recurse into embedded document");
570 } catch (const uno::Exception
&) { }
571 ::rtl::OUStringBuffer
buf(i_rBaseURI
);
572 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
573 readStream(i_rImpl
, xDir
, rest
, buf
.makeStringAndClear() );
575 throw mkException(::rtl::OUString(
576 "readStream: is not a directory"),
577 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
580 } catch (const container::NoSuchElementException
& e
) {
581 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
582 i_rBaseURI
+ i_rPath
, i_rPath
);
583 } catch (const io::IOException
& e
) {
584 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
585 i_rBaseURI
+ i_rPath
, i_rPath
);
586 } catch (const rdf::ParseException
& e
) {
587 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
588 i_rBaseURI
+ i_rPath
, i_rPath
);
592 /** import a metadata file into repository */
594 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
595 uno::Reference
<embed::XStorage
> const & i_xStorage
,
596 ::rtl::OUString
const & i_rBaseURI
,
597 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
598 ::rtl::OUString i_rPath
)
602 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
603 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
604 if (handleError(e
, i_xHandler
)) goto retry
;
605 } catch (const uno::RuntimeException
&) {
607 } catch (const uno::Exception
& e
) {
608 throw lang::WrappedTargetRuntimeException(
609 ::rtl::OUString("importFile: exception"),
614 /** actually write a metadata file to the storage */
616 exportStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
617 uno::Reference
< embed::XStorage
> const & i_xStorage
,
618 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
619 ::rtl::OUString
const & i_rFileName
,
620 ::rtl::OUString
const & i_rBaseURI
)
622 const uno::Reference
<io::XStream
> xStream(
623 i_xStorage
->openStreamElement(i_rFileName
,
624 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
626 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
628 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
629 xStreamProps
->setPropertyValue(
630 ::rtl::OUString("MediaType"),
631 uno::makeAny(::rtl::OUString(s_rdfxml
)));
633 const uno::Reference
<io::XOutputStream
> xOutStream(
634 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
635 const uno::Reference
<rdf::XURI
> xBaseURI(
636 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
637 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
638 xOutStream
, i_xGraphName
, xBaseURI
);
641 /** write a metadata file to the storage */
643 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
644 uno::Reference
< embed::XStorage
> const & i_xStorage
,
645 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
646 ::rtl::OUString
const & i_rPath
,
647 ::rtl::OUString
const & i_rBaseURI
)
650 ::rtl::OUString rest
;
651 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
654 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
657 const uno::Reference
<embed::XStorage
> xDir(
658 i_xStorage
->openStorageElement(dir
,
659 embed::ElementModes::WRITE
));
660 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
661 uno::UNO_QUERY_THROW
);
663 ::rtl::OUString mimeType
;
664 xDirProps
->getPropertyValue(
665 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
667 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1)) {
668 OSL_TRACE("writeStream: "
669 "refusing to recurse into embedded document");
672 } catch (const uno::Exception
&) { }
673 ::rtl::OUStringBuffer
buf(i_rBaseURI
);
674 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
675 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
,
676 buf
.makeStringAndClear());
677 uno::Reference
<embed::XTransactedObject
> const xTransaction(
678 xDir
, uno::UNO_QUERY
);
679 if (xTransaction
.is()) {
680 xTransaction
->commit();
683 } catch (const uno::RuntimeException
&) {
685 } catch (const io::IOException
&) {
691 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
692 const uno::Reference
< embed::XStorage
> & i_xStorage
,
693 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
694 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
698 i_rImpl
.m_xManifest
.clear();
700 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
703 i_rImpl
.m_xRepository
.clear();
704 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
707 const ::rtl::OUString
manifest (
708 ::rtl::OUString::createFromAscii(s_manifest
));
709 const ::rtl::OUString
baseURI( i_xBaseURI
->getStringValue() );
710 // try to delay raising errors until after initialization is done
712 ucb::InteractiveAugmentedIOException iaioe
;
715 const uno::Reference
<rdf::XURI
> xManifest(
716 getURIForStream(i_rImpl
, manifest
));
718 readStream(i_rImpl
, i_xStorage
, manifest
, baseURI
);
719 } catch (const ucb::InteractiveAugmentedIOException
& e
) {
720 // no manifest.rdf: this is not an error in ODF < 1.2
721 if (!(ucb::IOErrorCode_NOT_EXISTING_PATH
== e
.Code
)) {
725 } catch (const uno::Exception
& e
) {
729 // init manifest graph
730 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
731 i_rImpl
.m_xRepository
->getGraph(xManifest
));
732 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
733 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
734 const uno::Reference
<container::XEnumeration
> xEnum(
735 i_rImpl
.m_xManifest
->getStatements(0,
736 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
737 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get()));
739 // document statement
740 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
741 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
742 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
744 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
745 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
746 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
748 if (rterr
.hasValue()) {
749 throw lang::WrappedTargetRuntimeException(
751 "DocumentMetadataAccess::loadMetadataFromStorage: "
752 "exception"), 0, rterr
);
756 if (handleError(iaioe
, i_xHandler
)) goto retry
;
760 /** init Impl struct */
761 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
765 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
766 getURIForStream(i_rImpl
,
767 ::rtl::OUString::createFromAscii(s_manifest
))),
770 // insert the document statement
771 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
772 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
773 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
774 } catch (const uno::Exception
& e
) {
775 throw lang::WrappedTargetRuntimeException(
776 ::rtl::OUString("init: unexpected exception"), 0,
780 // add top-level content files
781 if (!addContentOrStylesFileImpl(i_rImpl
,
782 ::rtl::OUString::createFromAscii(s_content
))) {
783 throw uno::RuntimeException();
785 if (!addContentOrStylesFileImpl(i_rImpl
,
786 ::rtl::OUString::createFromAscii(s_styles
))) {
787 throw uno::RuntimeException();
793 DocumentMetadataAccess::DocumentMetadataAccess(
794 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
795 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
)
796 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
798 // no initalization: must call loadFrom...
801 DocumentMetadataAccess::DocumentMetadataAccess(
802 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
803 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
,
804 ::rtl::OUString
const & i_rURI
)
805 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
807 OSL_ENSURE(!i_rURI
.isEmpty(), "DMA::DMA: no URI given!");
808 OSL_ENSURE(i_rURI
.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!");
809 if (!i_rURI
.endsWithAsciiL("/", 1)) throw uno::RuntimeException();
810 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
811 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
817 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
818 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
819 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
822 DocumentMetadataAccess::~DocumentMetadataAccess()
826 // ::com::sun::star::rdf::XRepositorySupplier:
827 uno::Reference
< rdf::XRepository
> SAL_CALL
828 DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException
)
830 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
831 return m_pImpl
->m_xRepository
;
834 // ::com::sun::star::rdf::XNode:
835 ::rtl::OUString SAL_CALL
836 DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException
)
838 return m_pImpl
->m_xBaseURI
->getStringValue();
841 // ::com::sun::star::rdf::XURI:
842 ::rtl::OUString SAL_CALL
843 DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException
)
845 return m_pImpl
->m_xBaseURI
->getNamespace();
848 ::rtl::OUString SAL_CALL
849 DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException
)
851 return m_pImpl
->m_xBaseURI
->getLocalName();
854 // ::com::sun::star::rdf::XDocumentMetadataAccess:
855 uno::Reference
< rdf::XMetadatable
> SAL_CALL
856 DocumentMetadataAccess::getElementByMetadataReference(
857 const ::com::sun::star::beans::StringPair
& i_rReference
)
858 throw (uno::RuntimeException
)
860 const IXmlIdRegistry
* pReg(
861 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
863 throw uno::RuntimeException(::rtl::OUString(
864 "DocumentMetadataAccess::getElementByXmlId: no registry"), *this);
866 return pReg
->GetElementByMetadataReference(i_rReference
);
869 uno::Reference
< rdf::XMetadatable
> SAL_CALL
870 DocumentMetadataAccess::getElementByURI(
871 const uno::Reference
< rdf::XURI
> & i_xURI
)
872 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
875 throw lang::IllegalArgumentException(::rtl::OUString(
876 "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0);
879 const ::rtl::OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
880 const ::rtl::OUString
name( i_xURI
->getStringValue() );
881 if (!name
.match(baseURI
)) {
884 const ::rtl::OUString
relName( name
.copy(baseURI
.getLength()) );
885 ::rtl::OUString path
;
886 ::rtl::OUString idref
;
887 if (!splitXmlId(relName
, path
, idref
)) {
891 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
895 uno::Sequence
< uno::Reference
< rdf::XURI
> > SAL_CALL
896 DocumentMetadataAccess::getMetadataGraphsWithType(
897 const uno::Reference
<rdf::XURI
> & i_xType
)
898 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
901 throw lang::IllegalArgumentException(::rtl::OUString(
902 "DocumentMetadataAccess::getMetadataGraphsWithType: "
903 "type is null"), *this, 0);
906 ::comphelper::SequenceAsVector
< uno::Reference
< rdf::XURI
> > ret
;
907 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
908 getAllParts(*m_pImpl
) );
909 ::std::remove_copy_if(parts
.begin(), parts
.end(),
910 ::std::back_inserter(ret
),
912 ::std::logical_not
<bool>(),
913 ::boost::bind(&isPartOfType
, ::boost::ref(*m_pImpl
), _1
, i_xType
) ));
914 return ret
.getAsConstList();
917 uno::Reference
<rdf::XURI
> SAL_CALL
918 DocumentMetadataAccess::addMetadataFile(const ::rtl::OUString
& i_rFileName
,
919 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
920 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
921 container::ElementExistException
)
923 if (!isFileNameValid(i_rFileName
)) {
924 throw lang::IllegalArgumentException(::rtl::OUString(
925 "DocumentMetadataAccess::addMetadataFile: invalid FileName"),
928 if (isReservedFile(i_rFileName
)) {
929 throw lang::IllegalArgumentException(::rtl::OUString(
930 "DocumentMetadataAccess::addMetadataFile:"
931 "invalid FileName: reserved"), *this, 0);
933 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
934 if (!i_rTypes
[i
].is()) {
935 throw lang::IllegalArgumentException(
937 "DocumentMetadataAccess::addMetadataFile: "
938 "null type"), *this, 2);
942 const uno::Reference
<rdf::XURI
> xGraphName(
943 getURIForStream(*m_pImpl
, i_rFileName
) );
946 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
947 } catch (const rdf::RepositoryException
& e
) {
948 throw lang::WrappedTargetRuntimeException(
950 "DocumentMetadataAccess::addMetadataFile: exception"),
951 *this, uno::makeAny(e
));
952 // note: all other exceptions are propagated
955 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
959 uno::Reference
<rdf::XURI
> SAL_CALL
960 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
961 const uno::Reference
< io::XInputStream
> & i_xInStream
,
962 const ::rtl::OUString
& i_rFileName
,
963 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
964 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
965 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
966 datatransfer::UnsupportedFlavorException
,
967 container::ElementExistException
, rdf::ParseException
, io::IOException
)
969 if (!isFileNameValid(i_rFileName
)) {
970 throw lang::IllegalArgumentException(::rtl::OUString(
971 "DocumentMetadataAccess::importMetadataFile: invalid FileName"),
974 if (isReservedFile(i_rFileName
)) {
975 throw lang::IllegalArgumentException(::rtl::OUString(
976 "DocumentMetadataAccess::importMetadataFile:"
977 "invalid FileName: reserved"), *this, 0);
979 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
980 if (!i_rTypes
[i
].is()) {
981 throw lang::IllegalArgumentException(
983 "DocumentMetadataAccess::importMetadataFile: null type"),
988 const uno::Reference
<rdf::XURI
> xGraphName(
989 getURIForStream(*m_pImpl
, i_rFileName
) );
992 m_pImpl
->m_xRepository
->importGraph(
993 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
994 } catch (const rdf::RepositoryException
& e
) {
995 throw lang::WrappedTargetRuntimeException(
997 "DocumentMetadataAccess::importMetadataFile: "
998 "RepositoryException"), *this, uno::makeAny(e
));
999 // note: all other exceptions are propagated
1003 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1008 DocumentMetadataAccess::removeMetadataFile(
1009 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1010 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1011 container::NoSuchElementException
)
1014 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1015 } catch (const rdf::RepositoryException
& e
) {
1016 throw lang::WrappedTargetRuntimeException(
1018 "DocumentMetadataAccess::removeMetadataFile: "
1019 "RepositoryException"), *this, uno::makeAny(e
));
1020 // note: all other exceptions are propagated
1023 // remove file from manifest
1024 removeFile(*m_pImpl
, i_xGraphName
.get());
1028 DocumentMetadataAccess::addContentOrStylesFile(
1029 const ::rtl::OUString
& i_rFileName
)
1030 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1031 container::ElementExistException
)
1033 if (!isFileNameValid(i_rFileName
)) {
1034 throw lang::IllegalArgumentException(::rtl::OUString(
1035 "DocumentMetadataAccess::addContentOrStylesFile: "
1036 "invalid FileName"), *this, 0);
1039 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1040 throw lang::IllegalArgumentException(::rtl::OUString(
1041 "DocumentMetadataAccess::addContentOrStylesFile: "
1042 "invalid FileName: must end with content.xml or styles.xml"),
1048 DocumentMetadataAccess::removeContentOrStylesFile(
1049 const ::rtl::OUString
& i_rFileName
)
1050 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1051 container::NoSuchElementException
)
1053 if (!isFileNameValid(i_rFileName
)) {
1054 throw lang::IllegalArgumentException(::rtl::OUString(
1055 "DocumentMetadataAccess::removeContentOrStylesFile: "
1056 "invalid FileName"), *this, 0);
1060 const uno::Reference
<rdf::XURI
> xPart(
1061 getURIForStream(*m_pImpl
, i_rFileName
) );
1062 const uno::Reference
<container::XEnumeration
> xEnum(
1063 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
.get(),
1064 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1066 uno::UNO_SET_THROW
);
1067 if (!xEnum
->hasMoreElements()) {
1068 throw container::NoSuchElementException(
1070 "DocumentMetadataAccess::removeContentOrStylesFile: "
1071 "cannot find stream in manifest graph: ") + i_rFileName
,
1075 // remove file from manifest
1076 removeFile(*m_pImpl
, xPart
);
1078 } catch (const uno::RuntimeException
&) {
1080 } catch (const uno::Exception
& e
) {
1081 throw lang::WrappedTargetRuntimeException(
1083 "DocumentMetadataAccess::removeContentOrStylesFile: exception"),
1084 *this, uno::makeAny(e
));
1088 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1089 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1090 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1091 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1092 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1093 lang::WrappedTargetException
)
1095 if (!i_xStorage
.is()) {
1096 throw lang::IllegalArgumentException(::rtl::OUString(
1097 "DocumentMetadataAccess::loadMetadataFromStorage: "
1098 "storage is null"), *this, 0);
1100 if (!i_xBaseURI
.is()) {
1101 throw lang::IllegalArgumentException(::rtl::OUString(
1102 "DocumentMetadataAccess::loadMetadataFromStorage: "
1103 "base URI is null"), *this, 1);
1105 const ::rtl::OUString
baseURI( i_xBaseURI
->getStringValue());
1106 if (baseURI
.indexOf('#') >= 0) {
1107 throw lang::IllegalArgumentException(::rtl::OUString(
1108 "DocumentMetadataAccess::loadMetadataFromStorage: "
1109 "base URI not absolute"), *this, 1);
1111 if (baseURI
.isEmpty() || !baseURI
.endsWithAsciiL("/", 1)) {
1112 throw lang::IllegalArgumentException(::rtl::OUString(
1113 "DocumentMetadataAccess::loadMetadataFromStorage: "
1114 "base URI does not end with slash"), *this, 1);
1117 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1119 std::set
< ::rtl::OUString
> StgFiles
;
1120 collectFilesFromStorage(i_xStorage
,
1121 ::rtl::OUString(""), StgFiles
);
1123 std::vector
< ::rtl::OUString
> MfstMetadataFiles
;
1126 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1127 getAllParts(*m_pImpl
) );
1128 const uno::Reference
<rdf::XURI
> xContentFile(
1129 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1130 const uno::Reference
<rdf::XURI
> xStylesFile(
1131 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1132 const uno::Reference
<rdf::XURI
> xMetadataFile(
1133 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1134 const sal_Int32
len( baseURI
.getLength() );
1135 const ::rtl::OUString
manifest (
1136 ::rtl::OUString::createFromAscii(s_manifest
));
1137 for (::std::vector
< uno::Reference
< rdf::XURI
> >::const_iterator it
1139 it
!= parts
.end(); ++it
) {
1140 const ::rtl::OUString
name((*it
)->getStringValue());
1141 if (!name
.match(baseURI
)) {
1142 OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
1143 ::rtl::OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1147 const ::rtl::OUString
relName( name
.copy(len
) );
1148 if (relName
== manifest
) {
1149 OSL_TRACE("loadMetadataFromStorage: "
1150 "found ourselves a recursive manifest!");
1153 // remove found items from StgFiles
1154 StgFiles
.erase(relName
);
1155 if (isContentFile(relName
)) {
1156 if (!isPartOfType(*m_pImpl
, *it
, xContentFile
)) {
1157 const uno::Reference
<rdf::XURI
> xName(
1158 getURIForStream(*m_pImpl
, relName
) );
1159 // add missing type statement
1160 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1161 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1162 xContentFile
.get());
1164 } else if (isStylesFile(relName
)) {
1165 if (!isPartOfType(*m_pImpl
, *it
, xStylesFile
)) {
1166 const uno::Reference
<rdf::XURI
> xName(
1167 getURIForStream(*m_pImpl
, relName
) );
1168 // add missing type statement
1169 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1170 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1173 } else if (isReservedFile(relName
)) {
1174 OSL_TRACE("loadMetadataFromStorage: "
1175 "reserved file name in manifest");
1177 if (isPartOfType(*m_pImpl
, *it
, xMetadataFile
)) {
1178 MfstMetadataFiles
.push_back(relName
);
1180 // do not add statement for MetadataFile; it could be
1181 // something else! just ignore it...
1184 } catch (const uno::RuntimeException
&) {
1186 } catch (const uno::Exception
& e
) {
1187 throw lang::WrappedTargetRuntimeException(
1189 "DocumentMetadataAccess::loadMetadataFromStorage: "
1190 "exception"), *this, uno::makeAny(e
));
1193 std::for_each(StgFiles
.begin(), StgFiles
.end(),
1194 boost::bind(addContentOrStylesFileImpl
, boost::ref(*m_pImpl
), _1
));
1196 std::for_each(MfstMetadataFiles
.begin(), MfstMetadataFiles
.end(),
1197 boost::bind(importFile
, boost::ref(*m_pImpl
),
1198 i_xStorage
, baseURI
, i_xHandler
, _1
));
1201 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1202 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1203 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1204 lang::WrappedTargetException
)
1206 if (!i_xStorage
.is()) {
1207 throw lang::IllegalArgumentException(::rtl::OUString(
1208 "DocumentMetadataAccess::storeMetadataToStorage: "
1209 "storage is null"), *this, 0);
1213 const ::rtl::OUString
manifest (
1214 ::rtl::OUString::createFromAscii(s_manifest
));
1215 const uno::Reference
<rdf::XURI
> xManifest(
1216 getURIForStream(*m_pImpl
, manifest
) );
1217 const ::rtl::OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1219 writeStream(*m_pImpl
, i_xStorage
, xManifest
, manifest
, baseURI
);
1220 } catch (const uno::RuntimeException
&) {
1222 } catch (const io::IOException
& e
) {
1223 throw lang::WrappedTargetException( ::rtl::OUString(
1224 "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e
));
1225 } catch (const uno::Exception
& e
) {
1226 throw lang::WrappedTargetRuntimeException(
1228 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1231 // export metadata streams
1233 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1234 m_pImpl
->m_xRepository
->getGraphNames());
1235 const sal_Int32
len( baseURI
.getLength() );
1236 for (sal_Int32 i
= 0; i
< graphs
.getLength(); ++i
) {
1237 const uno::Reference
<rdf::XURI
> xName(graphs
[i
]);
1238 const ::rtl::OUString
name(xName
->getStringValue());
1239 if (!name
.match(baseURI
)) {
1240 OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
1241 ::rtl::OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1245 const ::rtl::OUString
relName( name
.copy(len
) );
1246 if (relName
== manifest
) {
1249 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1250 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
1251 ::rtl::OUStringToOString(relName
, RTL_TEXTENCODING_UTF8
)
1256 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1257 } catch (const uno::RuntimeException
&) {
1259 } catch (const io::IOException
& e
) {
1260 throw lang::WrappedTargetException(
1262 "storeMetadataToStorage: IO exception"),
1263 *this, uno::makeAny(e
));
1264 } catch (const uno::Exception
& e
) {
1265 throw lang::WrappedTargetRuntimeException(
1267 "storeMetadataToStorage: exception"),
1268 *this, uno::makeAny(e
));
1271 } catch (const rdf::RepositoryException
& e
) {
1272 throw lang::WrappedTargetRuntimeException(
1274 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1279 DocumentMetadataAccess::loadMetadataFromMedium(
1280 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1281 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1282 lang::WrappedTargetException
)
1284 uno::Reference
<io::XInputStream
> xIn
;
1285 ::comphelper::MediaDescriptor
md(i_rMedium
);
1286 ::rtl::OUString URL
;
1287 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1288 ::rtl::OUString BaseURL
;
1289 md
[ ::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL
;
1290 if (md
.addInputStream()) {
1291 md
[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1293 if (!xIn
.is() && URL
.isEmpty()) {
1294 throw lang::IllegalArgumentException(::rtl::OUString(
1295 "DocumentMetadataAccess::loadMetadataFromMedium: "
1296 "inalid medium: no URL, no input stream"), *this, 0);
1298 uno::Reference
<embed::XStorage
> xStorage
;
1300 const uno::Reference
<lang::XMultiServiceFactory
> xMsf (
1301 m_pImpl
->m_xContext
->getServiceManager(), uno::UNO_QUERY_THROW
);
1303 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1305 } else { // fallback to url
1306 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1307 URL
, embed::ElementModes::READ
, xMsf
);
1309 } catch (const uno::RuntimeException
&) {
1311 } catch (const io::IOException
&) {
1313 } catch (const uno::Exception
& e
) {
1314 throw lang::WrappedTargetException(
1316 "DocumentMetadataAccess::loadMetadataFromMedium: "
1317 "exception"), *this, uno::makeAny(e
));
1319 if (!xStorage
.is()) {
1320 throw uno::RuntimeException(::rtl::OUString(
1321 "DocumentMetadataAccess::loadMetadataFromMedium: "
1322 "cannot get Storage"), *this);
1324 uno::Reference
<rdf::XURI
> xBaseURI
;
1326 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, BaseURL
);
1327 } catch (const uno::Exception
&) {
1330 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, URL
);
1331 } catch (const uno::Exception
&) {
1332 OSL_FAIL("cannot create base URI");
1335 uno::Reference
<task::XInteractionHandler
> xIH
;
1336 md
[ ::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH
;
1337 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1341 DocumentMetadataAccess::storeMetadataToMedium(
1342 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1343 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1344 lang::WrappedTargetException
)
1346 ::comphelper::MediaDescriptor
md(i_rMedium
);
1347 ::rtl::OUString URL
;
1348 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1349 if (URL
.isEmpty()) {
1350 throw lang::IllegalArgumentException(::rtl::OUString(
1351 "DocumentMetadataAccess::storeMetadataToMedium: "
1352 "invalid medium: no URL"), *this, 0);
1355 SfxMedium
aMedium(i_rMedium
);
1356 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1359 if (xStorage
.is()) {
1362 const uno::Reference
<lang::XMultiServiceFactory
> xMsf (
1363 m_pImpl
->m_xContext
->getServiceManager(), uno::UNO_QUERY_THROW
);
1364 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1365 URL
, embed::ElementModes::WRITE
, xMsf
);
1368 if (!xStorage
.is()) {
1369 throw uno::RuntimeException(::rtl::OUString(
1370 "DocumentMetadataAccess::storeMetadataToMedium: "
1371 "cannot get Storage"), *this);
1373 // set MIME type of the storage
1374 ::comphelper::MediaDescriptor::const_iterator iter
1375 = md
.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE());
1376 if (iter
!= md
.end()) {
1377 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1378 uno::UNO_QUERY_THROW
);
1380 // this is NOT supported in FileSystemStorage
1381 xProps
->setPropertyValue(
1382 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
1384 } catch (const uno::Exception
&) { }
1386 storeMetadataToStorage(xStorage
);
1389 const sal_Bool bOk
= aMedium
.Commit();
1392 sal_uInt32 nError
= aMedium
.GetError();
1393 if ( nError
== ERRCODE_NONE
) {
1394 nError
= ERRCODE_IO_GENERAL
;
1396 task::ErrorCodeIOException
ex( ::rtl::OUString(),
1397 uno::Reference
< uno::XInterface
>(), nError
);
1398 throw lang::WrappedTargetException(::rtl::OUString(), *this,
1406 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */