mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +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