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