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