xref: /AOO41X/main/package/source/xstor/switchpersistencestream.cxx (revision a38728232e8c39f9058a1a2aa8ee4e6db7b8ca34)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 #include <osl/diagnose.h>
27 
28 #include <comphelper/storagehelper.hxx>
29 #include <switchpersistencestream.hxx>
30 
31 using namespace ::com::sun::star;
32 
33 // ========================================================================
34 struct SPStreamData_Impl
35 {
36     uno::Reference< lang::XMultiServiceFactory > m_xFactory;
37 
38     sal_Bool m_bInStreamBased;
39 
40     // the streams below are not visible from outside so there is no need to remember position
41 
42     // original stream related members
43     uno::Reference< io::XStream > m_xOrigStream;
44     uno::Reference< io::XTruncate > m_xOrigTruncate;
45     uno::Reference< io::XSeekable > m_xOrigSeekable;
46     uno::Reference< io::XInputStream > m_xOrigInStream;
47     uno::Reference< io::XOutputStream > m_xOrigOutStream;
48 
49     sal_Bool m_bInOpen;
50     sal_Bool m_bOutOpen;
51 
52 
SPStreamData_ImplSPStreamData_Impl53     SPStreamData_Impl(
54             const uno::Reference< lang::XMultiServiceFactory >& xFactory,
55             sal_Bool bInStreamBased,
56             const uno::Reference< io::XStream >& xOrigStream,
57             const uno::Reference< io::XTruncate >& xOrigTruncate,
58             const uno::Reference< io::XSeekable >& xOrigSeekable,
59             const uno::Reference< io::XInputStream >& xOrigInStream,
60             const uno::Reference< io::XOutputStream >& xOrigOutStream,
61             sal_Bool bInOpen,
62             sal_Bool bOutOpen )
63     : m_xFactory( xFactory )
64     , m_bInStreamBased( bInStreamBased )
65     , m_xOrigStream( xOrigStream )
66     , m_xOrigTruncate( xOrigTruncate )
67     , m_xOrigSeekable( xOrigSeekable )
68     , m_xOrigInStream( xOrigInStream )
69     , m_xOrigOutStream( xOrigOutStream )
70     , m_bInOpen( bInOpen )
71     , m_bOutOpen( bOutOpen )
72     {
73     }
74 };
75 
76 // ========================================================================
77 // ------------------------------------------------------------------------
SwitchablePersistenceStream(const uno::Reference<lang::XMultiServiceFactory> & xFactory,const uno::Reference<io::XStream> & xStream)78 SwitchablePersistenceStream::SwitchablePersistenceStream(
79         const uno::Reference< lang::XMultiServiceFactory >& xFactory,
80         const uno::Reference< io::XStream >& xStream )
81 : m_xFactory( xFactory )
82 , m_pStreamData( NULL )
83 {
84     SwitchPersistenceTo( xStream );
85 }
86 
87 // ------------------------------------------------------------------------
SwitchablePersistenceStream(const uno::Reference<lang::XMultiServiceFactory> & xFactory,const uno::Reference<io::XInputStream> & xInputStream)88 SwitchablePersistenceStream::SwitchablePersistenceStream(
89         const uno::Reference< lang::XMultiServiceFactory >& xFactory,
90         const uno::Reference< io::XInputStream >& xInputStream )
91 : m_xFactory( xFactory )
92 , m_pStreamData( NULL )
93 {
94     SwitchPersistenceTo( xInputStream );
95 }
96 
97 // ------------------------------------------------------------------------
~SwitchablePersistenceStream()98 SwitchablePersistenceStream::~SwitchablePersistenceStream()
99 {
100     CloseAll_Impl();
101 }
102 
103 // ------------------------------------------------------------------------
SwitchPersistenceTo(const uno::Reference<io::XStream> & xStream)104 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
105 {
106     uno::Reference< io::XTruncate > xNewTruncate( xStream, uno::UNO_QUERY_THROW );
107     uno::Reference< io::XSeekable > xNewSeekable( xStream, uno::UNO_QUERY_THROW );
108     uno::Reference< io::XInputStream > xNewInStream = xStream->getInputStream();
109     uno::Reference< io::XOutputStream > xNewOutStream = xStream->getOutputStream();
110     if ( !xNewInStream.is() || !xNewOutStream.is() )
111         throw uno::RuntimeException();
112 
113     sal_Int64 nPos = 0;
114     sal_Bool bInOpen = sal_False;
115     sal_Bool bOutOpen = sal_False;
116 
117     if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
118     {
119         // check that the length is the same
120         if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
121             throw uno::RuntimeException();
122 
123         // get the current position
124         nPos = m_pStreamData->m_xOrigSeekable->getPosition();
125         bInOpen = m_pStreamData->m_bInOpen;
126         bOutOpen = m_pStreamData->m_bOutOpen;
127     }
128 
129     xNewSeekable->seek( nPos );
130 
131     CloseAll_Impl();
132 
133     m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False,
134                                             xStream, xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream,
135                                             bInOpen, bOutOpen );
136 }
137 
138 // ------------------------------------------------------------------------
SwitchPersistenceTo(const uno::Reference<io::XInputStream> & xInputStream)139 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream )
140 {
141     uno::Reference< io::XStream > xNewStream;
142     uno::Reference< io::XTruncate > xNewTruncate;
143     uno::Reference< io::XSeekable > xNewSeekable( xInputStream, uno::UNO_QUERY_THROW );
144     uno::Reference< io::XOutputStream > xNewOutStream;
145     if ( !xInputStream.is() )
146         throw uno::RuntimeException();
147 
148     sal_Int64 nPos = 0;
149     sal_Bool bInOpen = sal_False;
150     sal_Bool bOutOpen = sal_False;
151 
152     if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
153     {
154         // check that the length is the same
155         if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
156             throw uno::RuntimeException();
157 
158         // get the current position
159         nPos = m_pStreamData->m_xOrigSeekable->getPosition();
160         bInOpen = m_pStreamData->m_bInOpen;
161         bOutOpen = m_pStreamData->m_bOutOpen;
162     }
163 
164     xNewSeekable->seek( nPos );
165 
166     CloseAll_Impl();
167 
168     m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_True,
169                                             xNewStream, xNewTruncate, xNewSeekable, xInputStream, xNewOutStream,
170                                             bInOpen, bOutOpen );
171 
172 }
173 
174 // ------------------------------------------------------------------------
CopyAndSwitchPersistenceTo(const uno::Reference<io::XStream> & xStream)175 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
176 {
177     uno::Reference< io::XStream > xTargetStream = xStream;
178     uno::Reference< io::XSeekable > xTargetSeek;
179 
180     if ( !xTargetStream.is() )
181     {
182         xTargetStream = uno::Reference < io::XStream >(
183             m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
184             uno::UNO_QUERY_THROW );
185 
186         xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW );
187     }
188     else
189     {
190         // the provided stream must be empty
191         xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW );
192         if ( xTargetSeek->getLength() )
193             throw io::IOException();
194     }
195 
196     uno::Reference< io::XTruncate > xTargetTruncate( xTargetStream, uno::UNO_QUERY_THROW );
197     uno::Reference< io::XInputStream > xTargetInStream = xTargetStream->getInputStream();
198     uno::Reference< io::XOutputStream > xTargetOutStream = xTargetStream->getOutputStream();
199     if ( !xTargetInStream.is() || !xTargetOutStream.is() )
200         throw uno::RuntimeException();
201 
202     if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() )
203         throw uno::RuntimeException();
204 
205     sal_Int64 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
206     m_pStreamData->m_xOrigSeekable->seek( 0 );
207     ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData->m_xOrigInStream, xTargetOutStream );
208     xTargetOutStream->flush();
209     xTargetSeek->seek( nPos );
210 
211     sal_Bool bInOpen = m_pStreamData->m_bInOpen;
212     sal_Bool bOutOpen = m_pStreamData->m_bOutOpen;
213 
214     CloseAll_Impl();
215 
216     m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False,
217                                         xTargetStream, xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream,
218                                         bInOpen, bOutOpen );
219 }
220 
221 // ------------------------------------------------------------------------
CloseAll_Impl()222 void SwitchablePersistenceStream::CloseAll_Impl()
223 {
224     if ( m_pStreamData )
225     {
226         delete m_pStreamData;
227         m_pStreamData = NULL;
228     }
229 }
230 
231 // com::sun::star::io::XStream
232 // ------------------------------------------------------------------------
getInputStream()233 uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream(  )
234     throw (uno::RuntimeException)
235 {
236     ::osl::MutexGuard aGuard( m_aMutex );
237 
238     if ( m_pStreamData )
239         m_pStreamData->m_bInOpen = sal_True;
240     return static_cast< io::XInputStream* >( this );
241 }
242 
243 
244 // ------------------------------------------------------------------------
getOutputStream()245 uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream(  )
246     throw (uno::RuntimeException)
247 {
248     ::osl::MutexGuard aGuard( m_aMutex );
249 
250     if ( m_pStreamData )
251         m_pStreamData->m_bOutOpen = sal_True;
252     return static_cast< io::XOutputStream* >( this );
253 }
254 
255 
256 
257 // com::sun::star::io::XInputStream
258 // ------------------------------------------------------------------------
readBytes(uno::Sequence<::sal_Int8> & aData,::sal_Int32 nBytesToRead)259 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead )
260     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
261 {
262     ::osl::MutexGuard aGuard( m_aMutex );
263 
264     if ( !m_pStreamData )
265         throw io::NotConnectedException();
266 
267     // the original stream data should be provided
268     if ( !m_pStreamData->m_xOrigInStream.is() )
269         throw uno::RuntimeException();
270 
271     return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead );
272 }
273 
274 
275 // ------------------------------------------------------------------------
readSomeBytes(uno::Sequence<::sal_Int8> & aData,::sal_Int32 nMaxBytesToRead)276 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead )
277     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
278 {
279     ::osl::MutexGuard aGuard( m_aMutex );
280 
281     if ( !m_pStreamData )
282         throw io::NotConnectedException();
283 
284     // the original stream data should be provided
285     if ( !m_pStreamData->m_xOrigInStream.is() )
286         throw uno::RuntimeException();
287 
288     return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead );
289 }
290 
291 // ------------------------------------------------------------------------
skipBytes(::sal_Int32 nBytesToSkip)292 void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip )
293     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
294 {
295     ::osl::MutexGuard aGuard( m_aMutex );
296 
297     if ( !m_pStreamData )
298         throw io::NotConnectedException();
299 
300     // the original stream data should be provided
301     if ( !m_pStreamData->m_xOrigInStream.is() )
302         throw uno::RuntimeException();
303 
304     m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip );
305 }
306 
307 
308 // ------------------------------------------------------------------------
available()309 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::available(  )
310     throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
311 {
312     ::osl::MutexGuard aGuard( m_aMutex );
313 
314     if ( !m_pStreamData )
315         throw io::NotConnectedException();
316 
317     // the original stream data should be provided
318     if ( !m_pStreamData->m_xOrigInStream.is() )
319         throw uno::RuntimeException();
320 
321     return m_pStreamData->m_xOrigInStream->available();
322 }
323 
324 
325 // ------------------------------------------------------------------------
closeInput()326 void SAL_CALL SwitchablePersistenceStream::closeInput()
327     throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
328 {
329     ::osl::MutexGuard aGuard( m_aMutex );
330 
331     if ( !m_pStreamData )
332         throw io::NotConnectedException();
333 
334     m_pStreamData->m_bInOpen = sal_False;
335     if ( !m_pStreamData->m_bOutOpen )
336         CloseAll_Impl();
337 }
338 
339 
340 
341 // com::sun::star::io::XOutputStream
342 // ------------------------------------------------------------------------
writeBytes(const uno::Sequence<::sal_Int8> & aData)343 void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData )
344     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
345 {
346     ::osl::MutexGuard aGuard( m_aMutex );
347 
348     if ( !m_pStreamData )
349         throw io::NotConnectedException();
350 
351     if ( m_pStreamData->m_bInStreamBased )
352         throw io::IOException();
353 
354     // the original stream data should be provided
355     if ( !m_pStreamData->m_xOrigOutStream.is() )
356         throw uno::RuntimeException();
357 
358     m_pStreamData->m_xOrigOutStream->writeBytes( aData );
359 }
360 
361 
362 // ------------------------------------------------------------------------
flush()363 void SAL_CALL SwitchablePersistenceStream::flush(  )
364     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
365 {
366     ::osl::MutexGuard aGuard( m_aMutex );
367 
368     if ( !m_pStreamData || m_pStreamData->m_bInStreamBased )
369     {
370         OSL_ENSURE( sal_False, "flush() is not acceptable!\n" );
371         return;
372         // in future throw exception, for now some code might call flush() on closed stream
373         // since file ucp implementation allows it
374         // throw io::NotConnectedException();
375     }
376 
377     // the original stream data should be provided
378     if ( !m_pStreamData->m_xOrigOutStream.is() )
379         throw uno::RuntimeException();
380 
381     m_pStreamData->m_xOrigOutStream->flush();
382 }
383 
384 
385 // ------------------------------------------------------------------------
closeOutput()386 void SAL_CALL SwitchablePersistenceStream::closeOutput(  )
387     throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
388 {
389     ::osl::MutexGuard aGuard( m_aMutex );
390 
391     if ( !m_pStreamData )
392         throw io::NotConnectedException();
393 
394     m_pStreamData->m_bOutOpen = sal_False;
395     if ( !m_pStreamData->m_bInOpen )
396         CloseAll_Impl();
397 }
398 
399 
400 
401 // com::sun::star::io::XTruncate
402 // ------------------------------------------------------------------------
truncate()403 void SAL_CALL SwitchablePersistenceStream::truncate(  )
404     throw (io::IOException, uno::RuntimeException)
405 {
406     ::osl::MutexGuard aGuard( m_aMutex );
407 
408     if ( !m_pStreamData )
409         throw io::NotConnectedException();
410 
411     if ( m_pStreamData->m_bInStreamBased )
412         throw io::IOException();
413 
414     // the original stream data should be provided
415     if ( !m_pStreamData->m_xOrigTruncate.is() )
416         throw uno::RuntimeException();
417 
418     m_pStreamData->m_xOrigTruncate->truncate();
419 }
420 
421 
422 // com::sun::star::io::XSeekable
423 // ------------------------------------------------------------------------
seek(::sal_Int64 location)424 void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location )
425     throw (lang::IllegalArgumentException, io::IOException, uno::RuntimeException)
426 {
427     ::osl::MutexGuard aGuard( m_aMutex );
428 
429     if ( !m_pStreamData )
430         throw io::NotConnectedException();
431 
432     // the original stream data should be provided
433     if ( !m_pStreamData->m_xOrigSeekable.is() )
434         throw uno::RuntimeException();
435 
436     m_pStreamData->m_xOrigSeekable->seek( location );
437 }
438 
439 
440 // ------------------------------------------------------------------------
getPosition()441 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getPosition(  )
442     throw (io::IOException, uno::RuntimeException)
443 {
444     ::osl::MutexGuard aGuard( m_aMutex );
445 
446     if ( !m_pStreamData )
447         throw io::NotConnectedException();
448 
449     // the original stream data should be provided
450     if ( !m_pStreamData->m_xOrigSeekable.is() )
451         throw uno::RuntimeException();
452 
453     return m_pStreamData->m_xOrigSeekable->getPosition();
454 }
455 
456 
457 // ------------------------------------------------------------------------
getLength()458 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getLength(  )
459     throw (io::IOException, uno::RuntimeException)
460 {
461     ::osl::MutexGuard aGuard( m_aMutex );
462 
463     if ( !m_pStreamData )
464         throw io::NotConnectedException();
465 
466     // the original stream data should be provided
467     if ( !m_pStreamData->m_xOrigSeekable.is() )
468         throw uno::RuntimeException();
469 
470     return m_pStreamData->m_xOrigSeekable->getLength();
471 }
472 
473 // ------------------------------------------------------------------------
waitForCompletion()474 void SAL_CALL SwitchablePersistenceStream::waitForCompletion()
475     throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException)
476 {
477     if ( !m_pStreamData )
478         throw io::NotConnectedException();
479 
480     uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY );
481     if ( asyncOutputMonitor.is() )
482         asyncOutputMonitor->waitForCompletion();
483 }
484 
485