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 .
20 #include <com/sun/star/beans/XPropertySet.hpp>
21 #include <com/sun/star/embed/ElementModes.hpp>
22 #include <com/sun/star/embed/InvalidStorageException.hpp>
23 #include <com/sun/star/embed/StorageFactory.hpp>
24 #include <com/sun/star/embed/StorageWrappedTargetException.hpp>
25 #include <com/sun/star/io/IOException.hpp>
26 #include <com/sun/star/packages/NoEncryptionException.hpp>
27 #include <cppuhelper/exc_hlp.hxx>
28 #include <osl/diagnose.h>
30 #include "tdoc_uri.hxx"
31 #include "tdoc_docmgr.hxx"
32 #include "tdoc_stgelems.hxx"
34 #include "tdoc_storage.hxx"
36 using namespace com::sun::star
;
37 using namespace tdoc_ucp
;
40 // StorageElementFactory Implementation.
43 StorageElementFactory::StorageElementFactory(
44 const uno::Reference
< uno::XComponentContext
> & rxContext
,
45 const rtl::Reference
< OfficeDocumentsManager
> & xDocsMgr
)
46 : m_xDocsMgr( xDocsMgr
),
47 m_xContext( rxContext
)
52 StorageElementFactory::~StorageElementFactory()
54 OSL_ENSURE( m_aMap
.empty(),
55 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
59 uno::Reference
< embed::XStorage
>
60 StorageElementFactory::createTemporaryStorage()
62 uno::Reference
< embed::XStorage
> xStorage
;
63 uno::Reference
< lang::XSingleServiceFactory
> xStorageFac
;
64 if ( m_xContext
.is() )
66 xStorageFac
= embed::StorageFactory::create( m_xContext
);
69 OSL_ENSURE( xStorageFac
.is(), "Can't create storage factory!" );
70 if ( xStorageFac
.is() )
71 xStorage
.set( xStorageFac
->createInstance(), uno::UNO_QUERY
);
74 throw uno::RuntimeException();
80 uno::Reference
< embed::XStorage
>
81 StorageElementFactory::createStorage( const OUString
& rUri
,
82 StorageAccessMode eMode
)
84 osl::MutexGuard
aGuard( m_aMutex
);
86 if ( ( eMode
!= READ
) &&
87 ( eMode
!= READ_WRITE_NOCREATE
) &&
88 ( eMode
!= READ_WRITE_CREATE
) )
89 throw lang::IllegalArgumentException(
91 uno::Reference
< uno::XInterface
>(),
97 throw lang::IllegalArgumentException(
98 "Root never has a storage!",
99 uno::Reference
< uno::XInterface
>(),
105 ? rUri
.copy( 0, rUri
.getLength() - 1 )
108 StorageMap::iterator
aIt ( m_aMap
.begin() );
109 StorageMap::iterator
aEnd( m_aMap
.end() );
111 while ( aIt
!= aEnd
)
113 if ( (*aIt
).first
.first
== aUriKey
)
115 // URI matches. Now, check open mode.
120 // No need to check; storage is at least readable.
124 case READ_WRITE_NOCREATE
:
125 case READ_WRITE_CREATE
:
126 // If found storage is writable, it can be used.
127 // If not, a new one must be created.
128 bMatch
= (*aIt
).first
.second
;
140 uno::Reference
< embed::XStorage
> xParentStorage
;
142 // documents never have a parent storage.
143 if ( !aUri
.isDocument() )
145 xParentStorage
= queryParentStorage( aUriKey
, eMode
);
147 if ( !xParentStorage
.is() )
149 // requested to create new storage, but failed?
150 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
151 "Unable to create parent storage!" );
152 return xParentStorage
;
156 uno::Reference
< embed::XStorage
> xStorage
157 = queryStorage( xParentStorage
, aUriKey
, eMode
);
159 if ( !xStorage
.is() )
161 // requested to create new storage, but failed?
162 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
163 "Unable to create storage!" );
167 bool bWritable
= ( ( eMode
== READ_WRITE_NOCREATE
)
168 || ( eMode
== READ_WRITE_CREATE
) );
170 rtl::Reference
< Storage
> xElement(
171 new Storage( m_xContext
, this, aUriKey
, xParentStorage
, xStorage
) );
173 aIt
= m_aMap
.emplace(
174 std::pair
< OUString
, bool >( aUriKey
, bWritable
),
175 xElement
.get() ).first
;
177 aIt
->second
->m_aContainerIt
= aIt
;
180 else if ( osl_atomic_increment( &aIt
->second
->m_refCount
) > 1 )
182 uno::Reference
< embed::XStorage
> xElement( aIt
->second
);
183 osl_atomic_decrement( &aIt
->second
->m_refCount
);
188 osl_atomic_decrement( &aIt
->second
->m_refCount
);
189 aIt
->second
->m_aContainerIt
= m_aMap
.end();
191 uno::Reference
< embed::XStorage
> xParentStorage
;
193 // documents never have a parent storage.
194 if ( !aUri
.isDocument() )
196 xParentStorage
= queryParentStorage( aUriKey
, eMode
);
198 if ( !xParentStorage
.is() )
200 // requested to create new storage, but failed?
201 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
202 "Unable to create parent storage!" );
203 return xParentStorage
;
207 uno::Reference
< embed::XStorage
> xStorage
208 = queryStorage( xParentStorage
, aUriKey
, eMode
);
210 if ( !xStorage
.is() )
212 // requested to create new storage, but failed?
213 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
214 "Unable to create storage!" );
218 rtl::Reference
<Storage
> pNewStorage
= new Storage( m_xContext
, this, aUriKey
, xParentStorage
, xStorage
);
219 aIt
->second
= pNewStorage
.get();
220 aIt
->second
->m_aContainerIt
= aIt
;
226 uno::Reference
< io::XInputStream
>
227 StorageElementFactory::createInputStream( const OUString
& rUri
,
228 const OUString
& rPassword
)
230 osl::MutexGuard
aGuard( m_aMutex
);
232 uno::Reference
< embed::XStorage
> xParentStorage
233 = queryParentStorage( rUri
, READ
);
235 // Each stream must have a parent storage.
236 if ( !xParentStorage
.is() )
237 return uno::Reference
< io::XInputStream
>();
239 uno::Reference
< io::XStream
> xStream
240 = queryStream( xParentStorage
, rUri
, rPassword
, READ
, false );
243 return uno::Reference
< io::XInputStream
>();
245 return xStream
->getInputStream();
249 uno::Reference
< io::XOutputStream
>
250 StorageElementFactory::createOutputStream( const OUString
& rUri
,
251 const OUString
& rPassword
,
254 osl::MutexGuard
aGuard( m_aMutex
);
256 uno::Reference
< embed::XStorage
> xParentStorage
257 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
259 // Each stream must have a parent storage.
260 if ( !xParentStorage
.is() )
262 OSL_FAIL( "StorageElementFactory::createOutputStream - "
263 "Unable to create parent storage!" );
264 return uno::Reference
< io::XOutputStream
>();
267 uno::Reference
< io::XStream
> xStream
269 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
273 OSL_FAIL( "StorageElementFactory::createOutputStream - "
274 "Unable to create stream!" );
275 return uno::Reference
< io::XOutputStream
>();
278 // Note: We need a wrapper to hold a reference to the parent storage to
279 // ensure that nobody else owns it at the moment we want to commit
280 // our changes. (There can be only one writable instance at a time
281 // and even no writable instance if there is already another
282 // read-only instance!)
283 return uno::Reference
< io::XOutputStream
>(
284 new OutputStream( m_xContext
, rUri
, xParentStorage
, xStream
->getOutputStream() ) );
288 uno::Reference
< io::XStream
>
289 StorageElementFactory::createStream( const OUString
& rUri
,
290 const OUString
& rPassword
,
293 osl::MutexGuard
aGuard( m_aMutex
);
295 uno::Reference
< embed::XStorage
> xParentStorage
296 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
298 // Each stream must have a parent storage.
299 if ( !xParentStorage
.is() )
301 OSL_FAIL( "StorageElementFactory::createStream - "
302 "Unable to create parent storage!" );
303 return uno::Reference
< io::XStream
>();
306 uno::Reference
< io::XStream
> xStream
308 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
312 OSL_FAIL( "StorageElementFactory::createStream - "
313 "Unable to create stream!" );
314 return uno::Reference
< io::XStream
>();
317 return uno::Reference
< io::XStream
>(
318 new Stream( m_xContext
, rUri
, xParentStorage
, xStream
) );
322 void StorageElementFactory::releaseElement( Storage
const * pElement
)
324 OSL_ASSERT( pElement
);
325 osl::MutexGuard
aGuard( m_aMutex
);
326 if ( pElement
->m_aContainerIt
!= m_aMap
.end() )
327 m_aMap
.erase( pElement
->m_aContainerIt
);
334 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
335 const OUString
& rUri
, StorageAccessMode eMode
)
337 uno::Reference
< embed::XStorage
> xParentStorage
;
340 Uri
aParentUri( aUri
.getParentUri() );
341 if ( !aParentUri
.isRoot() )
343 xParentStorage
= createStorage( aUri
.getParentUri(), eMode
);
344 OSL_ENSURE( xParentStorage
.is()
345 // requested to create new storage, but failed?
346 || ( eMode
!= READ_WRITE_CREATE
),
347 "StorageElementFactory::queryParentStorage - No storage!" );
349 return xParentStorage
;
353 uno::Reference
< embed::XStorage
> StorageElementFactory::queryStorage(
354 const uno::Reference
< embed::XStorage
> & xParentStorage
,
355 const OUString
& rUri
,
356 StorageAccessMode eMode
)
358 uno::Reference
< embed::XStorage
> xStorage
;
362 if ( !xParentStorage
.is() )
366 xStorage
= m_xDocsMgr
->queryStorage( aUri
.getDocumentId() );
368 if ( !xStorage
.is() )
370 if ( eMode
== READ_WRITE_CREATE
)
371 throw lang::IllegalArgumentException(
372 "Invalid open mode: document storages cannot be created!",
373 uno::Reference
< uno::XInterface
>(),
376 throw embed::InvalidStorageException(
377 "Invalid document id!",
378 uno::Reference
< uno::XInterface
>() );
381 // match xStorage's open mode against requested open mode
383 uno::Reference
< beans::XPropertySet
> xPropSet(
384 xStorage
, uno::UNO_QUERY
);
385 OSL_ENSURE( xPropSet
.is(),
386 "StorageElementFactory::queryStorage - "
387 "No XPropertySet interface!" );
390 uno::Any aPropValue
= xPropSet
->getPropertyValue("OpenMode");
392 sal_Int32 nOpenMode
= 0;
393 if ( aPropValue
>>= nOpenMode
)
398 if ( !( nOpenMode
& embed::ElementModes::READ
) )
400 // document opened, but not readable.
401 throw embed::InvalidStorageException(
402 "Storage is open, but not readable!" );
407 case READ_WRITE_NOCREATE
:
408 case READ_WRITE_CREATE
:
409 if ( !( nOpenMode
& embed::ElementModes::WRITE
) )
411 // document opened, but not writable.
412 throw embed::InvalidStorageException(
413 "Storage is open, but not writable!" );
422 "Bug! Value of property OpenMode has wrong type!" );
424 throw uno::RuntimeException(
425 "Bug! Value of property OpenMode has wrong type!" );
428 catch ( beans::UnknownPropertyException
const & )
430 css::uno::Any anyEx
= cppu::getCaughtException();
431 OSL_FAIL( "Property OpenMode not supported!" );
433 throw embed::StorageWrappedTargetException(
434 "Bug! Value of property OpenMode has wrong type!",
435 uno::Reference
< uno::XInterface
>(),
438 catch ( lang::WrappedTargetException
const & )
440 css::uno::Any anyEx
= cppu::getCaughtException();
441 OSL_FAIL( "Caught WrappedTargetException!" );
443 throw embed::StorageWrappedTargetException(
444 "WrappedTargetException during getPropertyValue!",
445 uno::Reference
< uno::XInterface
>(),
453 const OUString
& rName
= aUri
.getDecodedName();
459 sal_Int32
const nOpenMode
= embed::ElementModes::READ
460 | embed::ElementModes::NOCREATE
;
462 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
464 catch ( io::IOException
const & )
466 // Another chance: Try to clone storage.
467 xStorage
= createTemporaryStorage();
468 xParentStorage
->copyStorageElementLastCommitTo( rName
,
474 sal_Int32 nOpenMode
= embed::ElementModes::READWRITE
;
475 if ( eMode
== READ_WRITE_NOCREATE
)
476 nOpenMode
|= embed::ElementModes::NOCREATE
;
478 xStorage
= xParentStorage
->openStorageElement( rName
, nOpenMode
);
482 OSL_ENSURE( xStorage
.is() || ( eMode
!= READ_WRITE_CREATE
),
483 "StorageElementFactory::queryStorage - No storage!" );
488 uno::Reference
< io::XStream
>
489 StorageElementFactory::queryStream(
490 const uno::Reference
< embed::XStorage
> & xParentStorage
,
491 const OUString
& rUri
,
492 const OUString
& rPassword
,
493 StorageAccessMode eMode
,
496 osl::MutexGuard
aGuard( m_aMutex
);
498 if ( !xParentStorage
.is() )
500 throw lang::IllegalArgumentException(
501 "No parent storage!",
502 uno::Reference
< uno::XInterface
>(),
509 throw lang::IllegalArgumentException(
510 "Root never is a stream!",
511 uno::Reference
< uno::XInterface
>(),
514 else if ( aUri
.isDocument() )
516 throw lang::IllegalArgumentException(
517 "A document never is a stream!",
518 uno::Reference
< uno::XInterface
>(),
526 nOpenMode
= embed::ElementModes::READ
527 | embed::ElementModes::NOCREATE
528 | embed::ElementModes::SEEKABLE
;
531 case READ_WRITE_NOCREATE
:
532 nOpenMode
= embed::ElementModes::READWRITE
533 | embed::ElementModes::NOCREATE
534 | embed::ElementModes::SEEKABLE
;
537 nOpenMode
|= embed::ElementModes::TRUNCATE
;
541 case READ_WRITE_CREATE
:
542 nOpenMode
= embed::ElementModes::READWRITE
543 | embed::ElementModes::SEEKABLE
;
546 nOpenMode
|= embed::ElementModes::TRUNCATE
;
551 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
553 throw embed::InvalidStorageException(
554 "Unknown open mode!",
555 uno::Reference
< uno::XInterface
>() );
558 // No object re-usage mechanism; streams are seekable => not stateless.
560 uno::Reference
< io::XStream
> xStream
;
561 if ( !rPassword
.isEmpty() )
567 xStream
= xParentStorage
->cloneEncryptedStreamElement(
568 aUri
.getDecodedName(),
571 catch ( packages::NoEncryptionException
const & )
574 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
581 xStream
= xParentStorage
->openEncryptedStreamElement(
582 aUri
.getDecodedName(),
586 catch ( packages::NoEncryptionException
const & )
589 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
598 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
602 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
609 throw embed::InvalidStorageException(
611 uno::Reference
< uno::XInterface
>() );
617 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */