LibreOffice Module package (master) 1
switchpersistencestream.cxx
Go to the documentation of this file.
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#include <com/sun/star/io/IOException.hpp>
22#include <com/sun/star/io/NotConnectedException.hpp>
23#include <com/sun/star/io/TempFile.hpp>
25#include <unotools/tempfile.hxx>
26#include <utility>
28
29using namespace ::com::sun::star;
30
32{
34
35 // the streams below are not visible from outside so there is no need to remember position
36
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;
42
45
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 )
61 {
62 }
63};
64
66 const uno::Reference< io::XStream >& xStream )
67{
68 SwitchPersistenceTo( xStream );
69}
70
72 const uno::Reference< io::XInputStream >& xInputStream )
73{
74 SwitchPersistenceTo( xInputStream );
75}
76
78{
80}
81
82void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
83{
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();
90
91 sal_Int64 nPos = 0;
92 bool bInOpen = false;
93 bool bOutOpen = false;
94
95 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
96 {
97 // check that the length is the same
98 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
99 throw uno::RuntimeException();
100
101 // get the current position
102 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
103 bInOpen = m_pStreamData->m_bInOpen;
104 bOutOpen = m_pStreamData->m_bOutOpen;
105 }
106
107 xNewSeekable->seek( nPos );
108
110
111 m_pStreamData.reset( new SPStreamData_Impl( false,
112 xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream,
113 bInOpen, bOutOpen ) );
114}
115
116void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream )
117{
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();
123
124 sal_Int64 nPos = 0;
125 bool bInOpen = false;
126 bool bOutOpen = false;
127
128 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() )
129 {
130 // check that the length is the same
131 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() )
132 throw uno::RuntimeException();
133
134 // get the current position
135 nPos = m_pStreamData->m_xOrigSeekable->getPosition();
136 bInOpen = m_pStreamData->m_bInOpen;
137 bOutOpen = m_pStreamData->m_bOutOpen;
138 }
139
140 xNewSeekable->seek( nPos );
141
143
144 m_pStreamData.reset( new SPStreamData_Impl( true,
145 xNewTruncate, xNewSeekable, xInputStream, xNewOutStream,
146 bInOpen, bOutOpen ) );
147
148}
149
150void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream )
151{
152 uno::Reference< io::XStream > xTargetStream = xStream;
153 uno::Reference< io::XSeekable > xTargetSeek;
154
155 if ( !xTargetStream.is() )
156 {
157 xTargetStream.set( new utl::TempFileFastService );
158 xTargetSeek.set( xTargetStream, uno::UNO_QUERY_THROW );
159 }
160 else
161 {
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");
166 }
167
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();
173
174 if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() )
175 throw uno::RuntimeException();
176
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 );
182
183 bool bInOpen = m_pStreamData->m_bInOpen;
184 bool bOutOpen = m_pStreamData->m_bOutOpen;
185
187
188 m_pStreamData.reset( new SPStreamData_Impl( false,
189 xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream,
190 bInOpen, bOutOpen ) );
191}
192
194{
195 m_pStreamData.reset();
196}
197
198// css::io::XStream
199uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream( )
200{
201 std::scoped_lock aGuard( m_aMutex );
202
203 if ( m_pStreamData )
204 m_pStreamData->m_bInOpen = true;
205 return static_cast< io::XInputStream* >( this );
206}
207
208uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream( )
209{
210 std::scoped_lock aGuard( m_aMutex );
211
212 if ( m_pStreamData )
213 m_pStreamData->m_bOutOpen = true;
214 return static_cast< io::XOutputStream* >( this );
215}
216
217// css::io::XInputStream
218::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead )
219{
220 std::scoped_lock aGuard( m_aMutex );
221
222 if ( !m_pStreamData )
223 throw io::NotConnectedException();
224
225 // the original stream data should be provided
226 if ( !m_pStreamData->m_xOrigInStream.is() )
227 throw uno::RuntimeException();
228
229 return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead );
230}
231
232::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead )
233{
234 std::scoped_lock aGuard( m_aMutex );
235
236 if ( !m_pStreamData )
237 throw io::NotConnectedException();
238
239 // the original stream data should be provided
240 if ( !m_pStreamData->m_xOrigInStream.is() )
241 throw uno::RuntimeException();
242
243 return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead );
244}
245
246void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip )
247{
248 std::scoped_lock aGuard( m_aMutex );
249
250 if ( !m_pStreamData )
251 throw io::NotConnectedException();
252
253 // the original stream data should be provided
254 if ( !m_pStreamData->m_xOrigInStream.is() )
255 throw uno::RuntimeException();
256
257 m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip );
258}
259
261{
262 std::scoped_lock 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->available();
272}
273
275{
276 std::scoped_lock aGuard( m_aMutex );
277
278 if ( !m_pStreamData )
279 throw io::NotConnectedException();
280
281 m_pStreamData->m_bInOpen = false;
282 if ( !m_pStreamData->m_bOutOpen )
284}
285
286// css::io::XOutputStream
287void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData )
288{
289 std::scoped_lock aGuard( m_aMutex );
290
291 if ( !m_pStreamData )
292 throw io::NotConnectedException();
293
294 if ( m_pStreamData->m_bInStreamBased )
295 throw io::IOException();
296
297 // the original stream data should be provided
298 if ( !m_pStreamData->m_xOrigOutStream.is() )
299 throw uno::RuntimeException();
300
301 m_pStreamData->m_xOrigOutStream->writeBytes( aData );
302}
303
305{
306 std::scoped_lock aGuard( m_aMutex );
307
308 if ( !m_pStreamData || m_pStreamData->m_bInStreamBased )
309 {
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();
315 }
316
317 // the original stream data should be provided
318 if ( !m_pStreamData->m_xOrigOutStream.is() )
319 throw uno::RuntimeException();
320
321 m_pStreamData->m_xOrigOutStream->flush();
322}
323
325{
326 std::scoped_lock aGuard( m_aMutex );
327
328 if ( !m_pStreamData )
329 throw io::NotConnectedException();
330
331 m_pStreamData->m_bOutOpen = false;
332 if ( !m_pStreamData->m_bInOpen )
334}
335
336// css::io::XTruncate
338{
339 std::scoped_lock aGuard( m_aMutex );
340
341 if ( !m_pStreamData )
342 throw io::NotConnectedException();
343
344 if ( m_pStreamData->m_bInStreamBased )
345 throw io::IOException();
346
347 // the original stream data should be provided
348 if ( !m_pStreamData->m_xOrigTruncate.is() )
349 throw uno::RuntimeException();
350
351 m_pStreamData->m_xOrigTruncate->truncate();
352}
353
354// css::io::XSeekable
355void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location )
356{
357 std::scoped_lock aGuard( m_aMutex );
358
359 if ( !m_pStreamData )
360 throw io::NotConnectedException();
361
362 // the original stream data should be provided
363 if ( !m_pStreamData->m_xOrigSeekable.is() )
364 throw uno::RuntimeException();
365
366 m_pStreamData->m_xOrigSeekable->seek( location );
367}
368
370{
371 std::scoped_lock aGuard( m_aMutex );
372
373 if ( !m_pStreamData )
374 throw io::NotConnectedException();
375
376 // the original stream data should be provided
377 if ( !m_pStreamData->m_xOrigSeekable.is() )
378 throw uno::RuntimeException();
379
380 return m_pStreamData->m_xOrigSeekable->getPosition();
381}
382
384{
385 std::scoped_lock aGuard( m_aMutex );
386
387 if ( !m_pStreamData )
388 throw io::NotConnectedException();
389
390 // the original stream data should be provided
391 if ( !m_pStreamData->m_xOrigSeekable.is() )
392 throw uno::RuntimeException();
393
394 return m_pStreamData->m_xOrigSeekable->getLength();
395}
396
398{
399 if ( !m_pStreamData )
400 throw io::NotConnectedException();
401
402 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY );
403 if ( asyncOutputMonitor.is() )
404 asyncOutputMonitor->waitForCompletion();
405}
406
407/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Reference< XInputStream > xStream
virtual ::sal_Int64 SAL_CALL getPosition() override
virtual void SAL_CALL closeInput() override
virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getInputStream() override
virtual void SAL_CALL writeBytes(const css::uno::Sequence< ::sal_Int8 > &aData) override
void SwitchPersistenceTo(const css::uno::Reference< css::io::XStream > &xStream)
virtual ::sal_Int32 SAL_CALL readSomeBytes(css::uno::Sequence< ::sal_Int8 > &aData, ::sal_Int32 nMaxBytesToRead) override
virtual ::sal_Int32 SAL_CALL available() override
virtual void SAL_CALL closeOutput() override
virtual void SAL_CALL truncate() override
void CopyAndSwitchPersistenceTo(const css::uno::Reference< css::io::XStream > &xStream)
virtual ::sal_Int64 SAL_CALL getLength() override
virtual void SAL_CALL flush() override
virtual css::uno::Reference< css::io::XOutputStream > SAL_CALL getOutputStream() override
virtual void SAL_CALL waitForCompletion() override
virtual ~SwitchablePersistenceStream() override
virtual void SAL_CALL seek(::sal_Int64 location) override
std::unique_ptr< SPStreamData_Impl > m_pStreamData
virtual ::sal_Int32 SAL_CALL readBytes(css::uno::Sequence< ::sal_Int8 > &aData, ::sal_Int32 nBytesToRead) override
virtual void SAL_CALL skipBytes(::sal_Int32 nBytesToSkip) override
SwitchablePersistenceStream(const css::uno::Reference< css::io::XStream > &xStream)
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
sal_uInt16 nPos
constexpr OUStringLiteral aData
uno::Reference< io::XSeekable > m_xOrigSeekable
uno::Reference< io::XOutputStream > m_xOrigOutStream
SPStreamData_Impl(bool bInStreamBased, uno::Reference< io::XTruncate > xOrigTruncate, uno::Reference< io::XSeekable > xOrigSeekable, uno::Reference< io::XInputStream > xOrigInStream, uno::Reference< io::XOutputStream > xOrigOutStream, bool bInOpen, bool bOutOpen)
uno::Reference< io::XInputStream > m_xOrigInStream
uno::Reference< io::XTruncate > m_xOrigTruncate