Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / package / source / xstor / switchpersistencestream.cxx
blobff6118726628f69f004eb8af773c36fe8bb58c21
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 <unotools/tempfile.hxx>
26 #include <utility>
27 #include "switchpersistencestream.hxx"
29 using namespace ::com::sun::star;
31 struct SPStreamData_Impl
33 bool m_bInStreamBased;
35 // the streams below are not visible from outside so there is no need to remember position
37 // original stream related members
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;
43 bool m_bInOpen;
44 bool m_bOutOpen;
46 SPStreamData_Impl(
47 bool bInStreamBased,
48 uno::Reference< io::XTruncate > xOrigTruncate,
49 uno::Reference< io::XSeekable > xOrigSeekable,
50 uno::Reference< io::XInputStream > xOrigInStream,
51 uno::Reference< io::XOutputStream > xOrigOutStream,
52 bool bInOpen,
53 bool bOutOpen )
54 : m_bInStreamBased( bInStreamBased )
55 , m_xOrigTruncate(std::move( xOrigTruncate ))
56 , m_xOrigSeekable(std::move( xOrigSeekable ))
57 , m_xOrigInStream(std::move( xOrigInStream ))
58 , m_xOrigOutStream(std::move( xOrigOutStream ))
59 , m_bInOpen( bInOpen )
60 , m_bOutOpen( bOutOpen )
65 SwitchablePersistenceStream::SwitchablePersistenceStream(
66 const uno::Reference< io::XStream >& xStream )
68 SwitchPersistenceTo( xStream );
71 SwitchablePersistenceStream::SwitchablePersistenceStream(
72 const uno::Reference< io::XInputStream >& xInputStream )
74 SwitchPersistenceTo( xInputStream );
77 SwitchablePersistenceStream::~SwitchablePersistenceStream()
79 CloseAll_Impl();
82 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
84 uno::Reference< io::XTruncate > xNewTruncate( xStream, uno::UNO_QUERY_THROW );
85 uno::Reference< io::XSeekable > xNewSeekable( xStream, uno::UNO_QUERY_THROW );
86 uno::Reference< io::XInputStream > xNewInStream = xStream->getInputStream();
87 uno::Reference< io::XOutputStream > xNewOutStream = xStream->getOutputStream();
88 if ( !xNewInStream.is() || !xNewOutStream.is() )
89 throw uno::RuntimeException();
91 sal_Int64 nPos = 0;
92 bool bInOpen = false;
93 bool bOutOpen = false;
95 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
97 // check that the length is the same
98 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
99 throw uno::RuntimeException();
101 // get the current position
102 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
103 bInOpen = m_pStreamData->m_bInOpen;
104 bOutOpen = m_pStreamData->m_bOutOpen;
107 xNewSeekable->seek( nPos );
109 CloseAll_Impl();
111 m_pStreamData.reset( new SPStreamData_Impl( false,
112 xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream,
113 bInOpen, bOutOpen ) );
116 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream )
118 uno::Reference< io::XTruncate > xNewTruncate;
119 uno::Reference< io::XSeekable > xNewSeekable( xInputStream, uno::UNO_QUERY_THROW );
120 uno::Reference< io::XOutputStream > xNewOutStream;
121 if ( !xInputStream.is() )
122 throw uno::RuntimeException();
124 sal_Int64 nPos = 0;
125 bool bInOpen = false;
126 bool bOutOpen = false;
128 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
130 // check that the length is the same
131 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
132 throw uno::RuntimeException();
134 // get the current position
135 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
136 bInOpen = m_pStreamData->m_bInOpen;
137 bOutOpen = m_pStreamData->m_bOutOpen;
140 xNewSeekable->seek( nPos );
142 CloseAll_Impl();
144 m_pStreamData.reset( new SPStreamData_Impl( true,
145 xNewTruncate, xNewSeekable, xInputStream, xNewOutStream,
146 bInOpen, bOutOpen ) );
150 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
152 uno::Reference< io::XStream > xTargetStream = xStream;
153 uno::Reference< io::XSeekable > xTargetSeek;
155 if ( !xTargetStream.is() )
157 xTargetStream.set( new utl::TempFileFastService );
158 xTargetSeek.set( xTargetStream, uno::UNO_QUERY_THROW );
160 else
162 // the provided stream must be empty
163 xTargetSeek.set( xTargetStream, uno::UNO_QUERY_THROW );
164 if ( xTargetSeek->getLength() )
165 throw io::IOException("provided stream not empty");
168 uno::Reference< io::XTruncate > xTargetTruncate( xTargetStream, uno::UNO_QUERY_THROW );
169 uno::Reference< io::XInputStream > xTargetInStream = xTargetStream->getInputStream();
170 uno::Reference< io::XOutputStream > xTargetOutStream = xTargetStream->getOutputStream();
171 if ( !xTargetInStream.is() || !xTargetOutStream.is() )
172 throw uno::RuntimeException();
174 if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() )
175 throw uno::RuntimeException();
177 sal_Int64 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
178 m_pStreamData->m_xOrigSeekable->seek( 0 );
179 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData->m_xOrigInStream, xTargetOutStream );
180 xTargetOutStream->flush();
181 xTargetSeek->seek( nPos );
183 bool bInOpen = m_pStreamData->m_bInOpen;
184 bool bOutOpen = m_pStreamData->m_bOutOpen;
186 CloseAll_Impl();
188 m_pStreamData.reset( new SPStreamData_Impl( false,
189 xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream,
190 bInOpen, bOutOpen ) );
193 void SwitchablePersistenceStream::CloseAll_Impl()
195 m_pStreamData.reset();
198 // css::io::XStream
199 uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream( )
201 std::scoped_lock aGuard( m_aMutex );
203 if ( m_pStreamData )
204 m_pStreamData->m_bInOpen = true;
205 return static_cast< io::XInputStream* >( this );
208 uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream( )
210 std::scoped_lock aGuard( m_aMutex );
212 if ( m_pStreamData )
213 m_pStreamData->m_bOutOpen = true;
214 return static_cast< io::XOutputStream* >( this );
217 // css::io::XInputStream
218 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead )
220 std::scoped_lock aGuard( m_aMutex );
222 if ( !m_pStreamData )
223 throw io::NotConnectedException();
225 // the original stream data should be provided
226 if ( !m_pStreamData->m_xOrigInStream.is() )
227 throw uno::RuntimeException();
229 return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead );
232 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead )
234 std::scoped_lock aGuard( m_aMutex );
236 if ( !m_pStreamData )
237 throw io::NotConnectedException();
239 // the original stream data should be provided
240 if ( !m_pStreamData->m_xOrigInStream.is() )
241 throw uno::RuntimeException();
243 return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead );
246 void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip )
248 std::scoped_lock aGuard( m_aMutex );
250 if ( !m_pStreamData )
251 throw io::NotConnectedException();
253 // the original stream data should be provided
254 if ( !m_pStreamData->m_xOrigInStream.is() )
255 throw uno::RuntimeException();
257 m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip );
260 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::available( )
262 std::scoped_lock aGuard( m_aMutex );
264 if ( !m_pStreamData )
265 throw io::NotConnectedException();
267 // the original stream data should be provided
268 if ( !m_pStreamData->m_xOrigInStream.is() )
269 throw uno::RuntimeException();
271 return m_pStreamData->m_xOrigInStream->available();
274 void SAL_CALL SwitchablePersistenceStream::closeInput()
276 std::scoped_lock aGuard( m_aMutex );
278 if ( !m_pStreamData )
279 throw io::NotConnectedException();
281 m_pStreamData->m_bInOpen = false;
282 if ( !m_pStreamData->m_bOutOpen )
283 CloseAll_Impl();
286 // css::io::XOutputStream
287 void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData )
289 std::scoped_lock aGuard( m_aMutex );
291 if ( !m_pStreamData )
292 throw io::NotConnectedException();
294 if ( m_pStreamData->m_bInStreamBased )
295 throw io::IOException();
297 // the original stream data should be provided
298 if ( !m_pStreamData->m_xOrigOutStream.is() )
299 throw uno::RuntimeException();
301 m_pStreamData->m_xOrigOutStream->writeBytes( aData );
304 void SAL_CALL SwitchablePersistenceStream::flush( )
306 std::scoped_lock aGuard( m_aMutex );
308 if ( !m_pStreamData || m_pStreamData->m_bInStreamBased )
310 OSL_FAIL( "flush() is not acceptable!" );
311 return;
312 // in future throw exception, for now some code might call flush() on closed stream
313 // since file ucp implementation allows it
314 // throw io::NotConnectedException();
317 // the original stream data should be provided
318 if ( !m_pStreamData->m_xOrigOutStream.is() )
319 throw uno::RuntimeException();
321 m_pStreamData->m_xOrigOutStream->flush();
324 void SAL_CALL SwitchablePersistenceStream::closeOutput( )
326 std::scoped_lock aGuard( m_aMutex );
328 if ( !m_pStreamData )
329 throw io::NotConnectedException();
331 m_pStreamData->m_bOutOpen = false;
332 if ( !m_pStreamData->m_bInOpen )
333 CloseAll_Impl();
336 // css::io::XTruncate
337 void SAL_CALL SwitchablePersistenceStream::truncate( )
339 std::scoped_lock aGuard( m_aMutex );
341 if ( !m_pStreamData )
342 throw io::NotConnectedException();
344 if ( m_pStreamData->m_bInStreamBased )
345 throw io::IOException();
347 // the original stream data should be provided
348 if ( !m_pStreamData->m_xOrigTruncate.is() )
349 throw uno::RuntimeException();
351 m_pStreamData->m_xOrigTruncate->truncate();
354 // css::io::XSeekable
355 void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location )
357 std::scoped_lock aGuard( m_aMutex );
359 if ( !m_pStreamData )
360 throw io::NotConnectedException();
362 // the original stream data should be provided
363 if ( !m_pStreamData->m_xOrigSeekable.is() )
364 throw uno::RuntimeException();
366 m_pStreamData->m_xOrigSeekable->seek( location );
369 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getPosition( )
371 std::scoped_lock aGuard( m_aMutex );
373 if ( !m_pStreamData )
374 throw io::NotConnectedException();
376 // the original stream data should be provided
377 if ( !m_pStreamData->m_xOrigSeekable.is() )
378 throw uno::RuntimeException();
380 return m_pStreamData->m_xOrigSeekable->getPosition();
383 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getLength( )
385 std::scoped_lock aGuard( m_aMutex );
387 if ( !m_pStreamData )
388 throw io::NotConnectedException();
390 // the original stream data should be provided
391 if ( !m_pStreamData->m_xOrigSeekable.is() )
392 throw uno::RuntimeException();
394 return m_pStreamData->m_xOrigSeekable->getLength();
397 void SAL_CALL SwitchablePersistenceStream::waitForCompletion()
399 if ( !m_pStreamData )
400 throw io::NotConnectedException();
402 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY );
403 if ( asyncOutputMonitor.is() )
404 asyncOutputMonitor->waitForCompletion();
407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */