mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 16:32:18 +01:00 
			
		
		
		
	Bug 568394 – dropping the last reference to a stream filter closes the
2009-01-20 Ryan Lortie <desrt@desrt.ca> Bug 568394 – dropping the last reference to a stream filter closes the base stream * gfilterinputstream.h: * gfilterinputstream.c: add "close-base-stream" property and only close the base stream if it is true. issue async close callbacks from correct source object. * gfilteroutputstream.h: * gfilteroutputstream.c: add a "close-base-stream" property and only close the base stream if it is true. issue async close callbacks from correct source object. * gbufferedoutputstream: check g_filter_output_stream_get_close_base() before closing the base stream. fix invalid source tag comparison in close_async (was comparing to flush_async). * ../docs/reference/gio/gio-sections.txt: * gio.symbols: add g_filter_{in,out}put_stream_{g,s}et_close_base_stream * tests/filter-streams.c: new test cases * tests/Makefile.am: add new test * tests/.gitignore: add new test svn path=/trunk/; revision=7825
This commit is contained in:
		| @@ -518,6 +518,8 @@ GFileInputStreamPrivate | ||||
| <TITLE>GFilterInputStream</TITLE> | ||||
| GFilterInputStream | ||||
| g_filter_input_stream_get_base_stream | ||||
| g_filter_input_stream_get_close_base_stream | ||||
| g_filter_input_stream_set_close_base_stream | ||||
| <SUBSECTION Standard> | ||||
| GFilterInputStreamClass | ||||
| G_FILTER_INPUT_STREAM | ||||
| @@ -694,6 +696,8 @@ GFileOutputStreamPrivate | ||||
| <TITLE>GFilterOutputStream</TITLE> | ||||
| GFilterOutputStream | ||||
| g_filter_output_stream_get_base_stream | ||||
| g_filter_output_stream_get_close_base_stream | ||||
| g_filter_output_stream_set_close_base_stream | ||||
| <SUBSECTION Standard> | ||||
| GFilterOutputStreamClass | ||||
| G_FILTER_OUTPUT_STREAM | ||||
|   | ||||
| @@ -1,3 +1,26 @@ | ||||
| 2009-01-20  Ryan Lortie  <desrt@desrt.ca> | ||||
|  | ||||
| 	Bug 568394 – dropping the last reference to a stream filter closes the | ||||
| 	base stream | ||||
|  | ||||
| 	* gfilterinputstream.h: | ||||
| 	* gfilterinputstream.c: add "close-base-stream" property and only | ||||
| 	close the base stream if it is true.  issue async close callbacks from | ||||
| 	correct source object. | ||||
| 	* gfilteroutputstream.h: | ||||
| 	* gfilteroutputstream.c: add a "close-base-stream" property and only | ||||
| 	close the base stream if it is true.  issue async close callbacks from | ||||
| 	correct source object. | ||||
| 	* gbufferedoutputstream: check g_filter_output_stream_get_close_base() | ||||
| 	before closing the base stream.  fix invalid source tag comparison in | ||||
| 	close_async (was comparing to flush_async). | ||||
| 	* ../docs/reference/gio/gio-sections.txt: | ||||
| 	* gio.symbols: add | ||||
| 	g_filter_{in,out}put_stream_{g,s}et_close_base_stream | ||||
| 	* tests/filter-streams.c: new test cases | ||||
| 	* tests/Makefile.am: add new test | ||||
| 	* tests/.gitignore: add new test | ||||
|  | ||||
| 2009-01-19  Matthias Clasen  <mclasen@redhat.com> | ||||
|  | ||||
| 	* gdesktopappinfo.c (g_desktop_app_info_new): Expand the docs. | ||||
|   | ||||
| @@ -508,11 +508,14 @@ g_buffered_output_stream_close (GOutputStream  *stream, | ||||
|  | ||||
|   res = flush_buffer (bstream, cancellable, error); | ||||
|  | ||||
|   /* report the first error but still close the stream */ | ||||
|   if (res) | ||||
|     res = g_output_stream_close (base_stream, cancellable, error);  | ||||
|   else | ||||
|     g_output_stream_close (base_stream, cancellable, NULL);  | ||||
|   if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream))) | ||||
|     { | ||||
|       /* report the first error but still close the stream */ | ||||
|       if (res) | ||||
|         res = g_output_stream_close (base_stream, cancellable, error);  | ||||
|       else | ||||
|         g_output_stream_close (base_stream, cancellable, NULL);  | ||||
|     } | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| @@ -569,10 +572,13 @@ flush_buffer_thread (GSimpleAsyncResult *result, | ||||
|       /* if flushing the buffer or the stream returned  | ||||
|        * an error report that first error but still try  | ||||
|        * close the stream */ | ||||
|       if (res == FALSE) | ||||
|         g_output_stream_close (base_stream, cancellable, NULL); | ||||
|       else  | ||||
|         res = g_output_stream_close (base_stream, cancellable, &error); | ||||
|       if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream))) | ||||
|         { | ||||
|           if (res == FALSE) | ||||
|             g_output_stream_close (base_stream, cancellable, NULL); | ||||
|           else  | ||||
|             res = g_output_stream_close (base_stream, cancellable, &error); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   if (res == FALSE) | ||||
| @@ -758,7 +764,7 @@ g_buffered_output_stream_close_finish (GOutputStream        *stream, | ||||
|   simple = G_SIMPLE_ASYNC_RESULT (result); | ||||
|  | ||||
|   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==  | ||||
|             g_buffered_output_stream_flush_async); | ||||
|             g_buffered_output_stream_close_async); | ||||
|  | ||||
|   return TRUE; | ||||
| } | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
| #include "config.h" | ||||
| #include "gfilterinputstream.h" | ||||
| #include "ginputstream.h" | ||||
| #include "gsimpleasyncresult.h" | ||||
| #include "glibintl.h" | ||||
|  | ||||
| #include "gioalias.h" | ||||
| @@ -36,7 +37,8 @@ | ||||
|  | ||||
| enum { | ||||
|   PROP_0, | ||||
|   PROP_BASE_STREAM | ||||
|   PROP_BASE_STREAM, | ||||
|   PROP_CLOSE_BASE | ||||
| }; | ||||
|  | ||||
| static void     g_filter_input_stream_set_property (GObject      *object, | ||||
| @@ -93,6 +95,13 @@ static gboolean g_filter_input_stream_close_finish (GInputStream         *stream | ||||
|  | ||||
| G_DEFINE_TYPE (GFilterInputStream, g_filter_input_stream, G_TYPE_INPUT_STREAM) | ||||
|  | ||||
| #define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \ | ||||
|   G_TYPE_FILTER_INPUT_STREAM, GFilterInputStreamPrivate) | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   gboolean close_base; | ||||
| } GFilterInputStreamPrivate; | ||||
|  | ||||
| static void | ||||
| g_filter_input_stream_class_init (GFilterInputStreamClass *klass) | ||||
| @@ -117,6 +126,8 @@ g_filter_input_stream_class_init (GFilterInputStreamClass *klass) | ||||
|   istream_class->close_async  = g_filter_input_stream_close_async; | ||||
|   istream_class->close_finish = g_filter_input_stream_close_finish; | ||||
|  | ||||
|   g_type_class_add_private (klass, sizeof (GFilterInputStreamPrivate)); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_BASE_STREAM, | ||||
|                                    g_param_spec_object ("base-stream", | ||||
| @@ -126,6 +137,13 @@ g_filter_input_stream_class_init (GFilterInputStreamClass *klass) | ||||
|                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |  | ||||
|                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_CLOSE_BASE, | ||||
|                                    g_param_spec_boolean ("close-base-stream", | ||||
|                                                          P_("Close Base Stream"), | ||||
|                                                          P_("If the base stream be closed when the filter stream is"), | ||||
|                                                          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |  | ||||
|                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -146,6 +164,11 @@ g_filter_input_stream_set_property (GObject         *object, | ||||
|       filter_stream->base_stream = G_INPUT_STREAM (obj);  | ||||
|       break; | ||||
|  | ||||
|     case PROP_CLOSE_BASE: | ||||
|       g_filter_input_stream_set_close_base_stream (filter_stream, | ||||
|                                                    g_value_get_boolean (value)); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
| @@ -169,6 +192,10 @@ g_filter_input_stream_get_property (GObject    *object, | ||||
|       g_value_set_object (value, filter_stream->base_stream); | ||||
|       break; | ||||
|  | ||||
|     case PROP_CLOSE_BASE: | ||||
|       g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
| @@ -210,6 +237,49 @@ g_filter_input_stream_get_base_stream (GFilterInputStream *stream) | ||||
|   return stream->base_stream; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * g_filter_input_stream_get_close_base_stream: | ||||
|  * @stream: a #GFilterInputStream. | ||||
|  * | ||||
|  * Returns whether the base stream will be closed when @stream is | ||||
|  * closed. | ||||
|  * | ||||
|  * Return value: %TRUE if the base stream will be closed. | ||||
|  **/ | ||||
| gboolean | ||||
| g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream) | ||||
| { | ||||
|   g_return_val_if_fail (G_IS_FILTER_INPUT_STREAM (stream), FALSE); | ||||
|  | ||||
|   return GET_PRIVATE (stream)->close_base; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * g_filter_input_stream_set_close_base_stream: | ||||
|  * @stream: a #GFilterInputStream. | ||||
|  * @close_base: %TRUE to close the base stream. | ||||
|  * | ||||
|  * Sets whether the base stream will be closed when @stream is closed. | ||||
|  **/ | ||||
| void | ||||
| g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream, | ||||
|                                              gboolean            close_base) | ||||
| { | ||||
|   GFilterInputStreamPrivate *priv; | ||||
|  | ||||
|   g_return_if_fail (G_IS_FILTER_INPUT_STREAM (stream)); | ||||
|  | ||||
|   close_base = !!close_base; | ||||
|   | ||||
|   priv = GET_PRIVATE (stream); | ||||
|  | ||||
|   if (priv->close_base != close_base) | ||||
|     { | ||||
|       priv->close_base = close_base; | ||||
|       g_object_notify (G_OBJECT (stream), "close-base-stream"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static gssize | ||||
| g_filter_input_stream_read (GInputStream  *stream, | ||||
|                             void          *buffer, | ||||
| @@ -258,16 +328,20 @@ g_filter_input_stream_close (GInputStream  *stream, | ||||
|                              GCancellable  *cancellable, | ||||
|                              GError       **error) | ||||
| { | ||||
|   GFilterInputStream *filter_stream; | ||||
|   GInputStream       *base_stream; | ||||
|   gboolean            res; | ||||
|   gboolean res = TRUE; | ||||
|  | ||||
|   filter_stream = G_FILTER_INPUT_STREAM (stream); | ||||
|   base_stream = filter_stream->base_stream; | ||||
|   if (GET_PRIVATE (stream)->close_base) | ||||
|     { | ||||
|       GFilterInputStream *filter_stream; | ||||
|       GInputStream       *base_stream; | ||||
|  | ||||
|   res = g_input_stream_close (base_stream, | ||||
|                               cancellable, | ||||
|                               error); | ||||
|       filter_stream = G_FILTER_INPUT_STREAM (stream); | ||||
|       base_stream = filter_stream->base_stream; | ||||
|  | ||||
|       res = g_input_stream_close (base_stream, | ||||
|                                   cancellable, | ||||
|                                   error); | ||||
|     } | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| @@ -357,6 +431,26 @@ g_filter_input_stream_skip_finish (GInputStream  *stream, | ||||
|   return nskipped; | ||||
| } | ||||
|  | ||||
| static void | ||||
| g_filter_input_stream_close_ready (GObject       *object, | ||||
|                                    GAsyncResult  *result, | ||||
|                                    gpointer       user_data) | ||||
| { | ||||
|   GSimpleAsyncResult *simple = user_data; | ||||
|   GError *error = NULL; | ||||
|  | ||||
|   g_input_stream_close_finish (G_INPUT_STREAM (object), result, &error); | ||||
|  | ||||
|   if (error) | ||||
|     { | ||||
|       g_simple_async_result_set_from_error (simple, error); | ||||
|       g_error_free (error); | ||||
|     } | ||||
|  | ||||
|   g_simple_async_result_complete (simple); | ||||
|   g_object_unref (simple); | ||||
| } | ||||
|  | ||||
| static void | ||||
| g_filter_input_stream_close_async (GInputStream        *stream, | ||||
|                                    int                  io_priority, | ||||
| @@ -364,17 +458,26 @@ g_filter_input_stream_close_async (GInputStream        *stream, | ||||
|                                    GAsyncReadyCallback  callback, | ||||
|                                    gpointer             user_data) | ||||
| { | ||||
|   GFilterInputStream *filter_stream; | ||||
|   GInputStream       *base_stream; | ||||
|   GSimpleAsyncResult *simple; | ||||
|  | ||||
|   filter_stream = G_FILTER_INPUT_STREAM (stream); | ||||
|   base_stream = filter_stream->base_stream; | ||||
|   simple = g_simple_async_result_new (G_OBJECT (stream), | ||||
|                                       callback, user_data, | ||||
|                                       g_filter_input_stream_close_async); | ||||
|  | ||||
|   g_input_stream_close_async (base_stream, | ||||
|                               io_priority, | ||||
|                               cancellable, | ||||
|                               callback, | ||||
|                               user_data); | ||||
|   if (GET_PRIVATE (stream)->close_base) | ||||
|     { | ||||
|       GFilterInputStream *filter_stream = G_FILTER_INPUT_STREAM (stream); | ||||
|  | ||||
|       g_input_stream_close_async (filter_stream->base_stream, | ||||
|                                   io_priority, cancellable, | ||||
|                                   g_filter_input_stream_close_ready, | ||||
|                                   g_object_ref (simple)); | ||||
|     } | ||||
|   else | ||||
|     /* do nothing */ | ||||
|     g_simple_async_result_complete_in_idle (simple); | ||||
|  | ||||
|   g_object_unref (simple); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| @@ -382,18 +485,14 @@ g_filter_input_stream_close_finish (GInputStream  *stream, | ||||
|                                     GAsyncResult  *result, | ||||
|                                     GError       **error) | ||||
| { | ||||
|   GFilterInputStream *filter_stream; | ||||
|   GInputStream       *base_stream; | ||||
|   gboolean res; | ||||
|   GSimpleAsyncResult *simple; | ||||
|  | ||||
|   filter_stream = G_FILTER_INPUT_STREAM (stream); | ||||
|   base_stream = filter_stream->base_stream; | ||||
|   g_return_val_if_fail (g_simple_async_result_is_valid ( | ||||
|     result, G_OBJECT (stream), g_filter_input_stream_close_async), FALSE); | ||||
|  | ||||
|   res = g_input_stream_close_finish (stream, | ||||
|                                      result, | ||||
|                                      error); | ||||
|   simple = G_SIMPLE_ASYNC_RESULT (result); | ||||
|  | ||||
|   return res; | ||||
|   return !g_simple_async_result_propagate_error (simple, error); | ||||
| } | ||||
|  | ||||
| #define __G_FILTER_INPUT_STREAM_C__ | ||||
|   | ||||
| @@ -44,7 +44,6 @@ G_BEGIN_DECLS | ||||
|  * A base class for all input streams that work on an underlying stream. | ||||
|  **/ | ||||
| typedef struct _GFilterInputStreamClass    GFilterInputStreamClass; | ||||
| typedef struct _GFilterInputStreamPrivate  GFilterInputStreamPrivate; | ||||
|  | ||||
| struct _GFilterInputStream | ||||
| { | ||||
| @@ -66,8 +65,11 @@ struct _GFilterInputStreamClass | ||||
| }; | ||||
|  | ||||
|  | ||||
| GType          g_filter_input_stream_get_type        (void) G_GNUC_CONST; | ||||
| GInputStream * g_filter_input_stream_get_base_stream (GFilterInputStream *stream); | ||||
| GType          g_filter_input_stream_get_type              (void) G_GNUC_CONST; | ||||
| GInputStream * g_filter_input_stream_get_base_stream       (GFilterInputStream *stream); | ||||
| gboolean       g_filter_input_stream_get_close_base_stream (GFilterInputStream *stream); | ||||
| void           g_filter_input_stream_set_close_base_stream (GFilterInputStream *stream, | ||||
|                                                             gboolean            close_base); | ||||
|  | ||||
| G_END_DECLS | ||||
|  | ||||
|   | ||||
| @@ -22,6 +22,7 @@ | ||||
|  | ||||
| #include "config.h" | ||||
| #include "gfilteroutputstream.h" | ||||
| #include "gsimpleasyncresult.h" | ||||
| #include "goutputstream.h" | ||||
| #include "glibintl.h" | ||||
|  | ||||
| @@ -36,7 +37,8 @@ | ||||
|  | ||||
| enum { | ||||
|   PROP_0, | ||||
|   PROP_BASE_STREAM | ||||
|   PROP_BASE_STREAM, | ||||
|   PROP_CLOSE_BASE | ||||
| }; | ||||
|  | ||||
| static void     g_filter_output_stream_set_property (GObject      *object, | ||||
| @@ -93,7 +95,13 @@ static gboolean g_filter_output_stream_close_finish (GOutputStream        *strea | ||||
|  | ||||
| G_DEFINE_TYPE (GFilterOutputStream, g_filter_output_stream, G_TYPE_OUTPUT_STREAM) | ||||
|  | ||||
| #define GET_PRIVATE(inst) G_TYPE_INSTANCE_GET_PRIVATE (inst, \ | ||||
|   G_TYPE_FILTER_OUTPUT_STREAM, GFilterOutputStreamPrivate) | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|   gboolean close_base; | ||||
| } GFilterOutputStreamPrivate; | ||||
|  | ||||
| static void | ||||
| g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) | ||||
| @@ -117,6 +125,8 @@ g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) | ||||
|   ostream_class->close_async  = g_filter_output_stream_close_async; | ||||
|   ostream_class->close_finish = g_filter_output_stream_close_finish; | ||||
|  | ||||
|   g_type_class_add_private (klass, sizeof (GFilterOutputStreamPrivate)); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_BASE_STREAM, | ||||
|                                    g_param_spec_object ("base-stream", | ||||
| @@ -126,6 +136,13 @@ g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) | ||||
|                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |  | ||||
|                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); | ||||
|  | ||||
|   g_object_class_install_property (object_class, | ||||
|                                    PROP_CLOSE_BASE, | ||||
|                                    g_param_spec_boolean ("close-base-stream", | ||||
|                                                          P_("Close Base Stream"), | ||||
|                                                          P_("If the base stream be closed when the filter stream is"), | ||||
|                                                          TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | | ||||
|                                                          G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); | ||||
| } | ||||
|  | ||||
| static void | ||||
| @@ -146,6 +163,11 @@ g_filter_output_stream_set_property (GObject      *object, | ||||
|       filter_stream->base_stream = G_OUTPUT_STREAM (obj); | ||||
|       break; | ||||
|  | ||||
|     case PROP_CLOSE_BASE: | ||||
|       g_filter_output_stream_set_close_base_stream (filter_stream, | ||||
|                                                     g_value_get_boolean (value)); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
| @@ -169,6 +191,10 @@ g_filter_output_stream_get_property (GObject    *object, | ||||
|       g_value_set_object (value, filter_stream->base_stream); | ||||
|       break; | ||||
|  | ||||
|     case PROP_CLOSE_BASE: | ||||
|       g_value_set_boolean (value, GET_PRIVATE (filter_stream)->close_base); | ||||
|       break; | ||||
|  | ||||
|     default: | ||||
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | ||||
|       break; | ||||
| @@ -214,6 +240,49 @@ g_filter_output_stream_get_base_stream (GFilterOutputStream *stream) | ||||
|   return stream->base_stream; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * g_filter_output_stream_get_close_base_stream: | ||||
|  * @stream: a #GFilterOutputStream. | ||||
|  * | ||||
|  * Returns whether the base stream will be closed when @stream is | ||||
|  * closed. | ||||
|  * | ||||
|  * Return value: %TRUE if the base stream will be closed. | ||||
|  **/ | ||||
| gboolean | ||||
| g_filter_output_stream_get_close_base_stream (GFilterOutputStream *stream) | ||||
| { | ||||
|   g_return_val_if_fail (G_IS_FILTER_OUTPUT_STREAM (stream), FALSE); | ||||
|  | ||||
|   return GET_PRIVATE (stream)->close_base; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * g_filter_output_stream_set_close_base_stream: | ||||
|  * @stream: a #GFilterOutputStream. | ||||
|  * @close_base: %TRUE to close the base stream. | ||||
|  * | ||||
|  * Sets whether the base stream will be closed when @stream is closed. | ||||
|  **/ | ||||
| void | ||||
| g_filter_output_stream_set_close_base_stream (GFilterOutputStream *stream, | ||||
|                                               gboolean             close_base) | ||||
| { | ||||
|   GFilterOutputStreamPrivate *priv; | ||||
|  | ||||
|   g_return_if_fail (G_IS_FILTER_OUTPUT_STREAM (stream)); | ||||
|  | ||||
|   close_base = !!close_base; | ||||
|  | ||||
|   priv = GET_PRIVATE (stream); | ||||
|  | ||||
|   if (priv->close_base != close_base) | ||||
|     { | ||||
|       priv->close_base = close_base; | ||||
|       g_object_notify (G_OBJECT (stream), "close-base-stream"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static gssize | ||||
| g_filter_output_stream_write (GOutputStream  *stream, | ||||
|                               const void     *buffer, | ||||
| @@ -257,14 +326,18 @@ g_filter_output_stream_close (GOutputStream  *stream, | ||||
|                               GCancellable   *cancellable, | ||||
|                               GError        **error) | ||||
| { | ||||
|   GFilterOutputStream *filter_stream; | ||||
|   gboolean res; | ||||
|   gboolean res = TRUE; | ||||
|  | ||||
|   filter_stream = G_FILTER_OUTPUT_STREAM (stream); | ||||
|   if (GET_PRIVATE (stream)->close_base) | ||||
|     { | ||||
|       GFilterOutputStream *filter_stream; | ||||
|  | ||||
|   res = g_output_stream_close (filter_stream->base_stream, | ||||
|                                cancellable, | ||||
|                                error); | ||||
|       filter_stream = G_FILTER_OUTPUT_STREAM (stream); | ||||
|  | ||||
|       res = g_output_stream_close (filter_stream->base_stream, | ||||
|                                    cancellable, | ||||
|                                    error); | ||||
|     } | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| @@ -344,22 +417,53 @@ g_filter_output_stream_flush_finish (GOutputStream  *stream, | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| static void | ||||
| g_filter_output_stream_close_ready (GObject       *object, | ||||
|                                     GAsyncResult  *result, | ||||
|                                     gpointer       user_data) | ||||
| { | ||||
|   GSimpleAsyncResult *simple = user_data; | ||||
|   GError *error = NULL; | ||||
|  | ||||
|   g_output_stream_close_finish (G_OUTPUT_STREAM (object), result, &error); | ||||
|  | ||||
|   if (error) | ||||
|     { | ||||
|       g_simple_async_result_set_from_error (simple, error); | ||||
|       g_error_free (error); | ||||
|     } | ||||
|  | ||||
|   g_simple_async_result_complete (simple); | ||||
|   g_object_unref (simple); | ||||
| } | ||||
|  | ||||
| static void | ||||
| g_filter_output_stream_close_async (GOutputStream       *stream, | ||||
|                                     int                  io_priority, | ||||
|                                     GCancellable        *cancellable, | ||||
|                                     GAsyncReadyCallback  callback, | ||||
|                                     gpointer             data) | ||||
|                                     gpointer             user_data) | ||||
| { | ||||
|   GFilterOutputStream *filter_stream; | ||||
|   GSimpleAsyncResult *simple; | ||||
|  | ||||
|   filter_stream = G_FILTER_OUTPUT_STREAM (stream); | ||||
|   simple = g_simple_async_result_new (G_OBJECT (stream), | ||||
|                                       callback, user_data, | ||||
|                                       g_filter_output_stream_close_async); | ||||
|  | ||||
|   g_output_stream_close_async (filter_stream->base_stream, | ||||
|                                io_priority, | ||||
|                                cancellable, | ||||
|                                callback, | ||||
|                                data); | ||||
|   if (GET_PRIVATE (stream)->close_base) | ||||
|     { | ||||
|       GFilterOutputStream *filter_stream = G_FILTER_OUTPUT_STREAM (stream); | ||||
|  | ||||
|       g_output_stream_close_async (filter_stream->base_stream, | ||||
|                                   io_priority, cancellable, | ||||
|                                   g_filter_output_stream_close_ready, | ||||
|                                   g_object_ref (simple)); | ||||
|     } | ||||
|   else | ||||
|     /* do nothing */ | ||||
|     g_simple_async_result_complete_in_idle (simple); | ||||
|  | ||||
|   g_object_unref (simple); | ||||
| } | ||||
|  | ||||
| static gboolean | ||||
| @@ -367,16 +471,14 @@ g_filter_output_stream_close_finish (GOutputStream  *stream, | ||||
|                                      GAsyncResult   *result, | ||||
|                                      GError        **error) | ||||
| { | ||||
|   GFilterOutputStream *filter_stream; | ||||
|   gboolean res; | ||||
|   GSimpleAsyncResult *simple; | ||||
|  | ||||
|   filter_stream = G_FILTER_OUTPUT_STREAM (stream); | ||||
|   g_return_val_if_fail (g_simple_async_result_is_valid ( | ||||
|     result, G_OBJECT (stream), g_filter_output_stream_close_async), FALSE); | ||||
|  | ||||
|   res = g_output_stream_close_finish (filter_stream->base_stream, | ||||
|                                       result, | ||||
|                                       error); | ||||
|   simple = G_SIMPLE_ASYNC_RESULT (result); | ||||
|  | ||||
|   return res; | ||||
|   return !g_simple_async_result_propagate_error (simple, error); | ||||
| } | ||||
|  | ||||
| #define __G_FILTER_OUTPUT_STREAM_C__ | ||||
|   | ||||
| @@ -44,7 +44,6 @@ G_BEGIN_DECLS | ||||
|  * A base class for all output streams that work on an underlying stream. | ||||
|  **/ | ||||
| typedef struct _GFilterOutputStreamClass    GFilterOutputStreamClass; | ||||
| typedef struct _GFilterOutputStreamPrivate  GFilterOutputStreamPrivate; | ||||
|  | ||||
| struct _GFilterOutputStream | ||||
| { | ||||
| @@ -66,8 +65,11 @@ struct _GFilterOutputStreamClass | ||||
| }; | ||||
|  | ||||
|  | ||||
| GType           g_filter_output_stream_get_type        (void) G_GNUC_CONST; | ||||
| GOutputStream * g_filter_output_stream_get_base_stream (GFilterOutputStream *stream); | ||||
| GType           g_filter_output_stream_get_type              (void) G_GNUC_CONST; | ||||
| GOutputStream * g_filter_output_stream_get_base_stream       (GFilterOutputStream *stream); | ||||
| gboolean        g_filter_output_stream_get_close_base_stream (GFilterOutputStream *stream); | ||||
| void            g_filter_output_stream_set_close_base_stream (GFilterOutputStream *stream, | ||||
|                                                               gboolean             close_base); | ||||
|  | ||||
| G_END_DECLS | ||||
|  | ||||
|   | ||||
| @@ -456,6 +456,8 @@ g_file_output_stream_get_etag | ||||
| #if IN_FILE(__G_FILTER_INPUT_STREAM_C__) | ||||
| g_filter_input_stream_get_type  G_GNUC_CONST | ||||
| g_filter_input_stream_get_base_stream  | ||||
| g_filter_input_stream_get_close_base_stream | ||||
| g_filter_input_stream_set_close_base_stream | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
| @@ -463,6 +465,8 @@ g_filter_input_stream_get_base_stream | ||||
| #if IN_FILE(__G_FILTER_OUTPUT_STREAM_C__) | ||||
| g_filter_output_stream_get_type  G_GNUC_CONST | ||||
| g_filter_output_stream_get_base_stream  | ||||
| g_filter_output_stream_get_close_base_stream | ||||
| g_filter_output_stream_set_close_base_stream | ||||
| #endif | ||||
| #endif | ||||
|  | ||||
|   | ||||
							
								
								
									
										1
									
								
								gio/tests/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								gio/tests/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -10,3 +10,4 @@ g-file-info | ||||
| live-g-file | ||||
| memory-input-stream | ||||
| memory-output-stream | ||||
| filter-streams | ||||
|   | ||||
| @@ -25,6 +25,7 @@ TEST_PROGS +=	 		\ | ||||
| 	data-output-stream 	\ | ||||
| 	g-icon			\ | ||||
| 	buffered-input-stream	\ | ||||
| 	filter-streams		\ | ||||
| 	simple-async-result | ||||
|  | ||||
| if OS_UNIX | ||||
| @@ -68,4 +69,7 @@ unix_streams_LDADD	  = $(progs_ldadd) \ | ||||
| simple_async_result_SOURCES	= simple-async-result.c | ||||
| simple_async_result_LDADD	= $(progs_ldadd) | ||||
|  | ||||
| filter_streams_SOURCES		= filter-streams.c | ||||
| filter_streams_LDADD		= $(progs_ldadd) | ||||
|  | ||||
| DISTCLEAN_FILES = applications/mimeinfo.cache | ||||
|   | ||||
							
								
								
									
										239
									
								
								gio/tests/filter-streams.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								gio/tests/filter-streams.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | ||||
| /* | ||||
|  * Copyright © 2009 Codethink Limited | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Lesser General Public License as published | ||||
|  * by the Free Software Foundation; either version 2 of the licence or (at | ||||
|  * your option) any later version. | ||||
|  * | ||||
|  * See the included COPYING file for more information. | ||||
|  * | ||||
|  * Author: Ryan Lortie <desrt@desrt.ca> | ||||
|  */ | ||||
|  | ||||
| #include <glib/glib.h> | ||||
| #include <gio/gio.h> | ||||
|  | ||||
| static void | ||||
| test_input_filter (void) | ||||
| { | ||||
|   GInputStream *base, *f1, *f2; | ||||
|  | ||||
|   g_test_bug ("568394"); | ||||
|   base = g_memory_input_stream_new_from_data ("abcdefghijk", -1, NULL); | ||||
|   f1 = g_buffered_input_stream_new (base); | ||||
|   f2 = g_buffered_input_stream_new (base); | ||||
|  | ||||
|   g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (f1), FALSE); | ||||
|  | ||||
|   g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base); | ||||
|   g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base); | ||||
|  | ||||
|   g_assert (!g_input_stream_is_closed (base)); | ||||
|   g_assert (!g_input_stream_is_closed (f1)); | ||||
|   g_assert (!g_input_stream_is_closed (f2)); | ||||
|  | ||||
|   g_object_unref (f1); | ||||
|  | ||||
|   g_assert (!g_input_stream_is_closed (base)); | ||||
|   g_assert (!g_input_stream_is_closed (f2)); | ||||
|  | ||||
|   g_object_unref (f2); | ||||
|  | ||||
|   g_assert (g_input_stream_is_closed (base)); | ||||
|  | ||||
|   g_object_unref (base); | ||||
| } | ||||
|  | ||||
| static void | ||||
| test_output_filter (void) | ||||
| { | ||||
|   GOutputStream *base, *f1, *f2; | ||||
|  | ||||
|   base = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); | ||||
|   f1 = g_buffered_output_stream_new (base); | ||||
|   f2 = g_buffered_output_stream_new (base); | ||||
|  | ||||
|   g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (f1), FALSE); | ||||
|  | ||||
|   g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base); | ||||
|   g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base); | ||||
|  | ||||
|   g_assert (!g_output_stream_is_closed (base)); | ||||
|   g_assert (!g_output_stream_is_closed (f1)); | ||||
|   g_assert (!g_output_stream_is_closed (f2)); | ||||
|  | ||||
|   g_object_unref (f1); | ||||
|  | ||||
|   g_assert (!g_output_stream_is_closed (base)); | ||||
|   g_assert (!g_output_stream_is_closed (f2)); | ||||
|  | ||||
|   g_object_unref (f2); | ||||
|  | ||||
|   g_assert (g_output_stream_is_closed (base)); | ||||
|  | ||||
|   g_object_unref (base); | ||||
| } | ||||
|  | ||||
| gpointer expected_obj; | ||||
| gpointer expected_data; | ||||
| gboolean callback_happened; | ||||
|  | ||||
| static void | ||||
| in_cb (GObject      *object, | ||||
|        GAsyncResult *result, | ||||
|        gpointer      user_data) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|  | ||||
|   g_assert (object == expected_obj); | ||||
|   g_assert (user_data == expected_data); | ||||
|   g_assert (callback_happened == FALSE); | ||||
|  | ||||
|   g_input_stream_close_finish (expected_obj, result, &error); | ||||
|   g_assert (error == NULL); | ||||
|  | ||||
|   callback_happened = TRUE; | ||||
| } | ||||
|  | ||||
| static void | ||||
| test_input_async (void) | ||||
| { | ||||
|   GInputStream *base, *f1, *f2; | ||||
|  | ||||
|   base = g_memory_input_stream_new_from_data ("abcdefghijk", -1, NULL); | ||||
|   f1 = g_buffered_input_stream_new (base); | ||||
|   f2 = g_buffered_input_stream_new (base); | ||||
|  | ||||
|   g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (f1), FALSE); | ||||
|  | ||||
|   g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f1)) == base); | ||||
|   g_assert (g_filter_input_stream_get_base_stream (G_FILTER_INPUT_STREAM (f2)) == base); | ||||
|  | ||||
|   g_assert (!g_input_stream_is_closed (base)); | ||||
|   g_assert (!g_input_stream_is_closed (f1)); | ||||
|   g_assert (!g_input_stream_is_closed (f2)); | ||||
|  | ||||
|   expected_obj = f1; | ||||
|   expected_data = g_malloc (20); | ||||
|   callback_happened = FALSE; | ||||
|   g_input_stream_close_async (f1, 0, NULL, in_cb, expected_data); | ||||
|  | ||||
|   g_assert (callback_happened == FALSE); | ||||
|   while (g_main_context_pending (NULL)) | ||||
|     g_main_context_iteration (NULL, FALSE); | ||||
|   g_assert (callback_happened == TRUE); | ||||
|  | ||||
|   g_assert (!g_input_stream_is_closed (base)); | ||||
|   g_assert (!g_input_stream_is_closed (f2)); | ||||
|   g_free (expected_data); | ||||
|   g_object_unref (f1); | ||||
|   g_assert (!g_input_stream_is_closed (base)); | ||||
|   g_assert (!g_input_stream_is_closed (f2)); | ||||
|  | ||||
|   expected_obj = f2; | ||||
|   expected_data = g_malloc (20); | ||||
|   callback_happened = FALSE; | ||||
|   g_input_stream_close_async (f2, 0, NULL, in_cb, expected_data); | ||||
|  | ||||
|   g_assert (callback_happened == FALSE); | ||||
|   while (g_main_context_pending (NULL)) | ||||
|     g_main_context_iteration (NULL, FALSE); | ||||
|   g_assert (callback_happened == TRUE); | ||||
|  | ||||
|   g_assert (g_input_stream_is_closed (base)); | ||||
|   g_assert (g_input_stream_is_closed (f2)); | ||||
|   g_free (expected_data); | ||||
|   g_object_unref (f2); | ||||
|  | ||||
|   g_assert (g_input_stream_is_closed (base)); | ||||
|   g_object_unref (base); | ||||
| } | ||||
|  | ||||
| static void | ||||
| out_cb (GObject      *object, | ||||
|         GAsyncResult *result, | ||||
|         gpointer      user_data) | ||||
| { | ||||
|   GError *error = NULL; | ||||
|  | ||||
|   g_assert (object == expected_obj); | ||||
|   g_assert (user_data == expected_data); | ||||
|   g_assert (callback_happened == FALSE); | ||||
|  | ||||
|   g_output_stream_close_finish (expected_obj, result, &error); | ||||
|   g_assert (error == NULL); | ||||
|  | ||||
|   callback_happened = TRUE; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void | ||||
| test_output_async (void) | ||||
| { | ||||
|   GOutputStream *base, *f1, *f2; | ||||
|  | ||||
|   base = g_memory_output_stream_new (NULL, 0, g_realloc, g_free); | ||||
|   f1 = g_buffered_output_stream_new (base); | ||||
|   f2 = g_buffered_output_stream_new (base); | ||||
|  | ||||
|   g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (f1), FALSE); | ||||
|  | ||||
|   g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f1)) == base); | ||||
|   g_assert (g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (f2)) == base); | ||||
|  | ||||
|   g_assert (!g_output_stream_is_closed (base)); | ||||
|   g_assert (!g_output_stream_is_closed (f1)); | ||||
|   g_assert (!g_output_stream_is_closed (f2)); | ||||
|  | ||||
|   expected_obj = f1; | ||||
|   expected_data = g_malloc (20); | ||||
|   callback_happened = FALSE; | ||||
|   g_output_stream_close_async (f1, 0, NULL, out_cb, expected_data); | ||||
|  | ||||
|   g_assert (callback_happened == FALSE); | ||||
|   while (g_main_context_pending (NULL)) | ||||
|     g_main_context_iteration (NULL, FALSE); | ||||
|   g_assert (callback_happened == TRUE); | ||||
|  | ||||
|   g_assert (!g_output_stream_is_closed (base)); | ||||
|   g_assert (!g_output_stream_is_closed (f2)); | ||||
|   g_free (expected_data); | ||||
|   g_object_unref (f1); | ||||
|   g_assert (!g_output_stream_is_closed (base)); | ||||
|   g_assert (!g_output_stream_is_closed (f2)); | ||||
|  | ||||
|   expected_obj = f2; | ||||
|   expected_data = g_malloc (20); | ||||
|   callback_happened = FALSE; | ||||
|   g_output_stream_close_async (f2, 0, NULL, out_cb, expected_data); | ||||
|  | ||||
|   g_assert (callback_happened == FALSE); | ||||
|   while (g_main_context_pending (NULL)) | ||||
|     g_main_context_iteration (NULL, FALSE); | ||||
|   g_assert (callback_happened == TRUE); | ||||
|  | ||||
|   g_assert (g_output_stream_is_closed (base)); | ||||
|   g_assert (g_output_stream_is_closed (f2)); | ||||
|   g_free (expected_data); | ||||
|   g_object_unref (f2); | ||||
|  | ||||
|   g_assert (g_output_stream_is_closed (base)); | ||||
|   g_object_unref (base); | ||||
| } | ||||
|  | ||||
|  | ||||
| int | ||||
| main (int argc, char **argv) | ||||
| { | ||||
|   g_test_init (&argc, &argv, NULL); | ||||
|   g_test_bug_base ("http://bugzilla.gnome.org/"); | ||||
|  | ||||
|   g_type_init (); | ||||
|   g_test_add_func ("/filter-stream/input", test_input_filter); | ||||
|   g_test_add_func ("/filter-stream/output", test_output_filter); | ||||
|   g_test_add_func ("/filter-stream/async-input", test_input_async); | ||||
|   g_test_add_func ("/filter-stream/async-output", test_output_async); | ||||
|  | ||||
|   return g_test_run(); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user