1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: switchpersistencestream.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_package.hxx"
33 #include <osl/diagnose.h>
35 #include <comphelper/storagehelper.hxx>
36 #include <switchpersistencestream.hxx>
38 using namespace ::com::sun::star
;
40 // ========================================================================
41 struct SPStreamData_Impl
43 uno::Reference
< lang::XMultiServiceFactory
> m_xFactory
;
45 sal_Bool m_bInStreamBased
;
47 // the streams below are not visible from outside so there is no need to remember position
49 // original stream related members
50 uno::Reference
< io::XStream
> m_xOrigStream
;
51 uno::Reference
< io::XTruncate
> m_xOrigTruncate
;
52 uno::Reference
< io::XSeekable
> m_xOrigSeekable
;
53 uno::Reference
< io::XInputStream
> m_xOrigInStream
;
54 uno::Reference
< io::XOutputStream
> m_xOrigOutStream
;
61 const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
,
62 sal_Bool bInStreamBased
,
63 const uno::Reference
< io::XStream
>& xOrigStream
,
64 const uno::Reference
< io::XTruncate
>& xOrigTruncate
,
65 const uno::Reference
< io::XSeekable
>& xOrigSeekable
,
66 const uno::Reference
< io::XInputStream
>& xOrigInStream
,
67 const uno::Reference
< io::XOutputStream
>& xOrigOutStream
,
70 : m_xFactory( xFactory
)
71 , m_bInStreamBased( bInStreamBased
)
72 , m_xOrigStream( xOrigStream
)
73 , m_xOrigTruncate( xOrigTruncate
)
74 , m_xOrigSeekable( xOrigSeekable
)
75 , m_xOrigInStream( xOrigInStream
)
76 , m_xOrigOutStream( xOrigOutStream
)
77 , m_bInOpen( bInOpen
)
78 , m_bOutOpen( bOutOpen
)
83 // ========================================================================
84 // ------------------------------------------------------------------------
85 SwitchablePersistenceStream::SwitchablePersistenceStream(
86 const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
,
87 const uno::Reference
< io::XStream
>& xStream
)
88 : m_xFactory( xFactory
)
89 , m_pStreamData( NULL
)
91 SwitchPersistenceTo( xStream
);
94 // ------------------------------------------------------------------------
95 SwitchablePersistenceStream::SwitchablePersistenceStream(
96 const uno::Reference
< lang::XMultiServiceFactory
>& xFactory
,
97 const uno::Reference
< io::XInputStream
>& xInputStream
)
98 : m_xFactory( xFactory
)
99 , m_pStreamData( NULL
)
101 SwitchPersistenceTo( xInputStream
);
104 // ------------------------------------------------------------------------
105 SwitchablePersistenceStream::~SwitchablePersistenceStream()
110 // ------------------------------------------------------------------------
111 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
113 uno::Reference
< io::XTruncate
> xNewTruncate( xStream
, uno::UNO_QUERY_THROW
);
114 uno::Reference
< io::XSeekable
> xNewSeekable( xStream
, uno::UNO_QUERY_THROW
);
115 uno::Reference
< io::XInputStream
> xNewInStream
= xStream
->getInputStream();
116 uno::Reference
< io::XOutputStream
> xNewOutStream
= xStream
->getOutputStream();
117 if ( !xNewInStream
.is() || !xNewOutStream
.is() )
118 throw uno::RuntimeException();
121 sal_Bool bInOpen
= sal_False
;
122 sal_Bool bOutOpen
= sal_False
;
124 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
126 // check that the length is the same
127 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
128 throw uno::RuntimeException();
130 // get the current position
131 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
132 bInOpen
= m_pStreamData
->m_bInOpen
;
133 bOutOpen
= m_pStreamData
->m_bOutOpen
;
136 xNewSeekable
->seek( nPos
);
140 m_pStreamData
= new SPStreamData_Impl( m_xFactory
, sal_False
,
141 xStream
, xNewTruncate
, xNewSeekable
, xNewInStream
, xNewOutStream
,
145 // ------------------------------------------------------------------------
146 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference
< io::XInputStream
>& xInputStream
)
148 uno::Reference
< io::XStream
> xNewStream
;
149 uno::Reference
< io::XTruncate
> xNewTruncate
;
150 uno::Reference
< io::XSeekable
> xNewSeekable( xInputStream
, uno::UNO_QUERY_THROW
);
151 uno::Reference
< io::XOutputStream
> xNewOutStream
;
152 if ( !xInputStream
.is() )
153 throw uno::RuntimeException();
156 sal_Bool bInOpen
= sal_False
;
157 sal_Bool bOutOpen
= sal_False
;
159 if ( m_pStreamData
&& m_pStreamData
->m_xOrigSeekable
.is() )
161 // check that the length is the same
162 if ( m_pStreamData
->m_xOrigSeekable
->getLength() != xNewSeekable
->getLength() )
163 throw uno::RuntimeException();
165 // get the current position
166 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
167 bInOpen
= m_pStreamData
->m_bInOpen
;
168 bOutOpen
= m_pStreamData
->m_bOutOpen
;
171 xNewSeekable
->seek( nPos
);
175 m_pStreamData
= new SPStreamData_Impl( m_xFactory
, sal_True
,
176 xNewStream
, xNewTruncate
, xNewSeekable
, xInputStream
, xNewOutStream
,
181 // ------------------------------------------------------------------------
182 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference
< io::XStream
>& xStream
)
184 uno::Reference
< io::XStream
> xTargetStream
= xStream
;
185 uno::Reference
< io::XSeekable
> xTargetSeek
;
187 if ( !xTargetStream
.is() )
189 xTargetStream
= uno::Reference
< io::XStream
>(
190 m_xFactory
->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
191 uno::UNO_QUERY_THROW
);
193 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
197 // the provided stream must be empty
198 xTargetSeek
= uno::Reference
< io::XSeekable
>( xTargetStream
, uno::UNO_QUERY_THROW
);
199 if ( xTargetSeek
->getLength() )
200 throw io::IOException();
203 uno::Reference
< io::XTruncate
> xTargetTruncate( xTargetStream
, uno::UNO_QUERY_THROW
);
204 uno::Reference
< io::XInputStream
> xTargetInStream
= xTargetStream
->getInputStream();
205 uno::Reference
< io::XOutputStream
> xTargetOutStream
= xTargetStream
->getOutputStream();
206 if ( !xTargetInStream
.is() || !xTargetOutStream
.is() )
207 throw uno::RuntimeException();
209 if ( !m_pStreamData
->m_xOrigInStream
.is() || !m_pStreamData
->m_xOrigSeekable
.is() )
210 throw uno::RuntimeException();
212 sal_Int64 nPos
= m_pStreamData
->m_xOrigSeekable
->getPosition();
213 m_pStreamData
->m_xOrigSeekable
->seek( 0 );
214 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData
->m_xOrigInStream
, xTargetOutStream
);
215 xTargetOutStream
->flush();
216 xTargetSeek
->seek( nPos
);
218 sal_Bool bInOpen
= m_pStreamData
->m_bInOpen
;
219 sal_Bool bOutOpen
= m_pStreamData
->m_bOutOpen
;
223 m_pStreamData
= new SPStreamData_Impl( m_xFactory
, sal_False
,
224 xTargetStream
, xTargetTruncate
, xTargetSeek
, xTargetInStream
, xTargetOutStream
,
228 // ------------------------------------------------------------------------
229 void SwitchablePersistenceStream::CloseAll_Impl()
233 delete m_pStreamData
;
234 m_pStreamData
= NULL
;
238 // com::sun::star::io::XStream
239 // ------------------------------------------------------------------------
240 uno::Reference
< io::XInputStream
> SAL_CALL
SwitchablePersistenceStream::getInputStream( )
241 throw (uno::RuntimeException
)
243 ::osl::MutexGuard
aGuard( m_aMutex
);
246 m_pStreamData
->m_bInOpen
= sal_True
;
247 return static_cast< io::XInputStream
* >( this );
251 // ------------------------------------------------------------------------
252 uno::Reference
< io::XOutputStream
> SAL_CALL
SwitchablePersistenceStream::getOutputStream( )
253 throw (uno::RuntimeException
)
255 ::osl::MutexGuard
aGuard( m_aMutex
);
258 m_pStreamData
->m_bOutOpen
= sal_True
;
259 return static_cast< io::XOutputStream
* >( this );
264 // com::sun::star::io::XInputStream
265 // ------------------------------------------------------------------------
266 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nBytesToRead
)
267 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
269 ::osl::MutexGuard
aGuard( m_aMutex
);
271 if ( !m_pStreamData
)
272 throw io::NotConnectedException();
274 // the original stream data should be provided
275 if ( !m_pStreamData
->m_xOrigInStream
.is() )
276 throw uno::RuntimeException();
278 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nBytesToRead
);
282 // ------------------------------------------------------------------------
283 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::readSomeBytes( uno::Sequence
< ::sal_Int8
>& aData
, ::sal_Int32 nMaxBytesToRead
)
284 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
286 ::osl::MutexGuard
aGuard( m_aMutex
);
288 if ( !m_pStreamData
)
289 throw io::NotConnectedException();
291 // the original stream data should be provided
292 if ( !m_pStreamData
->m_xOrigInStream
.is() )
293 throw uno::RuntimeException();
295 return m_pStreamData
->m_xOrigInStream
->readBytes( aData
, nMaxBytesToRead
);
298 // ------------------------------------------------------------------------
299 void SAL_CALL
SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip
)
300 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
302 ::osl::MutexGuard
aGuard( m_aMutex
);
304 if ( !m_pStreamData
)
305 throw io::NotConnectedException();
307 // the original stream data should be provided
308 if ( !m_pStreamData
->m_xOrigInStream
.is() )
309 throw uno::RuntimeException();
311 m_pStreamData
->m_xOrigInStream
->skipBytes( nBytesToSkip
);
315 // ------------------------------------------------------------------------
316 ::sal_Int32 SAL_CALL
SwitchablePersistenceStream::available( )
317 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
)
319 ::osl::MutexGuard
aGuard( m_aMutex
);
321 if ( !m_pStreamData
)
322 throw io::NotConnectedException();
324 // the original stream data should be provided
325 if ( !m_pStreamData
->m_xOrigInStream
.is() )
326 throw uno::RuntimeException();
328 return m_pStreamData
->m_xOrigInStream
->available();
332 // ------------------------------------------------------------------------
333 void SAL_CALL
SwitchablePersistenceStream::closeInput()
334 throw (io::NotConnectedException
, io::IOException
, uno::RuntimeException
)
336 ::osl::MutexGuard
aGuard( m_aMutex
);
338 if ( !m_pStreamData
)
339 throw io::NotConnectedException();
341 m_pStreamData
->m_bInOpen
= sal_False
;
342 if ( !m_pStreamData
->m_bOutOpen
)
348 // com::sun::star::io::XOutputStream
349 // ------------------------------------------------------------------------
350 void SAL_CALL
SwitchablePersistenceStream::writeBytes( const uno::Sequence
< ::sal_Int8
>& aData
)
351 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
353 ::osl::MutexGuard
aGuard( m_aMutex
);
355 if ( !m_pStreamData
)
356 throw io::NotConnectedException();
358 if ( m_pStreamData
->m_bInStreamBased
)
359 throw io::IOException();
361 // the original stream data should be provided
362 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
363 throw uno::RuntimeException();
365 m_pStreamData
->m_xOrigOutStream
->writeBytes( aData
);
369 // ------------------------------------------------------------------------
370 void SAL_CALL
SwitchablePersistenceStream::flush( )
371 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
373 ::osl::MutexGuard
aGuard( m_aMutex
);
375 if ( !m_pStreamData
|| m_pStreamData
->m_bInStreamBased
)
377 OSL_ENSURE( sal_False
, "flush() is not acceptable!\n" );
379 // in future throw exception, for now some code might call flush() on closed stream
380 // since file ucp implementation allows it
381 // throw io::NotConnectedException();
384 // the original stream data should be provided
385 if ( !m_pStreamData
->m_xOrigOutStream
.is() )
386 throw uno::RuntimeException();
388 m_pStreamData
->m_xOrigOutStream
->flush();
392 // ------------------------------------------------------------------------
393 void SAL_CALL
SwitchablePersistenceStream::closeOutput( )
394 throw (io::NotConnectedException
, io::BufferSizeExceededException
, io::IOException
, uno::RuntimeException
)
396 ::osl::MutexGuard
aGuard( m_aMutex
);
398 if ( !m_pStreamData
)
399 throw io::NotConnectedException();
401 m_pStreamData
->m_bOutOpen
= sal_False
;
402 if ( !m_pStreamData
->m_bInOpen
)
408 // com::sun::star::io::XTruncate
409 // ------------------------------------------------------------------------
410 void SAL_CALL
SwitchablePersistenceStream::truncate( )
411 throw (io::IOException
, uno::RuntimeException
)
413 ::osl::MutexGuard
aGuard( m_aMutex
);
415 if ( !m_pStreamData
)
416 throw io::NotConnectedException();
418 if ( m_pStreamData
->m_bInStreamBased
)
419 throw io::IOException();
421 // the original stream data should be provided
422 if ( !m_pStreamData
->m_xOrigTruncate
.is() )
423 throw uno::RuntimeException();
425 m_pStreamData
->m_xOrigTruncate
->truncate();
429 // com::sun::star::io::XSeekable
430 // ------------------------------------------------------------------------
431 void SAL_CALL
SwitchablePersistenceStream::seek( ::sal_Int64 location
)
432 throw (lang::IllegalArgumentException
, io::IOException
, uno::RuntimeException
)
434 ::osl::MutexGuard
aGuard( m_aMutex
);
436 if ( !m_pStreamData
)
437 throw io::NotConnectedException();
439 // the original stream data should be provided
440 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
441 throw uno::RuntimeException();
443 m_pStreamData
->m_xOrigSeekable
->seek( location
);
447 // ------------------------------------------------------------------------
448 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getPosition( )
449 throw (io::IOException
, uno::RuntimeException
)
451 ::osl::MutexGuard
aGuard( m_aMutex
);
453 if ( !m_pStreamData
)
454 throw io::NotConnectedException();
456 // the original stream data should be provided
457 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
458 throw uno::RuntimeException();
460 return m_pStreamData
->m_xOrigSeekable
->getPosition();
464 // ------------------------------------------------------------------------
465 ::sal_Int64 SAL_CALL
SwitchablePersistenceStream::getLength( )
466 throw (io::IOException
, uno::RuntimeException
)
468 ::osl::MutexGuard
aGuard( m_aMutex
);
470 if ( !m_pStreamData
)
471 throw io::NotConnectedException();
473 // the original stream data should be provided
474 if ( !m_pStreamData
->m_xOrigSeekable
.is() )
475 throw uno::RuntimeException();
477 return m_pStreamData
->m_xOrigSeekable
->getLength();
480 // ------------------------------------------------------------------------
481 void SAL_CALL
SwitchablePersistenceStream::waitForCompletion()
482 throw (::com::sun::star::io::IOException
, ::com::sun::star::uno::RuntimeException
)
484 if ( !m_pStreamData
)
485 throw io::NotConnectedException();
487 uno::Reference
< io::XAsyncOutputMonitor
> asyncOutputMonitor( m_pStreamData
->m_xOrigOutStream
, uno::UNO_QUERY
);
488 if ( asyncOutputMonitor
.is() )
489 asyncOutputMonitor
->waitForCompletion();