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/lang/DisposedException.hpp>
21 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
22 #include <com/sun/star/io/XStream.hpp>
23 #include <com/sun/star/io/XInputStream.hpp>
24 #include <com/sun/star/io/XSeekable.hpp>
25 #include <com/sun/star/io/XTruncate.hpp>
26 #include <com/sun/star/io/TempFile.hpp>
28 #include <comphelper/processfactory.hxx>
29 #include <comphelper/storagehelper.hxx>
31 #include <unotools/ucbstreamhelper.hxx>
33 #include <cppuhelper/exc_hlp.hxx>
34 #include <cppuhelper/supportsservice.hxx>
36 #include <sot/storinfo.hxx>
38 #include "xolesimplestorage.hxx"
41 using namespace ::com::sun::star
;
43 const sal_Int32 nBytesCount
= 32000;
47 OLESimpleStorage::OLESimpleStorage( uno::Reference
< lang::XMultiServiceFactory
> xFactory
)
48 : m_bDisposed( false )
51 , m_pListenersContainer( NULL
)
52 , m_xFactory( xFactory
)
53 , m_bNoTemporaryCopy( false )
55 OSL_ENSURE( m_xFactory
.is(), "No factory is provided on creation!\n" );
56 if ( !m_xFactory
.is() )
57 throw uno::RuntimeException();
61 OLESimpleStorage::~OLESimpleStorage()
66 } catch( uno::Exception
& )
69 if ( m_pListenersContainer
)
71 delete m_pListenersContainer
;
72 m_pListenersContainer
= NULL
;
77 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::impl_staticGetSupportedServiceNames()
79 uno::Sequence
< OUString
> aRet(1);
80 aRet
[0] = "com.sun.star.embed.OLESimpleStorage";
85 OUString SAL_CALL
OLESimpleStorage::impl_staticGetImplementationName()
87 return OUString("com.sun.star.comp.embed.OLESimpleStorage");
91 uno::Reference
< uno::XInterface
> SAL_CALL
OLESimpleStorage::impl_staticCreateSelfInstance(
92 const uno::Reference
< lang::XMultiServiceFactory
>& xServiceManager
)
94 return uno::Reference
< uno::XInterface
>( *new OLESimpleStorage( xServiceManager
) );
98 void OLESimpleStorage::UpdateOriginal_Impl()
100 if ( !m_bNoTemporaryCopy
)
102 uno::Reference
< io::XSeekable
> xSeek( m_xStream
, uno::UNO_QUERY_THROW
);
105 uno::Reference
< io::XSeekable
> xTempSeek( m_xTempStream
, uno::UNO_QUERY_THROW
);
106 sal_Int64 nPos
= xTempSeek
->getPosition();
107 xTempSeek
->seek( 0 );
109 uno::Reference
< io::XInputStream
> xTempInp
= m_xTempStream
->getInputStream();
110 uno::Reference
< io::XOutputStream
> xOutputStream
= m_xStream
->getOutputStream();
111 if ( !xTempInp
.is() || !xOutputStream
.is() )
112 throw uno::RuntimeException();
114 uno::Reference
< io::XTruncate
> xTrunc( xOutputStream
, uno::UNO_QUERY_THROW
);
117 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInp
, xOutputStream
);
118 xOutputStream
->flush();
119 xTempSeek
->seek( nPos
);
124 void OLESimpleStorage::InsertInputStreamToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< io::XInputStream
>& xInputStream
)
125 throw ( uno::Exception
)
127 if ( !pStorage
|| aName
.isEmpty() || !xInputStream
.is() )
128 throw uno::RuntimeException();
130 if ( pStorage
->IsContained( aName
) )
131 throw container::ElementExistException(); // TODO:
133 BaseStorageStream
* pNewStream
= pStorage
->OpenStream( aName
);
134 if ( !pNewStream
|| pNewStream
->GetError() || pStorage
->GetError() )
137 DELETEZ( pNewStream
);
138 pStorage
->ResetError();
139 throw io::IOException(); // TODO
144 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
148 nRead
= xInputStream
->readBytes( aData
, nBytesCount
);
149 if ( nRead
< nBytesCount
)
150 aData
.realloc( nRead
);
152 sal_Int32 nWritten
= pNewStream
->Write( aData
.getArray(), nRead
);
153 if ( nWritten
< nRead
)
154 throw io::IOException();
155 } while( nRead
== nBytesCount
);
157 catch( uno::Exception
& )
159 DELETEZ( pNewStream
);
160 pStorage
->Remove( aName
);
165 DELETEZ( pNewStream
);
169 void OLESimpleStorage::InsertNameAccessToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< container::XNameAccess
>& xNameAccess
)
170 throw ( uno::Exception
)
172 if ( !pStorage
|| aName
.isEmpty() || !xNameAccess
.is() )
173 throw uno::RuntimeException();
175 if ( pStorage
->IsContained( aName
) )
176 throw container::ElementExistException(); // TODO:
178 BaseStorage
* pNewStorage
= pStorage
->OpenStorage( aName
);
179 if ( !pNewStorage
|| pNewStorage
->GetError() || pStorage
->GetError() )
182 DELETEZ( pNewStorage
);
183 pStorage
->ResetError();
184 throw io::IOException(); // TODO
189 uno::Sequence
< OUString
> aElements
= xNameAccess
->getElementNames();
190 for ( sal_Int32 nInd
= 0; nInd
< aElements
.getLength(); nInd
++ )
192 uno::Reference
< io::XInputStream
> xInputStream
;
193 uno::Reference
< container::XNameAccess
> xSubNameAccess
;
194 uno::Any aAny
= xNameAccess
->getByName( aElements
[nInd
] );
195 if ( aAny
>>= xInputStream
)
196 InsertInputStreamToStorage_Impl( pNewStorage
, aElements
[nInd
], xInputStream
);
197 else if ( aAny
>>= xSubNameAccess
)
198 InsertNameAccessToStorage_Impl( pNewStorage
, aElements
[nInd
], xSubNameAccess
);
201 catch( uno::Exception
& )
203 DELETEZ( pNewStorage
);
204 pStorage
->Remove( aName
);
209 DELETEZ( pNewStorage
);
216 void SAL_CALL
OLESimpleStorage::initialize( const uno::Sequence
< uno::Any
>& aArguments
)
217 throw ( uno::Exception
,
218 uno::RuntimeException
, std::exception
)
220 if ( m_pStream
|| m_pStorage
)
221 throw io::IOException(); // TODO: already initilized
223 sal_Int32 nArgNum
= aArguments
.getLength();
224 OSL_ENSURE( nArgNum
>= 1 && nArgNum
<= 2, "Wrong parameter number" );
226 if ( nArgNum
< 1 || nArgNum
> 2 )
227 throw lang::IllegalArgumentException(); // TODO:
229 uno::Reference
< io::XStream
> xStream
;
230 uno::Reference
< io::XInputStream
> xInputStream
;
231 if ( !( aArguments
[0] >>= xStream
) && !( aArguments
[0] >>= xInputStream
) )
232 throw lang::IllegalArgumentException(); // TODO:
236 if ( !( aArguments
[1] >>= m_bNoTemporaryCopy
) )
237 throw lang::IllegalArgumentException(); // TODO:
240 if ( m_bNoTemporaryCopy
)
243 // If the temporary stream is not created, the original stream must be wrapped
244 // since SvStream wrapper closes the stream is owns
245 if ( xInputStream
.is() )
247 // the stream must be seekable for direct access
248 uno::Reference
< io::XSeekable
> xSeek( xInputStream
, uno::UNO_QUERY_THROW
);
249 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xInputStream
, false );
251 else if ( xStream
.is() )
253 // the stream must be seekable for direct access
254 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
255 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xStream
, false );
258 throw lang::IllegalArgumentException(); // TODO:
262 uno::Reference
< io::XStream
> xTempFile(
263 io::TempFile::create(comphelper::getComponentContext(m_xFactory
)),
264 uno::UNO_QUERY_THROW
);
265 uno::Reference
< io::XSeekable
> xTempSeek( xTempFile
, uno::UNO_QUERY_THROW
);
266 uno::Reference
< io::XOutputStream
> xTempOut
= xTempFile
->getOutputStream();
267 if ( !xTempOut
.is() )
268 throw uno::RuntimeException();
270 if ( xInputStream
.is() )
274 uno::Reference
< io::XSeekable
> xSeek( xInputStream
, uno::UNO_QUERY_THROW
);
277 catch( uno::Exception
& )
280 ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream
, xTempOut
);
281 xTempOut
->closeOutput();
282 xTempSeek
->seek( 0 );
283 uno::Reference
< io::XInputStream
> xTempInput
= xTempFile
->getInputStream();
284 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempInput
, false );
286 else if ( xStream
.is() )
288 // not sure that the storage flashes the stream on commit
290 m_xTempStream
= xTempFile
;
292 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
294 uno::Reference
< io::XInputStream
> xInpStream
= xStream
->getInputStream();
295 if ( !xInpStream
.is() || !xStream
->getOutputStream().is() )
296 throw uno::RuntimeException();
298 ::comphelper::OStorageHelper::CopyInputToOutput( xInpStream
, xTempOut
);
300 xTempSeek
->seek( 0 );
302 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false );
305 throw lang::IllegalArgumentException(); // TODO:
308 if ( !m_pStream
|| m_pStream
->GetError() )
309 throw io::IOException(); // TODO
311 m_pStorage
= new Storage( *m_pStream
, false );
320 void SAL_CALL
OLESimpleStorage::insertByName( const OUString
& aName
, const uno::Any
& aElement
)
321 throw ( lang::IllegalArgumentException
,
322 container::ElementExistException
,
323 lang::WrappedTargetException
,
324 uno::RuntimeException
, std::exception
)
326 ::osl::MutexGuard
aGuard( m_aMutex
);
329 throw lang::DisposedException();
332 throw uno::RuntimeException();
334 uno::Reference
< io::XStream
> xStream
;
335 uno::Reference
< io::XInputStream
> xInputStream
;
336 uno::Reference
< container::XNameAccess
> xNameAccess
;
340 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
341 throw io::IOException(); // TODO
343 if ( aElement
>>= xStream
)
344 xInputStream
= xStream
->getInputStream();
345 else if ( !( aElement
>>= xInputStream
) && !( aElement
>>= xNameAccess
) )
346 throw lang::IllegalArgumentException(); // TODO:
348 if ( xInputStream
.is() )
349 InsertInputStreamToStorage_Impl( m_pStorage
, aName
, xInputStream
);
350 else if ( xNameAccess
.is() )
351 InsertNameAccessToStorage_Impl( m_pStorage
, aName
, xNameAccess
);
353 throw uno::RuntimeException();
355 catch( uno::RuntimeException
& )
359 catch( container::ElementExistException
& )
363 catch( const uno::Exception
& e
)
365 throw lang::WrappedTargetException("Insert has failed!",
366 uno::Reference
< uno::XInterface
>(),
372 void SAL_CALL
OLESimpleStorage::removeByName( const OUString
& aName
)
373 throw ( container::NoSuchElementException
,
374 lang::WrappedTargetException
,
375 uno::RuntimeException
, std::exception
)
377 ::osl::MutexGuard
aGuard( m_aMutex
);
380 throw lang::DisposedException();
383 throw uno::RuntimeException();
385 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
386 throw lang::WrappedTargetException(); // io::IOException(); // TODO
388 if ( !m_pStorage
->IsContained( aName
) )
389 throw container::NoSuchElementException(); // TODO:
391 m_pStorage
->Remove( aName
);
393 if ( m_pStorage
->GetError() )
395 m_pStorage
->ResetError();
396 throw lang::WrappedTargetException(); // io::IOException(); // TODO
401 void SAL_CALL
OLESimpleStorage::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
402 throw ( lang::IllegalArgumentException
,
403 container::NoSuchElementException
,
404 lang::WrappedTargetException
,
405 uno::RuntimeException
, std::exception
)
407 ::osl::MutexGuard
aGuard( m_aMutex
);
410 throw lang::DisposedException();
412 removeByName( aName
);
416 insertByName( aName
, aElement
);
418 catch( container::ElementExistException
& )
420 uno::Any
aCaught( ::cppu::getCaughtException() );
422 throw lang::WrappedTargetException("Can't copy raw stream",
423 uno::Reference
< uno::XInterface
>(),
429 uno::Any SAL_CALL
OLESimpleStorage::getByName( const OUString
& aName
)
430 throw ( container::NoSuchElementException
,
431 lang::WrappedTargetException
,
432 uno::RuntimeException
, std::exception
)
434 ::osl::MutexGuard
aGuard( m_aMutex
);
437 throw lang::DisposedException();
440 throw uno::RuntimeException();
442 if ( !m_pStorage
->IsContained( aName
) )
443 throw container::NoSuchElementException(); // TODO:
447 uno::Reference
< io::XStream
> xTempFile(
448 io::TempFile::create(comphelper::getComponentContext(m_xFactory
)),
450 uno::Reference
< io::XSeekable
> xSeekable( xTempFile
, uno::UNO_QUERY_THROW
);
451 uno::Reference
< io::XOutputStream
> xOutputStream
= xTempFile
->getOutputStream();
452 uno::Reference
< io::XInputStream
> xInputStream
= xTempFile
->getInputStream();
453 if ( !xOutputStream
.is() || !xInputStream
.is() )
454 throw uno::RuntimeException();
456 if ( m_pStorage
->IsStorage( aName
) )
458 BaseStorage
* pStrg
= m_pStorage
->OpenStorage( aName
);
459 m_pStorage
->ResetError();
461 throw lang::WrappedTargetException(); // io::IOException(); // TODO
463 SvStream
* pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false ); // do not close the original stream
465 throw uno::RuntimeException();
467 BaseStorage
* pNewStor
= new Storage( *pStream
, false );
468 bool bSuccess
= ( pStrg
->CopyTo( pNewStor
) && pNewStor
->Commit() &&
469 !pNewStor
->GetError() && !pStrg
->GetError() );
476 throw uno::RuntimeException();
478 uno::Sequence
< uno::Any
> aArgs( 2 );
479 aArgs
[0] <<= xInputStream
; // allow readonly access only
480 aArgs
[1] <<= true; // do not create copy
482 uno::Reference
< container::XNameContainer
> xResultNameContainer(
483 m_xFactory
->createInstanceWithArguments(
484 OUString("com.sun.star.embed.OLESimpleStorage"),
486 uno::UNO_QUERY_THROW
);
488 aResult
<<= xResultNameContainer
;
492 BaseStorageStream
* pStream
= m_pStorage
->OpenStream( aName
, StreamMode::READ
| StreamMode::SHARE_DENYALL
| StreamMode::NOCREATE
);
495 if ( !pStream
|| pStream
->GetError() || m_pStorage
->GetError() )
497 m_pStorage
->ResetError();
499 throw io::IOException(); // TODO
502 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
503 sal_Int32 nSize
= nBytesCount
;
505 while( 0 != ( nRead
= pStream
->Read( aData
.getArray(), nSize
) ) )
510 aData
.realloc( nSize
);
513 xOutputStream
->writeBytes( aData
);
516 if ( pStream
->GetError() )
517 throw io::IOException(); // TODO
519 xOutputStream
->closeOutput();
520 xSeekable
->seek( 0 );
522 catch (const uno::RuntimeException
&)
527 catch (const uno::Exception
&)
530 throw lang::WrappedTargetException(); // TODO:
535 aResult
<<= xInputStream
;
542 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getElementNames()
543 throw ( uno::RuntimeException
, std::exception
)
545 ::osl::MutexGuard
aGuard( m_aMutex
);
548 throw lang::DisposedException();
551 throw uno::RuntimeException();
553 SvStorageInfoList aList
;
554 m_pStorage
->FillInfoList( &aList
);
556 if ( m_pStorage
->GetError() )
558 m_pStorage
->ResetError();
559 throw uno::RuntimeException(); // TODO:
562 uno::Sequence
< OUString
> aSeq( aList
.size() );
563 for ( sal_uInt32 nInd
= 0; nInd
< aList
.size(); nInd
++ )
564 aSeq
[nInd
] = aList
[nInd
].GetName();
570 sal_Bool SAL_CALL
OLESimpleStorage::hasByName( const OUString
& aName
)
571 throw ( uno::RuntimeException
, std::exception
)
573 ::osl::MutexGuard
aGuard( m_aMutex
);
576 throw lang::DisposedException();
579 throw uno::RuntimeException();
581 bool bResult
= m_pStorage
->IsContained( aName
);
583 if ( m_pStorage
->GetError() )
585 m_pStorage
->ResetError();
586 throw uno::RuntimeException(); // TODO:
589 return bResult
? sal_True
: sal_False
;
593 uno::Type SAL_CALL
OLESimpleStorage::getElementType()
594 throw ( uno::RuntimeException
, std::exception
)
596 ::osl::MutexGuard
aGuard( m_aMutex
);
599 throw lang::DisposedException();
601 return cppu::UnoType
<io::XInputStream
>::get();
605 sal_Bool SAL_CALL
OLESimpleStorage::hasElements()
606 throw ( uno::RuntimeException
, std::exception
)
608 ::osl::MutexGuard
aGuard( m_aMutex
);
611 throw lang::DisposedException();
614 throw uno::RuntimeException();
616 SvStorageInfoList aList
;
617 m_pStorage
->FillInfoList( &aList
);
619 if ( m_pStorage
->GetError() )
621 m_pStorage
->ResetError();
622 throw uno::RuntimeException(); // TODO:
625 return aList
.size() != 0 ? sal_True
: sal_False
;
633 void SAL_CALL
OLESimpleStorage::dispose()
634 throw ( uno::RuntimeException
, std::exception
)
636 ::osl::MutexGuard
aGuard( m_aMutex
);
639 throw lang::DisposedException();
641 if ( m_pListenersContainer
)
643 lang::EventObject
aSource( static_cast< ::cppu::OWeakObject
* >(this) );
644 m_pListenersContainer
->disposeAndClear( aSource
);
647 DELETEZ( m_pStorage
);
648 DELETEZ( m_pStream
);
650 m_xStream
= uno::Reference
< io::XStream
>();
651 m_xTempStream
= uno::Reference
< io::XStream
>();
657 void SAL_CALL
OLESimpleStorage::addEventListener(
658 const uno::Reference
< lang::XEventListener
>& xListener
)
659 throw ( uno::RuntimeException
, std::exception
)
661 ::osl::MutexGuard
aGuard( m_aMutex
);
664 throw lang::DisposedException();
666 if ( !m_pListenersContainer
)
667 m_pListenersContainer
= new ::cppu::OInterfaceContainerHelper( m_aMutex
);
669 m_pListenersContainer
->addInterface( xListener
);
673 void SAL_CALL
OLESimpleStorage::removeEventListener(
674 const uno::Reference
< lang::XEventListener
>& xListener
)
675 throw ( uno::RuntimeException
, std::exception
)
677 ::osl::MutexGuard
aGuard( m_aMutex
);
680 throw lang::DisposedException();
682 if ( m_pListenersContainer
)
683 m_pListenersContainer
->removeInterface( xListener
);
691 void SAL_CALL
OLESimpleStorage::commit()
692 throw ( ::com::sun::star::io::IOException
,
693 ::com::sun::star::lang::WrappedTargetException
,
694 ::com::sun::star::uno::RuntimeException
, std::exception
)
696 ::osl::MutexGuard
aGuard( m_aMutex
);
699 throw lang::DisposedException();
702 throw uno::RuntimeException();
704 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
705 throw io::IOException(); // TODO
707 if ( !m_pStorage
->Commit() || m_pStorage
->GetError() )
709 m_pStorage
->ResetError();
710 throw io::IOException(); // TODO
713 UpdateOriginal_Impl();
717 void SAL_CALL
OLESimpleStorage::revert()
718 throw ( ::com::sun::star::io::IOException
,
719 ::com::sun::star::lang::WrappedTargetException
,
720 ::com::sun::star::uno::RuntimeException
, std::exception
)
722 ::osl::MutexGuard
aGuard( m_aMutex
);
725 throw lang::DisposedException();
728 throw uno::RuntimeException();
730 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
731 throw io::IOException(); // TODO
733 if ( !m_pStorage
->Revert() || m_pStorage
->GetError() )
735 m_pStorage
->ResetError();
736 throw io::IOException(); // TODO
739 UpdateOriginal_Impl();
746 uno::Sequence
< sal_Int8
> SAL_CALL
OLESimpleStorage::getClassID()
747 throw ( uno::RuntimeException
, std::exception
)
749 ::osl::MutexGuard
aGuard( m_aMutex
);
752 throw lang::DisposedException();
755 throw uno::RuntimeException();
757 return m_pStorage
->GetClassName().GetByteSequence();
760 OUString SAL_CALL
OLESimpleStorage::getClassName()
761 throw ( uno::RuntimeException
, std::exception
)
766 void SAL_CALL
OLESimpleStorage::setClassInfo( const uno::Sequence
< sal_Int8
>& /*aClassID*/,
767 const OUString
& /*sClassName*/ )
768 throw ( lang::NoSupportException
,
769 uno::RuntimeException
, std::exception
)
771 throw lang::NoSupportException();
775 OUString SAL_CALL
OLESimpleStorage::getImplementationName()
776 throw ( uno::RuntimeException
, std::exception
)
778 return impl_staticGetImplementationName();
781 sal_Bool SAL_CALL
OLESimpleStorage::supportsService( const OUString
& ServiceName
)
782 throw ( uno::RuntimeException
, std::exception
)
784 return cppu::supportsService(this, ServiceName
);
787 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getSupportedServiceNames()
788 throw ( uno::RuntimeException
, std::exception
)
790 return impl_staticGetSupportedServiceNames();
794 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */