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