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