1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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
),
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
;
70 xStorageFac
= uno::Reference
< lang::XSingleServiceFactory
>(
71 m_xSMgr
->createInstance(
72 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
73 "com.sun.star.embed.StorageFactory" ) ) ),
77 OSL_ENSURE( xStorageFac
.is(), "Can't create storage factory!" );
78 if ( xStorageFac
.is() )
79 xStorage
= uno::Reference
< embed::XStorage
>(
80 xStorageFac
->createInstance(),
84 throw uno::RuntimeException();
89 //=========================================================================
90 uno::Reference
< embed::XStorage
>
91 StorageElementFactory::createStorage( const rtl::OUString
& rUri
,
92 StorageAccessMode eMode
)
93 throw ( embed::InvalidStorageException
,
94 lang::IllegalArgumentException
,
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
>(),
113 throw lang::IllegalArgumentException(
114 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
115 "Root never has a storage!" ) ),
116 uno::Reference
< uno::XInterface
>(),
120 rtl::OUString aUriKey
121 ( ( rUri
.getStr()[ rUri
.getLength() - 1 ] == sal_Unicode( '/' ) )
122 ? rUri
.copy( 0, rUri
.getLength() - 1 )
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.
137 // No need to check; storage is at least readable.
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
;
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!" );
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
) );
191 StorageMap::value_type(
192 std::pair
< rtl::OUString
, bool >( aUriKey
, bWritable
),
193 xElement
.get() ) ).first
;
195 aIt
->second
->m_aContainerIt
= aIt
;
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
);
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!" );
238 = new Storage( comphelper::getComponentContext(m_xSMgr
), this, aUriKey
, xParentStorage
, xStorage
);
239 aIt
->second
->m_aContainerIt
= aIt
;
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
,
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 );
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
,
278 throw ( embed::InvalidStorageException
,
279 lang::IllegalArgumentException
,
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
300 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
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
>(
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
,
324 throw ( embed::InvalidStorageException
,
325 lang::IllegalArgumentException
,
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
346 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
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 //=========================================================================
372 //=========================================================================
374 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
375 const rtl::OUString
& rUri
, StorageAccessMode eMode
)
376 throw ( embed::InvalidStorageException
,
377 lang::IllegalArgumentException
,
379 embed::StorageWrappedTargetException
,
380 uno::RuntimeException
)
382 uno::Reference
< embed::XStorage
> xParentStorage
;
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
,
405 embed::StorageWrappedTargetException
,
406 uno::RuntimeException
)
408 uno::Reference
< embed::XStorage
> xStorage
;
412 if ( !xParentStorage
.is() )
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 "
425 uno::Reference
< uno::XInterface
>(),
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(
445 RTL_CONSTASCII_USTRINGPARAM( "OpenMode" ) ) );
447 sal_Int32 nOpenMode
= 0;
448 if ( aPropValue
>>= nOpenMode
)
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
>() );
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
>() );
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
>(),
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
>(),
514 const rtl::OUString
& rName
= aUri
.getDecodedName();
520 sal_Int32 nOpenMode
= embed::ElementModes::READ
521 | embed::ElementModes::NOCREATE
;
523 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
525 catch ( io::IOException
const & )
527 // Another chance: Try to clone storage.
528 xStorage
= createTemporaryStorage();
529 xParentStorage
->copyStorageElementLastCommitTo( rName
,
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!" );
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
,
556 throw ( embed::InvalidStorageException
,
557 lang::IllegalArgumentException
,
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
>(),
577 throw lang::IllegalArgumentException(
578 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
579 "Root never is a stream!" ) ),
580 uno::Reference
< uno::XInterface
>(),
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
>(),
596 nOpenMode
= embed::ElementModes::READ
597 | embed::ElementModes::NOCREATE
598 | embed::ElementModes::SEEKABLE
;
601 case READ_WRITE_NOCREATE
:
602 nOpenMode
= embed::ElementModes::READWRITE
603 | embed::ElementModes::NOCREATE
604 | embed::ElementModes::SEEKABLE
;
607 nOpenMode
|= embed::ElementModes::TRUNCATE
;
611 case READ_WRITE_CREATE
:
612 nOpenMode
= embed::ElementModes::READWRITE
613 | embed::ElementModes::SEEKABLE
;
616 nOpenMode
|= embed::ElementModes::TRUNCATE
;
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() )
638 xStream
= xParentStorage
->cloneEncryptedStreamElement(
639 aUri
.getDecodedName(),
642 catch ( packages::NoEncryptionException
const & )
645 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
652 xStream
= xParentStorage
->openEncryptedStreamElement(
653 aUri
.getDecodedName(),
657 catch ( packages::NoEncryptionException
const & )
660 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
669 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
673 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
680 throw embed::InvalidStorageException(
681 rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
683 uno::Reference
< uno::XInterface
>() );
689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */