Branch data 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 [ + - ][ + - ]: 82 : OMarkableOutputStream::OMarkableOutputStream( )
149 : : {
150 [ + - ]: 82 : g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
151 [ + - ][ + - ]: 82 : m_pBuffer = new MemRingBuffer;
152 : 82 : m_nCurrentPos = 0;
153 : 82 : m_nCurrentMark = 0;
154 : 82 : }
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 : 3838 : void OMarkableOutputStream::writeBytes(const Sequence< sal_Int8 >& aData)
165 : : throw ( NotConnectedException,
166 : : BufferSizeExceededException,
167 : : RuntimeException)
168 : : {
169 [ + - ]: 3838 : if( m_bValidStream ) {
170 [ + + ][ + - ]: 3838 : if( m_mapMarks.empty() && ( m_pBuffer->getSize() == 0 ) ) {
[ + + ]
171 : : // no mark and buffer active, simple write through
172 : 1436 : m_output->writeBytes( aData );
173 : : }
174 : : else {
175 [ + - ]: 2402 : MutexGuard guard( m_mutex );
176 : : // new data must be buffered
177 : : try
178 : : {
179 [ + - ]: 2402 : m_pBuffer->writeAt( m_nCurrentPos , aData );
180 : 2402 : 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 [ + - ][ + - ]: 2402 : checkMarksAndFlush();
191 : : }
192 : : }
193 : : else {
194 [ # # ]: 0 : throw NotConnectedException();
195 : : }
196 : 3838 : }
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 : 176 : sal_Int32 OMarkableOutputStream::createMark(void)
247 : : throw ( IOException,
248 : : RuntimeException)
249 : : {
250 [ + - ]: 176 : MutexGuard guard( m_mutex );
251 : 176 : sal_Int32 nMark = m_nCurrentMark;
252 : :
253 [ + - ]: 176 : m_mapMarks[nMark] = m_nCurrentPos;
254 : :
255 : 176 : m_nCurrentMark ++;
256 [ + - ]: 176 : return nMark;
257 : : }
258 : :
259 : 176 : void OMarkableOutputStream::deleteMark(sal_Int32 Mark)
260 : : throw( IOException,
261 : : IllegalArgumentException,
262 : : RuntimeException)
263 : : {
264 [ + - ]: 176 : MutexGuard guard( m_mutex );
265 [ + - ]: 176 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
266 : :
267 [ + - ][ - + ]: 176 : 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 [ + - ]: 176 : m_mapMarks.erase( ii );
276 [ + - ]: 176 : checkMarksAndFlush();
277 [ + - ]: 176 : }
278 : 176 : }
279 : :
280 : 176 : void OMarkableOutputStream::jumpToMark(sal_Int32 nMark)
281 : : throw (IOException,
282 : : IllegalArgumentException,
283 : : RuntimeException)
284 : : {
285 [ + - ]: 176 : MutexGuard guard( m_mutex );
286 [ + - ]: 176 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
287 : :
288 [ + - ][ - + ]: 176 : 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 [ + - ]: 176 : m_nCurrentPos = (*ii).second;
297 [ + - ]: 176 : }
298 : 176 : }
299 : :
300 : 176 : void OMarkableOutputStream::jumpToFurthest(void)
301 : : throw (IOException,
302 : : RuntimeException)
303 : : {
304 [ + - ]: 176 : MutexGuard guard( m_mutex );
305 : 176 : m_nCurrentPos = m_pBuffer->getSize();
306 [ + - ][ + - ]: 176 : checkMarksAndFlush();
307 : 176 : }
308 : :
309 : 176 : sal_Int32 OMarkableOutputStream::offsetToMark(sal_Int32 nMark)
310 : : throw (IOException,
311 : : IllegalArgumentException,
312 : : RuntimeException)
313 : : {
314 : :
315 [ + - ]: 176 : MutexGuard guard( m_mutex );
316 [ + - ][ + - ]: 176 : map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
317 : :
318 [ + - ][ + - ]: 176 : 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 [ + - ][ + - ]: 176 : return m_nCurrentPos - (*ii).second;
327 : : }
328 : :
329 : :
330 : :
331 : : // XActiveDataSource2
332 : 82 : void OMarkableOutputStream::setOutputStream(const Reference < XOutputStream >& aStream)
333 : : throw (RuntimeException)
334 : : {
335 [ + - ]: 82 : if( m_output != aStream ) {
336 [ + - ]: 82 : m_output = aStream;
337 : :
338 [ + - ]: 82 : Reference < XConnectable > succ( m_output , UNO_QUERY );
339 [ + - ]: 82 : setSuccessor( succ );
340 : : }
341 : 82 : m_bValidStream = m_output.is();
342 : 82 : }
343 : :
344 : 0 : Reference< XOutputStream > OMarkableOutputStream::getOutputStream(void) throw (RuntimeException)
345 : : {
346 : 0 : return m_output;
347 : : }
348 : :
349 : :
350 : :
351 : 164 : void OMarkableOutputStream::setSuccessor( const Reference< XConnectable > &r )
352 : : throw (RuntimeException)
353 : : {
354 : : /// if the references match, nothing needs to be done
355 [ + + ]: 164 : if( m_succ != r ) {
356 : : /// store the reference for later use
357 : 82 : m_succ = r;
358 : :
359 [ + - ]: 82 : if( m_succ.is() ) {
360 : 82 : m_succ->setPredecessor( Reference < XConnectable > (
361 [ + - ]: 82 : (static_cast< XConnectable * >(this)) ) );
362 : : }
363 : : }
364 : 164 : }
365 : 0 : Reference <XConnectable > OMarkableOutputStream::getSuccessor() throw (RuntimeException)
366 : : {
367 : 0 : return m_succ;
368 : : }
369 : :
370 : :
371 : : // XDataSource
372 : 82 : void OMarkableOutputStream::setPredecessor( const Reference< XConnectable > &r )
373 : : throw (RuntimeException)
374 : : {
375 [ + - ]: 82 : if( r != m_pred ) {
376 : 82 : m_pred = r;
377 [ + - ]: 82 : if( m_pred.is() ) {
378 : 82 : m_pred->setSuccessor( Reference < XConnectable > (
379 [ + - ]: 82 : (static_cast< XConnectable * >(this )) ) );
380 : : }
381 : : }
382 : 82 : }
383 : 0 : Reference < XConnectable > OMarkableOutputStream::getPredecessor() throw (RuntimeException)
384 : : {
385 : 0 : return m_pred;
386 : : }
387 : :
388 : :
389 : : // private methods
390 : :
391 : 2754 : void OMarkableOutputStream::checkMarksAndFlush() throw( NotConnectedException,
392 : : BufferSizeExceededException)
393 : : {
394 [ + - ]: 2754 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
395 : :
396 : : // find the smallest mark
397 : 2754 : sal_Int32 nNextFound = m_nCurrentPos;
398 [ + - ][ + - ]: 8240 : for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
[ + + ]
399 [ + - ][ + + ]: 5486 : if( (*ii).second <= nNextFound ) {
400 [ + - ]: 2684 : nNextFound = (*ii).second;
401 : : }
402 : : }
403 : :
404 [ + + ]: 2754 : if( nNextFound ) {
405 : : // some data must be released !
406 : 70 : m_nCurrentPos -= nNextFound;
407 [ # # ][ + - ]: 70 : for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
[ - + ]
408 [ # # ]: 0 : (*ii).second -= nNextFound;
409 : : }
410 : :
411 [ + - ]: 70 : Sequence<sal_Int8> seq(nNextFound);
412 [ + - ]: 70 : m_pBuffer->readAt( 0 , seq , nNextFound );
413 [ + - ]: 70 : m_pBuffer->forgetFromStart( nNextFound );
414 : :
415 : : // now write data through to streams
416 [ + - ][ + - ]: 70 : 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 : 2754 : }
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 : 82 : Reference< XInterface > SAL_CALL OMarkableOutputStream_CreateInstance(
459 : : SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
460 : : throw(Exception)
461 : : {
462 [ + - ]: 82 : OMarkableOutputStream *p = new OMarkableOutputStream( );
463 : :
464 : 82 : return Reference < XInterface > ( ( OWeakObject * ) p );
465 : : }
466 : :
467 : 20 : OUString OMarkableOutputStream_getImplementationName()
468 : : {
469 : 20 : return OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.stm.MarkableOutputStream" ));
470 : : }
471 : :
472 : 4 : Sequence<OUString> OMarkableOutputStream_getSupportedServiceNames(void)
473 : : {
474 : 4 : Sequence<OUString> aRet(1);
475 [ + - ][ + - ]: 4 : aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.MarkableOutputStream" ) );
476 : :
477 : 4 : 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 [ + - ][ + - ]: 82 : OMarkableInputStream::OMarkableInputStream()
575 : : {
576 [ + - ]: 82 : g_moduleCount.modCnt.acquire( &g_moduleCount.modCnt );
577 : 82 : m_nCurrentPos = 0;
578 : 82 : m_nCurrentMark = 0;
579 [ + - ][ + - ]: 82 : m_pBuffer = new MemRingBuffer;
580 : 82 : }
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 : 3770 : 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 [ + - ]: 3770 : if( m_bValidStream ) {
604 [ + - ]: 3770 : MutexGuard guard( m_mutex );
605 [ + + ][ + - ]: 3770 : if( m_mapMarks.empty() && ! m_pBuffer->getSize() ) {
[ + + ]
606 : : // normal read !
607 [ + - ][ + - ]: 1506 : 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 [ + + ]: 2264 : if( m_pBuffer->getSize() - m_nCurrentPos < nBytesToRead ) {
615 : 2108 : sal_Int32 nToRead = nBytesToRead - ( m_pBuffer->getSize() - m_nCurrentPos );
616 [ + - ][ + - ]: 2108 : nRead = m_input->readBytes( aData , nToRead );
617 : :
618 : : OSL_ASSERT( aData.getLength() == nRead );
619 : :
620 : : try
621 : : {
622 [ + - ]: 2108 : 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 [ - + ]: 2108 : if( nRead < nToRead ) {
632 : 0 : nBytesToRead = nBytesToRead - (nToRead-nRead);
633 : : }
634 : : }
635 : :
636 : : OSL_ASSERT( m_pBuffer->getSize() - m_nCurrentPos >= nBytesToRead );
637 : :
638 [ + - ]: 2264 : m_pBuffer->readAt( m_nCurrentPos , aData , nBytesToRead );
639 : :
640 : 2264 : m_nCurrentPos += nBytesToRead;
641 : 2264 : nBytesRead = nBytesToRead;
642 [ + - ]: 3770 : }
643 : : }
644 : : else {
645 : : throw NotConnectedException(
646 : : OUString( RTL_CONSTASCII_USTRINGPARAM("MarkableInputStream::readBytes NotConnectedException")) ,
647 [ # # ][ # # ]: 0 : *this );
[ # # ]
648 : : }
649 : 3770 : 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( RTL_CONSTASCII_USTRINGPARAM("MarkableInputStream::readSomeBytes NotConnectedException")) ,
709 [ # # ][ # # ]: 0 : *this );
[ # # ]
710 : : }
711 : 0 : return nBytesRead;
712 : :
713 : :
714 : : }
715 : :
716 : :
717 : 168 : void OMarkableInputStream::skipBytes(sal_Int32 nBytesToSkip)
718 : : throw ( NotConnectedException,
719 : : BufferSizeExceededException,
720 : : RuntimeException)
721 : : {
722 [ - + ]: 168 : if ( nBytesToSkip < 0 )
723 : : throw BufferSizeExceededException(
724 : : ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("precondition not met: XInputStream::skipBytes: non-negative integer required!")),
725 : : *this
726 [ # # ][ # # ]: 0 : );
[ # # ]
727 : :
728 : : // this method is blocking
729 [ + - ]: 168 : Sequence<sal_Int8> seqDummy( nBytesToSkip );
730 [ + - ][ + - ]: 168 : readBytes( seqDummy , nBytesToSkip );
731 : 168 : }
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( RTL_CONSTASCII_USTRINGPARAM( "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( RTL_CONSTASCII_USTRINGPARAM( "MarkableInputStream::closeInput NotConnectedException" ) ) ,
770 [ # # ][ # # ]: 0 : *this );
[ # # ]
771 : : }
772 : 0 : }
773 : :
774 : : // XMarkable
775 : :
776 : 170 : sal_Int32 OMarkableInputStream::createMark(void) throw (IOException, RuntimeException)
777 : : {
778 [ + - ]: 170 : MutexGuard guard( m_mutex );
779 : 170 : sal_Int32 nMark = m_nCurrentMark;
780 : :
781 [ + - ]: 170 : m_mapMarks[nMark] = m_nCurrentPos;
782 : :
783 : 170 : m_nCurrentMark ++;
784 [ + - ]: 170 : return nMark;
785 : : }
786 : :
787 : 170 : void OMarkableInputStream::deleteMark(sal_Int32 Mark) throw (IOException, IllegalArgumentException, RuntimeException)
788 : : {
789 [ + - ]: 170 : MutexGuard guard( m_mutex );
790 [ + - ]: 170 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( Mark );
791 : :
792 [ + - ][ - + ]: 170 : 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 [ + - ]: 170 : m_mapMarks.erase( ii );
801 [ + - ]: 170 : checkMarksAndFlush();
802 [ + - ]: 170 : }
803 : 170 : }
804 : :
805 : 168 : void OMarkableInputStream::jumpToMark(sal_Int32 nMark)
806 : : throw (IOException,
807 : : IllegalArgumentException,
808 : : RuntimeException)
809 : : {
810 [ + - ]: 168 : MutexGuard guard( m_mutex );
811 [ + - ]: 168 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii = m_mapMarks.find( nMark );
812 : :
813 [ + - ][ - + ]: 168 : 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 [ + - ]: 168 : m_nCurrentPos = (*ii).second;
824 [ + - ]: 168 : }
825 : 168 : }
826 : :
827 : 2 : void OMarkableInputStream::jumpToFurthest(void) throw (IOException, RuntimeException)
828 : : {
829 [ + - ]: 2 : MutexGuard guard( m_mutex );
830 : 2 : m_nCurrentPos = m_pBuffer->getSize();
831 [ + - ][ + - ]: 2 : checkMarksAndFlush();
832 : 2 : }
833 : :
834 : 2 : sal_Int32 OMarkableInputStream::offsetToMark(sal_Int32 nMark)
835 : : throw (IOException,
836 : : IllegalArgumentException,
837 : : RuntimeException)
838 : : {
839 [ + - ]: 2 : MutexGuard guard( m_mutex );
840 [ + - ][ + - ]: 2 : map<sal_Int32,sal_Int32,less<sal_Int32> >::const_iterator ii = m_mapMarks.find( nMark );
841 : :
842 [ + - ][ + - ]: 2 : 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 [ + - ][ + - ]: 2 : return m_nCurrentPos - (*ii).second;
851 : : }
852 : :
853 : :
854 : :
855 : :
856 : :
857 : :
858 : :
859 : : // XActiveDataSource
860 : 82 : void OMarkableInputStream::setInputStream(const Reference< XInputStream > & aStream)
861 : : throw (RuntimeException)
862 : : {
863 : :
864 [ + - ]: 82 : if( m_input != aStream ) {
865 [ + - ]: 82 : m_input = aStream;
866 : :
867 [ + - ]: 82 : Reference < XConnectable > pred( m_input , UNO_QUERY );
868 [ + - ]: 82 : setPredecessor( pred );
869 : : }
870 : :
871 : 82 : m_bValidStream = m_input.is();
872 : :
873 : 82 : }
874 : :
875 : 0 : Reference< XInputStream > OMarkableInputStream::getInputStream(void) throw (RuntimeException)
876 : : {
877 : 0 : return m_input;
878 : : }
879 : :
880 : :
881 : :
882 : : // XDataSink
883 : 82 : void OMarkableInputStream::setSuccessor( const Reference< XConnectable > &r )
884 : : throw (RuntimeException)
885 : : {
886 : : /// if the references match, nothing needs to be done
887 [ + - ]: 82 : if( m_succ != r ) {
888 : : /// store the reference for later use
889 : 82 : m_succ = r;
890 : :
891 [ + - ]: 82 : if( m_succ.is() ) {
892 : : /// set this instance as the sink !
893 : 82 : m_succ->setPredecessor( Reference< XConnectable > (
894 [ + - ]: 82 : (static_cast< XConnectable * >(this)) ) );
895 : : }
896 : : }
897 : 82 : }
898 : :
899 : 0 : Reference < XConnectable > OMarkableInputStream::getSuccessor() throw (RuntimeException)
900 : : {
901 : 0 : return m_succ;
902 : : }
903 : :
904 : :
905 : : // XDataSource
906 : 164 : void OMarkableInputStream::setPredecessor( const Reference < XConnectable > &r )
907 : : throw (RuntimeException)
908 : : {
909 [ + + ]: 164 : if( r != m_pred ) {
910 : 82 : m_pred = r;
911 [ + - ]: 82 : if( m_pred.is() ) {
912 : 82 : m_pred->setSuccessor( Reference< XConnectable > (
913 [ + - ]: 82 : (static_cast< XConnectable * >(this)) ) );
914 : : }
915 : : }
916 : 164 : }
917 : 0 : Reference< XConnectable > OMarkableInputStream::getPredecessor() throw (RuntimeException)
918 : : {
919 : 0 : return m_pred;
920 : : }
921 : :
922 : :
923 : :
924 : :
925 : 172 : void OMarkableInputStream::checkMarksAndFlush()
926 : : {
927 [ + - ]: 172 : map<sal_Int32,sal_Int32,less<sal_Int32> >::iterator ii;
928 : :
929 : : // find the smallest mark
930 : 172 : sal_Int32 nNextFound = m_nCurrentPos;
931 [ + - ][ + - ]: 324 : for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
[ + + ]
932 [ + - ][ + + ]: 152 : if( (*ii).second <= nNextFound ) {
933 [ + - ]: 106 : nNextFound = (*ii).second;
934 : : }
935 : : }
936 : :
937 [ + + ]: 172 : if( nNextFound ) {
938 : : // some data must be released !
939 : 66 : m_nCurrentPos -= nNextFound;
940 [ # # ][ + - ]: 66 : for( ii = m_mapMarks.begin() ; ii != m_mapMarks.end() ; ++ii ) {
[ - + ]
941 [ # # ]: 0 : (*ii).second -= nNextFound;
942 : : }
943 : :
944 [ + - ]: 66 : 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 : 172 : }
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 : 82 : Reference < XInterface > SAL_CALL OMarkableInputStream_CreateInstance(
987 : : SAL_UNUSED_PARAMETER const Reference < XComponentContext > & )
988 : : throw(Exception)
989 : : {
990 [ + - ]: 82 : OMarkableInputStream *p = new OMarkableInputStream( );
991 : 82 : return Reference< XInterface > ( (OWeakObject * ) p );
992 : : }
993 : :
994 : 20 : OUString OMarkableInputStream_getImplementationName()
995 : : {
996 : 20 : return OUString(RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.comp.io.stm.MarkableInputStream" ));
997 : : }
998 : :
999 : 4 : Sequence<OUString> OMarkableInputStream_getSupportedServiceNames(void)
1000 : : {
1001 : 4 : Sequence<OUString> aRet(1);
1002 [ + - ][ + - ]: 4 : aRet.getArray()[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.MarkableInputStream" ));
1003 : 4 : return aRet;
1004 : : }
1005 : :
1006 : : }
1007 : :
1008 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|