Bug 568394 – dropping the last reference to a stream filter closes the
[platform/upstream/glib.git] / gio / gfilterinputstream.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: Christian Kellner <gicmo@gnome.org> 
21  */
22
23 #include "config.h"
24 #include "gfilterinputstream.h"
25 #include "ginputstream.h"
26 #include "gsimpleasyncresult.h"
27 #include "glibintl.h"
28
29 #include "gioalias.h"
30
31 /**
32  * SECTION:gfilterinputstream
33  * @short_description: Filter Input Stream
34  * @include: gio/gio.h
35  *
36  **/
37
38 enum {
39   PROP_0,
40   PROP_BASE_STREAM,
41   PROP_CLOSE_BASE
42 };
43
44 static void     g_filter_input_stream_set_property (GObject      *object,
45                                                     guint         prop_id,
46                                                     const GValue *value,
47                                                     GParamSpec   *pspec);
48
49 static void     g_filter_input_stream_get_property (GObject      *object,
50                                                     guint         prop_id,
51                                                     GValue       *value,
52                                                     GParamSpec   *pspec);
53 static void     g_filter_input_stream_finalize     (GObject *object);
54
55
56 static gssize   g_filter_input_stream_read         (GInputStream         *stream,
57                                                     void                 *buffer,
58                                                     gsize                 count,
59                                                     GCancellable         *cancellable,
60                                                     GError              **error);
61 static gssize   g_filter_input_stream_skip         (GInputStream         *stream,
62                                                     gsize                 count,
63                                                     GCancellable         *cancellable,
64                                                     GError              **error);
65 static gboolean g_filter_input_stream_close        (GInputStream         *stream,
66                                                     GCancellable         *cancellable,
67                                                     GError              **error);
68 static void     g_filter_input_stream_read_async   (GInputStream         *stream,
69                                                     void                 *buffer,
70                                                     gsize                 count,
71                                                     int                   io_priority,
72                                                     GCancellable         *cancellable,
73                                                     GAsyncReadyCallback   callback,
74                                                     gpointer              user_data);
75 static gssize   g_filter_input_stream_read_finish  (GInputStream         *stream,
76                                                     GAsyncResult         *result,
77                                                     GError              **error);
78 static void     g_filter_input_stream_skip_async   (GInputStream         *stream,
79                                                     gsize                 count,
80                                                     int                   io_priority,
81                                                     GCancellable         *cancellabl,
82                                                     GAsyncReadyCallback   callback,
83                                                     gpointer              datae);
84 static gssize   g_filter_input_stream_skip_finish  (GInputStream         *stream,
85                                                     GAsyncResult         *result,
86                                                     GError              **error);
87 static void     g_filter_input_stream_close_async  (GInputStream         *stream,
88                                                     int                   io_priority,
89                                                     GCancellable         *cancellabl,
90                                                     GAsyncReadyCallback   callback,
91                                                     gpointer              data);
92 static gboolean g_filter_input_stream_close_finish (GInputStream         *stream,
93                                                     GAsyncResult         *result,
94                                                     GError              **error);
95
96 G_DEFINE_TYPE (GFilterInputStream, g_filter_input_stream, G_TYPE_INPUT_STREAM)
97
98 #define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \
99   G_TYPE_FILTER_INPUT_STREAM, GFilterInputStreamPrivate)
100
101 typedef struct
102 {
103   gboolean close_base;
104 } GFilterInputStreamPrivate;
105
106 static void
107 g_filter_input_stream_class_init (GFilterInputStreamClass *klass)
108 {
109   GObjectClass *object_class;
110   GInputStreamClass *istream_class;
111
112   object_class = G_OBJECT_CLASS (klass);
113   object_class->get_property = g_filter_input_stream_get_property;
114   object_class->set_property = g_filter_input_stream_set_property;
115   object_class->finalize     = g_filter_input_stream_finalize;
116
117   istream_class = G_INPUT_STREAM_CLASS (klass);
118   istream_class->read_fn  = g_filter_input_stream_read;
119   istream_class->skip  = g_filter_input_stream_skip;
120   istream_class->close_fn = g_filter_input_stream_close;
121
122   istream_class->read_async   = g_filter_input_stream_read_async;
123   istream_class->read_finish  = g_filter_input_stream_read_finish;
124   istream_class->skip_async   = g_filter_input_stream_skip_async;
125   istream_class->skip_finish  = g_filter_input_stream_skip_finish;
126   istream_class->close_async  = g_filter_input_stream_close_async;
127   istream_class->close_finish = g_filter_input_stream_close_finish;
128
129   g_type_class_add_private (klass, sizeof (GFilterInputStreamPrivate));
130
131   g_object_class_install_property (object_class,
132                                    PROP_BASE_STREAM,
133                                    g_param_spec_object ("base-stream",
134                                                          P_("The Filter Base Stream"),
135                                                          P_("The underlying base stream the io ops will be done on"),
136                                                          G_TYPE_INPUT_STREAM,
137                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 
138                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
139
140   g_object_class_install_property (object_class,
141                                    PROP_CLOSE_BASE,
142                                    g_param_spec_boolean ("close-base-stream",
143                                                          P_("Close Base Stream"),
144                                                          P_("If the base stream be closed when the filter stream is"),
145                                                          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | 
146                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
147 }
148
149 static void
150 g_filter_input_stream_set_property (GObject         *object,
151                                     guint            prop_id,
152                                     const GValue    *value,
153                                     GParamSpec      *pspec)
154 {
155   GFilterInputStream *filter_stream;
156   GObject *obj;
157
158   filter_stream = G_FILTER_INPUT_STREAM (object);
159
160   switch (prop_id) 
161     {
162     case PROP_BASE_STREAM:
163       obj = g_value_dup_object (value);
164       filter_stream->base_stream = G_INPUT_STREAM (obj); 
165       break;
166
167     case PROP_CLOSE_BASE:
168       g_filter_input_stream_set_close_base_stream (filter_stream,
169                                                    g_value_get_boolean (value));
170       break;
171
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175     }
176
177 }
178
179 static void
180 g_filter_input_stream_get_property (GObject    *object,
181                                     guint       prop_id,
182                                     GValue     *value,
183                                     GParamSpec *pspec)
184 {
185   GFilterInputStream *filter_stream;
186
187   filter_stream = G_FILTER_INPUT_STREAM (object);
188
189   switch (prop_id)
190     {
191     case PROP_BASE_STREAM:
192       g_value_set_object (value, filter_stream->base_stream);
193       break;
194
195     case PROP_CLOSE_BASE:
196       g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base);
197       break;
198
199     default:
200       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
201       break;
202     }
203
204 }
205
206 static void
207 g_filter_input_stream_finalize (GObject *object)
208 {
209   GFilterInputStream *stream;
210
211   stream = G_FILTER_INPUT_STREAM (object);
212
213   g_object_unref (stream->base_stream);
214
215   G_OBJECT_CLASS (g_filter_input_stream_parent_class)->finalize (object);
216 }
217
218 static void
219 g_filter_input_stream_init (GFilterInputStream *stream)
220 {
221
222 }
223
224 /**
225  * g_filter_input_stream_get_base_stream:
226  * @stream: a #GFilterInputStream.
227  * 
228  * Gets the base stream for the filter stream.
229  *
230  * Returns: a #GInputStream.
231  **/
232 GInputStream *
233 g_filter_input_stream_get_base_stream (GFilterInputStream *stream)
234 {
235   g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), NULL);
236
237   return stream->base_stream;
238 }
239
240 /**
241  * g_filter_input_stream_get_close_base_stream:
242  * @stream: a #GFilterInputStream.
243  *
244  * Returns whether the base stream will be closed when @stream is
245  * closed.
246  *
247  * Return value: %TRUE if the base stream will be closed.
248  **/
249 gboolean
250 g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream)
251 {
252   g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), FALSE);
253
254   return GET_PRIVATE (stream)->close_base;
255 }
256
257 /**
258  * g_filter_input_stream_set_close_base_stream:
259  * @stream: a #GFilterInputStream.
260  * @close_base: %TRUE to close the base stream.
261  *
262  * Sets whether the base stream will be closed when @stream is closed.
263  **/
264 void
265 g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream,
266                                              gboolean            close_base)
267 {
268   GFilterInputStreamPrivate *priv;
269
270   g_return_if_fail (G_IS_FILTER_INPUT_STREAM (stream));
271
272   close_base = !!close_base;
273  
274   priv = GET_PRIVATE (stream);
275
276   if (priv->close_base != close_base)
277     {
278       priv->close_base = close_base;
279       g_object_notify (G_OBJECT (stream), "close-base-stream");
280     }
281 }
282
283 static gssize
284 g_filter_input_stream_read (GInputStream  *stream,
285                             void          *buffer,
286                             gsize          count,
287                             GCancellable  *cancellable,
288                             GError       **error)
289 {
290   GFilterInputStream *filter_stream;
291   GInputStream       *base_stream;
292   gssize              nread;
293
294   filter_stream = G_FILTER_INPUT_STREAM (stream);
295   base_stream = filter_stream->base_stream;
296
297   nread = g_input_stream_read (base_stream,
298                                buffer,
299                                count,
300                                cancellable,
301                                error);
302
303   return nread;
304 }
305
306 static gssize
307 g_filter_input_stream_skip (GInputStream  *stream,
308                             gsize          count,
309                             GCancellable  *cancellable,
310                             GError       **error)
311 {
312   GFilterInputStream *filter_stream;
313   GInputStream       *base_stream;
314   gssize              nskipped;
315
316   filter_stream = G_FILTER_INPUT_STREAM (stream);
317   base_stream = filter_stream->base_stream;
318
319   nskipped = g_input_stream_skip (base_stream,
320                                   count,
321                                   cancellable,
322                                   error);
323   return nskipped;
324 }
325
326 static gboolean
327 g_filter_input_stream_close (GInputStream  *stream,
328                              GCancellable  *cancellable,
329                              GError       **error)
330 {
331   gboolean res = TRUE;
332
333   if (GET_PRIVATE (stream)->close_base)
334     {
335       GFilterInputStream *filter_stream;
336       GInputStream       *base_stream;
337
338       filter_stream = G_FILTER_INPUT_STREAM (stream);
339       base_stream = filter_stream->base_stream;
340
341       res = g_input_stream_close (base_stream,
342                                   cancellable,
343                                   error);
344     }
345
346   return res;
347 }
348
349 static void
350 g_filter_input_stream_read_async (GInputStream        *stream,
351                                   void                *buffer,
352                                   gsize                count,
353                                   int                  io_priority,
354                                   GCancellable        *cancellable,
355                                   GAsyncReadyCallback  callback,
356                                   gpointer             user_data)
357 {
358   GFilterInputStream *filter_stream;
359   GInputStream       *base_stream;
360
361   filter_stream = G_FILTER_INPUT_STREAM (stream);
362   base_stream = filter_stream->base_stream;
363
364   g_input_stream_read_async (base_stream,
365                              buffer,
366                              count,
367                              io_priority,
368                              cancellable,
369                              callback,
370                              user_data);
371 }
372
373 static gssize
374 g_filter_input_stream_read_finish (GInputStream  *stream,
375                                    GAsyncResult  *result,
376                                    GError       **error)
377 {
378   GFilterInputStream *filter_stream;
379   GInputStream       *base_stream;
380   gssize nread;
381
382   filter_stream = G_FILTER_INPUT_STREAM (stream);
383   base_stream = filter_stream->base_stream;
384
385   nread = g_input_stream_read_finish (base_stream,
386                                       result,
387                                       error);
388   
389   return nread;
390 }
391
392 static void
393 g_filter_input_stream_skip_async (GInputStream        *stream,
394                                   gsize                count,
395                                   int                  io_priority,
396                                   GCancellable        *cancellable,
397                                   GAsyncReadyCallback  callback,
398                                   gpointer             user_data)
399 {
400   GFilterInputStream *filter_stream;
401   GInputStream       *base_stream;
402
403   filter_stream = G_FILTER_INPUT_STREAM (stream);
404   base_stream = filter_stream->base_stream;
405
406   g_input_stream_skip_async (base_stream,
407                              count,
408                              io_priority,
409                              cancellable,
410                              callback,
411                              user_data);
412
413 }
414
415 static gssize
416 g_filter_input_stream_skip_finish (GInputStream  *stream,
417                                    GAsyncResult  *result,
418                                    GError       **error)
419 {
420   GFilterInputStream *filter_stream;
421   GInputStream       *base_stream;
422   gssize nskipped;
423
424   filter_stream = G_FILTER_INPUT_STREAM (stream);
425   base_stream = filter_stream->base_stream;
426
427   nskipped = g_input_stream_skip_finish (base_stream,
428                                          result,
429                                          error);
430
431   return nskipped;
432 }
433
434 static void
435 g_filter_input_stream_close_ready (GObject       *object,
436                                    GAsyncResult  *result,
437                                    gpointer       user_data)
438 {
439   GSimpleAsyncResult *simple = user_data;
440   GError *error = NULL;
441
442   g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error);
443
444   if (error)
445     {
446       g_simple_async_result_set_from_error (simple, error);
447       g_error_free (error);
448     }
449
450   g_simple_async_result_complete (simple);
451   g_object_unref (simple);
452 }
453
454 static void
455 g_filter_input_stream_close_async (GInputStream        *stream,
456                                    int                  io_priority,
457                                    GCancellable        *cancellable,
458                                    GAsyncReadyCallback  callback,
459                                    gpointer             user_data)
460 {
461   GSimpleAsyncResult *simple;
462
463   simple = g_simple_async_result_new (G_OBJECT (stream),
464                                       callback, user_data,
465                                       g_filter_input_stream_close_async);
466
467   if (GET_PRIVATE (stream)->close_base)
468     {
469       GFilterInputStream *filter_stream = G_FILTER_INPUT_STREAM (stream);
470
471       g_input_stream_close_async (filter_stream->base_stream,
472                                   io_priority, cancellable,
473                                   g_filter_input_stream_close_ready,
474                                   g_object_ref (simple));
475     }
476   else
477     /* do nothing */
478     g_simple_async_result_complete_in_idle (simple);
479
480   g_object_unref (simple);
481 }
482
483 static gboolean
484 g_filter_input_stream_close_finish (GInputStream  *stream,
485                                     GAsyncResult  *result,
486                                     GError       **error)
487 {
488   GSimpleAsyncResult *simple;
489
490   g_return_val_if_fail (g_simple_async_result_is_valid (
491     result, G_OBJECT (stream), g_filter_input_stream_close_async), FALSE);
492
493   simple = G_SIMPLE_ASYNC_RESULT (result);
494
495   return !g_simple_async_result_propagate_error (simple, error);
496 }
497
498 #define __G_FILTER_INPUT_STREAM_C__
499 #include "gioaliasdef.c"