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: tdoc_storage.cxx,v $
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 /**************************************************************************
36 **************************************************************************
38 - remove root storage access workaround
40 *************************************************************************/
42 #define ROOTSTORAGE_ACCESS_WORKAROUND 1
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
),
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
;
93 xStorageFac
= uno::Reference
< lang::XSingleServiceFactory
>(
94 m_xSMgr
->createInstance(
95 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
96 "com.sun.star.embed.StorageFactory" ) ) ),
100 OSL_ENSURE( xStorageFac
.is(), "Can't create storage factory!" );
101 if ( xStorageFac
.is() )
102 xStorage
= uno::Reference
< embed::XStorage
>(
103 xStorageFac
->createInstance(),
106 if ( !xStorage
.is() )
107 throw uno::RuntimeException();
112 //=========================================================================
113 uno::Reference
< embed::XStorage
>
114 StorageElementFactory::createStorage( const rtl::OUString
& rUri
,
115 StorageAccessMode eMode
)
116 throw ( embed::InvalidStorageException
,
117 lang::IllegalArgumentException
,
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
>(),
136 throw lang::IllegalArgumentException(
137 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
138 "Root never has a storage!" ) ),
139 uno::Reference
< uno::XInterface
>(),
143 rtl::OUString aUriKey
144 ( ( rUri
.getStr()[ rUri
.getLength() - 1 ] == sal_Unicode( '/' ) )
145 ? rUri
.copy( 0, rUri
.getLength() - 1 )
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.
160 // No need to check; storage is at least readable.
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
;
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!" );
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
) );
214 StorageMap::value_type(
215 std::pair
< rtl::OUString
, bool >( aUriKey
, bWritable
),
216 xElement
.get() ) ).first
;
218 aIt
->second
->m_aContainerIt
= aIt
;
222 else if ( osl_incrementInterlockedCount( &aIt
->second
->m_refCount
) > 1 )
224 rtl::Reference
< Storage
> xElement( aIt
->second
);
225 osl_decrementInterlockedCount( &aIt
->second
->m_refCount
);
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!" );
261 = new Storage( m_xSMgr
, this, aUriKey
, xParentStorage
, xStorage
);
262 aIt
->second
->m_aContainerIt
= aIt
;
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
,
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 );
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
,
301 throw ( embed::InvalidStorageException
,
302 lang::IllegalArgumentException
,
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() )
317 "StorageElementFactory::createOutputStream - "
318 "Unable to create parent storage!" );
319 return uno::Reference
< io::XOutputStream
>();
322 uno::Reference
< io::XStream
> xStream
324 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
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
>(
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
,
349 throw ( embed::InvalidStorageException
,
350 lang::IllegalArgumentException
,
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() )
365 "StorageElementFactory::createStream - "
366 "Unable to create parent storage!" );
367 return uno::Reference
< io::XStream
>();
370 uno::Reference
< io::XStream
> xStream
372 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
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 //=========================================================================
399 //=========================================================================
401 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
402 const rtl::OUString
& rUri
, StorageAccessMode eMode
)
403 throw ( embed::InvalidStorageException
,
404 lang::IllegalArgumentException
,
406 embed::StorageWrappedTargetException
,
407 uno::RuntimeException
)
409 uno::Reference
< embed::XStorage
> xParentStorage
;
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
,
432 embed::StorageWrappedTargetException
,
433 uno::RuntimeException
)
435 uno::Reference
< embed::XStorage
> xStorage
;
439 if ( !xParentStorage
.is() )
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 "
452 uno::Reference
< uno::XInterface
>(),
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(
472 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
474 sal_Int32 nOpenMode
= 0;
475 if ( aPropValue
>>= nOpenMode
)
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
>() );
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
>() );
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
>(),
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
>(),
541 const rtl::OUString
& rName
= aUri
.getDecodedName();
547 sal_Int32 nOpenMode
= embed::ElementModes::READ
548 | embed::ElementModes::NOCREATE
;
550 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
552 catch ( io::IOException
const & )
554 // Another chance: Try to clone storage.
555 xStorage
= createTemporaryStorage();
556 xParentStorage
->copyStorageElementLastCommitTo( rName
,
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!" );
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
,
583 throw ( embed::InvalidStorageException
,
584 lang::IllegalArgumentException
,
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
>(),
604 throw lang::IllegalArgumentException(
605 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
606 "Root never is a stream!" ) ),
607 uno::Reference
< uno::XInterface
>(),
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
>(),
623 nOpenMode
= embed::ElementModes::READ
624 | embed::ElementModes::NOCREATE
625 | embed::ElementModes::SEEKABLE
;
628 case READ_WRITE_NOCREATE
:
629 nOpenMode
= embed::ElementModes::READWRITE
630 | embed::ElementModes::NOCREATE
631 | embed::ElementModes::SEEKABLE
;
634 nOpenMode
|= embed::ElementModes::TRUNCATE
;
638 case READ_WRITE_CREATE
:
639 nOpenMode
= embed::ElementModes::READWRITE
640 | embed::ElementModes::SEEKABLE
;
643 nOpenMode
|= embed::ElementModes::TRUNCATE
;
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 )
666 xStream
= xParentStorage
->cloneEncryptedStreamElement(
667 aUri
.getDecodedName(),
670 catch ( packages::NoEncryptionException
const & )
673 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
680 xStream
= xParentStorage
->openEncryptedStreamElement(
681 aUri
.getDecodedName(),
685 catch ( packages::NoEncryptionException
const & )
688 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
697 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
701 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
708 throw embed::InvalidStorageException(
709 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
711 uno::Reference
< uno::XInterface
>() );