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