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