Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_storage.cxx
blob014065416cb51d9823c281e945ca5a87b353415f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 );
73 if ( !xStorage.is() )
74 throw uno::RuntimeException();
76 return xStorage;
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(
90 "Invalid open mode!",
91 uno::Reference< uno::XInterface >(),
92 sal_Int16( 2 ) );
94 Uri aUri( rUri );
95 if ( aUri.isRoot() )
97 throw lang::IllegalArgumentException(
98 "Root never has a storage!",
99 uno::Reference< uno::XInterface >(),
100 sal_Int16( 1 ) );
103 OUString aUriKey
104 ( rUri.endsWith("/")
105 ? rUri.copy( 0, rUri.getLength() - 1 )
106 : rUri );
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.
116 bool bMatch = true;
117 switch ( eMode )
119 case READ:
120 // No need to check; storage is at least readable.
121 bMatch = true;
122 break;
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;
129 break;
132 if ( bMatch )
133 break;
135 ++aIt;
138 if ( aIt == aEnd )
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!" );
164 return xStorage;
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;
178 return aIt->second;
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 );
184 return aIt->second;
186 else
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!" );
215 return xStorage;
218 aIt->second = new Storage( m_xContext, this, aUriKey, xParentStorage, xStorage );
219 aIt->second->m_aContainerIt = aIt;
220 return aIt->second;
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 );
241 if ( !xStream.is() )
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,
251 bool bTruncate )
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
267 = queryStream(
268 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate );
270 if ( !xStream.is() )
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,
290 bool bTruncate )
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
306 = queryStream(
307 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate );
309 if ( !xStream.is() )
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 );
330 // Non-UNO interface
333 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage(
334 const OUString & rUri, StorageAccessMode eMode )
336 uno::Reference< embed::XStorage > xParentStorage;
338 Uri aUri( rUri );
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;
359 Uri aUri( rUri );
361 if ( !xParentStorage.is() )
363 // document storage
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 >(),
373 sal_Int16( 2 ) );
374 else
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 )
394 switch ( eMode )
396 case READ:
397 if ( !( nOpenMode & embed::ElementModes::READ ) )
399 // document opened, but not readable.
400 throw embed::InvalidStorageException(
401 "Storage is open, but not readable!" );
403 // storage okay
404 break;
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!" );
414 // storage okay
415 break;
418 else
420 OSL_FAIL(
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 >(),
435 anyEx );
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 >(),
445 anyEx );
448 else
450 // sub storage
452 const OUString & rName = aUri.getDecodedName();
454 if ( eMode == READ )
458 sal_Int32 const nOpenMode = embed::ElementModes::READ
459 | embed::ElementModes::NOCREATE;
460 xStorage
461 = xParentStorage->openStorageElement( rName, nOpenMode );
463 catch ( io::IOException const & )
465 // Another chance: Try to clone storage.
466 xStorage = createTemporaryStorage();
467 xParentStorage->copyStorageElementLastCommitTo( rName,
468 xStorage );
471 else
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!" );
483 return xStorage;
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,
493 bool bTruncate )
495 osl::MutexGuard aGuard( m_aMutex );
497 if ( !xParentStorage.is() )
499 throw lang::IllegalArgumentException(
500 "No parent storage!",
501 uno::Reference< uno::XInterface >(),
502 sal_Int16( 2 ) );
505 Uri aUri( rUri );
506 if ( aUri.isRoot() )
508 throw lang::IllegalArgumentException(
509 "Root never is a stream!",
510 uno::Reference< uno::XInterface >(),
511 sal_Int16( 2 ) );
513 else if ( aUri.isDocument() )
515 throw lang::IllegalArgumentException(
516 "A document never is a stream!",
517 uno::Reference< uno::XInterface >(),
518 sal_Int16( 2 ) );
521 sal_Int32 nOpenMode;
522 switch ( eMode )
524 case READ:
525 nOpenMode = embed::ElementModes::READ
526 | embed::ElementModes::NOCREATE
527 | embed::ElementModes::SEEKABLE;
528 break;
530 case READ_WRITE_NOCREATE:
531 nOpenMode = embed::ElementModes::READWRITE
532 | embed::ElementModes::NOCREATE
533 | embed::ElementModes::SEEKABLE;
535 if ( bTruncate )
536 nOpenMode |= embed::ElementModes::TRUNCATE;
538 break;
540 case READ_WRITE_CREATE:
541 nOpenMode = embed::ElementModes::READWRITE
542 | embed::ElementModes::SEEKABLE;
544 if ( bTruncate )
545 nOpenMode |= embed::ElementModes::TRUNCATE;
547 break;
549 default:
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() )
562 if ( eMode == READ )
566 xStream = xParentStorage->cloneEncryptedStreamElement(
567 aUri.getDecodedName(),
568 rPassword );
570 catch ( packages::NoEncryptionException const & )
572 xStream
573 = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
576 else
580 xStream = xParentStorage->openEncryptedStreamElement(
581 aUri.getDecodedName(),
582 nOpenMode,
583 rPassword );
585 catch ( packages::NoEncryptionException const & )
587 xStream
588 = xParentStorage->openStreamElement( aUri.getDecodedName(),
589 nOpenMode );
593 else
595 if ( eMode == READ )
597 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
599 else
601 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
602 nOpenMode );
606 if ( !xStream.is() )
608 throw embed::InvalidStorageException(
609 "No stream!",
610 uno::Reference< uno::XInterface >() );
613 return xStream;
616 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */