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