| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| #include "precompiled_unotools.hxx" |
| #include <XTempFile.hxx> |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/typeprovider.hxx> |
| #include <unotools/tempfile.hxx> |
| #include <osl/file.hxx> |
| #include <unotools/configmgr.hxx> |
| #include <tools/urlobj.hxx> |
| #include <tools/debug.hxx> |
| |
| namespace css = com::sun::star; |
| |
| // copy define from desktop\source\app\appinit.cxx |
| |
| #define DESKTOP_TEMPNAMEBASE_DIR "/temp/soffice.tmp" |
| |
| OTempFileService::OTempFileService(::css::uno::Reference< ::css::uno::XComponentContext > const & context) |
| : ::cppu::PropertySetMixin< ::css::io::XTempFile >( |
| context |
| , static_cast< Implements >( IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET | IMPLEMENTS_PROPERTY_ACCESS ) |
| , com::sun::star::uno::Sequence< rtl::OUString >() ) |
| , mpStream( NULL ) |
| , mbRemoveFile( sal_True ) |
| , mbInClosed( sal_False ) |
| , mbOutClosed( sal_False ) |
| , mnCachedPos( 0 ) |
| , mbHasCachedPos( sal_False ) |
| |
| { |
| mpTempFile = new ::utl::TempFile; |
| mpTempFile->EnableKillingFile ( sal_True ); |
| } |
| |
| OTempFileService::~OTempFileService () |
| { |
| if ( mpTempFile ) |
| delete mpTempFile; |
| } |
| |
| |
| // XInterface |
| |
| ::css::uno::Any SAL_CALL OTempFileService::queryInterface( ::css::uno::Type const & aType ) |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::css::uno::Any aResult( OTempFileBase::queryInterface( aType ) ); |
| if (!aResult.hasValue()) |
| aResult = cppu::PropertySetMixin< ::css::io::XTempFile >::queryInterface( aType ) ; |
| return aResult; |
| }; |
| void SAL_CALL OTempFileService::acquire( ) |
| throw () |
| { |
| OTempFileBase::acquire(); |
| } |
| void SAL_CALL OTempFileService::release( ) |
| throw () |
| { |
| OTempFileBase::release(); |
| } |
| |
| // XTypeProvider |
| |
| ::css::uno::Sequence< ::css::uno::Type > SAL_CALL OTempFileService::getTypes( ) |
| throw ( ::css::uno::RuntimeException ) |
| { |
| static ::cppu::OTypeCollection* pTypeCollection = NULL; |
| if ( pTypeCollection == NULL ) |
| { |
| ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ; |
| |
| if ( pTypeCollection == NULL ) |
| { |
| static ::cppu::OTypeCollection aTypeCollection( |
| ::getCppuType( ( const ::css::uno::Reference< ::css::beans::XPropertySet >*)NULL ) |
| ,OTempFileBase::getTypes() ); |
| pTypeCollection = &aTypeCollection; |
| } |
| } |
| return pTypeCollection->getTypes(); |
| }; |
| ::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId( ) |
| throw ( ::css::uno::RuntimeException ) |
| { |
| return OTempFileBase::getImplementationId(); |
| } |
| |
| // XTempFile |
| |
| sal_Bool SAL_CALL OTempFileService::getRemoveFile() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| |
| if ( !mpTempFile ) |
| { |
| // the stream is already disconnected |
| throw ::css::uno::RuntimeException(); |
| } |
| |
| return mbRemoveFile; |
| }; |
| void SAL_CALL OTempFileService::setRemoveFile( sal_Bool _removefile ) |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| |
| if ( !mpTempFile ) |
| { |
| // the stream is already disconnected |
| throw ::css::uno::RuntimeException(); |
| } |
| |
| mbRemoveFile = _removefile; |
| mpTempFile->EnableKillingFile( mbRemoveFile ); |
| }; |
| ::rtl::OUString SAL_CALL OTempFileService::getUri() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| |
| if ( !mpTempFile ) |
| { |
| throw ::css::uno::RuntimeException(); |
| } |
| |
| return ::rtl::OUString( mpTempFile->GetURL() ); |
| |
| }; |
| ::rtl::OUString SAL_CALL OTempFileService::getResourceName() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| |
| if ( !mpTempFile ) |
| { |
| throw ::css::uno::RuntimeException(); |
| } |
| |
| return ::rtl::OUString( mpTempFile->GetFileName() ); |
| }; |
| |
| |
| |
| // XInputStream |
| |
| sal_Int32 SAL_CALL OTempFileService::readBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) |
| throw (::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbInClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| if (nBytesToRead < 0) |
| throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this)); |
| |
| aData.realloc(nBytesToRead); |
| |
| sal_uInt32 nRead = mpStream->Read(static_cast < void* > ( aData.getArray() ), nBytesToRead); |
| checkError(); |
| |
| if (nRead < static_cast < sal_uInt32 > ( nBytesToRead ) ) |
| aData.realloc( nRead ); |
| |
| if ( sal::static_int_cast<sal_uInt32>(nBytesToRead) > nRead ) |
| { |
| // usually that means that the stream was read till the end |
| // 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? ) |
| mnCachedPos = mpStream->Tell(); |
| mbHasCachedPos = sal_True; |
| |
| mpStream = NULL; |
| if ( mpTempFile ) |
| mpTempFile->CloseStream(); |
| } |
| |
| return nRead; |
| } |
| sal_Int32 SAL_CALL OTempFileService::readSomeBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) |
| throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbInClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| checkError(); |
| |
| if (nMaxBytesToRead < 0) |
| throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast < ::css::uno::XWeak * >( this ) ); |
| |
| if (mpStream->IsEof()) |
| { |
| aData.realloc(0); |
| return 0; |
| } |
| else |
| return readBytes(aData, nMaxBytesToRead); |
| } |
| void SAL_CALL OTempFileService::skipBytes( sal_Int32 nBytesToSkip ) |
| throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbInClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| checkError(); |
| mpStream->SeekRel(nBytesToSkip); |
| checkError(); |
| } |
| sal_Int32 SAL_CALL OTempFileService::available( ) |
| throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbInClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| |
| sal_uInt32 nPos = mpStream->Tell(); |
| checkError(); |
| |
| mpStream->Seek(STREAM_SEEK_TO_END); |
| checkError(); |
| |
| sal_Int32 nAvailable = (sal_Int32)mpStream->Tell() - nPos; |
| mpStream->Seek(nPos); |
| checkError(); |
| |
| return nAvailable; |
| } |
| void SAL_CALL OTempFileService::closeInput( ) |
| throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbInClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| mbInClosed = sal_True; |
| |
| if ( mbOutClosed ) |
| { |
| // stream will be deleted by TempFile implementation |
| mpStream = NULL; |
| |
| if ( mpTempFile ) |
| { |
| delete mpTempFile; |
| mpTempFile = NULL; |
| } |
| } |
| } |
| |
| // XOutputStream |
| |
| void SAL_CALL OTempFileService::writeBytes( const ::css::uno::Sequence< sal_Int8 >& aData ) |
| throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbOutClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| sal_uInt32 nWritten = mpStream->Write(aData.getConstArray(),aData.getLength()); |
| checkError(); |
| if ( nWritten != (sal_uInt32)aData.getLength()) |
| throw ::css::io::BufferSizeExceededException( ::rtl::OUString(),static_cast < ::css::uno::XWeak * > ( this ) ); |
| } |
| void SAL_CALL OTempFileService::flush( ) |
| throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbOutClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| checkConnected(); |
| mpStream->Flush(); |
| checkError(); |
| } |
| void SAL_CALL OTempFileService::closeOutput( ) |
| throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| if ( mbOutClosed ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| |
| mbOutClosed = sal_True; |
| |
| // 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? ) |
| if ( mpStream ) |
| { |
| mnCachedPos = mpStream->Tell(); |
| mbHasCachedPos = sal_True; |
| |
| mpStream = NULL; |
| if ( mpTempFile ) |
| mpTempFile->CloseStream(); |
| } |
| |
| if ( mbInClosed ) |
| { |
| // stream will be deleted by TempFile implementation |
| mpStream = NULL; |
| |
| if ( mpTempFile ) |
| { |
| delete mpTempFile; |
| mpTempFile = NULL; |
| } |
| } |
| } |
| |
| |
| void OTempFileService::checkError () const |
| { |
| if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE ) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| } |
| void OTempFileService::checkConnected () |
| { |
| if (!mpStream && mpTempFile) |
| { |
| mpStream = mpTempFile->GetStream( STREAM_STD_READWRITE ); |
| if ( mpStream && mbHasCachedPos ) |
| { |
| mpStream->Seek( sal::static_int_cast<sal_Size>(mnCachedPos) ); |
| if ( mpStream->SvStream::GetError () == ERRCODE_NONE ) |
| { |
| mbHasCachedPos = sal_False; |
| mnCachedPos = 0; |
| } |
| else |
| { |
| mpStream = NULL; |
| mpTempFile->CloseStream(); |
| } |
| } |
| } |
| |
| if (!mpStream) |
| throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) ); |
| } |
| |
| // XSeekable |
| |
| void SAL_CALL OTempFileService::seek( sal_Int64 nLocation ) |
| throw ( ::css::lang::IllegalArgumentException, ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| checkConnected(); |
| if ( nLocation < 0 || nLocation > getLength() ) |
| throw ::css::lang::IllegalArgumentException(); |
| |
| mpStream->Seek((sal_uInt32) nLocation ); |
| checkError(); |
| } |
| sal_Int64 SAL_CALL OTempFileService::getPosition( ) |
| throw ( ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| checkConnected(); |
| |
| sal_uInt32 nPos = mpStream->Tell(); |
| checkError(); |
| return (sal_Int64)nPos; |
| } |
| sal_Int64 SAL_CALL OTempFileService::getLength( ) |
| throw ( ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| checkConnected(); |
| |
| sal_uInt32 nCurrentPos = mpStream->Tell(); |
| checkError(); |
| |
| mpStream->Seek(STREAM_SEEK_TO_END); |
| sal_uInt32 nEndPos = mpStream->Tell(); |
| mpStream->Seek(nCurrentPos); |
| |
| checkError(); |
| |
| return (sal_Int64)nEndPos; |
| } |
| |
| |
| // XStream |
| |
| ::css::uno::Reference< ::css::io::XInputStream > SAL_CALL OTempFileService::getInputStream() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| return ::css::uno::Reference< ::css::io::XInputStream >( *this, ::css::uno::UNO_QUERY ); |
| } |
| |
| ::css::uno::Reference< ::css::io::XOutputStream > SAL_CALL OTempFileService::getOutputStream() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| return ::css::uno::Reference< ::css::io::XOutputStream >( *this, ::css::uno::UNO_QUERY ); |
| } |
| |
| // XTruncate |
| |
| void SAL_CALL OTempFileService::truncate() |
| throw ( ::css::io::IOException, ::css::uno::RuntimeException ) |
| { |
| ::osl::MutexGuard aGuard( maMutex ); |
| checkConnected(); |
| // SetStreamSize() call does not change the position |
| mpStream->Seek( 0 ); |
| mpStream->SetStreamSize( 0 ); |
| checkError(); |
| } |
| |
| // XServiceInfo |
| |
| ::rtl::OUString SAL_CALL OTempFileService::getImplementationName() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| return getImplementationName_Static(); |
| } |
| |
| sal_Bool SAL_CALL OTempFileService::supportsService( ::rtl::OUString const & rServiceName ) |
| throw ( ::css::uno::RuntimeException ) |
| { |
| ::css::uno::Sequence< ::rtl::OUString > aServices(getSupportedServiceNames_Static()); |
| return rServiceName == aServices[0]; |
| } |
| |
| ::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames() |
| throw ( ::css::uno::RuntimeException ) |
| { |
| return getSupportedServiceNames_Static(); |
| } |
| |
| |
| |
| ::rtl::OUString OTempFileService::getImplementationName_Static () |
| { |
| return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) ); |
| } |
| ::css::uno::Sequence < ::rtl::OUString > OTempFileService::getSupportedServiceNames_Static() |
| { |
| ::css::uno::Sequence < ::rtl::OUString > aNames ( 1 ); |
| aNames[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); |
| return aNames; |
| } |
| ::css::uno::Reference < ::css::uno::XInterface >SAL_CALL XTempFile_createInstance( |
| css::uno::Reference< ::css::uno::XComponentContext > const & context) |
| SAL_THROW( ( css::uno::Exception ) ) |
| { |
| return static_cast< ::cppu::OWeakObject * >( new OTempFileService(context) ); |
| } |
| |
| ::css::uno::Reference < ::css::lang::XSingleComponentFactory > OTempFileService::createServiceFactory_Static( ::css::uno::Reference < ::css::lang::XMultiServiceFactory > const & ) |
| { |
| return ::cppu::createSingleComponentFactory( XTempFile_createInstance, getImplementationName_Static(), getSupportedServiceNames_Static() ); |
| } |
| |
| // C functions to implement this as a component |
| |
| extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment( |
| const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ ) |
| { |
| *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME; |
| } |
| |
| /** |
| * This function is called to get service factories for an implementation. |
| * @param pImplName name of implementation |
| * @param pServiceManager generic uno interface providing a service manager to instantiate components |
| * @param pRegistryKey registry data key to read and write component persistent data |
| * @return a component factory (generic uno interface) |
| */ |
| extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory( |
| const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ ) |
| { |
| void * pRet = 0; |
| ::css::uno::Reference< ::css::lang::XMultiServiceFactory > xSMgr( |
| reinterpret_cast< ::css::lang::XMultiServiceFactory * >( pServiceManager ) ); |
| ::css::uno::Reference< ::css::lang::XSingleComponentFactory > xFactory; |
| |
| if (OTempFileService::getImplementationName_Static().compareToAscii( pImplName ) == 0) |
| xFactory = OTempFileService::createServiceFactory_Static ( xSMgr ); |
| |
| if ( xFactory.is() ) |
| { |
| xFactory->acquire(); |
| pRet = xFactory.get(); |
| } |
| return pRet; |
| } |