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 // ========================================================================
30 struct SPStreamData_Impl
32 sal_Bool m_bInStreamBased
;
34 // the streams below are not visible from outside so there is no need to remember position
36 // original stream related members
37 uno::Reference
< io::XStream
> m_xOrigStream
;
38 uno::Reference
< io::XTruncate
> m_xOrigTruncate
;
39 uno::Reference
< io::XSeekable
> m_xOrigSeekable
;
40 uno::Reference
< io::XInputStream
> m_xOrigInStream
;
41 uno::Reference
< io::XOutputStream
> m_xOrigOutStream
;
48 sal_Bool bInStreamBased
,
49 const uno::Reference
< io::XStream
>& xOrigStream
,
50 const uno::Reference
< io::XTruncate
>& xOrigTruncate
,
51 const uno::Reference
< io::XSeekable
>& xOrigSeekable
,
52 const uno::Reference
< io::XInputStream
>& xOrigInStream
,
53 const uno::Reference
< io::XOutputStream
>& xOrigOutStream
,
56 : m_bInStreamBased( bInStreamBased
)
57 , m_xOrigStream( xOrigStream
)
58 , m_xOrigTruncate( xOrigTruncate
)
59 , m_xOrigSeekable( xOrigSeekable
)
60 , m_xOrigInStream( xOrigInStream
)
61 , m_xOrigOutStream( xOrigOutStream
)
62 , m_bInOpen( bInOpen
)
63 , m_bOutOpen( bOutOpen
)
68 // ========================================================================
69 // ------------------------------------------------------------------------
70 SwitchablePersistenceStream::SwitchablePersistenceStream(
71 const uno::Reference
< uno::XComponentContext
>& xContext
,
72 const uno::Reference
< io::XStream
>& xStream
)
73 : m_xContext( xContext
)
74 , m_pStreamData( NULL
)
76 SwitchPersistenceTo( xStream
);
79 // ------------------------------------------------------------------------
80 SwitchablePersistenceStream::SwitchablePersistenceStream(
81 const uno::Reference
< uno::XComponentContext
>& xContext
,
82 const uno::Reference
< io::XInputStream
>& xInputStream
)
83 : m_xContext( xContext
)
84 , m_pStreamData( NULL
)
86 SwitchPersistenceTo( xInputStream
);
89 // ------------------------------------------------------------------------
90 SwitchablePersistenceStream::~SwitchablePersistenceStream()
95 // ------------------------------------------------------------------------
96 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
98 uno::Reference
< io::XTruncate
> xNewTruncate( xStream
, uno::UNO_QUERY_THROW
);
99 uno::Reference
< io::XSeekable
> xNewSeekable( xStream
, uno::UNO_QUERY_THROW
);
100 uno::Reference
< io::XInputStream
> xNewInStream
= xStream
->getInputStream();
101 uno::Reference
< io::XOutputStream
> xNewOutStream
= xStream
->getOutputStream();
102 if ( !xNewInStream
.is() || !xNewOutStream
.is() )
103 throw uno::RuntimeException();
106 sal_Bool bInOpen
= sal_False
;
107 sal_Bool bOutOpen
= sal_False
;
109 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
111 // check that the length is the same
112 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
113 throw uno::RuntimeException();
115 // get the current position
116 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
117 bInOpen
= m_pStreamData
->m_bInOpen
;
118 bOutOpen
= m_pStreamData
->m_bOutOpen
;
121 xNewSeekable
->seek( nPos
);
125 m_pStreamData
= new SPStreamData_Impl( sal_False
,
126 xStream
, xNewTruncate
, xNewSeekable
, xNewInStream
, xNewOutStream
,
130 // ------------------------------------------------------------------------
131 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XInputStream
>& xInputStream
)
133 uno::Reference
< io::XStream
> xNewStream
;
134 uno::Reference
< io::XTruncate
> xNewTruncate
;
135 uno::Reference
< io::XSeekable
> xNewSeekable( xInputStream
, uno::UNO_QUERY_THROW
);
136 uno::Reference
< io::XOutputStream
> xNewOutStream
;
137 if ( !xInputStream
.is() )
138 throw uno::RuntimeException();
141 sal_Bool bInOpen
= sal_False
;
142 sal_Bool bOutOpen
= sal_False
;
144 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
146 // check that the length is the same
147 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
148 throw uno::RuntimeException();
150 // get the current position
151 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
152 bInOpen
= m_pStreamData
->m_bInOpen
;
153 bOutOpen
= m_pStreamData
->m_bOutOpen
;
156 xNewSeekable
->seek( nPos
);
160 m_pStreamData
= new SPStreamData_Impl( sal_True
,
161 xNewStream
, xNewTruncate
, xNewSeekable
, xInputStream
, xNewOutStream
,
166 // ------------------------------------------------------------------------
167 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
169 uno::Reference
< io::XStream
> xTargetStream
= xStream
;
170 uno::Reference
< io::XSeekable
> xTargetSeek
;
172 if ( !xTargetStream
.is() )
174 xTargetStream
= uno::Reference
< io::XStream
>(
175 io::TempFile::create(m_xContext
),
176 uno::UNO_QUERY_THROW
);
178 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
182 // the provided stream must be empty
183 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
184 if ( xTargetSeek
->getLength() )
185 throw io::IOException();
188 uno::Reference
< io::XTruncate
> xTargetTruncate( xTargetStream
, uno::UNO_QUERY_THROW
);
189 uno::Reference
< io::XInputStream
> xTargetInStream
= xTargetStream
->getInputStream();
190 uno::Reference
< io::XOutputStream
> xTargetOutStream
= xTargetStream
->getOutputStream();
191 if ( !xTargetInStream
.is() || !xTargetOutStream
.is() )
192 throw uno::RuntimeException();
194 if ( !m_pStreamData
->m_xOrigInStream
.is() || !m_pStreamData
->m_xOrigSeekable
.is() )
195 throw uno::RuntimeException();
197 sal_Int64 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
198 m_pStreamData
->m_xOrigSeekable
->seek( 0 );
199 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData
->m_xOrigInStream
, xTargetOutStream
);
200 xTargetOutStream
->flush();
201 xTargetSeek
->seek( nPos
);
203 sal_Bool bInOpen
= m_pStreamData
->m_bInOpen
;
204 sal_Bool bOutOpen
= m_pStreamData
->m_bOutOpen
;
208 m_pStreamData
= new SPStreamData_Impl( sal_False
,
209 xTargetStream
, xTargetTruncate
, xTargetSeek
, xTargetInStream
, xTargetOutStream
,
213 // ------------------------------------------------------------------------
214 void SwitchablePersistenceStream::CloseAll_Impl()
218 delete m_pStreamData
;
219 m_pStreamData
= NULL
;
223 // com::sun::star::io::XStream
224 // ------------------------------------------------------------------------
225 uno::Reference
< io::XInputStream
> SAL_CALL
SwitchablePersistenceStream::getInputStream( )
226 throw (uno::RuntimeException
)
228 ::osl::MutexGuard
aGuard( m_aMutex
);
231 m_pStreamData
->m_bInOpen
= sal_True
;
232 return static_cast< io::XInputStream
* >( this );
236 // ------------------------------------------------------------------------
237 uno::Reference
< io::XOutputStream
> SAL_CALL
SwitchablePersistenceStream::getOutputStream( )
238 throw (uno::RuntimeException
)
240 ::osl::MutexGuard
aGuard( m_aMutex
);
243 m_pStreamData
->m_bOutOpen
= sal_True
;
244 return static_cast< io::XOutputStream
* >( this );
249 // com::sun::star::io::XInputStream
250 // ------------------------------------------------------------------------
251 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nBytesToRead
)
252 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
254 ::osl::MutexGuard
aGuard( m_aMutex
);
256 if ( !m_pStreamData
)
257 throw io::NotConnectedException();
259 // the original stream data should be provided
260 if ( !m_pStreamData
->m_xOrigInStream
.is() )
261 throw uno::RuntimeException();
263 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nBytesToRead
);
267 // ------------------------------------------------------------------------
268 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readSomeBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nMaxBytesToRead
)
269 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
271 ::osl::MutexGuard
aGuard( m_aMutex
);
273 if ( !m_pStreamData
)
274 throw io::NotConnectedException();
276 // the original stream data should be provided
277 if ( !m_pStreamData
->m_xOrigInStream
.is() )
278 throw uno::RuntimeException();
280 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nMaxBytesToRead
);
283 // ------------------------------------------------------------------------
284 void SAL_CALL
SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip
)
285 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
287 ::osl::MutexGuard
aGuard( m_aMutex
);
289 if ( !m_pStreamData
)
290 throw io::NotConnectedException();
292 // the original stream data should be provided
293 if ( !m_pStreamData
->m_xOrigInStream
.is() )
294 throw uno::RuntimeException();
296 m_pStreamData
->m_xOrigInStream
->skipBytes( nBytesToSkip
);
300 // ------------------------------------------------------------------------
301 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::available( )
302 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
)
304 ::osl::MutexGuard
aGuard( m_aMutex
);
306 if ( !m_pStreamData
)
307 throw io::NotConnectedException();
309 // the original stream data should be provided
310 if ( !m_pStreamData
->m_xOrigInStream
.is() )
311 throw uno::RuntimeException();
313 return m_pStreamData
->m_xOrigInStream
->available();
317 // ------------------------------------------------------------------------
318 void SAL_CALL
SwitchablePersistenceStream::closeInput()
319 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
)
321 ::osl::MutexGuard
aGuard( m_aMutex
);
323 if ( !m_pStreamData
)
324 throw io::NotConnectedException();
326 m_pStreamData
->m_bInOpen
= sal_False
;
327 if ( !m_pStreamData
->m_bOutOpen
)
333 // com::sun::star::io::XOutputStream
334 // ------------------------------------------------------------------------
335 void SAL_CALL
SwitchablePersistenceStream::writeBytes( const uno::Sequence
< ::sal_Int8
>& aData
)
336 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
338 ::osl::MutexGuard
aGuard( m_aMutex
);
340 if ( !m_pStreamData
)
341 throw io::NotConnectedException();
343 if ( m_pStreamData
->m_bInStreamBased
)
344 throw io::IOException();
346 // the original stream data should be provided
347 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
348 throw uno::RuntimeException();
350 m_pStreamData
->m_xOrigOutStream
->writeBytes( aData
);
354 // ------------------------------------------------------------------------
355 void SAL_CALL
SwitchablePersistenceStream::flush( )
356 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
358 ::osl::MutexGuard
aGuard( m_aMutex
);
360 if ( !m_pStreamData
|| m_pStreamData
->m_bInStreamBased
)
362 OSL_FAIL( "flush() is not acceptable!\n" );
364 // in future throw exception, for now some code might call flush() on closed stream
365 // since file ucp implementation allows it
366 // throw io::NotConnectedException();
369 // the original stream data should be provided
370 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
371 throw uno::RuntimeException();
373 m_pStreamData
->m_xOrigOutStream
->flush();
377 // ------------------------------------------------------------------------
378 void SAL_CALL
SwitchablePersistenceStream::closeOutput( )
379 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
381 ::osl::MutexGuard
aGuard( m_aMutex
);
383 if ( !m_pStreamData
)
384 throw io::NotConnectedException();
386 m_pStreamData
->m_bOutOpen
= sal_False
;
387 if ( !m_pStreamData
->m_bInOpen
)
393 // com::sun::star::io::XTruncate
394 // ------------------------------------------------------------------------
395 void SAL_CALL
SwitchablePersistenceStream::truncate( )
396 throw (io::IOException
, uno::RuntimeException
)
398 ::osl::MutexGuard
aGuard( m_aMutex
);
400 if ( !m_pStreamData
)
401 throw io::NotConnectedException();
403 if ( m_pStreamData
->m_bInStreamBased
)
404 throw io::IOException();
406 // the original stream data should be provided
407 if ( !m_pStreamData
->m_xOrigTruncate
.is() )
408 throw uno::RuntimeException();
410 m_pStreamData
->m_xOrigTruncate
->truncate();
414 // com::sun::star::io::XSeekable
415 // ------------------------------------------------------------------------
416 void SAL_CALL
SwitchablePersistenceStream::seek( ::sal_Int64 location
)
417 throw (lang::IllegalArgumentException
, io::IOException
, uno::RuntimeException
)
419 ::osl::MutexGuard
aGuard( m_aMutex
);
421 if ( !m_pStreamData
)
422 throw io::NotConnectedException();
424 // the original stream data should be provided
425 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
426 throw uno::RuntimeException();
428 m_pStreamData
->m_xOrigSeekable
->seek( location
);
432 // ------------------------------------------------------------------------
433 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getPosition( )
434 throw (io::IOException
, uno::RuntimeException
)
436 ::osl::MutexGuard
aGuard( m_aMutex
);
438 if ( !m_pStreamData
)
439 throw io::NotConnectedException();
441 // the original stream data should be provided
442 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
443 throw uno::RuntimeException();
445 return m_pStreamData
->m_xOrigSeekable
->getPosition();
449 // ------------------------------------------------------------------------
450 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getLength( )
451 throw (io::IOException
, uno::RuntimeException
)
453 ::osl::MutexGuard
aGuard( m_aMutex
);
455 if ( !m_pStreamData
)
456 throw io::NotConnectedException();
458 // the original stream data should be provided
459 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
460 throw uno::RuntimeException();
462 return m_pStreamData
->m_xOrigSeekable
->getLength();
465 // ------------------------------------------------------------------------
466 void SAL_CALL
SwitchablePersistenceStream::waitForCompletion()
467 throw (::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
469 if ( !m_pStreamData
)
470 throw io::NotConnectedException();
472 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( m_pStreamData
->m_xOrigOutStream
, uno::UNO_QUERY
);
473 if ( asyncOutputMonitor
.is() )
474 asyncOutputMonitor
->waitForCompletion();
477 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */