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 <osl/diagnose.h>
21 #include <com/sun/star/io/IOException.hpp>
22 #include <com/sun/star/io/NotConnectedException.hpp>
23 #include <com/sun/star/io/TempFile.hpp>
24 #include <comphelper/storagehelper.hxx>
25 #include "switchpersistencestream.hxx"
27 using namespace ::com::sun::star
;
29 struct SPStreamData_Impl
31 bool m_bInStreamBased
;
33 // the streams below are not visible from outside so there is no need to remember position
35 // original stream related members
36 uno::Reference
< io::XTruncate
> m_xOrigTruncate
;
37 uno::Reference
< io::XSeekable
> m_xOrigSeekable
;
38 uno::Reference
< io::XInputStream
> m_xOrigInStream
;
39 uno::Reference
< io::XOutputStream
> m_xOrigOutStream
;
46 const uno::Reference
< io::XTruncate
>& xOrigTruncate
,
47 const uno::Reference
< io::XSeekable
>& xOrigSeekable
,
48 const uno::Reference
< io::XInputStream
>& xOrigInStream
,
49 const uno::Reference
< io::XOutputStream
>& xOrigOutStream
,
52 : m_bInStreamBased( bInStreamBased
)
53 , m_xOrigTruncate( xOrigTruncate
)
54 , m_xOrigSeekable( xOrigSeekable
)
55 , m_xOrigInStream( xOrigInStream
)
56 , m_xOrigOutStream( xOrigOutStream
)
57 , m_bInOpen( bInOpen
)
58 , m_bOutOpen( bOutOpen
)
63 SwitchablePersistenceStream::SwitchablePersistenceStream(
64 const uno::Reference
< uno::XComponentContext
>& xContext
,
65 const uno::Reference
< io::XStream
>& xStream
)
66 : m_xContext( xContext
)
67 , m_pStreamData( nullptr )
69 SwitchPersistenceTo( xStream
);
72 SwitchablePersistenceStream::SwitchablePersistenceStream(
73 const uno::Reference
< uno::XComponentContext
>& xContext
,
74 const uno::Reference
< io::XInputStream
>& xInputStream
)
75 : m_xContext( xContext
)
76 , m_pStreamData( nullptr )
78 SwitchPersistenceTo( xInputStream
);
81 SwitchablePersistenceStream::~SwitchablePersistenceStream()
86 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
88 uno::Reference
< io::XTruncate
> xNewTruncate( xStream
, uno::UNO_QUERY_THROW
);
89 uno::Reference
< io::XSeekable
> xNewSeekable( xStream
, uno::UNO_QUERY_THROW
);
90 uno::Reference
< io::XInputStream
> xNewInStream
= xStream
->getInputStream();
91 uno::Reference
< io::XOutputStream
> xNewOutStream
= xStream
->getOutputStream();
92 if ( !xNewInStream
.is() || !xNewOutStream
.is() )
93 throw uno::RuntimeException();
97 bool bOutOpen
= false;
99 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
101 // check that the length is the same
102 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
103 throw uno::RuntimeException();
105 // get the current position
106 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
107 bInOpen
= m_pStreamData
->m_bInOpen
;
108 bOutOpen
= m_pStreamData
->m_bOutOpen
;
111 xNewSeekable
->seek( nPos
);
115 m_pStreamData
.reset( new SPStreamData_Impl( false,
116 xNewTruncate
, xNewSeekable
, xNewInStream
, xNewOutStream
,
117 bInOpen
, bOutOpen
) );
120 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XInputStream
>& xInputStream
)
122 uno::Reference
< io::XTruncate
> xNewTruncate
;
123 uno::Reference
< io::XSeekable
> xNewSeekable( xInputStream
, uno::UNO_QUERY_THROW
);
124 uno::Reference
< io::XOutputStream
> xNewOutStream
;
125 if ( !xInputStream
.is() )
126 throw uno::RuntimeException();
129 bool bInOpen
= false;
130 bool bOutOpen
= false;
132 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
134 // check that the length is the same
135 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
136 throw uno::RuntimeException();
138 // get the current position
139 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
140 bInOpen
= m_pStreamData
->m_bInOpen
;
141 bOutOpen
= m_pStreamData
->m_bOutOpen
;
144 xNewSeekable
->seek( nPos
);
148 m_pStreamData
.reset( new SPStreamData_Impl( true,
149 xNewTruncate
, xNewSeekable
, xInputStream
, xNewOutStream
,
150 bInOpen
, bOutOpen
) );
154 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
156 uno::Reference
< io::XStream
> xTargetStream
= xStream
;
157 uno::Reference
< io::XSeekable
> xTargetSeek
;
159 if ( !xTargetStream
.is() )
161 xTargetStream
.set( io::TempFile::create(m_xContext
), uno::UNO_QUERY_THROW
);
162 xTargetSeek
.set( xTargetStream
, uno::UNO_QUERY_THROW
);
166 // the provided stream must be empty
167 xTargetSeek
.set( xTargetStream
, uno::UNO_QUERY_THROW
);
168 if ( xTargetSeek
->getLength() )
169 throw io::IOException();
172 uno::Reference
< io::XTruncate
> xTargetTruncate( xTargetStream
, uno::UNO_QUERY_THROW
);
173 uno::Reference
< io::XInputStream
> xTargetInStream
= xTargetStream
->getInputStream();
174 uno::Reference
< io::XOutputStream
> xTargetOutStream
= xTargetStream
->getOutputStream();
175 if ( !xTargetInStream
.is() || !xTargetOutStream
.is() )
176 throw uno::RuntimeException();
178 if ( !m_pStreamData
->m_xOrigInStream
.is() || !m_pStreamData
->m_xOrigSeekable
.is() )
179 throw uno::RuntimeException();
181 sal_Int64 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
182 m_pStreamData
->m_xOrigSeekable
->seek( 0 );
183 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData
->m_xOrigInStream
, xTargetOutStream
);
184 xTargetOutStream
->flush();
185 xTargetSeek
->seek( nPos
);
187 bool bInOpen
= m_pStreamData
->m_bInOpen
;
188 bool bOutOpen
= m_pStreamData
->m_bOutOpen
;
192 m_pStreamData
.reset( new SPStreamData_Impl( false,
193 xTargetTruncate
, xTargetSeek
, xTargetInStream
, xTargetOutStream
,
194 bInOpen
, bOutOpen
) );
197 void SwitchablePersistenceStream::CloseAll_Impl()
199 m_pStreamData
.reset();
203 uno::Reference
< io::XInputStream
> SAL_CALL
SwitchablePersistenceStream::getInputStream( )
205 ::osl::MutexGuard
aGuard( m_aMutex
);
208 m_pStreamData
->m_bInOpen
= true;
209 return static_cast< io::XInputStream
* >( this );
212 uno::Reference
< io::XOutputStream
> SAL_CALL
SwitchablePersistenceStream::getOutputStream( )
214 ::osl::MutexGuard
aGuard( m_aMutex
);
217 m_pStreamData
->m_bOutOpen
= true;
218 return static_cast< io::XOutputStream
* >( this );
221 // css::io::XInputStream
222 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nBytesToRead
)
224 ::osl::MutexGuard
aGuard( m_aMutex
);
226 if ( !m_pStreamData
)
227 throw io::NotConnectedException();
229 // the original stream data should be provided
230 if ( !m_pStreamData
->m_xOrigInStream
.is() )
231 throw uno::RuntimeException();
233 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nBytesToRead
);
236 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readSomeBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nMaxBytesToRead
)
238 ::osl::MutexGuard
aGuard( m_aMutex
);
240 if ( !m_pStreamData
)
241 throw io::NotConnectedException();
243 // the original stream data should be provided
244 if ( !m_pStreamData
->m_xOrigInStream
.is() )
245 throw uno::RuntimeException();
247 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nMaxBytesToRead
);
250 void SAL_CALL
SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip
)
252 ::osl::MutexGuard
aGuard( m_aMutex
);
254 if ( !m_pStreamData
)
255 throw io::NotConnectedException();
257 // the original stream data should be provided
258 if ( !m_pStreamData
->m_xOrigInStream
.is() )
259 throw uno::RuntimeException();
261 m_pStreamData
->m_xOrigInStream
->skipBytes( nBytesToSkip
);
264 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::available( )
266 ::osl::MutexGuard
aGuard( m_aMutex
);
268 if ( !m_pStreamData
)
269 throw io::NotConnectedException();
271 // the original stream data should be provided
272 if ( !m_pStreamData
->m_xOrigInStream
.is() )
273 throw uno::RuntimeException();
275 return m_pStreamData
->m_xOrigInStream
->available();
278 void SAL_CALL
SwitchablePersistenceStream::closeInput()
280 ::osl::MutexGuard
aGuard( m_aMutex
);
282 if ( !m_pStreamData
)
283 throw io::NotConnectedException();
285 m_pStreamData
->m_bInOpen
= false;
286 if ( !m_pStreamData
->m_bOutOpen
)
290 // css::io::XOutputStream
291 void SAL_CALL
SwitchablePersistenceStream::writeBytes( const uno::Sequence
< ::sal_Int8
>& aData
)
293 ::osl::MutexGuard
aGuard( m_aMutex
);
295 if ( !m_pStreamData
)
296 throw io::NotConnectedException();
298 if ( m_pStreamData
->m_bInStreamBased
)
299 throw io::IOException();
301 // the original stream data should be provided
302 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
303 throw uno::RuntimeException();
305 m_pStreamData
->m_xOrigOutStream
->writeBytes( aData
);
308 void SAL_CALL
SwitchablePersistenceStream::flush( )
310 ::osl::MutexGuard
aGuard( m_aMutex
);
312 if ( !m_pStreamData
|| m_pStreamData
->m_bInStreamBased
)
314 OSL_FAIL( "flush() is not acceptable!" );
316 // in future throw exception, for now some code might call flush() on closed stream
317 // since file ucp implementation allows it
318 // throw io::NotConnectedException();
321 // the original stream data should be provided
322 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
323 throw uno::RuntimeException();
325 m_pStreamData
->m_xOrigOutStream
->flush();
328 void SAL_CALL
SwitchablePersistenceStream::closeOutput( )
330 ::osl::MutexGuard
aGuard( m_aMutex
);
332 if ( !m_pStreamData
)
333 throw io::NotConnectedException();
335 m_pStreamData
->m_bOutOpen
= false;
336 if ( !m_pStreamData
->m_bInOpen
)
340 // css::io::XTruncate
341 void SAL_CALL
SwitchablePersistenceStream::truncate( )
343 ::osl::MutexGuard
aGuard( m_aMutex
);
345 if ( !m_pStreamData
)
346 throw io::NotConnectedException();
348 if ( m_pStreamData
->m_bInStreamBased
)
349 throw io::IOException();
351 // the original stream data should be provided
352 if ( !m_pStreamData
->m_xOrigTruncate
.is() )
353 throw uno::RuntimeException();
355 m_pStreamData
->m_xOrigTruncate
->truncate();
358 // css::io::XSeekable
359 void SAL_CALL
SwitchablePersistenceStream::seek( ::sal_Int64 location
)
361 ::osl::MutexGuard
aGuard( m_aMutex
);
363 if ( !m_pStreamData
)
364 throw io::NotConnectedException();
366 // the original stream data should be provided
367 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
368 throw uno::RuntimeException();
370 m_pStreamData
->m_xOrigSeekable
->seek( location
);
373 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getPosition( )
375 ::osl::MutexGuard
aGuard( m_aMutex
);
377 if ( !m_pStreamData
)
378 throw io::NotConnectedException();
380 // the original stream data should be provided
381 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
382 throw uno::RuntimeException();
384 return m_pStreamData
->m_xOrigSeekable
->getPosition();
387 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getLength( )
389 ::osl::MutexGuard
aGuard( m_aMutex
);
391 if ( !m_pStreamData
)
392 throw io::NotConnectedException();
394 // the original stream data should be provided
395 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
396 throw uno::RuntimeException();
398 return m_pStreamData
->m_xOrigSeekable
->getLength();
401 void SAL_CALL
SwitchablePersistenceStream::waitForCompletion()
403 if ( !m_pStreamData
)
404 throw io::NotConnectedException();
406 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( m_pStreamData
->m_xOrigOutStream
, uno::UNO_QUERY
);
407 if ( asyncOutputMonitor
.is() )
408 asyncOutputMonitor
->waitForCompletion();
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */