fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_storage.cxx
blob31168a08d5045f8e59fd7b5be8239c759457a1c4
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 <memory>
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(),
78 uno::UNO_QUERY );
80 if ( !xStorage.is() )
81 throw uno::RuntimeException();
83 return xStorage;
87 uno::Reference< embed::XStorage >
88 StorageElementFactory::createStorage( const OUString & rUri,
89 StorageAccessMode eMode )
90 throw ( embed::InvalidStorageException,
91 lang::IllegalArgumentException,
92 io::IOException,
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(
102 OUString(
103 "Invalid open mode!" ),
104 uno::Reference< uno::XInterface >(),
105 sal_Int16( 2 ) );
107 Uri aUri( rUri );
108 if ( aUri.isRoot() )
110 throw lang::IllegalArgumentException(
111 OUString(
112 "Root never has a storage!" ),
113 uno::Reference< uno::XInterface >(),
114 sal_Int16( 1 ) );
117 OUString aUriKey
118 ( rUri.endsWith("/")
119 ? rUri.copy( 0, rUri.getLength() - 1 )
120 : rUri );
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.
130 bool bMatch = true;
131 switch ( eMode )
133 case READ:
134 // No need to check; storage is at least readable.
135 bMatch = true;
136 break;
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;
143 break;
146 if ( bMatch )
147 break;
149 ++aIt;
152 if ( aIt == aEnd )
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!" );
178 return xStorage;
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 ) );
187 aIt = m_aMap.insert(
188 StorageMap::value_type(
189 std::pair< OUString, bool >( aUriKey, bWritable ),
190 xElement.get() ) ).first;
192 aIt->second->m_aContainerIt = aIt;
193 xElement.release();
194 return aIt->second;
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 );
200 return aIt->second;
202 else
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!" );
231 return xStorage;
234 aIt->second = new Storage( m_xContext, this, aUriKey, xParentStorage, xStorage );
235 aIt->second->m_aContainerIt = aIt;
236 return aIt->second;
241 uno::Reference< io::XInputStream >
242 StorageElementFactory::createInputStream( const OUString & rUri,
243 const OUString & rPassword )
244 throw ( embed::InvalidStorageException,
245 lang::IllegalArgumentException,
246 io::IOException,
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 );
263 if ( !xStream.is() )
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,
273 bool bTruncate )
274 throw ( embed::InvalidStorageException,
275 lang::IllegalArgumentException,
276 io::IOException,
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
295 = queryStream(
296 xParentStorage, rUri, rPassword, READ_WRITE_CREATE, bTruncate );
298 if ( !xStream.is() )
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,
318 bool bTruncate )
319 throw ( embed::InvalidStorageException,
320 lang::IllegalArgumentException,
321 io::IOException,
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
340 = queryStream(
341 xParentStorage, rUri, rPassword, READ_WRITE_NOCREATE, bTruncate );
343 if ( !xStream.is() )
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 );
365 // Non-UNO interface
369 uno::Reference< embed::XStorage > StorageElementFactory::queryParentStorage(
370 const OUString & rUri, StorageAccessMode eMode )
371 throw ( embed::InvalidStorageException,
372 lang::IllegalArgumentException,
373 io::IOException,
374 embed::StorageWrappedTargetException,
375 uno::RuntimeException )
377 uno::Reference< embed::XStorage > xParentStorage;
379 Uri aUri( rUri );
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,
399 io::IOException,
400 embed::StorageWrappedTargetException,
401 uno::RuntimeException )
403 uno::Reference< embed::XStorage > xStorage;
405 Uri aUri( rUri );
407 if ( !xParentStorage.is() )
409 // document storage
411 xStorage = m_xDocsMgr->queryStorage( aUri.getDocumentId() );
413 if ( !xStorage.is() )
415 if ( eMode == READ_WRITE_CREATE )
416 throw lang::IllegalArgumentException(
417 OUString(
418 "Invalid open mode: document storages cannot be "
419 "created!" ),
420 uno::Reference< uno::XInterface >(),
421 sal_Int16( 2 ) );
422 else
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 )
443 switch ( eMode )
445 case READ:
446 if ( !( nOpenMode & embed::ElementModes::READ ) )
448 // document opened, but not readable.
449 throw embed::InvalidStorageException(
450 "Storage is open, but not readable!" );
452 // storage okay
453 break;
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!" );
463 // storage okay
464 break;
467 else
469 OSL_FAIL(
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(
481 OUString(
482 "Bug! Value of property OpenMode has wrong type!" ),
483 uno::Reference< uno::XInterface >(),
484 uno::makeAny( e ) );
486 catch ( lang::WrappedTargetException const & e )
488 OSL_FAIL( "Caught WrappedTargetException!" );
490 throw embed::StorageWrappedTargetException(
491 OUString(
492 "WrappedTargetException during getPropertyValue!" ),
493 uno::Reference< uno::XInterface >(),
494 uno::makeAny( e ) );
497 else
499 // sub storage
501 const OUString & rName = aUri.getDecodedName();
503 if ( eMode == READ )
507 sal_Int32 nOpenMode = embed::ElementModes::READ
508 | embed::ElementModes::NOCREATE;
509 xStorage
510 = xParentStorage->openStorageElement( rName, nOpenMode );
512 catch ( io::IOException const & )
514 // Another chance: Try to clone storage.
515 xStorage = createTemporaryStorage();
516 xParentStorage->copyStorageElementLastCommitTo( rName,
517 xStorage );
520 else
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!" );
532 return xStorage;
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,
542 bool bTruncate )
543 throw ( embed::InvalidStorageException,
544 lang::IllegalArgumentException,
545 io::IOException,
546 embed::StorageWrappedTargetException,
547 packages::WrongPasswordException,
548 uno::RuntimeException )
550 osl::MutexGuard aGuard( m_aMutex );
552 if ( !xParentStorage.is() )
554 throw lang::IllegalArgumentException(
555 OUString(
556 "No parent storage!" ),
557 uno::Reference< uno::XInterface >(),
558 sal_Int16( 2 ) );
561 Uri aUri( rUri );
562 if ( aUri.isRoot() )
564 throw lang::IllegalArgumentException(
565 OUString(
566 "Root never is a stream!" ),
567 uno::Reference< uno::XInterface >(),
568 sal_Int16( 2 ) );
570 else if ( aUri.isDocument() )
572 throw lang::IllegalArgumentException(
573 OUString(
574 "A document never is a stream!" ),
575 uno::Reference< uno::XInterface >(),
576 sal_Int16( 2 ) );
579 sal_Int32 nOpenMode;
580 switch ( eMode )
582 case READ:
583 nOpenMode = embed::ElementModes::READ
584 | embed::ElementModes::NOCREATE
585 | embed::ElementModes::SEEKABLE;
586 break;
588 case READ_WRITE_NOCREATE:
589 nOpenMode = embed::ElementModes::READWRITE
590 | embed::ElementModes::NOCREATE
591 | embed::ElementModes::SEEKABLE;
593 if ( bTruncate )
594 nOpenMode |= embed::ElementModes::TRUNCATE;
596 break;
598 case READ_WRITE_CREATE:
599 nOpenMode = embed::ElementModes::READWRITE
600 | embed::ElementModes::SEEKABLE;
602 if ( bTruncate )
603 nOpenMode |= embed::ElementModes::TRUNCATE;
605 break;
607 default:
608 OSL_FAIL( "StorageElementFactory::queryStream : Unknown open mode!" );
610 throw embed::InvalidStorageException(
611 OUString(
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() )
621 if ( eMode == READ )
625 xStream = xParentStorage->cloneEncryptedStreamElement(
626 aUri.getDecodedName(),
627 rPassword );
629 catch ( packages::NoEncryptionException const & )
631 xStream
632 = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
635 else
639 xStream = xParentStorage->openEncryptedStreamElement(
640 aUri.getDecodedName(),
641 nOpenMode,
642 rPassword );
644 catch ( packages::NoEncryptionException const & )
646 xStream
647 = xParentStorage->openStreamElement( aUri.getDecodedName(),
648 nOpenMode );
652 else
654 if ( eMode == READ )
656 xStream = xParentStorage->cloneStreamElement( aUri.getDecodedName() );
658 else
660 xStream = xParentStorage->openStreamElement( aUri.getDecodedName(),
661 nOpenMode );
665 if ( !xStream.is() )
667 throw embed::InvalidStorageException(
668 OUString(
669 "No stream!" ),
670 uno::Reference< uno::XInterface >() );
673 return xStream;
676 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */