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