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 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_comphelper.hxx"
26 #include <osl/diagnose.h>
27 #include <com/sun/star/beans/PropertyAttribute.hpp>
28 #include <com/sun/star/io/XAsyncOutputMonitor.hpp>
29 #include <com/sun/star/embed/UseBackupException.hpp>
30 
31 #include <comphelper/otransactedfilestream.hxx>
32 #include <comphelper/storagehelper.hxx>
33 #include <cppuhelper/implbase1.hxx>
34 
35 using namespace ::com::sun::star;
36 
37 namespace comphelper
38 {
39 
40 // ========================================================================
41 class OTransactionHelper : public ::cppu::WeakImplHelper1 < embed::XTransactedObject >
42 {
43 	OTruncatedTransactedFileStream* m_pFileStream;
44 	uno::Reference< io::XStream > m_xStreamHolder;
45 
46 public:
OTransactionHelper(OTruncatedTransactedFileStream * pStream)47 	OTransactionHelper( OTruncatedTransactedFileStream* pStream )
48 	: m_pFileStream( pStream )
49 	{
50 		m_xStreamHolder = static_cast< io::XStream* >( pStream );
51 		if ( !m_xStreamHolder.is() )
52 			throw uno::RuntimeException();
53 	}
54 
55 	virtual void SAL_CALL commit(  ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException);
56 	virtual void SAL_CALL revert(  ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException);
57 };
58 
59 // ------------------------------------------------------------------------
commit()60 void SAL_CALL OTransactionHelper::commit(  ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException)
61 {
62 	m_pFileStream->Commit_Impl();
63 }
64 
65 // ------------------------------------------------------------------------
revert()66 void SAL_CALL OTransactionHelper::revert(  ) throw (io::IOException, lang::WrappedTargetException, uno::RuntimeException)
67 {
68 	m_pFileStream->Revert_Impl();
69 }
70 
71 // ========================================================================
72 struct TTFileStreamData_Impl
73 {
74 	uno::Reference< ucb::XSimpleFileAccess > m_xFileAccess;
75 	sal_Bool m_bDelete;
76 	::rtl::OUString m_aURL;
77 
78 	// the streams below are not visible from outside so there is no need to remember position
79 
80 	// original stream related members
81 	uno::Reference< io::XStream > m_xOrigStream;
82 	uno::Reference< io::XTruncate > m_xOrigTruncate;
83 	uno::Reference< io::XSeekable > m_xOrigSeekable;
84 	uno::Reference< io::XInputStream > m_xOrigInStream;
85 	uno::Reference< io::XOutputStream > m_xOrigOutStream;
86 
87 	// temporary stream related members
88 	uno::Reference< io::XStream > m_xTempStream;
89 	uno::Reference< io::XTruncate > m_xTempTruncate;
90 	uno::Reference< io::XSeekable > m_xTempSeekable;
91 	uno::Reference< io::XInputStream > m_xTempInStream;
92 	uno::Reference< io::XOutputStream > m_xTempOutStream;
93 
94 	sal_Bool m_bInOpen;
95 	sal_Bool m_bOutOpen;
96 
97 	sal_Bool m_bTransacted;
98 
99 
TTFileStreamData_Implcomphelper::TTFileStreamData_Impl100 	TTFileStreamData_Impl(
101 			const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess,
102 			sal_Bool bDelete,
103 			const ::rtl::OUString& aURL,
104 			const uno::Reference< io::XStream >& xOrigStream,
105 			const uno::Reference< io::XTruncate >& xOrigTruncate,
106 			const uno::Reference< io::XSeekable >& xOrigSeekable,
107 			const uno::Reference< io::XInputStream >& xOrigInStream,
108 			const uno::Reference< io::XOutputStream >& xOrigOutStream,
109 			const uno::Reference< io::XStream >& xTempStream,
110 			const uno::Reference< io::XTruncate >& xTempTruncate,
111 			const uno::Reference< io::XSeekable >& xTempSeekable,
112 			const uno::Reference< io::XInputStream >& xTempInStream,
113 			const uno::Reference< io::XOutputStream >& xTempOutStream )
114 	: m_xFileAccess( xFileAccess )
115 	, m_bDelete( bDelete )
116 	, m_aURL( aURL )
117 	, m_xOrigStream( xOrigStream )
118 	, m_xOrigTruncate( xOrigTruncate )
119 	, m_xOrigSeekable( xOrigSeekable )
120 	, m_xOrigInStream( xOrigInStream )
121 	, m_xOrigOutStream( xOrigOutStream )
122 	, m_xTempStream( xTempStream )
123 	, m_xTempTruncate( xTempTruncate )
124 	, m_xTempSeekable( xTempSeekable )
125 	, m_xTempInStream( xTempInStream )
126 	, m_xTempOutStream( xTempOutStream )
127 	, m_bInOpen( sal_False )
128 	, m_bOutOpen( sal_False )
129 	, m_bTransacted( sal_True )
130 	{}
131 
NoTransactioncomphelper::TTFileStreamData_Impl132 	void NoTransaction()
133 	{
134 		m_bDelete = sal_False;
135 		m_bTransacted = sal_False;
136 		m_xTempStream = uno::Reference< io::XStream >();
137 		m_xTempTruncate = uno::Reference< io::XTruncate >();
138 		m_xTempSeekable = uno::Reference< io::XSeekable >();
139 		m_xTempInStream = uno::Reference< io::XInputStream >();
140 		m_xTempOutStream = uno::Reference< io::XOutputStream >();
141 	}
142 
FreeOriginalcomphelper::TTFileStreamData_Impl143 	void FreeOriginal()
144 	{
145 		m_bDelete = sal_False;
146 		m_bTransacted = sal_False;
147 
148 		m_xOrigStream = m_xTempStream;
149 		m_xTempStream = uno::Reference< io::XStream >();
150 
151 		m_xOrigTruncate = m_xTempTruncate;
152 		m_xTempTruncate = uno::Reference< io::XTruncate >();
153 
154 		m_xOrigSeekable = m_xTempSeekable;
155 		m_xTempSeekable = uno::Reference< io::XSeekable >();
156 
157 		m_xOrigInStream = m_xTempInStream;
158 		m_xTempInStream = uno::Reference< io::XInputStream >();
159 
160 		m_xOrigOutStream = m_xTempOutStream;
161 		m_xTempOutStream = uno::Reference< io::XOutputStream >();
162 	}
163 };
164 
165 // ========================================================================
166 // ------------------------------------------------------------------------
OTruncatedTransactedFileStream(const::rtl::OUString & aURL,const uno::Reference<lang::XMultiServiceFactory> & xFactory)167 OTruncatedTransactedFileStream::OTruncatedTransactedFileStream(
168 		const ::rtl::OUString& aURL,
169 		const uno::Reference< lang::XMultiServiceFactory >& xFactory )
170 : m_pStreamData( NULL )
171 {
172 	uno::Reference< ucb::XSimpleFileAccess > xSimpleFileAccess(
173 		xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.ucb.SimpleFileAccess" ) ) ),
174 		uno::UNO_QUERY_THROW );
175 
176 	CommonInit_Impl( aURL, xSimpleFileAccess, xFactory, sal_False );
177 }
178 
179 // ------------------------------------------------------------------------
OTruncatedTransactedFileStream(const::rtl::OUString & aURL,const uno::Reference<ucb::XSimpleFileAccess> & xFileAccess,const uno::Reference<lang::XMultiServiceFactory> & xFactory)180 OTruncatedTransactedFileStream::OTruncatedTransactedFileStream(
181 		const ::rtl::OUString& aURL,
182 		const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess,
183 		const uno::Reference< lang::XMultiServiceFactory >& xFactory )
184 : m_pStreamData( NULL )
185 {
186 	CommonInit_Impl( aURL, xFileAccess, xFactory, sal_False );
187 }
188 
189 // ------------------------------------------------------------------------
OTruncatedTransactedFileStream(const::rtl::OUString & aURL,const uno::Reference<ucb::XSimpleFileAccess> & xFileAccess,const uno::Reference<lang::XMultiServiceFactory> & xFactory,sal_Bool bDeleteIfNotCommited)190 OTruncatedTransactedFileStream::OTruncatedTransactedFileStream(
191 		const ::rtl::OUString& aURL,
192 		const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess,
193 		const uno::Reference< lang::XMultiServiceFactory >& xFactory,
194 		sal_Bool bDeleteIfNotCommited )
195 : m_pStreamData( NULL )
196 {
197 	CommonInit_Impl( aURL, xFileAccess, xFactory, sal_True );
198 	if ( m_pStreamData )
199 		m_pStreamData->m_bDelete = bDeleteIfNotCommited;
200 }
201 
202 // ------------------------------------------------------------------------
~OTruncatedTransactedFileStream()203 OTruncatedTransactedFileStream::~OTruncatedTransactedFileStream()
204 {
205 	CloseAll_Impl();
206 }
207 
208 // ------------------------------------------------------------------------
CloseAll_Impl()209 void OTruncatedTransactedFileStream::CloseAll_Impl()
210 {
211 	::osl::MutexGuard aGuard( m_aMutex );
212 
213 	if ( m_pStreamData )
214 	{
215 		sal_Bool bDelete = m_pStreamData->m_bDelete;
216 		::rtl::OUString aURL = m_pStreamData->m_aURL;
217 		uno::Reference< ucb::XSimpleFileAccess > xFileAccess = m_pStreamData->m_xFileAccess;
218 
219 		delete m_pStreamData;
220 		m_pStreamData = NULL;
221 
222 		if ( bDelete && xFileAccess.is() && !aURL.isEmpty() )
223 		{
224 			// delete the file
225 			try
226 			{
227 				xFileAccess->kill( aURL );
228 			} catch( uno::Exception& )
229 			{
230 				OSL_ENSURE( sal_False, "Could not remove the file!" );
231 			}
232 		}
233 	}
234 }
235 
236 // ------------------------------------------------------------------------
CommonInit_Impl(const::rtl::OUString & aURL,const uno::Reference<ucb::XSimpleFileAccess> & xFileAccess,const uno::Reference<lang::XMultiServiceFactory> & xFactory,sal_Bool bDeleteOptionIsProvided)237 void OTruncatedTransactedFileStream::CommonInit_Impl(
238 		const ::rtl::OUString& aURL,
239 		const uno::Reference< ucb::XSimpleFileAccess >& xFileAccess,
240 		const uno::Reference< lang::XMultiServiceFactory >& xFactory,
241 		sal_Bool bDeleteOptionIsProvided )
242 {
243 	sal_Bool bDelete = sal_False;
244 	if ( !bDeleteOptionIsProvided )
245 		bDelete = !xFileAccess->exists( aURL );
246 
247 	uno::Reference< io::XStream > xOrigStream = xFileAccess->openFileReadWrite( aURL );
248 	uno::Reference< io::XTruncate > xOrigTruncate( xOrigStream, uno::UNO_QUERY_THROW );
249 	uno::Reference< io::XSeekable > xOrigSeekable( xOrigStream, uno::UNO_QUERY_THROW );
250 	uno::Reference< io::XInputStream > xOrigInStream = xOrigStream->getInputStream();
251 	uno::Reference< io::XOutputStream > xOrigOutStream = xOrigStream->getOutputStream();
252 	if ( !xOrigInStream.is() || !xOrigOutStream.is() )
253 		throw uno::RuntimeException();
254 
255 	// temporary stream related members
256 	uno::Reference< io::XStream > xTempStream( xFactory->createInstance(
257 		::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ),
258 		uno::UNO_QUERY_THROW );
259 	uno::Reference< io::XTruncate > xTempTruncate( xTempStream, uno::UNO_QUERY_THROW );
260 	uno::Reference< io::XSeekable > xTempSeekable( xTempStream, uno::UNO_QUERY_THROW );
261 	uno::Reference< io::XInputStream > xTempInStream = xTempStream->getInputStream();
262 	uno::Reference< io::XOutputStream > xTempOutStream = xTempStream->getOutputStream();
263 	if ( !xTempInStream.is() || !xTempOutStream.is() )
264 		throw uno::RuntimeException();
265 
266 	m_pStreamData = new TTFileStreamData_Impl( xFileAccess, bDelete, aURL,
267 											xOrigStream, xOrigTruncate, xOrigSeekable, xOrigInStream, xOrigOutStream,
268 											xTempStream, xTempTruncate, xTempSeekable, xTempInStream, xTempOutStream );
269 }
270 
271 // ------------------------------------------------------------------------
Commit_Impl()272 void OTruncatedTransactedFileStream::Commit_Impl()
273 {
274 	::osl::MutexGuard aGuard( m_aMutex );
275 
276 	if ( !m_pStreamData )
277 		throw io::NotConnectedException();
278 
279 	if ( m_pStreamData->m_bTransacted )
280 	{
281 		sal_Int64 nPos = m_pStreamData->m_xTempSeekable->getPosition();
282 		m_pStreamData->m_xTempSeekable->seek( 0 );
283 
284 		// after the following step fails the information might be lost, throw an exception with URL of temporary file
285 		try
286 		{
287 			m_pStreamData->m_xOrigTruncate->truncate();
288 			OStorageHelper::CopyInputToOutput( m_pStreamData->m_xTempInStream, m_pStreamData->m_xOrigOutStream );
289 			m_pStreamData->m_xOrigOutStream->flush();
290 
291 			// in case the stream is based on a file it will implement the following interface
292 			// the call should be used to be sure that the contents are written to the file system
293 			uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( m_pStreamData->m_xOrigOutStream, uno::UNO_QUERY );
294 			if ( asyncOutputMonitor.is() )
295 				asyncOutputMonitor->waitForCompletion();
296 		}
297 		catch( uno::Exception& )
298 		{
299 			::rtl::OUString aTempURL;
300 			try {
301 				uno::Reference< beans::XPropertySet > xTempFile( m_pStreamData->m_xTempStream, uno::UNO_QUERY_THROW );
302 				uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
303 				aUrl >>= aTempURL;
304 				xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
305 									 		uno::makeAny( sal_False ) );
306 
307 				m_pStreamData->m_xTempSeekable->seek( nPos );
308 			}
309 			catch( uno::Exception& )
310 			{
311 				OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
312 			}
313 
314 			m_pStreamData->FreeOriginal();
315 
316 			::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( "Writing file failed!" ) );
317 			embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
318 			throw lang::WrappedTargetException( aErrTxt,
319 												static_cast < OWeakObject * > ( this ),
320 												uno::makeAny ( aException ) );
321 		}
322 
323 		m_pStreamData->m_xOrigSeekable->seek( nPos );
324 		m_pStreamData->NoTransaction();
325 	}
326 	else
327 		throw io::NotConnectedException();
328 }
329 
330 // ------------------------------------------------------------------------
Revert_Impl()331 void OTruncatedTransactedFileStream::Revert_Impl()
332 {
333 	::osl::MutexGuard aGuard( m_aMutex );
334 
335 	if ( !m_pStreamData )
336 		throw io::NotConnectedException();
337 
338 	if ( m_pStreamData->m_bTransacted )
339 		m_pStreamData->m_xTempTruncate->truncate();
340 	else
341 		throw io::NotConnectedException();
342 }
343 
344 // com::sun::star::io::XStream
345 // ------------------------------------------------------------------------
getInputStream()346 uno::Reference< io::XInputStream > SAL_CALL OTruncatedTransactedFileStream::getInputStream(  )
347 	throw (uno::RuntimeException)
348 {
349 	::osl::MutexGuard aGuard( m_aMutex );
350 
351 	if ( m_pStreamData )
352 		m_pStreamData->m_bInOpen = sal_True;
353 	return static_cast< io::XInputStream* >( this );
354 }
355 
356 
357 // ------------------------------------------------------------------------
getOutputStream()358 uno::Reference< io::XOutputStream > SAL_CALL OTruncatedTransactedFileStream::getOutputStream(  )
359 	throw (uno::RuntimeException)
360 {
361 	::osl::MutexGuard aGuard( m_aMutex );
362 
363 	if ( m_pStreamData )
364 		m_pStreamData->m_bOutOpen = sal_True;
365 	return static_cast< io::XOutputStream* >( this );
366 }
367 
368 
369 
370 // com::sun::star::io::XInputStream
371 // ------------------------------------------------------------------------
readBytes(uno::Sequence<::sal_Int8> & aData,::sal_Int32 nBytesToRead)372 ::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::readBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nBytesToRead )
373 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
374 {
375 	::osl::MutexGuard aGuard( m_aMutex );
376 
377 	if ( !m_pStreamData )
378 		throw io::NotConnectedException();
379 
380 	if ( m_pStreamData->m_bTransacted )
381 	{
382 		// temporary stream data should be provided
383 		if ( !m_pStreamData->m_xTempInStream.is() )
384 			throw uno::RuntimeException();
385 
386 		return m_pStreamData->m_xTempInStream->readBytes( aData, nBytesToRead );
387 	}
388 	else
389 	{
390 		// the original stream data should be provided
391 		if ( !m_pStreamData->m_xOrigInStream.is() )
392 			throw uno::RuntimeException();
393 
394 		return m_pStreamData->m_xOrigInStream->readBytes( aData, nBytesToRead );
395 	}
396 }
397 
398 
399 // ------------------------------------------------------------------------
readSomeBytes(uno::Sequence<::sal_Int8> & aData,::sal_Int32 nMaxBytesToRead)400 ::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::readSomeBytes( uno::Sequence< ::sal_Int8 >& aData, ::sal_Int32 nMaxBytesToRead )
401 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
402 {
403 	::osl::MutexGuard aGuard( m_aMutex );
404 
405 	if ( !m_pStreamData )
406 		throw io::NotConnectedException();
407 
408 	if ( m_pStreamData->m_bTransacted )
409 	{
410 		// temporary stream data should be provided
411 		if ( !m_pStreamData->m_xTempInStream.is() )
412 			throw uno::RuntimeException();
413 
414 		return m_pStreamData->m_xTempInStream->readSomeBytes( aData, nMaxBytesToRead );
415 	}
416 	else
417 	{
418 		// the original stream data should be provided
419 		if ( !m_pStreamData->m_xOrigInStream.is() )
420 			throw uno::RuntimeException();
421 
422 		return m_pStreamData->m_xOrigInStream->readSomeBytes( aData, nMaxBytesToRead );
423 	}
424 }
425 
426 // ------------------------------------------------------------------------
skipBytes(::sal_Int32 nBytesToSkip)427 void SAL_CALL OTruncatedTransactedFileStream::skipBytes( ::sal_Int32 nBytesToSkip )
428 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
429 {
430 	::osl::MutexGuard aGuard( m_aMutex );
431 
432 	if ( !m_pStreamData )
433 		throw io::NotConnectedException();
434 
435 	if ( m_pStreamData->m_bTransacted )
436 	{
437 		// temporary stream data should be provided
438 		if ( !m_pStreamData->m_xTempInStream.is() )
439 			throw uno::RuntimeException();
440 
441 		m_pStreamData->m_xTempInStream->skipBytes( nBytesToSkip );
442 	}
443 	else
444 	{
445 		// the original stream data should be provided
446 		if ( !m_pStreamData->m_xOrigInStream.is() )
447 			throw uno::RuntimeException();
448 
449 		m_pStreamData->m_xOrigInStream->skipBytes( nBytesToSkip );
450 	}
451 }
452 
453 
454 // ------------------------------------------------------------------------
available()455 ::sal_Int32 SAL_CALL OTruncatedTransactedFileStream::available(  )
456 	throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
457 {
458 	::osl::MutexGuard aGuard( m_aMutex );
459 
460 	if ( !m_pStreamData )
461 		throw io::NotConnectedException();
462 
463 	if ( m_pStreamData->m_bTransacted )
464 	{
465 		// temporary stream data should be provided
466 		if ( !m_pStreamData->m_xTempInStream.is() )
467 			throw uno::RuntimeException();
468 
469 		return m_pStreamData->m_xTempInStream->available();
470 	}
471 	else
472 	{
473 		// the original stream data should be provided
474 		if ( !m_pStreamData->m_xOrigInStream.is() )
475 			throw uno::RuntimeException();
476 
477 		return m_pStreamData->m_xOrigInStream->available();
478 	}
479 }
480 
481 
482 // ------------------------------------------------------------------------
closeInput()483 void SAL_CALL OTruncatedTransactedFileStream::closeInput()
484 	throw (io::NotConnectedException, io::IOException, uno::RuntimeException)
485 {
486 	::osl::MutexGuard aGuard( m_aMutex );
487 
488 	if ( !m_pStreamData )
489 		throw io::NotConnectedException();
490 
491 	m_pStreamData->m_bInOpen = sal_False;
492 	if ( !m_pStreamData->m_bOutOpen )
493 		CloseAll_Impl();
494 }
495 
496 
497 
498 // com::sun::star::io::XOutputStream
499 // ------------------------------------------------------------------------
writeBytes(const uno::Sequence<::sal_Int8> & aData)500 void SAL_CALL OTruncatedTransactedFileStream::writeBytes( const uno::Sequence< ::sal_Int8 >& aData )
501 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
502 {
503 	::osl::MutexGuard aGuard( m_aMutex );
504 
505 	if ( !m_pStreamData )
506 		throw io::NotConnectedException();
507 
508 	if ( m_pStreamData->m_bTransacted )
509 	{
510 		// temporary stream data should be provided
511 		if ( !m_pStreamData->m_xTempOutStream.is() )
512 			throw uno::RuntimeException();
513 
514 		m_pStreamData->m_xTempOutStream->writeBytes( aData );
515 	}
516 	else
517 	{
518 		// the original stream data should be provided
519 		if ( !m_pStreamData->m_xOrigOutStream.is() )
520 			throw uno::RuntimeException();
521 
522 		m_pStreamData->m_xOrigOutStream->writeBytes( aData );
523 	}
524 }
525 
526 
527 // ------------------------------------------------------------------------
flush()528 void SAL_CALL OTruncatedTransactedFileStream::flush(  )
529 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
530 {
531 	::osl::MutexGuard aGuard( m_aMutex );
532 
533 	if ( !m_pStreamData )
534 	{
535 		OSL_ENSURE( sal_False, "flush() call on closed stream!\n" );
536 		return;
537 		// in future throw exception, for now some code might call flush() on closed stream
538 		// since file ucp implementation allows it
539 		// throw io::NotConnectedException();
540 	}
541 
542 	if ( m_pStreamData->m_bTransacted )
543 	{
544 		// temporary stream data should be provided
545 		if ( !m_pStreamData->m_xTempOutStream.is() )
546 			throw uno::RuntimeException();
547 
548 		m_pStreamData->m_xTempOutStream->flush();
549 	}
550 	else
551 	{
552 		// the original stream data should be provided
553 		if ( !m_pStreamData->m_xOrigOutStream.is() )
554 			throw uno::RuntimeException();
555 
556 		m_pStreamData->m_xOrigOutStream->flush();
557 	}
558 }
559 
560 
561 // ------------------------------------------------------------------------
closeOutput()562 void SAL_CALL OTruncatedTransactedFileStream::closeOutput(  )
563 	throw (io::NotConnectedException, io::BufferSizeExceededException, io::IOException, uno::RuntimeException)
564 {
565 	::osl::MutexGuard aGuard( m_aMutex );
566 
567 	if ( !m_pStreamData )
568 		throw io::NotConnectedException();
569 
570 	m_pStreamData->m_bOutOpen = sal_False;
571 	if ( !m_pStreamData->m_bInOpen )
572 		CloseAll_Impl();
573 }
574 
575 
576 
577 // com::sun::star::io::XTruncate
578 // ------------------------------------------------------------------------
truncate()579 void SAL_CALL OTruncatedTransactedFileStream::truncate(  )
580 	throw (io::IOException, uno::RuntimeException)
581 {
582 	::osl::MutexGuard aGuard( m_aMutex );
583 
584 	if ( !m_pStreamData )
585 		throw io::NotConnectedException();
586 
587 	if ( m_pStreamData->m_bTransacted )
588 	{
589 		// temporary stream data should be provided
590 		if ( !m_pStreamData->m_xTempTruncate.is() )
591 			throw uno::RuntimeException();
592 
593 		m_pStreamData->m_xTempTruncate->truncate();
594 	}
595 	else
596 	{
597 		// the original stream data should be provided
598 		if ( !m_pStreamData->m_xOrigTruncate.is() )
599 			throw uno::RuntimeException();
600 
601 		m_pStreamData->m_xOrigTruncate->truncate();
602 	}
603 }
604 
605 
606 
607 // com::sun::star::io::XSeekable
608 // ------------------------------------------------------------------------
seek(::sal_Int64 location)609 void SAL_CALL OTruncatedTransactedFileStream::seek( ::sal_Int64 location )
610 	throw (lang::IllegalArgumentException, io::IOException, uno::RuntimeException)
611 {
612 	::osl::MutexGuard aGuard( m_aMutex );
613 
614 	if ( !m_pStreamData )
615 		throw io::NotConnectedException();
616 
617 	if ( m_pStreamData->m_bTransacted )
618 	{
619 		// temporary stream data should be provided
620 		if ( !m_pStreamData->m_xTempSeekable.is() )
621 			throw uno::RuntimeException();
622 
623 		m_pStreamData->m_xTempSeekable->seek( location );
624 	}
625 	else
626 	{
627 		// the original stream data should be provided
628 		if ( !m_pStreamData->m_xOrigSeekable.is() )
629 			throw uno::RuntimeException();
630 
631 		m_pStreamData->m_xOrigSeekable->seek( location );
632 	}
633 }
634 
635 
636 // ------------------------------------------------------------------------
getPosition()637 ::sal_Int64 SAL_CALL OTruncatedTransactedFileStream::getPosition(  )
638 	throw (io::IOException, uno::RuntimeException)
639 {
640 	::osl::MutexGuard aGuard( m_aMutex );
641 
642 	if ( !m_pStreamData )
643 		throw io::NotConnectedException();
644 
645 	if ( m_pStreamData->m_bTransacted )
646 	{
647 		// temporary stream data should be provided
648 		if ( !m_pStreamData->m_xTempSeekable.is() )
649 			throw uno::RuntimeException();
650 
651 		return m_pStreamData->m_xTempSeekable->getPosition();
652 	}
653 	else
654 	{
655 		// the original stream data should be provided
656 		if ( !m_pStreamData->m_xOrigSeekable.is() )
657 			throw uno::RuntimeException();
658 
659 		return m_pStreamData->m_xOrigSeekable->getPosition();
660 	}
661 }
662 
663 
664 // ------------------------------------------------------------------------
getLength()665 ::sal_Int64 SAL_CALL OTruncatedTransactedFileStream::getLength(  )
666 	throw (io::IOException, uno::RuntimeException)
667 {
668 	::osl::MutexGuard aGuard( m_aMutex );
669 
670 	if ( !m_pStreamData )
671 		throw io::NotConnectedException();
672 
673 	if ( m_pStreamData->m_bTransacted )
674 	{
675 		// temporary stream data should be provided
676 		if ( !m_pStreamData->m_xTempSeekable.is() )
677 			throw uno::RuntimeException();
678 
679 		return m_pStreamData->m_xTempSeekable->getLength();
680 	}
681 	else
682 	{
683 		// the original stream data should be provided
684 		if ( !m_pStreamData->m_xOrigSeekable.is() )
685 			throw uno::RuntimeException();
686 
687 		return m_pStreamData->m_xOrigSeekable->getLength();
688 	}
689 }
690 
691 // com::sun::star::beans::XPropertySetInfo
692 // ------------------------------------------------------------------------
getProperties()693 uno::Sequence< beans::Property > SAL_CALL OTruncatedTransactedFileStream::getProperties()
694 	throw (uno::RuntimeException)
695 {
696 	::osl::MutexGuard aGuard( m_aMutex );
697 
698 	uno::Sequence< beans::Property > aProps( 1 );
699 	aProps[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
700 	aProps[0].Type = getCppuType( static_cast< uno::Reference< beans::XPropertySet >* >( NULL ) );
701 	aProps[0].Attributes = beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::READONLY;
702 
703 	return aProps;
704 }
705 
706 
707 // ------------------------------------------------------------------------
getPropertyByName(const::rtl::OUString & aName)708 beans::Property SAL_CALL OTruncatedTransactedFileStream::getPropertyByName( const ::rtl::OUString& aName )
709 	throw (beans::UnknownPropertyException, uno::RuntimeException)
710 {
711 	::osl::MutexGuard aGuard( m_aMutex );
712 
713 	::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
714 
715 	if ( !aName.equals( aTransactionPropName ) )
716 		throw beans::UnknownPropertyException();
717 
718 	beans::Property aProp;
719 	aProp.Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
720 	aProp.Type = getCppuType( static_cast< uno::Reference< beans::XPropertySet >* >( NULL ) );
721 	aProp.Attributes = beans::PropertyAttribute::TRANSIENT | beans::PropertyAttribute::READONLY;
722 
723 	return aProp;
724 }
725 
726 
727 // ------------------------------------------------------------------------
hasPropertyByName(const::rtl::OUString & Name)728 ::sal_Bool SAL_CALL OTruncatedTransactedFileStream::hasPropertyByName( const ::rtl::OUString& Name )
729 	throw (uno::RuntimeException)
730 {
731 	::osl::MutexGuard aGuard( m_aMutex );
732 
733 	::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
734 	return ( Name.equals( aTransactionPropName ) );
735 }
736 
737 
738 
739 // com::sun::star::beans::XPropertySet
740 // ------------------------------------------------------------------------
getPropertySetInfo()741 uno::Reference< beans::XPropertySetInfo > SAL_CALL OTruncatedTransactedFileStream::getPropertySetInfo()
742 	throw (uno::RuntimeException)
743 {
744 	::osl::MutexGuard aGuard( m_aMutex );
745 
746 	return static_cast< beans::XPropertySetInfo* >( this );
747 }
748 
749 
750 // ------------------------------------------------------------------------
setPropertyValue(const::rtl::OUString & aPropertyName,const uno::Any &)751 void SAL_CALL OTruncatedTransactedFileStream::setPropertyValue( const ::rtl::OUString& aPropertyName, const uno::Any& )
752 	throw (beans::UnknownPropertyException, beans::PropertyVetoException, lang::IllegalArgumentException, lang::WrappedTargetException, uno::RuntimeException)
753 {
754 	::osl::MutexGuard aGuard( m_aMutex );
755 
756 	::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
757 	if ( aPropertyName.equals( aTransactionPropName ) )
758 		throw beans::PropertyVetoException();
759 
760 	throw beans::UnknownPropertyException();
761 }
762 
763 
764 // ------------------------------------------------------------------------
getPropertyValue(const::rtl::OUString & PropertyName)765 uno::Any SAL_CALL OTruncatedTransactedFileStream::getPropertyValue( const ::rtl::OUString& PropertyName )
766 	throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
767 {
768 	::osl::MutexGuard aGuard( m_aMutex );
769 
770 	if ( !m_pStreamData )
771 		throw io::NotConnectedException();
772 
773 	::rtl::OUString aTransactionPropName( RTL_CONSTASCII_USTRINGPARAM( "TransactionSupport" ) );
774 	if ( PropertyName.equals( aTransactionPropName ) )
775 	{
776 		uno::Reference< embed::XTransactedObject > xObj;
777 		if ( m_pStreamData->m_bTransacted )
778 			xObj = static_cast< embed::XTransactedObject* >( new OTransactionHelper( this ) );
779 
780 		return uno::makeAny( xObj );
781 	}
782 
783 	throw beans::UnknownPropertyException();
784 }
785 
786 
787 // ------------------------------------------------------------------------
addPropertyChangeListener(const::rtl::OUString &,const uno::Reference<beans::XPropertyChangeListener> &)788 void SAL_CALL OTruncatedTransactedFileStream::addPropertyChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
789 	throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
790 {
791 	// not implemented
792 }
793 
794 
795 // ------------------------------------------------------------------------
removePropertyChangeListener(const::rtl::OUString &,const uno::Reference<beans::XPropertyChangeListener> &)796 void SAL_CALL OTruncatedTransactedFileStream::removePropertyChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
797 	throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
798 {
799 	// not implemented
800 }
801 
802 
803 // ------------------------------------------------------------------------
addVetoableChangeListener(const::rtl::OUString &,const uno::Reference<beans::XVetoableChangeListener> &)804 void SAL_CALL OTruncatedTransactedFileStream::addVetoableChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
805 	throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
806 {
807 	// not implemented
808 }
809 
810 
811 // ------------------------------------------------------------------------
removeVetoableChangeListener(const::rtl::OUString &,const uno::Reference<beans::XVetoableChangeListener> &)812 void SAL_CALL OTruncatedTransactedFileStream::removeVetoableChangeListener( const ::rtl::OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
813 	throw (beans::UnknownPropertyException, lang::WrappedTargetException, uno::RuntimeException)
814 {
815 	// not implemented
816 }
817 
818 
819 } // namespace comphelper
820