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
);
104 catch( uno::Exception
& )
107 ::comphelper::OStorageHelper::CopyInputToOutput( xInputStream
, xTempOut
);
108 xTempOut
->closeOutput();
109 xTempSeek
->seek( 0 );
110 uno::Reference
< io::XInputStream
> xTempInput
= xTempFile
->getInputStream();
111 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempInput
, false );
113 else if ( xStream
.is() )
115 // not sure that the storage flashes the stream on commit
117 m_xTempStream
= xTempFile
;
119 uno::Reference
< io::XSeekable
> xSeek( xStream
, uno::UNO_QUERY_THROW
);
121 uno::Reference
< io::XInputStream
> xInpStream
= xStream
->getInputStream();
122 if ( !xInpStream
.is() || !xStream
->getOutputStream().is() )
123 throw uno::RuntimeException();
125 ::comphelper::OStorageHelper::CopyInputToOutput( xInpStream
, xTempOut
);
127 xTempSeek
->seek( 0 );
129 m_pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false );
132 throw lang::IllegalArgumentException(); // TODO:
135 if ( !m_pStream
|| m_pStream
->GetError() )
136 throw io::IOException(); // TODO
138 m_pStorage
.reset(new Storage( *m_pStream
, false ));
141 OLESimpleStorage::~OLESimpleStorage()
144 osl_atomic_increment(&m_refCount
);
146 } catch( uno::Exception
& )
150 void OLESimpleStorage::UpdateOriginal_Impl()
152 if ( m_bNoTemporaryCopy
)
155 uno::Reference
< io::XSeekable
> xSeek( m_xStream
, uno::UNO_QUERY_THROW
);
158 uno::Reference
< io::XSeekable
> xTempSeek( m_xTempStream
, uno::UNO_QUERY_THROW
);
159 sal_Int64 nPos
= xTempSeek
->getPosition();
160 xTempSeek
->seek( 0 );
162 uno::Reference
< io::XInputStream
> xTempInp
= m_xTempStream
->getInputStream();
163 uno::Reference
< io::XOutputStream
> xOutputStream
= m_xStream
->getOutputStream();
164 if ( !xTempInp
.is() || !xOutputStream
.is() )
165 throw uno::RuntimeException();
167 uno::Reference
< io::XTruncate
> xTrunc( xOutputStream
, uno::UNO_QUERY_THROW
);
170 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInp
, xOutputStream
);
171 xOutputStream
->flush();
172 xTempSeek
->seek( nPos
);
176 void OLESimpleStorage::InsertInputStreamToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< io::XInputStream
>& xInputStream
)
178 if ( !pStorage
|| aName
.isEmpty() || !xInputStream
.is() )
179 throw uno::RuntimeException();
181 if ( pStorage
->IsContained( aName
) )
182 throw container::ElementExistException(); // TODO:
184 std::unique_ptr
<BaseStorageStream
> pNewStream(pStorage
->OpenStream( aName
));
185 if ( !pNewStream
|| pNewStream
->GetError() || pStorage
->GetError() )
188 pStorage
->ResetError();
189 throw io::IOException(); // TODO
194 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
198 nRead
= xInputStream
->readBytes( aData
, nBytesCount
);
200 sal_Int32 nWritten
= pNewStream
->Write( aData
.getConstArray(), nRead
);
201 if ( nWritten
< nRead
)
202 throw io::IOException();
203 } while( nRead
== nBytesCount
);
205 catch( uno::Exception
& )
208 pStorage
->Remove( aName
);
215 void OLESimpleStorage::InsertNameAccessToStorage_Impl( BaseStorage
* pStorage
, const OUString
& aName
, const uno::Reference
< container::XNameAccess
>& xNameAccess
)
217 if ( !pStorage
|| aName
.isEmpty() || !xNameAccess
.is() )
218 throw uno::RuntimeException();
220 if ( pStorage
->IsContained( aName
) )
221 throw container::ElementExistException(); // TODO:
223 std::unique_ptr
<BaseStorage
> pNewStorage(pStorage
->OpenStorage( aName
));
224 if ( !pNewStorage
|| pNewStorage
->GetError() || pStorage
->GetError() )
227 pStorage
->ResetError();
228 throw io::IOException(); // TODO
233 const uno::Sequence
< OUString
> aElements
= xNameAccess
->getElementNames();
234 for ( const auto& rElement
: aElements
)
236 uno::Reference
< io::XInputStream
> xInputStream
;
237 uno::Reference
< container::XNameAccess
> xSubNameAccess
;
238 uno::Any aAny
= xNameAccess
->getByName( rElement
);
239 if ( aAny
>>= xInputStream
)
240 InsertInputStreamToStorage_Impl( pNewStorage
.get(), rElement
, xInputStream
);
241 else if ( aAny
>>= xSubNameAccess
)
242 InsertNameAccessToStorage_Impl( pNewStorage
.get(), rElement
, xSubNameAccess
);
245 catch( uno::Exception
& )
248 pStorage
->Remove( aName
);
258 void SAL_CALL
OLESimpleStorage::insertByName( const OUString
& aName
, const uno::Any
& aElement
)
260 std::unique_lock
aGuard( m_aMutex
);
263 throw lang::DisposedException();
266 throw uno::RuntimeException();
268 uno::Reference
< io::XStream
> xStream
;
269 uno::Reference
< io::XInputStream
> xInputStream
;
270 uno::Reference
< container::XNameAccess
> xNameAccess
;
274 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
275 throw io::IOException(); // TODO
277 if ( aElement
>>= xStream
)
278 xInputStream
= xStream
->getInputStream();
279 else if ( !( aElement
>>= xInputStream
) && !( aElement
>>= xNameAccess
) )
280 throw lang::IllegalArgumentException(); // TODO:
282 if ( xInputStream
.is() )
283 InsertInputStreamToStorage_Impl( m_pStorage
.get(), aName
, xInputStream
);
284 else if ( xNameAccess
.is() )
285 InsertNameAccessToStorage_Impl( m_pStorage
.get(), aName
, xNameAccess
);
287 throw uno::RuntimeException();
289 catch( uno::RuntimeException
& )
293 catch( container::ElementExistException
& )
297 catch( const uno::Exception
& )
299 css::uno::Any anyEx
= cppu::getCaughtException();
300 throw lang::WrappedTargetException(u
"Insert has failed!"_ustr
,
301 uno::Reference
< uno::XInterface
>(),
307 void SAL_CALL
OLESimpleStorage::removeByName( const OUString
& aName
)
309 std::unique_lock
aGuard( m_aMutex
);
312 throw lang::DisposedException();
315 throw uno::RuntimeException();
317 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
318 throw lang::WrappedTargetException(); // io::IOException(); // TODO
320 if ( !m_pStorage
->IsContained( aName
) )
321 throw container::NoSuchElementException(); // TODO:
323 m_pStorage
->Remove( aName
);
325 if ( m_pStorage
->GetError() )
327 m_pStorage
->ResetError();
328 throw lang::WrappedTargetException(); // io::IOException(); // TODO
333 void SAL_CALL
OLESimpleStorage::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
335 std::unique_lock
aGuard( m_aMutex
);
338 throw lang::DisposedException();
340 removeByName( aName
);
344 insertByName( aName
, aElement
);
346 catch( container::ElementExistException
& )
348 uno::Any
aCaught( ::cppu::getCaughtException() );
350 throw lang::WrappedTargetException(u
"Can't copy raw stream"_ustr
,
351 uno::Reference
< uno::XInterface
>(),
357 uno::Any SAL_CALL
OLESimpleStorage::getByName( const OUString
& aName
)
359 std::unique_lock
aGuard( m_aMutex
);
362 throw lang::DisposedException();
365 throw uno::RuntimeException();
367 if ( !m_pStorage
->IsContained( aName
) )
368 throw container::NoSuchElementException(); // TODO:
372 uno::Reference
< io::XStream
> xTempFile
= io::TempFile::create(m_xContext
);
373 uno::Reference
< io::XSeekable
> xSeekable( xTempFile
, uno::UNO_QUERY_THROW
);
374 uno::Reference
< io::XOutputStream
> xOutputStream
= xTempFile
->getOutputStream();
375 uno::Reference
< io::XInputStream
> xInputStream
= xTempFile
->getInputStream();
376 if ( !xOutputStream
.is() || !xInputStream
.is() )
377 throw uno::RuntimeException();
379 if ( m_pStorage
->IsStorage( aName
) )
381 std::unique_ptr
<BaseStorage
> pStrg(m_pStorage
->OpenStorage( aName
));
382 m_pStorage
->ResetError();
384 throw lang::WrappedTargetException(); // io::IOException(); // TODO
386 std::unique_ptr
<SvStream
> pStream
= ::utl::UcbStreamHelper::CreateStream( xTempFile
, false ); // do not close the original stream
388 throw uno::RuntimeException();
390 std::unique_ptr
<BaseStorage
> pNewStor(new Storage( *pStream
, false ));
391 bool bSuccess
= ( pStrg
->CopyTo( *pNewStor
) && pNewStor
->Commit() &&
392 !pNewStor
->GetError() && !pStrg
->GetError() );
399 throw uno::RuntimeException();
401 uno::Reference
< container::XNameContainer
> xResultNameContainer(
402 css::embed::OLESimpleStorage::createFromInputStream(m_xContext
, xInputStream
, true),
403 uno::UNO_QUERY_THROW
);
405 aResult
<<= xResultNameContainer
;
409 std::unique_ptr
<BaseStorageStream
> pStream(m_pStorage
->OpenStream( aName
, StreamMode::READ
| StreamMode::SHARE_DENYALL
| StreamMode::NOCREATE
));
412 if ( !pStream
|| pStream
->GetError() || m_pStorage
->GetError() )
414 m_pStorage
->ResetError();
415 throw io::IOException(); // TODO
418 uno::Sequence
< sal_Int8
> aData( nBytesCount
);
419 sal_Int32 nSize
= nBytesCount
;
421 while( 0 != ( nRead
= pStream
->Read( aData
.getArray(), nSize
) ) )
426 aData
.realloc( nSize
);
429 xOutputStream
->writeBytes( aData
);
432 if ( pStream
->GetError() )
433 throw io::IOException(); // TODO
435 xOutputStream
->closeOutput();
436 xSeekable
->seek( 0 );
438 catch (const uno::RuntimeException
&)
442 catch (const uno::Exception
& ex
)
444 css::uno::Any anyEx
= cppu::getCaughtException();
445 throw css::lang::WrappedTargetException( ex
.Message
,
451 aResult
<<= xInputStream
;
458 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getElementNames()
460 std::unique_lock
aGuard( m_aMutex
);
463 throw lang::DisposedException();
466 throw uno::RuntimeException();
468 SvStorageInfoList aList
;
469 m_pStorage
->FillInfoList( &aList
);
471 if ( m_pStorage
->GetError() )
473 m_pStorage
->ResetError();
474 throw uno::RuntimeException(); // TODO:
477 uno::Sequence
< OUString
> aSeq( aList
.size() );
478 auto aSeqRange
= asNonConstRange(aSeq
);
479 for ( size_t nInd
= 0; nInd
< aList
.size(); nInd
++ )
480 aSeqRange
[nInd
] = aList
[nInd
].GetName();
486 sal_Bool SAL_CALL
OLESimpleStorage::hasByName( const OUString
& aName
)
488 std::unique_lock
aGuard( m_aMutex
);
491 throw lang::DisposedException();
494 throw uno::RuntimeException();
496 bool bResult
= m_pStorage
->IsContained( aName
);
498 if ( m_pStorage
->GetError() )
500 m_pStorage
->ResetError();
501 throw uno::RuntimeException(); // TODO:
508 uno::Type SAL_CALL
OLESimpleStorage::getElementType()
510 std::unique_lock
aGuard( m_aMutex
);
513 throw lang::DisposedException();
515 return cppu::UnoType
<io::XInputStream
>::get();
519 sal_Bool SAL_CALL
OLESimpleStorage::hasElements()
521 std::unique_lock
aGuard( m_aMutex
);
524 throw lang::DisposedException();
527 throw uno::RuntimeException();
529 SvStorageInfoList aList
;
530 m_pStorage
->FillInfoList( &aList
);
532 if ( m_pStorage
->GetError() )
534 m_pStorage
->ResetError();
535 throw uno::RuntimeException(); // TODO:
538 return !aList
.empty();
545 void SAL_CALL
OLESimpleStorage::dispose()
547 std::unique_lock
aGuard( m_aMutex
);
552 if ( m_aListenersContainer
.getLength(aGuard
) )
554 lang::EventObject
aSource( getXWeak() );
555 m_aListenersContainer
.disposeAndClear( aGuard
, aSource
);
562 m_xTempStream
.clear();
568 void SAL_CALL
OLESimpleStorage::addEventListener(
569 const uno::Reference
< lang::XEventListener
>& xListener
)
571 std::unique_lock
aGuard( m_aMutex
);
574 throw lang::DisposedException();
576 m_aListenersContainer
.addInterface( aGuard
, xListener
);
580 void SAL_CALL
OLESimpleStorage::removeEventListener(
581 const uno::Reference
< lang::XEventListener
>& xListener
)
583 std::unique_lock
aGuard( m_aMutex
);
586 throw lang::DisposedException();
588 m_aListenersContainer
.removeInterface( aGuard
, xListener
);
595 void SAL_CALL
OLESimpleStorage::commit()
597 std::unique_lock
aGuard( m_aMutex
);
600 throw lang::DisposedException();
603 throw uno::RuntimeException();
605 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
606 throw io::IOException(); // TODO
608 if ( !m_pStorage
->Commit() || m_pStorage
->GetError() )
610 m_pStorage
->ResetError();
611 throw io::IOException(); // TODO
614 UpdateOriginal_Impl();
618 void SAL_CALL
OLESimpleStorage::revert()
620 std::unique_lock
aGuard( m_aMutex
);
623 throw lang::DisposedException();
626 throw uno::RuntimeException();
628 if ( !m_bNoTemporaryCopy
&& !m_xStream
.is() )
629 throw io::IOException(); // TODO
631 if ( !m_pStorage
->Revert() || m_pStorage
->GetError() )
633 m_pStorage
->ResetError();
634 throw io::IOException(); // TODO
637 UpdateOriginal_Impl();
644 uno::Sequence
< sal_Int8
> SAL_CALL
OLESimpleStorage::getClassID()
646 std::unique_lock
aGuard( m_aMutex
);
649 throw lang::DisposedException();
652 throw uno::RuntimeException();
654 return m_pStorage
->GetClassName().GetByteSequence();
657 OUString SAL_CALL
OLESimpleStorage::getClassName()
662 void SAL_CALL
OLESimpleStorage::setClassInfo( const uno::Sequence
< sal_Int8
>& /*aClassID*/,
663 const OUString
& /*sClassName*/ )
665 throw lang::NoSupportException();
669 OUString SAL_CALL
OLESimpleStorage::getImplementationName()
671 return u
"com.sun.star.comp.embed.OLESimpleStorage"_ustr
;
674 sal_Bool SAL_CALL
OLESimpleStorage::supportsService( const OUString
& ServiceName
)
676 return cppu::supportsService(this, ServiceName
);
679 uno::Sequence
< OUString
> SAL_CALL
OLESimpleStorage::getSupportedServiceNames()
681 return { u
"com.sun.star.embed.OLESimpleStorage"_ustr
};
684 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
685 com_sun_star_comp_embed_OLESimpleStorage(
686 css::uno::XComponentContext
*context
,
687 css::uno::Sequence
<css::uno::Any
> const &arguments
)
689 return cppu::acquire(new OLESimpleStorage(context
, arguments
));
692 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */