1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright (C) 2006-2007 Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Author: Christian Kellner <gicmo@gnome.org>
24 #include "gbufferedoutputstream.h"
25 #include "goutputstream.h"
26 #include "gsimpleasyncresult.h"
31 * SECTION:gbufferedoutputstream
32 * @short_description: Buffered Output Stream
34 * @see_also: #GFilterOutputStream, #GOutputStream
36 * Buffered output stream implements #GFilterOutputStream and provides
37 * for buffered writes.
39 * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes.
41 * To create a buffered output stream, use g_buffered_output_stream_new(),
42 * or g_buffered_output_stream_new_sized() to specify the buffer's size
45 * To get the size of a buffer within a buffered input stream, use
46 * g_buffered_output_stream_get_buffer_size(). To change the size of a
47 * buffered output stream's buffer, use
48 * g_buffered_output_stream_set_buffer_size(). Note that the buffer's
49 * size cannot be reduced below the size of the data within the buffer.
52 #define DEFAULT_BUFFER_SIZE 4096
54 struct _GBufferedOutputStreamPrivate {
67 static void g_buffered_output_stream_set_property (GObject *object,
72 static void g_buffered_output_stream_get_property (GObject *object,
76 static void g_buffered_output_stream_finalize (GObject *object);
79 static gssize g_buffered_output_stream_write (GOutputStream *stream,
82 GCancellable *cancellable,
84 static gboolean g_buffered_output_stream_flush (GOutputStream *stream,
85 GCancellable *cancellable,
87 static gboolean g_buffered_output_stream_close (GOutputStream *stream,
88 GCancellable *cancellable,
91 static void g_buffered_output_stream_flush_async (GOutputStream *stream,
93 GCancellable *cancellable,
94 GAsyncReadyCallback callback,
96 static gboolean g_buffered_output_stream_flush_finish (GOutputStream *stream,
99 static void g_buffered_output_stream_close_async (GOutputStream *stream,
101 GCancellable *cancellable,
102 GAsyncReadyCallback callback,
104 static gboolean g_buffered_output_stream_close_finish (GOutputStream *stream,
105 GAsyncResult *result,
108 G_DEFINE_TYPE (GBufferedOutputStream,
109 g_buffered_output_stream,
110 G_TYPE_FILTER_OUTPUT_STREAM)
114 g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass)
116 GObjectClass *object_class;
117 GOutputStreamClass *ostream_class;
119 g_type_class_add_private (klass, sizeof (GBufferedOutputStreamPrivate));
121 object_class = G_OBJECT_CLASS (klass);
122 object_class->get_property = g_buffered_output_stream_get_property;
123 object_class->set_property = g_buffered_output_stream_set_property;
124 object_class->finalize = g_buffered_output_stream_finalize;
126 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
127 ostream_class->write_fn = g_buffered_output_stream_write;
128 ostream_class->flush = g_buffered_output_stream_flush;
129 ostream_class->close_fn = g_buffered_output_stream_close;
130 ostream_class->flush_async = g_buffered_output_stream_flush_async;
131 ostream_class->flush_finish = g_buffered_output_stream_flush_finish;
132 ostream_class->close_async = g_buffered_output_stream_close_async;
133 ostream_class->close_finish = g_buffered_output_stream_close_finish;
135 g_object_class_install_property (object_class,
137 g_param_spec_uint ("buffer-size",
139 P_("The size of the backend buffer"),
143 G_PARAM_READWRITE|G_PARAM_CONSTRUCT|
144 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
146 g_object_class_install_property (object_class,
148 g_param_spec_boolean ("auto-grow",
150 P_("Whether the buffer should automatically grow"),
153 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
158 * g_buffered_output_stream_get_buffer_size:
159 * @stream: a #GBufferedOutputStream.
161 * Gets the size of the buffer in the @stream.
163 * Returns: the current size of the buffer.
166 g_buffered_output_stream_get_buffer_size (GBufferedOutputStream *stream)
168 g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), -1);
170 return stream->priv->len;
174 * g_buffered_output_stream_set_buffer_size:
175 * @stream: a #GBufferedOutputStream.
178 * Sets the size of the internal buffer to @size.
181 g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream,
184 GBufferedOutputStreamPrivate *priv;
187 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
191 if (size == priv->len)
196 size = MAX (size, priv->pos);
198 buffer = g_malloc (size);
199 memcpy (buffer, priv->buffer, priv->pos);
200 g_free (priv->buffer);
201 priv->buffer = buffer;
207 priv->buffer = g_malloc (size);
212 g_object_notify (G_OBJECT (stream), "buffer-size");
216 * g_buffered_output_stream_get_auto_grow:
217 * @stream: a #GBufferedOutputStream.
219 * Checks if the buffer automatically grows as data is added.
221 * Returns: %TRUE if the @stream's buffer automatically grows,
225 g_buffered_output_stream_get_auto_grow (GBufferedOutputStream *stream)
227 g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), FALSE);
229 return stream->priv->auto_grow;
233 * g_buffered_output_stream_set_auto_grow:
234 * @stream: a #GBufferedOutputStream.
235 * @auto_grow: a #gboolean.
237 * Sets whether or not the @stream's buffer should automatically grow.
238 * If @auto_grow is true, then each write will just make the buffer
239 * larger, and you must manually flush the buffer to actually write out
240 * the data to the underlying stream.
243 g_buffered_output_stream_set_auto_grow (GBufferedOutputStream *stream,
246 GBufferedOutputStreamPrivate *priv;
247 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
249 auto_grow = auto_grow != FALSE;
250 if (priv->auto_grow != auto_grow)
252 priv->auto_grow = auto_grow;
253 g_object_notify (G_OBJECT (stream), "auto-grow");
258 g_buffered_output_stream_set_property (GObject *object,
263 GBufferedOutputStream *stream;
265 stream = G_BUFFERED_OUTPUT_STREAM (object);
270 g_buffered_output_stream_set_buffer_size (stream, g_value_get_uint (value));
274 g_buffered_output_stream_set_auto_grow (stream, g_value_get_boolean (value));
278 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285 g_buffered_output_stream_get_property (GObject *object,
290 GBufferedOutputStream *buffered_stream;
291 GBufferedOutputStreamPrivate *priv;
293 buffered_stream = G_BUFFERED_OUTPUT_STREAM (object);
294 priv = buffered_stream->priv;
299 g_value_set_uint (value, priv->len);
303 g_value_set_boolean (value, priv->auto_grow);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
314 g_buffered_output_stream_finalize (GObject *object)
316 GBufferedOutputStream *stream;
317 GBufferedOutputStreamPrivate *priv;
319 stream = G_BUFFERED_OUTPUT_STREAM (object);
322 g_free (priv->buffer);
324 G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize (object);
328 g_buffered_output_stream_init (GBufferedOutputStream *stream)
330 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
331 G_TYPE_BUFFERED_OUTPUT_STREAM,
332 GBufferedOutputStreamPrivate);
337 * g_buffered_output_stream_new:
338 * @base_stream: a #GOutputStream.
340 * Creates a new buffered output stream for a base stream.
342 * Returns: a #GOutputStream for the given @base_stream.
345 g_buffered_output_stream_new (GOutputStream *base_stream)
347 GOutputStream *stream;
349 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
351 stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
352 "base-stream", base_stream,
359 * g_buffered_output_stream_new_sized:
360 * @base_stream: a #GOutputStream.
363 * Creates a new buffered output stream with a given buffer size.
365 * Returns: a #GOutputStream with an internal buffer set to @size.
368 g_buffered_output_stream_new_sized (GOutputStream *base_stream,
371 GOutputStream *stream;
373 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
375 stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
376 "base-stream", base_stream,
384 flush_buffer (GBufferedOutputStream *stream,
385 GCancellable *cancellable,
388 GBufferedOutputStreamPrivate *priv;
389 GOutputStream *base_stream;
396 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
398 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), FALSE);
400 res = g_output_stream_write_all (base_stream,
407 count = priv->pos - bytes_written;
410 g_memmove (priv->buffer, priv->buffer + bytes_written, count);
412 priv->pos -= bytes_written;
418 g_buffered_output_stream_write (GOutputStream *stream,
421 GCancellable *cancellable,
424 GBufferedOutputStream *bstream;
425 GBufferedOutputStreamPrivate *priv;
430 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
431 priv = bstream->priv;
433 n = priv->len - priv->pos;
435 if (priv->auto_grow && n < count)
437 new_size = MAX (priv->len * 2, priv->len + count);
438 g_buffered_output_stream_set_buffer_size (bstream, new_size);
442 res = flush_buffer (bstream, cancellable, error);
448 n = priv->len - priv->pos;
450 count = MIN (count, n);
451 memcpy (priv->buffer + priv->pos, buffer, count);
458 g_buffered_output_stream_flush (GOutputStream *stream,
459 GCancellable *cancellable,
462 GBufferedOutputStream *bstream;
463 GOutputStream *base_stream;
466 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
467 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
469 res = flush_buffer (bstream, cancellable, error);
474 res = g_output_stream_flush (base_stream, cancellable, error);
480 g_buffered_output_stream_close (GOutputStream *stream,
481 GCancellable *cancellable,
484 GBufferedOutputStream *bstream;
485 GOutputStream *base_stream;
488 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
489 base_stream = G_FILTER_OUTPUT_STREAM (bstream)->base_stream;
490 res = flush_buffer (bstream, cancellable, error);
492 if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
494 /* report the first error but still close the stream */
496 res = g_output_stream_close (base_stream, cancellable, error);
498 g_output_stream_close (base_stream, cancellable, NULL);
504 /* ************************** */
505 /* Async stuff implementation */
506 /* ************************** */
508 /* TODO: This should be using the base class async ops, not threads */
512 guint flush_stream : 1;
513 guint close_stream : 1;
518 free_flush_data (gpointer data)
520 g_slice_free (FlushData, data);
523 /* This function is used by all three (i.e.
524 * _write, _flush, _close) functions since
525 * all of them will need to flush the buffer
526 * and so closing and writing is just a special
527 * case of flushing + some addition stuff */
529 flush_buffer_thread (GSimpleAsyncResult *result,
531 GCancellable *cancellable)
533 GBufferedOutputStream *stream;
534 GOutputStream *base_stream;
537 GError *error = NULL;
539 stream = G_BUFFERED_OUTPUT_STREAM (object);
540 fdata = g_simple_async_result_get_op_res_gpointer (result);
541 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
543 res = flush_buffer (stream, cancellable, &error);
545 /* if flushing the buffer didn't work don't even bother
546 * to flush the stream but just report that error */
547 if (res && fdata->flush_stream)
548 res = g_output_stream_flush (base_stream, cancellable, &error);
550 if (fdata->close_stream)
553 /* if flushing the buffer or the stream returned
554 * an error report that first error but still try
555 * close the stream */
556 if (g_filter_output_stream_get_close_base_stream (G_FILTER_OUTPUT_STREAM (stream)))
559 g_output_stream_close (base_stream, cancellable, NULL);
561 res = g_output_stream_close (base_stream, cancellable, &error);
566 g_simple_async_result_take_error (result, error);
570 g_buffered_output_stream_flush_async (GOutputStream *stream,
572 GCancellable *cancellable,
573 GAsyncReadyCallback callback,
576 GSimpleAsyncResult *res;
579 fdata = g_slice_new (FlushData);
580 fdata->flush_stream = TRUE;
581 fdata->close_stream = FALSE;
583 res = g_simple_async_result_new (G_OBJECT (stream),
586 g_buffered_output_stream_flush_async);
588 g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
590 g_simple_async_result_run_in_thread (res,
594 g_object_unref (res);
598 g_buffered_output_stream_flush_finish (GOutputStream *stream,
599 GAsyncResult *result,
602 GSimpleAsyncResult *simple;
604 simple = G_SIMPLE_ASYNC_RESULT (result);
606 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
607 g_buffered_output_stream_flush_async);
613 g_buffered_output_stream_close_async (GOutputStream *stream,
615 GCancellable *cancellable,
616 GAsyncReadyCallback callback,
619 GSimpleAsyncResult *res;
622 fdata = g_slice_new (FlushData);
623 fdata->close_stream = TRUE;
625 res = g_simple_async_result_new (G_OBJECT (stream),
628 g_buffered_output_stream_close_async);
630 g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
632 g_simple_async_result_run_in_thread (res,
636 g_object_unref (res);
640 g_buffered_output_stream_close_finish (GOutputStream *stream,
641 GAsyncResult *result,
644 GSimpleAsyncResult *simple;
646 simple = G_SIMPLE_ASYNC_RESULT (result);
648 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
649 g_buffered_output_stream_close_async);