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