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