Doc updates
[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 #include "gioalias.h"
32
33 /**
34  * SECTION:gfileinputstream
35  * @short_description: File input streaming operations
36  * @include: gio.h
37  * @see_also: #GInputStream, #GDataInputStream, #GSeekable
38  *
39  * GFileInputStream provides input streams that take their
40  * content from a file.
41  *
42  * GFileInputStream implements #GSeekable, which allows 
43  * the input stream to jump to arbitrary positions in the file.
44  **/
45
46 static void       g_file_input_stream_seekable_iface_init    (GSeekableIface       *iface);
47 static goffset    g_file_input_stream_seekable_tell          (GSeekable            *seekable);
48 static gboolean   g_file_input_stream_seekable_can_seek      (GSeekable            *seekable);
49 static gboolean   g_file_input_stream_seekable_seek          (GSeekable            *seekable,
50                                                               goffset               offset,
51                                                               GSeekType             type,
52                                                               GCancellable         *cancellable,
53                                                               GError              **error);
54 static gboolean   g_file_input_stream_seekable_can_truncate  (GSeekable            *seekable);
55 static gboolean   g_file_input_stream_seekable_truncate      (GSeekable            *seekable,
56                                                               goffset               offset,
57                                                               GCancellable         *cancellable,
58                                                               GError              **error);
59 static void       g_file_input_stream_real_query_info_async  (GFileInputStream     *stream,
60                                                               char                 *attributes,
61                                                               int                   io_priority,
62                                                               GCancellable         *cancellable,
63                                                               GAsyncReadyCallback   callback,
64                                                               gpointer              user_data);
65 static GFileInfo *g_file_input_stream_real_query_info_finish (GFileInputStream     *stream,
66                                                               GAsyncResult         *result,
67                                                               GError              **error);
68
69
70 G_DEFINE_TYPE_WITH_CODE (GFileInputStream, g_file_input_stream, G_TYPE_INPUT_STREAM,
71                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
72                                                 g_file_input_stream_seekable_iface_init))
73
74 struct _GFileInputStreamPrivate {
75   GAsyncReadyCallback outstanding_callback;
76 };
77
78 static void
79 g_file_input_stream_class_init (GFileInputStreamClass *klass)
80 {
81   g_type_class_add_private (klass, sizeof (GFileInputStreamPrivate));
82
83   klass->query_info_async = g_file_input_stream_real_query_info_async;
84   klass->query_info_finish = g_file_input_stream_real_query_info_finish;
85 }
86
87 static void
88 g_file_input_stream_seekable_iface_init (GSeekableIface *iface)
89 {
90   iface->tell = g_file_input_stream_seekable_tell;
91   iface->can_seek = g_file_input_stream_seekable_can_seek;
92   iface->seek = g_file_input_stream_seekable_seek;
93   iface->can_truncate = g_file_input_stream_seekable_can_truncate;
94   iface->truncate_fn = g_file_input_stream_seekable_truncate;
95 }
96
97 static void
98 g_file_input_stream_init (GFileInputStream *stream)
99 {
100   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
101                                               G_TYPE_FILE_INPUT_STREAM,
102                                               GFileInputStreamPrivate);
103 }
104
105 /**
106  * g_file_input_stream_query_info:
107  * @stream: a #GFileInputStream.
108  * @attributes: a file attribute query string.
109  * @cancellable: optional #GCancellable object, %NULL to ignore. 
110  * @error: a #GError location to store the error occuring, or %NULL to 
111  * ignore.
112  *
113  * Queries a file input stream the given @attributes.his function blocks 
114  * while querying the stream. For the asynchronous (non-blocking) version 
115  * of this function, see g_file_input_stream_query_info_async(). While the 
116  * stream is blocked, the stream will set the pending flag internally, and 
117  * any other operations on the stream will fail with %G_IO_ERROR_PENDING.
118  *
119  * Returns: a #GFileInfo, or %NULL on error.
120  **/
121 GFileInfo *
122 g_file_input_stream_query_info (GFileInputStream  *stream,
123                                 char              *attributes,
124                                 GCancellable      *cancellable,
125                                 GError           **error)
126 {
127   GFileInputStreamClass *class;
128   GInputStream *input_stream;
129   GFileInfo *info;
130   
131   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
132   
133   input_stream = G_INPUT_STREAM (stream);
134   
135   if (!g_input_stream_set_pending (input_stream, error))
136     return NULL;
137       
138   info = NULL;
139   
140   if (cancellable)
141     g_cancellable_push_current (cancellable);
142   
143   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
144   if (class->query_info)
145     info = class->query_info (stream, attributes, cancellable, error);
146   else
147     g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
148                  _("Stream doesn't support query_info"));
149
150   if (cancellable)
151     g_cancellable_pop_current (cancellable);
152   
153   g_input_stream_clear_pending (input_stream);
154   
155   return info;
156 }
157
158 static void
159 async_ready_callback_wrapper (GObject      *source_object,
160                               GAsyncResult *res,
161                               gpointer      user_data)
162 {
163   GFileInputStream *stream = G_FILE_INPUT_STREAM (source_object);
164
165   g_input_stream_clear_pending (G_INPUT_STREAM (stream));
166   if (stream->priv->outstanding_callback)
167     (*stream->priv->outstanding_callback) (source_object, res, user_data);
168   g_object_unref (stream);
169 }
170
171 /**
172  * g_file_input_stream_query_info_async:
173  * @stream: a #GFileInputStream.
174  * @attributes: a file attribute query string.
175  * @io_priority: the <link linkend="io-priority">I/O priority</link> 
176  *     of the request.
177  * @cancellable: optional #GCancellable object, %NULL to ignore. 
178  * @callback: callback to call when the request is satisfied
179  * @user_data: the data to pass to callback function
180  * 
181  * Queries the stream information asynchronously. For the synchronous 
182  * version of this function, see g_file_input_stream_query_info(). 
183  * 
184  * If @cancellable is not %NULL, then the operation can be cancelled by
185  * triggering the cancellable object from another thread. If the operation
186  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set
187  *  
188  **/
189 void
190 g_file_input_stream_query_info_async (GFileInputStream    *stream,
191                                       char                *attributes,
192                                       int                  io_priority,
193                                       GCancellable        *cancellable,
194                                       GAsyncReadyCallback  callback,
195                                       gpointer             user_data)
196 {
197   GFileInputStreamClass *klass;
198   GInputStream *input_stream;
199   GError *error = NULL;
200
201   g_return_if_fail (G_IS_FILE_INPUT_STREAM (stream));
202
203   input_stream = G_INPUT_STREAM (stream);
204   
205   if (!g_input_stream_set_pending (input_stream, &error))
206     {
207       g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
208                                             callback,
209                                             user_data,
210                                             error);
211       g_error_free (error);
212       return;
213     }
214
215   klass = G_FILE_INPUT_STREAM_GET_CLASS (stream);
216
217   stream->priv->outstanding_callback = callback;
218   g_object_ref (stream);
219   klass->query_info_async (stream, attributes, io_priority, cancellable,
220                               async_ready_callback_wrapper, user_data);
221 }
222
223 /**
224  * g_file_input_stream_query_info_finish:
225  * @stream: a #GFileInputStream.
226  * @result: a #GAsyncResult.
227  * @error: a #GError location to store the error occuring, 
228  *     or %NULL to ignore.
229  * 
230  * Finishes an asynchronous info query operation.
231  * 
232  * Returns: #GFileInfo. 
233  **/
234 GFileInfo *
235 g_file_input_stream_query_info_finish (GFileInputStream  *stream,
236                                        GAsyncResult      *result,
237                                        GError           **error)
238 {
239   GSimpleAsyncResult *simple;
240   GFileInputStreamClass *class;
241
242   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), NULL);
243   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
244
245   if (G_IS_SIMPLE_ASYNC_RESULT (result))
246     {
247       simple = G_SIMPLE_ASYNC_RESULT (result);
248       if (g_simple_async_result_propagate_error (simple, error))
249         return NULL;
250     }
251
252   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
253   return class->query_info_finish (stream, result, error);
254 }
255
256 /**
257  * g_file_input_stream_tell:
258  * @stream: a #GFileInputStream.
259  * 
260  * Gets the current position in the stream.
261  * 
262  * Returns: a #goffset with the position in the stream.
263  **/
264 goffset
265 g_file_input_stream_tell (GFileInputStream *stream)
266 {
267   GFileInputStreamClass *class;
268   goffset offset;
269
270   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), 0);
271
272   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
273
274   offset = 0;
275   if (class->tell)
276     offset = class->tell (stream);
277
278   return offset;
279 }
280
281 static goffset
282 g_file_input_stream_seekable_tell (GSeekable *seekable)
283 {
284   return g_file_input_stream_tell (G_FILE_INPUT_STREAM (seekable));
285 }
286
287 /**
288  * g_file_input_stream_can_seek:
289  * @stream: a #GFileInputStream.
290  * 
291  * Checks if a file input stream can be seeked.
292  * 
293  * Returns: %TRUE if stream can be seeked. %FALSE otherwise.
294  **/
295 gboolean
296 g_file_input_stream_can_seek (GFileInputStream *stream)
297 {
298   GFileInputStreamClass *class;
299   gboolean can_seek;
300
301   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
302
303   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
304
305   can_seek = FALSE;
306   if (class->seek)
307     {
308       can_seek = TRUE;
309       if (class->can_seek)
310         can_seek = class->can_seek (stream);
311     }
312   
313   return can_seek;
314 }
315
316 static gboolean
317 g_file_input_stream_seekable_can_seek (GSeekable *seekable)
318 {
319   return g_file_input_stream_can_seek (G_FILE_INPUT_STREAM (seekable));
320 }
321
322 /**
323  * g_file_input_stream_seek:
324  * @stream: a #GFileInputStream.
325  * @offset: a #goffset to seek.
326  * @type: a #GSeekType.
327  * @cancellable: optional #GCancellable object, %NULL to ignore. 
328  * @error: a #GError location to store the error occuring, or 
329  *     %NULL to ignore.
330  * 
331  * Seeks in the file input stream.
332  * 
333  * If @cancellable is not %NULL, then the operation can be cancelled by
334  * triggering the cancellable object from another thread. If the operation
335  * was cancelled, the error %G_IO_ERROR_CANCELLED will be set.
336  * 
337  * Returns: %TRUE if the stream was successfully seeked to the position.
338  * %FALSE on error.
339  **/
340 gboolean
341 g_file_input_stream_seek (GFileInputStream  *stream,
342                           goffset            offset,
343                           GSeekType          type,
344                           GCancellable      *cancellable,
345                           GError           **error)
346 {
347   GFileInputStreamClass *class;
348   GInputStream *input_stream;
349   gboolean res;
350
351   g_return_val_if_fail (G_IS_FILE_INPUT_STREAM (stream), FALSE);
352
353   input_stream = G_INPUT_STREAM (stream);
354   class = G_FILE_INPUT_STREAM_GET_CLASS (stream);
355
356   if (!class->seek)
357     {
358       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
359                    _("Seek not supported on stream"));
360       return FALSE;
361     }
362
363   if (!g_input_stream_set_pending (input_stream, error))
364     return FALSE;
365   
366   if (cancellable)
367     g_cancellable_push_current (cancellable);
368   
369   res = class->seek (stream, offset, type, cancellable, error);
370   
371   if (cancellable)
372     g_cancellable_pop_current (cancellable);
373
374   g_input_stream_clear_pending (input_stream);
375   
376   return res;
377 }
378
379 static gboolean
380 g_file_input_stream_seekable_seek (GSeekable     *seekable,
381                                    goffset        offset,
382                                    GSeekType      type,
383                                    GCancellable  *cancellable,
384                                    GError       **error)
385 {
386   return g_file_input_stream_seek (G_FILE_INPUT_STREAM (seekable),
387                                    offset, type, cancellable, error);
388 }
389
390 static gboolean
391 g_file_input_stream_seekable_can_truncate (GSeekable *seekable)
392 {
393   return FALSE;
394 }
395
396 static gboolean
397 g_file_input_stream_seekable_truncate (GSeekable     *seekable,
398                                        goffset        offset,
399                                        GCancellable  *cancellable,
400                                        GError       **error)
401 {
402   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
403                _("Truncate not allowed on input stream"));
404   return FALSE;
405 }
406
407 /********************************************
408  *   Default implementation of async ops    *
409  ********************************************/
410
411 typedef struct {
412   char *attributes;
413   GFileInfo *info;
414 } QueryInfoAsyncData;
415
416 static void
417 query_info_data_free (QueryInfoAsyncData *data)
418 {
419   if (data->info)
420     g_object_unref (data->info);
421   g_free (data->attributes);
422   g_free (data);
423 }
424
425 static void
426 query_info_async_thread (GSimpleAsyncResult *res,
427                          GObject            *object,
428                          GCancellable       *cancellable)
429 {
430   GFileInputStreamClass *class;
431   GError *error = NULL;
432   QueryInfoAsyncData *data;
433   GFileInfo *info;
434   
435   data = g_simple_async_result_get_op_res_gpointer (res);
436
437   info = NULL;
438   
439   class = G_FILE_INPUT_STREAM_GET_CLASS (object);
440   if (class->query_info)
441     info = class->query_info (G_FILE_INPUT_STREAM (object), data->attributes, cancellable, &error);
442   else
443     g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
444                  _("Stream doesn't support query_info"));
445
446   if (info == NULL)
447     {
448       g_simple_async_result_set_from_error (res, error);
449       g_error_free (error);
450     }
451   else
452     data->info = info;
453 }
454
455 static void
456 g_file_input_stream_real_query_info_async (GFileInputStream    *stream,
457                                            char                *attributes,
458                                            int                  io_priority,
459                                            GCancellable        *cancellable,
460                                            GAsyncReadyCallback  callback,
461                                            gpointer             user_data)
462 {
463   GSimpleAsyncResult *res;
464   QueryInfoAsyncData *data;
465
466   data = g_new0 (QueryInfoAsyncData, 1);
467   data->attributes = g_strdup (attributes);
468   
469   res = g_simple_async_result_new (G_OBJECT (stream), callback, user_data, g_file_input_stream_real_query_info_async);
470   g_simple_async_result_set_op_res_gpointer (res, data, (GDestroyNotify)query_info_data_free);
471   
472   g_simple_async_result_run_in_thread (res, query_info_async_thread, io_priority, cancellable);
473   g_object_unref (res);
474 }
475
476 static GFileInfo *
477 g_file_input_stream_real_query_info_finish (GFileInputStream  *stream,
478                                             GAsyncResult      *res,
479                                             GError           **error)
480 {
481   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
482   QueryInfoAsyncData *data;
483
484   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_file_input_stream_real_query_info_async);
485
486   data = g_simple_async_result_get_op_res_gpointer (simple);
487   if (data->info)
488     return g_object_ref (data->info);
489   
490   return NULL;
491 }
492
493 #define __G_FILE_INPUT_STREAM_C__
494 #include "gioaliasdef.c"
495