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 #include "precompiled_unotools.hxx" 28 #include <XTempFile.hxx> 29 #include <cppuhelper/factory.hxx> 30 #include <cppuhelper/typeprovider.hxx> 31 #include <unotools/tempfile.hxx> 32 #include <osl/file.hxx> 33 #include <unotools/configmgr.hxx> 34 #include <tools/urlobj.hxx> 35 #include <tools/debug.hxx> 36 37 namespace css = com::sun::star; 38 39 // copy define from desktop\source\app\appinit.cxx 40 41 #define DESKTOP_TEMPNAMEBASE_DIR "/temp/soffice.tmp" 42 43 OTempFileService::OTempFileService(::css::uno::Reference< ::css::uno::XComponentContext > const & context) 44 : ::cppu::PropertySetMixin< ::css::io::XTempFile >( 45 context 46 , static_cast< Implements >( IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET | IMPLEMENTS_PROPERTY_ACCESS ) 47 , com::sun::star::uno::Sequence< rtl::OUString >() ) 48 , mpStream( NULL ) 49 , mbRemoveFile( sal_True ) 50 , mbInClosed( sal_False ) 51 , mbOutClosed( sal_False ) 52 , mnCachedPos( 0 ) 53 , mbHasCachedPos( sal_False ) 54 55 { 56 mpTempFile = new ::utl::TempFile; 57 mpTempFile->EnableKillingFile ( sal_True ); 58 } 59 60 OTempFileService::~OTempFileService () 61 { 62 if ( mpTempFile ) 63 delete mpTempFile; 64 } 65 66 67 // XInterface 68 69 ::css::uno::Any SAL_CALL OTempFileService::queryInterface( ::css::uno::Type const & aType ) 70 throw ( ::css::uno::RuntimeException ) 71 { 72 ::css::uno::Any aResult( OTempFileBase::queryInterface( aType ) ); 73 if (!aResult.hasValue()) 74 aResult = cppu::PropertySetMixin< ::css::io::XTempFile >::queryInterface( aType ) ; 75 return aResult; 76 }; 77 void SAL_CALL OTempFileService::acquire( ) 78 throw () 79 { 80 OTempFileBase::acquire(); 81 } 82 void SAL_CALL OTempFileService::release( ) 83 throw () 84 { 85 OTempFileBase::release(); 86 } 87 88 // XTypeProvider 89 90 ::css::uno::Sequence< ::css::uno::Type > SAL_CALL OTempFileService::getTypes( ) 91 throw ( ::css::uno::RuntimeException ) 92 { 93 static ::cppu::OTypeCollection* pTypeCollection = NULL; 94 if ( pTypeCollection == NULL ) 95 { 96 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; 97 98 if ( pTypeCollection == NULL ) 99 { 100 static ::cppu::OTypeCollection aTypeCollection( 101 ::getCppuType( ( const ::css::uno::Reference< ::css::beans::XPropertySet >*)NULL ) 102 ,OTempFileBase::getTypes() ); 103 pTypeCollection = &aTypeCollection; 104 } 105 } 106 return pTypeCollection->getTypes(); 107 }; 108 ::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId( ) 109 throw ( ::css::uno::RuntimeException ) 110 { 111 return OTempFileBase::getImplementationId(); 112 } 113 114 // XTempFile 115 116 sal_Bool SAL_CALL OTempFileService::getRemoveFile() 117 throw ( ::css::uno::RuntimeException ) 118 { 119 ::osl::MutexGuard aGuard( maMutex ); 120 121 if ( !mpTempFile ) 122 { 123 // the stream is already disconnected 124 throw ::css::uno::RuntimeException(); 125 } 126 127 return mbRemoveFile; 128 }; 129 void SAL_CALL OTempFileService::setRemoveFile( sal_Bool _removefile ) 130 throw ( ::css::uno::RuntimeException ) 131 { 132 ::osl::MutexGuard aGuard( maMutex ); 133 134 if ( !mpTempFile ) 135 { 136 // the stream is already disconnected 137 throw ::css::uno::RuntimeException(); 138 } 139 140 mbRemoveFile = _removefile; 141 mpTempFile->EnableKillingFile( mbRemoveFile ); 142 }; 143 ::rtl::OUString SAL_CALL OTempFileService::getUri() 144 throw ( ::css::uno::RuntimeException ) 145 { 146 ::osl::MutexGuard aGuard( maMutex ); 147 148 if ( !mpTempFile ) 149 { 150 throw ::css::uno::RuntimeException(); 151 } 152 153 return ::rtl::OUString( mpTempFile->GetURL() ); 154 155 }; 156 ::rtl::OUString SAL_CALL OTempFileService::getResourceName() 157 throw ( ::css::uno::RuntimeException ) 158 { 159 ::osl::MutexGuard aGuard( maMutex ); 160 161 if ( !mpTempFile ) 162 { 163 throw ::css::uno::RuntimeException(); 164 } 165 166 return ::rtl::OUString( mpTempFile->GetFileName() ); 167 }; 168 169 170 171 // XInputStream 172 173 sal_Int32 SAL_CALL OTempFileService::readBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) 174 throw (::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 175 { 176 ::osl::MutexGuard aGuard( maMutex ); 177 if ( mbInClosed ) 178 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 179 180 checkConnected(); 181 if (nBytesToRead < 0) 182 throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); 183 184 aData.realloc(nBytesToRead); 185 186 sal_uInt32 nRead = mpStream->Read(static_cast < void* > ( aData.getArray() ), nBytesToRead); 187 checkError(); 188 189 if (nRead < static_cast < sal_uInt32 > ( nBytesToRead ) ) 190 aData.realloc( nRead ); 191 192 if ( sal::static_int_cast<sal_uInt32>(nBytesToRead) > nRead ) 193 { 194 // usually that means that the stream was read till the end 195 // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) 196 mnCachedPos = mpStream->Tell(); 197 mbHasCachedPos = sal_True; 198 199 mpStream = NULL; 200 if ( mpTempFile ) 201 mpTempFile->CloseStream(); 202 } 203 204 return nRead; 205 } 206 sal_Int32 SAL_CALL OTempFileService::readSomeBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) 207 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 208 { 209 ::osl::MutexGuard aGuard( maMutex ); 210 if ( mbInClosed ) 211 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 212 213 checkConnected(); 214 checkError(); 215 216 if (nMaxBytesToRead < 0) 217 throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast < ::css::uno::XWeak * >( this ) ); 218 219 if (mpStream->IsEof()) 220 { 221 aData.realloc(0); 222 return 0; 223 } 224 else 225 return readBytes(aData, nMaxBytesToRead); 226 } 227 void SAL_CALL OTempFileService::skipBytes( sal_Int32 nBytesToSkip ) 228 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 229 { 230 ::osl::MutexGuard aGuard( maMutex ); 231 if ( mbInClosed ) 232 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 233 234 checkConnected(); 235 checkError(); 236 mpStream->SeekRel(nBytesToSkip); 237 checkError(); 238 } 239 sal_Int32 SAL_CALL OTempFileService::available( ) 240 throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) 241 { 242 ::osl::MutexGuard aGuard( maMutex ); 243 if ( mbInClosed ) 244 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 245 246 checkConnected(); 247 248 sal_uInt32 nPos = mpStream->Tell(); 249 checkError(); 250 251 mpStream->Seek(STREAM_SEEK_TO_END); 252 checkError(); 253 254 sal_Int32 nAvailable = (sal_Int32)mpStream->Tell() - nPos; 255 mpStream->Seek(nPos); 256 checkError(); 257 258 return nAvailable; 259 } 260 void SAL_CALL OTempFileService::closeInput( ) 261 throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) 262 { 263 ::osl::MutexGuard aGuard( maMutex ); 264 if ( mbInClosed ) 265 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 266 267 mbInClosed = sal_True; 268 269 if ( mbOutClosed ) 270 { 271 // stream will be deleted by TempFile implementation 272 mpStream = NULL; 273 274 if ( mpTempFile ) 275 { 276 delete mpTempFile; 277 mpTempFile = NULL; 278 } 279 } 280 } 281 282 // XOutputStream 283 284 void SAL_CALL OTempFileService::writeBytes( const ::css::uno::Sequence< sal_Int8 >& aData ) 285 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 286 { 287 ::osl::MutexGuard aGuard( maMutex ); 288 if ( mbOutClosed ) 289 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 290 291 checkConnected(); 292 sal_uInt32 nWritten = mpStream->Write(aData.getConstArray(),aData.getLength()); 293 checkError(); 294 if ( nWritten != (sal_uInt32)aData.getLength()) 295 throw ::css::io::BufferSizeExceededException( ::rtl::OUString(),static_cast < ::css::uno::XWeak * > ( this ) ); 296 } 297 void SAL_CALL OTempFileService::flush( ) 298 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 299 { 300 ::osl::MutexGuard aGuard( maMutex ); 301 if ( mbOutClosed ) 302 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 303 304 checkConnected(); 305 mpStream->Flush(); 306 checkError(); 307 } 308 void SAL_CALL OTempFileService::closeOutput( ) 309 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) 310 { 311 ::osl::MutexGuard aGuard( maMutex ); 312 if ( mbOutClosed ) 313 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 314 315 mbOutClosed = sal_True; 316 317 // TODO/LATER: it is better to get rid of this optimization by avoiding using of multiple temporary files ( there should be only one temporary file? ) 318 if ( mpStream ) 319 { 320 mnCachedPos = mpStream->Tell(); 321 mbHasCachedPos = sal_True; 322 323 mpStream = NULL; 324 if ( mpTempFile ) 325 mpTempFile->CloseStream(); 326 } 327 328 if ( mbInClosed ) 329 { 330 // stream will be deleted by TempFile implementation 331 mpStream = NULL; 332 333 if ( mpTempFile ) 334 { 335 delete mpTempFile; 336 mpTempFile = NULL; 337 } 338 } 339 } 340 341 342 void OTempFileService::checkError () const 343 { 344 if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE ) 345 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 346 } 347 void OTempFileService::checkConnected () 348 { 349 if (!mpStream && mpTempFile) 350 { 351 mpStream = mpTempFile->GetStream( STREAM_STD_READWRITE ); 352 if ( mpStream && mbHasCachedPos ) 353 { 354 mpStream->Seek( sal::static_int_cast<sal_Size>(mnCachedPos) ); 355 if ( mpStream->SvStream::GetError () == ERRCODE_NONE ) 356 { 357 mbHasCachedPos = sal_False; 358 mnCachedPos = 0; 359 } 360 else 361 { 362 mpStream = NULL; 363 mpTempFile->CloseStream(); 364 } 365 } 366 } 367 368 if (!mpStream) 369 throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); 370 } 371 372 // XSeekable 373 374 void SAL_CALL OTempFileService::seek( sal_Int64 nLocation ) 375 throw ( ::css::lang::IllegalArgumentException, ::css::io::IOException, ::css::uno::RuntimeException ) 376 { 377 ::osl::MutexGuard aGuard( maMutex ); 378 checkConnected(); 379 if ( nLocation < 0 || nLocation > getLength() ) 380 throw ::css::lang::IllegalArgumentException(); 381 382 mpStream->Seek((sal_uInt32) nLocation ); 383 checkError(); 384 } 385 sal_Int64 SAL_CALL OTempFileService::getPosition( ) 386 throw ( ::css::io::IOException, ::css::uno::RuntimeException ) 387 { 388 ::osl::MutexGuard aGuard( maMutex ); 389 checkConnected(); 390 391 sal_uInt32 nPos = mpStream->Tell(); 392 checkError(); 393 return (sal_Int64)nPos; 394 } 395 sal_Int64 SAL_CALL OTempFileService::getLength( ) 396 throw ( ::css::io::IOException, ::css::uno::RuntimeException ) 397 { 398 ::osl::MutexGuard aGuard( maMutex ); 399 checkConnected(); 400 401 sal_uInt32 nCurrentPos = mpStream->Tell(); 402 checkError(); 403 404 mpStream->Seek(STREAM_SEEK_TO_END); 405 sal_uInt32 nEndPos = mpStream->Tell(); 406 mpStream->Seek(nCurrentPos); 407 408 checkError(); 409 410 return (sal_Int64)nEndPos; 411 } 412 413 414 // XStream 415 416 ::css::uno::Reference< ::css::io::XInputStream > SAL_CALL OTempFileService::getInputStream() 417 throw ( ::css::uno::RuntimeException ) 418 { 419 return ::css::uno::Reference< ::css::io::XInputStream >( *this, ::css::uno::UNO_QUERY ); 420 } 421 422 ::css::uno::Reference< ::css::io::XOutputStream > SAL_CALL OTempFileService::getOutputStream() 423 throw ( ::css::uno::RuntimeException ) 424 { 425 return ::css::uno::Reference< ::css::io::XOutputStream >( *this, ::css::uno::UNO_QUERY ); 426 } 427 428 // XTruncate 429 430 void SAL_CALL OTempFileService::truncate() 431 throw ( ::css::io::IOException, ::css::uno::RuntimeException ) 432 { 433 ::osl::MutexGuard aGuard( maMutex ); 434 checkConnected(); 435 // SetStreamSize() call does not change the position 436 mpStream->Seek( 0 ); 437 mpStream->SetStreamSize( 0 ); 438 checkError(); 439 } 440 441 // XServiceInfo 442 443 ::rtl::OUString SAL_CALL OTempFileService::getImplementationName() 444 throw ( ::css::uno::RuntimeException ) 445 { 446 return getImplementationName_Static(); 447 } 448 449 sal_Bool SAL_CALL OTempFileService::supportsService( ::rtl::OUString const & rServiceName ) 450 throw ( ::css::uno::RuntimeException ) 451 { 452 ::css::uno::Sequence< ::rtl::OUString > aServices(getSupportedServiceNames_Static()); 453 return rServiceName == aServices[0]; 454 } 455 456 ::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames() 457 throw ( ::css::uno::RuntimeException ) 458 { 459 return getSupportedServiceNames_Static(); 460 } 461 462 463 464 ::rtl::OUString OTempFileService::getImplementationName_Static () 465 { 466 return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) ); 467 } 468 ::css::uno::Sequence < ::rtl::OUString > OTempFileService::getSupportedServiceNames_Static() 469 { 470 ::css::uno::Sequence < ::rtl::OUString > aNames ( 1 ); 471 aNames[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); 472 return aNames; 473 } 474 ::css::uno::Reference < ::css::uno::XInterface >SAL_CALL XTempFile_createInstance( 475 css::uno::Reference< ::css::uno::XComponentContext > const & context) 476 SAL_THROW( ( css::uno::Exception ) ) 477 { 478 return static_cast< ::cppu::OWeakObject * >( new OTempFileService(context) ); 479 } 480 481 ::css::uno::Reference < ::css::lang::XSingleComponentFactory > OTempFileService::createServiceFactory_Static( ::css::uno::Reference < ::css::lang::XMultiServiceFactory > const & ) 482 { 483 return ::cppu::createSingleComponentFactory( XTempFile_createInstance, getImplementationName_Static(), getSupportedServiceNames_Static() ); 484 } 485 486 // C functions to implement this as a component 487 488 extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( 489 const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) 490 { 491 *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; 492 } 493 494 /** 495 * This function is called to get service factories for an implementation. 496 * @param pImplName name of implementation 497 * @param pServiceManager generic uno interface providing a service manager to instantiate components 498 * @param pRegistryKey registry data key to read and write component persistent data 499 * @return a component factory (generic uno interface) 500 */ 501 extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( 502 const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) 503 { 504 void * pRet = 0; 505 ::css::uno::Reference< ::css::lang::XMultiServiceFactory > xSMgr( 506 reinterpret_cast< ::css::lang::XMultiServiceFactory * >( pServiceManager ) ); 507 ::css::uno::Reference< ::css::lang::XSingleComponentFactory > xFactory; 508 509 if (OTempFileService::getImplementationName_Static().compareToAscii( pImplName ) == 0) 510 xFactory = OTempFileService::createServiceFactory_Static ( xSMgr ); 511 512 if ( xFactory.is() ) 513 { 514 xFactory->acquire(); 515 pRet = xFactory.get(); 516 } 517 return pRet; 518 } 519