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