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