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