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