LCOV - code coverage report
Current view: top level - io/source/stm - omark.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 199 325 61.2 %
Date: 2015-06-13 12:38:46 Functions: 37 50 74.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      21             : #include <map>
      22             : #include <vector>
      23             : 
      24             : #include <com/sun/star/io/XMarkableStream.hpp>
      25             : #include <com/sun/star/io/XOutputStream.hpp>
      26             : #include <com/sun/star/io/XInputStream.hpp>
      27             : #include <com/sun/star/io/XActiveDataSource.hpp>
      28             : #include <com/sun/star/io/XActiveDataSink.hpp>
      29             : #include <com/sun/star/io/XConnectable.hpp>
      30             : #include <com/sun/star/lang/XServiceInfo.hpp>
      31             : 
      32             : #include <cppuhelper/factory.hxx>
      33             : #include <cppuhelper/weak.hxx>
      34             : #include <cppuhelper/implbase5.hxx>
      35             : #include <cppuhelper/supportsservice.hxx>
      36             : 
      37             : #include <osl/mutex.hxx>
      38             : #include <rtl/ustrbuf.hxx>
      39             : #include <osl/diagnose.h>
      40             : 
      41             : #include <string.h>
      42             : 
      43             : 
      44             : using namespace ::std;
      45             : using namespace ::cppu;
      46             : using namespace ::osl;
      47             : using namespace ::com::sun::star::io;
      48             : using namespace ::com::sun::star::uno;
      49             : using namespace ::com::sun::star::lang;
      50             : 
      51             : #include "services.hxx"
      52             : #include "streamhelper.hxx"
      53             : 
      54             : namespace io_stm {
      55             : 
      56             : /***********************
      57             : *
      58             : * OMarkableOutputStream.
      59             : *
      60             : * This object allows to set marks in an outputstream. It is allowed to jump back to the marks and
      61             : * rewrite the some bytes.
      62             : *
      63             : *         The object must buffer the data since the last mark set. Flush will not
      64             : *         have any effect. As soon as the last mark has been removed, the object may write the data
      65             : *         through to the chained object.
      66             : *
      67             : **********************/
      68             : class OMarkableOutputStream :
      69             :     public WeakImplHelper5< XOutputStream ,
      70             :                             XActiveDataSource ,
      71             :                             XMarkableStream ,
      72             :                             XConnectable,
      73             :                             XServiceInfo
      74             :                           >
      75             : {
      76             : public:
      77             :     OMarkableOutputStream(  );
      78             :     virtual ~OMarkableOutputStream();
      79             : 
      80             : public: // XOutputStream
      81             :     virtual void SAL_CALL writeBytes(const Sequence< sal_Int8 >& aData)
      82             :         throw ( NotConnectedException,
      83             :                 BufferSizeExceededException,
      84             :                 RuntimeException, std::exception) SAL_OVERRIDE;
      85             :     virtual void SAL_CALL flush()
      86             :         throw ( NotConnectedException,
      87             :                 BufferSizeExceededException,
      88             :                 RuntimeException, std::exception) SAL_OVERRIDE;
      89             :     virtual void SAL_CALL closeOutput()
      90             :         throw ( NotConnectedException,
      91             :                 BufferSizeExceededException,
      92             :                 RuntimeException, std::exception) SAL_OVERRIDE;
      93             : 
      94             : public: // XMarkable
      95             :     virtual sal_Int32 SAL_CALL createMark()
      96             :         throw (IOException, RuntimeException, std::exception) SAL_OVERRIDE;
      97             :     virtual void SAL_CALL deleteMark(sal_Int32 Mark)
      98             :         throw (IOException,
      99             :                IllegalArgumentException,
     100             :                RuntimeException, std::exception) SAL_OVERRIDE;
     101             :     virtual void SAL_CALL jumpToMark(sal_Int32 nMark)
     102             :         throw (IOException,
     103             :                IllegalArgumentException,
     104             :                RuntimeException, std::exception) SAL_OVERRIDE;
     105             :     virtual void SAL_CALL jumpToFurthest()
     106             :         throw (IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     107             :     virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark)
     108             :         throw (IOException,
     109             :                IllegalArgumentException,
     110             :                RuntimeException, std::exception) SAL_OVERRIDE;
     111             : 
     112             : public: // XActiveDataSource
     113             :     virtual void SAL_CALL setOutputStream(const Reference < XOutputStream > & aStream)
     114             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     115             :     virtual Reference < XOutputStream > SAL_CALL getOutputStream()
     116             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     117             : 
     118             : public: // XConnectable
     119             :     virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor)
     120             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     121             :     virtual Reference < XConnectable > SAL_CALL getPredecessor() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     122             :     virtual void SAL_CALL setSuccessor(const Reference < XConnectable >& aSuccessor)
     123             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     124             :     virtual Reference<  XConnectable >  SAL_CALL getSuccessor() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     125             : 
     126             : public: // XServiceInfo
     127             :     OUString                     SAL_CALL getImplementationName() throw (std::exception) SAL_OVERRIDE;
     128             :     Sequence< OUString >         SAL_CALL getSupportedServiceNames() throw (std::exception) SAL_OVERRIDE;
     129             :     sal_Bool                        SAL_CALL supportsService(const OUString& ServiceName) throw (std::exception) SAL_OVERRIDE;
     130             : 
     131             : private:
     132             :     // helper methods
     133             :     void checkMarksAndFlush() throw( NotConnectedException, BufferSizeExceededException);
     134             : 
     135             :     Reference< XConnectable > m_succ;
     136             :     Reference< XConnectable > m_pred;
     137             : 
     138             :     Reference< XOutputStream >  m_output;
     139             :     bool m_bValidStream;
     140             : 
     141             :     IRingBuffer *m_pBuffer;
     142             :     map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
     143             :     sal_Int32 m_nCurrentPos;
     144             :     sal_Int32 m_nCurrentMark;
     145             : 
     146             :     Mutex m_mutex;
     147             : };
     148             : 
     149          41 : OMarkableOutputStream::OMarkableOutputStream( )
     150             :     : m_bValidStream(false)
     151             :     , m_nCurrentPos(0)
     152          41 :     , m_nCurrentMark(0)
     153             : {
     154          41 :     m_pBuffer = new MemRingBuffer;
     155          41 : }
     156             : 
     157           3 : OMarkableOutputStream::~OMarkableOutputStream()
     158             : {
     159           1 :     delete m_pBuffer;
     160           2 : }
     161             : 
     162             : 
     163             : // XOutputStream
     164        1859 : void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
     165             :     throw ( NotConnectedException,
     166             :             BufferSizeExceededException,
     167             :             RuntimeException, std::exception)
     168             : {
     169        1859 :     if( m_bValidStream ) {
     170        1859 :         if( m_mapMarks.empty() && ( m_pBuffer->getSize() == 0 ) ) {
     171             :             // no mark and  buffer active, simple write through
     172         701 :             m_output->writeBytes( aData );
     173             :         }
     174             :         else {
     175        1158 :             MutexGuard guard( m_mutex );
     176             :             // new data must be buffered
     177             :             try
     178             :             {
     179        1158 :                 m_pBuffer->writeAt( m_nCurrentPos , aData );
     180        1158 :                 m_nCurrentPos += aData.getLength();
     181             :             }
     182           0 :             catch( IRingBuffer_OutOfBoundsException & )
     183             :             {
     184           0 :                 throw BufferSizeExceededException();
     185             :             }
     186           0 :             catch( IRingBuffer_OutOfMemoryException & )
     187             :             {
     188           0 :                 throw BufferSizeExceededException();
     189             :             }
     190        1158 :             checkMarksAndFlush();
     191             :         }
     192             :     }
     193             :     else {
     194           0 :         throw NotConnectedException();
     195             :     }
     196        1859 : }
     197             : 
     198           0 : void OMarkableOutputStream::flush()
     199             :     throw ( NotConnectedException,
     200             :             BufferSizeExceededException,
     201             :             RuntimeException, std::exception)
     202             : {
     203           0 :     Reference< XOutputStream > output;
     204             :     {
     205           0 :         MutexGuard guard( m_mutex );
     206           0 :         output = m_output;
     207             :     }
     208             : 
     209             :     // Markable cannot flush buffered data, because the data may get rewritten,
     210             :     // however one can forward the flush to the chained stream to give it
     211             :     // a chance to write data buffered in the chained stream.
     212           0 :     if( output.is() )
     213             :     {
     214           0 :         output->flush();
     215           0 :     }
     216           0 : }
     217             : 
     218           0 : void OMarkableOutputStream::closeOutput()
     219             :     throw ( NotConnectedException,
     220             :             BufferSizeExceededException,
     221             :             RuntimeException, std::exception)
     222             : {
     223           0 :     if( m_bValidStream ) {
     224           0 :         MutexGuard guard( m_mutex );
     225             :         // all marks must be cleared and all
     226             : 
     227           0 :         if( ! m_mapMarks.empty() )
     228             :         {
     229           0 :             m_mapMarks.clear();
     230             :          }
     231           0 :         m_nCurrentPos = m_pBuffer->getSize();
     232           0 :           checkMarksAndFlush();
     233             : 
     234           0 :         m_output->closeOutput();
     235             : 
     236           0 :         setOutputStream( Reference< XOutputStream > () );
     237           0 :         setPredecessor( Reference < XConnectable >() );
     238           0 :         setSuccessor( Reference< XConnectable > () );
     239             :     }
     240             :     else {
     241           0 :         throw NotConnectedException();
     242             :     }
     243           0 : }
     244             : 
     245             : 
     246          86 : sal_Int32 OMarkableOutputStream::createMark()
     247             :     throw ( IOException,
     248             :             RuntimeException, std::exception)
     249             : {
     250          86 :     MutexGuard guard( m_mutex );
     251          86 :     sal_Int32 nMark = m_nCurrentMark;
     252             : 
     253          86 :     m_mapMarks[nMark] = m_nCurrentPos;
     254             : 
     255          86 :     m_nCurrentMark ++;
     256          86 :     return nMark;
     257             : }
     258             : 
     259          86 : void OMarkableOutputStream::deleteMark(sal_Int32 Mark)
     260             :     throw( IOException,
     261             :            IllegalArgumentException,
     262             :            RuntimeException, std::exception)
     263             : {
     264          86 :     MutexGuard guard( m_mutex );
     265          86 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
     266             : 
     267          86 :     if( ii == m_mapMarks.end() ) {
     268           0 :         OUStringBuffer buf( 128 );
     269           0 :         buf.appendAscii( "MarkableOutputStream::deleteMark unknown mark (" );
     270           0 :         buf.append( Mark );
     271           0 :         buf.appendAscii( ")");
     272           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
     273             :     }
     274             :     else {
     275          86 :         m_mapMarks.erase( ii );
     276          86 :         checkMarksAndFlush();
     277          86 :     }
     278          86 : }
     279             : 
     280          86 : void OMarkableOutputStream::jumpToMark(sal_Int32 nMark)
     281             :     throw (IOException,
     282             :            IllegalArgumentException,
     283             :            RuntimeException, std::exception)
     284             : {
     285          86 :     MutexGuard guard( m_mutex );
     286          86 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
     287             : 
     288          86 :     if( ii == m_mapMarks.end() ) {
     289           0 :         OUStringBuffer buf( 128 );
     290           0 :         buf.appendAscii( "MarkableOutputStream::jumpToMark unknown mark (" );
     291           0 :         buf.append( nMark );
     292           0 :         buf.appendAscii( ")");
     293           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
     294             :     }
     295             :     else {
     296          86 :         m_nCurrentPos = (*ii).second;
     297          86 :     }
     298          86 : }
     299             : 
     300          86 : void OMarkableOutputStream::jumpToFurthest()
     301             :     throw (IOException,
     302             :            RuntimeException, std::exception)
     303             : {
     304          86 :     MutexGuard guard( m_mutex );
     305          86 :     m_nCurrentPos = m_pBuffer->getSize();
     306          86 :     checkMarksAndFlush();
     307          86 : }
     308             : 
     309          86 : sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark)
     310             :     throw (IOException,
     311             :            IllegalArgumentException,
     312             :            RuntimeException, std::exception)
     313             : {
     314             : 
     315          86 :     MutexGuard guard( m_mutex );
     316          86 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
     317             : 
     318          86 :     if( ii == m_mapMarks.end() )
     319             :     {
     320           0 :         OUStringBuffer buf( 128 );
     321           0 :         buf.appendAscii( "MarkableOutputStream::offsetToMark unknown mark (" );
     322           0 :         buf.append( nMark );
     323           0 :         buf.appendAscii( ")");
     324           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this, 0);
     325             :     }
     326          86 :     return m_nCurrentPos - (*ii).second;
     327             : }
     328             : 
     329             : 
     330             : 
     331             : // XActiveDataSource2
     332          40 : void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream)
     333             :     throw (RuntimeException, std::exception)
     334             : {
     335          40 :     if( m_output != aStream ) {
     336          40 :         m_output = aStream;
     337             : 
     338          40 :         Reference < XConnectable > succ( m_output , UNO_QUERY );
     339          40 :         setSuccessor( succ );
     340             :     }
     341          40 :     m_bValidStream = m_output.is();
     342          40 : }
     343             : 
     344           0 : Reference< XOutputStream > OMarkableOutputStream::getOutputStream() throw (RuntimeException, std::exception)
     345             : {
     346           0 :     return m_output;
     347             : }
     348             : 
     349             : 
     350             : 
     351          80 : void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r )
     352             :     throw (RuntimeException, std::exception)
     353             : {
     354             :      /// if the references match, nothing needs to be done
     355          80 :      if( m_succ != r ) {
     356             :          /// store the reference for later use
     357          40 :          m_succ = r;
     358             : 
     359          40 :          if( m_succ.is() ) {
     360          40 :               m_succ->setPredecessor( Reference < XConnectable > (
     361          40 :                   (static_cast< XConnectable *  >(this)) ) );
     362             :          }
     363             :      }
     364          80 : }
     365           0 : Reference <XConnectable > OMarkableOutputStream::getSuccessor()     throw (RuntimeException, std::exception)
     366             : {
     367           0 :     return m_succ;
     368             : }
     369             : 
     370             : 
     371             : // XDataSource
     372          40 : void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r )
     373             :     throw (RuntimeException, std::exception)
     374             : {
     375          40 :     if( r != m_pred ) {
     376          40 :         m_pred = r;
     377          40 :         if( m_pred.is() ) {
     378          40 :             m_pred->setSuccessor( Reference < XConnectable > (
     379          40 :                 (static_cast< XConnectable *  >(this )) ) );
     380             :         }
     381             :     }
     382          40 : }
     383           0 : Reference < XConnectable > OMarkableOutputStream::getPredecessor() throw (RuntimeException, std::exception)
     384             : {
     385           0 :     return m_pred;
     386             : }
     387             : 
     388             : 
     389             : // private methods
     390             : 
     391        1330 : void OMarkableOutputStream::checkMarksAndFlush() throw(     NotConnectedException,
     392             :                                                             BufferSizeExceededException)
     393             : {
     394        1330 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
     395             : 
     396             :     // find the smallest mark
     397        1330 :     sal_Int32 nNextFound = m_nCurrentPos;
     398        3987 :     for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
     399        2657 :         if( (*ii).second <= nNextFound )  {
     400        1296 :             nNextFound = (*ii).second;
     401             :         }
     402             :     }
     403             : 
     404        1330 :     if( nNextFound ) {
     405             :         // some data must be released !
     406          34 :         m_nCurrentPos -= nNextFound;
     407          34 :         for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
     408           0 :             (*ii).second -= nNextFound;
     409             :         }
     410             : 
     411          34 :         Sequence<sal_Int8> seq(nNextFound);
     412          34 :         m_pBuffer->readAt( 0 , seq , nNextFound );
     413          34 :         m_pBuffer->forgetFromStart( nNextFound );
     414             : 
     415             :         // now write data through to streams
     416          34 :         m_output->writeBytes( seq );
     417             :     }
     418             :     else {
     419             :         // nothing to do. There is a mark or the current cursor position, that prevents
     420             :         // releasing data !
     421             :     }
     422        1330 : }
     423             : 
     424             : 
     425             : // XServiceInfo
     426           1 : OUString OMarkableOutputStream::getImplementationName() throw (std::exception)
     427             : {
     428           1 :     return OMarkableOutputStream_getImplementationName();
     429             : }
     430             : 
     431             : // XServiceInfo
     432           0 : sal_Bool OMarkableOutputStream::supportsService(const OUString& ServiceName) throw (std::exception)
     433             : {
     434           0 :     return cppu::supportsService(this, ServiceName);
     435             : }
     436             : 
     437             : // XServiceInfo
     438           1 : Sequence< OUString > OMarkableOutputStream::getSupportedServiceNames() throw (std::exception)
     439             : {
     440           1 :     return OMarkableOutputStream_getSupportedServiceNames();
     441             : }
     442             : 
     443             : /*------------------------
     444             : *
     445             : * external binding
     446             : *
     447             : *------------------------*/
     448          41 : Reference< XInterface > SAL_CALL OMarkableOutputStream_CreateInstance(
     449             :     SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
     450             :     throw(Exception)
     451             : {
     452          41 :     OMarkableOutputStream *p = new OMarkableOutputStream( );
     453             : 
     454          41 :     return Reference < XInterface > ( static_cast<OWeakObject *>(p) );
     455             : }
     456             : 
     457         174 : OUString    OMarkableOutputStream_getImplementationName()
     458             : {
     459         174 :     return OUString("com.sun.star.comp.io.stm.MarkableOutputStream");
     460             : }
     461             : 
     462           9 : Sequence<OUString> OMarkableOutputStream_getSupportedServiceNames()
     463             : {
     464           9 :     Sequence<OUString> aRet(1);
     465           9 :     aRet.getArray()[0] = "com.sun.star.io.MarkableOutputStream";
     466             : 
     467           9 :     return aRet;
     468             : }
     469             : 
     470             : 
     471             : 
     472             : 
     473             : 
     474             : 
     475             : 
     476             : 
     477             : // XMarkableInputStream
     478             : 
     479             : 
     480             : 
     481             : class OMarkableInputStream :
     482             :     public WeakImplHelper5
     483             :     <
     484             :              XInputStream,
     485             :              XActiveDataSink,
     486             :              XMarkableStream,
     487             :              XConnectable,
     488             :              XServiceInfo
     489             :     >
     490             : {
     491             : public:
     492             :     OMarkableInputStream(  );
     493             :     virtual ~OMarkableInputStream();
     494             : 
     495             : 
     496             : public: // XInputStream
     497             :     virtual sal_Int32 SAL_CALL readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
     498             :         throw ( NotConnectedException,
     499             :                 BufferSizeExceededException,
     500             :                 RuntimeException, std::exception) SAL_OVERRIDE ;
     501             :     virtual sal_Int32 SAL_CALL readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
     502             :         throw ( NotConnectedException,
     503             :                 BufferSizeExceededException,
     504             :                 RuntimeException, std::exception) SAL_OVERRIDE;
     505             :     virtual void SAL_CALL skipBytes(sal_Int32 nBytesToSkip)
     506             :         throw ( NotConnectedException,
     507             :                 BufferSizeExceededException,
     508             :                 RuntimeException, std::exception) SAL_OVERRIDE;
     509             : 
     510             :     virtual sal_Int32 SAL_CALL available()
     511             :         throw ( NotConnectedException,
     512             :                 RuntimeException, std::exception) SAL_OVERRIDE;
     513             :     virtual void SAL_CALL closeInput() throw (NotConnectedException, RuntimeException, std::exception) SAL_OVERRIDE;
     514             : 
     515             : public: // XMarkable
     516             :     virtual sal_Int32 SAL_CALL createMark()
     517             :         throw (IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     518             :     virtual void SAL_CALL deleteMark(sal_Int32 Mark)
     519             :         throw (IOException, IllegalArgumentException, RuntimeException, std::exception) SAL_OVERRIDE;
     520             :     virtual void SAL_CALL jumpToMark(sal_Int32 nMark)
     521             :         throw (IOException, IllegalArgumentException, RuntimeException, std::exception) SAL_OVERRIDE;
     522             :     virtual void SAL_CALL jumpToFurthest()
     523             :         throw (IOException, RuntimeException, std::exception) SAL_OVERRIDE;
     524             :     virtual sal_Int32 SAL_CALL offsetToMark(sal_Int32 nMark)
     525             :         throw (IOException, IllegalArgumentException,RuntimeException, std::exception) SAL_OVERRIDE;
     526             : 
     527             : public: // XActiveDataSink
     528             :     virtual void SAL_CALL setInputStream(const Reference < XInputStream > & aStream)
     529             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     530             :     virtual Reference < XInputStream > SAL_CALL getInputStream()
     531             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     532             : 
     533             : public: // XConnectable
     534             :     virtual void SAL_CALL setPredecessor(const Reference < XConnectable > & aPredecessor)
     535             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     536             :     virtual Reference < XConnectable > SAL_CALL getPredecessor()
     537             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     538             :     virtual void SAL_CALL setSuccessor(const Reference < XConnectable > & aSuccessor)
     539             :         throw (RuntimeException, std::exception) SAL_OVERRIDE;
     540             :     virtual Reference < XConnectable > SAL_CALL getSuccessor() throw (RuntimeException, std::exception) SAL_OVERRIDE;
     541             : 
     542             : public: // XServiceInfo
     543             :     OUString                     SAL_CALL getImplementationName() throw (std::exception) SAL_OVERRIDE;
     544             :     Sequence< OUString >         SAL_CALL getSupportedServiceNames() throw (std::exception) SAL_OVERRIDE;
     545             :     sal_Bool                         SAL_CALL  supportsService(const OUString& ServiceName) throw (std::exception) SAL_OVERRIDE;
     546             : 
     547             : private:
     548             :     void checkMarksAndFlush();
     549             : 
     550             :     Reference < XConnectable >  m_succ;
     551             :     Reference < XConnectable >  m_pred;
     552             : 
     553             :     Reference< XInputStream > m_input;
     554             :     bool m_bValidStream;
     555             : 
     556             :     IRingBuffer *m_pBuffer;
     557             :     map<sal_Int32,sal_Int32,less< sal_Int32 > > m_mapMarks;
     558             :     sal_Int32 m_nCurrentPos;
     559             :     sal_Int32 m_nCurrentMark;
     560             : 
     561             :     Mutex m_mutex;
     562             : };
     563             : 
     564          41 : OMarkableInputStream::OMarkableInputStream()
     565             :     : m_bValidStream(false)
     566             :     , m_nCurrentPos(0)
     567          41 :     , m_nCurrentMark(0)
     568             : {
     569          41 :     m_pBuffer = new MemRingBuffer;
     570          41 : }
     571             : 
     572           3 : OMarkableInputStream::~OMarkableInputStream()
     573             : {
     574           1 :     if( m_pBuffer ) {
     575           1 :         delete m_pBuffer;
     576             :     }
     577           2 : }
     578             : 
     579             : 
     580             : 
     581             : 
     582             : // XInputStream
     583             : 
     584        1825 : sal_Int32 OMarkableInputStream::readBytes(Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead)
     585             :     throw ( NotConnectedException,
     586             :             BufferSizeExceededException,
     587             :             RuntimeException, std::exception)
     588             : {
     589             :     sal_Int32 nBytesRead;
     590             : 
     591        1825 :     if( m_bValidStream ) {
     592        1825 :         MutexGuard guard( m_mutex );
     593        1825 :         if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
     594             :             // normal read !
     595         735 :             nBytesRead = m_input->readBytes( aData, nBytesToRead );
     596             :         }
     597             :         else {
     598             :             // read from buffer
     599             :             sal_Int32 nRead;
     600             : 
     601             :             // read enough bytes into buffer
     602        1090 :             if( m_pBuffer->getSize() - m_nCurrentPos < nBytesToRead  ) {
     603        1014 :                 sal_Int32 nToRead = nBytesToRead - ( m_pBuffer->getSize() - m_nCurrentPos );
     604        1014 :                 nRead = m_input->readBytes( aData , nToRead );
     605             : 
     606             :                 OSL_ASSERT( aData.getLength() == nRead );
     607             : 
     608             :                 try
     609             :                 {
     610        1014 :                     m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
     611             :                 }
     612           0 :                 catch( IRingBuffer_OutOfMemoryException & ) {
     613           0 :                     throw BufferSizeExceededException();
     614             :                 }
     615           0 :                 catch( IRingBuffer_OutOfBoundsException & ) {
     616           0 :                     throw BufferSizeExceededException();
     617             :                 }
     618             : 
     619        1014 :                 if( nRead < nToRead ) {
     620           0 :                     nBytesToRead = nBytesToRead - (nToRead-nRead);
     621             :                 }
     622             :             }
     623             : 
     624             :             OSL_ASSERT( m_pBuffer->getSize() - m_nCurrentPos >= nBytesToRead  );
     625             : 
     626        1090 :             m_pBuffer->readAt( m_nCurrentPos , aData , nBytesToRead );
     627             : 
     628        1090 :             m_nCurrentPos += nBytesToRead;
     629        1090 :             nBytesRead = nBytesToRead;
     630        1825 :         }
     631             :     }
     632             :     else {
     633             :         throw NotConnectedException(
     634             :             "MarkableInputStream::readBytes NotConnectedException",
     635           0 :             *this );
     636             :     }
     637        1825 :     return nBytesRead;
     638             : }
     639             : 
     640             : 
     641           0 : sal_Int32 OMarkableInputStream::readSomeBytes(Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead)
     642             :     throw ( NotConnectedException,
     643             :             BufferSizeExceededException,
     644             :             RuntimeException, std::exception)
     645             : {
     646             : 
     647             :     sal_Int32 nBytesRead;
     648           0 :     if( m_bValidStream ) {
     649           0 :         MutexGuard guard( m_mutex );
     650           0 :         if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
     651             :             // normal read !
     652           0 :             nBytesRead = m_input->readSomeBytes( aData, nMaxBytesToRead );
     653             :         }
     654             :         else {
     655             :             // read from buffer
     656           0 :             sal_Int32 nRead = 0;
     657           0 :             sal_Int32 nInBuffer = m_pBuffer->getSize() - m_nCurrentPos;
     658           0 :             sal_Int32 nAdditionalBytesToRead = Min(nMaxBytesToRead-nInBuffer,m_input->available());
     659           0 :             nAdditionalBytesToRead = Max(0 , nAdditionalBytesToRead );
     660             : 
     661             :             // read enough bytes into buffer
     662           0 :             if( 0 == nInBuffer ) {
     663           0 :                 nRead = m_input->readSomeBytes( aData , nMaxBytesToRead );
     664             :             }
     665           0 :             else if( nAdditionalBytesToRead ) {
     666           0 :                 nRead = m_input->readBytes( aData , nAdditionalBytesToRead );
     667             :             }
     668             : 
     669           0 :             if( nRead ) {
     670           0 :                 aData.realloc( nRead );
     671             :                 try
     672             :                 {
     673           0 :                     m_pBuffer->writeAt( m_pBuffer->getSize() , aData );
     674             :                 }
     675           0 :                 catch( IRingBuffer_OutOfMemoryException & )
     676             :                 {
     677           0 :                     throw BufferSizeExceededException();
     678             :                 }
     679           0 :                 catch( IRingBuffer_OutOfBoundsException &  )
     680             :                 {
     681           0 :                     throw BufferSizeExceededException();
     682             :                 }
     683             :             }
     684             : 
     685           0 :             nBytesRead = Min( nMaxBytesToRead , nInBuffer + nRead );
     686             : 
     687             :             // now take everything from buffer !
     688           0 :             m_pBuffer->readAt( m_nCurrentPos , aData , nBytesRead );
     689             : 
     690           0 :             m_nCurrentPos += nBytesRead;
     691           0 :         }
     692             :     }
     693             :     else
     694             :     {
     695             :         throw NotConnectedException(
     696             :             "MarkableInputStream::readSomeBytes NotConnectedException",
     697           0 :             *this );
     698             :     }
     699           0 :     return nBytesRead;
     700             : 
     701             : 
     702             : }
     703             : 
     704             : 
     705          82 : void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip)
     706             :     throw ( NotConnectedException,
     707             :             BufferSizeExceededException,
     708             :             RuntimeException, std::exception)
     709             : {
     710          82 :     if ( nBytesToSkip < 0 )
     711             :         throw BufferSizeExceededException(
     712             :             "precondition not met: XInputStream::skipBytes: non-negative integer required!",
     713             :             *this
     714           0 :         );
     715             : 
     716             :     // this method is blocking
     717          82 :     Sequence<sal_Int8> seqDummy( nBytesToSkip );
     718          82 :     readBytes( seqDummy , nBytesToSkip );
     719          82 : }
     720             : 
     721           0 : sal_Int32 OMarkableInputStream::available() throw (NotConnectedException, RuntimeException, std::exception)
     722             : {
     723             :     sal_Int32 nAvail;
     724           0 :     if( m_bValidStream ) {
     725           0 :         MutexGuard guard( m_mutex );
     726           0 :         nAvail = m_input->available() + ( m_pBuffer->getSize() - m_nCurrentPos );
     727             :     }
     728             :     else
     729             :     {
     730             :         throw NotConnectedException(
     731             :             "MarkableInputStream::available NotConnectedException",
     732           0 :             *this );
     733             :     }
     734             : 
     735           0 :     return nAvail;
     736             : }
     737             : 
     738             : 
     739           0 : void OMarkableInputStream::closeInput() throw (NotConnectedException, RuntimeException, std::exception)
     740             : {
     741           0 :     if( m_bValidStream ) {
     742           0 :         MutexGuard guard( m_mutex );
     743             : 
     744           0 :         m_input->closeInput();
     745             : 
     746           0 :         setInputStream( Reference< XInputStream > () );
     747           0 :         setPredecessor( Reference< XConnectable > () );
     748           0 :         setSuccessor( Reference< XConnectable >() );
     749             : 
     750           0 :         delete m_pBuffer;
     751           0 :         m_pBuffer = 0;
     752           0 :         m_nCurrentPos = 0;
     753           0 :         m_nCurrentMark = 0;
     754             :     }
     755             :     else {
     756             :         throw NotConnectedException(
     757             :             "MarkableInputStream::closeInput NotConnectedException",
     758           0 :             *this );
     759             :     }
     760           0 : }
     761             : 
     762             : // XMarkable
     763             : 
     764          83 : sal_Int32 OMarkableInputStream::createMark()            throw (IOException, RuntimeException, std::exception)
     765             : {
     766          83 :     MutexGuard guard( m_mutex );
     767          83 :     sal_Int32 nMark = m_nCurrentMark;
     768             : 
     769          83 :     m_mapMarks[nMark] = m_nCurrentPos;
     770             : 
     771          83 :     m_nCurrentMark ++;
     772          83 :     return nMark;
     773             : }
     774             : 
     775          83 : void OMarkableInputStream::deleteMark(sal_Int32 Mark)       throw (IOException, IllegalArgumentException, RuntimeException, std::exception)
     776             : {
     777          83 :     MutexGuard guard( m_mutex );
     778          83 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
     779             : 
     780          83 :     if( ii == m_mapMarks.end() ) {
     781           0 :         OUStringBuffer buf( 128 );
     782           0 :         buf.appendAscii( "MarkableInputStream::deleteMark unknown mark (" );
     783           0 :         buf.append( Mark );
     784           0 :         buf.appendAscii( ")");
     785           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
     786             :     }
     787             :     else {
     788          83 :         m_mapMarks.erase( ii );
     789          83 :         checkMarksAndFlush();
     790          83 :     }
     791          83 : }
     792             : 
     793          82 : void OMarkableInputStream::jumpToMark(sal_Int32 nMark)
     794             :     throw (IOException,
     795             :            IllegalArgumentException,
     796             :            RuntimeException, std::exception)
     797             : {
     798          82 :     MutexGuard guard( m_mutex );
     799          82 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
     800             : 
     801          82 :     if( ii == m_mapMarks.end() )
     802             :     {
     803           0 :         OUStringBuffer buf( 128 );
     804           0 :         buf.appendAscii( "MarkableInputStream::jumpToMark unknown mark (" );
     805           0 :         buf.append( nMark );
     806           0 :         buf.appendAscii( ")");
     807           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
     808             :     }
     809             :     else
     810             :     {
     811          82 :         m_nCurrentPos = (*ii).second;
     812          82 :     }
     813          82 : }
     814             : 
     815           1 : void OMarkableInputStream::jumpToFurthest()         throw (IOException, RuntimeException, std::exception)
     816             : {
     817           1 :     MutexGuard guard( m_mutex );
     818           1 :     m_nCurrentPos = m_pBuffer->getSize();
     819           1 :     checkMarksAndFlush();
     820           1 : }
     821             : 
     822           1 : sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark)
     823             :      throw (IOException,
     824             :            IllegalArgumentException,
     825             :            RuntimeException, std::exception)
     826             : {
     827           1 :     MutexGuard guard( m_mutex );
     828           1 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
     829             : 
     830           1 :     if( ii == m_mapMarks.end() )
     831             :     {
     832           0 :         OUStringBuffer buf( 128 );
     833           0 :         buf.appendAscii( "MarkableInputStream::offsetToMark unknown mark (" );
     834           0 :         buf.append( nMark );
     835           0 :         buf.appendAscii( ")");
     836           0 :         throw IllegalArgumentException( buf.makeStringAndClear(), *this , 0 );
     837             :     }
     838           1 :     return m_nCurrentPos - (*ii).second;
     839             : }
     840             : 
     841             : 
     842             : 
     843             : 
     844             : 
     845             : 
     846             : 
     847             : // XActiveDataSource
     848          40 : void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream)
     849             :     throw (RuntimeException, std::exception)
     850             : {
     851             : 
     852          40 :     if( m_input != aStream ) {
     853          40 :         m_input = aStream;
     854             : 
     855          40 :         Reference < XConnectable >  pred( m_input , UNO_QUERY );
     856          40 :         setPredecessor( pred );
     857             :     }
     858             : 
     859          40 :     m_bValidStream = m_input.is();
     860             : 
     861          40 : }
     862             : 
     863           0 : Reference< XInputStream > OMarkableInputStream::getInputStream() throw (RuntimeException, std::exception)
     864             : {
     865           0 :     return m_input;
     866             : }
     867             : 
     868             : 
     869             : 
     870             : // XDataSink
     871          40 : void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r )
     872             :     throw (RuntimeException, std::exception)
     873             : {
     874             :      /// if the references match, nothing needs to be done
     875          40 :      if( m_succ != r ) {
     876             :          /// store the reference for later use
     877          40 :          m_succ = r;
     878             : 
     879          40 :          if( m_succ.is() ) {
     880             :               /// set this instance as the sink !
     881          40 :               m_succ->setPredecessor( Reference< XConnectable > (
     882          40 :                   (static_cast< XConnectable *  >(this)) ) );
     883             :          }
     884             :      }
     885          40 : }
     886             : 
     887           0 : Reference < XConnectable >  OMarkableInputStream::getSuccessor() throw (RuntimeException, std::exception)
     888             : {
     889           0 :     return m_succ;
     890             : }
     891             : 
     892             : 
     893             : // XDataSource
     894          80 : void OMarkableInputStream::setPredecessor( const Reference < XConnectable >  &r )
     895             :     throw (RuntimeException, std::exception)
     896             : {
     897          80 :     if( r != m_pred ) {
     898          40 :         m_pred = r;
     899          40 :         if( m_pred.is() ) {
     900          40 :             m_pred->setSuccessor( Reference< XConnectable > (
     901          40 :                 (static_cast< XConnectable *  >(this)) ) );
     902             :         }
     903             :     }
     904          80 : }
     905           0 : Reference< XConnectable >  OMarkableInputStream::getPredecessor() throw (RuntimeException, std::exception)
     906             : {
     907           0 :     return m_pred;
     908             : }
     909             : 
     910             : 
     911             : 
     912             : 
     913          84 : void OMarkableInputStream::checkMarksAndFlush()
     914             : {
     915          84 :     map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
     916             : 
     917             :     // find the smallest mark
     918          84 :     sal_Int32 nNextFound = m_nCurrentPos;
     919         159 :     for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
     920          75 :         if( (*ii).second <= nNextFound )  {
     921          52 :             nNextFound = (*ii).second;
     922             :         }
     923             :     }
     924             : 
     925          84 :     if( nNextFound ) {
     926             :         // some data must be released !
     927          32 :         m_nCurrentPos -= nNextFound;
     928          32 :         for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
     929           0 :             (*ii).second -= nNextFound;
     930             :         }
     931             : 
     932          32 :         m_pBuffer->forgetFromStart( nNextFound );
     933             : 
     934             :     }
     935             :     else {
     936             :         // nothing to do. There is a mark or the current cursor position, that prevents
     937             :         // releasing data !
     938             :     }
     939          84 : }
     940             : 
     941             : // XServiceInfo
     942           1 : OUString OMarkableInputStream::getImplementationName() throw (std::exception)
     943             : {
     944           1 :     return OMarkableInputStream_getImplementationName();
     945             : }
     946             : 
     947             : // XServiceInfo
     948           0 : sal_Bool OMarkableInputStream::supportsService(const OUString& ServiceName) throw (std::exception)
     949             : {
     950           0 :     return cppu::supportsService(this, ServiceName);
     951             : }
     952             : 
     953             : // XServiceInfo
     954           1 : Sequence< OUString > OMarkableInputStream::getSupportedServiceNames() throw (std::exception)
     955             : {
     956           1 :     return OMarkableInputStream_getSupportedServiceNames();
     957             : }
     958             : 
     959             : /*------------------------
     960             : *
     961             : * external binding
     962             : *
     963             : *------------------------*/
     964          41 : Reference < XInterface > SAL_CALL OMarkableInputStream_CreateInstance(
     965             :     SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
     966             :     throw(Exception)
     967             : {
     968          41 :     OMarkableInputStream *p = new OMarkableInputStream( );
     969          41 :     return Reference< XInterface > ( static_cast<OWeakObject *>(p) );
     970             : }
     971             : 
     972         174 : OUString    OMarkableInputStream_getImplementationName()
     973             : {
     974         174 :     return OUString("com.sun.star.comp.io.stm.MarkableInputStream");
     975             : }
     976             : 
     977           9 : Sequence<OUString> OMarkableInputStream_getSupportedServiceNames()
     978             : {
     979           9 :     Sequence<OUString> aRet(1);
     980           9 :     aRet.getArray()[0] = "com.sun.star.io.MarkableInputStream";
     981           9 :     return aRet;
     982             : }
     983             : 
     984             : }
     985             : 
     986             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11