Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/comphelper/source/streaming/seekableinput.cxx
Line
Count
Source
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 <sal/config.h>
21
22
#include <com/sun/star/io/IOException.hpp>
23
#include <com/sun/star/io/NotConnectedException.hpp>
24
#include <com/sun/star/io/TempFile.hpp>
25
#include <com/sun/star/io/XOutputStream.hpp>
26
27
#include <com/sun/star/lang/IllegalArgumentException.hpp>
28
29
#include <comphelper/seekableinput.hxx>
30
#include <utility>
31
32
using namespace ::com::sun::star;
33
34
namespace comphelper
35
{
36
37
const sal_Int32 nConstBufferSize = 32000;
38
39
40
static void copyInputToOutput_Impl( const uno::Reference< io::XInputStream >& xIn,
41
                            const uno::Reference< io::XOutputStream >& xOut )
42
0
{
43
0
    sal_Int32 nRead;
44
0
    uno::Sequence< sal_Int8 > aSequence( nConstBufferSize );
45
46
0
    do
47
0
    {
48
0
        nRead = xIn->readBytes( aSequence, nConstBufferSize );
49
0
        if ( nRead < nConstBufferSize )
50
0
        {
51
0
            uno::Sequence< sal_Int8 > aTempBuf( aSequence.getConstArray(), nRead );
52
0
            xOut->writeBytes( aTempBuf );
53
0
        }
54
0
        else
55
0
            xOut->writeBytes( aSequence );
56
0
    }
57
0
    while ( nRead == nConstBufferSize );
58
0
}
59
60
61
OSeekableInputWrapper::OSeekableInputWrapper(
62
            uno::Reference< io::XInputStream > xInStream,
63
            uno::Reference< uno::XComponentContext > xContext )
64
2
: m_xContext(std::move( xContext ))
65
2
, m_xOriginalStream(std::move( xInStream ))
66
2
{
67
2
    if ( !m_xContext.is() )
68
0
        throw lang::IllegalArgumentException(u"no component context"_ustr, *this, 1);
69
2
}
70
71
72
OSeekableInputWrapper::~OSeekableInputWrapper()
73
2
{
74
2
}
75
76
77
uno::Reference< io::XInputStream > OSeekableInputWrapper::CheckSeekableCanWrap(
78
                            const uno::Reference< io::XInputStream >& xInStream,
79
                            const uno::Reference< uno::XComponentContext >& rxContext )
80
98.8k
{
81
    // check that the stream is seekable and just wrap it if it is not
82
98.8k
    uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
83
98.8k
    if ( xSeek.is() )
84
98.8k
        return xInStream;
85
86
2
    return new OSeekableInputWrapper(xInStream, rxContext);
87
98.8k
}
88
89
90
void OSeekableInputWrapper::PrepareCopy_Impl()
91
2
{
92
2
    if ( !m_xCopyInput.is() )
93
2
    {
94
2
        if ( !m_xContext.is() )
95
0
            throw uno::RuntimeException(u"no component context"_ustr);
96
97
2
        uno::Reference< io::XOutputStream > xTempOut(
98
2
                io::TempFile::create(m_xContext),
99
2
                uno::UNO_QUERY_THROW );
100
101
2
        copyInputToOutput_Impl( m_xOriginalStream, xTempOut );
102
2
        xTempOut->closeOutput();
103
104
2
        uno::Reference< io::XSeekable > xTempSeek( xTempOut, uno::UNO_QUERY );
105
2
        if ( xTempSeek.is() )
106
0
        {
107
0
            xTempSeek->seek( 0 );
108
0
            m_xCopyInput.set( xTempOut, uno::UNO_QUERY );
109
0
            if ( m_xCopyInput.is() )
110
0
            {
111
0
                m_xCopySeek = std::move(xTempSeek);
112
0
                m_pCopyByteReader = dynamic_cast<comphelper::ByteReader*>(xTempOut.get());
113
0
                assert(m_pCopyByteReader);
114
0
            }
115
0
        }
116
2
    }
117
118
2
    if ( !m_xCopyInput.is() )
119
0
        throw io::IOException(u"no m_xCopyInput"_ustr);
120
2
}
121
122
// XInputStream
123
124
sal_Int32 SAL_CALL OSeekableInputWrapper::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
125
0
{
126
0
    std::scoped_lock aGuard( m_aMutex );
127
128
0
    if ( !m_xOriginalStream.is() )
129
0
        throw io::NotConnectedException();
130
131
0
    PrepareCopy_Impl();
132
133
0
    return m_xCopyInput->readBytes( aData, nBytesToRead );
134
0
}
135
136
137
sal_Int32 SAL_CALL OSeekableInputWrapper::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
138
0
{
139
0
    std::scoped_lock aGuard( m_aMutex );
140
141
0
    if ( !m_xOriginalStream.is() )
142
0
        throw io::NotConnectedException();
143
144
0
    PrepareCopy_Impl();
145
146
0
    return m_xCopyInput->readSomeBytes( aData, nMaxBytesToRead );
147
0
}
148
149
sal_Int32 OSeekableInputWrapper::readSomeBytes( sal_Int8* aData, sal_Int32 nMaxBytesToRead )
150
0
{
151
0
    std::scoped_lock aGuard( m_aMutex );
152
153
0
    if ( !m_xOriginalStream.is() )
154
0
        throw io::NotConnectedException();
155
156
0
    PrepareCopy_Impl();
157
158
0
    return m_pCopyByteReader->readSomeBytes( aData, nMaxBytesToRead );
159
0
}
160
161
162
void SAL_CALL OSeekableInputWrapper::skipBytes( sal_Int32 nBytesToSkip )
163
0
{
164
0
    std::scoped_lock aGuard( m_aMutex );
165
166
0
    if ( !m_xOriginalStream.is() )
167
0
        throw io::NotConnectedException();
168
169
0
    PrepareCopy_Impl();
170
171
0
    m_xCopyInput->skipBytes( nBytesToSkip );
172
0
}
173
174
175
sal_Int32 SAL_CALL OSeekableInputWrapper::available()
176
0
{
177
0
    std::scoped_lock aGuard( m_aMutex );
178
179
0
    if ( !m_xOriginalStream.is() )
180
0
        throw io::NotConnectedException();
181
182
0
    PrepareCopy_Impl();
183
184
0
    return m_xCopyInput->available();
185
0
}
186
187
188
void SAL_CALL OSeekableInputWrapper::closeInput()
189
0
{
190
0
    std::scoped_lock aGuard( m_aMutex );
191
192
0
    if ( !m_xOriginalStream.is() )
193
0
        throw io::NotConnectedException();
194
195
0
    m_xOriginalStream->closeInput();
196
0
    m_xOriginalStream.clear();
197
198
0
    if ( m_xCopyInput.is() )
199
0
    {
200
0
        m_xCopyInput->closeInput();
201
0
        m_xCopyInput.clear();
202
0
    }
203
204
0
    m_xCopySeek.clear();
205
0
    m_pCopyByteReader = nullptr;
206
0
}
207
208
209
// XSeekable
210
211
void SAL_CALL OSeekableInputWrapper::seek( sal_Int64 location )
212
0
{
213
0
    std::scoped_lock aGuard( m_aMutex );
214
215
0
    if ( !m_xOriginalStream.is() )
216
0
        throw io::NotConnectedException();
217
218
0
    PrepareCopy_Impl();
219
220
0
    m_xCopySeek->seek( location );
221
0
}
222
223
224
sal_Int64 SAL_CALL OSeekableInputWrapper::getPosition()
225
0
{
226
0
    std::scoped_lock aGuard( m_aMutex );
227
228
0
    if ( !m_xOriginalStream.is() )
229
0
        throw io::NotConnectedException();
230
231
0
    PrepareCopy_Impl();
232
233
0
    return m_xCopySeek->getPosition();
234
0
}
235
236
237
sal_Int64 SAL_CALL OSeekableInputWrapper::getLength()
238
2
{
239
2
    std::scoped_lock aGuard( m_aMutex );
240
241
2
    if ( !m_xOriginalStream.is() )
242
0
        throw io::NotConnectedException();
243
244
2
    PrepareCopy_Impl();
245
246
2
    return m_xCopySeek->getLength();
247
2
}
248
249
}   // namespace comphelper
250
251
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */