xref: /AOO41X/main/unotools/source/ucbhelper/xtempfile.cxx (revision b5088357f810cb81479bbbd0e021cd3c9835ca0d)
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 
OTempFileService(::css::uno::Reference<::css::uno::XComponentContext> const & context)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 
~OTempFileService()56 OTempFileService::~OTempFileService ()
57 {
58     if ( mpTempFile )
59         delete mpTempFile;
60 }
61 
62 
63 // XInterface
64 
queryInterface(::css::uno::Type const & aType)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 };
acquire()73 void SAL_CALL OTempFileService::acquire(  )
74 throw ()
75 {
76     OTempFileBase::acquire();
77 }
release()78 void SAL_CALL OTempFileService::release(  )
79 throw ()
80 {
81     OTempFileBase::release();
82 }
83 
84 //  XTypeProvider
85 
getTypes()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 };
getImplementationId()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 
getRemoveFile()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 };
setRemoveFile(sal_Bool _removefile)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 };
getUri()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 };
getResourceName()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 
readBytes(::css::uno::Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)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 }
readSomeBytes(::css::uno::Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)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 }
skipBytes(sal_Int32 nBytesToSkip)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 }
available()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 }
closeInput()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 
writeBytes(const::css::uno::Sequence<sal_Int8> & aData)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 }
flush()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 }
closeOutput()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 
checkError() const338 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 }
checkConnected()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 
seek(sal_Int64 nLocation)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 }
getPosition()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 }
getLength()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 
getInputStream()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 
getOutputStream()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 
truncate()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 
getImplementationName()439 ::rtl::OUString SAL_CALL OTempFileService::getImplementationName()
440 throw ( ::css::uno::RuntimeException )
441 {
442     return getImplementationName_Static();
443 }
444 
supportsService(::rtl::OUString const & rServiceName)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 
getSupportedServiceNames()452 ::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames()
453 throw ( ::css::uno::RuntimeException )
454 {
455     return getSupportedServiceNames_Static();
456 }
457 
458 
459 
getImplementationName_Static()460 ::rtl::OUString OTempFileService::getImplementationName_Static ()
461 {
462     return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) );
463 }
getSupportedServiceNames_Static()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 }
XTempFile_createInstance(css::uno::Reference<::css::uno::XComponentContext> const & context)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 
createServiceFactory_Static(::css::uno::Reference<::css::lang::XMultiServiceFactory> const &)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 
component_getImplementationEnvironment(const sal_Char ** ppEnvTypeName,uno_Environment **)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  */
component_getFactory(const sal_Char * pImplName,void * pServiceManager,void *)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