X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgbufferedoutputstream.c;h=ac9b45f053c0341a0fa5f19d27742f6a4f71d66d;hb=356a3987cee7ceddcb3fe623edf0bd2881895add;hp=3fb35e13ef9dc0911383377c8fdab115552d117f;hpb=a2ca589703273fca80cb126430a8b058aba3eb52;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gbufferedoutputstream.c b/gio/gbufferedoutputstream.c index 3fb35e1..ac9b45f 100644 --- a/gio/gbufferedoutputstream.c +++ b/gio/gbufferedoutputstream.c @@ -13,25 +13,24 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: Christian Kellner */ -#include +#include "config.h" #include "gbufferedoutputstream.h" #include "goutputstream.h" -#include "gsimpleasyncresult.h" +#include "gseekable.h" +#include "gtask.h" #include "string.h" +#include "gioerror.h" #include "glibintl.h" -#include - /** * SECTION:gbufferedoutputstream * @short_description: Buffered Output Stream + * @include: gio/gio.h * @see_also: #GFilterOutputStream, #GOutputStream * * Buffered output stream implements #GFilterOutputStream and provides @@ -39,19 +38,17 @@ * * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes. * - * To create a buffered output stream, use g_buffered_output_stream_new(), or - * g_buffered_output_stream_new_sized() to specify the buffer's size at construction. + * To create a buffered output stream, use g_buffered_output_stream_new(), + * or g_buffered_output_stream_new_sized() to specify the buffer's size + * at construction. * * To get the size of a buffer within a buffered input stream, use * g_buffered_output_stream_get_buffer_size(). To change the size of a - * buffered output stream's buffer, use g_buffered_output_stream_set_buffer_size(). - * Note: the buffer's size cannot be reduced below the size of the data within the - * buffer. - * + * buffered output stream's buffer, use + * g_buffered_output_stream_set_buffer_size(). Note that the buffer's + * size cannot be reduced below the size of the data within the buffer. **/ - - #define DEFAULT_BUFFER_SIZE 4096 struct _GBufferedOutputStreamPrivate { @@ -63,7 +60,8 @@ struct _GBufferedOutputStreamPrivate { enum { PROP_0, - PROP_BUFSIZE + PROP_BUFSIZE, + PROP_AUTO_GROW }; static void g_buffered_output_stream_set_property (GObject *object, @@ -90,16 +88,6 @@ static gboolean g_buffered_output_stream_close (GOutputStream *stream, GCancellable *cancellable, GError **error); -static void g_buffered_output_stream_write_async (GOutputStream *stream, - const void *buffer, - gsize count, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer data); -static gssize g_buffered_output_stream_write_finish (GOutputStream *stream, - GAsyncResult *result, - GError **error); static void g_buffered_output_stream_flush_async (GOutputStream *stream, int io_priority, GCancellable *cancellable, @@ -117,9 +105,26 @@ static gboolean g_buffered_output_stream_close_finish (GOutputStream *str GAsyncResult *result, GError **error); -G_DEFINE_TYPE (GBufferedOutputStream, - g_buffered_output_stream, - G_TYPE_FILTER_OUTPUT_STREAM) +static void g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface); +static goffset g_buffered_output_stream_tell (GSeekable *seekable); +static gboolean g_buffered_output_stream_can_seek (GSeekable *seekable); +static gboolean g_buffered_output_stream_seek (GSeekable *seekable, + goffset offset, + GSeekType type, + GCancellable *cancellable, + GError **error); +static gboolean g_buffered_output_stream_can_truncate (GSeekable *seekable); +static gboolean g_buffered_output_stream_truncate (GSeekable *seekable, + goffset offset, + GCancellable *cancellable, + GError **error); + +G_DEFINE_TYPE_WITH_CODE (GBufferedOutputStream, + g_buffered_output_stream, + G_TYPE_FILTER_OUTPUT_STREAM, + G_ADD_PRIVATE (GBufferedOutputStream) + G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, + g_buffered_output_stream_seekable_iface_init)) static void @@ -127,8 +132,6 @@ g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass) { GObjectClass *object_class; GOutputStreamClass *ostream_class; - - g_type_class_add_private (klass, sizeof (GBufferedOutputStreamPrivate)); object_class = G_OBJECT_CLASS (klass); object_class->get_property = g_buffered_output_stream_get_property; @@ -136,11 +139,9 @@ g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass) object_class->finalize = g_buffered_output_stream_finalize; ostream_class = G_OUTPUT_STREAM_CLASS (klass); - ostream_class->write = g_buffered_output_stream_write; + ostream_class->write_fn = g_buffered_output_stream_write; ostream_class->flush = g_buffered_output_stream_flush; - ostream_class->close = g_buffered_output_stream_close; - ostream_class->write_async = g_buffered_output_stream_write_async; - ostream_class->write_finish = g_buffered_output_stream_write_finish; + ostream_class->close_fn = g_buffered_output_stream_close; ostream_class->flush_async = g_buffered_output_stream_flush_async; ostream_class->flush_finish = g_buffered_output_stream_flush_finish; ostream_class->close_async = g_buffered_output_stream_close_async; @@ -154,9 +155,18 @@ g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass) 1, G_MAXUINT, DEFAULT_BUFFER_SIZE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE|G_PARAM_CONSTRUCT| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + g_object_class_install_property (object_class, + PROP_AUTO_GROW, + g_param_spec_boolean ("auto-grow", + P_("Auto-grow"), + P_("Whether the buffer should automatically grow"), + FALSE, + G_PARAM_READWRITE| + G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + } /** @@ -184,7 +194,7 @@ g_buffered_output_stream_get_buffer_size (GBufferedOutputStream *stream) **/ void g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream, - gsize size) + gsize size) { GBufferedOutputStreamPrivate *priv; guint8 *buffer; @@ -193,6 +203,9 @@ g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream, priv = stream->priv; + if (size == priv->len) + return; + if (priv->buffer) { size = MAX (size, priv->pos); @@ -210,6 +223,8 @@ g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream, priv->len = size; priv->pos = 0; } + + g_object_notify (G_OBJECT (stream), "buffer-size"); } /** @@ -235,35 +250,45 @@ g_buffered_output_stream_get_auto_grow (GBufferedOutputStream *stream) * @auto_grow: a #gboolean. * * Sets whether or not the @stream's buffer should automatically grow. + * If @auto_grow is true, then each write will just make the buffer + * larger, and you must manually flush the buffer to actually write out + * the data to the underlying stream. **/ void g_buffered_output_stream_set_auto_grow (GBufferedOutputStream *stream, - gboolean auto_grow) + gboolean auto_grow) { + GBufferedOutputStreamPrivate *priv; g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream)); - - stream->priv->auto_grow = auto_grow; + priv = stream->priv; + auto_grow = auto_grow != FALSE; + if (priv->auto_grow != auto_grow) + { + priv->auto_grow = auto_grow; + g_object_notify (G_OBJECT (stream), "auto-grow"); + } } static void -g_buffered_output_stream_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +g_buffered_output_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { - GBufferedOutputStream *buffered_stream; - GBufferedOutputStreamPrivate *priv; + GBufferedOutputStream *stream; - buffered_stream = G_BUFFERED_OUTPUT_STREAM (object); - priv = buffered_stream->priv; + stream = G_BUFFERED_OUTPUT_STREAM (object); switch (prop_id) { - case PROP_BUFSIZE: - g_buffered_output_stream_set_buffer_size (buffered_stream, g_value_get_uint (value)); + g_buffered_output_stream_set_buffer_size (stream, g_value_get_uint (value)); break; + case PROP_AUTO_GROW: + g_buffered_output_stream_set_auto_grow (stream, g_value_get_boolean (value)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -285,11 +310,14 @@ g_buffered_output_stream_get_property (GObject *object, switch (prop_id) { - case PROP_BUFSIZE: g_value_set_uint (value, priv->len); break; + case PROP_AUTO_GROW: + g_value_set_boolean (value, priv->auto_grow); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -308,17 +336,23 @@ g_buffered_output_stream_finalize (GObject *object) g_free (priv->buffer); - if (G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize) - (*G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize) (object); + G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize (object); } static void g_buffered_output_stream_init (GBufferedOutputStream *stream) { - stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, - G_TYPE_BUFFERED_OUTPUT_STREAM, - GBufferedOutputStreamPrivate); + stream->priv = g_buffered_output_stream_get_instance_private (stream); +} +static void +g_buffered_output_stream_seekable_iface_init (GSeekableIface *iface) +{ + iface->tell = g_buffered_output_stream_tell; + iface->can_seek = g_buffered_output_stream_can_seek; + iface->seek = g_buffered_output_stream_seek; + iface->can_truncate = g_buffered_output_stream_can_truncate; + iface->truncate_fn = g_buffered_output_stream_truncate; } /** @@ -354,7 +388,7 @@ g_buffered_output_stream_new (GOutputStream *base_stream) **/ GOutputStream * g_buffered_output_stream_new_sized (GOutputStream *base_stream, - guint size) + gsize size) { GOutputStream *stream; @@ -395,7 +429,7 @@ flush_buffer (GBufferedOutputStream *stream, count = priv->pos - bytes_written; if (count > 0) - g_memmove (priv->buffer, priv->buffer + bytes_written, count); + memmove (priv->buffer, priv->buffer + bytes_written, count); priv->pos -= bytes_written; @@ -448,12 +482,10 @@ g_buffered_output_stream_flush (GOutputStream *stream, GError **error) { GBufferedOutputStream *bstream; - GBufferedOutputStreamPrivate *priv; GOutputStream *base_stream; gboolean res; bstream = G_BUFFERED_OUTPUT_STREAM (stream); - priv = bstream->priv; base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream; res = flush_buffer (bstream, cancellable, error); @@ -472,25 +504,123 @@ g_buffered_output_stream_close (GOutputStream *stream, GError **error) { GBufferedOutputStream *bstream; - GBufferedOutputStreamPrivate *priv; GOutputStream *base_stream; gboolean res; bstream = G_BUFFERED_OUTPUT_STREAM (stream); - priv = bstream->priv; base_stream = G_FILTER_OUTPUT_STREAM (bstream)->base_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; } +static goffset +g_buffered_output_stream_tell (GSeekable *seekable) +{ + GBufferedOutputStream *bstream; + GBufferedOutputStreamPrivate *priv; + GOutputStream *base_stream; + GSeekable *base_stream_seekable; + goffset base_offset; + + bstream = G_BUFFERED_OUTPUT_STREAM (seekable); + priv = bstream->priv; + + base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; + if (!G_IS_SEEKABLE (base_stream)) + return 0; + + base_stream_seekable = G_SEEKABLE (base_stream); + + base_offset = g_seekable_tell (base_stream_seekable); + return base_offset + priv->pos; +} + +static gboolean +g_buffered_output_stream_can_seek (GSeekable *seekable) +{ + GOutputStream *base_stream; + + base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; + return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream)); +} + +static gboolean +g_buffered_output_stream_seek (GSeekable *seekable, + goffset offset, + GSeekType type, + GCancellable *cancellable, + GError **error) +{ + GBufferedOutputStream *bstream; + GOutputStream *base_stream; + GSeekable *base_stream_seekable; + gboolean flushed; + + bstream = G_BUFFERED_OUTPUT_STREAM (seekable); + + base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; + if (!G_IS_SEEKABLE (base_stream)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("Seek not supported on base stream")); + return FALSE; + } + + base_stream_seekable = G_SEEKABLE (base_stream); + flushed = flush_buffer (bstream, cancellable, error); + if (!flushed) + return FALSE; + + return g_seekable_seek (base_stream_seekable, offset, type, cancellable, error); +} + +static gboolean +g_buffered_output_stream_can_truncate (GSeekable *seekable) +{ + GOutputStream *base_stream; + + base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; + return G_IS_SEEKABLE (base_stream) && g_seekable_can_truncate (G_SEEKABLE (base_stream)); +} + +static gboolean +g_buffered_output_stream_truncate (GSeekable *seekable, + goffset offset, + GCancellable *cancellable, + GError **error) +{ + GBufferedOutputStream *bstream; + GOutputStream *base_stream; + GSeekable *base_stream_seekable; + gboolean flushed; + + bstream = G_BUFFERED_OUTPUT_STREAM (seekable); + base_stream = G_FILTER_OUTPUT_STREAM (seekable)->base_stream; + if (!G_IS_SEEKABLE (base_stream)) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + _("Truncate not supported on base stream")); + return FALSE; + } + + base_stream_seekable = G_SEEKABLE (base_stream); + + flushed = flush_buffer (bstream, cancellable, error); + if (!flushed) + return FALSE; + return g_seekable_truncate (base_stream_seekable, offset, cancellable, error); +} + /* ************************** */ /* Async stuff implementation */ /* ************************** */ @@ -516,9 +646,10 @@ free_flush_data (gpointer data) * and so closing and writing is just a special * case of flushing + some addition stuff */ static void -flush_buffer_thread (GSimpleAsyncResult *result, - GObject *object, - GCancellable *cancellable) +flush_buffer_thread (GTask *task, + gpointer object, + gpointer task_data, + GCancellable *cancellable) { GBufferedOutputStream *stream; GOutputStream *base_stream; @@ -527,7 +658,7 @@ flush_buffer_thread (GSimpleAsyncResult *result, GError *error = NULL; stream = G_BUFFERED_OUTPUT_STREAM (object); - fdata = g_simple_async_result_get_op_res_gpointer (result); + fdata = task_data; base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream; res = flush_buffer (stream, cancellable, &error); @@ -543,113 +674,19 @@ 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) - { - g_simple_async_result_set_from_error (result, error); - g_error_free (error); - } -} - -typedef struct { - - FlushData fdata; - - gsize count; - const void *buffer; - -} WriteData; - -static void -free_write_data (gpointer data) -{ - g_slice_free (WriteData, data); -} - -static void -g_buffered_output_stream_write_async (GOutputStream *stream, - const void *buffer, - gsize count, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer data) -{ - GBufferedOutputStream *buffered_stream; - GBufferedOutputStreamPrivate *priv; - GSimpleAsyncResult *res; - WriteData *wdata; - - buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream); - priv = buffered_stream->priv; - - wdata = g_slice_new (WriteData); - wdata->count = count; - wdata->buffer = buffer; - - res = g_simple_async_result_new (G_OBJECT (stream), - callback, - data, - g_buffered_output_stream_write_async); - - g_simple_async_result_set_op_res_gpointer (res, wdata, free_write_data); - - /* if we have space left directly call the - * callback (from idle) otherwise schedule a buffer - * flush in the thread. In both cases the actual - * copying of the data to the buffer will be done in - * the write_finish () func since that should - * be fast enough */ - if (priv->len - priv->pos > 0) - { - g_simple_async_result_complete_in_idle (res); - } + g_task_return_error (task, error); else - { - wdata->fdata.flush_stream = FALSE; - wdata->fdata.close_stream = FALSE; - g_simple_async_result_run_in_thread (res, - flush_buffer_thread, - io_priority, - cancellable); - g_object_unref (res); - } -} - -static gssize -g_buffered_output_stream_write_finish (GOutputStream *stream, - GAsyncResult *result, - GError **error) -{ - GBufferedOutputStreamPrivate *priv; - GBufferedOutputStream *buffered_stream; - GSimpleAsyncResult *simple; - WriteData *wdata; - gssize count; - - simple = G_SIMPLE_ASYNC_RESULT (result); - buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream); - priv = buffered_stream->priv; - - g_assert (g_simple_async_result_get_source_tag (simple) == - g_buffered_output_stream_write_async); - - wdata = g_simple_async_result_get_op_res_gpointer (simple); - - /* Now do the real copying of data to the buffer */ - count = priv->len - priv->pos; - count = MIN (wdata->count, count); - - memcpy (priv->buffer + priv->pos, wdata->buffer, count); - - priv->pos += count; - - return count; + g_task_return_boolean (task, TRUE); } static void @@ -659,25 +696,19 @@ g_buffered_output_stream_flush_async (GOutputStream *stream, GAsyncReadyCallback callback, gpointer data) { - GSimpleAsyncResult *res; - FlushData *fdata; + GTask *task; + FlushData *fdata; fdata = g_slice_new (FlushData); fdata->flush_stream = TRUE; fdata->close_stream = FALSE; - res = g_simple_async_result_new (G_OBJECT (stream), - callback, - data, - g_buffered_output_stream_flush_async); - - g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data); + task = g_task_new (stream, cancellable, callback, data); + g_task_set_task_data (task, fdata, free_flush_data); + g_task_set_priority (task, io_priority); - g_simple_async_result_run_in_thread (res, - flush_buffer_thread, - io_priority, - cancellable); - g_object_unref (res); + g_task_run_in_thread (task, flush_buffer_thread); + g_object_unref (task); } static gboolean @@ -685,14 +716,9 @@ g_buffered_output_stream_flush_finish (GOutputStream *stream, GAsyncResult *result, GError **error) { - GSimpleAsyncResult *simple; - - simple = G_SIMPLE_ASYNC_RESULT (result); - - g_assert (g_simple_async_result_get_source_tag (simple) == - g_buffered_output_stream_flush_async); + g_return_val_if_fail (g_task_is_valid (result, stream), FALSE); - return TRUE; + return g_task_propagate_boolean (G_TASK (result), error); } static void @@ -702,24 +728,18 @@ g_buffered_output_stream_close_async (GOutputStream *stream, GAsyncReadyCallback callback, gpointer data) { - GSimpleAsyncResult *res; - FlushData *fdata; + GTask *task; + FlushData *fdata; fdata = g_slice_new (FlushData); fdata->close_stream = TRUE; - res = g_simple_async_result_new (G_OBJECT (stream), - callback, - data, - g_buffered_output_stream_close_async); + task = g_task_new (stream, cancellable, callback, data); + g_task_set_task_data (task, fdata, free_flush_data); + g_task_set_priority (task, io_priority); - g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data); - - g_simple_async_result_run_in_thread (res, - flush_buffer_thread, - io_priority, - cancellable); - g_object_unref (res); + g_task_run_in_thread (task, flush_buffer_thread); + g_object_unref (task); } static gboolean @@ -727,15 +747,7 @@ g_buffered_output_stream_close_finish (GOutputStream *stream, GAsyncResult *result, GError **error) { - GSimpleAsyncResult *simple; - - simple = G_SIMPLE_ASYNC_RESULT (result); + g_return_val_if_fail (g_task_is_valid (result, stream), FALSE); - g_assert (g_simple_async_result_get_source_tag (simple) == - g_buffered_output_stream_flush_async); - - return TRUE; + return g_task_propagate_boolean (G_TASK (result), error); } - -#define __G_BUFFERED_OUTPUT_STREAM_C__ -#include "gioaliasdef.c"