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

Generated by: LCOV version 1.10