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