Version 4.0.2.1, tag libreoffice-4.0.2.1
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_storage.cxx
blobdd86cff85a9210d2d11359704751515131636fe4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
22 #include "com/sun/star/beans/XPropertySet.hpp"
23 #include "com/sun/star/embed/ElementModes.hpp"
24 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
25 #include "comphelper/processfactory.hxx"
27 #include "tdoc_uri.hxx"
28 #include "tdoc_docmgr.hxx"
29 #include "tdoc_stgelems.hxx"
31 #include "tdoc_storage.hxx"
33 using namespace com::sun::star;
34 using namespace tdoc_ucp;
37 //=========================================================================
38 //=========================================================================
40 // StorageElementFactory Implementation.
42 //=========================================================================
43 //=========================================================================
45 StorageElementFactory::StorageElementFactory(
46 const uno::Reference< lang::XMultiServiceFactory > & xSMgr,
47 const rtl::Reference< OfficeDocumentsManager > & xDocsMgr )
48 : m_xDocsMgr( xDocsMgr ),
49 m_xSMgr( xSMgr )
53 //=========================================================================
54 StorageElementFactory::~StorageElementFactory()
56 OSL_ENSURE( m_aMap.empty(),
57 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
60 //=========================================================================
61 uno::Reference< embed::XStorage >
62 StorageElementFactory::createTemporaryStorage()
63 throw ( uno::Exception,
64 uno::RuntimeException )
66 uno::Reference< embed::XStorage > xStorage;
67 uno::Reference< lang::XSingleServiceFactory > xStorageFac;
68 if ( m_xSMgr.is() )
70 xStorageFac = uno::Reference< lang::XSingleServiceFactory >(
71 m_xSMgr->createInstance(
72 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
73 "com.sun.star.embed.StorageFactory" ) ) ),
74 uno::UNO_QUERY );
77 OSL_ENSURE( xStorageFac.is(), "Can't create storage factory!" );
78 if ( xStorageFac.is() )
79 xStorage = uno::Reference< embed::XStorage >(
80 xStorageFac->createInstance(),
81 uno::UNO_QUERY );
83 if ( !xStorage.is() )
84 throw uno::RuntimeException();
86 return xStorage;
89 //=========================================================================
90 uno::Reference< embed::XStorage >
91 StorageElementFactory::createStorage( const rtl::OUString & rUri,
92 StorageAccessMode eMode )
93 throw ( embed::InvalidStorageException,
94 lang::IllegalArgumentException,
95 io::IOException,
96 embed::StorageWrappedTargetException,
97 uno::RuntimeException )
99 osl::MutexGuard aGuard( m_aMutex );
101 if ( ( eMode != READ ) &&
102 ( eMode != READ_WRITE_NOCREATE ) &&
103 ( eMode != READ_WRITE_CREATE ) )
104 throw lang::IllegalArgumentException(
105 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
106 "Invalid open mode!" ) ),
107 uno::Reference< uno::XInterface >(),
108 sal_Int16( 2 ) );
110 Uri aUri( rUri );
111 if ( aUri.isRoot() )
113 throw lang::IllegalArgumentException(
114 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
115 "Root never has a storage!" ) ),
116 uno::Reference< uno::XInterface >(),
117 sal_Int16( 1 ) );
120 rtl::OUString aUriKey
121 ( ( rUri.getStr()[ rUri.getLength() - 1 ] == sal_Unicode( '/' ) )
122 ? rUri.copy( 0, rUri.getLength() - 1 )
123 : rUri );
125 StorageMap::iterator aIt ( m_aMap.begin() );
126 StorageMap::iterator aEnd( m_aMap.end() );
128 while ( aIt != aEnd )
130 if ( (*aIt).first.first == aUriKey )
132 // URI matches. Now, check open mode.
133 bool bMatch = true;
134 switch ( eMode )
136 case READ:
137 // No need to check; storage is at least readable.
138 bMatch = true;
139 break;
141 case READ_WRITE_NOCREATE:
142 case READ_WRITE_CREATE:
143 // If found storage is writable, it can be used.
144 // If not, a new one must be created.
145 bMatch = (*aIt).first.second;
146 break;
149 if ( bMatch )
150 break;
152 ++aIt;
155 if ( aIt == aEnd )
157 uno::Reference< embed::XStorage > xParentStorage;
159 // documents never have a parent storage.
160 if ( !aUri.isDocument() )
162 xParentStorage = queryParentStorage( aUriKey, eMode );
164 if ( !xParentStorage.is() )
166 // requested to create new storage, but failed?
167 OSL_ENSURE( eMode != READ_WRITE_CREATE,
168 "Unable to create parent storage!" );
169 return xParentStorage;
173 uno::Reference< embed::XStorage > xStorage
174 = queryStorage( xParentStorage, aUriKey, eMode );
176 if ( !xStorage.is() )
178 // requested to create new storage, but failed?
179 OSL_ENSURE( eMode != READ_WRITE_CREATE,
180 "Unable to create storage!" );
181 return xStorage;
184 bool bWritable = ( ( eMode == READ_WRITE_NOCREATE )
185 || ( eMode == READ_WRITE_CREATE ) );
187 std::auto_ptr< Storage > xElement(
188 new Storage( comphelper::getComponentContext(m_xSMgr), this, aUriKey, xParentStorage, xStorage ) );
190 aIt = m_aMap.insert(
191 StorageMap::value_type(
192 std::pair< rtl::OUString, bool >( aUriKey, bWritable ),
193 xElement.get() ) ).first;
195 aIt->second->m_aContainerIt = aIt;
196 xElement.release();
197 return aIt->second;
199 else if ( osl_atomic_increment( &aIt->second->m_refCount ) > 1 )
201 rtl::Reference< Storage > xElement( aIt->second );
202 osl_atomic_decrement( &aIt->second->m_refCount );
203 return aIt->second;
205 else
207 osl_atomic_decrement( &aIt->second->m_refCount );
208 aIt->second->m_aContainerIt = m_aMap.end();
210 uno::Reference< embed::XStorage > xParentStorage;
212 // documents never have a parent storage.
213 if ( !aUri.isDocument() )
215 xParentStorage = queryParentStorage( aUriKey, eMode );
217 if ( !xParentStorage.is() )
219 // requested to create new storage, but failed?
220 OSL_ENSURE( eMode != READ_WRITE_CREATE,
221 "Unable to create parent storage!" );
222 return xParentStorage;
226 uno::Reference< embed::XStorage > xStorage
227 = queryStorage( xParentStorage, aUriKey, eMode );
229 if ( !xStorage.is() )
231 // requested to create new storage, but failed?
232 OSL_ENSURE( eMode != READ_WRITE_CREATE,
233 "Unable to create storage!" );
234 return xStorage;
237 aIt->second
238 = new Storage( comphelper::getComponentContext(m_xSMgr), this, aUriKey, xParentStorage, xStorage );
239 aIt->second->m_aContainerIt = aIt;
240 return aIt->second;
244 //=========================================================================
245 uno::Reference< io::XInputStream >
246 StorageElementFactory::createInputStream( const rtl::OUString & rUri,
247 const rtl::OUString & rPassword )
248 throw ( embed::InvalidStorageException,
249 lang::IllegalArgumentException,
250 io::IOException,
251 embed::StorageWrappedTargetException,
252 packages::WrongPasswordException,
253 uno::RuntimeException )
255 osl::MutexGuard aGuard( m_aMutex );
257 uno::Reference< embed::XStorage > xParentStorage
258 = queryParentStorage( rUri, READ );
260 // Each stream must have a parent storage.
261 if ( !xParentStorage.is() )
262 return uno::Reference< io::XInputStream >();
264 uno::Reference< io::XStream > xStream
265 = queryStream( xParentStorage, rUri, rPassword, READ, false );
267 if ( !xStream.is() )
268 return uno::Reference< io::XInputStream >();
270 return xStream->getInputStream();
273 //=========================================================================
274 uno::Reference< io::XOutputStream >
275 StorageElementFactory::createOutputStream( const rtl::OUString & rUri,
276 const rtl::OUString & rPassword,
277 bool bTruncate )
278 throw ( embed::InvalidStorageException,
279 lang::IllegalArgumentException,
280 io::IOException,
281 embed::StorageWrappedTargetException,
282 packages::WrongPasswordException,
283 uno::RuntimeException )
285 osl::MutexGuard aGuard( m_aMutex );
287 uno::Reference< embed::XStorage > xParentStorage
288 = queryParentStorage( rUri, READ_WRITE_CREATE );
290 // Each stream must have a parent storage.
291 if ( !xParentStorage.is() )
293 OSL_FAIL( "StorageElementFactory::createOutputStream - "
294 "Unable to create parent storage!" );
295 return uno::Reference< io::XOutputStream >();
298 uno::Reference< io::XStream > xStream
299 = queryStream(
300 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate );
302 if ( !xStream.is() )
304 OSL_FAIL( "StorageElementFactory::createOutputStream - "
305 "Unable to create stream!" );
306 return uno::Reference< io::XOutputStream >();
309 // Note: We need a wrapper to hold a reference to the parent storage to
310 // ensure that nobody else owns it at the moment we want to commit
311 // our changes. (There can be only one writable instance at a time
312 // and even no writable instance if there is already another
313 // read-only instance!)
314 return uno::Reference< io::XOutputStream >(
315 new OutputStream(
316 comphelper::getComponentContext(m_xSMgr), rUri, xParentStorage, xStream->getOutputStream() ) );
319 //=========================================================================
320 uno::Reference< io::XStream >
321 StorageElementFactory::createStream( const rtl::OUString & rUri,
322 const rtl::OUString & rPassword,
323 bool bTruncate )
324 throw ( embed::InvalidStorageException,
325 lang::IllegalArgumentException,
326 io::IOException,
327 embed::StorageWrappedTargetException,
328 packages::WrongPasswordException,
329 uno::RuntimeException )
331 osl::MutexGuard aGuard( m_aMutex );
333 uno::Reference< embed::XStorage > xParentStorage
334 = queryParentStorage( rUri, READ_WRITE_CREATE );
336 // Each stream must have a parent storage.
337 if ( !xParentStorage.is() )
339 OSL_FAIL( "StorageElementFactory::createStream - "
340 "Unable to create parent storage!" );
341 return uno::Reference< io::XStream >();
344 uno::Reference< io::XStream > xStream
345 = queryStream(
346 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate );
348 if ( !xStream.is() )
350 OSL_FAIL( "StorageElementFactory::createStream - "
351 "Unable to create stream!" );
352 return uno::Reference< io::XStream >();
355 return uno::Reference< io::XStream >(
356 new Stream( comphelper::getComponentContext(m_xSMgr), rUri, xParentStorage, xStream ) );
359 //=========================================================================
360 void StorageElementFactory::releaseElement( Storage * pElement ) SAL_THROW(())
362 OSL_ASSERT( pElement );
363 osl::MutexGuard aGuard( m_aMutex );
364 if ( pElement->m_aContainerIt != m_aMap.end() )
365 m_aMap.erase( pElement->m_aContainerIt );
368 //=========================================================================
370 // Non-UNO interface
372 //=========================================================================
374 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage(
375 const rtl::OUString & rUri, StorageAccessMode eMode )
376 throw ( embed::InvalidStorageException,
377 lang::IllegalArgumentException,
378 io::IOException,
379 embed::StorageWrappedTargetException,
380 uno::RuntimeException )
382 uno::Reference< embed::XStorage > xParentStorage;
384 Uri aUri( rUri );
385 Uri aParentUri( aUri.getParentUri() );
386 if ( !aParentUri.isRoot() )
388 xParentStorage = createStorage( aUri.getParentUri(), eMode );
389 OSL_ENSURE( xParentStorage.is()
390 // requested to create new storage, but failed?
391 || ( eMode != READ_WRITE_CREATE ),
392 "StorageElementFactory::queryParentStorage - No storage!" );
394 return xParentStorage;
397 //=========================================================================
398 uno::Reference< embed::XStorage > StorageElementFactory::queryStorage(
399 const uno::Reference< embed::XStorage > & xParentStorage,
400 const rtl::OUString & rUri,
401 StorageAccessMode eMode )
402 throw ( embed::InvalidStorageException,
403 lang::IllegalArgumentException,
404 io::IOException,
405 embed::StorageWrappedTargetException,
406 uno::RuntimeException )
408 uno::Reference< embed::XStorage > xStorage;
410 Uri aUri( rUri );
412 if ( !xParentStorage.is() )
414 // document storage
416 xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() );
418 if ( !xStorage.is() )
420 if ( eMode == READ_WRITE_CREATE )
421 throw lang::IllegalArgumentException(
422 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
423 "Invalid open mode: document storages cannot be "
424 "created!" ) ),
425 uno::Reference< uno::XInterface >(),
426 sal_Int16( 2 ) );
427 else
428 throw embed::InvalidStorageException(
429 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
430 "Invalid document id!" ) ),
431 uno::Reference< uno::XInterface >() );
434 // match xStorage's open mode against requested open mode
436 uno::Reference< beans::XPropertySet > xPropSet(
437 xStorage, uno::UNO_QUERY );
438 OSL_ENSURE( xPropSet.is(),
439 "StorageElementFactory::queryStorage - "
440 "No XPropertySet interface!" );
443 uno::Any aPropValue = xPropSet->getPropertyValue(
444 rtl::OUString(
445 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
447 sal_Int32 nOpenMode = 0;
448 if ( aPropValue >>= nOpenMode )
450 switch ( eMode )
452 case READ:
453 if ( !( nOpenMode & embed::ElementModes::READ ) )
455 // document opened, but not readable.
456 throw embed::InvalidStorageException(
457 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
458 "Storage is open, but not readable!" ) ),
459 uno::Reference< uno::XInterface >() );
461 // storage okay
462 break;
464 case READ_WRITE_NOCREATE:
465 case READ_WRITE_CREATE:
466 if ( !( nOpenMode & embed::ElementModes::WRITE ) )
468 // document opened, but not writable.
469 throw embed::InvalidStorageException(
470 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
471 "Storage is open, but not writable!" ) ),
472 uno::Reference< uno::XInterface >() );
474 // storage okay
475 break;
478 else
480 OSL_FAIL(
481 "Bug! Value of property OpenMode has wrong type!" );
483 throw uno::RuntimeException(
484 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
485 "Bug! Value of property OpenMode has wrong type!" ) ),
486 uno::Reference< uno::XInterface >() );
489 catch ( beans::UnknownPropertyException const & e )
491 OSL_FAIL( "Property OpenMode not supported!" );
493 throw embed::StorageWrappedTargetException(
494 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
495 "Bug! Value of property OpenMode has wrong type!" ) ),
496 uno::Reference< uno::XInterface >(),
497 uno::makeAny( e ) );
499 catch ( lang::WrappedTargetException const & e )
501 OSL_FAIL( "Caught WrappedTargetException!" );
503 throw embed::StorageWrappedTargetException(
504 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
505 "WrappedTargetException during getPropertyValue!" ) ),
506 uno::Reference< uno::XInterface >(),
507 uno::makeAny( e ) );
510 else
512 // sub storage
514 const rtl::OUString & rName = aUri.getDecodedName();
516 if ( eMode == READ )
520 sal_Int32 nOpenMode = embed::ElementModes::READ
521 | embed::ElementModes::NOCREATE;
522 xStorage
523 = xParentStorage->openStorageElement( rName, nOpenMode );
525 catch ( io::IOException const & )
527 // Another chance: Try to clone storage.
528 xStorage = createTemporaryStorage();
529 xParentStorage->copyStorageElementLastCommitTo( rName,
530 xStorage );
533 else
535 sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
536 if ( eMode == READ_WRITE_NOCREATE )
537 nOpenMode |= embed::ElementModes::NOCREATE;
539 xStorage = xParentStorage->openStorageElement( rName, nOpenMode );
543 OSL_ENSURE( xStorage.is() || ( eMode != READ_WRITE_CREATE ),
544 "StorageElementFactory::queryStorage - No storage!" );
545 return xStorage;
548 //=========================================================================
549 uno::Reference< io::XStream >
550 StorageElementFactory::queryStream(
551 const uno::Reference< embed::XStorage > & xParentStorage,
552 const rtl::OUString & rUri,
553 const rtl::OUString & rPassword,
554 StorageAccessMode eMode,
555 bool bTruncate )
556 throw ( embed::InvalidStorageException,
557 lang::IllegalArgumentException,
558 io::IOException,
559 embed::StorageWrappedTargetException,
560 packages::WrongPasswordException,
561 uno::RuntimeException )
563 osl::MutexGuard aGuard( m_aMutex );
565 if ( !xParentStorage.is() )
567 throw lang::IllegalArgumentException(
568 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
569 "No parent storage!" ) ),
570 uno::Reference< uno::XInterface >(),
571 sal_Int16( 2 ) );
574 Uri aUri( rUri );
575 if ( aUri.isRoot() )
577 throw lang::IllegalArgumentException(
578 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
579 "Root never is a stream!" ) ),
580 uno::Reference< uno::XInterface >(),
581 sal_Int16( 2 ) );
583 else if ( aUri.isDocument() )
585 throw lang::IllegalArgumentException(
586 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
587 "A document never is a stream!" ) ),
588 uno::Reference< uno::XInterface >(),
589 sal_Int16( 2 ) );
592 sal_Int32 nOpenMode;
593 switch ( eMode )
595 case READ:
596 nOpenMode = embed::ElementModes::READ
597 | embed::ElementModes::NOCREATE
598 | embed::ElementModes::SEEKABLE;
599 break;
601 case READ_WRITE_NOCREATE:
602 nOpenMode = embed::ElementModes::READWRITE
603 | embed::ElementModes::NOCREATE
604 | embed::ElementModes::SEEKABLE;
606 if ( bTruncate )
607 nOpenMode |= embed::ElementModes::TRUNCATE;
609 break;
611 case READ_WRITE_CREATE:
612 nOpenMode = embed::ElementModes::READWRITE
613 | embed::ElementModes::SEEKABLE;
615 if ( bTruncate )
616 nOpenMode |= embed::ElementModes::TRUNCATE;
618 break;
620 default:
621 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
623 throw embed::InvalidStorageException(
624 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
625 "Unknown open mode!" ) ),
626 uno::Reference< uno::XInterface >() );
629 // No object re-usage mechanism; streams are seekable => not stateless.
631 uno::Reference< io::XStream > xStream;
632 if ( !rPassword.isEmpty() )
634 if ( eMode == READ )
638 xStream = xParentStorage->cloneEncryptedStreamElement(
639 aUri.getDecodedName(),
640 rPassword );
642 catch ( packages::NoEncryptionException const & )
644 xStream
645 = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
648 else
652 xStream = xParentStorage->openEncryptedStreamElement(
653 aUri.getDecodedName(),
654 nOpenMode,
655 rPassword );
657 catch ( packages::NoEncryptionException const & )
659 xStream
660 = xParentStorage->openStreamElement( aUri.getDecodedName(),
661 nOpenMode );
665 else
667 if ( eMode == READ )
669 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
671 else
673 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
674 nOpenMode );
678 if ( !xStream.is() )
680 throw embed::InvalidStorageException(
681 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
682 "No stream!" ) ),
683 uno::Reference< uno::XInterface >() );
686 return xStream;
689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */