Bump for 3.6-28
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_storage.cxx
blob501f4e32fae0062dadc5812c7d2a7754f9f449d3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 /**************************************************************************
31 TODO
32 **************************************************************************
34 - remove root storage access workaround
36 *************************************************************************/
38 #define ROOTSTORAGE_ACCESS_WORKAROUND 1
40 #include <memory>
42 #include "com/sun/star/beans/XPropertySet.hpp"
43 #include "com/sun/star/embed/ElementModes.hpp"
44 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
46 #include "tdoc_uri.hxx"
47 #include "tdoc_docmgr.hxx"
48 #include "tdoc_stgelems.hxx"
50 #include "tdoc_storage.hxx"
52 using namespace com::sun::star;
53 using namespace tdoc_ucp;
56 //=========================================================================
57 //=========================================================================
59 // StorageElementFactory Implementation.
61 //=========================================================================
62 //=========================================================================
64 StorageElementFactory::StorageElementFactory(
65 const uno::Reference< lang::XMultiServiceFactory > & xSMgr,
66 const rtl::Reference< OfficeDocumentsManager > & xDocsMgr )
67 : m_xDocsMgr( xDocsMgr ),
68 m_xSMgr( xSMgr )
72 //=========================================================================
73 StorageElementFactory::~StorageElementFactory()
75 OSL_ENSURE( m_aMap.empty(),
76 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
79 //=========================================================================
80 uno::Reference< embed::XStorage >
81 StorageElementFactory::createTemporaryStorage()
82 throw ( uno::Exception,
83 uno::RuntimeException )
85 uno::Reference< embed::XStorage > xStorage;
86 uno::Reference< lang::XSingleServiceFactory > xStorageFac;
87 if ( m_xSMgr.is() )
89 xStorageFac = uno::Reference< lang::XSingleServiceFactory >(
90 m_xSMgr->createInstance(
91 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
92 "com.sun.star.embed.StorageFactory" ) ) ),
93 uno::UNO_QUERY );
96 OSL_ENSURE( xStorageFac.is(), "Can't create storage factory!" );
97 if ( xStorageFac.is() )
98 xStorage = uno::Reference< embed::XStorage >(
99 xStorageFac->createInstance(),
100 uno::UNO_QUERY );
102 if ( !xStorage.is() )
103 throw uno::RuntimeException();
105 return xStorage;
108 //=========================================================================
109 uno::Reference< embed::XStorage >
110 StorageElementFactory::createStorage( const rtl::OUString & rUri,
111 StorageAccessMode eMode )
112 throw ( embed::InvalidStorageException,
113 lang::IllegalArgumentException,
114 io::IOException,
115 embed::StorageWrappedTargetException,
116 uno::RuntimeException )
118 osl::MutexGuard aGuard( m_aMutex );
120 if ( ( eMode != READ ) &&
121 ( eMode != READ_WRITE_NOCREATE ) &&
122 ( eMode != READ_WRITE_CREATE ) )
123 throw lang::IllegalArgumentException(
124 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
125 "Invalid open mode!" ) ),
126 uno::Reference< uno::XInterface >(),
127 sal_Int16( 2 ) );
129 Uri aUri( rUri );
130 if ( aUri.isRoot() )
132 throw lang::IllegalArgumentException(
133 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
134 "Root never has a storage!" ) ),
135 uno::Reference< uno::XInterface >(),
136 sal_Int16( 1 ) );
139 rtl::OUString aUriKey
140 ( ( rUri.getStr()[ rUri.getLength() - 1 ] == sal_Unicode( '/' ) )
141 ? rUri.copy( 0, rUri.getLength() - 1 )
142 : rUri );
144 StorageMap::iterator aIt ( m_aMap.begin() );
145 StorageMap::iterator aEnd( m_aMap.end() );
147 while ( aIt != aEnd )
149 if ( (*aIt).first.first == aUriKey )
151 // URI matches. Now, check open mode.
152 bool bMatch = true;
153 switch ( eMode )
155 case READ:
156 // No need to check; storage is at least readable.
157 bMatch = true;
158 break;
160 case READ_WRITE_NOCREATE:
161 case READ_WRITE_CREATE:
162 // If found storage is writable, it can be used.
163 // If not, a new one must be created.
164 bMatch = (*aIt).first.second;
165 break;
168 if ( bMatch )
169 break;
171 ++aIt;
174 if ( aIt == aEnd )
176 uno::Reference< embed::XStorage > xParentStorage;
178 // documents never have a parent storage.
179 if ( !aUri.isDocument() )
181 xParentStorage = queryParentStorage( aUriKey, eMode );
183 if ( !xParentStorage.is() )
185 // requested to create new storage, but failed?
186 OSL_ENSURE( eMode != READ_WRITE_CREATE,
187 "Unable to create parent storage!" );
188 return xParentStorage;
192 uno::Reference< embed::XStorage > xStorage
193 = queryStorage( xParentStorage, aUriKey, eMode );
195 if ( !xStorage.is() )
197 // requested to create new storage, but failed?
198 OSL_ENSURE( eMode != READ_WRITE_CREATE,
199 "Unable to create storage!" );
200 return xStorage;
203 bool bWritable = ( ( eMode == READ_WRITE_NOCREATE )
204 || ( eMode == READ_WRITE_CREATE ) );
206 std::auto_ptr< Storage > xElement(
207 new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage ) );
209 aIt = m_aMap.insert(
210 StorageMap::value_type(
211 std::pair< rtl::OUString, bool >( aUriKey, bWritable ),
212 xElement.get() ) ).first;
214 aIt->second->m_aContainerIt = aIt;
215 xElement.release();
216 return aIt->second;
218 else if ( osl_incrementInterlockedCount( &aIt->second->m_refCount ) > 1 )
220 rtl::Reference< Storage > xElement( aIt->second );
221 osl_decrementInterlockedCount( &aIt->second->m_refCount );
222 return aIt->second;
224 else
226 osl_decrementInterlockedCount( &aIt->second->m_refCount );
227 aIt->second->m_aContainerIt = m_aMap.end();
229 uno::Reference< embed::XStorage > xParentStorage;
231 // documents never have a parent storage.
232 if ( !aUri.isDocument() )
234 xParentStorage = queryParentStorage( aUriKey, eMode );
236 if ( !xParentStorage.is() )
238 // requested to create new storage, but failed?
239 OSL_ENSURE( eMode != READ_WRITE_CREATE,
240 "Unable to create parent storage!" );
241 return xParentStorage;
245 uno::Reference< embed::XStorage > xStorage
246 = queryStorage( xParentStorage, aUriKey, eMode );
248 if ( !xStorage.is() )
250 // requested to create new storage, but failed?
251 OSL_ENSURE( eMode != READ_WRITE_CREATE,
252 "Unable to create storage!" );
253 return xStorage;
256 aIt->second
257 = new Storage( m_xSMgr, this, aUriKey, xParentStorage, xStorage );
258 aIt->second->m_aContainerIt = aIt;
259 return aIt->second;
263 //=========================================================================
264 uno::Reference< io::XInputStream >
265 StorageElementFactory::createInputStream( const rtl::OUString & rUri,
266 const rtl::OUString & rPassword )
267 throw ( embed::InvalidStorageException,
268 lang::IllegalArgumentException,
269 io::IOException,
270 embed::StorageWrappedTargetException,
271 packages::WrongPasswordException,
272 uno::RuntimeException )
274 osl::MutexGuard aGuard( m_aMutex );
276 uno::Reference< embed::XStorage > xParentStorage
277 = queryParentStorage( rUri, READ );
279 // Each stream must have a parent storage.
280 if ( !xParentStorage.is() )
281 return uno::Reference< io::XInputStream >();
283 uno::Reference< io::XStream > xStream
284 = queryStream( xParentStorage, rUri, rPassword, READ, false );
286 if ( !xStream.is() )
287 return uno::Reference< io::XInputStream >();
289 return xStream->getInputStream();
292 //=========================================================================
293 uno::Reference< io::XOutputStream >
294 StorageElementFactory::createOutputStream( const rtl::OUString & rUri,
295 const rtl::OUString & rPassword,
296 bool bTruncate )
297 throw ( embed::InvalidStorageException,
298 lang::IllegalArgumentException,
299 io::IOException,
300 embed::StorageWrappedTargetException,
301 packages::WrongPasswordException,
302 uno::RuntimeException )
304 osl::MutexGuard aGuard( m_aMutex );
306 uno::Reference< embed::XStorage > xParentStorage
307 = queryParentStorage( rUri, READ_WRITE_CREATE );
309 // Each stream must have a parent storage.
310 if ( !xParentStorage.is() )
312 OSL_FAIL( "StorageElementFactory::createOutputStream - "
313 "Unable to create parent storage!" );
314 return uno::Reference< io::XOutputStream >();
317 uno::Reference< io::XStream > xStream
318 = queryStream(
319 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate );
321 if ( !xStream.is() )
323 OSL_FAIL( "StorageElementFactory::createOutputStream - "
324 "Unable to create stream!" );
325 return uno::Reference< io::XOutputStream >();
328 // Note: We need a wrapper to hold a reference to the parent storage to
329 // ensure that nobody else owns it at the moment we want to commit
330 // our changes. (There can be only one writable instance at a time
331 // and even no writable instance if there is already another
332 // read-only instance!)
333 return uno::Reference< io::XOutputStream >(
334 new OutputStream(
335 m_xSMgr, rUri, xParentStorage, xStream->getOutputStream() ) );
338 //=========================================================================
339 uno::Reference< io::XStream >
340 StorageElementFactory::createStream( const rtl::OUString & rUri,
341 const rtl::OUString & rPassword,
342 bool bTruncate )
343 throw ( embed::InvalidStorageException,
344 lang::IllegalArgumentException,
345 io::IOException,
346 embed::StorageWrappedTargetException,
347 packages::WrongPasswordException,
348 uno::RuntimeException )
350 osl::MutexGuard aGuard( m_aMutex );
352 uno::Reference< embed::XStorage > xParentStorage
353 = queryParentStorage( rUri, READ_WRITE_CREATE );
355 // Each stream must have a parent storage.
356 if ( !xParentStorage.is() )
358 OSL_FAIL( "StorageElementFactory::createStream - "
359 "Unable to create parent storage!" );
360 return uno::Reference< io::XStream >();
363 uno::Reference< io::XStream > xStream
364 = queryStream(
365 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate );
367 if ( !xStream.is() )
369 OSL_FAIL( "StorageElementFactory::createStream - "
370 "Unable to create stream!" );
371 return uno::Reference< io::XStream >();
374 return uno::Reference< io::XStream >(
375 new Stream( m_xSMgr, rUri, xParentStorage, xStream ) );
378 //=========================================================================
379 void StorageElementFactory::releaseElement( Storage * pElement ) SAL_THROW(())
381 OSL_ASSERT( pElement );
382 osl::MutexGuard aGuard( m_aMutex );
383 if ( pElement->m_aContainerIt != m_aMap.end() )
384 m_aMap.erase( pElement->m_aContainerIt );
387 //=========================================================================
389 // Non-UNO interface
391 //=========================================================================
393 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage(
394 const rtl::OUString & rUri, StorageAccessMode eMode )
395 throw ( embed::InvalidStorageException,
396 lang::IllegalArgumentException,
397 io::IOException,
398 embed::StorageWrappedTargetException,
399 uno::RuntimeException )
401 uno::Reference< embed::XStorage > xParentStorage;
403 Uri aUri( rUri );
404 Uri aParentUri( aUri.getParentUri() );
405 if ( !aParentUri.isRoot() )
407 xParentStorage = createStorage( aUri.getParentUri(), eMode );
408 OSL_ENSURE( xParentStorage.is()
409 // requested to create new storage, but failed?
410 || ( eMode != READ_WRITE_CREATE ),
411 "StorageElementFactory::queryParentStorage - No storage!" );
413 return xParentStorage;
416 //=========================================================================
417 uno::Reference< embed::XStorage > StorageElementFactory::queryStorage(
418 const uno::Reference< embed::XStorage > & xParentStorage,
419 const rtl::OUString & rUri,
420 StorageAccessMode eMode )
421 throw ( embed::InvalidStorageException,
422 lang::IllegalArgumentException,
423 io::IOException,
424 embed::StorageWrappedTargetException,
425 uno::RuntimeException )
427 uno::Reference< embed::XStorage > xStorage;
429 Uri aUri( rUri );
431 if ( !xParentStorage.is() )
433 // document storage
435 xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() );
437 if ( !xStorage.is() )
439 if ( eMode == READ_WRITE_CREATE )
440 throw lang::IllegalArgumentException(
441 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
442 "Invalid open mode: document storages cannot be "
443 "created!" ) ),
444 uno::Reference< uno::XInterface >(),
445 sal_Int16( 2 ) );
446 else
447 throw embed::InvalidStorageException(
448 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
449 "Invalid document id!" ) ),
450 uno::Reference< uno::XInterface >() );
453 // match xStorage's open mode against requested open mode
455 uno::Reference< beans::XPropertySet > xPropSet(
456 xStorage, uno::UNO_QUERY );
457 OSL_ENSURE( xPropSet.is(),
458 "StorageElementFactory::queryStorage - "
459 "No XPropertySet interface!" );
462 uno::Any aPropValue = xPropSet->getPropertyValue(
463 rtl::OUString(
464 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
466 sal_Int32 nOpenMode = 0;
467 if ( aPropValue >>= nOpenMode )
469 switch ( eMode )
471 case READ:
472 if ( !( nOpenMode & embed::ElementModes::READ ) )
474 // document opened, but not readable.
475 throw embed::InvalidStorageException(
476 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
477 "Storage is open, but not readable!" ) ),
478 uno::Reference< uno::XInterface >() );
480 // storage okay
481 break;
483 case READ_WRITE_NOCREATE:
484 case READ_WRITE_CREATE:
485 if ( !( nOpenMode & embed::ElementModes::WRITE ) )
487 // document opened, but not writable.
488 throw embed::InvalidStorageException(
489 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
490 "Storage is open, but not writable!" ) ),
491 uno::Reference< uno::XInterface >() );
493 // storage okay
494 break;
497 else
499 OSL_FAIL(
500 "Bug! Value of property OpenMode has wrong type!" );
502 throw uno::RuntimeException(
503 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
504 "Bug! Value of property OpenMode has wrong type!" ) ),
505 uno::Reference< uno::XInterface >() );
508 catch ( beans::UnknownPropertyException const & e )
510 OSL_FAIL( "Property OpenMode not supported!" );
512 throw embed::StorageWrappedTargetException(
513 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
514 "Bug! Value of property OpenMode has wrong type!" ) ),
515 uno::Reference< uno::XInterface >(),
516 uno::makeAny( e ) );
518 catch ( lang::WrappedTargetException const & e )
520 OSL_FAIL( "Caught WrappedTargetException!" );
522 throw embed::StorageWrappedTargetException(
523 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
524 "WrappedTargetException during getPropertyValue!" ) ),
525 uno::Reference< uno::XInterface >(),
526 uno::makeAny( e ) );
529 else
531 // sub storage
533 const rtl::OUString & rName = aUri.getDecodedName();
535 if ( eMode == READ )
539 sal_Int32 nOpenMode = embed::ElementModes::READ
540 | embed::ElementModes::NOCREATE;
541 xStorage
542 = xParentStorage->openStorageElement( rName, nOpenMode );
544 catch ( io::IOException const & )
546 // Another chance: Try to clone storage.
547 xStorage = createTemporaryStorage();
548 xParentStorage->copyStorageElementLastCommitTo( rName,
549 xStorage );
552 else
554 sal_Int32 nOpenMode = embed::ElementModes::READWRITE;
555 if ( eMode == READ_WRITE_NOCREATE )
556 nOpenMode |= embed::ElementModes::NOCREATE;
558 xStorage = xParentStorage->openStorageElement( rName, nOpenMode );
562 OSL_ENSURE( xStorage.is() || ( eMode != READ_WRITE_CREATE ),
563 "StorageElementFactory::queryStorage - No storage!" );
564 return xStorage;
567 //=========================================================================
568 uno::Reference< io::XStream >
569 StorageElementFactory::queryStream(
570 const uno::Reference< embed::XStorage > & xParentStorage,
571 const rtl::OUString & rUri,
572 const rtl::OUString & rPassword,
573 StorageAccessMode eMode,
574 bool bTruncate )
575 throw ( embed::InvalidStorageException,
576 lang::IllegalArgumentException,
577 io::IOException,
578 embed::StorageWrappedTargetException,
579 packages::WrongPasswordException,
580 uno::RuntimeException )
582 osl::MutexGuard aGuard( m_aMutex );
584 if ( !xParentStorage.is() )
586 throw lang::IllegalArgumentException(
587 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
588 "No parent storage!" ) ),
589 uno::Reference< uno::XInterface >(),
590 sal_Int16( 2 ) );
593 Uri aUri( rUri );
594 if ( aUri.isRoot() )
596 throw lang::IllegalArgumentException(
597 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
598 "Root never is a stream!" ) ),
599 uno::Reference< uno::XInterface >(),
600 sal_Int16( 2 ) );
602 else if ( aUri.isDocument() )
604 throw lang::IllegalArgumentException(
605 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
606 "A document never is a stream!" ) ),
607 uno::Reference< uno::XInterface >(),
608 sal_Int16( 2 ) );
611 sal_Int32 nOpenMode;
612 switch ( eMode )
614 case READ:
615 nOpenMode = embed::ElementModes::READ
616 | embed::ElementModes::NOCREATE
617 | embed::ElementModes::SEEKABLE;
618 break;
620 case READ_WRITE_NOCREATE:
621 nOpenMode = embed::ElementModes::READWRITE
622 | embed::ElementModes::NOCREATE
623 | embed::ElementModes::SEEKABLE;
625 if ( bTruncate )
626 nOpenMode |= embed::ElementModes::TRUNCATE;
628 break;
630 case READ_WRITE_CREATE:
631 nOpenMode = embed::ElementModes::READWRITE
632 | embed::ElementModes::SEEKABLE;
634 if ( bTruncate )
635 nOpenMode |= embed::ElementModes::TRUNCATE;
637 break;
639 default:
640 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
642 throw embed::InvalidStorageException(
643 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
644 "Unknown open mode!" ) ),
645 uno::Reference< uno::XInterface >() );
648 // No object re-usage mechanism; streams are seekable => not stateless.
650 uno::Reference< io::XStream > xStream;
651 if ( !rPassword.isEmpty() )
653 if ( eMode == READ )
657 xStream = xParentStorage->cloneEncryptedStreamElement(
658 aUri.getDecodedName(),
659 rPassword );
661 catch ( packages::NoEncryptionException const & )
663 xStream
664 = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
667 else
671 xStream = xParentStorage->openEncryptedStreamElement(
672 aUri.getDecodedName(),
673 nOpenMode,
674 rPassword );
676 catch ( packages::NoEncryptionException const & )
678 xStream
679 = xParentStorage->openStreamElement( aUri.getDecodedName(),
680 nOpenMode );
684 else
686 if ( eMode == READ )
688 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
690 else
692 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
693 nOpenMode );
697 if ( !xStream.is() )
699 throw embed::InvalidStorageException(
700 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
701 "No stream!" ) ),
702 uno::Reference< uno::XInterface >() );
705 return xStream;
708 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */