1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <sal/config.h>
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>
27 #include <com/sun/star/lang/XServiceInfo.hpp>
29 #include <cppuhelper/implbase.hxx>
30 #include <cppuhelper/supportsservice.hxx>
32 #include <osl/conditn.hxx>
33 #include <osl/mutex.hxx>
39 using namespace ::osl
;
40 using namespace ::cppu
;
41 using namespace ::com::sun::star::uno
;
42 using namespace ::com::sun::star::io
;
43 using namespace ::com::sun::star::lang
;
45 #include "streamhelper.hxx"
47 namespace com::sun::star::uno
{ class XComponentContext
; }
49 // Implementation and service names
50 #define IMPLEMENTATION_NAME "com.sun.star.comp.io.stm.Pipe"
57 public WeakImplHelper
< XPipe
, XConnectable
, XServiceInfo
>
62 public: // XInputStream
63 virtual sal_Int32 SAL_CALL
readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
) override
;
64 virtual sal_Int32 SAL_CALL
readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
) override
;
65 virtual void SAL_CALL
skipBytes(sal_Int32 nBytesToSkip
) override
;
66 virtual sal_Int32 SAL_CALL
available() override
;
67 virtual void SAL_CALL
closeInput() override
;
69 public: // XOutputStream
71 virtual void SAL_CALL
writeBytes(const Sequence
< sal_Int8
>& aData
) override
;
72 virtual void SAL_CALL
flush() override
;
73 virtual void SAL_CALL
closeOutput() override
;
75 public: // XConnectable
76 virtual void SAL_CALL
setPredecessor(const Reference
< XConnectable
>& aPredecessor
) override
;
77 virtual Reference
< XConnectable
> SAL_CALL
getPredecessor() override
;
78 virtual void SAL_CALL
setSuccessor(const Reference
< XConnectable
> & aSuccessor
) override
;
79 virtual Reference
< XConnectable
> SAL_CALL
getSuccessor() override
;
82 public: // XServiceInfo
83 OUString SAL_CALL
getImplementationName() override
;
84 Sequence
< OUString
> SAL_CALL
getSupportedServiceNames() override
;
85 sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) override
;
89 Reference
< XConnectable
> m_succ
;
90 Reference
< XConnectable
> m_pred
;
92 sal_Int32 m_nBytesToSkip
;
94 bool m_bOutputStreamClosed
;
95 bool m_bInputStreamClosed
;
97 osl::Condition m_conditionBytesAvail
;
99 std::unique_ptr
<MemFIFO
> m_pFIFO
;
104 OPipeImpl::OPipeImpl()
106 , m_bOutputStreamClosed(false )
107 , m_bInputStreamClosed( false )
108 , m_pFIFO( new MemFIFO
)
114 sal_Int32
OPipeImpl::readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
118 { // start guarded section
119 MutexGuard
guard( m_mutexAccess
);
120 if( m_bInputStreamClosed
)
122 throw NotConnectedException(
123 "Pipe::readBytes NotConnectedException",
126 sal_Int32 nOccupiedBufferLen
= m_pFIFO
->getSize();
128 if( m_bOutputStreamClosed
&& nBytesToRead
> nOccupiedBufferLen
)
130 nBytesToRead
= nOccupiedBufferLen
;
133 if( nOccupiedBufferLen
< nBytesToRead
)
135 // wait outside guarded section
136 m_conditionBytesAvail
.reset();
139 // necessary bytes are available
140 m_pFIFO
->read( aData
, nBytesToRead
);
143 } // end guarded section
145 // wait for new data outside guarded section!
146 m_conditionBytesAvail
.wait();
151 sal_Int32
OPipeImpl::readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
155 MutexGuard
guard( m_mutexAccess
);
156 if( m_bInputStreamClosed
)
158 throw NotConnectedException(
159 "Pipe::readSomeBytes NotConnectedException",
162 if( m_pFIFO
->getSize() )
164 sal_Int32 nSize
= std::min( nMaxBytesToRead
, m_pFIFO
->getSize() );
165 aData
.realloc( nSize
);
166 m_pFIFO
->read( aData
, nSize
);
170 if( m_bOutputStreamClosed
)
172 // no bytes in buffer anymore
177 m_conditionBytesAvail
.wait();
182 void OPipeImpl::skipBytes(sal_Int32 nBytesToSkip
)
184 MutexGuard
guard( m_mutexAccess
);
185 if( m_bInputStreamClosed
)
187 throw NotConnectedException(
188 "Pipe::skipBytes NotConnectedException",
194 > std::numeric_limits
< sal_Int32
>::max() - m_nBytesToSkip
) )
196 throw BufferSizeExceededException(
197 "Pipe::skipBytes BufferSizeExceededException",
200 m_nBytesToSkip
+= nBytesToSkip
;
202 nBytesToSkip
= std::min( m_pFIFO
->getSize() , m_nBytesToSkip
);
203 m_pFIFO
->skip( nBytesToSkip
);
204 m_nBytesToSkip
-= nBytesToSkip
;
208 sal_Int32
OPipeImpl::available()
210 MutexGuard
guard( m_mutexAccess
);
211 if( m_bInputStreamClosed
)
213 throw NotConnectedException(
214 "Pipe::available NotConnectedException",
217 return m_pFIFO
->getSize();
220 void OPipeImpl::closeInput()
222 MutexGuard
guard( m_mutexAccess
);
224 m_bInputStreamClosed
= true;
228 // readBytes may throw an exception
229 m_conditionBytesAvail
.set();
231 setSuccessor( Reference
< XConnectable
> () );
235 void OPipeImpl::writeBytes(const Sequence
< sal_Int8
>& aData
)
237 MutexGuard
guard( m_mutexAccess
);
239 if( m_bOutputStreamClosed
)
241 throw NotConnectedException(
242 "Pipe::writeBytes NotConnectedException (outputstream)",
246 if( m_bInputStreamClosed
)
248 throw NotConnectedException(
249 "Pipe::writeBytes NotConnectedException (inputstream)",
254 sal_Int32 nLen
= aData
.getLength();
255 if( m_nBytesToSkip
&& m_nBytesToSkip
>= nLen
) {
256 // all must be skipped - forget whole call
257 m_nBytesToSkip
-= nLen
;
261 // adjust buffersize if necessary
264 Sequence
< sal_Int8
> seqCopy( nLen
- m_nBytesToSkip
);
265 memcpy( seqCopy
.getArray() , &( aData
.getConstArray()[m_nBytesToSkip
] ) , nLen
-m_nBytesToSkip
);
266 m_pFIFO
->write( seqCopy
);
270 m_pFIFO
->write( aData
);
274 // readBytes may check again if enough bytes are available
275 m_conditionBytesAvail
.set();
279 void OPipeImpl::flush()
281 // nothing to do for a pipe
284 void OPipeImpl::closeOutput()
286 MutexGuard
guard( m_mutexAccess
);
288 m_bOutputStreamClosed
= true;
289 m_conditionBytesAvail
.set();
290 setPredecessor( Reference
< XConnectable
> () );
294 void OPipeImpl::setSuccessor( const Reference
< XConnectable
> &r
)
296 /// if the references match, nothing needs to be done
298 /// store the reference for later use
303 m_succ
->setPredecessor(
304 Reference
< XConnectable
> ( static_cast< XConnectable
* >(this) ) );
309 Reference
< XConnectable
> OPipeImpl::getSuccessor()
316 void OPipeImpl::setPredecessor( const Reference
< XConnectable
> &r
)
321 m_pred
->setSuccessor(
322 Reference
< XConnectable
> ( static_cast< XConnectable
* >(this) ) );
327 Reference
< XConnectable
> OPipeImpl::getPredecessor()
334 OUString
OPipeImpl::getImplementationName()
336 return IMPLEMENTATION_NAME
;
340 sal_Bool
OPipeImpl::supportsService(const OUString
& ServiceName
)
342 return cppu::supportsService(this, ServiceName
);
346 Sequence
< OUString
> OPipeImpl::getSupportedServiceNames()
348 return { "com.sun.star.io.Pipe" };
353 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
*
354 io_OPipeImpl_get_implementation(
355 css::uno::XComponentContext
* , css::uno::Sequence
<css::uno::Any
> const&)
357 return cppu::acquire(new io_stm::OPipeImpl());
360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */