Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/io/source/stm/opipe.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/BufferSizeExceededException.hpp>
23
#include <com/sun/star/io/NotConnectedException.hpp>
24
#include <com/sun/star/io/XPipe.hpp>
25
#include <com/sun/star/io/XConnectable.hpp>
26
27
#include <com/sun/star/lang/XServiceInfo.hpp>
28
29
#include <cppuhelper/implbase.hxx>
30
#include <cppuhelper/supportsservice.hxx>
31
32
#include <osl/conditn.hxx>
33
#include <osl/mutex.hxx>
34
35
#include <limits>
36
#include <memory>
37
#include <optional>
38
#include <string.h>
39
40
using namespace ::osl;
41
using namespace ::cppu;
42
using namespace ::com::sun::star::uno;
43
using namespace ::com::sun::star::io;
44
using namespace ::com::sun::star::lang;
45
46
#include "streamhelper.hxx"
47
48
namespace com::sun::star::uno { class XComponentContext; }
49
50
namespace io_stm{
51
52
namespace {
53
54
class OPipeImpl :
55
    public WeakImplHelper< XPipe , XConnectable , XServiceInfo >
56
{
57
public:
58
    OPipeImpl( );
59
60
public: // XInputStream
61
    virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead) override;
62
    virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead) override;
63
    virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip) override;
64
    virtual sal_Int32 SAL_CALL available() override;
65
    virtual void SAL_CALL closeInput() override;
66
67
public: // XOutputStream
68
69
    virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData) override;
70
    virtual void SAL_CALL flush() override;
71
    virtual void SAL_CALL closeOutput() override;
72
73
public: // XConnectable
74
    virtual void SAL_CALL setPredecessor(const Reference< XConnectable >& aPredecessor) override;
75
    virtual Reference< XConnectable > SAL_CALL getPredecessor() override;
76
    virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor) override;
77
    virtual Reference < XConnectable > SAL_CALL getSuccessor() override ;
78
79
80
public: // XServiceInfo
81
    OUString                    SAL_CALL getImplementationName() override;
82
    Sequence< OUString >         SAL_CALL getSupportedServiceNames() override;
83
    sal_Bool                        SAL_CALL supportsService(const OUString& ServiceName) override;
84
85
private:
86
87
    Reference < XConnectable >  m_succ;
88
    Reference < XConnectable >  m_pred;
89
90
    sal_Int32 m_nBytesToSkip;
91
92
    bool m_bOutputStreamClosed;
93
    bool m_bInputStreamClosed;
94
95
    osl::Condition m_conditionBytesAvail;
96
    Mutex          m_mutexAccess;
97
    std::optional<MemFIFO> m_oFIFO;
98
};
99
100
}
101
102
OPipeImpl::OPipeImpl()
103
0
    : m_nBytesToSkip(0 )
104
0
    , m_bOutputStreamClosed(false )
105
0
    , m_bInputStreamClosed( false )
106
0
    , m_oFIFO( std::in_place )
