xref: /trunk/main/unotools/source/ucbhelper/xtempfile.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #include "precompiled_unotools.hxx"
28 #include <XTempFile.hxx>
29 #include <cppuhelper/factory.hxx>
30 #include <cppuhelper/typeprovider.hxx>
31 #include <unotools/tempfile.hxx>
32 #include <osl/file.hxx>
33 #include <unotools/configmgr.hxx>
34 #include <tools/urlobj.hxx>
35 #include <tools/debug.hxx>
36 
37 namespace css = com::sun::star;
38 
39 // copy define from desktop\source\app\appinit.cxx
40 
41 #define DESKTOP_TEMPNAMEBASE_DIR    "/temp/soffice.tmp"
42 
43 OTempFileService::OTempFileService(::css::uno::Reference< ::css::uno::XComponentContext > const & context)
44 : ::cppu::PropertySetMixin< ::css::io::XTempFile >(
45     context
46     , static_cast< Implements >( IMPLEMENTS_PROPERTY_SET | IMPLEMENTS_FAST_PROPERTY_SET | IMPLEMENTS_PROPERTY_ACCESS )
47     , com::sun::star::uno::Sequence< rtl::OUString >() )
48 , mpStream( NULL )
49 , mbRemoveFile( sal_True )
50 , mbInClosed( sal_False )
51 , mbOutClosed( sal_False )
52 , mnCachedPos( 0 )
53 , mbHasCachedPos( sal_False )
54 
55 {
56     mpTempFile = new ::utl::TempFile;
57     mpTempFile->EnableKillingFile ( sal_True );
58 }
59 
60 OTempFileService::~OTempFileService ()
61 {
62     if ( mpTempFile )
63         delete mpTempFile;
64 }
65 
66 
67 // XInterface
68 
69 ::css::uno::Any SAL_CALL OTempFileService::queryInterface( ::css::uno::Type const & aType )
70 throw ( ::css::uno::RuntimeException )
71 {
72     ::css::uno::Any aResult( OTempFileBase::queryInterface( aType ) );
73     if (!aResult.hasValue())
74         aResult = cppu::PropertySetMixin< ::css::io::XTempFile >::queryInterface( aType ) ;
75     return aResult;
76 };
77 void SAL_CALL OTempFileService::acquire(  )
78 throw ()
79 {
80     OTempFileBase::acquire();
81 }
82 void SAL_CALL OTempFileService::release(  )
83 throw ()
84 {
85     OTempFileBase::release();
86 }
87 
88 //  XTypeProvider
89 
90 ::css::uno::Sequence< ::css::uno::Type > SAL_CALL OTempFileService::getTypes(  )
91 throw ( ::css::uno::RuntimeException )
92 {
93     static ::cppu::OTypeCollection* pTypeCollection = NULL;
94     if ( pTypeCollection == NULL )
95     {
96         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ) ;
97 
98         if ( pTypeCollection == NULL )
99         {
100             static ::cppu::OTypeCollection aTypeCollection(
101                 ::getCppuType( ( const ::css::uno::Reference< ::css::beans::XPropertySet >*)NULL )
102                 ,OTempFileBase::getTypes() );
103             pTypeCollection = &aTypeCollection;
104         }
105     }
106     return pTypeCollection->getTypes();
107 };
108 ::css::uno::Sequence< sal_Int8 > SAL_CALL OTempFileService::getImplementationId(  )
109 throw ( ::css::uno::RuntimeException )
110 {
111     return OTempFileBase::getImplementationId();
112 }
113 
114 //  XTempFile
115 
116 sal_Bool SAL_CALL OTempFileService::getRemoveFile()
117 throw ( ::css::uno::RuntimeException )
118 {
119     ::osl::MutexGuard aGuard( maMutex );
120 
121     if ( !mpTempFile )
122     {
123         // the stream is already disconnected
124         throw ::css::uno::RuntimeException();
125         }
126 
127     return mbRemoveFile;
128 };
129 void SAL_CALL OTempFileService::setRemoveFile( sal_Bool _removefile )
130 throw ( ::css::uno::RuntimeException )
131 {
132     ::osl::MutexGuard aGuard( maMutex );
133 
134     if ( !mpTempFile )
135     {
136         // the stream is already disconnected
137         throw ::css::uno::RuntimeException();
138     }
139 
140     mbRemoveFile = _removefile;
141     mpTempFile->EnableKillingFile( mbRemoveFile );
142 };
143 ::rtl::OUString SAL_CALL OTempFileService::getUri()
144 throw ( ::css::uno::RuntimeException )
145 {
146     ::osl::MutexGuard aGuard( maMutex );
147 
148     if ( !mpTempFile )
149     {
150         throw ::css::uno::RuntimeException();
151     }
152 
153     return ::rtl::OUString( mpTempFile->GetURL() );
154 
155 };
156 ::rtl::OUString SAL_CALL OTempFileService::getResourceName()
157 throw ( ::css::uno::RuntimeException )
158 {
159     ::osl::MutexGuard aGuard( maMutex );
160 
161     if ( !mpTempFile )
162     {
163         throw ::css::uno::RuntimeException();
164 }
165 
166     return ::rtl::OUString( mpTempFile->GetFileName() );
167 };
168 
169 
170 
171 // XInputStream
172 
173 sal_Int32 SAL_CALL OTempFileService::readBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
174 throw (::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
175 {
176     ::osl::MutexGuard aGuard( maMutex );
177     if ( mbInClosed )
178         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
179 
180     checkConnected();
181     if (nBytesToRead < 0)
182         throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast< ::css::uno::XWeak * >(this));
183 
184     aData.realloc(nBytesToRead);
185 
186     sal_uInt32 nRead = mpStream->Read(static_cast < void* > ( aData.getArray() ), nBytesToRead);
187     checkError();
188 
189     if (nRead < static_cast < sal_uInt32 > ( nBytesToRead ) )
190         aData.realloc( nRead );
191 
192     if ( sal::static_int_cast<sal_uInt32>(nBytesToRead) > nRead )
193     {
194         // usually that means that the stream was read till the end
195         // 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? )
196         mnCachedPos = mpStream->Tell();
197         mbHasCachedPos = sal_True;
198 
199         mpStream = NULL;
200         if ( mpTempFile )
201             mpTempFile->CloseStream();
202     }
203 
204     return nRead;
205 }
206 sal_Int32 SAL_CALL OTempFileService::readSomeBytes( ::css::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
207 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
208 {
209     ::osl::MutexGuard aGuard( maMutex );
210     if ( mbInClosed )
211         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
212 
213     checkConnected();
214     checkError();
215 
216     if (nMaxBytesToRead < 0)
217         throw ::css::io::BufferSizeExceededException( ::rtl::OUString(), static_cast < ::css::uno::XWeak * >( this ) );
218 
219     if (mpStream->IsEof())
220     {
221         aData.realloc(0);
222         return 0;
223     }
224     else
225         return readBytes(aData, nMaxBytesToRead);
226 }
227 void SAL_CALL OTempFileService::skipBytes( sal_Int32 nBytesToSkip )
228 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
229 {
230     ::osl::MutexGuard aGuard( maMutex );
231     if ( mbInClosed )
232         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
233 
234     checkConnected();
235     checkError();
236     mpStream->SeekRel(nBytesToSkip);
237     checkError();
238 }
239 sal_Int32 SAL_CALL OTempFileService::available(  )
240 throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException )
241 {
242     ::osl::MutexGuard aGuard( maMutex );
243     if ( mbInClosed )
244         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
245 
246     checkConnected();
247 
248     sal_uInt32 nPos = mpStream->Tell();
249     checkError();
250 
251     mpStream->Seek(STREAM_SEEK_TO_END);
252     checkError();
253 
254     sal_Int32 nAvailable = (sal_Int32)mpStream->Tell() - nPos;
255     mpStream->Seek(nPos);
256     checkError();
257 
258     return nAvailable;
259 }
260 void SAL_CALL OTempFileService::closeInput(  )
261 throw ( ::css::io::NotConnectedException, ::css::io::IOException, ::css::uno::RuntimeException )
262 {
263     ::osl::MutexGuard aGuard( maMutex );
264     if ( mbInClosed )
265         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak  * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
266 
267     mbInClosed = sal_True;
268 
269     if ( mbOutClosed )
270     {
271         // stream will be deleted by TempFile implementation
272         mpStream = NULL;
273 
274         if ( mpTempFile )
275         {
276             delete mpTempFile;
277             mpTempFile = NULL;
278         }
279     }
280 }
281 
282 // XOutputStream
283 
284 void SAL_CALL OTempFileService::writeBytes( const ::css::uno::Sequence< sal_Int8 >& aData )
285 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
286 {
287     ::osl::MutexGuard aGuard( maMutex );
288     if ( mbOutClosed )
289         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
290 
291     checkConnected();
292     sal_uInt32 nWritten = mpStream->Write(aData.getConstArray(),aData.getLength());
293     checkError();
294     if  ( nWritten != (sal_uInt32)aData.getLength())
295         throw ::css::io::BufferSizeExceededException( ::rtl::OUString(),static_cast < ::css::uno::XWeak * > ( this ) );
296 }
297 void SAL_CALL OTempFileService::flush(  )
298 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
299 {
300     ::osl::MutexGuard aGuard( maMutex );
301     if ( mbOutClosed )
302         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
303 
304     checkConnected();
305     mpStream->Flush();
306     checkError();
307 }
308 void SAL_CALL OTempFileService::closeOutput(  )
309 throw ( ::css::io::NotConnectedException, ::css::io::BufferSizeExceededException, ::css::io::IOException, ::css::uno::RuntimeException )
310 {
311     ::osl::MutexGuard aGuard( maMutex );
312     if ( mbOutClosed )
313         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
314 
315     mbOutClosed = sal_True;
316 
317     // 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? )
318     if ( mpStream )
319     {
320         mnCachedPos = mpStream->Tell();
321         mbHasCachedPos = sal_True;
322 
323         mpStream = NULL;
324         if ( mpTempFile )
325             mpTempFile->CloseStream();
326     }
327 
328     if ( mbInClosed )
329     {
330         // stream will be deleted by TempFile implementation
331         mpStream = NULL;
332 
333         if ( mpTempFile )
334         {
335             delete mpTempFile;
336             mpTempFile = NULL;
337         }
338     }
339 }
340 
341 
342 void OTempFileService::checkError () const
343 {
344     if (!mpStream || mpStream->SvStream::GetError () != ERRCODE_NONE )
345         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
346 }
347 void OTempFileService::checkConnected ()
348 {
349     if (!mpStream && mpTempFile)
350     {
351         mpStream = mpTempFile->GetStream( STREAM_STD_READWRITE );
352         if ( mpStream && mbHasCachedPos )
353         {
354             mpStream->Seek( sal::static_int_cast<sal_Size>(mnCachedPos) );
355             if ( mpStream->SvStream::GetError () == ERRCODE_NONE )
356             {
357                 mbHasCachedPos = sal_False;
358                 mnCachedPos = 0;
359             }
360             else
361             {
362                 mpStream = NULL;
363                 mpTempFile->CloseStream();
364             }
365         }
366     }
367 
368     if (!mpStream)
369         throw ::css::io::NotConnectedException ( ::rtl::OUString(), const_cast < ::css::uno::XWeak * > ( static_cast < const ::css::uno::XWeak * > (this ) ) );
370 }
371 
372 // XSeekable
373 
374 void SAL_CALL OTempFileService::seek( sal_Int64 nLocation )
375 throw ( ::css::lang::IllegalArgumentException, ::css::io::IOException, ::css::uno::RuntimeException )
376 {
377     ::osl::MutexGuard aGuard( maMutex );
378     checkConnected();
379     if ( nLocation < 0 || nLocation > getLength() )
380         throw ::css::lang::IllegalArgumentException();
381 
382     mpStream->Seek((sal_uInt32) nLocation );
383     checkError();
384 }
385 sal_Int64 SAL_CALL OTempFileService::getPosition(  )
386 throw ( ::css::io::IOException, ::css::uno::RuntimeException )
387 {
388     ::osl::MutexGuard aGuard( maMutex );
389     checkConnected();
390 
391     sal_uInt32 nPos = mpStream->Tell();
392     checkError();
393     return (sal_Int64)nPos;
394 }
395 sal_Int64 SAL_CALL OTempFileService::getLength(  )
396 throw ( ::css::io::IOException, ::css::uno::RuntimeException )
397 {
398     ::osl::MutexGuard aGuard( maMutex );
399     checkConnected();
400 
401     sal_uInt32 nCurrentPos = mpStream->Tell();
402     checkError();
403 
404     mpStream->Seek(STREAM_SEEK_TO_END);
405     sal_uInt32 nEndPos = mpStream->Tell();
406     mpStream->Seek(nCurrentPos);
407 
408     checkError();
409 
410     return (sal_Int64)nEndPos;
411 }
412 
413 
414 // XStream
415 
416 ::css::uno::Reference< ::css::io::XInputStream > SAL_CALL OTempFileService::getInputStream()
417 throw ( ::css::uno::RuntimeException )
418     {
419     return ::css::uno::Reference< ::css::io::XInputStream >( *this, ::css::uno::UNO_QUERY );
420 }
421 
422 ::css::uno::Reference< ::css::io::XOutputStream > SAL_CALL OTempFileService::getOutputStream()
423 throw ( ::css::uno::RuntimeException )
424     {
425     return ::css::uno::Reference< ::css::io::XOutputStream >( *this, ::css::uno::UNO_QUERY );
426     }
427 
428 // XTruncate
429 
430 void SAL_CALL OTempFileService::truncate()
431 throw ( ::css::io::IOException, ::css::uno::RuntimeException )
432 {
433     ::osl::MutexGuard aGuard( maMutex );
434     checkConnected();
435     // SetStreamSize() call does not change the position
436     mpStream->Seek( 0 );
437     mpStream->SetStreamSize( 0 );
438     checkError();
439 }
440 
441 // XServiceInfo
442 
443 ::rtl::OUString SAL_CALL OTempFileService::getImplementationName()
444 throw ( ::css::uno::RuntimeException )
445 {
446     return getImplementationName_Static();
447 }
448 
449 sal_Bool SAL_CALL OTempFileService::supportsService( ::rtl::OUString const & rServiceName )
450 throw ( ::css::uno::RuntimeException )
451 {
452     ::css::uno::Sequence< ::rtl::OUString > aServices(getSupportedServiceNames_Static());
453     return rServiceName == aServices[0];
454 }
455 
456 ::css::uno::Sequence < ::rtl::OUString > SAL_CALL OTempFileService::getSupportedServiceNames()
457 throw ( ::css::uno::RuntimeException )
458 {
459     return getSupportedServiceNames_Static();
460 }
461 
462 
463 
464 ::rtl::OUString OTempFileService::getImplementationName_Static ()
465 {
466     return ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.comp.TempFile" ) );
467 }
468 ::css::uno::Sequence < ::rtl::OUString > OTempFileService::getSupportedServiceNames_Static()
469 {
470     ::css::uno::Sequence < ::rtl::OUString > aNames ( 1 );
471     aNames[0] = ::rtl::OUString ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
472     return aNames;
473 }
474 ::css::uno::Reference < ::css::uno::XInterface >SAL_CALL XTempFile_createInstance(
475     css::uno::Reference< ::css::uno::XComponentContext > const & context)
476     SAL_THROW( ( css::uno::Exception ) )
477 {
478     return static_cast< ::cppu::OWeakObject * >( new OTempFileService(context) );
479 }
480 
481 ::css::uno::Reference < ::css::lang::XSingleComponentFactory > OTempFileService::createServiceFactory_Static( ::css::uno::Reference < ::css::lang::XMultiServiceFactory > const & )
482 {
483     return ::cppu::createSingleComponentFactory( XTempFile_createInstance, getImplementationName_Static(), getSupportedServiceNames_Static() );
484 }
485 
486 // C functions to implement this as a component
487 
488 extern "C" SAL_DLLPUBLIC_EXPORT void SAL_CALL component_getImplementationEnvironment(
489                 const sal_Char ** ppEnvTypeName, uno_Environment ** /*ppEnv*/ )
490 {
491     *ppEnvTypeName = CPPU_CURRENT_LANGUAGE_BINDING_NAME;
492 }
493 
494 /**
495  * This function is called to get service factories for an implementation.
496  * @param pImplName name of implementation
497  * @param pServiceManager generic uno interface providing a service manager to instantiate components
498  * @param pRegistryKey registry data key to read and write component persistent data
499  * @return a component factory (generic uno interface)
500  */
501 extern "C" SAL_DLLPUBLIC_EXPORT void * SAL_CALL component_getFactory(
502     const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
503 {
504     void * pRet = 0;
505     ::css::uno::Reference< ::css::lang::XMultiServiceFactory > xSMgr(
506         reinterpret_cast< ::css::lang::XMultiServiceFactory * >( pServiceManager ) );
507     ::css::uno::Reference< ::css::lang::XSingleComponentFactory > xFactory;
508 
509     if (OTempFileService::getImplementationName_Static().compareToAscii( pImplName ) == 0)
510         xFactory = OTempFileService::createServiceFactory_Static ( xSMgr );
511 
512     if ( xFactory.is() )
513     {
514         xFactory->acquire();
515         pRet = xFactory.get();
516     }
517     return pRet;
518 }
519