1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: opipe.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_io.hxx"
35 #include <com/sun/star/io/XInputStream.hpp>
36 #include <com/sun/star/io/XOutputStream.hpp>
37 #include <com/sun/star/io/XConnectable.hpp>
39 #include <com/sun/star/lang/XServiceInfo.hpp>
41 #include <cppuhelper/factory.hxx>
43 #include <cppuhelper/implbase4.hxx> // OWeakObject
45 #include <osl/conditn.hxx>
46 #include <osl/mutex.hxx>
51 using namespace ::rtl
;
52 using namespace ::osl
;
53 using namespace ::cppu
;
54 using namespace ::com::sun::star::uno
;
55 using namespace ::com::sun::star::io
;
56 using namespace ::com::sun::star::lang
;
58 #include "factreg.hxx"
59 #include "streamhelper.hxx"
61 // Implementation and service names
62 #define IMPLEMENTATION_NAME "com.sun.star.comp.io.stm.Pipe"
63 #define SERVICE_NAME "com.sun.star.io.Pipe"
68 public WeakImplHelper4
< XInputStream
, XOutputStream
, XConnectable
, XServiceInfo
>
74 public: // XInputStream
75 virtual sal_Int32 SAL_CALL
readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
76 throw( NotConnectedException
,
77 BufferSizeExceededException
,
79 virtual sal_Int32 SAL_CALL
readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
80 throw( NotConnectedException
,
81 BufferSizeExceededException
,
83 virtual void SAL_CALL
skipBytes(sal_Int32 nBytesToSkip
)
84 throw( NotConnectedException
,
85 BufferSizeExceededException
,
87 virtual sal_Int32 SAL_CALL
available(void)
88 throw( NotConnectedException
,
90 virtual void SAL_CALL
closeInput(void)
91 throw( NotConnectedException
,
94 public: // XOutputStream
96 virtual void SAL_CALL
writeBytes(const Sequence
< sal_Int8
>& aData
)
97 throw( NotConnectedException
,
98 BufferSizeExceededException
,
100 virtual void SAL_CALL
flush(void)
101 throw( NotConnectedException
,
102 BufferSizeExceededException
,
104 virtual void SAL_CALL
closeOutput(void)
105 throw( NotConnectedException
,
106 BufferSizeExceededException
,
109 public: // XConnectable
110 virtual void SAL_CALL
setPredecessor(const Reference
< XConnectable
>& aPredecessor
)
111 throw( RuntimeException
);
112 virtual Reference
< XConnectable
> SAL_CALL
getPredecessor(void) throw( RuntimeException
);
113 virtual void SAL_CALL
setSuccessor(const Reference
< XConnectable
> & aSuccessor
)
114 throw( RuntimeException
);
115 virtual Reference
< XConnectable
> SAL_CALL
getSuccessor(void) throw( RuntimeException
) ;
118 public: // XServiceInfo
119 OUString SAL_CALL
getImplementationName() throw( );
120 Sequence
< OUString
> SAL_CALL
getSupportedServiceNames(void) throw( );
121 sal_Bool SAL_CALL
supportsService(const OUString
& ServiceName
) throw( );
126 inline void checkInvariant();
128 Reference
< XConnectable
> m_succ
;
129 Reference
< XConnectable
> m_pred
;
131 sal_Int32 m_nBytesToSkip
;
135 sal_Bool m_bOutputStreamClosed
;
136 sal_Bool m_bInputStreamClosed
;
138 oslCondition m_conditionBytesAvail
;
145 OPipeImpl::OPipeImpl()
147 g_moduleCount
.modCnt
.acquire( &g_moduleCount
.modCnt
);
150 m_bOutputStreamClosed
= sal_False
;
151 m_bInputStreamClosed
= sal_False
;
153 m_pFIFO
= new MemFIFO
;
154 m_conditionBytesAvail
= osl_createCondition();
157 OPipeImpl::~OPipeImpl()
159 osl_destroyCondition( m_conditionBytesAvail
);
161 g_moduleCount
.modCnt
.release( &g_moduleCount
.modCnt
);
165 // These invariants must hold when entering a guarded method or leaving a guarded method.
166 void OPipeImpl::checkInvariant()
171 sal_Int32
OPipeImpl::readBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nBytesToRead
)
172 throw( NotConnectedException
, BufferSizeExceededException
,RuntimeException
)
176 { // start guarded section
177 MutexGuard
guard( m_mutexAccess
);
178 if( m_bInputStreamClosed
)
180 throw NotConnectedException(
181 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::readBytes NotConnectedException" )),
184 sal_Int32 nOccupiedBufferLen
= m_pFIFO
->getSize();
186 if( m_bOutputStreamClosed
&& nBytesToRead
> nOccupiedBufferLen
)
188 nBytesToRead
= nOccupiedBufferLen
;
191 if( nOccupiedBufferLen
< nBytesToRead
)
193 // wait outside guarded section
194 osl_resetCondition( m_conditionBytesAvail
);
197 // necessary bytes are available
198 m_pFIFO
->read( aData
, nBytesToRead
);
201 } // end guarded section
203 // wait for new data outside guarded section!
204 osl_waitCondition( m_conditionBytesAvail
, 0 );
209 sal_Int32
OPipeImpl::readSomeBytes(Sequence
< sal_Int8
>& aData
, sal_Int32 nMaxBytesToRead
)
210 throw( NotConnectedException
,
211 BufferSizeExceededException
,
216 MutexGuard
guard( m_mutexAccess
);
217 if( m_bInputStreamClosed
)
219 throw NotConnectedException(
220 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::readSomeBytes NotConnectedException" )),
223 if( m_pFIFO
->getSize() )
225 sal_Int32 nSize
= Min( nMaxBytesToRead
, m_pFIFO
->getSize() );
226 aData
.realloc( nSize
);
227 m_pFIFO
->read( aData
, nSize
);
231 if( m_bOutputStreamClosed
)
233 // no bytes in buffer anymore
238 osl_waitCondition( m_conditionBytesAvail
, 0 );
243 void OPipeImpl::skipBytes(sal_Int32 nBytesToSkip
)
244 throw( NotConnectedException
,
245 BufferSizeExceededException
,
248 MutexGuard
guard( m_mutexAccess
);
249 if( m_bInputStreamClosed
)
251 throw NotConnectedException(
252 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::skipBytes NotConnectedException" ) ),
258 > std::numeric_limits
< sal_Int32
>::max() - m_nBytesToSkip
) )
260 throw BufferSizeExceededException(
261 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::skipBytes BufferSizeExceededException" )),
264 m_nBytesToSkip
+= nBytesToSkip
;
266 nBytesToSkip
= Min( m_pFIFO
->getSize() , m_nBytesToSkip
);
267 m_pFIFO
->skip( nBytesToSkip
);
268 m_nBytesToSkip
-= nBytesToSkip
;
272 sal_Int32
OPipeImpl::available(void)
273 throw( NotConnectedException
,
276 MutexGuard
guard( m_mutexAccess
);
277 if( m_bInputStreamClosed
)
279 throw NotConnectedException(
280 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::available NotConnectedException" ) ),
284 return m_pFIFO
->getSize();
287 void OPipeImpl::closeInput(void)
288 throw( NotConnectedException
,
291 MutexGuard
guard( m_mutexAccess
);
293 m_bInputStreamClosed
= sal_True
;
298 // readBytes may throw an exception
299 osl_setCondition( m_conditionBytesAvail
);
301 setSuccessor( Reference
< XConnectable
> () );
306 void OPipeImpl::writeBytes(const Sequence
< sal_Int8
>& aData
)
307 throw( NotConnectedException
,
308 BufferSizeExceededException
,
311 MutexGuard
guard( m_mutexAccess
);
314 if( m_bOutputStreamClosed
)
316 throw NotConnectedException(
317 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::writeBytes NotConnectedException (outputstream)" )),
321 if( m_bInputStreamClosed
)
323 throw NotConnectedException(
324 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::writeBytes NotConnectedException (inputstream)" )),
329 sal_Int32 nLen
= aData
.getLength();
330 if( m_nBytesToSkip
&& m_nBytesToSkip
>= nLen
) {
331 // all must be skipped - forget whole call
332 m_nBytesToSkip
-= nLen
;
336 // adjust buffersize if necessary
342 Sequence
< sal_Int8
> seqCopy( nLen
- m_nBytesToSkip
);
343 memcpy( seqCopy
.getArray() , &( aData
.getConstArray()[m_nBytesToSkip
] ) , nLen
-m_nBytesToSkip
);
344 m_pFIFO
->write( seqCopy
);
348 m_pFIFO
->write( aData
);
352 catch ( IFIFO_OutOfBoundsException
& )
354 throw BufferSizeExceededException(
355 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::writeBytes BufferSizeExceededException" )),
358 catch ( IFIFO_OutOfMemoryException
& )
360 throw BufferSizeExceededException(
361 OUString( RTL_CONSTASCII_USTRINGPARAM( "Pipe::writeBytes BufferSizeExceededException" )),
365 // readBytes may check again if enough bytes are available
366 osl_setCondition( m_conditionBytesAvail
);
372 void OPipeImpl::flush(void)
373 throw( NotConnectedException
,
374 BufferSizeExceededException
,
377 // nothing to do for a pipe
381 void OPipeImpl::closeOutput(void)
382 throw( NotConnectedException
,
383 BufferSizeExceededException
,
386 MutexGuard
guard( m_mutexAccess
);
388 m_bOutputStreamClosed
= sal_True
;
389 osl_setCondition( m_conditionBytesAvail
);
390 setPredecessor( Reference
< XConnectable
> () );
395 void OPipeImpl::setSuccessor( const Reference
< XConnectable
> &r
)
396 throw( RuntimeException
)
398 /// if the references match, nothing needs to be done
400 /// store the reference for later use
405 m_succ
->setPredecessor(
406 Reference
< XConnectable
> ( SAL_STATIC_CAST( XConnectable
* , this ) ) );
411 Reference
< XConnectable
> OPipeImpl::getSuccessor() throw( RuntimeException
)
418 void OPipeImpl::setPredecessor( const Reference
< XConnectable
> &r
)
419 throw( RuntimeException
)
424 m_pred
->setSuccessor(
425 Reference
< XConnectable
> ( SAL_STATIC_CAST( XConnectable
* , this ) ) );
430 Reference
< XConnectable
> OPipeImpl::getPredecessor() throw( RuntimeException
)
439 OUString
OPipeImpl::getImplementationName() throw( )
441 return OPipeImpl_getImplementationName();
445 sal_Bool
OPipeImpl::supportsService(const OUString
& ServiceName
) throw( )
447 Sequence
< OUString
> aSNL
= getSupportedServiceNames();
448 const OUString
* pArray
= aSNL
.getConstArray();
450 for( sal_Int32 i
= 0; i
< aSNL
.getLength(); i
++ )
451 if( pArray
[i
] == ServiceName
)
458 Sequence
< OUString
> OPipeImpl::getSupportedServiceNames(void) throw( )
460 return OPipeImpl_getSupportedServiceNames();
467 /* implementation functions
473 Reference
< XInterface
> SAL_CALL
OPipeImpl_CreateInstance(
474 const Reference
< XComponentContext
> & ) throw(Exception
)
476 OPipeImpl
*p
= new OPipeImpl
;
478 return Reference
< XInterface
> ( SAL_STATIC_CAST( OWeakObject
* , p
) );
482 OUString
OPipeImpl_getImplementationName()
484 return OUString( RTL_CONSTASCII_USTRINGPARAM ( IMPLEMENTATION_NAME
) );
487 Sequence
<OUString
> OPipeImpl_getSupportedServiceNames(void)
489 Sequence
<OUString
> aRet(1);
490 aRet
.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( SERVICE_NAME
));