107
0
{
108
0
}
109
110
111
112
sal_Int32 OPipeImpl::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
113
0
{
114
0
    while( true )
115
0
    {
116
0
        { // start guarded section
117
0
            MutexGuard guard( m_mutexAccess );
118
0
            if( m_bInputStreamClosed )
119
0
            {
120
0
                throw NotConnectedException(
121
0
                    u"Pipe::readBytes NotConnectedException"_ustr,
122
0
                    *this );
123
0
            }
124
0
            sal_Int32 nOccupiedBufferLen = m_oFIFO->getSize();
125
126
0
            if( m_bOutputStreamClosed && nBytesToRead > nOccupiedBufferLen )
127
0
            {
128
0
                nBytesToRead = nOccupiedBufferLen;
129
0
            }
130
131
0
            if( nOccupiedBufferLen < nBytesToRead )
132
0
            {
133
                // wait outside guarded section
134
0
                m_conditionBytesAvail.reset();
135
0
            }
136
0
            else {
137
                // necessary bytes are available
138
0
                m_oFIFO->read( aData , nBytesToRead );
139
0
                return nBytesToRead;
140
0
            }
141
0
        } // end guarded section
142
143
        // wait for new data outside guarded section!
144
0
        m_conditionBytesAvail.wait();
145
0
    }
146
0
}
147
148
149
sal_Int32 OPipeImpl::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
150
0
{
151
0
    while( true ) {
152
0
        {
153
0
            MutexGuard guard( m_mutexAccess );
154
0
            if( m_bInputStreamClosed )
155
0
            {
156
0
                throw NotConnectedException(
157
0
                    u"Pipe::readSomeBytes NotConnectedException"_ustr,
158
0
                    *this );
159
0
            }
160
0
            if( m_oFIFO->getSize() )
161
0
            {
162
0
                sal_Int32 nSize = std::min( nMaxBytesToRead , m_oFIFO->getSize() );
163
0
                aData.realloc( nSize );
164
0
                m_oFIFO->read( aData , nSize );
165
0
                return nSize;
166
0
            }
167
168
0
            if( m_bOutputStreamClosed )
169
0
            {
170
                // no bytes in buffer anymore
171
0
                return 0;
172
0
            }
173
0
        }
174
175
0
        m_conditionBytesAvail.wait();
176
0
    }
177
0
}
178
179
180
void OPipeImpl::skipBytes(sal_Int32 nBytesToSkip)
181
0
{
182
0
    MutexGuard guard( m_mutexAccess );
183
0
    if( m_bInputStreamClosed )
184
0
    {
185
0
        throw NotConnectedException(
186
0
            u"Pipe::skipBytes NotConnectedException"_ustr,
187
0
            *this );
188
0
    }
189
190
0
    if( nBytesToSkip < 0
191
0
        || (nBytesToSkip
192
0
            > std::numeric_limits< sal_Int32 >::max() - m_nBytesToSkip) )
193
0
    {
194
0
        throw BufferSizeExceededException(
195
0
            u"Pipe::skipBytes BufferSizeExceededException"_ustr,
196
0
            *this );
197
0
    }
198
0
    m_nBytesToSkip += nBytesToSkip;
199
200
0
    nBytesToSkip = std::min( m_oFIFO->getSize() , m_nBytesToSkip );
201
0
    m_oFIFO->skip( nBytesToSkip );
202
0
    m_nBytesToSkip -= nBytesToSkip;
203
0
}
204
205
206
sal_Int32 OPipeImpl::available()
207
0
 {
208
0
    MutexGuard guard( m_mutexAccess );
209
0
    if( m_bInputStreamClosed )
210
0
    {
211
0
        throw NotConnectedException(
212
0
            u"Pipe::available NotConnectedException"_ustr,
213
0
            *this );
214
0
    }
215
0
    return m_oFIFO->getSize();
216
0
}
217
218
void OPipeImpl::closeInput()
219
0
{
220
0
    MutexGuard guard( m_mutexAccess );
221
222
0
    m_bInputStreamClosed = true;
223
224
0
    m_oFIFO.reset();
225
226
    // readBytes may throw an exception
227
0
    m_conditionBytesAvail.set();
228
229
0
    setSuccessor( Reference< XConnectable > () );
230
0
}
231
232
233
void OPipeImpl::writeBytes(const Sequence< sal_Int8 >& aData)
234
0
{
235
0
    MutexGuard guard( m_mutexAccess );
236
237
0
    if( m_bOutputStreamClosed )
238
0
    {
239
0
        throw NotConnectedException(
240
0
            u"Pipe::writeBytes NotConnectedException (outputstream)"_ustr,
241
0
            *this );
242
0
    }
243
244
0
    if( m_bInputStreamClosed )
245
0
    {
246
0
        throw NotConnectedException(
247
0
            u"Pipe::writeBytes NotConnectedException (inputstream)"_ustr,
248
0
            *this );
249
0
    }
250
251
    // check skipping
252
0
    sal_Int32 nLen = aData.getLength();
253
0
    if( m_nBytesToSkip  && m_nBytesToSkip >= nLen  ) {
254
        // all must be skipped - forget whole call
255
0
        m_nBytesToSkip -= nLen;
256
0
        return;
257
0
    }
258
259
    // adjust buffersize if necessary
260
0
    if( m_nBytesToSkip )
261
0
    {
262
0
        Sequence<sal_Int8> seqCopy(aData.getConstArray() + m_nBytesToSkip, nLen - m_nBytesToSkip);
263
0
        m_oFIFO->write( seqCopy );
264
0
    }
265
0
    else
266
0
    {
267
0
        m_oFIFO->write( aData );
268
0
    }
269
0
    m_nBytesToSkip = 0;
270
271
    // readBytes may check again if enough bytes are available
272
0
    m_conditionBytesAvail.set();
273
0
}
274
275
276
void OPipeImpl::flush()
277
0
{
278
    // nothing to do for a pipe
279
0
}
280
281
void OPipeImpl::closeOutput()
282
0
{
283
0
    MutexGuard guard( m_mutexAccess );
284
285
0
    m_bOutputStreamClosed = true;
286
0
    m_conditionBytesAvail.set();
287
0
    setPredecessor( Reference < XConnectable > () );
288
0
}
289
290
291
void OPipeImpl::setSuccessor( const Reference < XConnectable >  &r )
292
0
{
293
     /// if the references match, nothing needs to be done
294
0
     if( m_succ != r ) {
295
         /// store the reference for later use
296
0
         m_succ = r;
297
298
0
         if( m_succ.is() )
299
0
         {
300
0
              m_succ->setPredecessor(
301
0
                  Reference< XConnectable > ( static_cast< XConnectable * >(this) ) );
302
0
         }
303
0
     }
304
0
}
305
306
Reference < XConnectable > OPipeImpl::getSuccessor()
307
0
{
308
0
    return m_succ;
309
0
}
310
311
312
// XDataSource
313
void OPipeImpl::setPredecessor( const Reference < XConnectable > &r )
314
0
{
315
0
    if( r != m_pred ) {
316
0
        m_pred = r;
317
0
        if( m_pred.is() ) {
318
0
            m_pred->setSuccessor(
319
0
                Reference < XConnectable > ( static_cast< XConnectable * >(this) ) );
320
0
        }
321
0
    }
322
0
}
323
324
Reference < XConnectable > OPipeImpl::getPredecessor()
325
0
{
326
0
    return m_pred;
327
0
}
328
329
330
// XServiceInfo
331
OUString OPipeImpl::getImplementationName()
332
0
{
333
0
    return u"com.sun.star.comp.io.stm.Pipe"_ustr;
334
0
}
335
336
// XServiceInfo
337
sal_Bool OPipeImpl::supportsService(const OUString& ServiceName)
338
0
{
339
0
    return cppu::supportsService(this, ServiceName);
340
0
}
341
342
// XServiceInfo
343
Sequence< OUString > OPipeImpl::getSupportedServiceNames()
344
0
{
345
0
    return { u"com.sun.star.io.Pipe"_ustr };
346
0
}
347
348
}
349
350
extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
351
io_OPipeImpl_get_implementation(
352
    css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
353
0
{
354
0
    return cppu::acquire(new io_stm::OPipeImpl());
355
0
}
356
357
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */