1015 lines
29 KiB
C++
1015 lines
29 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_io.hxx"
|
|
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include <com/sun/star/io/XMarkableStream.hpp>
|
|
#include <com/sun/star/io/XOutputStream.hpp>
|
|
#include <com/sun/star/io/XInputStream.hpp>
|
|
#include <com/sun/star/io/XActiveDataSource.hpp>
|
|
#include <com/sun/star/io/XActiveDataSink.hpp>
|
|
#include <com/sun/star/io/XConnectable.hpp>
|
|
#include <com/sun/star/lang/XServiceInfo.hpp>
|
|
|
|
#include <cppuhelper/factory.hxx>
|
|
#include <cppuhelper/weak.hxx> // OWeakObject
|
|
#include <cppuhelper/implbase5.hxx>
|
|
|
|
#include <osl/mutex.hxx>
|
|
#include <rtl/ustrbuf.hxx>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
using namespace ::std;
|
|
using namespace ::rtl;
|
|
using namespace ::cppu;
|
|
using namespace ::osl;
|
|
using namespace ::com::sun::star::io;
|
|
using namespace ::com::sun::star::uno;
|
|
using namespace ::com::sun::star::lang;
|
|
|
|
#include "streamhelper.hxx"
|
|
#include "factreg.hxx"
|
|
|
|
namespace io_stm {
|
|
|
|
/***********************
|
|
*
|
|
* OMarkableOutputStream.
|
|
*
|
|
* This object allows to set marks in an outputstream. It is allowed to jump back to the marks and
|
|
* rewrite the some bytes.
|
|
*
|
|
* The object must buffer the data since the last mark set. Flush will not
|
|
* have any effect. As soon as the last mark has been removed, the object may write the data
|
|
* through to the chained object.
|
|
*
|
|
**********************/
|
|
class OMarkableOutputStream :
|
|
public WeakImplHelper5< XOutputStream ,
|
|
XActiveDataSource ,
|
|
XMarkableStream ,
|
|
XConnectable,
|
|
XServiceInfo
|
|
>
|
|
{
|
|
public:
|
|
OMarkableOutputStream( );
|
|
~OMarkableOutputStream();
|
|
|
|
public: // XOutputStream
|
|
virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL flush(void)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL closeOutput(void)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException);
|
|
|
|
public: // XMarkable
|
|
virtual sal_Int32 SAL_CALL createMark(void)
|
|
throw (IOException, RuntimeException);
|
|
virtual void SAL_CALL deleteMark(sal_Int32 Mark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL jumpToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL jumpToFurthest(void)
|
|
throw (IOException, RuntimeException);
|
|
virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException);
|
|
|
|
public: // XActiveDataSource
|
|
virtual void SAL_CALL setOutputStream(const Reference < XOutputStream > & aStream)
|
|
throw (RuntimeException);
|
|
virtual Reference < XOutputStream > SAL_CALL getOutputStream(void)
|
|
throw (RuntimeException);
|
|
|
|
public: // XConnectable
|
|
virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor)
|
|
throw (RuntimeException);
|
|
virtual Reference < XConnectable > SAL_CALL getPredecessor(void) throw (RuntimeException);
|
|
virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor)
|
|
throw (RuntimeException);
|
|
virtual Reference< XConnectable > SAL_CALL getSuccessor(void) throw (RuntimeException);
|
|
|
|
public: // XServiceInfo
|
|
OUString SAL_CALL getImplementationName() throw ();
|
|
Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw ();
|
|
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw ();
|
|
|
|
private:
|
|
// helper methods
|
|
void checkMarksAndFlush() throw( NotConnectedException, BufferSizeExceededException);
|
|
|
|
Reference< XConnectable > m_succ;
|
|
Reference< XConnectable > m_pred;
|
|
|
|
Reference< XOutputStream > m_output;
|
|
sal_Bool m_bValidStream;
|
|
|
|
IRingBuffer *m_pBuffer;
|
|
map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
|
|
sal_Int32 m_nCurrentPos;
|
|
sal_Int32 m_nCurrentMark;
|
|
|
|
Mutex m_mutex;
|
|
};
|
|
|
|
OMarkableOutputStream::OMarkableOutputStream( )
|
|
{
|
|
g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
|
|
m_pBuffer = new MemRingBuffer;
|
|
m_nCurrentPos = 0;
|
|
m_nCurrentMark = 0;
|
|
}
|
|
|
|
OMarkableOutputStream::~OMarkableOutputStream()
|
|
{
|
|
delete m_pBuffer;
|
|
g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
|
|
}
|
|
|
|
|
|
// XOutputStream
|
|
void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
if( m_bValidStream ) {
|
|
if( m_mapMarks.empty() && ( m_pBuffer->getSize() == 0 ) ) {
|
|
// no mark and buffer active, simple write through
|
|
m_output->writeBytes( aData );
|
|
}
|
|
else {
|
|
MutexGuard guard( m_mutex );
|
|
// new data must be buffered
|
|
try
|
|
{
|
|
m_pBuffer->writeAt( m_nCurrentPos , aData );
|
|
m_nCurrentPos += aData.getLength();
|
|
}
|
|
catch( IRingBuffer_OutOfBoundsException & )
|
|
{
|
|
throw BufferSizeExceededException();
|
|
}
|
|
catch( IRingBuffer_OutOfMemoryException & )
|
|
{
|
|
throw BufferSizeExceededException();
|
|
}
|
|
checkMarksAndFlush();
|
|
}
|
|
}
|
|
else {
|
|
throw NotConnectedException();
|
|
}
|
|
}
|
|
|
|
void OMarkableOutputStream::flush(void)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
Reference< XOutputStream > output;
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
output = m_output;
|
|
}
|
|
|
|
// Markable cannot flush buffered data, because the data may get rewritten,
|
|
// however one can forward the flush to the chained stream to give it
|
|
// a chance to write data buffered in the chained stream.
|
|
if( output.is() )
|
|
{
|
|
output->flush();
|
|
}
|
|
}
|
|
|
|
void OMarkableOutputStream::closeOutput(void)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
if( m_bValidStream ) {
|
|
MutexGuard guard( m_mutex );
|
|
// all marks must be cleared and all
|
|
|
|
if( ! m_mapMarks.empty() )
|
|
{
|
|
m_mapMarks.clear();
|
|
}
|
|
m_nCurrentPos = m_pBuffer->getSize();
|
|
checkMarksAndFlush();
|
|
|
|
m_output->closeOutput();
|
|
|
|
setOutputStream( Reference< XOutputStream > () );
|
|
setPredecessor( Reference < XConnectable >() );
|
|
setSuccessor( Reference< XConnectable > () );
|
|
}
|
|
else {
|
|
throw NotConnectedException();
|
|
}
|
|
}
|
|
|
|
|
|
sal_Int32 OMarkableOutputStream::createMark(void)
|
|
throw ( IOException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
sal_Int32 nMark = m_nCurrentMark;
|
|
|
|
m_mapMarks[nMark] = m_nCurrentPos;
|
|
|
|
m_nCurrentMark ++;
|
|
return nMark;
|
|
}
|
|
|
|
void OMarkableOutputStream::deleteMark(sal_Int32 Mark)
|
|
throw( IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
|
|
|
|
if( ii == m_mapMarks.end() ) {
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableOutputStream::deleteMark unknown mark (" );
|
|
buf.append( Mark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
|
|
}
|
|
else {
|
|
m_mapMarks.erase( ii );
|
|
checkMarksAndFlush();
|
|
}
|
|
}
|
|
|
|
void OMarkableOutputStream::jumpToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
|
|
|
|
if( ii == m_mapMarks.end() ) {
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableOutputStream::jumpToMark unknown mark (" );
|
|
buf.append( nMark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
|
|
}
|
|
else {
|
|
m_nCurrentPos = (*ii).second;
|
|
}
|
|
}
|
|
|
|
void OMarkableOutputStream::jumpToFurthest(void)
|
|
throw (IOException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
m_nCurrentPos = m_pBuffer->getSize();
|
|
checkMarksAndFlush();
|
|
}
|
|
|
|
sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException)
|
|
{
|
|
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
|
|
|
|
if( ii == m_mapMarks.end() )
|
|
{
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableOutputStream::offsetToMark unknown mark (" );
|
|
buf.append( nMark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
|
|
}
|
|
return m_nCurrentPos - (*ii).second;
|
|
}
|
|
|
|
|
|
|
|
// XActiveDataSource2
|
|
void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream)
|
|
throw (RuntimeException)
|
|
{
|
|
if( m_output != aStream ) {
|
|
m_output = aStream;
|
|
|
|
Reference < XConnectable > succ( m_output , UNO_QUERY );
|
|
setSuccessor( succ );
|
|
}
|
|
m_bValidStream = m_output.is();
|
|
}
|
|
|
|
Reference< XOutputStream > OMarkableOutputStream::getOutputStream(void) throw (RuntimeException)
|
|
{
|
|
return m_output;
|
|
}
|
|
|
|
|
|
|
|
void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r )
|
|
throw (RuntimeException)
|
|
{
|
|
/// if the references match, nothing needs to be done
|
|
if( m_succ != r ) {
|
|
/// store the reference for later use
|
|
m_succ = r;
|
|
|
|
if( m_succ.is() ) {
|
|
m_succ->setPredecessor( Reference < XConnectable > (
|
|
SAL_STATIC_CAST( XConnectable * , this ) ) );
|
|
}
|
|
}
|
|
}
|
|
Reference <XConnectable > OMarkableOutputStream::getSuccessor() throw (RuntimeException)
|
|
{
|
|
return m_succ;
|
|
}
|
|
|
|
|
|
// XDataSource
|
|
void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r )
|
|
throw (RuntimeException)
|
|
{
|
|
if( r != m_pred ) {
|
|
m_pred = r;
|
|
if( m_pred.is() ) {
|
|
m_pred->setSuccessor( Reference < XConnectable > (
|
|
SAL_STATIC_CAST ( XConnectable * , this ) ) );
|
|
}
|
|
}
|
|
}
|
|
Reference < XConnectable > OMarkableOutputStream::getPredecessor() throw (RuntimeException)
|
|
{
|
|
return m_pred;
|
|
}
|
|
|
|
|
|
// private methods
|
|
|
|
void OMarkableOutputStream::checkMarksAndFlush() throw( NotConnectedException,
|
|
BufferSizeExceededException)
|
|
{
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
|
|
|
|
// find the smallest mark
|
|
sal_Int32 nNextFound = m_nCurrentPos;
|
|
for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ii ++ ) {
|
|
if( (*ii).second <= nNextFound ) {
|
|
nNextFound = (*ii).second;
|
|
}
|
|
}
|
|
|
|
if( nNextFound ) {
|
|
// some data must be released !
|
|
m_nCurrentPos -= nNextFound;
|
|
for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ii ++ ) {
|
|
(*ii).second -= nNextFound;
|
|
}
|
|
|
|
Sequence<sal_Int8> seq(nNextFound);
|
|
m_pBuffer->readAt( 0 , seq , nNextFound );
|
|
m_pBuffer->forgetFromStart( nNextFound );
|
|
|
|
// now write data through to streams
|
|
m_output->writeBytes( seq );
|
|
}
|
|
else {
|
|
// nothing to do. There is a mark or the current cursor position, that prevents
|
|
// releasing data !
|
|
}
|
|
}
|
|
|
|
|
|
// XServiceInfo
|
|
OUString OMarkableOutputStream::getImplementationName() throw ()
|
|
{
|
|
return OMarkableOutputStream_getImplementationName();
|
|
}
|
|
|
|
// XServiceInfo
|
|
sal_Bool OMarkableOutputStream::supportsService(const OUString& ServiceName) throw ()
|
|
{
|
|
Sequence< OUString > aSNL = getSupportedServiceNames();
|
|
const OUString * pArray = aSNL.getConstArray();
|
|
|
|
for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
|
|
if( pArray[i] == ServiceName )
|
|
return sal_True;
|
|
|
|
return sal_False;
|
|
}
|
|
|
|
// XServiceInfo
|
|
Sequence< OUString > OMarkableOutputStream::getSupportedServiceNames(void) throw ()
|
|
{
|
|
return OMarkableOutputStream_getSupportedServiceNames();
|
|
}
|
|
|
|
|
|
|
|
|
|
/*------------------------
|
|
*
|
|
* external binding
|
|
*
|
|
*------------------------*/
|
|
Reference< XInterface > SAL_CALL OMarkableOutputStream_CreateInstance( const Reference < XComponentContext > & ) throw(Exception)
|
|
{
|
|
OMarkableOutputStream *p = new OMarkableOutputStream( );
|
|
|
|
return Reference < XInterface > ( ( OWeakObject * ) p );
|
|
}
|
|
|
|
OUString OMarkableOutputStream_getImplementationName()
|
|
{
|
|
return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.stm.MarkableOutputStream" ));
|
|
}
|
|
|
|
Sequence<OUString> OMarkableOutputStream_getSupportedServiceNames(void)
|
|
{
|
|
Sequence<OUString> aRet(1);
|
|
aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.MarkableOutputStream" ) );
|
|
|
|
return aRet;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//------------------------------------------------
|
|
//
|
|
// XMarkableInputStream
|
|
//
|
|
//------------------------------------------------
|
|
|
|
class OMarkableInputStream :
|
|
public WeakImplHelper5
|
|
<
|
|
XInputStream,
|
|
XActiveDataSink,
|
|
XMarkableStream,
|
|
XConnectable,
|
|
XServiceInfo
|
|
>
|
|
{
|
|
public:
|
|
OMarkableInputStream( );
|
|
~OMarkableInputStream();
|
|
|
|
|
|
public: // XInputStream
|
|
virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException) ;
|
|
virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException);
|
|
|
|
virtual sal_Int32 SAL_CALL available(void)
|
|
throw ( NotConnectedException,
|
|
RuntimeException);
|
|
virtual void SAL_CALL closeInput(void) throw (NotConnectedException, RuntimeException);
|
|
|
|
public: // XMarkable
|
|
virtual sal_Int32 SAL_CALL createMark(void)
|
|
throw (IOException, RuntimeException);
|
|
virtual void SAL_CALL deleteMark(sal_Int32 Mark)
|
|
throw (IOException, IllegalArgumentException, RuntimeException);
|
|
virtual void SAL_CALL jumpToMark(sal_Int32 nMark)
|
|
throw (IOException, IllegalArgumentException, RuntimeException);
|
|
virtual void SAL_CALL jumpToFurthest(void)
|
|
throw (IOException, RuntimeException);
|
|
virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark)
|
|
throw (IOException, IllegalArgumentException,RuntimeException);
|
|
|
|
public: // XActiveDataSink
|
|
virtual void SAL_CALL setInputStream(const Reference < XInputStream > & aStream)
|
|
throw (RuntimeException);
|
|
virtual Reference < XInputStream > SAL_CALL getInputStream(void)
|
|
throw (RuntimeException);
|
|
|
|
public: // XConnectable
|
|
virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor)
|
|
throw (RuntimeException);
|
|
virtual Reference < XConnectable > SAL_CALL getPredecessor(void)
|
|
throw (RuntimeException);
|
|
virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor)
|
|
throw (RuntimeException);
|
|
virtual Reference < XConnectable > SAL_CALL getSuccessor(void) throw (RuntimeException);
|
|
|
|
public: // XServiceInfo
|
|
OUString SAL_CALL getImplementationName() throw ();
|
|
Sequence< OUString > SAL_CALL getSupportedServiceNames(void) throw ();
|
|
sal_Bool SAL_CALL supportsService(const OUString& ServiceName) throw ();
|
|
|
|
private:
|
|
void checkMarksAndFlush();
|
|
|
|
Reference < XConnectable > m_succ;
|
|
Reference < XConnectable > m_pred;
|
|
|
|
Reference< XInputStream > m_input;
|
|
sal_Bool m_bValidStream;
|
|
|
|
IRingBuffer *m_pBuffer;
|
|
map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
|
|
sal_Int32 m_nCurrentPos;
|
|
sal_Int32 m_nCurrentMark;
|
|
|
|
Mutex m_mutex;
|
|
};
|
|
|
|
OMarkableInputStream::OMarkableInputStream()
|
|
{
|
|
g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
|
|
m_nCurrentPos = 0;
|
|
m_nCurrentMark = 0;
|
|
m_pBuffer = new MemRingBuffer;
|
|
}
|
|
|
|
|
|
OMarkableInputStream::~OMarkableInputStream()
|
|
{
|
|
if( m_pBuffer ) {
|
|
delete m_pBuffer;
|
|
}
|
|
g_moduleCount.modCnt.release( &g_moduleCount.modCnt );
|
|
}
|
|
|
|
|
|
|
|
|
|
// XInputStream
|
|
|
|
sal_Int32 OMarkableInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
sal_Int32 nBytesRead;
|
|
|
|
if( m_bValidStream ) {
|
|
MutexGuard guard( m_mutex );
|
|
if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
|
|
// normal read !
|
|
nBytesRead = m_input->readBytes( aData, nBytesToRead );
|
|
}
|
|
else {
|
|
// read from buffer
|
|
sal_Int32 nRead;
|
|
|
|
// read enough bytes into buffer
|
|
if( m_pBuffer->getSize() - m_nCurrentPos < nBytesToRead ) {
|
|
sal_Int32 nToRead = nBytesToRead - ( m_pBuffer->getSize() - m_nCurrentPos );
|
|
nRead = m_input->readBytes( aData , nToRead );
|
|
|
|
OSL_ASSERT( aData.getLength() == nRead );
|
|
|
|
try
|
|
{
|
|
m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
|
|
}
|
|
catch( IRingBuffer_OutOfMemoryException & ) {
|
|
throw BufferSizeExceededException();
|
|
}
|
|
catch( IRingBuffer_OutOfBoundsException & ) {
|
|
throw BufferSizeExceededException();
|
|
}
|
|
|
|
if( nRead < nToRead ) {
|
|
nBytesToRead = nBytesToRead - (nToRead-nRead);
|
|
}
|
|
}
|
|
|
|
OSL_ASSERT( m_pBuffer->getSize() - m_nCurrentPos >= nBytesToRead );
|
|
|
|
m_pBuffer->readAt( m_nCurrentPos , aData , nBytesToRead );
|
|
|
|
m_nCurrentPos += nBytesToRead;
|
|
nBytesRead = nBytesToRead;
|
|
}
|
|
}
|
|
else {
|
|
throw NotConnectedException(
|
|
OUString( RTL_CONSTASCII_USTRINGPARAM("MarkableInputStream::readBytes NotConnectedException")) ,
|
|
*this );
|
|
}
|
|
return nBytesRead;
|
|
}
|
|
|
|
|
|
sal_Int32 OMarkableInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
|
|
sal_Int32 nBytesRead;
|
|
if( m_bValidStream ) {
|
|
MutexGuard guard( m_mutex );
|
|
if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
|
|
// normal read !
|
|
nBytesRead = m_input->readSomeBytes( aData, nMaxBytesToRead );
|
|
}
|
|
else {
|
|
// read from buffer
|
|
sal_Int32 nRead = 0;
|
|
sal_Int32 nInBuffer = m_pBuffer->getSize() - m_nCurrentPos;
|
|
sal_Int32 nAdditionalBytesToRead = Min(nMaxBytesToRead-nInBuffer,m_input->available());
|
|
nAdditionalBytesToRead = Max(0 , nAdditionalBytesToRead );
|
|
|
|
// read enough bytes into buffer
|
|
if( 0 == nInBuffer ) {
|
|
nRead = m_input->readSomeBytes( aData , nMaxBytesToRead );
|
|
}
|
|
else if( nAdditionalBytesToRead ) {
|
|
nRead = m_input->readBytes( aData , nAdditionalBytesToRead );
|
|
}
|
|
|
|
if( nRead ) {
|
|
aData.realloc( nRead );
|
|
try
|
|
{
|
|
m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
|
|
}
|
|
catch( IRingBuffer_OutOfMemoryException & )
|
|
{
|
|
throw BufferSizeExceededException();
|
|
}
|
|
catch( IRingBuffer_OutOfBoundsException & )
|
|
{
|
|
throw BufferSizeExceededException();
|
|
}
|
|
}
|
|
|
|
nBytesRead = Min( nMaxBytesToRead , nInBuffer + nRead );
|
|
|
|
// now take everything from buffer !
|
|
m_pBuffer->readAt( m_nCurrentPos , aData , nBytesRead );
|
|
|
|
m_nCurrentPos += nBytesRead;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw NotConnectedException(
|
|
OUString( RTL_CONSTASCII_USTRINGPARAM("MarkableInputStream::readSomeBytes NotConnectedException")) ,
|
|
*this );
|
|
}
|
|
return nBytesRead;
|
|
|
|
|
|
}
|
|
|
|
|
|
void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip)
|
|
throw ( NotConnectedException,
|
|
BufferSizeExceededException,
|
|
RuntimeException)
|
|
{
|
|
if ( nBytesToSkip < 0 )
|
|
throw BufferSizeExceededException(
|
|
::rtl::OUString::createFromAscii( "precondition not met: XInputStream::skipBytes: non-negative integer required!" ),
|
|
*this
|
|
);
|
|
|
|
// this method is blocking
|
|
sal_Int32 nRead;
|
|
Sequence<sal_Int8> seqDummy( nBytesToSkip );
|
|
|
|
nRead = readBytes( seqDummy , nBytesToSkip );
|
|
}
|
|
|
|
sal_Int32 OMarkableInputStream::available(void) throw (NotConnectedException, RuntimeException)
|
|
{
|
|
sal_Int32 nAvail;
|
|
if( m_bValidStream ) {
|
|
MutexGuard guard( m_mutex );
|
|
nAvail = m_input->available() + ( m_pBuffer->getSize() - m_nCurrentPos );
|
|
}
|
|
else
|
|
{
|
|
throw NotConnectedException(
|
|
OUString( RTL_CONSTASCII_USTRINGPARAM( "MarkableInputStream::available NotConnectedException" ) ) ,
|
|
*this );
|
|
}
|
|
|
|
return nAvail;
|
|
}
|
|
|
|
|
|
void OMarkableInputStream::closeInput(void) throw (NotConnectedException, RuntimeException)
|
|
{
|
|
if( m_bValidStream ) {
|
|
MutexGuard guard( m_mutex );
|
|
|
|
m_input->closeInput();
|
|
|
|
setInputStream( Reference< XInputStream > () );
|
|
setPredecessor( Reference< XConnectable > () );
|
|
setSuccessor( Reference< XConnectable >() );
|
|
|
|
delete m_pBuffer;
|
|
m_pBuffer = 0;
|
|
m_nCurrentPos = 0;
|
|
m_nCurrentMark = 0;
|
|
}
|
|
else {
|
|
throw NotConnectedException(
|
|
OUString( RTL_CONSTASCII_USTRINGPARAM( "MarkableInputStream::closeInput NotConnectedException" ) ) ,
|
|
*this );
|
|
}
|
|
}
|
|
|
|
// XMarkable
|
|
|
|
sal_Int32 OMarkableInputStream::createMark(void) throw (IOException, RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
sal_Int32 nMark = m_nCurrentMark;
|
|
|
|
m_mapMarks[nMark] = m_nCurrentPos;
|
|
|
|
m_nCurrentMark ++;
|
|
return nMark;
|
|
}
|
|
|
|
void OMarkableInputStream::deleteMark(sal_Int32 Mark) throw (IOException, IllegalArgumentException, RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
|
|
|
|
if( ii == m_mapMarks.end() ) {
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableInputStream::deleteMark unknown mark (" );
|
|
buf.append( Mark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
|
|
}
|
|
else {
|
|
m_mapMarks.erase( ii );
|
|
checkMarksAndFlush();
|
|
}
|
|
}
|
|
|
|
void OMarkableInputStream::jumpToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
|
|
|
|
if( ii == m_mapMarks.end() )
|
|
{
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableInputStream::jumpToMark unknown mark (" );
|
|
buf.append( nMark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
|
|
}
|
|
else
|
|
{
|
|
m_nCurrentPos = (*ii).second;
|
|
}
|
|
}
|
|
|
|
void OMarkableInputStream::jumpToFurthest(void) throw (IOException, RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
m_nCurrentPos = m_pBuffer->getSize();
|
|
checkMarksAndFlush();
|
|
}
|
|
|
|
sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark)
|
|
throw (IOException,
|
|
IllegalArgumentException,
|
|
RuntimeException)
|
|
{
|
|
MutexGuard guard( m_mutex );
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
|
|
|
|
if( ii == m_mapMarks.end() )
|
|
{
|
|
OUStringBuffer buf( 128 );
|
|
buf.appendAscii( "MarkableInputStream::offsetToMark unknown mark (" );
|
|
buf.append( nMark );
|
|
buf.appendAscii( ")");
|
|
throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
|
|
}
|
|
return m_nCurrentPos - (*ii).second;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// XActiveDataSource
|
|
void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream)
|
|
throw (RuntimeException)
|
|
{
|
|
|
|
if( m_input != aStream ) {
|
|
m_input = aStream;
|
|
|
|
Reference < XConnectable > pred( m_input , UNO_QUERY );
|
|
setPredecessor( pred );
|
|
}
|
|
|
|
m_bValidStream = m_input.is();
|
|
|
|
}
|
|
|
|
Reference< XInputStream > OMarkableInputStream::getInputStream(void) throw (RuntimeException)
|
|
{
|
|
return m_input;
|
|
}
|
|
|
|
|
|
|
|
// XDataSink
|
|
void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r )
|
|
throw (RuntimeException)
|
|
{
|
|
/// if the references match, nothing needs to be done
|
|
if( m_succ != r ) {
|
|
/// store the reference for later use
|
|
m_succ = r;
|
|
|
|
if( m_succ.is() ) {
|
|
/// set this instance as the sink !
|
|
m_succ->setPredecessor( Reference< XConnectable > (
|
|
SAL_STATIC_CAST( XConnectable * , this ) ) );
|
|
}
|
|
}
|
|
}
|
|
|
|
Reference < XConnectable > OMarkableInputStream::getSuccessor() throw (RuntimeException)
|
|
{
|
|
return m_succ;
|
|
}
|
|
|
|
|
|
// XDataSource
|
|
void OMarkableInputStream::setPredecessor( const Reference < XConnectable > &r )
|
|
throw (RuntimeException)
|
|
{
|
|
if( r != m_pred ) {
|
|
m_pred = r;
|
|
if( m_pred.is() ) {
|
|
m_pred->setSuccessor( Reference< XConnectable > (
|
|
SAL_STATIC_CAST( XConnectable * , this ) ) );
|
|
}
|
|
}
|
|
}
|
|
Reference< XConnectable > OMarkableInputStream::getPredecessor() throw (RuntimeException)
|
|
{
|
|
return m_pred;
|
|
}
|
|
|
|
|
|
|
|
|
|
void OMarkableInputStream::checkMarksAndFlush()
|
|
{
|
|
map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
|
|
|
|
// find the smallest mark
|
|
sal_Int32 nNextFound = m_nCurrentPos;
|
|
for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ii ++ ) {
|
|
if( (*ii).second <= nNextFound ) {
|
|
nNextFound = (*ii).second;
|
|
}
|
|
}
|
|
|
|
if( nNextFound ) {
|
|
// some data must be released !
|
|
m_nCurrentPos -= nNextFound;
|
|
for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ii ++ ) {
|
|
(*ii).second -= nNextFound;
|
|
}
|
|
|
|
m_pBuffer->forgetFromStart( nNextFound );
|
|
|
|
}
|
|
else {
|
|
// nothing to do. There is a mark or the current cursor position, that prevents
|
|
// releasing data !
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// XServiceInfo
|
|
OUString OMarkableInputStream::getImplementationName() throw ()
|
|
{
|
|
return OMarkableInputStream_getImplementationName();
|
|
}
|
|
|
|
// XServiceInfo
|
|
sal_Bool OMarkableInputStream::supportsService(const OUString& ServiceName) throw ()
|
|
{
|
|
Sequence< OUString > aSNL = getSupportedServiceNames();
|
|
const OUString * pArray = aSNL.getConstArray();
|
|
|
|
for( sal_Int32 i = 0; i < aSNL.getLength(); i++ )
|
|
if( pArray[i] == ServiceName )
|
|
return sal_True;
|
|
|
|
return sal_False;
|
|
}
|
|
|
|
// XServiceInfo
|
|
Sequence< OUString > OMarkableInputStream::getSupportedServiceNames(void) throw ()
|
|
{
|
|
return OMarkableInputStream_getSupportedServiceNames();
|
|
}
|
|
|
|
|
|
/*------------------------
|
|
*
|
|
* external binding
|
|
*
|
|
*------------------------*/
|
|
Reference < XInterface > SAL_CALL OMarkableInputStream_CreateInstance(
|
|
const Reference < XComponentContext > & ) throw(Exception)
|
|
{
|
|
OMarkableInputStream *p = new OMarkableInputStream( );
|
|
return Reference< XInterface > ( (OWeakObject * ) p );
|
|
}
|
|
|
|
OUString OMarkableInputStream_getImplementationName()
|
|
{
|
|
return OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.stm.MarkableInputStream" ));
|
|
}
|
|
|
|
Sequence<OUString> OMarkableInputStream_getSupportedServiceNames(void)
|
|
{
|
|
Sequence<OUString> aRet(1);
|
|
aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.MarkableInputStream" ));
|
|
return aRet;
|
|
}
|
|
|
|
}
|