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