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_package.hxx" 30 #include <osl/diagnose.h> 31 32 #include <comphelper/storagehelper.hxx> 33 #include <switchpersistencestream.hxx> 34 35 using namespace ::com::sun::star; 36 37 // ======================================================================== 38 struct SPStreamData_Impl 39 { 40 uno::Reference< lang::XMultiServiceFactory > m_xFactory; 41 42 sal_Bool m_bInStreamBased; 43 44 // the streams below are not visible from outside so there is no need to remember position 45 46 // original stream related members 47 uno::Reference< io::XStream > m_xOrigStream; 48 uno::Reference< io::XTruncate > m_xOrigTruncate; 49 uno::Reference< io::XSeekable > m_xOrigSeekable; 50 uno::Reference< io::XInputStream > m_xOrigInStream; 51 uno::Reference< io::XOutputStream > m_xOrigOutStream; 52 53 sal_Bool m_bInOpen; 54 sal_Bool m_bOutOpen; 55 56 57 SPStreamData_Impl( 58 const uno::Reference< lang::XMultiServiceFactory >& xFactory, 59 sal_Bool bInStreamBased, 60 const uno::Reference< io::XStream >& xOrigStream, 61 const uno::Reference< io::XTruncate >& xOrigTruncate, 62 const uno::Reference< io::XSeekable >& xOrigSeekable, 63 const uno::Reference< io::XInputStream >& xOrigInStream, 64 const uno::Reference< io::XOutputStream >& xOrigOutStream, 65 sal_Bool bInOpen, 66 sal_Bool bOutOpen ) 67 : m_xFactory( xFactory ) 68 , m_bInStreamBased( bInStreamBased ) 69 , m_xOrigStream( xOrigStream ) 70 , m_xOrigTruncate( xOrigTruncate ) 71 , m_xOrigSeekable( xOrigSeekable ) 72 , m_xOrigInStream( xOrigInStream ) 73 , m_xOrigOutStream( xOrigOutStream ) 74 , m_bInOpen( bInOpen ) 75 , m_bOutOpen( bOutOpen ) 76 { 77 } 78 }; 79 80 // ======================================================================== 81 // ------------------------------------------------------------------------ 82 SwitchablePersistenceStream::SwitchablePersistenceStream( 83 const uno::Reference< lang::XMultiServiceFactory >& xFactory, 84 const uno::Reference< io::XStream >& xStream ) 85 : m_xFactory( xFactory ) 86 , m_pStreamData( NULL ) 87 { 88 SwitchPersistenceTo( xStream ); 89 } 90 91 // ------------------------------------------------------------------------ 92 SwitchablePersistenceStream::SwitchablePersistenceStream( 93 const uno::Reference< lang::XMultiServiceFactory >& xFactory, 94 const uno::Reference< io::XInputStream >& xInputStream ) 95 : m_xFactory( xFactory ) 96 , m_pStreamData( NULL ) 97 { 98 SwitchPersistenceTo( xInputStream ); 99 } 100 101 // ------------------------------------------------------------------------ 102 SwitchablePersistenceStream::~SwitchablePersistenceStream() 103 { 104 CloseAll_Impl(); 105 } 106 107 // ------------------------------------------------------------------------ 108 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XStream >& xStream ) 109 { 110 uno::Reference< io::XTruncate > xNewTruncate( xStream, uno::UNO_QUERY_THROW ); 111 uno::Reference< io::XSeekable > xNewSeekable( xStream, uno::UNO_QUERY_THROW ); 112 uno::Reference< io::XInputStream > xNewInStream = xStream->getInputStream(); 113 uno::Reference< io::XOutputStream > xNewOutStream = xStream->getOutputStream(); 114 if ( !xNewInStream.is() || !xNewOutStream.is() ) 115 throw uno::RuntimeException(); 116 117 sal_Int64 nPos = 0; 118 sal_Bool bInOpen = sal_False; 119 sal_Bool bOutOpen = sal_False; 120 121 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() ) 122 { 123 // check that the length is the same 124 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() ) 125 throw uno::RuntimeException(); 126 127 // get the current position 128 nPos = m_pStreamData->m_xOrigSeekable->getPosition(); 129 bInOpen = m_pStreamData->m_bInOpen; 130 bOutOpen = m_pStreamData->m_bOutOpen; 131 } 132 133 xNewSeekable->seek( nPos ); 134 135 CloseAll_Impl(); 136 137 m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False, 138 xStream, xNewTruncate, xNewSeekable, xNewInStream, xNewOutStream, 139 bInOpen, bOutOpen ); 140 } 141 142 // ------------------------------------------------------------------------ 143 void SwitchablePersistenceStream::SwitchPersistenceTo( const uno::Reference< io::XInputStream >& xInputStream ) 144 { 145 uno::Reference< io::XStream > xNewStream; 146 uno::Reference< io::XTruncate > xNewTruncate; 147 uno::Reference< io::XSeekable > xNewSeekable( xInputStream, uno::UNO_QUERY_THROW ); 148 uno::Reference< io::XOutputStream > xNewOutStream; 149 if ( !xInputStream.is() ) 150 throw uno::RuntimeException(); 151 152 sal_Int64 nPos = 0; 153 sal_Bool bInOpen = sal_False; 154 sal_Bool bOutOpen = sal_False; 155 156 if ( m_pStreamData && m_pStreamData->m_xOrigSeekable.is() ) 157 { 158 // check that the length is the same 159 if ( m_pStreamData->m_xOrigSeekable->getLength() != xNewSeekable->getLength() ) 160 throw uno::RuntimeException(); 161 162 // get the current position 163 nPos = m_pStreamData->m_xOrigSeekable->getPosition(); 164 bInOpen = m_pStreamData->m_bInOpen; 165 bOutOpen = m_pStreamData->m_bOutOpen; 166 } 167 168 xNewSeekable->seek( nPos ); 169 170 CloseAll_Impl(); 171 172 m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_True, 173 xNewStream, xNewTruncate, xNewSeekable, xInputStream, xNewOutStream, 174 bInOpen, bOutOpen ); 175 176 } 177 178 // ------------------------------------------------------------------------ 179 void SwitchablePersistenceStream::CopyAndSwitchPersistenceTo( const uno::Reference< io::XStream >& xStream ) 180 { 181 uno::Reference< io::XStream > xTargetStream = xStream; 182 uno::Reference< io::XSeekable > xTargetSeek; 183 184 if ( !xTargetStream.is() ) 185 { 186 xTargetStream = uno::Reference < io::XStream >( 187 m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ), 188 uno::UNO_QUERY_THROW ); 189 190 xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW ); 191 } 192 else 193 { 194 // the provided stream must be empty 195 xTargetSeek = uno::Reference< io::XSeekable >( xTargetStream, uno::UNO_QUERY_THROW ); 196 if ( xTargetSeek->getLength() ) 197 throw io::IOException(); 198 } 199 200 uno::Reference< io::XTruncate > xTargetTruncate( xTargetStream, uno::UNO_QUERY_THROW ); 201 uno::Reference< io::XInputStream > xTargetInStream = xTargetStream->getInputStream(); 202 uno::Reference< io::XOutputStream > xTargetOutStream = xTargetStream->getOutputStream(); 203 if ( !xTargetInStream.is() || !xTargetOutStream.is() ) 204 throw uno::RuntimeException(); 205 206 if ( !m_pStreamData->m_xOrigInStream.is() || !m_pStreamData->m_xOrigSeekable.is() ) 207 throw uno::RuntimeException(); 208 209 sal_Int64 nPos = m_pStreamData->m_xOrigSeekable->getPosition(); 210 m_pStreamData->m_xOrigSeekable->seek( 0 ); 211 ::comphelper::OStorageHelper::CopyInputToOutput( m_pStreamData->m_xOrigInStream, xTargetOutStream ); 212 xTargetOutStream->flush(); 213 xTargetSeek->seek( nPos ); 214 215 sal_Bool bInOpen = m_pStreamData->m_bInOpen; 216 sal_Bool bOutOpen = m_pStreamData->m_bOutOpen; 217 218 CloseAll_Impl(); 219 220 m_pStreamData = new SPStreamData_Impl( m_xFactory, sal_False, 221 xTargetStream, xTargetTruncate, xTargetSeek, xTargetInStream, xTargetOutStream, 222 bInOpen, bOutOpen ); 223 } 224 225 // ------------------------------------------------------------------------ 226 void SwitchablePersistenceStream::CloseAll_Impl() 227 { 228 if ( m_pStreamData ) 229 { 230 delete m_pStreamData; 231 m_pStreamData = NULL; 232 } 233 } 234 235 // com::sun::star::io::XStream 236 // ------------------------------------------------------------------------ 237 uno::Reference< io::XInputStream > SAL_CALL SwitchablePersistenceStream::getInputStream( ) 238 throw (uno::RuntimeException) 239 { 240 ::osl::MutexGuard aGuard( m_aMutex ); 241 242 if ( m_pStreamData ) 243 m_pStreamData->m_bInOpen = sal_True; 244 return static_cast< io::XInputStream* >( this ); 245 } 246 247 248 // ------------------------------------------------------------------------ 249 uno::Reference< io::XOutputStream > SAL_CALL SwitchablePersistenceStream::getOutputStream( ) 250 throw (uno::RuntimeException) 251 { 252 ::osl::MutexGuard aGuard( m_aMutex ); 253 254 if ( m_pStreamData ) 255 m_pStreamData->m_bOutOpen = sal_True; 256 return static_cast< io::XOutputStream* >( this ); 257 } 258 259 260 261 // com::sun::star::io::XInputStream 262 // ------------------------------------------------------------------------ 263 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead ) 264 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 265 { 266 ::osl::MutexGuard aGuard( m_aMutex ); 267 268 if ( !m_pStreamData ) 269 throw io::NotConnectedException(); 270 271 // the original stream data should be provided 272 if ( !m_pStreamData->m_xOrigInStream.is() ) 273 throw uno::RuntimeException(); 274 275 return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead ); 276 } 277 278 279 // ------------------------------------------------------------------------ 280 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead ) 281 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 282 { 283 ::osl::MutexGuard aGuard( m_aMutex ); 284 285 if ( !m_pStreamData ) 286 throw io::NotConnectedException(); 287 288 // the original stream data should be provided 289 if ( !m_pStreamData->m_xOrigInStream.is() ) 290 throw uno::RuntimeException(); 291 292 return m_pStreamData->m_xOrigInStream->readBytes( aData, nMaxBytesToRead ); 293 } 294 295 // ------------------------------------------------------------------------ 296 void SAL_CALL SwitchablePersistenceStream::skipBytes( ::sal_Int32 nBytesToSkip ) 297 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 298 { 299 ::osl::MutexGuard aGuard( m_aMutex ); 300 301 if ( !m_pStreamData ) 302 throw io::NotConnectedException(); 303 304 // the original stream data should be provided 305 if ( !m_pStreamData->m_xOrigInStream.is() ) 306 throw uno::RuntimeException(); 307 308 m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip ); 309 } 310 311 312 // ------------------------------------------------------------------------ 313 ::sal_Int32 SAL_CALL SwitchablePersistenceStream::available( ) 314 throw (io::NotConnectedException, io::IOException, uno::RuntimeException) 315 { 316 ::osl::MutexGuard aGuard( m_aMutex ); 317 318 if ( !m_pStreamData ) 319 throw io::NotConnectedException(); 320 321 // the original stream data should be provided 322 if ( !m_pStreamData->m_xOrigInStream.is() ) 323 throw uno::RuntimeException(); 324 325 return m_pStreamData->m_xOrigInStream->available(); 326 } 327 328 329 // ------------------------------------------------------------------------ 330 void SAL_CALL SwitchablePersistenceStream::closeInput() 331 throw (io::NotConnectedException, io::IOException, uno::RuntimeException) 332 { 333 ::osl::MutexGuard aGuard( m_aMutex ); 334 335 if ( !m_pStreamData ) 336 throw io::NotConnectedException(); 337 338 m_pStreamData->m_bInOpen = sal_False; 339 if ( !m_pStreamData->m_bOutOpen ) 340 CloseAll_Impl(); 341 } 342 343 344 345 // com::sun::star::io::XOutputStream 346 // ------------------------------------------------------------------------ 347 void SAL_CALL SwitchablePersistenceStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData ) 348 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 349 { 350 ::osl::MutexGuard aGuard( m_aMutex ); 351 352 if ( !m_pStreamData ) 353 throw io::NotConnectedException(); 354 355 if ( m_pStreamData->m_bInStreamBased ) 356 throw io::IOException(); 357 358 // the original stream data should be provided 359 if ( !m_pStreamData->m_xOrigOutStream.is() ) 360 throw uno::RuntimeException(); 361 362 m_pStreamData->m_xOrigOutStream->writeBytes( aData ); 363 } 364 365 366 // ------------------------------------------------------------------------ 367 void SAL_CALL SwitchablePersistenceStream::flush( ) 368 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 369 { 370 ::osl::MutexGuard aGuard( m_aMutex ); 371 372 if ( !m_pStreamData || m_pStreamData->m_bInStreamBased ) 373 { 374 OSL_ENSURE( sal_False, "flush() is not acceptable!\n" ); 375 return; 376 // in future throw exception, for now some code might call flush() on closed stream 377 // since file ucp implementation allows it 378 // throw io::NotConnectedException(); 379 } 380 381 // the original stream data should be provided 382 if ( !m_pStreamData->m_xOrigOutStream.is() ) 383 throw uno::RuntimeException(); 384 385 m_pStreamData->m_xOrigOutStream->flush(); 386 } 387 388 389 // ------------------------------------------------------------------------ 390 void SAL_CALL SwitchablePersistenceStream::closeOutput( ) 391 throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException) 392 { 393 ::osl::MutexGuard aGuard( m_aMutex ); 394 395 if ( !m_pStreamData ) 396 throw io::NotConnectedException(); 397 398 m_pStreamData->m_bOutOpen = sal_False; 399 if ( !m_pStreamData->m_bInOpen ) 400 CloseAll_Impl(); 401 } 402 403 404 405 // com::sun::star::io::XTruncate 406 // ------------------------------------------------------------------------ 407 void SAL_CALL SwitchablePersistenceStream::truncate( ) 408 throw (io::IOException, uno::RuntimeException) 409 { 410 ::osl::MutexGuard aGuard( m_aMutex ); 411 412 if ( !m_pStreamData ) 413 throw io::NotConnectedException(); 414 415 if ( m_pStreamData->m_bInStreamBased ) 416 throw io::IOException(); 417 418 // the original stream data should be provided 419 if ( !m_pStreamData->m_xOrigTruncate.is() ) 420 throw uno::RuntimeException(); 421 422 m_pStreamData->m_xOrigTruncate->truncate(); 423 } 424 425 426 // com::sun::star::io::XSeekable 427 // ------------------------------------------------------------------------ 428 void SAL_CALL SwitchablePersistenceStream::seek( ::sal_Int64 location ) 429 throw (lang::IllegalArgumentException, io::IOException, uno::RuntimeException) 430 { 431 ::osl::MutexGuard aGuard( m_aMutex ); 432 433 if ( !m_pStreamData ) 434 throw io::NotConnectedException(); 435 436 // the original stream data should be provided 437 if ( !m_pStreamData->m_xOrigSeekable.is() ) 438 throw uno::RuntimeException(); 439 440 m_pStreamData->m_xOrigSeekable->seek( location ); 441 } 442 443 444 // ------------------------------------------------------------------------ 445 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getPosition( ) 446 throw (io::IOException, uno::RuntimeException) 447 { 448 ::osl::MutexGuard aGuard( m_aMutex ); 449 450 if ( !m_pStreamData ) 451 throw io::NotConnectedException(); 452 453 // the original stream data should be provided 454 if ( !m_pStreamData->m_xOrigSeekable.is() ) 455 throw uno::RuntimeException(); 456 457 return m_pStreamData->m_xOrigSeekable->getPosition(); 458 } 459 460 461 // ------------------------------------------------------------------------ 462 ::sal_Int64 SAL_CALL SwitchablePersistenceStream::getLength( ) 463 throw (io::IOException, uno::RuntimeException) 464 { 465 ::osl::MutexGuard aGuard( m_aMutex ); 466 467 if ( !m_pStreamData ) 468 throw io::NotConnectedException(); 469 470 // the original stream data should be provided 471 if ( !m_pStreamData->m_xOrigSeekable.is() ) 472 throw uno::RuntimeException(); 473 474 return m_pStreamData->m_xOrigSeekable->getLength(); 475 } 476 477 // ------------------------------------------------------------------------ 478 void SAL_CALL SwitchablePersistenceStream::waitForCompletion() 479 throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) 480 { 481 if ( !m_pStreamData ) 482 throw io::NotConnectedException(); 483 484 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY ); 485 if ( asyncOutputMonitor.is() ) 486 asyncOutputMonitor->waitForCompletion(); 487 } 488 489