1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_comphelper.hxx"
30 #include <com/sun/star/io/XOutputStream.hpp>
31 
32 
33 #include <comphelper/seekableinput.hxx>
34 
35 using namespace ::com::sun::star;
36 
37 namespace comphelper
38 {
39 
40 const sal_Int32 nConstBufferSize = 32000;
41 
42 //---------------------------------------------------------------------------
43 void copyInputToOutput_Impl( const uno::Reference< io::XInputStream >& xIn,
44 							const uno::Reference< io::XOutputStream >& xOut )
45 {
46 	sal_Int32 nRead;
47 	uno::Sequence< sal_Int8 > aSequence( nConstBufferSize );
48 
49 	do
50 	{
51 		nRead = xIn->readBytes( aSequence, nConstBufferSize );
52 		if ( nRead < nConstBufferSize )
53 		{
54 			uno::Sequence< sal_Int8 > aTempBuf( aSequence.getConstArray(), nRead );
55 			xOut->writeBytes( aTempBuf );
56 		}
57 		else
58 			xOut->writeBytes( aSequence );
59 	}
60 	while ( nRead == nConstBufferSize );
61 }
62 
63 //---------------------------------------------------------------------------
64 OSeekableInputWrapper::OSeekableInputWrapper(
65 			const uno::Reference< io::XInputStream >& xInStream,
66 			const uno::Reference< lang::XMultiServiceFactory >& xFactory )
67 : m_xFactory( xFactory )
68 , m_xOriginalStream( xInStream )
69 {
70 	if ( !m_xFactory.is() )
71 		throw uno::RuntimeException();
72 }
73 
74 //---------------------------------------------------------------------------
75 OSeekableInputWrapper::~OSeekableInputWrapper()
76 {
77 }
78 
79 //---------------------------------------------------------------------------
80 uno::Reference< io::XInputStream > OSeekableInputWrapper::CheckSeekableCanWrap(
81 							const uno::Reference< io::XInputStream >& xInStream,
82 							const uno::Reference< lang::XMultiServiceFactory >& xFactory )
83 {
84 	// check that the stream is seekable and just wrap it if it is not
85 	uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
86 	if ( xSeek.is() )
87 		return xInStream;
88 
89 	uno::Reference< io::XInputStream > xNewStream(
90 			static_cast< io::XInputStream* >(
91 				new OSeekableInputWrapper( xInStream, xFactory ) ) );
92     return xNewStream;
93 }
94 
95 //---------------------------------------------------------------------------
96 void OSeekableInputWrapper::PrepareCopy_Impl()
97 {
98 	if ( !m_xCopyInput.is() )
99 	{
100 		if ( !m_xFactory.is() )
101 			throw uno::RuntimeException();
102 
103 		uno::Reference< io::XOutputStream > xTempOut(
104 				m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
105 				uno::UNO_QUERY );
106 
107 		if ( xTempOut.is() )
108 		{
109 			copyInputToOutput_Impl( m_xOriginalStream, xTempOut );
110 			xTempOut->closeOutput();
111 
112 			uno::Reference< io::XSeekable > xTempSeek( xTempOut, uno::UNO_QUERY );
113 			if ( xTempSeek.is() )
114 			{
115 				xTempSeek->seek( 0 );
116 				m_xCopyInput = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY );
117 				if ( m_xCopyInput.is() )
118 					m_xCopySeek = xTempSeek;
119 			}
120 		}
121 	}
122 
123 	if ( !m_xCopyInput.is() )
124 		throw io::IOException();
125 }
126 
127 // XInputStream
128 //---------------------------------------------------------------------------
129 sal_Int32 SAL_CALL OSeekableInputWrapper::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
130 	throw ( io::NotConnectedException,
131 			io::BufferSizeExceededException,
132 			io::IOException,
133 			uno::RuntimeException )
134 {
135 	::osl::MutexGuard aGuard( m_aMutex );
136 
137 	if ( !m_xOriginalStream.is() )
138 		throw io::NotConnectedException();
139 
140 	PrepareCopy_Impl();
141 
142 	return m_xCopyInput->readBytes( aData, nBytesToRead );
143 }
144 
145 //---------------------------------------------------------------------------
146 sal_Int32 SAL_CALL OSeekableInputWrapper::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
147 	throw ( io::NotConnectedException,
148 			io::BufferSizeExceededException,
149 			io::IOException,
150 			uno::RuntimeException )
151 {
152 	::osl::MutexGuard aGuard( m_aMutex );
153 
154 	if ( !m_xOriginalStream.is() )
155 		throw io::NotConnectedException();
156 
157 	PrepareCopy_Impl();
158 
159 	return m_xCopyInput->readSomeBytes( aData, nMaxBytesToRead );
160 }
161 
162 //---------------------------------------------------------------------------
163 void SAL_CALL OSeekableInputWrapper::skipBytes( sal_Int32 nBytesToSkip )
164 	throw ( io::NotConnectedException,
165 			io::BufferSizeExceededException,
166 			io::IOException,
167 			uno::RuntimeException )
168 {
169 	::osl::MutexGuard aGuard( m_aMutex );
170 
171 	if ( !m_xOriginalStream.is() )
172 		throw io::NotConnectedException();
173 
174 	PrepareCopy_Impl();
175 
176 	m_xCopyInput->skipBytes( nBytesToSkip );
177 }
178 
179 //---------------------------------------------------------------------------
180 sal_Int32 SAL_CALL OSeekableInputWrapper::available()
181 	throw ( io::NotConnectedException,
182 			io::IOException,
183 			uno::RuntimeException )
184 {
185 	::osl::MutexGuard aGuard( m_aMutex );
186 
187 	if ( !m_xOriginalStream.is() )
188 		throw io::NotConnectedException();
189 
190 	PrepareCopy_Impl();
191 
192 	return m_xCopyInput->available();
193 }
194 
195 //---------------------------------------------------------------------------
196 void SAL_CALL OSeekableInputWrapper::closeInput()
197 	throw ( io::NotConnectedException,
198 			io::IOException,
199 			uno::RuntimeException )
200 {
201 	::osl::MutexGuard aGuard( m_aMutex );
202 
203 	if ( !m_xOriginalStream.is() )
204 		throw io::NotConnectedException();
205 
206 	m_xOriginalStream->closeInput();
207 	m_xOriginalStream = uno::Reference< io::XInputStream >();
208 
209 	if ( m_xCopyInput.is() )
210 	{
211 		m_xCopyInput->closeInput();
212 		m_xCopyInput = uno::Reference< io::XInputStream >();
213 	}
214 
215 	m_xCopySeek = uno::Reference< io::XSeekable >();
216 }
217 
218 
219 // XSeekable
220 //---------------------------------------------------------------------------
221 void SAL_CALL OSeekableInputWrapper::seek( sal_Int64 location )
222 	throw ( lang::IllegalArgumentException,
223 			io::IOException,
224 			uno::RuntimeException )
225 {
226 	::osl::MutexGuard aGuard( m_aMutex );
227 
228 	if ( !m_xOriginalStream.is() )
229 		throw io::NotConnectedException();
230 
231 	PrepareCopy_Impl();
232 
233 	m_xCopySeek->seek( location );
234 }
235 
236 //---------------------------------------------------------------------------
237 sal_Int64 SAL_CALL OSeekableInputWrapper::getPosition()
238 	throw ( io::IOException,
239 			uno::RuntimeException )
240 {
241 	::osl::MutexGuard aGuard( m_aMutex );
242 
243 	if ( !m_xOriginalStream.is() )
244 		throw io::NotConnectedException();
245 
246 	PrepareCopy_Impl();
247 
248 	return m_xCopySeek->getPosition();
249 }
250 
251 //---------------------------------------------------------------------------
252 sal_Int64 SAL_CALL OSeekableInputWrapper::getLength()
253 	throw ( io::IOException,
254 			uno::RuntimeException )
255 {
256 	::osl::MutexGuard aGuard( m_aMutex );
257 
258 	if ( !m_xOriginalStream.is() )
259 		throw io::NotConnectedException();
260 
261 	PrepareCopy_Impl();
262 
263 	return m_xCopySeek->getLength();
264 }
265 
266 }	// namespace comphelper
267 
268