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