1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: DocumentMetadataAccess.cxx,v $
10 * $Revision: 1.1.2.9 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sfx2.hxx"
33 #include <sfx2/DocumentMetadataAccess.hxx>
35 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/embed/ElementModes.hpp>
38 #include <com/sun/star/embed/XStorage.hpp>
39 #include <com/sun/star/embed/XTransactedObject.hpp>
40 #include <com/sun/star/task/ErrorCodeIOException.hpp>
41 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
42 #include <com/sun/star/rdf/FileFormat.hpp>
43 #include <com/sun/star/rdf/URIs.hpp>
44 #include <com/sun/star/rdf/Statement.hpp>
45 #include <com/sun/star/rdf/Literal.hpp>
46 #include <com/sun/star/rdf/URI.hpp>
47 #include <com/sun/star/rdf/Repository.hpp>
50 #include <rtl/ustrbuf.hxx>
52 #include <comphelper/interaction.hxx>
53 #include <comphelper/makesequence.hxx>
54 #include <comphelper/mediadescriptor.hxx>
55 #include <comphelper/sequenceasvector.hxx>
56 #include <comphelper/storagehelper.hxx>
58 #include <sfx2/docfile.hxx>
59 #include <sfx2/XmlIdRegistry.hxx>
61 #include <libxml/tree.h> // for xmlValidateNCName
63 #include <boost/bind.hpp>
64 #include <boost/shared_array.hpp>
65 #include <boost/tuple/tuple.hpp>
73 #include <unotools/ucbhelper.hxx>
74 #include <com/sun/star/uri/XUriReference.hpp>
75 #include <com/sun/star/uri/XUriReferenceFactory.hpp>
76 #include <com/sun/star/uri/XVndSunStarPkgUrlReferenceFactory.hpp>
80 Note: in the context of this implementation, all rdf.QueryExceptions and
81 rdf.RepositoryExceptions are RuntimeExceptions, and will be reported as such.
83 This implementation assumes that it is only used with ODF documents, not mere
84 ODF packages. In other words, we enforce that metadata files must not be
85 called reserved names.
88 using namespace ::com::sun::star
;
93 bool isValidNCName(::rtl::OUString
const & i_rIdref
)
95 const ::rtl::OString
id(
96 ::rtl::OUStringToOString(i_rIdref
, RTL_TEXTENCODING_UTF8
) );
97 return !(xmlValidateNCName(
98 reinterpret_cast<const unsigned char*>(id
.getStr()), 0));
101 ////////////////////////////////////////////////////////////////////////////
103 static const char s_content
[] = "content.xml";
104 static const char s_styles
[] = "styles.xml";
105 static const char s_meta
[] = "meta.xml";
106 static const char s_settings
[] = "settings.xml";
107 static const char s_manifest
[] = "manifest.rdf";
108 static const char s_rdfxml
[] = "application/rdf+xml";
109 static const char s_odfmime
[] = "application/vnd.oasis.opendocument.";
111 ////////////////////////////////////////////////////////////////////////////
113 static bool isContentFile(::rtl::OUString
const & i_rPath
)
115 return i_rPath
.equalsAscii(s_content
);
118 static bool isStylesFile (::rtl::OUString
const & i_rPath
)
120 return i_rPath
.equalsAscii(s_styles
);
123 static bool isReservedFile(::rtl::OUString
const & i_rPath
)
125 return isContentFile(i_rPath
)
126 || isStylesFile(i_rPath
)
127 || i_rPath
.equalsAscii(s_meta
)
128 || i_rPath
.equalsAscii(s_settings
);
131 ////////////////////////////////////////////////////////////////////////////
133 uno::Reference
<rdf::XURI
> createBaseURI(
134 uno::Reference
<uno::XComponentContext
> const & i_xContext
,
135 uno::Reference
<embed::XStorage
> const & i_xStorage
,
136 ::rtl::OUString
const & i_rPkgURI
, ::rtl::OUString
const & i_rSubDocument
)
138 if (!i_xContext
.is() || !i_xStorage
.is() || !i_rPkgURI
.getLength()) {
139 throw uno::RuntimeException();
142 const uno::Reference
<lang::XMultiComponentFactory
> xServiceFactory(
143 i_xContext
->getServiceManager(), uno::UNO_SET_THROW
);
144 const uno::Reference
<uri::XUriReferenceFactory
> xUriFactory(
145 xServiceFactory
->createInstanceWithContext(
146 ::rtl::OUString::createFromAscii(
147 "com.sun.star.uri.UriReferenceFactory"), i_xContext
),
148 uno::UNO_QUERY_THROW
);
149 uno::Reference
< uri::XUriReference
> xBaseURI
;
151 const uno::Reference
< uri::XUriReference
> xPkgURI(
152 xUriFactory
->parse(i_rPkgURI
), uno::UNO_SET_THROW
);
153 xPkgURI
->clearFragment();
154 // need to know whether the storage is a FileSystemStorage
155 // XServiceInfo would be better, but it is not implemented
156 // if ( i_rPkgURI.getLength() && ::utl::UCBContentHelper::IsFolder(i_rPkgURI) )
158 xBaseURI
.set( xPkgURI
, uno::UNO_SET_THROW
);
161 const uno::Reference
<uri::XVndSunStarPkgUrlReferenceFactory
>
162 xPkgUriFactory( xServiceFactory
->createInstanceWithContext(
163 ::rtl::OUString::createFromAscii(
164 "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory"),
166 uno::UNO_QUERY_THROW
);
167 xBaseURI
.set( xPkgUriFactory
->createVndSunStarPkgUrlReference(xPkgURI
),
168 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
.getLength())
184 buf
.append(i_rSubDocument
);
185 buf
.append(static_cast<sal_Unicode
>('/'));
187 const ::rtl::OUString
Path(buf
.makeStringAndClear());
188 if (Path
.getLength())
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());
201 ////////////////////////////////////////////////////////////////////////////
203 struct DocumentMetadataAccess_Impl
205 // note: these are all initialized in constructor, and loadFromStorage
206 const uno::Reference
<uno::XComponentContext
> m_xContext
;
207 const IXmlIdRegistrySupplier
& m_rXmlIdRegistrySupplier
;
208 uno::Reference
<rdf::XURI
> m_xBaseURI
;
209 uno::Reference
<rdf::XRepository
> m_xRepository
;
210 uno::Reference
<rdf::XNamedGraph
> m_xManifest
;
211 DocumentMetadataAccess_Impl(
212 uno::Reference
<uno::XComponentContext
> const& i_xContext
,
213 IXmlIdRegistrySupplier
const & i_rRegistrySupplier
)
214 : m_xContext(i_xContext
)
215 , m_rXmlIdRegistrySupplier(i_rRegistrySupplier
)
220 OSL_ENSURE(m_xContext
.is(), "context null");
224 // this is... a hack.
225 template<sal_Int16 Constant
>
226 /*static*/ uno::Reference
<rdf::XURI
>
227 getURI(uno::Reference
< uno::XComponentContext
> const & i_xContext
)
229 static uno::Reference
< rdf::XURI
> xURI(
230 rdf::URI::createKnown(i_xContext
, Constant
), uno::UNO_QUERY_THROW
);
235 /** would storing the file to a XStorage succeed? */
236 static bool isFileNameValid(const ::rtl::OUString
& i_rFileName
)
238 if (i_rFileName
.getLength() <= 0) return false;
239 if (i_rFileName
[0] == '/') return false; // no absolute paths!
242 const ::rtl::OUString
segment(
243 i_rFileName
.getToken(0, static_cast<sal_Unicode
> ('/'), idx
) );
244 if (!segment
.getLength() || // no empty segments
245 segment
.equalsAscii(".") || // no . segments
246 segment
.equalsAscii("..") || // no .. segments
247 !::comphelper::OStorageHelper::IsValidZipEntryFileName(
248 segment
, sal_False
)) // no invalid characters
254 /** split a uri hierarchy into first segment and rest */
256 splitPath(::rtl::OUString
const & i_rPath
,
257 ::rtl::OUString
& o_rDir
, ::rtl::OUString
& o_rRest
)
259 const sal_Int32
idx(i_rPath
.indexOf(static_cast<sal_Unicode
>('/')));
260 if (idx
< 0 || idx
>= i_rPath
.getLength()) {
261 o_rDir
= ::rtl::OUString();
264 } else if (idx
== 0 || idx
== i_rPath
.getLength() - 1) {
265 // input must not start or end with '/'
268 o_rDir
= (i_rPath
.copy(0, idx
));
269 o_rRest
= (i_rPath
.copy(idx
+1));
275 splitXmlId(::rtl::OUString
const & i_XmlId
,
276 ::rtl::OUString
& o_StreamName
, ::rtl::OUString
& o_Idref
)
278 const sal_Int32
idx(i_XmlId
.indexOf(static_cast<sal_Unicode
>('#')));
279 if ((idx
<= 0) || (idx
>= i_XmlId
.getLength() - 1)) {
282 o_StreamName
= (i_XmlId
.copy(0, idx
));
283 o_Idref
= (i_XmlId
.copy(idx
+1));
284 return isValidXmlId(o_StreamName
, o_Idref
);
288 ////////////////////////////////////////////////////////////////////////////
290 static uno::Reference
<rdf::XURI
>
291 getURIForStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
292 ::rtl::OUString
const& i_rPath
)
294 const uno::Reference
<rdf::XURI
> xURI(
295 rdf::URI::createNS( i_rImpl
.m_xContext
,
296 i_rImpl
.m_xBaseURI
->getStringValue(), i_rPath
),
301 /** add statements declaring i_xResource to be a file of type i_xType with
302 path i_rPath to manifest, with optional additional types i_pTypes */
304 addFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
305 uno::Reference
<rdf::XURI
> const& i_xType
,
306 ::rtl::OUString
const & i_rPath
,
307 const uno::Sequence
< uno::Reference
< rdf::XURI
> > * i_pTypes
= 0)
310 const uno::Reference
<rdf::XURI
> xURI( getURIForStream(
313 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
314 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
316 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
317 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
320 for (sal_Int32 i
= 0; i
< i_pTypes
->getLength(); ++i
) {
321 i_rImpl
.m_xManifest
->addStatement(xURI
.get(),
322 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
323 (*i_pTypes
)[i
].get());
326 } catch (uno::RuntimeException
&) {
328 } catch (uno::Exception
& e
) {
329 throw lang::WrappedTargetRuntimeException(
330 ::rtl::OUString::createFromAscii(
331 "addFile: exception"), /*this*/0, uno::makeAny(e
));
335 /** add content.xml or styles.xml to manifest */
337 addContentOrStylesFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
338 const ::rtl::OUString
& i_rPath
)
340 uno::Reference
<rdf::XURI
> xType
;
341 if (isContentFile(i_rPath
)) {
342 xType
.set(getURI
<rdf::URIs::ODF_CONTENTFILE
>(i_rImpl
.m_xContext
));
343 } else if (isStylesFile(i_rPath
)) {
344 xType
.set(getURI
<rdf::URIs::ODF_STYLESFILE
>(i_rImpl
.m_xContext
));
348 addFile(i_rImpl
, xType
.get(), i_rPath
);
352 /** add metadata file to manifest */
354 addMetadataFileImpl(struct DocumentMetadataAccess_Impl
& i_rImpl
,
355 const ::rtl::OUString
& i_rPath
,
356 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
359 getURI
<rdf::URIs::PKG_METADATAFILE
>(i_rImpl
.m_xContext
),
363 /** remove a file from the manifest */
365 removeFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
366 uno::Reference
<rdf::XURI
> const& i_xPart
)
368 if (!i_xPart
.is()) throw uno::RuntimeException();
370 i_rImpl
.m_xManifest
->removeStatements(i_rImpl
.m_xBaseURI
.get(),
371 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
),
373 i_rImpl
.m_xManifest
->removeStatements(i_xPart
.get(),
374 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
), 0);
375 } catch (uno::RuntimeException
&) {
377 } catch (uno::Exception
& e
) {
378 throw lang::WrappedTargetRuntimeException(
379 ::rtl::OUString::createFromAscii("removeFile: exception"),
384 static ::std::vector
< uno::Reference
< rdf::XURI
> >
385 getAllParts(struct DocumentMetadataAccess_Impl
& i_rImpl
)
387 ::std::vector
< uno::Reference
< rdf::XURI
> > ret
;
389 const uno::Reference
<container::XEnumeration
> xEnum(
390 i_rImpl
.m_xManifest
->getStatements( i_rImpl
.m_xBaseURI
.get(),
391 getURI
<rdf::URIs::PKG_HASPART
>(i_rImpl
.m_xContext
), 0),
393 while (xEnum
->hasMoreElements()) {
395 if (!(xEnum
->nextElement() >>= stmt
)) {
396 throw uno::RuntimeException();
398 const uno::Reference
<rdf::XURI
> xPart(stmt
.Object
,
400 if (!xPart
.is()) continue;
401 ret
.push_back(xPart
);
404 } catch (uno::RuntimeException
&) {
406 } catch (uno::Exception
& e
) {
407 throw lang::WrappedTargetRuntimeException(
408 ::rtl::OUString::createFromAscii("getAllParts: exception"),
414 isPartOfType(struct DocumentMetadataAccess_Impl
& i_rImpl
,
415 uno::Reference
<rdf::XURI
> const & i_xPart
,
416 uno::Reference
<rdf::XURI
> const & i_xType
)
418 if (!i_xPart
.is() || !i_xType
.is()) throw uno::RuntimeException();
420 const uno::Reference
<container::XEnumeration
> xEnum(
421 i_rImpl
.m_xManifest
->getStatements(i_xPart
.get(),
422 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
425 return (xEnum
->hasMoreElements());
426 } catch (uno::RuntimeException
&) {
428 } catch (uno::Exception
& e
) {
429 throw lang::WrappedTargetRuntimeException(
430 ::rtl::OUString::createFromAscii("isPartOfType: exception"),
435 ////////////////////////////////////////////////////////////////////////////
437 static ucb::InteractiveAugmentedIOException
438 mkException( ::rtl::OUString
const & i_rMessage
,
439 ucb::IOErrorCode
const i_ErrorCode
,
440 ::rtl::OUString
const & i_rUri
, ::rtl::OUString
const & i_rResource
)
442 ucb::InteractiveAugmentedIOException iaioe
;
443 iaioe
.Message
= i_rMessage
;
444 iaioe
.Classification
= task::InteractionClassification_ERROR
;
445 iaioe
.Code
= i_ErrorCode
;
447 const beans::PropertyValue
uriProp(::rtl::OUString::createFromAscii("Uri"),
448 -1, uno::makeAny(i_rUri
), static_cast<beans::PropertyState
>(0));
449 const beans::PropertyValue
rnProp(
450 ::rtl::OUString::createFromAscii("ResourceName"),
451 -1, uno::makeAny(i_rResource
), static_cast<beans::PropertyState
>(0));
452 iaioe
.Arguments
= ::comphelper::makeSequence(
453 uno::makeAny(uriProp
), uno::makeAny(rnProp
));
457 /** error handling policy.
458 <p>If a handler is given, ask it how to proceed:
459 <ul><li>(default:) cancel import, raise exception</li>
460 <li>ignore the error and continue</li>
461 <li>retry the action that led to the error</li></ul></p>
462 N.B.: must not be called before DMA is fully initalized!
463 @returns true iff caller should retry
466 handleError( ucb::InteractiveAugmentedIOException
const & i_rException
,
467 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
469 if (!i_xHandler
.is()) {
470 throw lang::WrappedTargetException(::rtl::OUString::createFromAscii(
471 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
472 /* *this*/ 0, uno::makeAny(i_rException
));
475 ::rtl::Reference
< ::comphelper::OInteractionRequest
> pRequest(
476 new ::comphelper::OInteractionRequest(uno::makeAny(i_rException
)) );
477 ::rtl::Reference
< ::comphelper::OInteractionRetry
> pRetry(
478 new ::comphelper::OInteractionRetry
);
479 ::rtl::Reference
< ::comphelper::OInteractionApprove
> pApprove(
480 new ::comphelper::OInteractionApprove
);
481 ::rtl::Reference
< ::comphelper::OInteractionAbort
> pAbort(
482 new ::comphelper::OInteractionAbort
);
483 /* this does not seem to work
484 if (i_rException.Code != ucb::IOErrorCode_WRONG_FORMAT) {
485 pRequest->addContinuation( pRetry.get() );
488 pRequest
->addContinuation( pApprove
.get() );
489 pRequest
->addContinuation( pAbort
.get() );
490 // actually call the handler
491 i_xHandler
->handle( pRequest
.get() );
492 if (pRetry
->wasSelected()) {
494 } else if (pApprove
->wasSelected()) {
497 OSL_ENSURE(pAbort
->wasSelected(), "no continuation selected?");
498 throw lang::WrappedTargetException(::rtl::OUString::createFromAscii(
499 "DocumentMetadataAccess::loadMetadataFromStorage: exception"),
500 /* *this*/ 0, uno::makeAny(i_rException
));
504 /** check if storage has content.xml/styles.xml;
505 e.g. ODB files seem to only have content.xml */
507 collectFilesFromStorage(uno::Reference
<embed::XStorage
> const& i_xStorage
,
508 ::rtl::OUString i_Path
,
509 std::set
< ::rtl::OUString
> & o_rFiles
)
511 static ::rtl::OUString
content(::rtl::OUString::createFromAscii(s_content
));
512 static ::rtl::OUString
styles (::rtl::OUString::createFromAscii(s_styles
));
514 if (i_xStorage
->hasByName(content
) &&
515 i_xStorage
->isStreamElement(content
))
517 o_rFiles
.insert(i_Path
+ content
);
519 if (i_xStorage
->hasByName(styles
) &&
520 i_xStorage
->isStreamElement(styles
))
522 o_rFiles
.insert(i_Path
+ styles
);
524 } catch (uno::Exception
&) {
525 OSL_TRACE("collectFilesFromStorage: exception?");
529 /** import a metadata file into repository */
531 readStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
532 uno::Reference
< embed::XStorage
> const & i_xStorage
,
533 ::rtl::OUString
const & i_rPath
,
534 ::rtl::OUString
const & i_rBaseURI
)
537 ::rtl::OUString rest
;
539 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
540 if (dir
.equalsAscii("")) {
541 if (i_xStorage
->isStreamElement(i_rPath
)) {
542 const uno::Reference
<io::XStream
> xStream(
543 i_xStorage
->openStreamElement(i_rPath
,
544 embed::ElementModes::READ
), uno::UNO_SET_THROW
);
545 const uno::Reference
<io::XInputStream
> xInStream(
546 xStream
->getInputStream(), uno::UNO_SET_THROW
);
547 const uno::Reference
<rdf::XURI
> xBaseURI(
548 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
549 const uno::Reference
<rdf::XURI
> xURI(
550 rdf::URI::createNS(i_rImpl
.m_xContext
,
551 i_rBaseURI
, i_rPath
));
552 i_rImpl
.m_xRepository
->importGraph(rdf::FileFormat::RDF_XML
,
553 xInStream
, xURI
, xBaseURI
);
555 throw mkException(::rtl::OUString::createFromAscii(
556 "readStream: is not a stream"),
557 ucb::IOErrorCode_NO_FILE
, i_rBaseURI
+ i_rPath
, i_rPath
);
560 if (i_xStorage
->isStorageElement(dir
)) {
561 const uno::Reference
<embed::XStorage
> xDir(
562 i_xStorage
->openStorageElement(dir
,
563 embed::ElementModes::READ
));
564 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
565 uno::UNO_QUERY_THROW
);
567 ::rtl::OUString mimeType
;
568 xDirProps
->getPropertyValue(
569 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
571 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1))
573 OSL_TRACE("readStream: "
574 "refusing to recurse into embedded document");
577 } catch (uno::Exception
&) { }
578 ::rtl::OUStringBuffer
buf(i_rBaseURI
);
579 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
580 readStream(i_rImpl
, xDir
, rest
, buf
.makeStringAndClear() );
582 throw mkException(::rtl::OUString::createFromAscii(
583 "readStream: is not a directory"),
584 ucb::IOErrorCode_NO_DIRECTORY
, i_rBaseURI
+ dir
, dir
);
587 } catch (container::NoSuchElementException
& e
) {
588 throw mkException(e
.Message
, ucb::IOErrorCode_NOT_EXISTING_PATH
,
589 i_rBaseURI
+ i_rPath
, i_rPath
);
590 } catch (io::IOException
& e
) {
591 throw mkException(e
.Message
, ucb::IOErrorCode_CANT_READ
,
592 i_rBaseURI
+ i_rPath
, i_rPath
);
593 } catch (rdf::ParseException
& e
) {
594 throw mkException(e
.Message
, ucb::IOErrorCode_WRONG_FORMAT
,
595 i_rBaseURI
+ i_rPath
, i_rPath
);
599 /** import a metadata file into repository */
601 importFile(struct DocumentMetadataAccess_Impl
& i_rImpl
,
602 uno::Reference
<embed::XStorage
> const & i_xStorage
,
603 ::rtl::OUString
const & i_rBaseURI
,
604 uno::Reference
<task::XInteractionHandler
> const & i_xHandler
,
605 ::rtl::OUString i_rPath
)
609 readStream(i_rImpl
, i_xStorage
, i_rPath
, i_rBaseURI
);
610 } catch (ucb::InteractiveAugmentedIOException
& e
) {
611 if (handleError(e
, i_xHandler
)) goto retry
;
612 } catch (uno::RuntimeException
&) {
614 } catch (uno::Exception
& e
) {
615 throw lang::WrappedTargetRuntimeException(
616 ::rtl::OUString::createFromAscii("importFile: exception"),
621 /** actually write a metadata file to the storage */
623 exportStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
624 uno::Reference
< embed::XStorage
> const & i_xStorage
,
625 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
626 ::rtl::OUString
const & i_rFileName
,
627 ::rtl::OUString
const & i_rBaseURI
)
629 const uno::Reference
<io::XStream
> xStream(
630 i_xStorage
->openStreamElement(i_rFileName
,
631 embed::ElementModes::WRITE
| embed::ElementModes::TRUNCATE
),
633 const uno::Reference
< beans::XPropertySet
> xStreamProps(xStream
,
635 if (xStreamProps
.is()) { // this is NOT supported in FileSystemStorage
636 xStreamProps
->setPropertyValue(
637 ::rtl::OUString::createFromAscii("MediaType"),
638 uno::makeAny(::rtl::OUString::createFromAscii(s_rdfxml
)));
640 const uno::Reference
<io::XOutputStream
> xOutStream(
641 xStream
->getOutputStream(), uno::UNO_SET_THROW
);
642 const uno::Reference
<rdf::XURI
> xBaseURI(
643 rdf::URI::create(i_rImpl
.m_xContext
, i_rBaseURI
));
644 i_rImpl
.m_xRepository
->exportGraph(rdf::FileFormat::RDF_XML
,
645 xOutStream
, i_xGraphName
, xBaseURI
);
648 /** write a metadata file to the storage */
650 writeStream(struct DocumentMetadataAccess_Impl
& i_rImpl
,
651 uno::Reference
< embed::XStorage
> const & i_xStorage
,
652 uno::Reference
<rdf::XURI
> const & i_xGraphName
,
653 ::rtl::OUString
const & i_rPath
,
654 ::rtl::OUString
const & i_rBaseURI
)
657 ::rtl::OUString rest
;
658 if (!splitPath(i_rPath
, dir
, rest
)) throw uno::RuntimeException();
660 if (dir
.equalsAscii("")) {
661 exportStream(i_rImpl
, i_xStorage
, i_xGraphName
, i_rPath
,
664 const uno::Reference
<embed::XStorage
> xDir(
665 i_xStorage
->openStorageElement(dir
,
666 embed::ElementModes::WRITE
));
667 const uno::Reference
< beans::XPropertySet
> xDirProps(xDir
,
668 uno::UNO_QUERY_THROW
);
670 ::rtl::OUString mimeType
;
671 xDirProps
->getPropertyValue(
672 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
674 if (mimeType
.matchAsciiL(s_odfmime
, sizeof(s_odfmime
) - 1)) {
675 OSL_TRACE("writeStream: "
676 "refusing to recurse into embedded document");
679 } catch (uno::Exception
&) { }
680 ::rtl::OUStringBuffer
buf(i_rBaseURI
);
681 buf
.append(dir
).append(static_cast<sal_Unicode
>('/'));
682 writeStream(i_rImpl
, xDir
, i_xGraphName
, rest
,
683 buf
.makeStringAndClear());
685 const uno::Reference
<embed::XTransactedObject
> xTransaction(
686 i_xStorage
, uno::UNO_QUERY
);
687 if (xTransaction
.is()) {
688 xTransaction
->commit();
690 } catch (uno::RuntimeException
&) {
692 } catch (io::IOException
&) {
698 initLoading(struct DocumentMetadataAccess_Impl
& i_rImpl
,
699 const uno::Reference
< embed::XStorage
> & i_xStorage
,
700 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
701 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
705 i_rImpl
.m_xManifest
.clear();
707 i_rImpl
.m_xBaseURI
= i_xBaseURI
;
710 i_rImpl
.m_xRepository
.clear();
711 i_rImpl
.m_xRepository
.set(rdf::Repository::create(i_rImpl
.m_xContext
),
714 const ::rtl::OUString
manifest (
715 ::rtl::OUString::createFromAscii(s_manifest
));
716 const ::rtl::OUString
baseURI( i_xBaseURI
->getStringValue() );
717 // try to delay raising errors until after initialization is done
719 ucb::InteractiveAugmentedIOException iaioe
;
722 const uno::Reference
<rdf::XURI
> xManifest(
723 getURIForStream(i_rImpl
, manifest
));
725 readStream(i_rImpl
, i_xStorage
, manifest
, baseURI
);
726 } catch (ucb::InteractiveAugmentedIOException
& e
) {
727 // no manifest.rdf: this is not an error in ODF < 1.2
728 if (!(ucb::IOErrorCode_NOT_EXISTING_PATH
== e
.Code
)) {
732 } catch (uno::Exception
& e
) {
736 // init manifest graph
737 const uno::Reference
<rdf::XNamedGraph
> xManifestGraph(
738 i_rImpl
.m_xRepository
->getGraph(xManifest
));
739 i_rImpl
.m_xManifest
.set(xManifestGraph
.is() ? xManifestGraph
:
740 i_rImpl
.m_xRepository
->createGraph(xManifest
), uno::UNO_SET_THROW
);
741 const uno::Reference
<container::XEnumeration
> xEnum(
742 i_rImpl
.m_xManifest
->getStatements(0,
743 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
744 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get()));
746 // document statement
747 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
748 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
749 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
751 OSL_ENSURE(i_rImpl
.m_xBaseURI
.is(), "base URI is null");
752 OSL_ENSURE(i_rImpl
.m_xRepository
.is(), "repository is null");
753 OSL_ENSURE(i_rImpl
.m_xManifest
.is(), "manifest is null");
755 if (rterr
.hasValue()) {
756 throw lang::WrappedTargetRuntimeException(
757 ::rtl::OUString::createFromAscii(
758 "DocumentMetadataAccess::loadMetadataFromStorage: "
759 "exception"), 0, rterr
);
763 if (handleError(iaioe
, i_xHandler
)) goto retry
;
767 /** init Impl struct */
768 static void init(struct DocumentMetadataAccess_Impl
& i_rImpl
)
772 i_rImpl
.m_xManifest
.set(i_rImpl
.m_xRepository
->createGraph(
773 getURIForStream(i_rImpl
,
774 ::rtl::OUString::createFromAscii(s_manifest
))),
777 // insert the document statement
778 i_rImpl
.m_xManifest
->addStatement(i_rImpl
.m_xBaseURI
.get(),
779 getURI
<rdf::URIs::RDF_TYPE
>(i_rImpl
.m_xContext
),
780 getURI
<rdf::URIs::PKG_DOCUMENT
>(i_rImpl
.m_xContext
).get());
781 } catch (uno::Exception
& e
) {
782 throw lang::WrappedTargetRuntimeException(
783 ::rtl::OUString::createFromAscii("init: unexpected exception"), 0,
787 // add top-level content files
788 if (!addContentOrStylesFileImpl(i_rImpl
,
789 ::rtl::OUString::createFromAscii(s_content
))) {
790 throw uno::RuntimeException();
792 if (!addContentOrStylesFileImpl(i_rImpl
,
793 ::rtl::OUString::createFromAscii(s_styles
))) {
794 throw uno::RuntimeException();
799 ////////////////////////////////////////////////////////////////////////////
801 DocumentMetadataAccess::DocumentMetadataAccess(
802 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
803 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
)
804 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
806 // no initalization: must call loadFrom...
809 DocumentMetadataAccess::DocumentMetadataAccess(
810 uno::Reference
< uno::XComponentContext
> const & i_xContext
,
811 const IXmlIdRegistrySupplier
& i_rRegistrySupplier
,
812 ::rtl::OUString
const & i_rURI
)
813 : m_pImpl(new DocumentMetadataAccess_Impl(i_xContext
, i_rRegistrySupplier
))
815 OSL_ENSURE(i_rURI
.getLength(), "DMA::DMA: no URI given!");
816 OSL_ENSURE(i_rURI
.endsWithAsciiL("/", 1), "DMA::DMA: URI without / given!");
817 if (!i_rURI
.endsWithAsciiL("/", 1)) throw uno::RuntimeException();
818 m_pImpl
->m_xBaseURI
.set(rdf::URI::create(m_pImpl
->m_xContext
, i_rURI
));
819 m_pImpl
->m_xRepository
.set(rdf::Repository::create(m_pImpl
->m_xContext
),
825 OSL_ENSURE(m_pImpl
->m_xBaseURI
.is(), "base URI is null");
826 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository is null");
827 OSL_ENSURE(m_pImpl
->m_xManifest
.is(), "manifest is null");
830 DocumentMetadataAccess::~DocumentMetadataAccess()
835 // ::com::sun::star::rdf::XRepositorySupplier:
836 uno::Reference
< rdf::XRepository
> SAL_CALL
837 DocumentMetadataAccess::getRDFRepository() throw (uno::RuntimeException
)
839 OSL_ENSURE(m_pImpl
->m_xRepository
.is(), "repository not initialized");
840 return m_pImpl
->m_xRepository
;
843 // ::com::sun::star::rdf::XNode:
844 ::rtl::OUString SAL_CALL
845 DocumentMetadataAccess::getStringValue() throw (uno::RuntimeException
)
847 return m_pImpl
->m_xBaseURI
->getStringValue();
850 // ::com::sun::star::rdf::XURI:
851 ::rtl::OUString SAL_CALL
852 DocumentMetadataAccess::getNamespace() throw (uno::RuntimeException
)
854 return m_pImpl
->m_xBaseURI
->getNamespace();
857 ::rtl::OUString SAL_CALL
858 DocumentMetadataAccess::getLocalName() throw (uno::RuntimeException
)
860 return m_pImpl
->m_xBaseURI
->getLocalName();
863 // ::com::sun::star::rdf::XDocumentMetadataAccess:
864 uno::Reference
< rdf::XMetadatable
> SAL_CALL
865 DocumentMetadataAccess::getElementByMetadataReference(
866 const ::com::sun::star::beans::StringPair
& i_rReference
)
867 throw (uno::RuntimeException
)
869 const IXmlIdRegistry
* pReg(
870 m_pImpl
->m_rXmlIdRegistrySupplier
.GetXmlIdRegistry() );
872 throw uno::RuntimeException(::rtl::OUString::createFromAscii(
873 "DocumentMetadataAccess::getElementByXmlId: no registry"), *this);
875 return pReg
->GetElementByMetadataReference(i_rReference
);
878 uno::Reference
< rdf::XMetadatable
> SAL_CALL
879 DocumentMetadataAccess::getElementByURI(
880 const uno::Reference
< rdf::XURI
> & i_xURI
)
881 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
884 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
885 "DocumentMetadataAccess::getElementByURI: URI is null"), *this, 0);
888 const ::rtl::OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
889 const ::rtl::OUString
name( i_xURI
->getStringValue() );
890 if (!name
.match(baseURI
)) {
893 const ::rtl::OUString
relName( name
.copy(baseURI
.getLength()) );
894 ::rtl::OUString path
;
895 ::rtl::OUString idref
;
896 if (!splitXmlId(relName
, path
, idref
)) {
900 return getElementByMetadataReference( beans::StringPair(path
, idref
) );
904 uno::Sequence
< uno::Reference
< rdf::XURI
> > SAL_CALL
905 DocumentMetadataAccess::getMetadataGraphsWithType(
906 const uno::Reference
<rdf::XURI
> & i_xType
)
907 throw (uno::RuntimeException
, lang::IllegalArgumentException
)
910 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
911 "DocumentMetadataAccess::getMetadataGraphsWithType: "
912 "type is null"), *this, 0);
915 ::comphelper::SequenceAsVector
< uno::Reference
< rdf::XURI
> > ret
;
916 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
917 getAllParts(*m_pImpl
) );
918 ::std::remove_copy_if(parts
.begin(), parts
.end(),
919 ::std::back_inserter(ret
),
921 ::std::logical_not
<bool>(),
922 ::boost::bind(&isPartOfType
, ::boost::ref(*m_pImpl
), _1
, i_xType
) ));
923 return ret
.getAsConstList();
926 uno::Reference
<rdf::XURI
> SAL_CALL
927 DocumentMetadataAccess::addMetadataFile(const ::rtl::OUString
& i_rFileName
,
928 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
929 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
930 container::ElementExistException
)
932 if (!isFileNameValid(i_rFileName
)) {
933 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
934 "DocumentMetadataAccess::addMetadataFile: invalid FileName"),
937 if (isReservedFile(i_rFileName
)) {
938 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
939 "DocumentMetadataAccess::addMetadataFile:"
940 "invalid FileName: reserved"), *this, 0);
942 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
943 if (!i_rTypes
[i
].is()) {
944 throw lang::IllegalArgumentException(
945 ::rtl::OUString::createFromAscii(
946 "DocumentMetadataAccess::addMetadataFile: "
947 "null type"), *this, 2);
951 const uno::Reference
<rdf::XURI
> xGraphName(
952 getURIForStream(*m_pImpl
, i_rFileName
) );
955 m_pImpl
->m_xRepository
->createGraph(xGraphName
);
956 } catch (rdf::RepositoryException
& e
) {
957 throw lang::WrappedTargetRuntimeException(
958 ::rtl::OUString::createFromAscii(
959 "DocumentMetadataAccess::addMetadataFile: exception"),
960 *this, uno::makeAny(e
));
961 // note: all other exceptions are propagated
964 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
968 uno::Reference
<rdf::XURI
> SAL_CALL
969 DocumentMetadataAccess::importMetadataFile(::sal_Int16 i_Format
,
970 const uno::Reference
< io::XInputStream
> & i_xInStream
,
971 const ::rtl::OUString
& i_rFileName
,
972 const uno::Reference
< rdf::XURI
> & i_xBaseURI
,
973 const uno::Sequence
< uno::Reference
< rdf::XURI
> > & i_rTypes
)
974 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
975 datatransfer::UnsupportedFlavorException
,
976 container::ElementExistException
, rdf::ParseException
, io::IOException
)
978 if (!isFileNameValid(i_rFileName
)) {
979 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
980 "DocumentMetadataAccess::importMetadataFile: invalid FileName"),
983 if (isReservedFile(i_rFileName
)) {
984 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
985 "DocumentMetadataAccess::importMetadataFile:"
986 "invalid FileName: reserved"), *this, 0);
988 for (sal_Int32 i
= 0; i
< i_rTypes
.getLength(); ++i
) {
989 if (!i_rTypes
[i
].is()) {
990 throw lang::IllegalArgumentException(
991 ::rtl::OUString::createFromAscii(
992 "DocumentMetadataAccess::importMetadataFile: null type"),
997 const uno::Reference
<rdf::XURI
> xGraphName(
998 getURIForStream(*m_pImpl
, i_rFileName
) );
1001 m_pImpl
->m_xRepository
->importGraph(
1002 i_Format
, i_xInStream
, xGraphName
, i_xBaseURI
);
1003 } catch (rdf::RepositoryException
& e
) {
1004 throw lang::WrappedTargetRuntimeException(
1005 ::rtl::OUString::createFromAscii(
1006 "DocumentMetadataAccess::importMetadataFile: "
1007 "RepositoryException"), *this, uno::makeAny(e
));
1008 // note: all other exceptions are propagated
1012 addMetadataFileImpl(*m_pImpl
, i_rFileName
, i_rTypes
);
1017 DocumentMetadataAccess::removeMetadataFile(
1018 const uno::Reference
< rdf::XURI
> & i_xGraphName
)
1019 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1020 container::NoSuchElementException
)
1023 m_pImpl
->m_xRepository
->destroyGraph(i_xGraphName
);
1024 } catch (rdf::RepositoryException
& e
) {
1025 throw lang::WrappedTargetRuntimeException(
1026 ::rtl::OUString::createFromAscii(
1027 "DocumentMetadataAccess::removeMetadataFile: "
1028 "RepositoryException"), *this, uno::makeAny(e
));
1029 // note: all other exceptions are propagated
1032 // remove file from manifest
1033 removeFile(*m_pImpl
, i_xGraphName
.get());
1037 DocumentMetadataAccess::addContentOrStylesFile(
1038 const ::rtl::OUString
& i_rFileName
)
1039 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1040 container::ElementExistException
)
1042 if (!isFileNameValid(i_rFileName
)) {
1043 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1044 "DocumentMetadataAccess::addContentOrStylesFile: "
1045 "invalid FileName"), *this, 0);
1048 if (!addContentOrStylesFileImpl(*m_pImpl
, i_rFileName
)) {
1049 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1050 "DocumentMetadataAccess::addContentOrStylesFile: "
1051 "invalid FileName: must end with content.xml or styles.xml"),
1057 DocumentMetadataAccess::removeContentOrStylesFile(
1058 const ::rtl::OUString
& i_rFileName
)
1059 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1060 container::NoSuchElementException
)
1062 if (!isFileNameValid(i_rFileName
)) {
1063 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1064 "DocumentMetadataAccess::removeContentOrStylesFile: "
1065 "invalid FileName"), *this, 0);
1069 const uno::Reference
<rdf::XURI
> xPart(
1070 getURIForStream(*m_pImpl
, i_rFileName
) );
1071 const uno::Reference
<container::XEnumeration
> xEnum(
1072 m_pImpl
->m_xManifest
->getStatements( m_pImpl
->m_xBaseURI
.get(),
1073 getURI
<rdf::URIs::PKG_HASPART
>(m_pImpl
->m_xContext
),
1075 uno::UNO_SET_THROW
);
1076 if (!xEnum
->hasMoreElements()) {
1077 throw container::NoSuchElementException(
1078 ::rtl::OUString::createFromAscii(
1079 "DocumentMetadataAccess::removeContentOrStylesFile: "
1080 "cannot find stream in manifest graph: ") + i_rFileName
,
1084 // remove file from manifest
1085 removeFile(*m_pImpl
, xPart
);
1087 } catch (uno::RuntimeException
&) {
1089 } catch (uno::Exception
& e
) {
1090 throw lang::WrappedTargetRuntimeException(
1091 ::rtl::OUString::createFromAscii(
1092 "DocumentMetadataAccess::removeContentOrStylesFile: exception"),
1093 *this, uno::makeAny(e
));
1097 void SAL_CALL
DocumentMetadataAccess::loadMetadataFromStorage(
1098 const uno::Reference
< embed::XStorage
> & i_xStorage
,
1099 const uno::Reference
<rdf::XURI
> & i_xBaseURI
,
1100 const uno::Reference
<task::XInteractionHandler
> & i_xHandler
)
1101 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1102 lang::WrappedTargetException
)
1104 if (!i_xStorage
.is()) {
1105 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1106 "DocumentMetadataAccess::loadMetadataFromStorage: "
1107 "storage is null"), *this, 0);
1109 if (!i_xBaseURI
.is()) {
1110 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1111 "DocumentMetadataAccess::loadMetadataFromStorage: "
1112 "base URI is null"), *this, 1);
1114 const ::rtl::OUString
baseURI( i_xBaseURI
->getStringValue());
1115 if (baseURI
.indexOf('#') >= 0) {
1116 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1117 "DocumentMetadataAccess::loadMetadataFromStorage: "
1118 "base URI not absolute"), *this, 1);
1120 if (!baseURI
.getLength() || !baseURI
.endsWithAsciiL("/", 1)) {
1121 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1122 "DocumentMetadataAccess::loadMetadataFromStorage: "
1123 "base URI does not end with slash"), *this, 1);
1126 initLoading(*m_pImpl
, i_xStorage
, i_xBaseURI
, i_xHandler
);
1128 std::set
< ::rtl::OUString
> StgFiles
;
1129 collectFilesFromStorage(i_xStorage
,
1130 ::rtl::OUString::createFromAscii(""), StgFiles
);
1132 std::vector
< ::rtl::OUString
> MfstMetadataFiles
;
1135 const ::std::vector
< uno::Reference
< rdf::XURI
> > parts(
1136 getAllParts(*m_pImpl
) );
1137 const uno::Reference
<rdf::XURI
> xContentFile(
1138 getURI
<rdf::URIs::ODF_CONTENTFILE
>(m_pImpl
->m_xContext
));
1139 const uno::Reference
<rdf::XURI
> xStylesFile(
1140 getURI
<rdf::URIs::ODF_STYLESFILE
>(m_pImpl
->m_xContext
));
1141 const uno::Reference
<rdf::XURI
> xMetadataFile(
1142 getURI
<rdf::URIs::PKG_METADATAFILE
>(m_pImpl
->m_xContext
));
1143 const sal_Int32
len( baseURI
.getLength() );
1144 const ::rtl::OUString
manifest (
1145 ::rtl::OUString::createFromAscii(s_manifest
));
1146 for (::std::vector
< uno::Reference
< rdf::XURI
> >::const_iterator it
1148 it
!= parts
.end(); ++it
) {
1149 const ::rtl::OUString
name((*it
)->getStringValue());
1150 if (!name
.match(baseURI
)) {
1151 OSL_TRACE("loadMetadataFromStorage: graph not in document: %s",
1152 ::rtl::OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1156 const ::rtl::OUString
relName( name
.copy(len
) );
1157 if (relName
== manifest
) {
1158 OSL_TRACE("loadMetadataFromStorage: "
1159 "found ourselves a recursive manifest!");
1162 // remove found items from StgFiles
1163 StgFiles
.erase(relName
);
1164 if (isContentFile(relName
)) {
1165 if (!isPartOfType(*m_pImpl
, *it
, xContentFile
)) {
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
),
1171 xContentFile
.get());
1173 } else if (isStylesFile(relName
)) {
1174 if (!isPartOfType(*m_pImpl
, *it
, xStylesFile
)) {
1175 const uno::Reference
<rdf::XURI
> xName(
1176 getURIForStream(*m_pImpl
, relName
) );
1177 // add missing type statement
1178 m_pImpl
->m_xManifest
->addStatement(xName
.get(),
1179 getURI
<rdf::URIs::RDF_TYPE
>(m_pImpl
->m_xContext
),
1182 } else if (isReservedFile(relName
)) {
1183 OSL_TRACE("loadMetadataFromStorage: "
1184 "reserved file name in manifest");
1186 if (isPartOfType(*m_pImpl
, *it
, xMetadataFile
)) {
1187 MfstMetadataFiles
.push_back(relName
);
1189 // do not add statement for MetadataFile; it could be
1190 // something else! just ignore it...
1193 } catch (uno::RuntimeException
&) {
1195 } catch (uno::Exception
& e
) {
1196 throw lang::WrappedTargetRuntimeException(
1197 ::rtl::OUString::createFromAscii(
1198 "DocumentMetadataAccess::loadMetadataFromStorage: "
1199 "exception"), *this, uno::makeAny(e
));
1202 std::for_each(StgFiles
.begin(), StgFiles
.end(),
1203 boost::bind(addContentOrStylesFileImpl
, boost::ref(*m_pImpl
), _1
));
1205 std::for_each(MfstMetadataFiles
.begin(), MfstMetadataFiles
.end(),
1206 boost::bind(importFile
, boost::ref(*m_pImpl
),
1207 i_xStorage
, baseURI
, i_xHandler
, _1
));
1210 void SAL_CALL
DocumentMetadataAccess::storeMetadataToStorage(
1211 const uno::Reference
< embed::XStorage
> & i_xStorage
)
1212 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1213 lang::WrappedTargetException
)
1215 if (!i_xStorage
.is()) {
1216 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1217 "DocumentMetadataAccess::storeMetadataToStorage: "
1218 "storage is null"), *this, 0);
1222 const ::rtl::OUString
manifest (
1223 ::rtl::OUString::createFromAscii(s_manifest
));
1224 const uno::Reference
<rdf::XURI
> xManifest(
1225 getURIForStream(*m_pImpl
, manifest
) );
1226 const ::rtl::OUString
baseURI( m_pImpl
->m_xBaseURI
->getStringValue() );
1228 writeStream(*m_pImpl
, i_xStorage
, xManifest
, manifest
, baseURI
);
1229 } catch (uno::RuntimeException
&) {
1231 } catch (io::IOException
& e
) {
1232 throw lang::WrappedTargetException( ::rtl::OUString::createFromAscii(
1233 "storeMetadataToStorage: IO exception"), *this, uno::makeAny(e
));
1234 } catch (uno::Exception
& e
) {
1235 throw lang::WrappedTargetRuntimeException(
1236 ::rtl::OUString::createFromAscii(
1237 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1240 // export metadata streams
1242 const uno::Sequence
<uno::Reference
<rdf::XURI
> > graphs(
1243 m_pImpl
->m_xRepository
->getGraphNames());
1244 const sal_Int32
len( baseURI
.getLength() );
1245 for (sal_Int32 i
= 0; i
< graphs
.getLength(); ++i
) {
1246 const uno::Reference
<rdf::XURI
> xName(graphs
[i
]);
1247 const ::rtl::OUString
name(xName
->getStringValue());
1248 if (!name
.match(baseURI
)) {
1249 OSL_TRACE("storeMetadataToStorage: graph not in document: %s",
1250 ::rtl::OUStringToOString(name
, RTL_TEXTENCODING_UTF8
)
1254 const ::rtl::OUString
relName( name
.copy(len
) );
1255 if (relName
== manifest
) {
1258 if (!isFileNameValid(relName
) || isReservedFile(relName
)) {
1259 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
1260 ::rtl::OUStringToOString(relName
, RTL_TEXTENCODING_UTF8
)
1265 writeStream(*m_pImpl
, i_xStorage
, xName
, relName
, baseURI
);
1266 } catch (uno::RuntimeException
&) {
1268 } catch (io::IOException
& e
) {
1269 throw lang::WrappedTargetException(
1270 ::rtl::OUString::createFromAscii(
1271 "storeMetadataToStorage: IO exception"),
1272 *this, uno::makeAny(e
));
1273 } catch (uno::Exception
& e
) {
1274 throw lang::WrappedTargetRuntimeException(
1275 ::rtl::OUString::createFromAscii(
1276 "storeMetadataToStorage: exception"),
1277 *this, uno::makeAny(e
));
1280 } catch (rdf::RepositoryException
& e
) {
1281 throw lang::WrappedTargetRuntimeException(
1282 ::rtl::OUString::createFromAscii(
1283 "storeMetadataToStorage: exception"), *this, uno::makeAny(e
));
1288 DocumentMetadataAccess::loadMetadataFromMedium(
1289 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1290 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1291 lang::WrappedTargetException
)
1293 uno::Reference
<io::XInputStream
> xIn
;
1294 ::comphelper::MediaDescriptor
md(i_rMedium
);
1295 ::rtl::OUString URL
;
1296 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1297 ::rtl::OUString BaseURL
;
1298 md
[ ::comphelper::MediaDescriptor::PROP_DOCUMENTBASEURL() ] >>= BaseURL
;
1299 if (md
.addInputStream()) {
1300 md
[ ::comphelper::MediaDescriptor::PROP_INPUTSTREAM() ] >>= xIn
;
1302 if (!xIn
.is() && URL
.equalsAscii("")) {
1303 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1304 "DocumentMetadataAccess::loadMetadataFromMedium: "
1305 "inalid medium: no URL, no input stream"), *this, 0);
1307 uno::Reference
<embed::XStorage
> xStorage
;
1309 const uno::Reference
<lang::XMultiServiceFactory
> xMsf (
1310 m_pImpl
->m_xContext
->getServiceManager(), uno::UNO_QUERY_THROW
);
1312 xStorage
= ::comphelper::OStorageHelper::GetStorageFromInputStream(
1314 } else { // fallback to url
1315 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1316 URL
, embed::ElementModes::READ
, xMsf
);
1318 } catch (uno::RuntimeException
&) {
1320 } catch (io::IOException
&) {
1322 } catch (uno::Exception
& e
) {
1323 throw lang::WrappedTargetException(
1324 ::rtl::OUString::createFromAscii(
1325 "DocumentMetadataAccess::loadMetadataFromMedium: "
1326 "exception"), *this, uno::makeAny(e
));
1328 if (!xStorage
.is()) {
1329 throw uno::RuntimeException(::rtl::OUString::createFromAscii(
1330 "DocumentMetadataAccess::loadMetadataFromMedium: "
1331 "cannot get Storage"), *this);
1333 uno::Reference
<rdf::XURI
> xBaseURI
;
1335 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, BaseURL
);
1336 } catch (uno::Exception
&) {
1339 xBaseURI
= createBaseURI(m_pImpl
->m_xContext
, xStorage
, URL
);
1340 } catch (uno::Exception
&) {
1341 OSL_ENSURE(false, "cannot create base URI");
1344 uno::Reference
<task::XInteractionHandler
> xIH
;
1345 md
[ ::comphelper::MediaDescriptor::PROP_INTERACTIONHANDLER() ] >>= xIH
;
1346 loadMetadataFromStorage(xStorage
, xBaseURI
, xIH
);
1350 DocumentMetadataAccess::storeMetadataToMedium(
1351 const uno::Sequence
< beans::PropertyValue
> & i_rMedium
)
1352 throw (uno::RuntimeException
, lang::IllegalArgumentException
,
1353 lang::WrappedTargetException
)
1355 ::comphelper::MediaDescriptor
md(i_rMedium
);
1356 ::rtl::OUString URL
;
1357 md
[ ::comphelper::MediaDescriptor::PROP_URL() ] >>= URL
;
1358 if (URL
.equalsAscii("")) {
1359 throw lang::IllegalArgumentException(::rtl::OUString::createFromAscii(
1360 "DocumentMetadataAccess::storeMetadataToMedium: "
1361 "invalid medium: no URL"), *this, 0);
1364 SfxMedium
aMedium(i_rMedium
);
1365 uno::Reference
<embed::XStorage
> xStorage(aMedium
.GetOutputStorage());
1368 if (xStorage
.is()) {
1371 const uno::Reference
<lang::XMultiServiceFactory
> xMsf (
1372 m_pImpl
->m_xContext
->getServiceManager(), uno::UNO_QUERY_THROW
);
1373 xStorage
= ::comphelper::OStorageHelper::GetStorageFromURL2(
1374 URL
, embed::ElementModes::WRITE
, xMsf
);
1377 if (!xStorage
.is()) {
1378 throw uno::RuntimeException(::rtl::OUString::createFromAscii(
1379 "DocumentMetadataAccess::storeMetadataToMedium: "
1380 "cannot get Storage"), *this);
1382 // set MIME type of the storage
1383 ::comphelper::MediaDescriptor::const_iterator iter
1384 = md
.find(::comphelper::MediaDescriptor::PROP_MEDIATYPE());
1385 if (iter
!= md
.end()) {
1386 uno::Reference
< beans::XPropertySet
> xProps(xStorage
,
1387 uno::UNO_QUERY_THROW
);
1389 // this is NOT supported in FileSystemStorage
1390 xProps
->setPropertyValue(
1391 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
1393 } catch (uno::Exception
&) { }
1395 storeMetadataToStorage(xStorage
);
1398 const sal_Bool bOk
= aMedium
.Commit();
1401 sal_uInt32 nError
= aMedium
.GetError();
1402 if ( nError
== ERRCODE_NONE
) {
1403 nError
= ERRCODE_IO_GENERAL
;
1405 task::ErrorCodeIOException
ex( ::rtl::OUString(),
1406 uno::Reference
< uno::XInterface
>(), nError
);
1407 throw lang::WrappedTargetException(::rtl::OUString(), *this,