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