gio/ docs/reference/gio Merged gio-standalone into glib.
[platform/upstream/glib.git] / gio / gfileinputstream.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <glib.h>
26 #include <gfileinputstream.h>
27 #include <gseekable.h>
28 #include "gsimpleasyncresult.h"
29 #include "glibintl.h"
30
31 static void       g_file_input_stream_seekable_iface_init    (GSeekableIface       *iface);
32 static goffset    g_file_input_stream_seekable_tell          (GSeekable            *seekable);
33 static gboolean   g_file_input_stream_seekable_can_seek      (GSeekable            *seekable);
34 static gboolean   g_file_input_stream_seekable_seek          (GSeekable            *seekable,
35                                                               goffset               offset,
36                                                               GSeekType             type,
37                                                               GCancellable         *cancellable,
38                                                               GError              **error);
39 static gboolean   g_file_input_stream_seekable_can_truncate  (GSeekable            *seekable);
40 static gboolean   g_file_input_stream_seekable_truncate      (GSeekable            *seekable,
41                                                               goffset               offset,
42                                                               GCancellable         *cancellable,
43                                                               GError              **error);
44 static void       g_file_input_stream_real_query_info_async  (GFileInputStream     *stream,
45                                                               char                 *attributes,
46                                                               int                   io_priority,
47                                                               GCancellable         *cancellable,
48                                                               GAsyncReadyCallback   callback,
49                                                               gpointer              user_data);
50 static GFileInfo *g_file_input_stream_real_query_info_finish (GFileInputStream     *stream,
51                                                               GAsyncResult         *result,
52                                                               GError              **error);
53
54
55 G_DEFINE_TYPE_WITH_CODE (GFileInputStream, g_file_input_stream, G_TYPE_INPUT_STREAM,
56                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
57                                                 g_file_input_stream_seekable_iface_init))
58
59 struct _GFileInputStreamPrivate {
60   GAsyncReadyCallback outstanding_callback;
61 };
62
63 static void
64 g_file_input_stream_class_init (GFileInputStreamClass *klass)
65 {
66   g_type_class_add_private (klass, sizeof (GFileInputStreamPrivate));
67
68   klass->query_info_async = g_file_input_stream_real_query_info_async;
69   klass->query_info_finish = g_file_input_stream_real_query_info_finish;
70 }
71
72 static void
73 g_file_input_stream_seekable_iface_init (GSeekableIface *iface)
74 {
75   iface->tell = g_file_input_stream_seekable_tell;
76   iface->can_seek = g_file_input_stream_seekable_can_seek;
77   iface->seek = g_file_input_stream_seekable_seek;
78   iface->can_truncate = g_file_input_stream_seekable_can_truncate;
79   iface->truncate = g_file_input_stream_seekable_truncate;
80 }
81
82 static void
83 g_file_input_stream_init (GFileInputStream *stream)
84 {
85   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
86                                               G_TYPE_FILE_INPUT_STREAM,
87                                               GFileInputStreamPrivate);
88 }
89
90 /**
91  * g_file_input_stream_query_info:
92  * @stream:
93  * @attributes:
94  * @cancellable: optional #GCancellable object, %NULL to ignore. 
95  * @error: a #GError location to store the error occuring, or %NULL to 
96  * ignore.
97  * Returns: 
98  **/
99 GFileInfo *
100 g_file_input_stream_query_info (GFileInputStream     *stream,
101                                    char                 *attributes,
102                                    GCancellable         *cancellable,
103                                    GError              **error)
104 {
105   GFileInputStreamClass *class;
106   GInputStream *input_stream;
107   GFileInfo *info;
108   
109   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
110   
111   input_stream = G_INPUT_STREAM (stream);
112   
113   if (g_input_stream_is_closed (input_stream))
114     {
115       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
116                    _("Stream is already closed"));
117       return NULL;
118     }
119   
120   if (g_input_stream_has_pending (input_stream))
121     {
122       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
123                    _("Stream has outstanding operation"));
124       return NULL;
125     }
126       
127   info = NULL;
128   
129   g_input_stream_set_pending (input_stream, TRUE);
130
131   if (cancellable)
132     g_push_current_cancellable (cancellable);
133   
134   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
135   if (class->query_info)
136     info = class->query_info (stream, attributes, cancellable, error);
137   else
138     g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
139                  _("Stream doesn't support query_info"));
140
141   if (cancellable)
142     g_pop_current_cancellable (cancellable);
143   
144   g_input_stream_set_pending (input_stream, FALSE);
145   
146   return info;
147 }
148
149 static void
150 async_ready_callback_wrapper (GObject *source_object,
151                               GAsyncResult *res,
152                               gpointer      user_data)
153 {
154   GFileInputStream *stream = G_FILE_INPUT_STREAM (source_object);
155
156   g_input_stream_set_pending (G_INPUT_STREAM (stream), FALSE);
157   if (stream->priv->outstanding_callback)
158     (*stream->priv->outstanding_callback) (source_object, res, user_data);
159   g_object_unref (stream);
160 }
161
162 /**
163  * g_file_input_stream_query_info_async:
164  * @stream:
165  * @attributes:
166  * @io_priority: the io priority of the request.
167  * @cancellable: optional #GCancellable object, %NULL to ignore. @callback:
168  * @user_data:
169  *  
170  **/
171 void
172 g_file_input_stream_query_info_async (GFileInputStream     *stream,
173                                          char                 *attributes,
174                                          int                   io_priority,
175                                          GCancellable         *cancellable,
176                                          GAsyncReadyCallback   callback,
177                                          gpointer              user_data)
178 {
179   GFileInputStreamClass *klass;
180   GInputStream *input_stream;
181
182   g_return_if_fail (G_IS_FILE_INPUT_STREAM (stream));
183
184   input_stream = G_INPUT_STREAM (stream);
185  
186   if (g_input_stream_is_closed (input_stream))
187     {
188       g_simple_async_report_error_in_idle (G_OBJECT (stream),
189                                            callback,
190                                            user_data,
191                                            G_IO_ERROR, G_IO_ERROR_CLOSED,
192                                            _("Stream is already closed"));
193       return;
194     }
195   
196   if (g_input_stream_has_pending (input_stream))
197     {
198       g_simple_async_report_error_in_idle (G_OBJECT (stream),
199                                            callback,
200                                            user_data,
201                                            G_IO_ERROR, G_IO_ERROR_PENDING,
202                                            _("Stream has outstanding operation"));
203       return;
204     }
205
206   klass = G_FILE_INPUT_STREAM_GET_CLASS (stream);
207
208   g_input_stream_set_pending (input_stream, TRUE);
209   stream->priv->outstanding_callback = callback;
210   g_object_ref (stream);
211   klass->query_info_async (stream, attributes, io_priority, cancellable,
212                               async_ready_callback_wrapper, user_data);
213 }
214
215 /**
216  * g_file_input_stream_query_info_finish:
217  * @stream:
218  * @result:
219  * @error: a #GError location to store the error occuring, or %NULL to 
220  * ignore.
221  * Returns: #GFileInfo. 
222  **/
223 GFileInfo *
224 g_file_input_stream_query_info_finish (GFileInputStream     *stream,
225                                           GAsyncResult         *result,
226                                           GError              **error)
227 {
228   GSimpleAsyncResult *simple;
229   GFileInputStreamClass *class;
230
231   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
232   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
233
234   if (G_IS_SIMPLE_ASYNC_RESULT (result))
235     {
236       simple = G_SIMPLE_ASYNC_RESULT (result);
237       if (g_simple_async_result_propagate_error (simple, error))
238         return NULL;
239     }
240
241   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
242   return class->query_info_finish (stream, result, error);
243 }
244
245 /**
246  * g_file_input_stream_tell:
247  * @stream:
248  * 
249  * Returns: 
250  **/
251 goffset
252 g_file_input_stream_tell (GFileInputStream  *stream)
253 {
254   GFileInputStreamClass *class;
255   goffset offset;
256
257   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), 0);
258
259   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
260
261   offset = 0;
262   if (class->tell)
263     offset = class->tell (stream);
264
265   return offset;
266 }
267
268 static goffset
269 g_file_input_stream_seekable_tell (GSeekable *seekable)
270 {
271   return g_file_input_stream_tell (G_FILE_INPUT_STREAM (seekable));
272 }
273
274 /**
275  * g_file_input_stream_can_seek:
276  * @stream:
277  * 
278  * Returns: %TRUE if stream can be seeked. %FALSE otherwise.
279  **/
280 gboolean
281 g_file_input_stream_can_seek (GFileInputStream  *stream)
282 {
283   GFileInputStreamClass *class;
284   gboolean can_seek;
285
286   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
287
288   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
289
290   can_seek = FALSE;
291   if (class->seek)
292     {
293       can_seek = TRUE;
294       if (class->can_seek)
295         can_seek = class->can_seek (stream);
296     }
297   
298   return can_seek;
299 }
300
301 static gboolean
302 g_file_input_stream_seekable_can_seek (GSeekable *seekable)
303 {
304   return g_file_input_stream_can_seek (G_FILE_INPUT_STREAM (seekable));
305 }
306
307 /**
308  * g_file_input_stream_seek:
309  * @stream:
310  * @offset:
311  * @type:
312  * @cancellable: optional #GCancellable object, %NULL to ignore. 
313  * @error: a #GError location to store the error occuring, or %NULL to 
314  * ignore.
315  * Returns: 
316  **/
317 gboolean
318 g_file_input_stream_seek (GFileInputStream  *stream,
319                           goffset            offset,
320                           GSeekType          type,
321                           GCancellable      *cancellable,
322                           GError           **error)
323 {
324   GFileInputStreamClass *class;
325   GInputStream *input_stream;
326   gboolean res;
327
328   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
329
330   input_stream = G_INPUT_STREAM (stream);
331   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
332
333   if (g_input_stream_is_closed (input_stream))
334     {
335       g_set_error (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
336                    _("Stream is already closed"));
337       return FALSE;
338     }
339   
340   if (g_input_stream_has_pending (input_stream))
341     {
342       g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING,
343                    _("Stream has outstanding operation"));
344       return FALSE;
345     }
346   
347   if (!class->seek)
348     {
349       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
350                    _("Seek not supported on stream"));
351       return FALSE;
352     }
353
354   g_input_stream_set_pending (input_stream, TRUE);
355   
356   if (cancellable)
357     g_push_current_cancellable (cancellable);
358   
359   res = class->seek (stream, offset, type, cancellable, error);
360   
361   if (cancellable)
362     g_pop_current_cancellable (cancellable);
363
364   g_input_stream_set_pending (input_stream, FALSE);
365   
366   return res;
367 }
368
369 static gboolean
370 g_file_input_stream_seekable_seek (GSeekable  *seekable,
371                                    goffset     offset,
372                                    GSeekType   type,
373                                    GCancellable  *cancellable,
374                                    GError    **error)
375 {
376   return g_file_input_stream_seek (G_FILE_INPUT_STREAM (seekable),
377                                    offset, type, cancellable, error);
378 }
379
380 static gboolean
381 g_file_input_stream_seekable_can_truncate (GSeekable  *seekable)
382 {
383   return FALSE;
384 }
385
386 static gboolean
387 g_file_input_stream_seekable_truncate (GSeekable  *seekable,
388                                        goffset     offset,
389                                        GCancellable  *cancellable,
390                                        GError    **error)
391 {
392   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
393                _("Truncate not allowed on input stream"));
394   return FALSE;
395 }
396
397 /********************************************
398  *   Default implementation of async ops    *
399  ********************************************/
400
401 typedef struct {
402   char *attributes;
403   GFileInfo *info;
404 } QueryInfoAsyncData;
405
406 static void
407 query_info_data_free (QueryInfoAsyncData *data)
408 {
409   if (data->info)
410     g_object_unref (data->info);
411   g_free (data->attributes);
412   g_free (data);
413 }
414
415 static void
416 query_info_async_thread (GSimpleAsyncResult *res,
417                        GObject *object,
418                        GCancellable *cancellable)
419 {
420   GFileInputStreamClass *class;
421   GError *error = NULL;
422   QueryInfoAsyncData *data;
423   GFileInfo *info;
424   
425   data = g_simple_async_result_get_op_res_gpointer (res);
426
427   info = NULL;
428   
429   class = G_FILE_INPUT_STREAM_GET_CLASS (object);
430   if (class->query_info)
431     info = class->query_info (G_FILE_INPUT_STREAM (object), data->attributes, cancellable, &error);
432   else
433     g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
434                  _("Stream doesn't support query_info"));
435
436   if (info == NULL)
437     {
438       g_simple_async_result_set_from_error (res, error);
439       g_error_free (error);
440     }
441   else
442     data->info = info;
443 }
444
445 static void
446 g_file_input_stream_real_query_info_async (GFileInputStream     *stream,
447                                               char                 *attributes,
448                                               int                   io_priority,
449                                               GCancellable         *cancellable,
450                                               GAsyncReadyCallback   callback,
451                                               gpointer              user_data)
452 {
453   GSimpleAsyncResult *res;
454   QueryInfoAsyncData *data;
455
456   data = g_new0 (QueryInfoAsyncData, 1);
457   data->attributes = g_strdup (attributes);
458   
459   res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_file_input_stream_real_query_info_async);
460   g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_info_data_free);
461   
462   g_simple_async_result_run_in_thread (res, query_info_async_thread, io_priority, cancellable);
463   g_object_unref (res);
464 }
465
466 static GFileInfo *
467 g_file_input_stream_real_query_info_finish (GFileInputStream     *stream,
468                                                GAsyncResult         *res,
469                                                GError              **error)
470 {
471   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
472   QueryInfoAsyncData *data;
473
474   g_assert (g_simple_async_result_get_source_tag (simple) == g_file_input_stream_real_query_info_async);
475
476   data = g_simple_async_result_get_op_res_gpointer (simple);
477   if (data->info)
478     return g_object_ref (data->info);
479   
480   return NULL;
481 }