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