xref: /trunk/main/unotools/source/ucbhelper/xtempfile.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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 {
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 {
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 };
getImplementationId()103 ::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId(  )
104 {
105     return OTempFileBase::getImplementationId();
106 }
107 
108 //  XTempFile
109 
getRemoveFile()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 };
setRemoveFile(sal_Bool _removefile)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 };
getUri()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 };
getResourceName()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 
readBytes(::css::uno::Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)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 }
readSomeBytes(::css::uno::Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)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 }
skipBytes(sal_Int32 nBytesToSkip)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 }
available()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 }
closeInput()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 
writeBytes(const::css::uno::Sequence<sal_Int8> & aData)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 }
flush()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 }
closeOutput()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 
checkError() const324 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 }
checkConnected()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 
seek(sal_Int64 nLocation)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 }
getPosition()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 }
getLength()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 
getInputStream()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 
getOutputStream()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 
truncate()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 
getImplementationName()419 ::rtl::OUString SAL_CALL OTempFileService::getImplementationName()
420 {
421     return getImplementationName_Static();
422 }
423 
supportsService(::rtl::OUString const & rServiceName)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 
getSupportedServiceNames()430 ::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames()
431 {
432     return getSupportedServiceNames_Static();
433 }
434 
435 
436 
getImplementationName_Static()437 ::rtl::OUString OTempFileService::getImplementationName_Static ()
438 {
439     return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) );
440 }
getSupportedServiceNames_Static()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 }
XTempFile_createInstance(css::uno::Reference<::css::uno::XComponentContext> const & context)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 
component_getImplementationEnvironment(const sal_Char ** ppEnvTypeName,uno_Environment **)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  */
component_getFactory(const sal_Char * pImplName,void * pServiceManager,void * pRegistryKey)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