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 "xolesimplestorage.hxx"
22 #include <com/sun/star/embed/OLESimpleStorage.hpp>
23 #include <com/sun/star/lang/DisposedException.hpp>
24 #include <com/sun/star/lang/NoSupportException.hpp>
25 #include <com/sun/star/io/IOException.hpp>
26 #include <com/sun/star/io/XStream.hpp>
27 #include <com/sun/star/io/XInputStream.hpp>
28 #include <com/sun/star/io/XSeekable.hpp>
29 #include <com/sun/star/io/XTruncate.hpp>
30 #include <com/sun/star/io/TempFile.hpp>
32 #include <comphelper/storagehelper.hxx>
33 #include <unotools/ucbstreamhelper.hxx>
34 #include <cppuhelper/exc_hlp.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <sot/stg.hxx>
37 #include <sot/storinfo.hxx>
40 using namespace ::com::sun::star
;
42 const sal_Int32 nBytesCount
= 32000;
45 OLESimpleStorage::OLESimpleStorage(
46 css::uno::Reference
<css::uno::XComponentContext
> xContext
,
47 css::uno::Sequence
<css::uno::Any
> const &aArguments
)
48 : m_bDisposed( false )
49 , m_xContext(std::move( xContext
))
50 , m_bNoTemporaryCopy( false )
52 sal_Int32 nArgNum
= aArguments
.getLength();
53 if ( nArgNum
< 1 || nArgNum
> 2 )
54 throw lang::IllegalArgumentException(); // TODO:
56 uno::Reference
< io::XStream
> xStream
;
57 uno::Reference
< io::XInputStream
> xInputStream
;
58 if ( !( aArguments
[0] >>= xStream
) && !( aArguments
[0] >>= xInputStream
) )
59 throw lang::IllegalArgumentException(); // TODO:
63 if ( !( aArguments
[1] >>= m_bNoTemporaryCopy
) )
64 throw lang::IllegalArgumentException(); // TODO:
67 if ( m_bNoTemporaryCopy
)
70 // If the temporary stream is not created, the original stream must be wrapped
71 // since SvStream wrapper closes the stream is owns
72 if ( xInputStream
.is() )
74 // the stream must be seekable for direct access
75 uno::Reference
< io::XSeekable
> xSeek( xInputStream
, uno::UNO_QUERY_THROW
);
76 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xInputStream
, false );
78 else if ( xStream
.is() )
80 // the stream must be seekable for direct access
81 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
82 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xStream
, false );
85 throw lang::IllegalArgumentException(); // TODO:
89 uno::Reference
< io::XStream
> xTempFile( io::TempFile::create(m_xContext
),
90 uno::UNO_QUERY_THROW
);
91 uno::Reference
< io::XSeekable
> xTempSeek( xTempFile
, uno::UNO_QUERY_THROW
);
92 uno::Reference
< io::XOutputStream
> xTempOut
= xTempFile
->getOutputStream();
94 throw uno::RuntimeException();
96 if ( xInputStream
.is() )
100 uno::Reference
< io::XSeekable
> xSeek( xInputStream
, uno::UNO_QUERY_THROW
);
103 catch( uno::Exception
& )
106 ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream
, xTempOut
);
107 xTempOut
->closeOutput();
108 xTempSeek
->seek( 0 );
109 uno::Reference
< io::XInputStream
> xTempInput
= xTempFile
->getInputStream();
110 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempInput
, false );
112 else if ( xStream
.is() )
114 // not sure that the storage flashes the stream on commit
116 m_xTempStream
= xTempFile
;
118 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
120 uno::Reference
< io::XInputStream
> xInpStream
= xStream
->getInputStream();
121 if ( !xInpStream
.is() || !xStream
->getOutputStream().is() )
122 throw uno::RuntimeException();
124 ::comphelper::OStorageHelper::CopyInputToOutput( xInpStream
, xTempOut
);
126 xTempSeek
->seek( 0 );
128 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false );
131 throw lang::IllegalArgumentException(); // TODO:
134 if ( !m_pStream
|| m_pStream
->GetError() )
135 throw io::IOException(); // TODO
137 m_pStorage
.reset(new Storage( *m_pStream
, false ));
140 OLESimpleStorage::~OLESimpleStorage()
143 osl_atomic_increment(&m_refCount
);
145 } catch( uno::Exception
& )
149 void OLESimpleStorage::UpdateOriginal_Impl()
151 if ( m_bNoTemporaryCopy
)
154 uno::Reference
< io::XSeekable
> xSeek( m_xStream
, uno::UNO_QUERY_THROW
);
157 uno::Reference
< io::XSeekable
> xTempSeek( m_xTempStream
, uno::UNO_QUERY_THROW
);
158 sal_Int64 nPos
= xTempSeek
->getPosition();
159 xTempSeek
->seek( 0 );
161 uno::Reference
< io::XInputStream
> xTempInp
= m_xTempStream
->getInputStream();
162 uno::Reference
< io::XOutputStream
> xOutputStream
= m_xStream
->getOutputStream();
163 if ( !xTempInp
.is() || !xOutputStream
.is() )
164 throw uno::RuntimeException();
166 uno::Reference
< io::XTruncate
> xTrunc( xOutputStream
, uno::UNO_QUERY_THROW
);
169 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInp
, xOutputStream
);
170 xOutputStream
->flush();
171 xTempSeek
->seek( nPos
);
175 void OLESimpleStorage::InsertInputStreamToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< io::XInputStream
>& xInputStream
)
177 if ( !pStorage
|| aName
.isEmpty() || !xInputStream
.is() )
178 throw uno::RuntimeException();
180 if ( pStorage
->IsContained( aName
) )
181 throw container::ElementExistException(); // TODO:
183 std::unique_ptr
<BaseStorageStream
> pNewStream(pStorage
->OpenStream( aName
));
184 if ( !pNewStream
|| pNewStream
->GetError() || pStorage
->GetError() )
187 pStorage
->ResetError();
188 throw io::IOException(); // TODO
193 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
197 nRead
= xInputStream
->readBytes( aData
, nBytesCount
);
199 sal_Int32 nWritten
= pNewStream
->Write( aData
.getConstArray(), nRead
);
200 if ( nWritten
< nRead
)
201 throw io::IOException();
202 } while( nRead
== nBytesCount
);
204 catch( uno::Exception
& )
207 pStorage
->Remove( aName
);
214 void OLESimpleStorage::InsertNameAccessToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< container::XNameAccess
>& xNameAccess
)
216 if ( !pStorage
|| aName
.isEmpty() || !xNameAccess
.is() )
217 throw uno::RuntimeException();
219 if ( pStorage
->IsContained( aName
) )
220 throw container::ElementExistException(); // TODO:
222 std::unique_ptr
<BaseStorage
> pNewStorage(pStorage
->OpenStorage( aName
));
223 if ( !pNewStorage
|| pNewStorage
->GetError() || pStorage
->GetError() )
226 pStorage
->ResetError();
227 throw io::IOException(); // TODO
232 const uno::Sequence
< OUString
> aElements
= xNameAccess
->getElementNames();
233 for ( const auto& rElement
: aElements
)
235 uno::Reference
< io::XInputStream
> xInputStream
;
236 uno::Reference
< container::XNameAccess
> xSubNameAccess
;
237 uno::Any aAny
= xNameAccess
->getByName( rElement
);
238 if ( aAny
>>= xInputStream
)
239 InsertInputStreamToStorage_Impl( pNewStorage
.get(), rElement
, xInputStream
);
240 else if ( aAny
>>= xSubNameAccess
)
241 InsertNameAccessToStorage_Impl( pNewStorage
.get(), rElement
, xSubNameAccess
);
244 catch( uno::Exception
& )
247 pStorage
->Remove( aName
);
257 void SAL_CALL
OLESimpleStorage::insertByName( const OUString
& aName
, const uno::Any
& aElement
)
259 std::unique_lock
aGuard( m_aMutex
);
262 throw lang::DisposedException();
265 throw uno::RuntimeException();
267 uno::Reference
< io::XStream
> xStream
;
268 uno::Reference
< io::XInputStream
> xInputStream
;
269 uno::Reference
< container::XNameAccess
> xNameAccess
;
273 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
274 throw io::IOException(); // TODO
276 if ( aElement
>>= xStream
)
277 xInputStream
= xStream
->getInputStream();
278 else if ( !( aElement
>>= xInputStream
) && !( aElement
>>= xNameAccess
) )
279 throw lang::IllegalArgumentException(); // TODO:
281 if ( xInputStream
.is() )
282 InsertInputStreamToStorage_Impl( m_pStorage
.get(), aName
, xInputStream
);
283 else if ( xNameAccess
.is() )
284 InsertNameAccessToStorage_Impl( m_pStorage
.get(), aName
, xNameAccess
);
286 throw uno::RuntimeException();
288 catch( uno::RuntimeException
& )
292 catch( container::ElementExistException
& )
296 catch( const uno::Exception
& )
298 css::uno::Any anyEx
= cppu::getCaughtException();
299 throw lang::WrappedTargetException("Insert has failed!",
300 uno::Reference
< uno::XInterface
>(),
306 void SAL_CALL
OLESimpleStorage::removeByName( const OUString
& aName
)
308 std::unique_lock
aGuard( m_aMutex
);
311 throw lang::DisposedException();
314 throw uno::RuntimeException();
316 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
317 throw lang::WrappedTargetException(); // io::IOException(); // TODO
319 if ( !m_pStorage
->IsContained( aName
) )
320 throw container::NoSuchElementException(); // TODO:
322 m_pStorage
->Remove( aName
);
324 if ( m_pStorage
->GetError() )
326 m_pStorage
->ResetError();
327 throw lang::WrappedTargetException(); // io::IOException(); // TODO
332 void SAL_CALL
OLESimpleStorage::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
334 std::unique_lock
aGuard( m_aMutex
);
337 throw lang::DisposedException();
339 removeByName( aName
);
343 insertByName( aName
, aElement
);
345 catch( container::ElementExistException
& )
347 uno::Any
aCaught( ::cppu::getCaughtException() );
349 throw lang::WrappedTargetException("Can't copy raw stream",
350 uno::Reference
< uno::XInterface
>(),
356 uno::Any SAL_CALL
OLESimpleStorage::getByName( const OUString
& aName
)
358 std::unique_lock
aGuard( m_aMutex
);
361 throw lang::DisposedException();
364 throw uno::RuntimeException();
366 if ( !m_pStorage
->IsContained( aName
) )
367 throw container::NoSuchElementException(); // TODO:
371 uno::Reference
< io::XStream
> xTempFile
= io::TempFile::create(m_xContext
);
372 uno::Reference
< io::XSeekable
> xSeekable( xTempFile
, uno::UNO_QUERY_THROW
);
373 uno::Reference
< io::XOutputStream
> xOutputStream
= xTempFile
->getOutputStream();
374 uno::Reference
< io::XInputStream
> xInputStream
= xTempFile
->getInputStream();
375 if ( !xOutputStream
.is() || !xInputStream
.is() )
376 throw uno::RuntimeException();
378 if ( m_pStorage
->IsStorage( aName
) )
380 std::unique_ptr
<BaseStorage
> pStrg(m_pStorage
->OpenStorage( aName
));
381 m_pStorage
->ResetError();
383 throw lang::WrappedTargetException(); // io::IOException(); // TODO
385 std::unique_ptr
<SvStream
> pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false ); // do not close the original stream
387 throw uno::RuntimeException();
389 std::unique_ptr
<BaseStorage
> pNewStor(new Storage( *pStream
, false ));
390 bool bSuccess
= ( pStrg
->CopyTo( pNewStor
.get() ) && pNewStor
->Commit() &&
391 !pNewStor
->GetError() && !pStrg
->GetError() );
398 throw uno::RuntimeException();
400 uno::Reference
< container::XNameContainer
> xResultNameContainer(
401 css::embed::OLESimpleStorage::createFromInputStream(m_xContext
, xInputStream
, true),
402 uno::UNO_QUERY_THROW
);
404 aResult
<<= xResultNameContainer
;
408 std::unique_ptr
<BaseStorageStream
> pStream(m_pStorage
->OpenStream( aName
, StreamMode::READ
| StreamMode::SHARE_DENYALL
| StreamMode::NOCREATE
));
411 if ( !pStream
|| pStream
->GetError() || m_pStorage
->GetError() )
413 m_pStorage
->ResetError();
414 throw io::IOException(); // TODO
417 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
418 sal_Int32 nSize
= nBytesCount
;
420 while( 0 != ( nRead
= pStream
->Read( aData
.getArray(), nSize
) ) )
425 aData
.realloc( nSize
);
428 xOutputStream
->writeBytes( aData
);
431 if ( pStream
->GetError() )
432 throw io::IOException(); // TODO
434 xOutputStream
->closeOutput();
435 xSeekable
->seek( 0 );
437 catch (const uno::RuntimeException
&)
441 catch (const uno::Exception
& ex
)
443 css::uno::Any anyEx
= cppu::getCaughtException();
444 throw css::lang::WrappedTargetException( ex
.Message
,
450 aResult
<<= xInputStream
;
457 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getElementNames()
459 std::unique_lock
aGuard( m_aMutex
);
462 throw lang::DisposedException();
465 throw uno::RuntimeException();
467 SvStorageInfoList aList
;
468 m_pStorage
->FillInfoList( &aList
);
470 if ( m_pStorage
->GetError() )
472 m_pStorage
->ResetError();
473 throw uno::RuntimeException(); // TODO:
476 uno::Sequence
< OUString
> aSeq( aList
.size() );
477 auto aSeqRange
= asNonConstRange(aSeq
);
478 for ( size_t nInd
= 0; nInd
< aList
.size(); nInd
++ )
479 aSeqRange
[nInd
] = aList
[nInd
].GetName();
485 sal_Bool SAL_CALL
OLESimpleStorage::hasByName( const OUString
& aName
)
487 std::unique_lock
aGuard( m_aMutex
);
490 throw lang::DisposedException();
493 throw uno::RuntimeException();
495 bool bResult
= m_pStorage
->IsContained( aName
);
497 if ( m_pStorage
->GetError() )
499 m_pStorage
->ResetError();
500 throw uno::RuntimeException(); // TODO:
507 uno::Type SAL_CALL
OLESimpleStorage::getElementType()
509 std::unique_lock
aGuard( m_aMutex
);
512 throw lang::DisposedException();
514 return cppu::UnoType
<io::XInputStream
>::get();
518 sal_Bool SAL_CALL
OLESimpleStorage::hasElements()
520 std::unique_lock
aGuard( m_aMutex
);
523 throw lang::DisposedException();
526 throw uno::RuntimeException();
528 SvStorageInfoList aList
;
529 m_pStorage
->FillInfoList( &aList
);
531 if ( m_pStorage
->GetError() )
533 m_pStorage
->ResetError();
534 throw uno::RuntimeException(); // TODO:
537 return !aList
.empty();
544 void SAL_CALL
OLESimpleStorage::dispose()
546 std::unique_lock
aGuard( m_aMutex
);
551 if ( m_aListenersContainer
.getLength(aGuard
) )
553 lang::EventObject
aSource( getXWeak() );
554 m_aListenersContainer
.disposeAndClear( aGuard
, aSource
);
561 m_xTempStream
.clear();
567 void SAL_CALL
OLESimpleStorage::addEventListener(
568 const uno::Reference
< lang::XEventListener
>& xListener
)
570 std::unique_lock
aGuard( m_aMutex
);
573 throw lang::DisposedException();
575 m_aListenersContainer
.addInterface( aGuard
, xListener
);
579 void SAL_CALL
OLESimpleStorage::removeEventListener(
580 const uno::Reference
< lang::XEventListener
>& xListener
)
582 std::unique_lock
aGuard( m_aMutex
);
585 throw lang::DisposedException();
587 m_aListenersContainer
.removeInterface( aGuard
, xListener
);
594 void SAL_CALL
OLESimpleStorage::commit()
596 std::unique_lock
aGuard( m_aMutex
);
599 throw lang::DisposedException();
602 throw uno::RuntimeException();
604 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
605 throw io::IOException(); // TODO
607 if ( !m_pStorage
->Commit() || m_pStorage
->GetError() )
609 m_pStorage
->ResetError();
610 throw io::IOException(); // TODO
613 UpdateOriginal_Impl();
617 void SAL_CALL
OLESimpleStorage::revert()
619 std::unique_lock
aGuard( m_aMutex
);
622 throw lang::DisposedException();
625 throw uno::RuntimeException();
627 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
628 throw io::IOException(); // TODO
630 if ( !m_pStorage
->Revert() || m_pStorage
->GetError() )
632 m_pStorage
->ResetError();
633 throw io::IOException(); // TODO
636 UpdateOriginal_Impl();
643 uno::Sequence
< sal_Int8
> SAL_CALL
OLESimpleStorage::getClassID()
645 std::unique_lock
aGuard( m_aMutex
);
648 throw lang::DisposedException();
651 throw uno::RuntimeException();
653 return m_pStorage
->GetClassName().GetByteSequence();
656 OUString SAL_CALL
OLESimpleStorage::getClassName()
661 void SAL_CALL
OLESimpleStorage::setClassInfo( const uno::Sequence
< sal_Int8
>& /*aClassID*/,
662 const OUString
& /*sClassName*/ )
664 throw lang::NoSupportException();
668 OUString SAL_CALL
OLESimpleStorage::getImplementationName()
670 return "com.sun.star.comp.embed.OLESimpleStorage";
673 sal_Bool SAL_CALL
OLESimpleStorage::supportsService( const OUString
& ServiceName
)
675 return cppu::supportsService(this, ServiceName
);
678 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getSupportedServiceNames()
680 return { "com.sun.star.embed.OLESimpleStorage" };
683 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
684 com_sun_star_comp_embed_OLESimpleStorage(
685 css::uno::XComponentContext
*context
,
686 css::uno::Sequence
<css::uno::Any
> const &arguments
)
688 return cppu::acquire(new OLESimpleStorage(context
, arguments
));
691 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */