xref: /aoo41x/main/io/source/stm/omark.cxx (revision cdf0e10c)
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