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