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>
22 #include <com/sun/star/io/TempFile.hpp>
23 #include <comphelper/processfactory.hxx>
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::XStream
> m_xOrigStream
;
37 uno::Reference
< io::XTruncate
> m_xOrigTruncate
;
38 uno::Reference
< io::XSeekable
> m_xOrigSeekable
;
39 uno::Reference
< io::XInputStream
> m_xOrigInStream
;
40 uno::Reference
< io::XOutputStream
> m_xOrigOutStream
;
47 const uno::Reference
< io::XStream
>& xOrigStream
,
48 const uno::Reference
< io::XTruncate
>& xOrigTruncate
,
49 const uno::Reference
< io::XSeekable
>& xOrigSeekable
,
50 const uno::Reference
< io::XInputStream
>& xOrigInStream
,
51 const uno::Reference
< io::XOutputStream
>& xOrigOutStream
,
54 : m_bInStreamBased( bInStreamBased
)
55 , m_xOrigStream( xOrigStream
)
56 , m_xOrigTruncate( xOrigTruncate
)
57 , m_xOrigSeekable( xOrigSeekable
)
58 , m_xOrigInStream( xOrigInStream
)
59 , m_xOrigOutStream( xOrigOutStream
)
60 , m_bInOpen( bInOpen
)
61 , m_bOutOpen( bOutOpen
)
66 SwitchablePersistenceStream::SwitchablePersistenceStream(
67 const uno::Reference
< uno::XComponentContext
>& xContext
,
68 const uno::Reference
< io::XStream
>& xStream
)
69 : m_xContext( xContext
)
70 , m_pStreamData( NULL
)
72 SwitchPersistenceTo( xStream
);
75 SwitchablePersistenceStream::SwitchablePersistenceStream(
76 const uno::Reference
< uno::XComponentContext
>& xContext
,
77 const uno::Reference
< io::XInputStream
>& xInputStream
)
78 : m_xContext( xContext
)
79 , m_pStreamData( NULL
)
81 SwitchPersistenceTo( xInputStream
);
84 SwitchablePersistenceStream::~SwitchablePersistenceStream()
89 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
91 uno::Reference
< io::XTruncate
> xNewTruncate( xStream
, uno::UNO_QUERY_THROW
);
92 uno::Reference
< io::XSeekable
> xNewSeekable( xStream
, uno::UNO_QUERY_THROW
);
93 uno::Reference
< io::XInputStream
> xNewInStream
= xStream
->getInputStream();
94 uno::Reference
< io::XOutputStream
> xNewOutStream
= xStream
->getOutputStream();
95 if ( !xNewInStream
.is() || !xNewOutStream
.is() )
96 throw uno::RuntimeException();
100 bool bOutOpen
= false;
102 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
104 // check that the length is the same
105 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
106 throw uno::RuntimeException();
108 // get the current position
109 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
110 bInOpen
= m_pStreamData
->m_bInOpen
;
111 bOutOpen
= m_pStreamData
->m_bOutOpen
;
114 xNewSeekable
->seek( nPos
);
118 m_pStreamData
= new SPStreamData_Impl( false,
119 xStream
, xNewTruncate
, xNewSeekable
, xNewInStream
, xNewOutStream
,
123 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XInputStream
>& xInputStream
)
125 uno::Reference
< io::XStream
> xNewStream
;
126 uno::Reference
< io::XTruncate
> xNewTruncate
;
127 uno::Reference
< io::XSeekable
> xNewSeekable( xInputStream
, uno::UNO_QUERY_THROW
);
128 uno::Reference
< io::XOutputStream
> xNewOutStream
;
129 if ( !xInputStream
.is() )
130 throw uno::RuntimeException();
133 bool bInOpen
= false;
134 bool bOutOpen
= false;
136 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
138 // check that the length is the same
139 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
140 throw uno::RuntimeException();
142 // get the current position
143 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
144 bInOpen
= m_pStreamData
->m_bInOpen
;
145 bOutOpen
= m_pStreamData
->m_bOutOpen
;
148 xNewSeekable
->seek( nPos
);
152 m_pStreamData
= new SPStreamData_Impl( true,
153 xNewStream
, xNewTruncate
, xNewSeekable
, xInputStream
, xNewOutStream
,
158 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
160 uno::Reference
< io::XStream
> xTargetStream
= xStream
;
161 uno::Reference
< io::XSeekable
> xTargetSeek
;
163 if ( !xTargetStream
.is() )
165 xTargetStream
= uno::Reference
< io::XStream
>(
166 io::TempFile::create(m_xContext
),
167 uno::UNO_QUERY_THROW
);
169 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
173 // the provided stream must be empty
174 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
175 if ( xTargetSeek
->getLength() )
176 throw io::IOException();
179 uno::Reference
< io::XTruncate
> xTargetTruncate( xTargetStream
, uno::UNO_QUERY_THROW
);
180 uno::Reference
< io::XInputStream
> xTargetInStream
= xTargetStream
->getInputStream();
181 uno::Reference
< io::XOutputStream
> xTargetOutStream
= xTargetStream
->getOutputStream();
182 if ( !xTargetInStream
.is() || !xTargetOutStream
.is() )
183 throw uno::RuntimeException();
185 if ( !m_pStreamData
->m_xOrigInStream
.is() || !m_pStreamData
->m_xOrigSeekable
.is() )
186 throw uno::RuntimeException();
188 sal_Int64 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
189 m_pStreamData
->m_xOrigSeekable
->seek( 0 );
190 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData
->m_xOrigInStream
, xTargetOutStream
);
191 xTargetOutStream
->flush();
192 xTargetSeek
->seek( nPos
);
194 bool bInOpen
= m_pStreamData
->m_bInOpen
;
195 bool bOutOpen
= m_pStreamData
->m_bOutOpen
;
199 m_pStreamData
= new SPStreamData_Impl( false,
200 xTargetStream
, xTargetTruncate
, xTargetSeek
, xTargetInStream
, xTargetOutStream
,
204 void SwitchablePersistenceStream::CloseAll_Impl()
208 delete m_pStreamData
;
209 m_pStreamData
= NULL
;
213 // com::sun::star::io::XStream
214 uno::Reference
< io::XInputStream
> SAL_CALL
SwitchablePersistenceStream::getInputStream( )
215 throw (uno::RuntimeException
, std::exception
)
217 ::osl::MutexGuard
aGuard( m_aMutex
);
220 m_pStreamData
->m_bInOpen
= true;
221 return static_cast< io::XInputStream
* >( this );
224 uno::Reference
< io::XOutputStream
> SAL_CALL
SwitchablePersistenceStream::getOutputStream( )
225 throw (uno::RuntimeException
, std::exception
)
227 ::osl::MutexGuard
aGuard( m_aMutex
);
230 m_pStreamData
->m_bOutOpen
= true;
231 return static_cast< io::XOutputStream
* >( this );
234 // com::sun::star::io::XInputStream
235 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nBytesToRead
)
236 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
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
, nBytesToRead
);
250 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readSomeBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nMaxBytesToRead
)
251 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
253 ::osl::MutexGuard
aGuard( m_aMutex
);
255 if ( !m_pStreamData
)
256 throw io::NotConnectedException();
258 // the original stream data should be provided
259 if ( !m_pStreamData
->m_xOrigInStream
.is() )
260 throw uno::RuntimeException();
262 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nMaxBytesToRead
);
265 void SAL_CALL
SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip
)
266 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
268 ::osl::MutexGuard
aGuard( m_aMutex
);
270 if ( !m_pStreamData
)
271 throw io::NotConnectedException();
273 // the original stream data should be provided
274 if ( !m_pStreamData
->m_xOrigInStream
.is() )
275 throw uno::RuntimeException();
277 m_pStreamData
->m_xOrigInStream
->skipBytes( nBytesToSkip
);
280 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::available( )
281 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
, std::exception
)
283 ::osl::MutexGuard
aGuard( m_aMutex
);
285 if ( !m_pStreamData
)
286 throw io::NotConnectedException();
288 // the original stream data should be provided
289 if ( !m_pStreamData
->m_xOrigInStream
.is() )
290 throw uno::RuntimeException();
292 return m_pStreamData
->m_xOrigInStream
->available();
295 void SAL_CALL
SwitchablePersistenceStream::closeInput()
296 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
, std::exception
)
298 ::osl::MutexGuard
aGuard( m_aMutex
);
300 if ( !m_pStreamData
)
301 throw io::NotConnectedException();
303 m_pStreamData
->m_bInOpen
= false;
304 if ( !m_pStreamData
->m_bOutOpen
)
308 // com::sun::star::io::XOutputStream
309 void SAL_CALL
SwitchablePersistenceStream::writeBytes( const uno::Sequence
< ::sal_Int8
>& aData
)
310 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
312 ::osl::MutexGuard
aGuard( m_aMutex
);
314 if ( !m_pStreamData
)
315 throw io::NotConnectedException();
317 if ( m_pStreamData
->m_bInStreamBased
)
318 throw io::IOException();
320 // the original stream data should be provided
321 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
322 throw uno::RuntimeException();
324 m_pStreamData
->m_xOrigOutStream
->writeBytes( aData
);
327 void SAL_CALL
SwitchablePersistenceStream::flush( )
328 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
330 ::osl::MutexGuard
aGuard( m_aMutex
);
332 if ( !m_pStreamData
|| m_pStreamData
->m_bInStreamBased
)
334 OSL_FAIL( "flush() is not acceptable!\n" );
336 // in future throw exception, for now some code might call flush() on closed stream
337 // since file ucp implementation allows it
338 // throw io::NotConnectedException();
341 // the original stream data should be provided
342 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
343 throw uno::RuntimeException();
345 m_pStreamData
->m_xOrigOutStream
->flush();
348 void SAL_CALL
SwitchablePersistenceStream::closeOutput( )
349 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
, std::exception
)
351 ::osl::MutexGuard
aGuard( m_aMutex
);
353 if ( !m_pStreamData
)
354 throw io::NotConnectedException();
356 m_pStreamData
->m_bOutOpen
= false;
357 if ( !m_pStreamData
->m_bInOpen
)
361 // com::sun::star::io::XTruncate
362 void SAL_CALL
SwitchablePersistenceStream::truncate( )
363 throw (io::IOException
, uno::RuntimeException
, std::exception
)
365 ::osl::MutexGuard
aGuard( m_aMutex
);
367 if ( !m_pStreamData
)
368 throw io::NotConnectedException();
370 if ( m_pStreamData
->m_bInStreamBased
)
371 throw io::IOException();
373 // the original stream data should be provided
374 if ( !m_pStreamData
->m_xOrigTruncate
.is() )
375 throw uno::RuntimeException();
377 m_pStreamData
->m_xOrigTruncate
->truncate();
380 // com::sun::star::io::XSeekable
381 void SAL_CALL
SwitchablePersistenceStream::seek( ::sal_Int64 location
)
382 throw (lang::IllegalArgumentException
, io::IOException
, uno::RuntimeException
, std::exception
)
384 ::osl::MutexGuard
aGuard( m_aMutex
);
386 if ( !m_pStreamData
)
387 throw io::NotConnectedException();
389 // the original stream data should be provided
390 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
391 throw uno::RuntimeException();
393 m_pStreamData
->m_xOrigSeekable
->seek( location
);
396 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getPosition( )
397 throw (io::IOException
, uno::RuntimeException
, std::exception
)
399 ::osl::MutexGuard
aGuard( m_aMutex
);
401 if ( !m_pStreamData
)
402 throw io::NotConnectedException();
404 // the original stream data should be provided
405 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
406 throw uno::RuntimeException();
408 return m_pStreamData
->m_xOrigSeekable
->getPosition();
411 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getLength( )
412 throw (io::IOException
, uno::RuntimeException
, std::exception
)
414 ::osl::MutexGuard
aGuard( m_aMutex
);
416 if ( !m_pStreamData
)
417 throw io::NotConnectedException();
419 // the original stream data should be provided
420 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
421 throw uno::RuntimeException();
423 return m_pStreamData
->m_xOrigSeekable
->getLength();
426 void SAL_CALL
SwitchablePersistenceStream::waitForCompletion()
427 throw (::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
, std::exception
)
429 if ( !m_pStreamData
)
430 throw io::NotConnectedException();
432 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( m_pStreamData
->m_xOrigOutStream
, uno::UNO_QUERY
);
433 if ( asyncOutputMonitor
.is() )
434 asyncOutputMonitor
->waitForCompletion();
437 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */