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