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