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