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 /**************************************************************************
32 **************************************************************************
34 - remove root storage access workaround
36 *************************************************************************/
38 #define ROOTSTORAGE_ACCESS_WORKAROUND 1
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
),
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
;
89 xStorageFac
= uno::Reference
< lang::XSingleServiceFactory
>(
90 m_xSMgr
->createInstance(
91 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
92 "com.sun.star.embed.StorageFactory" ) ) ),
96 OSL_ENSURE( xStorageFac
.is(), "Can't create storage factory!" );
97 if ( xStorageFac
.is() )
98 xStorage
= uno::Reference
< embed::XStorage
>(
99 xStorageFac
->createInstance(),
102 if ( !xStorage
.is() )
103 throw uno::RuntimeException();
108 //=========================================================================
109 uno::Reference
< embed::XStorage
>
110 StorageElementFactory::createStorage( const rtl::OUString
& rUri
,
111 StorageAccessMode eMode
)
112 throw ( embed::InvalidStorageException
,
113 lang::IllegalArgumentException
,
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
>(),
132 throw lang::IllegalArgumentException(
133 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
134 "Root never has a storage!" ) ),
135 uno::Reference
< uno::XInterface
>(),
139 rtl::OUString aUriKey
140 ( ( rUri
.getStr()[ rUri
.getLength() - 1 ] == sal_Unicode( '/' ) )
141 ? rUri
.copy( 0, rUri
.getLength() - 1 )
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.
156 // No need to check; storage is at least readable.
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
;
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!" );
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
) );
210 StorageMap::value_type(
211 std::pair
< rtl::OUString
, bool >( aUriKey
, bWritable
),
212 xElement
.get() ) ).first
;
214 aIt
->second
->m_aContainerIt
= aIt
;
218 else if ( osl_incrementInterlockedCount( &aIt
->second
->m_refCount
) > 1 )
220 rtl::Reference
< Storage
> xElement( aIt
->second
);
221 osl_decrementInterlockedCount( &aIt
->second
->m_refCount
);
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!" );
257 = new Storage( m_xSMgr
, this, aUriKey
, xParentStorage
, xStorage
);
258 aIt
->second
->m_aContainerIt
= aIt
;
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
,
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 );
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
,
297 throw ( embed::InvalidStorageException
,
298 lang::IllegalArgumentException
,
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
319 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
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
>(
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
,
343 throw ( embed::InvalidStorageException
,
344 lang::IllegalArgumentException
,
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
365 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
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 //=========================================================================
391 //=========================================================================
393 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
394 const rtl::OUString
& rUri
, StorageAccessMode eMode
)
395 throw ( embed::InvalidStorageException
,
396 lang::IllegalArgumentException
,
398 embed::StorageWrappedTargetException
,
399 uno::RuntimeException
)
401 uno::Reference
< embed::XStorage
> xParentStorage
;
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
,
424 embed::StorageWrappedTargetException
,
425 uno::RuntimeException
)
427 uno::Reference
< embed::XStorage
> xStorage
;
431 if ( !xParentStorage
.is() )
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 "
444 uno::Reference
< uno::XInterface
>(),
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(
464 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
466 sal_Int32 nOpenMode
= 0;
467 if ( aPropValue
>>= nOpenMode
)
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
>() );
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
>() );
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
>(),
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
>(),
533 const rtl::OUString
& rName
= aUri
.getDecodedName();
539 sal_Int32 nOpenMode
= embed::ElementModes::READ
540 | embed::ElementModes::NOCREATE
;
542 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
544 catch ( io::IOException
const & )
546 // Another chance: Try to clone storage.
547 xStorage
= createTemporaryStorage();
548 xParentStorage
->copyStorageElementLastCommitTo( rName
,
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!" );
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
,
575 throw ( embed::InvalidStorageException
,
576 lang::IllegalArgumentException
,
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
>(),
596 throw lang::IllegalArgumentException(
597 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
598 "Root never is a stream!" ) ),
599 uno::Reference
< uno::XInterface
>(),
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
>(),
615 nOpenMode
= embed::ElementModes::READ
616 | embed::ElementModes::NOCREATE
617 | embed::ElementModes::SEEKABLE
;
620 case READ_WRITE_NOCREATE
:
621 nOpenMode
= embed::ElementModes::READWRITE
622 | embed::ElementModes::NOCREATE
623 | embed::ElementModes::SEEKABLE
;
626 nOpenMode
|= embed::ElementModes::TRUNCATE
;
630 case READ_WRITE_CREATE
:
631 nOpenMode
= embed::ElementModes::READWRITE
632 | embed::ElementModes::SEEKABLE
;
635 nOpenMode
|= embed::ElementModes::TRUNCATE
;
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() )
657 xStream
= xParentStorage
->cloneEncryptedStreamElement(
658 aUri
.getDecodedName(),
661 catch ( packages::NoEncryptionException
const & )
664 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
671 xStream
= xParentStorage
->openEncryptedStreamElement(
672 aUri
.getDecodedName(),
676 catch ( packages::NoEncryptionException
const & )
679 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
688 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
692 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
699 throw embed::InvalidStorageException(
700 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
702 uno::Reference
< uno::XInterface
>() );
708 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */