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 <com/sun/star/io/XOutputStream.hpp>
27 
28 
29 #include <comphelper/seekableinput.hxx>
30 
31 using namespace ::com::sun::star;
32 
33 namespace comphelper
34 {
35 
36 const sal_Int32 nConstBufferSize = 32000;
37 
38 //---------------------------------------------------------------------------
copyInputToOutput_Impl(const uno::Reference<io::XInputStream> & xIn,const uno::Reference<io::XOutputStream> & xOut)39 void copyInputToOutput_Impl( const uno::Reference< io::XInputStream >& xIn,
40 							const uno::Reference< io::XOutputStream >& xOut )
41 {
42 	sal_Int32 nRead;
43 	uno::Sequence< sal_Int8 > aSequence( nConstBufferSize );
44 
45 	do
46 	{
47 		nRead = xIn->readBytes( aSequence, nConstBufferSize );
48 		if ( nRead < nConstBufferSize )
49 		{
50 			uno::Sequence< sal_Int8 > aTempBuf( aSequence.getConstArray(), nRead );
51 			xOut->writeBytes( aTempBuf );
52 		}
53 		else
54 			xOut->writeBytes( aSequence );
55 	}
56 	while ( nRead == nConstBufferSize );
57 }
58 
59 //---------------------------------------------------------------------------
OSeekableInputWrapper(const uno::Reference<io::XInputStream> & xInStream,const uno::Reference<lang::XMultiServiceFactory> & xFactory)60 OSeekableInputWrapper::OSeekableInputWrapper(
61 			const uno::Reference< io::XInputStream >& xInStream,
62 			const uno::Reference< lang::XMultiServiceFactory >& xFactory )
63 : m_xFactory( xFactory )
64 , m_xOriginalStream( xInStream )
65 {
66 	if ( !m_xFactory.is() )
67 		throw uno::RuntimeException();
68 }
69 
70 //---------------------------------------------------------------------------
~OSeekableInputWrapper()71 OSeekableInputWrapper::~OSeekableInputWrapper()
72 {
73 }
74 
75 //---------------------------------------------------------------------------
CheckSeekableCanWrap(const uno::Reference<io::XInputStream> & xInStream,const uno::Reference<lang::XMultiServiceFactory> & xFactory)76 uno::Reference< io::XInputStream > OSeekableInputWrapper::CheckSeekableCanWrap(
77 							const uno::Reference< io::XInputStream >& xInStream,
78 							const uno::Reference< lang::XMultiServiceFactory >& xFactory )
79 {
80 	// check that the stream is seekable and just wrap it if it is not
81 	uno::Reference< io::XSeekable > xSeek( xInStream, uno::UNO_QUERY );
82 	if ( xSeek.is() )
83 		return xInStream;
84 
85 	uno::Reference< io::XInputStream > xNewStream(
86 			static_cast< io::XInputStream* >(
87 				new OSeekableInputWrapper( xInStream, xFactory ) ) );
88     return xNewStream;
89 }
90 
91 //---------------------------------------------------------------------------
PrepareCopy_Impl()92 void OSeekableInputWrapper::PrepareCopy_Impl()
93 {
94 	if ( !m_xCopyInput.is() )
95 	{
96 		if ( !m_xFactory.is() )
97 			throw uno::RuntimeException();
98 
99 		uno::Reference< io::XOutputStream > xTempOut(
100 				m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.io.TempFile" ) ),
101 				uno::UNO_QUERY );
102 
103 		if ( xTempOut.is() )
104 		{
105 			copyInputToOutput_Impl( m_xOriginalStream, xTempOut );
106 			xTempOut->closeOutput();
107 
108 			uno::Reference< io::XSeekable > xTempSeek( xTempOut, uno::UNO_QUERY );
109 			if ( xTempSeek.is() )
110 			{
111 				xTempSeek->seek( 0 );
112 				m_xCopyInput = uno::Reference< io::XInputStream >( xTempOut, uno::UNO_QUERY );
113 				if ( m_xCopyInput.is() )
114 					m_xCopySeek = xTempSeek;
115 			}
116 		}
117 	}
118 
119 	if ( !m_xCopyInput.is() )
120 		throw io::IOException();
121 }
122 
123 // XInputStream
124 //---------------------------------------------------------------------------
readBytes(uno::Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)125 sal_Int32 SAL_CALL OSeekableInputWrapper::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
126 	throw ( io::NotConnectedException,
127 			io::BufferSizeExceededException,
128 			io::IOException,
129 			uno::RuntimeException )
130 {
131 	::osl::MutexGuard aGuard( m_aMutex );
132 
133 	if ( !m_xOriginalStream.is() )
134 		throw io::NotConnectedException();
135 
136 	PrepareCopy_Impl();
137 
138 	return m_xCopyInput->readBytes( aData, nBytesToRead );
139 }
140 
141 //---------------------------------------------------------------------------
readSomeBytes(uno::Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)142 sal_Int32 SAL_CALL OSeekableInputWrapper::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
143 	throw ( io::NotConnectedException,
144 			io::BufferSizeExceededException,
145 			io::IOException,
146 			uno::RuntimeException )
147 {
148 	::osl::MutexGuard aGuard( m_aMutex );
149 
150 	if ( !m_xOriginalStream.is() )
151 		throw io::NotConnectedException();
152 
153 	PrepareCopy_Impl();
154 
155 	return m_xCopyInput->readSomeBytes( aData, nMaxBytesToRead );
156 }
157 
158 //---------------------------------------------------------------------------
skipBytes(sal_Int32 nBytesToSkip)159 void SAL_CALL OSeekableInputWrapper::skipBytes( sal_Int32 nBytesToSkip )
160 	throw ( io::NotConnectedException,
161 			io::BufferSizeExceededException,
162 			io::IOException,
163 			uno::RuntimeException )
164 {
165 	::osl::MutexGuard aGuard( m_aMutex );
166 
167 	if ( !m_xOriginalStream.is() )
168 		throw io::NotConnectedException();
169 
170 	PrepareCopy_Impl();
171 
172 	m_xCopyInput->skipBytes( nBytesToSkip );
173 }
174 
175 //---------------------------------------------------------------------------
available()176 sal_Int32 SAL_CALL OSeekableInputWrapper::available()
177 	throw ( io::NotConnectedException,
178 			io::IOException,
179 			uno::RuntimeException )
180 {
181 	::osl::MutexGuard aGuard( m_aMutex );
182 
183 	if ( !m_xOriginalStream.is() )
184 		throw io::NotConnectedException();
185 
186 	PrepareCopy_Impl();
187 
188 	return m_xCopyInput->available();
189 }
190 
191 //---------------------------------------------------------------------------
closeInput()192 void SAL_CALL OSeekableInputWrapper::closeInput()
193 	throw ( io::NotConnectedException,
194 			io::IOException,
195 			uno::RuntimeException )
196 {
197 	::osl::MutexGuard aGuard( m_aMutex );
198 
199 	if ( !m_xOriginalStream.is() )
200 		throw io::NotConnectedException();
201 
202 	m_xOriginalStream->closeInput();
203 	m_xOriginalStream = uno::Reference< io::XInputStream >();
204 
205 	if ( m_xCopyInput.is() )
206 	{
207 		m_xCopyInput->closeInput();
208 		m_xCopyInput = uno::Reference< io::XInputStream >();
209 	}
210 
211 	m_xCopySeek = uno::Reference< io::XSeekable >();
212 }
213 
214 
215 // XSeekable
216 //---------------------------------------------------------------------------
seek(sal_Int64 location)217 void SAL_CALL OSeekableInputWrapper::seek( sal_Int64 location )
218 	throw ( lang::IllegalArgumentException,
219 			io::IOException,
220 			uno::RuntimeException )
221 {
222 	::osl::MutexGuard aGuard( m_aMutex );
223 
224 	if ( !m_xOriginalStream.is() )
225 		throw io::NotConnectedException();
226 
227 	PrepareCopy_Impl();
228 
229 	m_xCopySeek->seek( location );
230 }
231 
232 //---------------------------------------------------------------------------
getPosition()233 sal_Int64 SAL_CALL OSeekableInputWrapper::getPosition()
234 	throw ( io::IOException,
235 			uno::RuntimeException )
236 {
237 	::osl::MutexGuard aGuard( m_aMutex );
238 
239 	if ( !m_xOriginalStream.is() )
240 		throw io::NotConnectedException();
241 
242 	PrepareCopy_Impl();
243 
244 	return m_xCopySeek->getPosition();
245 }
246 
247 //---------------------------------------------------------------------------
getLength()248 sal_Int64 SAL_CALL OSeekableInputWrapper::getLength()
249 	throw ( io::IOException,
250 			uno::RuntimeException )
251 {
252 	::osl::MutexGuard aGuard( m_aMutex );
253 
254 	if ( !m_xOriginalStream.is() )
255 		throw io::NotConnectedException();
256 
257 	PrepareCopy_Impl();
258 
259 	return m_xCopySeek->getLength();
260 }
261 
262 }	// namespace comphelper
263 
264