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/embed/StorageFactory.hpp"
25 #include <osl/diagnose.h>
26 #include "comphelper/processfactory.hxx"
28 #include "tdoc_uri.hxx"
29 #include "tdoc_docmgr.hxx"
30 #include "tdoc_stgelems.hxx"
32 #include "tdoc_storage.hxx"
34 using namespace com::sun::star
;
35 using namespace tdoc_ucp
;
41 // StorageElementFactory Implementation.
46 StorageElementFactory::StorageElementFactory(
47 const uno::Reference
< uno::XComponentContext
> & rxContext
,
48 const rtl::Reference
< OfficeDocumentsManager
> & xDocsMgr
)
49 : m_xDocsMgr( xDocsMgr
),
50 m_xContext( rxContext
)
55 StorageElementFactory::~StorageElementFactory()
57 OSL_ENSURE( m_aMap
.empty(),
58 "StorageElementFactory::~StorageElementFactory - Dangling storages!" );
62 uno::Reference
< embed::XStorage
>
63 StorageElementFactory::createTemporaryStorage()
64 throw ( uno::Exception
,
65 uno::RuntimeException
)
67 uno::Reference
< embed::XStorage
> xStorage
;
68 uno::Reference
< lang::XSingleServiceFactory
> xStorageFac
;
69 if ( m_xContext
.is() )
71 xStorageFac
= embed::StorageFactory::create( m_xContext
);
74 OSL_ENSURE( xStorageFac
.is(), "Can't create storage factory!" );
75 if ( xStorageFac
.is() )
76 xStorage
= uno::Reference
< embed::XStorage
>(
77 xStorageFac
->createInstance(),
81 throw uno::RuntimeException();
87 uno::Reference
< embed::XStorage
>
88 StorageElementFactory::createStorage( const OUString
& rUri
,
89 StorageAccessMode eMode
)
90 throw ( embed::InvalidStorageException
,
91 lang::IllegalArgumentException
,
93 embed::StorageWrappedTargetException
,
94 uno::RuntimeException
)
96 osl::MutexGuard
aGuard( m_aMutex
);
98 if ( ( eMode
!= READ
) &&
99 ( eMode
!= READ_WRITE_NOCREATE
) &&
100 ( eMode
!= READ_WRITE_CREATE
) )
101 throw lang::IllegalArgumentException(
103 "Invalid open mode!" ),
104 uno::Reference
< uno::XInterface
>(),
110 throw lang::IllegalArgumentException(
112 "Root never has a storage!" ),
113 uno::Reference
< uno::XInterface
>(),
119 ? rUri
.copy( 0, rUri
.getLength() - 1 )
122 StorageMap::iterator
aIt ( m_aMap
.begin() );
123 StorageMap::iterator
aEnd( m_aMap
.end() );
125 while ( aIt
!= aEnd
)
127 if ( (*aIt
).first
.first
== aUriKey
)
129 // URI matches. Now, check open mode.
134 // No need to check; storage is at least readable.
138 case READ_WRITE_NOCREATE
:
139 case READ_WRITE_CREATE
:
140 // If found storage is writable, it can be used.
141 // If not, a new one must be created.
142 bMatch
= (*aIt
).first
.second
;
154 uno::Reference
< embed::XStorage
> xParentStorage
;
156 // documents never have a parent storage.
157 if ( !aUri
.isDocument() )
159 xParentStorage
= queryParentStorage( aUriKey
, eMode
);
161 if ( !xParentStorage
.is() )
163 // requested to create new storage, but failed?
164 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
165 "Unable to create parent storage!" );
166 return xParentStorage
;
170 uno::Reference
< embed::XStorage
> xStorage
171 = queryStorage( xParentStorage
, aUriKey
, eMode
);
173 if ( !xStorage
.is() )
175 // requested to create new storage, but failed?
176 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
177 "Unable to create storage!" );
181 bool bWritable
= ( ( eMode
== READ_WRITE_NOCREATE
)
182 || ( eMode
== READ_WRITE_CREATE
) );
184 std::unique_ptr
< Storage
> xElement(
185 new Storage( m_xContext
, this, aUriKey
, xParentStorage
, xStorage
) );
188 StorageMap::value_type(
189 std::pair
< OUString
, bool >( aUriKey
, bWritable
),
190 xElement
.get() ) ).first
;
192 aIt
->second
->m_aContainerIt
= aIt
;
196 else if ( osl_atomic_increment( &aIt
->second
->m_refCount
) > 1 )
198 rtl::Reference
< Storage
> xElement( aIt
->second
);
199 osl_atomic_decrement( &aIt
->second
->m_refCount
);
204 osl_atomic_decrement( &aIt
->second
->m_refCount
);
205 aIt
->second
->m_aContainerIt
= m_aMap
.end();
207 uno::Reference
< embed::XStorage
> xParentStorage
;
209 // documents never have a parent storage.
210 if ( !aUri
.isDocument() )
212 xParentStorage
= queryParentStorage( aUriKey
, eMode
);
214 if ( !xParentStorage
.is() )
216 // requested to create new storage, but failed?
217 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
218 "Unable to create parent storage!" );
219 return xParentStorage
;
223 uno::Reference
< embed::XStorage
> xStorage
224 = queryStorage( xParentStorage
, aUriKey
, eMode
);
226 if ( !xStorage
.is() )
228 // requested to create new storage, but failed?
229 OSL_ENSURE( eMode
!= READ_WRITE_CREATE
,
230 "Unable to create storage!" );
234 aIt
->second
= new Storage( m_xContext
, this, aUriKey
, xParentStorage
, xStorage
);
235 aIt
->second
->m_aContainerIt
= aIt
;
241 uno::Reference
< io::XInputStream
>
242 StorageElementFactory::createInputStream( const OUString
& rUri
,
243 const OUString
& rPassword
)
244 throw ( embed::InvalidStorageException
,
245 lang::IllegalArgumentException
,
247 embed::StorageWrappedTargetException
,
248 packages::WrongPasswordException
,
249 uno::RuntimeException
)
251 osl::MutexGuard
aGuard( m_aMutex
);
253 uno::Reference
< embed::XStorage
> xParentStorage
254 = queryParentStorage( rUri
, READ
);
256 // Each stream must have a parent storage.
257 if ( !xParentStorage
.is() )
258 return uno::Reference
< io::XInputStream
>();
260 uno::Reference
< io::XStream
> xStream
261 = queryStream( xParentStorage
, rUri
, rPassword
, READ
, false );
264 return uno::Reference
< io::XInputStream
>();
266 return xStream
->getInputStream();
270 uno::Reference
< io::XOutputStream
>
271 StorageElementFactory::createOutputStream( const OUString
& rUri
,
272 const OUString
& rPassword
,
274 throw ( embed::InvalidStorageException
,
275 lang::IllegalArgumentException
,
277 embed::StorageWrappedTargetException
,
278 packages::WrongPasswordException
,
279 uno::RuntimeException
)
281 osl::MutexGuard
aGuard( m_aMutex
);
283 uno::Reference
< embed::XStorage
> xParentStorage
284 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
286 // Each stream must have a parent storage.
287 if ( !xParentStorage
.is() )
289 OSL_FAIL( "StorageElementFactory::createOutputStream - "
290 "Unable to create parent storage!" );
291 return uno::Reference
< io::XOutputStream
>();
294 uno::Reference
< io::XStream
> xStream
296 xParentStorage
, rUri
, rPassword
, READ_WRITE_CREATE
, bTruncate
);
300 OSL_FAIL( "StorageElementFactory::createOutputStream - "
301 "Unable to create stream!" );
302 return uno::Reference
< io::XOutputStream
>();
305 // Note: We need a wrapper to hold a reference to the parent storage to
306 // ensure that nobody else owns it at the moment we want to commit
307 // our changes. (There can be only one writable instance at a time
308 // and even no writable instance if there is already another
309 // read-only instance!)
310 return uno::Reference
< io::XOutputStream
>(
311 new OutputStream( m_xContext
, rUri
, xParentStorage
, xStream
->getOutputStream() ) );
315 uno::Reference
< io::XStream
>
316 StorageElementFactory::createStream( const OUString
& rUri
,
317 const OUString
& rPassword
,
319 throw ( embed::InvalidStorageException
,
320 lang::IllegalArgumentException
,
322 embed::StorageWrappedTargetException
,
323 packages::WrongPasswordException
,
324 uno::RuntimeException
)
326 osl::MutexGuard
aGuard( m_aMutex
);
328 uno::Reference
< embed::XStorage
> xParentStorage
329 = queryParentStorage( rUri
, READ_WRITE_CREATE
);
331 // Each stream must have a parent storage.
332 if ( !xParentStorage
.is() )
334 OSL_FAIL( "StorageElementFactory::createStream - "
335 "Unable to create parent storage!" );
336 return uno::Reference
< io::XStream
>();
339 uno::Reference
< io::XStream
> xStream
341 xParentStorage
, rUri
, rPassword
, READ_WRITE_NOCREATE
, bTruncate
);
345 OSL_FAIL( "StorageElementFactory::createStream - "
346 "Unable to create stream!" );
347 return uno::Reference
< io::XStream
>();
350 return uno::Reference
< io::XStream
>(
351 new Stream( m_xContext
, rUri
, xParentStorage
, xStream
) );
355 void StorageElementFactory::releaseElement( Storage
* pElement
)
357 OSL_ASSERT( pElement
);
358 osl::MutexGuard
aGuard( m_aMutex
);
359 if ( pElement
->m_aContainerIt
!= m_aMap
.end() )
360 m_aMap
.erase( pElement
->m_aContainerIt
);
369 uno::Reference
< embed::XStorage
> StorageElementFactory::queryParentStorage(
370 const OUString
& rUri
, StorageAccessMode eMode
)
371 throw ( embed::InvalidStorageException
,
372 lang::IllegalArgumentException
,
374 embed::StorageWrappedTargetException
,
375 uno::RuntimeException
)
377 uno::Reference
< embed::XStorage
> xParentStorage
;
380 Uri
aParentUri( aUri
.getParentUri() );
381 if ( !aParentUri
.isRoot() )
383 xParentStorage
= createStorage( aUri
.getParentUri(), eMode
);
384 OSL_ENSURE( xParentStorage
.is()
385 // requested to create new storage, but failed?
386 || ( eMode
!= READ_WRITE_CREATE
),
387 "StorageElementFactory::queryParentStorage - No storage!" );
389 return xParentStorage
;
393 uno::Reference
< embed::XStorage
> StorageElementFactory::queryStorage(
394 const uno::Reference
< embed::XStorage
> & xParentStorage
,
395 const OUString
& rUri
,
396 StorageAccessMode eMode
)
397 throw ( embed::InvalidStorageException
,
398 lang::IllegalArgumentException
,
400 embed::StorageWrappedTargetException
,
401 uno::RuntimeException
)
403 uno::Reference
< embed::XStorage
> xStorage
;
407 if ( !xParentStorage
.is() )
411 xStorage
= m_xDocsMgr
->queryStorage( aUri
.getDocumentId() );
413 if ( !xStorage
.is() )
415 if ( eMode
== READ_WRITE_CREATE
)
416 throw lang::IllegalArgumentException(
418 "Invalid open mode: document storages cannot be "
420 uno::Reference
< uno::XInterface
>(),
423 throw embed::InvalidStorageException(
424 OUString( "Invalid document id!" ),
425 uno::Reference
< uno::XInterface
>() );
428 // match xStorage's open mode against requested open mode
430 uno::Reference
< beans::XPropertySet
> xPropSet(
431 xStorage
, uno::UNO_QUERY
);
432 OSL_ENSURE( xPropSet
.is(),
433 "StorageElementFactory::queryStorage - "
434 "No XPropertySet interface!" );
437 uno::Any aPropValue
= xPropSet
->getPropertyValue(
438 OUString( "OpenMode" ) );
440 sal_Int32 nOpenMode
= 0;
441 if ( aPropValue
>>= nOpenMode
)
446 if ( !( nOpenMode
& embed::ElementModes::READ
) )
448 // document opened, but not readable.
449 throw embed::InvalidStorageException(
450 "Storage is open, but not readable!" );
455 case READ_WRITE_NOCREATE
:
456 case READ_WRITE_CREATE
:
457 if ( !( nOpenMode
& embed::ElementModes::WRITE
) )
459 // document opened, but not writable.
460 throw embed::InvalidStorageException(
461 "Storage is open, but not writable!" );
470 "Bug! Value of property OpenMode has wrong type!" );
472 throw uno::RuntimeException(
473 "Bug! Value of property OpenMode has wrong type!" );
476 catch ( beans::UnknownPropertyException
const & e
)
478 OSL_FAIL( "Property OpenMode not supported!" );
480 throw embed::StorageWrappedTargetException(
482 "Bug! Value of property OpenMode has wrong type!" ),
483 uno::Reference
< uno::XInterface
>(),
486 catch ( lang::WrappedTargetException
const & e
)
488 OSL_FAIL( "Caught WrappedTargetException!" );
490 throw embed::StorageWrappedTargetException(
492 "WrappedTargetException during getPropertyValue!" ),
493 uno::Reference
< uno::XInterface
>(),
501 const OUString
& rName
= aUri
.getDecodedName();
507 sal_Int32 nOpenMode
= embed::ElementModes::READ
508 | embed::ElementModes::NOCREATE
;
510 = xParentStorage
->openStorageElement( rName
, nOpenMode
);
512 catch ( io::IOException
const & )
514 // Another chance: Try to clone storage.
515 xStorage
= createTemporaryStorage();
516 xParentStorage
->copyStorageElementLastCommitTo( rName
,
522 sal_Int32 nOpenMode
= embed::ElementModes::READWRITE
;
523 if ( eMode
== READ_WRITE_NOCREATE
)
524 nOpenMode
|= embed::ElementModes::NOCREATE
;
526 xStorage
= xParentStorage
->openStorageElement( rName
, nOpenMode
);
530 OSL_ENSURE( xStorage
.is() || ( eMode
!= READ_WRITE_CREATE
),
531 "StorageElementFactory::queryStorage - No storage!" );
536 uno::Reference
< io::XStream
>
537 StorageElementFactory::queryStream(
538 const uno::Reference
< embed::XStorage
> & xParentStorage
,
539 const OUString
& rUri
,
540 const OUString
& rPassword
,
541 StorageAccessMode eMode
,
543 throw ( embed::InvalidStorageException
,
544 lang::IllegalArgumentException
,
546 embed::StorageWrappedTargetException
,
547 packages::WrongPasswordException
,
548 uno::RuntimeException
)
550 osl::MutexGuard
aGuard( m_aMutex
);
552 if ( !xParentStorage
.is() )
554 throw lang::IllegalArgumentException(
556 "No parent storage!" ),
557 uno::Reference
< uno::XInterface
>(),
564 throw lang::IllegalArgumentException(
566 "Root never is a stream!" ),
567 uno::Reference
< uno::XInterface
>(),
570 else if ( aUri
.isDocument() )
572 throw lang::IllegalArgumentException(
574 "A document never is a stream!" ),
575 uno::Reference
< uno::XInterface
>(),
583 nOpenMode
= embed::ElementModes::READ
584 | embed::ElementModes::NOCREATE
585 | embed::ElementModes::SEEKABLE
;
588 case READ_WRITE_NOCREATE
:
589 nOpenMode
= embed::ElementModes::READWRITE
590 | embed::ElementModes::NOCREATE
591 | embed::ElementModes::SEEKABLE
;
594 nOpenMode
|= embed::ElementModes::TRUNCATE
;
598 case READ_WRITE_CREATE
:
599 nOpenMode
= embed::ElementModes::READWRITE
600 | embed::ElementModes::SEEKABLE
;
603 nOpenMode
|= embed::ElementModes::TRUNCATE
;
608 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
610 throw embed::InvalidStorageException(
612 "Unknown open mode!" ),
613 uno::Reference
< uno::XInterface
>() );
616 // No object re-usage mechanism; streams are seekable => not stateless.
618 uno::Reference
< io::XStream
> xStream
;
619 if ( !rPassword
.isEmpty() )
625 xStream
= xParentStorage
->cloneEncryptedStreamElement(
626 aUri
.getDecodedName(),
629 catch ( packages::NoEncryptionException
const & )
632 = xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
639 xStream
= xParentStorage
->openEncryptedStreamElement(
640 aUri
.getDecodedName(),
644 catch ( packages::NoEncryptionException
const & )
647 = xParentStorage
->openStreamElement( aUri
.getDecodedName(),
656 xStream
= xParentStorage
->cloneStreamElement( aUri
.getDecodedName() );
660 xStream
= xParentStorage
->openStreamElement( aUri
.getDecodedName(),
667 throw embed::InvalidStorageException(
670 uno::Reference
< uno::XInterface
>() );
676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */