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