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