update dev300-m58
[ooovba.git] / ucb / source / ucp / tdoc / tdoc_storage.cxx
blob0ce268bb1502e4c6888dd013ca13a488dd391613
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tdoc_storage.cxx,v $
10 * $Revision: 1.10 $
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 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
34 /**************************************************************************
35 TODO
36 **************************************************************************
38 - remove root storage access workaround
40 *************************************************************************/
42 #define ROOTSTORAGE_ACCESS_WORKAROUND 1
44 #include <memory>
46 #include "com/sun/star/beans/XPropertySet.hpp"
47 #include "com/sun/star/embed/ElementModes.hpp"
48 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
50 #include "tdoc_uri.hxx"
51 #include "tdoc_docmgr.hxx"
52 #include "tdoc_stgelems.hxx"
54 #include "tdoc_storage.hxx"
56 using namespace com::sun::star;
57 using namespace tdoc_ucp;
60 //=========================================================================
61 //=========================================================================
63 // StorageElementFactory Implementation.
65 //=========================================================================
66 //=========================================================================
68 StorageElementFactory::StorageElementFactory(
69 const uno::Reference< lang::XMultiServiceFactory > & xSMgr,
70 const rtl::Reference< OfficeDocumentsManager > & xDocsMgr )
71 : m_xDocsMgr( xDocsMgr ),
72 m_xSMgr( xSMgr )
76 //=========================================================================
77 StorageElementFactory::~StorageElementFactory()
79 OSL_ENSURE( m_aMap.size() == 0,
80 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
83 //=========================================================================
84 uno::Reference< embed::XStorage >
85 StorageElementFactory::createTemporaryStorage()
86 throw ( uno::Exception,
87 uno::RuntimeException )
89 uno::Reference< embed::XStorage > xStorage;
90 uno::Reference< lang::XSingleServiceFactory > xStorageFac;
91 if ( m_xSMgr.is() )
93 xStorageFac = uno::Reference< lang::XSingleServiceFactory >(
94 m_xSMgr->createInstance(
95 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
96 "com.sun.star.embed.StorageFactory" ) ) ),
97 uno::UNO_QUERY );
100 OSL_ENSURE( xStorageFac.is(), "Can't create storage factory!" );
101 if ( xStorageFac.is() )
102 xStorage = uno::Reference< embed::XStorage >(
103 xStorageFac->createInstance(),
104 uno::UNO_QUERY );
106 if ( !xStorage.is() )
107 throw uno::RuntimeException();
109 return xStorage;
112 //=========================================================================
113 uno::Reference< embed::XStorage >
114 StorageElementFactory::createStorage( const rtl::OUString & rUri,
115 StorageAccessMode eMode )
116 throw ( embed::InvalidStorageException,
117 lang::IllegalArgumentException,
118 io::IOException,
119 embed::StorageWrappedTargetException,
120 uno::RuntimeException )
122 osl::MutexGuard aGuard( m_aMutex );
124 if ( ( eMode != READ ) &&
125 ( eMode != READ_WRITE_NOCREATE ) &&
126 ( eMode != READ_WRITE_CREATE ) )
127 throw lang::IllegalArgumentException(
128 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
129 "Invalid open mode!" ) ),
130 uno::Reference< uno::XInterface >(),
131 sal_Int16( 2 ) );
133 Uri aUri( rUri );
134 if ( aUri.isRoot() )
136 throw lang::IllegalArgumentException(
137 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
138 "Root never has a storage!" ) ),
139 uno::Reference< uno::XInterface >(),
140 sal_Int16( 1 ) );
143 rtl::OUString aUriKey
144 ( ( rUri.getStr()[ rUri.getLength() - 1 ] == sal_Unicode( '/' ) )
145 ? rUri.copy( 0, rUri.getLength() - 1 )
146 : rUri );
148 StorageMap::iterator aIt ( m_aMap.begin() );
149 StorageMap::iterator aEnd( m_aMap.end() );
151 while ( aIt != aEnd )
153 if ( (*aIt).first.first == aUriKey )
155 // URI matches. Now, check open mode.
156 bool bMatch = true;
157 switch ( eMode )
159 case READ:
160 // No need to check; storage is at least readable.
161 bMatch = true;
162 break;
164 case READ_WRITE_NOCREATE:
165 case READ_WRITE_CREATE:
166 // If found storage is writable, it can be used.
167 // If not, a new one must be created.
168 bMatch = (*aIt).first.second;
169 break;
172 if ( bMatch )
173 break;
175 ++aIt;
178 if ( aIt == aEnd )
180 uno::Reference< embed::XStorage > xParentStorage;
182 // documents never have a parent storage.
183 if ( !aUri.isDocument() )
185 xParentStorage = queryParentStorage( aUriKey, eMode );
187 if ( !xParentStorage.is() )
189 // requested to create new storage, but failed?
190 OSL_ENSURE( eMode != READ_WRITE_CREATE,
191 "Unable to create parent storage!" );
192 return xParentStorage;
196 uno::Reference< embed::XStorage > xStorage
197 = queryStorage( xParentStorage, aUriKey, eMode );
199 if ( !xStorage.is() )
201 // requested to create new storage, but failed?
202 OSL_ENSURE( eMode != READ_WRITE_CREATE,
203 "Unable to create storage!" );
204 return xStorage;
207 bool bWritable = ( ( eMode == READ_WRITE_NOCREATE )
208 || ( eMode == READ_WRITE_CREATE ) );
210 std::auto_ptr< Storage > xElement(
211 new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage ) );
213 aIt = m_aMap.insert(
214 StorageMap::value_type(
215 std::pair< rtl::OUString, bool >( aUriKey, bWritable ),
216 xElement.get() ) ).first;
218 aIt->second->m_aContainerIt = aIt;
219 xElement.release();
220 return aIt->second;
222 else if ( osl_incrementInterlockedCount( &aIt->second->m_refCount ) > 1 )
224 rtl::Reference< Storage > xElement( aIt->second );
225 osl_decrementInterlockedCount( &aIt->second->m_refCount );
226 return aIt->second;
228 else
230 osl_decrementInterlockedCount( &aIt->second->m_refCount );
231 aIt->second->m_aContainerIt = m_aMap.end();
233 uno::Reference< embed::XStorage > xParentStorage;
235 // documents never have a parent storage.
236 if ( !aUri.isDocument() )
238 xParentStorage = queryParentStorage( aUriKey, eMode );
240 if ( !xParentStorage.is() )
242 // requested to create new storage, but failed?
243 OSL_ENSURE( eMode != READ_WRITE_CREATE,
244 "Unable to create parent storage!" );
245 return xParentStorage;
249 uno::Reference< embed::XStorage > xStorage
250 = queryStorage( xParentStorage, aUriKey, eMode );
252 if ( !xStorage.is() )
254 // requested to create new storage, but failed?
255 OSL_ENSURE( eMode != READ_WRITE_CREATE,
256 "Unable to create storage!" );
257 return xStorage;
260 aIt->second
261 = new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage );
262 aIt->second->m_aContainerIt = aIt;
263 return aIt->second;
267 //=========================================================================
268 uno::Reference< io::XInputStream >
269 StorageElementFactory::createInputStream( const rtl::OUString & rUri,
270 const rtl::OUString & rPassword )
271 throw ( embed::InvalidStorageException,
272 lang::IllegalArgumentException,
273 io::IOException,
274 embed::StorageWrappedTargetException,
275 packages::WrongPasswordException,
276 uno::RuntimeException )
278 osl::MutexGuard aGuard( m_aMutex );
280 uno::Reference< embed::XStorage > xParentStorage
281 = queryParentStorage( rUri, READ );
283 // Each stream must have a parent storage.
284 if ( !xParentStorage.is() )
285 return uno::Reference< io::XInputStream >();
287 uno::Reference< io::XStream > xStream
288 = queryStream( xParentStorage, rUri, rPassword, READ, false );
290 if ( !xStream.is() )
291 return uno::Reference< io::XInputStream >();
293 return xStream->getInputStream();
296 //=========================================================================
297 uno::Reference< io::XOutputStream >
298 StorageElementFactory::createOutputStream( const rtl::OUString & rUri,
299 const rtl::OUString & rPassword,
300 bool bTruncate )
301 throw ( embed::InvalidStorageException,
302 lang::IllegalArgumentException,
303 io::IOException,
304 embed::StorageWrappedTargetException,
305 packages::WrongPasswordException,
306 uno::RuntimeException )
308 osl::MutexGuard aGuard( m_aMutex );
310 uno::Reference< embed::XStorage > xParentStorage
311 = queryParentStorage( rUri, READ_WRITE_CREATE );
313 // Each stream must have a parent storage.
314 if ( !xParentStorage.is() )
316 OSL_ENSURE( false,
317 "StorageElementFactory::createOutputStream - "
318 "Unable to create parent storage!" );
319 return uno::Reference< io::XOutputStream >();
322 uno::Reference< io::XStream > xStream
323 = queryStream(
324 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate );
326 if ( !xStream.is() )
328 OSL_ENSURE( false,
329 "StorageElementFactory::createOutputStream - "
330 "Unable to create stream!" );
331 return uno::Reference< io::XOutputStream >();
334 // Note: We need a wrapper to hold a reference to the parent storage to
335 // ensure that nobody else owns it at the moment we want to commit
336 // our changes. (There can be only one writable instance at a time
337 // and even no writable instance if there is already another
338 // read-only instance!)
339 return uno::Reference< io::XOutputStream >(
340 new OutputStream(
341 m_xSMgr, rUri, xParentStorage, xStream->getOutputStream() ) );
344 //=========================================================================
345 uno::Reference< io::XStream >
346 StorageElementFactory::createStream( const rtl::OUString & rUri,
347 const rtl::OUString & rPassword,
348 bool bTruncate )
349 throw ( embed::InvalidStorageException,
350 lang::IllegalArgumentException,
351 io::IOException,
352 embed::StorageWrappedTargetException,
353 packages::WrongPasswordException,
354 uno::RuntimeException )
356 osl::MutexGuard aGuard( m_aMutex );
358 uno::Reference< embed::XStorage > xParentStorage
359 = queryParentStorage( rUri, READ_WRITE_CREATE );
361 // Each stream must have a parent storage.
362 if ( !xParentStorage.is() )
364 OSL_ENSURE( false,
365 "StorageElementFactory::createStream - "
366 "Unable to create parent storage!" );
367 return uno::Reference< io::XStream >();
370 uno::Reference< io::XStream > xStream
371 = queryStream(
372 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate );
374 if ( !xStream.is() )
376 OSL_ENSURE( false,
377 "StorageElementFactory::createStream - "
378 "Unable to create stream!" );
379 return uno::Reference< io::XStream >();
382 return uno::Reference< io::XStream >(
383 new Stream( m_xSMgr, rUri, xParentStorage, xStream ) );
386 //=========================================================================
387 void StorageElementFactory::releaseElement( Storage * pElement ) SAL_THROW( () )
389 OSL_ASSERT( pElement );
390 osl::MutexGuard aGuard( m_aMutex );
391 if ( pElement->m_aContainerIt != m_aMap.end() )
392 m_aMap.erase( pElement->m_aContainerIt );
395 //=========================================================================
397 // Non-UNO interface
399 //=========================================================================
401 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage(
402 const rtl::OUString & rUri, StorageAccessMode eMode )
403 throw ( embed::InvalidStorageException,
404 lang::IllegalArgumentException,
405 io::IOException,
406 embed::StorageWrappedTargetException,
407 uno::RuntimeException )
409 uno::Reference< embed::XStorage > xParentStorage;
411 Uri aUri( rUri );
412 Uri aParentUri( aUri.getParentUri() );
413 if ( !aParentUri.isRoot() )
415 xParentStorage = createStorage( aUri.getParentUri(), eMode );
416 OSL_ENSURE( xParentStorage.is()
417 // requested to create new storage, but failed?
418 || ( eMode != READ_WRITE_CREATE ),
419 "StorageElementFactory::queryParentStorage - No storage!" );
421 return xParentStorage;
424 //=========================================================================
425 uno::Reference< embed::XStorage > StorageElementFactory::queryStorage(
426 const uno::Reference< embed::XStorage > & xParentStorage,
427 const rtl::OUString & rUri,
428 StorageAccessMode eMode )
429 throw ( embed::InvalidStorageException,
430 lang::IllegalArgumentException,
431 io::IOException,
432 embed::StorageWrappedTargetException,
433 uno::RuntimeException )
435 uno::Reference< embed::XStorage > xStorage;
437 Uri aUri( rUri );
439 if ( !xParentStorage.is() )
441 // document storage
443 xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() );
445 if ( !xStorage.is() )
447 if ( eMode == READ_WRITE_CREATE )
448 throw lang::IllegalArgumentException(
449 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
450 "Invalid open mode: document storages cannot be "
451 "created!" ) ),
452 uno::Reference< uno::XInterface >(),
453 sal_Int16( 2 ) );
454 else
455 throw embed::InvalidStorageException(
456 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
457 "Invalid document id!" ) ),
458 uno::Reference< uno::XInterface >() );
461 // match xStorage's open mode against requested open mode
463 uno::Reference< beans::XPropertySet > xPropSet(
464 xStorage, uno::UNO_QUERY );
465 OSL_ENSURE( xPropSet.is(),
466 "StorageElementFactory::queryStorage - "
467 "No XPropertySet interface!" );
470 uno::Any aPropValue = xPropSet->getPropertyValue(
471 rtl::OUString(
472 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
474 sal_Int32 nOpenMode = 0;
475 if ( aPropValue >>= nOpenMode )
477 switch ( eMode )
479 case READ:
480 if ( !( nOpenMode & embed::ElementModes::READ ) )
482 // document opened, but not readable.
483 throw embed::InvalidStorageException(
484 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
485 "Storage is open, but not readable!" ) ),
486 uno::Reference< uno::XInterface >() );
488 // storage okay
489 break;
491 case READ_WRITE_NOCREATE:
492 case READ_WRITE_CREATE:
493 if ( !( nOpenMode & embed::ElementModes::WRITE ) )
495 // document opened, but not writable.
496 throw embed::InvalidStorageException(
497 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
498 "Storage is open, but not writable!" ) ),
499 uno::Reference< uno::XInterface >() );
501 // storage okay
502 break;
505 else
507 OSL_ENSURE(
508 false, "Bug! Value of property OpenMode has wrong type!" );
510 throw uno::RuntimeException(
511 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
512 "Bug! Value of property OpenMode has wrong type!" ) ),
513 uno::Reference< uno::XInterface >() );
516 catch ( beans::UnknownPropertyException const & e )
518 OSL_ENSURE( false, "Property OpenMode not supported!" );
520 throw embed::StorageWrappedTargetException(
521 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
522 "Bug! Value of property OpenMode has wrong type!" ) ),
523 uno::Reference< uno::XInterface >(),
524 uno::makeAny( e ) );
526 catch ( lang::WrappedTargetException const & e )
528 OSL_ENSURE( false, "Caught WrappedTargetException!" );
530 throw embed::StorageWrappedTargetException(
531 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
532 "WrappedTargetException during getPropertyValue!" ) ),
533 uno::Reference< uno::XInterface >(),
534 uno::makeAny( e ) );
537 else
539 // sub storage
541 const rtl::OUString & rName = aUri.getDecodedName();
543 if ( eMode == READ )
547 sal_Int32 nOpenMode = embed::ElementModes::READ
548 | embed::ElementModes::NOCREATE;
549 xStorage
550 = xParentStorage->openStorageElement( rName, nOpenMode );
552 catch ( io::IOException const & )
554 // Another chance: Try to clone storage.
555 xStorage = createTemporaryStorage();
556 xParentStorage->copyStorageElementLastCommitTo( rName,
557 xStorage );
560 else
562 sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
563 if ( eMode == READ_WRITE_NOCREATE )
564 nOpenMode |= embed::ElementModes::NOCREATE;
566 xStorage = xParentStorage->openStorageElement( rName, nOpenMode );
570 OSL_ENSURE( xStorage.is() || ( eMode != READ_WRITE_CREATE ),
571 "StorageElementFactory::queryStorage - No storage!" );
572 return xStorage;
575 //=========================================================================
576 uno::Reference< io::XStream >
577 StorageElementFactory::queryStream(
578 const uno::Reference< embed::XStorage > & xParentStorage,
579 const rtl::OUString & rUri,
580 const rtl::OUString & rPassword,
581 StorageAccessMode eMode,
582 bool bTruncate )
583 throw ( embed::InvalidStorageException,
584 lang::IllegalArgumentException,
585 io::IOException,
586 embed::StorageWrappedTargetException,
587 packages::WrongPasswordException,
588 uno::RuntimeException )
590 osl::MutexGuard aGuard( m_aMutex );
592 if ( !xParentStorage.is() )
594 throw lang::IllegalArgumentException(
595 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
596 "No parent storage!" ) ),
597 uno::Reference< uno::XInterface >(),
598 sal_Int16( 2 ) );
601 Uri aUri( rUri );
602 if ( aUri.isRoot() )
604 throw lang::IllegalArgumentException(
605 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
606 "Root never is a stream!" ) ),
607 uno::Reference< uno::XInterface >(),
608 sal_Int16( 2 ) );
610 else if ( aUri.isDocument() )
612 throw lang::IllegalArgumentException(
613 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
614 "A document never is a stream!" ) ),
615 uno::Reference< uno::XInterface >(),
616 sal_Int16( 2 ) );
619 sal_Int32 nOpenMode;
620 switch ( eMode )
622 case READ:
623 nOpenMode = embed::ElementModes::READ
624 | embed::ElementModes::NOCREATE
625 | embed::ElementModes::SEEKABLE;
626 break;
628 case READ_WRITE_NOCREATE:
629 nOpenMode = embed::ElementModes::READWRITE
630 | embed::ElementModes::NOCREATE
631 | embed::ElementModes::SEEKABLE;
633 if ( bTruncate )
634 nOpenMode |= embed::ElementModes::TRUNCATE;
636 break;
638 case READ_WRITE_CREATE:
639 nOpenMode = embed::ElementModes::READWRITE
640 | embed::ElementModes::SEEKABLE;
642 if ( bTruncate )
643 nOpenMode |= embed::ElementModes::TRUNCATE;
645 break;
647 default:
648 OSL_ENSURE( false,
649 "StorageElementFactory::queryStream : Unknown open mode!" );
651 throw embed::InvalidStorageException(
652 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
653 "Unknown open mode!" ) ),
654 uno::Reference< uno::XInterface >() );
657 // No object re-usage mechanism; streams are seekable => not stateless.
659 uno::Reference< io::XStream > xStream;
660 if ( rPassword.getLength() > 0 )
662 if ( eMode == READ )
666 xStream = xParentStorage->cloneEncryptedStreamElement(
667 aUri.getDecodedName(),
668 rPassword );
670 catch ( packages::NoEncryptionException const & )
672 xStream
673 = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
676 else
680 xStream = xParentStorage->openEncryptedStreamElement(
681 aUri.getDecodedName(),
682 nOpenMode,
683 rPassword );
685 catch ( packages::NoEncryptionException const & )
687 xStream
688 = xParentStorage->openStreamElement( aUri.getDecodedName(),
689 nOpenMode );
693 else
695 if ( eMode == READ )
697 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
699 else
701 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
702 nOpenMode );
706 if ( !xStream.is() )
708 throw embed::InvalidStorageException(
709 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
710 "No stream!" ) ),
711 uno::Reference< uno::XInterface >() );
714 return xStream;