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 rtl::Reference
< Storage
> 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 aIt
->second
= new Storage( m_xContext
, this, aUriKey
, xParentStorage
, xStorage
);
219 aIt
->second
->m_aContainerIt
= aIt
;
225 uno::Reference
< io::XInputStream
>
226 StorageElementFactory::createInputStream( const OUString
& rUri
,
227 const OUString
& rPassword
)
229 osl::MutexGuard
aGuard( m_aMutex
);
231 uno::Reference
< embed::XStorage
> xParentStorage
232 = queryParentStorage( rUri
, READ
);
234 // Each stream must have a parent storage.
235 if ( !xParentStorage
.is() )
236 return uno::Reference
< io::XInputStream
>();
238 uno::Reference
< io::XStream
> xStream
239 = queryStream( xParentStorage
, rUri
, rPassword
, READ
, false );
242 return uno::Reference
< io::XInputStream
>();
244 return xStream
->getInputStream();
248 uno::Reference
< io::XOutputStream
>
249 StorageElementFactory::createOutputStream( const OUString
& rUri
,
250 const OUString
& rPassword
,
253 osl::MutexGuard
aGuard( m_aMutex
);
255 uno::Reference
< embed::XStorage
> xParentStorage
256 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
258 // Each stream must have a parent storage.
259 if ( !xParentStorage
.is() )
261 OSL_FAIL( "StorageElementFactory::createOutputStream - "
262 "Unable to create parent storage!" );
263 return uno::Reference
< io::XOutputStream
>();
266 uno::Reference
< io::XStream
> xStream
268 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
272 OSL_FAIL( "StorageElementFactory::createOutputStream - "
273 "Unable to create stream!" );
274 return uno::Reference
< io::XOutputStream
>();
277 // Note: We need a wrapper to hold a reference to the parent storage to
278 // ensure that nobody else owns it at the moment we want to commit
279 // our changes. (There can be only one writable instance at a time
280 // and even no writable instance if there is already another
281 // read-only instance!)
282 return uno::Reference
< io::XOutputStream
>(
283 new OutputStream( m_xContext
, rUri
, xParentStorage
, xStream
->getOutputStream() ) );
287 uno::Reference
< io::XStream
>
288 StorageElementFactory::createStream( const OUString
& rUri
,
289 const OUString
& rPassword
,
292 osl::MutexGuard
aGuard( m_aMutex
);
294 uno::Reference
< embed::XStorage
> xParentStorage
295 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
297 // Each stream must have a parent storage.
298 if ( !xParentStorage
.is() )
300 OSL_FAIL( "StorageElementFactory::createStream - "
301 "Unable to create parent storage!" );
302 return uno::Reference
< io::XStream
>();
305 uno::Reference
< io::XStream
> xStream
307 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
311 OSL_FAIL( "StorageElementFactory::createStream - "
312 "Unable to create stream!" );
313 return uno::Reference
< io::XStream
>();
316 return uno::Reference
< io::XStream
>(
317 new Stream( m_xContext
, rUri
, xParentStorage
, xStream
) );
321 void StorageElementFactory::releaseElement( Storage
const * pElement
)
323 OSL_ASSERT( pElement
);
324 osl::MutexGuard
aGuard( m_aMutex
);
325 if ( pElement
->m_aContainerIt
!= m_aMap
.end() )
326 m_aMap
.erase( pElement
->m_aContainerIt
);
333 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
334 const OUString
& rUri
, StorageAccessMode eMode
)
336 uno::Reference
< embed::XStorage
> xParentStorage
;
339 Uri
aParentUri( aUri
.getParentUri() );
340 if ( !aParentUri
.isRoot() )
342 xParentStorage
= createStorage( aUri
.getParentUri(), eMode
);
343 OSL_ENSURE( xParentStorage
.is()
344 // requested to create new storage, but failed?
345 || ( eMode
!= READ_WRITE_CREATE
),
346 "StorageElementFactory::queryParentStorage - No storage!" );
348 return xParentStorage
;
352 uno::Reference
< embed::XStorage
> StorageElementFactory::queryStorage(
353 const uno::Reference
< embed::XStorage
> & xParentStorage
,
354 const OUString
& rUri
,
355 StorageAccessMode eMode
)
357 uno::Reference
< embed::XStorage
> xStorage
;
361 if ( !xParentStorage
.is() )
365 xStorage
= m_xDocsMgr
->queryStorage( aUri
.getDocumentId() );
367 if ( !xStorage
.is() )
369 if ( eMode
== READ_WRITE_CREATE
)
370 throw lang::IllegalArgumentException(
371 "Invalid open mode: document storages cannot be created!",
372 uno::Reference
< uno::XInterface
>(),
375 throw embed::InvalidStorageException(
376 "Invalid document id!",
377 uno::Reference
< uno::XInterface
>() );
380 // match xStorage's open mode against requested open mode
382 uno::Reference
< beans::XPropertySet
> xPropSet(
383 xStorage
, uno::UNO_QUERY
);
384 OSL_ENSURE( xPropSet
.is(),
385 "StorageElementFactory::queryStorage - "
386 "No XPropertySet interface!" );
389 uno::Any aPropValue
= xPropSet
->getPropertyValue("OpenMode");
391 sal_Int32 nOpenMode
= 0;
392 if ( aPropValue
>>= nOpenMode
)
397 if ( !( nOpenMode
& embed::ElementModes::READ
) )
399 // document opened, but not readable.
400 throw embed::InvalidStorageException(
401 "Storage is open, but not readable!" );
406 case READ_WRITE_NOCREATE
:
407 case READ_WRITE_CREATE
:
408 if ( !( nOpenMode
& embed::ElementModes::WRITE
) )
410 // document opened, but not writable.
411 throw embed::InvalidStorageException(
412 "Storage is open, but not writable!" );
421 "Bug! Value of property OpenMode has wrong type!" );
423 throw uno::RuntimeException(
424 "Bug! Value of property OpenMode has wrong type!" );
427 catch ( beans::UnknownPropertyException
const & )
429 css::uno::Any anyEx
= cppu::getCaughtException();
430 OSL_FAIL( "Property OpenMode not supported!" );
432 throw embed::StorageWrappedTargetException(
433 "Bug! Value of property OpenMode has wrong type!",
434 uno::Reference
< uno::XInterface
>(),
437 catch ( lang::WrappedTargetException
const & )
439 css::uno::Any anyEx
= cppu::getCaughtException();
440 OSL_FAIL( "Caught WrappedTargetException!" );
442 throw embed::StorageWrappedTargetException(
443 "WrappedTargetException during getPropertyValue!",
444 uno::Reference
< uno::XInterface
>(),
452 const OUString
& rName
= aUri
.getDecodedName();
458 sal_Int32
const nOpenMode
= embed::ElementModes::READ
459 | embed::ElementModes::NOCREATE
;
461 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
463 catch ( io::IOException
const & )
465 // Another chance: Try to clone storage.
466 xStorage
= createTemporaryStorage();
467 xParentStorage
->copyStorageElementLastCommitTo( rName
,
473 sal_Int32 nOpenMode
= embed::ElementModes::READWRITE
;
474 if ( eMode
== READ_WRITE_NOCREATE
)
475 nOpenMode
|= embed::ElementModes::NOCREATE
;
477 xStorage
= xParentStorage
->openStorageElement( rName
, nOpenMode
);
481 OSL_ENSURE( xStorage
.is() || ( eMode
!= READ_WRITE_CREATE
),
482 "StorageElementFactory::queryStorage - No storage!" );
487 uno::Reference
< io::XStream
>
488 StorageElementFactory::queryStream(
489 const uno::Reference
< embed::XStorage
> & xParentStorage
,
490 const OUString
& rUri
,
491 const OUString
& rPassword
,
492 StorageAccessMode eMode
,
495 osl::MutexGuard
aGuard( m_aMutex
);
497 if ( !xParentStorage
.is() )
499 throw lang::IllegalArgumentException(
500 "No parent storage!",
501 uno::Reference
< uno::XInterface
>(),
508 throw lang::IllegalArgumentException(
509 "Root never is a stream!",
510 uno::Reference
< uno::XInterface
>(),
513 else if ( aUri
.isDocument() )
515 throw lang::IllegalArgumentException(
516 "A document never is a stream!",
517 uno::Reference
< uno::XInterface
>(),
525 nOpenMode
= embed::ElementModes::READ
526 | embed::ElementModes::NOCREATE
527 | embed::ElementModes::SEEKABLE
;
530 case READ_WRITE_NOCREATE
:
531 nOpenMode
= embed::ElementModes::READWRITE
532 | embed::ElementModes::NOCREATE
533 | embed::ElementModes::SEEKABLE
;
536 nOpenMode
|= embed::ElementModes::TRUNCATE
;
540 case READ_WRITE_CREATE
:
541 nOpenMode
= embed::ElementModes::READWRITE
542 | embed::ElementModes::SEEKABLE
;
545 nOpenMode
|= embed::ElementModes::TRUNCATE
;
550 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
552 throw embed::InvalidStorageException(
553 "Unknown open mode!",
554 uno::Reference
< uno::XInterface
>() );
557 // No object re-usage mechanism; streams are seekable => not stateless.
559 uno::Reference
< io::XStream
> xStream
;
560 if ( !rPassword
.isEmpty() )
566 xStream
= xParentStorage
->cloneEncryptedStreamElement(
567 aUri
.getDecodedName(),
570 catch ( packages::NoEncryptionException
const & )
573 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
580 xStream
= xParentStorage
->openEncryptedStreamElement(
581 aUri
.getDecodedName(),
585 catch ( packages::NoEncryptionException
const & )
588 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
597 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
601 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
608 throw embed::InvalidStorageException(
610 uno::Reference
< uno::XInterface
>() );
616 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */