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