Update ooo320-m1
[ooovba.git] / sfx2 / source / doc / DocumentMetadataAccess.cxx
blob112183a4efbe7d109eff3b195ec926a4605987a3
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>
49 #include <rtl/uuid.h>
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>
67 #include <vector>
68 #include <set>
69 #include <map>
70 #include <functional>
71 #include <algorithm>
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;
90 namespace sfx2 {
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) )
157 if (true) {
158 xBaseURI.set( xPkgURI, uno::UNO_SET_THROW );
159 #if 0
160 } else {
161 const uno::Reference<uri::XVndSunStarPkgUrlReferenceFactory>
162 xPkgUriFactory( xServiceFactory->createInstanceWithContext(
163 ::rtl::OUString::createFromAscii(
164 "com.sun.star.uri.VndSunStarPkgUrlReferenceFactory"),
165 i_xContext),
166 uno::UNO_QUERY_THROW);
167 xBaseURI.set( xPkgUriFactory->createVndSunStarPkgUrlReference(xPkgURI),
168 uno::UNO_SET_THROW );
169 #endif
171 ::rtl::OUStringBuffer buf;
172 if (!xBaseURI->getUriReference().endsWithAsciiL("/", 1))
174 const sal_Int32 count( xBaseURI->getPathSegmentCount() );
175 if (count > 0)
177 const ::rtl::OUString last( xBaseURI->getPathSegment(count - 1) );
178 buf.append(last);
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 );
192 xBaseURI.set(
193 xUriFactory->makeAbsolute(xBaseURI, xPathURI,
194 true, uri::RelativeUriExcessParentSegments_ERROR),
195 uno::UNO_SET_THROW);
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)
216 , m_xBaseURI()
217 , m_xRepository()
218 , m_xManifest()
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);
231 return xURI;
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!
240 sal_Int32 idx(0);
241 do {
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
249 return false;
250 } while (idx >= 0);
251 return true;
254 /** split a uri hierarchy into first segment and rest */
255 static bool
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();
262 o_rRest = i_rPath;
263 return true;
264 } else if (idx == 0 || idx == i_rPath.getLength() - 1) {
265 // input must not start or end with '/'
266 return false;
267 } else {
268 o_rDir = (i_rPath.copy(0, idx));
269 o_rRest = (i_rPath.copy(idx+1));
270 return true;
274 static bool
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)) {
280 return false;
281 } else {
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),
297 uno::UNO_SET_THROW);
298 return xURI;
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 */
303 static void
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)
309 try {
310 const uno::Reference<rdf::XURI> xURI( getURIForStream(
311 i_rImpl, i_rPath) );
313 i_rImpl.m_xManifest->addStatement(i_rImpl.m_xBaseURI.get(),
314 getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext),
315 xURI.get());
316 i_rImpl.m_xManifest->addStatement(xURI.get(),
317 getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext),
318 i_xType.get());
319 if (i_pTypes) {
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 &) {
327 throw;
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 */
336 static bool
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));
345 } else {
346 return false;
348 addFile(i_rImpl, xType.get(), i_rPath);
349 return true;
352 /** add metadata file to manifest */
353 static void
354 addMetadataFileImpl(struct DocumentMetadataAccess_Impl & i_rImpl,
355 const ::rtl::OUString & i_rPath,
356 const uno::Sequence < uno::Reference< rdf::XURI > > & i_rTypes)
358 addFile(i_rImpl,
359 getURI<rdf::URIs::PKG_METADATAFILE>(i_rImpl.m_xContext),
360 i_rPath, &i_rTypes);
363 /** remove a file from the manifest */
364 static void
365 removeFile(struct DocumentMetadataAccess_Impl & i_rImpl,
366 uno::Reference<rdf::XURI> const& i_xPart)
368 if (!i_xPart.is()) throw uno::RuntimeException();
369 try {
370 i_rImpl.m_xManifest->removeStatements(i_rImpl.m_xBaseURI.get(),
371 getURI<rdf::URIs::PKG_HASPART>(i_rImpl.m_xContext),
372 i_xPart.get());
373 i_rImpl.m_xManifest->removeStatements(i_xPart.get(),
374 getURI<rdf::URIs::RDF_TYPE>(i_rImpl.m_xContext), 0);
375 } catch (uno::RuntimeException &) {
376 throw;
377 } catch (uno::Exception & e) {
378 throw lang::WrappedTargetRuntimeException(
379 ::rtl::OUString::createFromAscii("removeFile: exception"),
380 0, uno::makeAny(e));
384 static ::std::vector< uno::Reference< rdf::XURI > >
385 getAllParts(struct DocumentMetadataAccess_Impl & i_rImpl)
387 ::std::vector< uno::Reference< rdf::XURI > > ret;
388 try {
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),
392 uno::UNO_SET_THROW);
393 while (xEnum->hasMoreElements()) {
394 rdf::Statement stmt;
395 if (!(xEnum->nextElement() >>= stmt)) {
396 throw uno::RuntimeException();
398 const uno::Reference<rdf::XURI> xPart(stmt.Object,
399 uno::UNO_QUERY);
400 if (!xPart.is()) continue;
401 ret.push_back(xPart);
403 return ret;
404 } catch (uno::RuntimeException &) {
405 throw;
406 } catch (uno::Exception & e) {
407 throw lang::WrappedTargetRuntimeException(
408 ::rtl::OUString::createFromAscii("getAllParts: exception"),
409 0, uno::makeAny(e));
413 static bool
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();
419 try {
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),
423 i_xType.get()),
424 uno::UNO_SET_THROW);
425 return (xEnum->hasMoreElements());
426 } catch (uno::RuntimeException &) {
427 throw;
428 } catch (uno::Exception & e) {
429 throw lang::WrappedTargetRuntimeException(
430 ::rtl::OUString::createFromAscii("isPartOfType: exception"),
431 0, uno::makeAny(e));
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));
454 return iaioe;
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
465 static bool
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()) {
493 return true;
494 } else if (pApprove->wasSelected()) {
495 return false;
496 } else {
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 */
506 static void
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 ));
513 try {
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 */
530 static void
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)
536 ::rtl::OUString dir;
537 ::rtl::OUString rest;
538 try {
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);
554 } else {
555 throw mkException(::rtl::OUString::createFromAscii(
556 "readStream: is not a stream"),
557 ucb::IOErrorCode_NO_FILE, i_rBaseURI + i_rPath, i_rPath);
559 } else {
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);
566 try {
567 ::rtl::OUString mimeType;
568 xDirProps->getPropertyValue(
569 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
570 >>= mimeType;
571 if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1))
573 OSL_TRACE("readStream: "
574 "refusing to recurse into embedded document");
575 return;
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() );
581 } else {
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 */
600 static void
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)
607 retry:
608 try {
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 &) {
613 throw;
614 } catch (uno::Exception & e) {
615 throw lang::WrappedTargetRuntimeException(
616 ::rtl::OUString::createFromAscii("importFile: exception"),
617 0, uno::makeAny(e));
621 /** actually write a metadata file to the storage */
622 static void
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),
632 uno::UNO_SET_THROW);
633 const uno::Reference< beans::XPropertySet > xStreamProps(xStream,
634 uno::UNO_QUERY);
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 */
649 static void
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)
656 ::rtl::OUString dir;
657 ::rtl::OUString rest;
658 if (!splitPath(i_rPath, dir, rest)) throw uno::RuntimeException();
659 try {
660 if (dir.equalsAscii("")) {
661 exportStream(i_rImpl, i_xStorage, i_xGraphName, i_rPath,
662 i_rBaseURI);
663 } else {
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);
669 try {
670 ::rtl::OUString mimeType;
671 xDirProps->getPropertyValue(
672 ::comphelper::MediaDescriptor::PROP_MEDIATYPE() )
673 >>= mimeType;
674 if (mimeType.matchAsciiL(s_odfmime, sizeof(s_odfmime) - 1)) {
675 OSL_TRACE("writeStream: "
676 "refusing to recurse into embedded document");
677 return;
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 &) {
691 throw;
692 } catch (io::IOException &) {
693 throw;
697 static void
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)
703 retry:
704 // clear old data
705 i_rImpl.m_xManifest.clear();
706 // init BaseURI
707 i_rImpl.m_xBaseURI = i_xBaseURI;
709 // create repository
710 i_rImpl.m_xRepository.clear();
711 i_rImpl.m_xRepository.set(rdf::Repository::create(i_rImpl.m_xContext),
712 uno::UNO_SET_THROW);
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
718 uno::Any rterr;
719 ucb::InteractiveAugmentedIOException iaioe;
720 bool err(false);
722 const uno::Reference <rdf::XURI> xManifest(
723 getURIForStream(i_rImpl, manifest));
724 try {
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)) {
729 iaioe = e;
730 err = true;
732 } catch (uno::Exception & e) {
733 rterr <<= 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);
762 if (err) {
763 if (handleError(iaioe, i_xHandler)) goto retry;
767 /** init Impl struct */
768 static void init(struct DocumentMetadataAccess_Impl & i_rImpl)
770 try {
772 i_rImpl.m_xManifest.set(i_rImpl.m_xRepository->createGraph(
773 getURIForStream(i_rImpl,
774 ::rtl::OUString::createFromAscii(s_manifest))),
775 uno::UNO_SET_THROW);
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,
784 uno::makeAny(e));
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),
820 uno::UNO_SET_THROW);
822 // init repository
823 init(*m_pImpl);
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() );
871 if (!pReg) {
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)
883 if (!i_xURI.is()) {
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)) {
891 return 0;
893 const ::rtl::OUString relName( name.copy(baseURI.getLength()) );
894 ::rtl::OUString path;
895 ::rtl::OUString idref;
896 if (!splitXmlId(relName, path, idref)) {
897 return 0;
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)
909 if (!i_xType.is()) {
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),
920 ::boost::bind(
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"),
935 *this, 0);
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) );
954 try {
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);
965 return xGraphName;
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"),
981 *this, 0);
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"),
993 *this, 5);
997 const uno::Reference<rdf::XURI> xGraphName(
998 getURIForStream(*m_pImpl, i_rFileName) );
1000 try {
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
1011 // add to manifest
1012 addMetadataFileImpl(*m_pImpl, i_rFileName, i_rTypes);
1013 return xGraphName;
1016 void SAL_CALL
1017 DocumentMetadataAccess::removeMetadataFile(
1018 const uno::Reference< rdf::XURI > & i_xGraphName)
1019 throw (uno::RuntimeException, lang::IllegalArgumentException,
1020 container::NoSuchElementException)
1022 try {
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());
1036 void SAL_CALL
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"),
1052 *this, 0);
1056 void SAL_CALL
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);
1068 try {
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),
1074 xPart.get()),
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,
1081 *this);
1084 // remove file from manifest
1085 removeFile(*m_pImpl, xPart);
1087 } catch (uno::RuntimeException &) {
1088 throw;
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;
1134 try {
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
1147 = parts.begin();
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)
1153 .getStr());
1154 continue;
1156 const ::rtl::OUString relName( name.copy(len) );
1157 if (relName == manifest) {
1158 OSL_TRACE("loadMetadataFromStorage: "
1159 "found ourselves a recursive manifest!");
1160 continue;
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),
1180 xStylesFile.get());
1182 } else if (isReservedFile(relName)) {
1183 OSL_TRACE("loadMetadataFromStorage: "
1184 "reserved file name in manifest");
1185 } else {
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 &) {
1194 throw;
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);
1221 // export manifest
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() );
1227 try {
1228 writeStream(*m_pImpl, i_xStorage, xManifest, manifest, baseURI);
1229 } catch (uno::RuntimeException &) {
1230 throw;
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
1241 try {
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)
1251 .getStr());
1252 continue;
1254 const ::rtl::OUString relName( name.copy(len) );
1255 if (relName == manifest) {
1256 continue;
1258 if (!isFileNameValid(relName) || isReservedFile(relName)) {
1259 OSL_TRACE("storeMetadataToStorage: invalid file name: %s",
1260 ::rtl::OUStringToOString(relName, RTL_TEXTENCODING_UTF8)
1261 .getStr());
1262 continue;
1264 try {
1265 writeStream(*m_pImpl, i_xStorage, xName, relName, baseURI);
1266 } catch (uno::RuntimeException &) {
1267 throw;
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));
1287 void SAL_CALL
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;
1308 try {
1309 const uno::Reference<lang::XMultiServiceFactory> xMsf (
1310 m_pImpl->m_xContext->getServiceManager(), uno::UNO_QUERY_THROW);
1311 if (xIn.is()) {
1312 xStorage = ::comphelper::OStorageHelper::GetStorageFromInputStream(
1313 xIn, xMsf);
1314 } else { // fallback to url
1315 xStorage = ::comphelper::OStorageHelper::GetStorageFromURL2(
1316 URL, embed::ElementModes::READ, xMsf);
1318 } catch (uno::RuntimeException &) {
1319 throw;
1320 } catch (io::IOException &) {
1321 throw;
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;
1334 try {
1335 xBaseURI = createBaseURI(m_pImpl->m_xContext, xStorage, BaseURL);
1336 } catch (uno::Exception &) {
1337 // fall back to URL
1338 try {
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);
1349 void SAL_CALL
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());
1367 bool sfx(false);
1368 if (xStorage.is()) {
1369 sfx = true;
1370 } else {
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);
1388 try {
1389 // this is NOT supported in FileSystemStorage
1390 xProps->setPropertyValue(
1391 ::comphelper::MediaDescriptor::PROP_MEDIATYPE(),
1392 iter->second);
1393 } catch (uno::Exception &) { }
1395 storeMetadataToStorage(xStorage);
1397 if (sfx) {
1398 const sal_Bool bOk = aMedium.Commit();
1399 aMedium.Close();
1400 if ( !bOk ) {
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,
1408 uno::makeAny(ex));
1413 } // namespace sfx2