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