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 #include "gvfs_stream.hxx"
25 #include <rtl/memory.h>
26 #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
27
28 #include <libgnomevfs/gnome-vfs-ops.h>
29
30 using namespace cppu;
31 using namespace rtl;
32 using namespace com::sun::star::io;
33 using namespace com::sun::star::uno;
34 using namespace com::sun::star::ucb;
35 using namespace gvfs;
36
Stream(GnomeVFSHandle * handle,const GnomeVFSFileInfo * aInfo)37 Stream::Stream( GnomeVFSHandle *handle,
38 const GnomeVFSFileInfo *aInfo ) :
39 m_eof (sal_False),
40 m_bInputStreamCalled( sal_False ),
41 m_bOutputStreamCalled( sal_False )
42 {
43 m_handle = handle;
44 gnome_vfs_file_info_copy (&m_info, aInfo);
45 }
46
~Stream(void)47 Stream::~Stream( void )
48 {
49 if (m_handle) {
50 gnome_vfs_close (m_handle);
51 m_handle = NULL;
52 }
53 }
54
queryInterface(const Type & type)55 Any Stream::queryInterface( const Type &type )
56 throw( RuntimeException )
57 {
58 Any aRet = ::cppu::queryInterface
59 ( type,
60 static_cast< XStream * >( this ),
61 static_cast< XInputStream * >( this ),
62 static_cast< XOutputStream * >( this ),
63 static_cast< XSeekable * >( this ),
64 static_cast< XTruncate * >( this ) );
65
66 return aRet.hasValue() ? aRet : OWeakObject::queryInterface( type );
67 }
68
69 // -------------------------------------------------------------------
70 // XStream
71 // -------------------------------------------------------------------
72
73 com::sun::star::uno::Reference< com::sun::star::io::XInputStream > SAL_CALL
getInputStream()74 Stream::getInputStream( )
75 throw( com::sun::star::uno::RuntimeException )
76 {
77 {
78 osl::MutexGuard aGuard( m_aMutex );
79 m_bInputStreamCalled = true;
80 }
81 return Reference< XInputStream >( this );
82 }
83
84 com::sun::star::uno::Reference< com::sun::star::io::XOutputStream > SAL_CALL
getOutputStream()85 Stream::getOutputStream( )
86 throw( com::sun::star::uno::RuntimeException )
87 {
88 {
89 osl::MutexGuard aGuard( m_aMutex );
90 m_bOutputStreamCalled = true;
91 }
92 return Reference< XOutputStream >( this );
93 }
94
95 // -------------------------------------------------------------------
96 // XInputStream
97 // -------------------------------------------------------------------
98
readBytes(Sequence<sal_Int8> & aData,sal_Int32 nBytesToRead)99 sal_Int32 SAL_CALL Stream::readBytes(
100 Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead )
101 throw( NotConnectedException,
102 BufferSizeExceededException,
103 IOException,
104 RuntimeException )
105 {
106 GnomeVFSResult result;
107 GnomeVFSFileSize nBytesRead = 0;
108
109 if( ! m_handle )
110 throw IOException();
111
112 if( m_eof ) {
113 aData.realloc( 0 );
114 return 0;
115 }
116
117 try {
118 aData.realloc( nBytesToRead );
119 } catch ( const Exception &e ) {
120 throw BufferSizeExceededException();
121 }
122
123 do {
124 result = gnome_vfs_read( m_handle, aData.getArray(),
125 nBytesToRead, &nBytesRead );
126 } while( result == GNOME_VFS_ERROR_INTERRUPTED );
127
128 if (result != GNOME_VFS_OK &&
129 result != GNOME_VFS_ERROR_EOF)
130 throwOnError( result );
131
132 if (result == GNOME_VFS_ERROR_EOF)
133 m_eof = sal_True;
134
135 aData.realloc( sal::static_int_cast<sal_uInt32>(nBytesRead) );
136
137 return sal::static_int_cast<sal_Int32>(nBytesRead);
138 }
139
readSomeBytes(Sequence<sal_Int8> & aData,sal_Int32 nMaxBytesToRead)140 sal_Int32 SAL_CALL Stream::readSomeBytes(
141 Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead )
142 throw( NotConnectedException,
143 BufferSizeExceededException,
144 IOException,
145 RuntimeException )
146 {
147 // Again - having 2 methods here just sucks; cf. filinpstr.cxx
148 // This can never be an effective non-blocking API - so why bother ?
149 return readBytes( aData, nMaxBytesToRead );
150 }
151
skipBytes(sal_Int32 nBytesToSkip)152 void SAL_CALL Stream::skipBytes( sal_Int32 nBytesToSkip )
153 throw( NotConnectedException,
154 BufferSizeExceededException,
155 IOException,
156 RuntimeException )
157 {
158 GnomeVFSResult result;
159
160 if( ! m_handle )
161 throw IOException();
162
163 result = gnome_vfs_seek( m_handle, GNOME_VFS_SEEK_CURRENT, nBytesToSkip );
164
165 if ( result == GNOME_VFS_ERROR_BAD_PARAMETERS ||
166 result == GNOME_VFS_ERROR_NOT_SUPPORTED )
167 g_warning ("FIXME: just read them in ...");
168
169 throwOnError( result );
170 }
171
available()172 sal_Int32 SAL_CALL Stream::available( )
173 throw( NotConnectedException,
174 IOException,
175 RuntimeException )
176 {
177 return 0; // cf. filinpstr.cxx
178 }
179
closeInput(void)180 void SAL_CALL Stream::closeInput( void )
181 throw( NotConnectedException,
182 IOException,
183 RuntimeException )
184 {
185 osl::MutexGuard aGuard( m_aMutex );
186 m_bInputStreamCalled = false;
187
188 if( ! m_bOutputStreamCalled )
189 closeStream();
190 }
191
192 // -------------------------------------------------------------------
193 // XSeekable
194 // -------------------------------------------------------------------
195
seek(sal_Int64 location)196 void SAL_CALL Stream::seek( sal_Int64 location )
197 throw( ::com::sun::star::lang::IllegalArgumentException,
198 IOException,
199 RuntimeException )
200 {
201 GnomeVFSResult result;
202
203 if( ! m_handle )
204 throw IOException();
205
206 if ( location < 0 )
207 throw ::com::sun::star::lang::IllegalArgumentException();
208
209 m_eof = sal_False;
210 result = gnome_vfs_seek( m_handle, GNOME_VFS_SEEK_START, location );
211
212 if (result == GNOME_VFS_ERROR_EOF)
213 throw ::com::sun::star::lang::IllegalArgumentException();
214
215 throwOnError( result );
216 }
217
getPosition()218 sal_Int64 SAL_CALL Stream::getPosition()
219 throw( IOException,
220 RuntimeException )
221 {
222 GnomeVFSFileSize nBytesIn = 0;
223
224 if( ! m_handle )
225 throw IOException();
226
227 throwOnError( gnome_vfs_tell( m_handle, &nBytesIn ) );
228
229 return nBytesIn;
230 }
231
getLength()232 sal_Int64 SAL_CALL Stream::getLength()
233 throw( IOException, RuntimeException )
234 {
235 // FIXME: so this sucks; it may be stale but ...
236 if (m_info.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)
237 return m_info.size;
238 else {
239 g_warning ("FIXME: No valid length");
240 return 0;
241 }
242 }
243
244 // -------------------------------------------------------------------
245 // XTruncate
246 // -------------------------------------------------------------------
247
truncate(void)248 void SAL_CALL Stream::truncate( void )
249 throw( com::sun::star::io::IOException,
250 com::sun::star::uno::RuntimeException )
251 {
252 if( ! m_handle )
253 throw IOException();
254
255 throwOnError( gnome_vfs_truncate_handle( m_handle, 0 ) );
256 }
257
258 // -------------------------------------------------------------------
259 // XOutputStream
260 // -------------------------------------------------------------------
261
writeBytes(const com::sun::star::uno::Sequence<sal_Int8> & aData)262 void SAL_CALL Stream::writeBytes( const com::sun::star::uno::Sequence< sal_Int8 >& aData )
263 throw( com::sun::star::io::NotConnectedException,
264 com::sun::star::io::BufferSizeExceededException,
265 com::sun::star::io::IOException,
266 com::sun::star::uno::RuntimeException)
267 {
268 GnomeVFSResult result = GNOME_VFS_OK;
269 GnomeVFSFileSize toWrite = aData.getLength();
270 const sal_Int8 *p = aData.getConstArray();
271
272 if( ! m_handle )
273 throw IOException();
274
275 while( toWrite > 0) {
276 GnomeVFSFileSize bytesWritten = 0;
277
278 result = gnome_vfs_write( m_handle, p, toWrite, &bytesWritten );
279 if( result == GNOME_VFS_ERROR_INTERRUPTED )
280 continue;
281 throwOnError( result );
282 g_assert( bytesWritten <= toWrite );
283 toWrite -= bytesWritten;
284 p += bytesWritten;
285 }
286 }
287
flush(void)288 void SAL_CALL Stream::flush( void )
289 throw( NotConnectedException, BufferSizeExceededException,
290 IOException, RuntimeException )
291 {
292 }
293
closeOutput(void)294 void SAL_CALL Stream::closeOutput( void )
295 throw( com::sun::star::io::NotConnectedException,
296 com::sun::star::io::IOException,
297 com::sun::star::uno::RuntimeException )
298 {
299 osl::MutexGuard aGuard( m_aMutex );
300 m_bOutputStreamCalled = false;
301
302 if( ! m_bInputStreamCalled )
303 closeStream();
304 }
305
306 // -------------------------------------------------------------------
307 // Misc.
308 // -------------------------------------------------------------------
309
closeStream(void)310 void Stream::closeStream( void )
311 throw( ::com::sun::star::io::NotConnectedException,
312 ::com::sun::star::io::IOException,
313 ::com::sun::star::uno::RuntimeException )
314 {
315 if (m_handle) {
316 gnome_vfs_close (m_handle);
317 m_handle = NULL;
318 } else
319 throw IOException();
320 }
321
throwOnError(GnomeVFSResult result)322 void Stream::throwOnError( GnomeVFSResult result )
323 throw( NotConnectedException,
324 BufferSizeExceededException,
325 IOException,
326 RuntimeException )
327 {
328 if( result != GNOME_VFS_OK ) {
329 ::rtl::OUString aMsg = ::rtl::OUString::createFromAscii
330 ( gnome_vfs_result_to_string( result ) );
331
332 g_warning( "Input Stream exceptional result '%s' (%d)",
333 gnome_vfs_result_to_string( result ), result );
334
335 throw IOException( aMsg, static_cast< cppu::OWeakObject * >( this ) );
336 }
337 }
338