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