Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / package / source / xstor / switchpersistencestream.cxx
blobb85be26f7eb66dd2a92788471ae37753bd706f29
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <osl/diagnose.h>
21 #include <com/sun/star/io/IOException.hpp>
22 #include <com/sun/star/io/NotConnectedException.hpp>
23 #include <com/sun/star/io/TempFile.hpp>
24 #include <comphelper/storagehelper.hxx>
25 #include "switchpersistencestream.hxx"
27 using namespace ::com::sun::star;
29 struct SPStreamData_Impl
31 bool m_bInStreamBased;
33 // the streams below are not visible from outside so there is no need to remember position
35 // original stream related members
36 uno::Reference< io::XTruncate > m_xOrigTruncate;
37 uno::Reference< io::XSeekable > m_xOrigSeekable;
38 uno::Reference< io::XInputStream > m_xOrigInStream;
39 uno::Reference< io::XOutputStream > m_xOrigOutStream;
41 bool m_bInOpen;
42 bool m_bOutOpen;
44 SPStreamData_Impl(
45 bool bInStreamBased,
46 const uno::Reference< io::XTruncate >& xOrigTruncate,
47 const uno::Reference< io::XSeekable >& xOrigSeekable,
48 const uno::Reference< io::XInputStream >& xOrigInStream,
49 const uno::Reference< io::XOutputStream >& xOrigOutStream,
50 bool bInOpen,
51 bool bOutOpen )
52 : m_bInStreamBased( bInStreamBased )
53 , m_xOrigTruncate( xOrigTruncate )
54 , m_xOrigSeekable( xOrigSeekable )
55 , m_xOrigInStream( xOrigInStream )
56 , m_xOrigOutStream( xOrigOutStream )
57 , m_bInOpen( bInOpen )
58 , m_bOutOpen( bOutOpen )
63 SwitchablePersistenceStream::SwitchablePersistenceStream(
64 const uno::Reference< uno::XComponentContext >& xContext,
65 const uno::Reference< io::XStream >& xStream )
66 : m_xContext( xContext )
67 , m_pStreamData( nullptr )
69 SwitchPersistenceTo( xStream );
72 SwitchablePersistenceStream::SwitchablePersistenceStream(
73 const uno::Reference< uno::XComponentContext >& xContext,
74 const uno::Reference< io::XInputStream >& xInputStream )
75 : m_xContext( xContext )
76 , m_pStreamData( nullptr )
78 SwitchPersistenceTo( xInputStream );
81 SwitchablePersistenceStream::~SwitchablePersistenceStream()
83 CloseAll_Impl();
86 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
88 uno::Reference< io::XTruncate > xNewTruncate( xStream, uno::UNO_QUERY_THROW );
89 uno::Reference< io::XSeekable > xNewSeekable( xStream, uno::UNO_QUERY_THROW );
90 uno::Reference< io::XInputStream > xNewInStream = xStream->getInputStream();
91 uno::Reference< io::XOutputStream > xNewOutStream = xStream->getOutputStream();
92 if ( !xNewInStream.is() || !xNewOutStream.is() )
93 throw uno::RuntimeException();
95 sal_Int64 nPos = 0;
96 bool bInOpen = false;
97 bool bOutOpen = false;
99 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
101 // check that the length is the same
102 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
103 throw uno::RuntimeException();
105 // get the current position
106 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
107 bInOpen = m_pStreamData->m_bInOpen;
108 bOutOpen = m_pStreamData->m_bOutOpen;
111 xNewSeekable->seek( nPos );
113 CloseAll_Impl();
115 m_pStreamData.reset( new SPStreamData_Impl( false,
116 xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream,
117 bInOpen, bOutOpen ) );
120 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream )
122 uno::Reference< io::XTruncate > xNewTruncate;
123 uno::Reference< io::XSeekable > xNewSeekable( xInputStream, uno::UNO_QUERY_THROW );
124 uno::Reference< io::XOutputStream > xNewOutStream;
125 if ( !xInputStream.is() )
126 throw uno::RuntimeException();
128 sal_Int64 nPos = 0;
129 bool bInOpen = false;
130 bool bOutOpen = false;
132 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
134 // check that the length is the same
135 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
136 throw uno::RuntimeException();
138 // get the current position
139 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
140 bInOpen = m_pStreamData->m_bInOpen;
141 bOutOpen = m_pStreamData->m_bOutOpen;
144 xNewSeekable->seek( nPos );
146 CloseAll_Impl();
148 m_pStreamData.reset( new SPStreamData_Impl( true,
149 xNewTruncate, xNewSeekable, xInputStream, xNewOutStream,
150 bInOpen, bOutOpen ) );
154 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
156 uno::Reference< io::XStream > xTargetStream = xStream;
157 uno::Reference< io::XSeekable > xTargetSeek;
159 if ( !xTargetStream.is() )
161 xTargetStream.set( io::TempFile::create(m_xContext), uno::UNO_QUERY_THROW );
162 xTargetSeek.set( xTargetStream, uno::UNO_QUERY_THROW );
164 else
166 // the provided stream must be empty
167 xTargetSeek.set( xTargetStream, uno::UNO_QUERY_THROW );
168 if ( xTargetSeek->getLength() )
169 throw io::IOException();
172 uno::Reference< io::XTruncate > xTargetTruncate( xTargetStream, uno::UNO_QUERY_THROW );
173 uno::Reference< io::XInputStream > xTargetInStream = xTargetStream->getInputStream();
174 uno::Reference< io::XOutputStream > xTargetOutStream = xTargetStream->getOutputStream();
175 if ( !xTargetInStream.is() || !xTargetOutStream.is() )
176 throw uno::RuntimeException();
178 if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() )
179 throw uno::RuntimeException();
181 sal_Int64 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
182 m_pStreamData->m_xOrigSeekable->seek( 0 );
183 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData->m_xOrigInStream, xTargetOutStream );
184 xTargetOutStream->flush();
185 xTargetSeek->seek( nPos );
187 bool bInOpen = m_pStreamData->m_bInOpen;
188 bool bOutOpen = m_pStreamData->m_bOutOpen;
190 CloseAll_Impl();
192 m_pStreamData.reset( new SPStreamData_Impl( false,
193 xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream,
194 bInOpen, bOutOpen ) );
197 void SwitchablePersistenceStream::CloseAll_Impl()
199 m_pStreamData.reset();
202 // css::io::XStream
203 uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream( )
205 ::osl::MutexGuard aGuard( m_aMutex );
207 if ( m_pStreamData )
208 m_pStreamData->m_bInOpen = true;
209 return static_cast< io::XInputStream* >( this );
212 uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream( )
214 ::osl::MutexGuard aGuard( m_aMutex );
216 if ( m_pStreamData )
217 m_pStreamData->m_bOutOpen = true;
218 return static_cast< io::XOutputStream* >( this );
221 // css::io::XInputStream
222 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead )
224 ::osl::MutexGuard aGuard( m_aMutex );
226 if ( !m_pStreamData )
227 throw io::NotConnectedException();
229 // the original stream data should be provided
230 if ( !m_pStreamData->m_xOrigInStream.is() )
231 throw uno::RuntimeException();
233 return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead );
236 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead )
238 ::osl::MutexGuard aGuard( m_aMutex );
240 if ( !m_pStreamData )
241 throw io::NotConnectedException();
243 // the original stream data should be provided
244 if ( !m_pStreamData->m_xOrigInStream.is() )
245 throw uno::RuntimeException();
247 return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead );
250 void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip )
252 ::osl::MutexGuard aGuard( m_aMutex );
254 if ( !m_pStreamData )
255 throw io::NotConnectedException();
257 // the original stream data should be provided
258 if ( !m_pStreamData->m_xOrigInStream.is() )
259 throw uno::RuntimeException();
261 m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip );
264 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::available( )
266 ::osl::MutexGuard aGuard( m_aMutex );
268 if ( !m_pStreamData )
269 throw io::NotConnectedException();
271 // the original stream data should be provided
272 if ( !m_pStreamData->m_xOrigInStream.is() )
273 throw uno::RuntimeException();
275 return m_pStreamData->m_xOrigInStream->available();
278 void SAL_CALL SwitchablePersistenceStream::closeInput()
280 ::osl::MutexGuard aGuard( m_aMutex );
282 if ( !m_pStreamData )
283 throw io::NotConnectedException();
285 m_pStreamData->m_bInOpen = false;
286 if ( !m_pStreamData->m_bOutOpen )
287 CloseAll_Impl();
290 // css::io::XOutputStream
291 void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData )
293 ::osl::MutexGuard aGuard( m_aMutex );
295 if ( !m_pStreamData )
296 throw io::NotConnectedException();
298 if ( m_pStreamData->m_bInStreamBased )
299 throw io::IOException();
301 // the original stream data should be provided
302 if ( !m_pStreamData->m_xOrigOutStream.is() )
303 throw uno::RuntimeException();
305 m_pStreamData->m_xOrigOutStream->writeBytes( aData );
308 void SAL_CALL SwitchablePersistenceStream::flush( )
310 ::osl::MutexGuard aGuard( m_aMutex );
312 if ( !m_pStreamData || m_pStreamData->m_bInStreamBased )
314 OSL_FAIL( "flush() is not acceptable!" );
315 return;
316 // in future throw exception, for now some code might call flush() on closed stream
317 // since file ucp implementation allows it
318 // throw io::NotConnectedException();
321 // the original stream data should be provided
322 if ( !m_pStreamData->m_xOrigOutStream.is() )
323 throw uno::RuntimeException();
325 m_pStreamData->m_xOrigOutStream->flush();
328 void SAL_CALL SwitchablePersistenceStream::closeOutput( )
330 ::osl::MutexGuard aGuard( m_aMutex );
332 if ( !m_pStreamData )
333 throw io::NotConnectedException();
335 m_pStreamData->m_bOutOpen = false;
336 if ( !m_pStreamData->m_bInOpen )
337 CloseAll_Impl();
340 // css::io::XTruncate
341 void SAL_CALL SwitchablePersistenceStream::truncate( )
343 ::osl::MutexGuard aGuard( m_aMutex );
345 if ( !m_pStreamData )
346 throw io::NotConnectedException();
348 if ( m_pStreamData->m_bInStreamBased )
349 throw io::IOException();
351 // the original stream data should be provided
352 if ( !m_pStreamData->m_xOrigTruncate.is() )
353 throw uno::RuntimeException();
355 m_pStreamData->m_xOrigTruncate->truncate();
358 // css::io::XSeekable
359 void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location )
361 ::osl::MutexGuard aGuard( m_aMutex );
363 if ( !m_pStreamData )
364 throw io::NotConnectedException();
366 // the original stream data should be provided
367 if ( !m_pStreamData->m_xOrigSeekable.is() )
368 throw uno::RuntimeException();
370 m_pStreamData->m_xOrigSeekable->seek( location );
373 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getPosition( )
375 ::osl::MutexGuard aGuard( m_aMutex );
377 if ( !m_pStreamData )
378 throw io::NotConnectedException();
380 // the original stream data should be provided
381 if ( !m_pStreamData->m_xOrigSeekable.is() )
382 throw uno::RuntimeException();
384 return m_pStreamData->m_xOrigSeekable->getPosition();
387 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getLength( )
389 ::osl::MutexGuard aGuard( m_aMutex );
391 if ( !m_pStreamData )
392 throw io::NotConnectedException();
394 // the original stream data should be provided
395 if ( !m_pStreamData->m_xOrigSeekable.is() )
396 throw uno::RuntimeException();
398 return m_pStreamData->m_xOrigSeekable->getLength();
401 void SAL_CALL SwitchablePersistenceStream::waitForCompletion()
403 if ( !m_pStreamData )
404 throw io::NotConnectedException();
406 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY );
407 if ( asyncOutputMonitor.is() )
408 asyncOutputMonitor->waitForCompletion();
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */