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"
33 * SECTION:gbufferedoutputstream
34 * @short_description: Buffered Output Stream
35 * @see_also: #GFilterOutputStream, #GOutputStream
37 * Buffered output stream implements #GFilterOutputStream and provides
38 * for buffered writes.
40 * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes.
42 * To create a buffered output stream, use g_buffered_output_stream_new(), or
43 * g_buffered_output_stream_new_sized() to specify the buffer's size at construction.
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 g_buffered_output_stream_set_buffer_size().
48 * Note: the buffer's size cannot be reduced below the size of the data within the
55 #define DEFAULT_BUFFER_SIZE 4096
57 struct _GBufferedOutputStreamPrivate {
69 static void g_buffered_output_stream_set_property (GObject *object,
74 static void g_buffered_output_stream_get_property (GObject *object,
78 static void g_buffered_output_stream_finalize (GObject *object);
81 static gssize g_buffered_output_stream_write (GOutputStream *stream,
84 GCancellable *cancellable,
86 static gboolean g_buffered_output_stream_flush (GOutputStream *stream,
87 GCancellable *cancellable,
89 static gboolean g_buffered_output_stream_close (GOutputStream *stream,
90 GCancellable *cancellable,
93 static void g_buffered_output_stream_write_async (GOutputStream *stream,
97 GCancellable *cancellable,
98 GAsyncReadyCallback callback,
100 static gssize g_buffered_output_stream_write_finish (GOutputStream *stream,
101 GAsyncResult *result,
103 static void g_buffered_output_stream_flush_async (GOutputStream *stream,
105 GCancellable *cancellable,
106 GAsyncReadyCallback callback,
108 static gboolean g_buffered_output_stream_flush_finish (GOutputStream *stream,
109 GAsyncResult *result,
111 static void g_buffered_output_stream_close_async (GOutputStream *stream,
113 GCancellable *cancellable,
114 GAsyncReadyCallback callback,
116 static gboolean g_buffered_output_stream_close_finish (GOutputStream *stream,
117 GAsyncResult *result,
120 G_DEFINE_TYPE (GBufferedOutputStream,
121 g_buffered_output_stream,
122 G_TYPE_FILTER_OUTPUT_STREAM)
126 g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass)
128 GObjectClass *object_class;
129 GOutputStreamClass *ostream_class;
131 g_type_class_add_private (klass, sizeof (GBufferedOutputStreamPrivate));
133 object_class = G_OBJECT_CLASS (klass);
134 object_class->get_property = g_buffered_output_stream_get_property;
135 object_class->set_property = g_buffered_output_stream_set_property;
136 object_class->finalize = g_buffered_output_stream_finalize;
138 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
139 ostream_class->write = g_buffered_output_stream_write;
140 ostream_class->flush = g_buffered_output_stream_flush;
141 ostream_class->close = g_buffered_output_stream_close;
142 ostream_class->write_async = g_buffered_output_stream_write_async;
143 ostream_class->write_finish = g_buffered_output_stream_write_finish;
144 ostream_class->flush_async = g_buffered_output_stream_flush_async;
145 ostream_class->flush_finish = g_buffered_output_stream_flush_finish;
146 ostream_class->close_async = g_buffered_output_stream_close_async;
147 ostream_class->close_finish = g_buffered_output_stream_close_finish;
149 g_object_class_install_property (object_class,
151 g_param_spec_uint ("buffer-size",
153 P_("The size of the backend buffer"),
157 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
158 G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
163 * g_buffered_output_stream_get_buffer_size:
164 * @stream: a #GBufferedOutputStream.
166 * Gets the size of the buffer in the @stream.
168 * Returns: the current size of the buffer.
171 g_buffered_output_stream_get_buffer_size (GBufferedOutputStream *stream)
173 g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream), -1);
175 return stream->priv->len;
179 * g_buffered_output_stream_set_buffer_size:
180 * @stream: a #GBufferedOutputStream.
183 * Sets the size of the internal buffer to @size.
186 g_buffered_output_stream_set_buffer_size (GBufferedOutputStream *stream,
189 GBufferedOutputStreamPrivate *priv;
192 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
198 size = MAX (size, priv->pos);
200 buffer = g_malloc (size);
201 memcpy (buffer, priv->buffer, priv->pos);
202 g_free (priv->buffer);
203 priv->buffer = buffer;
209 priv->buffer = g_malloc (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.
240 g_buffered_output_stream_set_auto_grow (GBufferedOutputStream *stream,
243 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream));
245 stream->priv->auto_grow = auto_grow;
249 g_buffered_output_stream_set_property (GObject *object,
254 GBufferedOutputStream *buffered_stream;
255 GBufferedOutputStreamPrivate *priv;
257 buffered_stream = G_BUFFERED_OUTPUT_STREAM (object);
258 priv = buffered_stream->priv;
264 g_buffered_output_stream_set_buffer_size (buffered_stream, g_value_get_uint (value));
268 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
275 g_buffered_output_stream_get_property (GObject *object,
280 GBufferedOutputStream *buffered_stream;
281 GBufferedOutputStreamPrivate *priv;
283 buffered_stream = G_BUFFERED_OUTPUT_STREAM (object);
284 priv = buffered_stream->priv;
290 g_value_set_uint (value, priv->len);
294 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
301 g_buffered_output_stream_finalize (GObject *object)
303 GBufferedOutputStream *stream;
304 GBufferedOutputStreamPrivate *priv;
306 stream = G_BUFFERED_OUTPUT_STREAM (object);
309 g_free (priv->buffer);
311 if (G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize)
312 (*G_OBJECT_CLASS (g_buffered_output_stream_parent_class)->finalize) (object);
316 g_buffered_output_stream_init (GBufferedOutputStream *stream)
318 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
319 G_TYPE_BUFFERED_OUTPUT_STREAM,
320 GBufferedOutputStreamPrivate);
325 * g_buffered_output_stream_new:
326 * @base_stream: a #GOutputStream.
328 * Creates a new buffered output stream for a base stream.
330 * Returns: a #GOutputStream for the given @base_stream.
333 g_buffered_output_stream_new (GOutputStream *base_stream)
335 GOutputStream *stream;
337 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
339 stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
340 "base-stream", base_stream,
347 * g_buffered_output_stream_new_sized:
348 * @base_stream: a #GOutputStream.
351 * Creates a new buffered output stream with a given buffer size.
353 * Returns: a #GOutputStream with an internal buffer set to @size.
356 g_buffered_output_stream_new_sized (GOutputStream *base_stream,
359 GOutputStream *stream;
361 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), NULL);
363 stream = g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM,
364 "base-stream", base_stream,
372 flush_buffer (GBufferedOutputStream *stream,
373 GCancellable *cancellable,
376 GBufferedOutputStreamPrivate *priv;
377 GOutputStream *base_stream;
384 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
386 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream), FALSE);
388 res = g_output_stream_write_all (base_stream,
395 count = priv->pos - bytes_written;
398 g_memmove (priv->buffer, priv->buffer + bytes_written, count);
400 priv->pos -= bytes_written;
406 g_buffered_output_stream_write (GOutputStream *stream,
409 GCancellable *cancellable,
412 GBufferedOutputStream *bstream;
413 GBufferedOutputStreamPrivate *priv;
418 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
419 priv = bstream->priv;
421 n = priv->len - priv->pos;
423 if (priv->auto_grow && n < count)
425 new_size = MAX (priv->len * 2, priv->len + count);
426 g_buffered_output_stream_set_buffer_size (bstream, new_size);
430 res = flush_buffer (bstream, cancellable, error);
436 n = priv->len - priv->pos;
438 count = MIN (count, n);
439 memcpy (priv->buffer + priv->pos, buffer, count);
446 g_buffered_output_stream_flush (GOutputStream *stream,
447 GCancellable *cancellable,
450 GBufferedOutputStream *bstream;
451 GBufferedOutputStreamPrivate *priv;
452 GOutputStream *base_stream;
455 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
456 priv = bstream->priv;
457 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
459 res = flush_buffer (bstream, cancellable, error);
464 res = g_output_stream_flush (base_stream, cancellable, error);
470 g_buffered_output_stream_close (GOutputStream *stream,
471 GCancellable *cancellable,
474 GBufferedOutputStream *bstream;
475 GBufferedOutputStreamPrivate *priv;
476 GOutputStream *base_stream;
479 bstream = G_BUFFERED_OUTPUT_STREAM (stream);
480 priv = bstream->priv;
481 base_stream = G_FILTER_OUTPUT_STREAM (bstream)->base_stream;
483 res = flush_buffer (bstream, cancellable, error);
485 /* report the first error but still close the stream */
487 res = g_output_stream_close (base_stream, cancellable, error);
489 g_output_stream_close (base_stream, cancellable, NULL);
494 /* ************************** */
495 /* Async stuff implementation */
496 /* ************************** */
498 /* TODO: This should be using the base class async ops, not threads */
502 guint flush_stream : 1;
503 guint close_stream : 1;
508 free_flush_data (gpointer data)
510 g_slice_free (FlushData, data);
513 /* This function is used by all three (i.e.
514 * _write, _flush, _close) functions since
515 * all of them will need to flush the buffer
516 * and so closing and writing is just a special
517 * case of flushing + some addition stuff */
519 flush_buffer_thread (GSimpleAsyncResult *result,
521 GCancellable *cancellable)
523 GBufferedOutputStream *stream;
524 GOutputStream *base_stream;
527 GError *error = NULL;
529 stream = G_BUFFERED_OUTPUT_STREAM (object);
530 fdata = g_simple_async_result_get_op_res_gpointer (result);
531 base_stream = G_FILTER_OUTPUT_STREAM (stream)->base_stream;
533 res = flush_buffer (stream, cancellable, &error);
535 /* if flushing the buffer didn't work don't even bother
536 * to flush the stream but just report that error */
537 if (res && fdata->flush_stream)
538 res = g_output_stream_flush (base_stream, cancellable, &error);
540 if (fdata->close_stream)
543 /* if flushing the buffer or the stream returned
544 * an error report that first error but still try
545 * close the stream */
547 g_output_stream_close (base_stream, cancellable, NULL);
549 res = g_output_stream_close (base_stream, cancellable, &error);
554 g_simple_async_result_set_from_error (result, error);
555 g_error_free (error);
569 free_write_data (gpointer data)
571 g_slice_free (WriteData, data);
575 g_buffered_output_stream_write_async (GOutputStream *stream,
579 GCancellable *cancellable,
580 GAsyncReadyCallback callback,
583 GBufferedOutputStream *buffered_stream;
584 GBufferedOutputStreamPrivate *priv;
585 GSimpleAsyncResult *res;
588 buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream);
589 priv = buffered_stream->priv;
591 wdata = g_slice_new (WriteData);
592 wdata->count = count;
593 wdata->buffer = buffer;
595 res = g_simple_async_result_new (G_OBJECT (stream),
598 g_buffered_output_stream_write_async);
600 g_simple_async_result_set_op_res_gpointer (res, wdata, free_write_data);
602 /* if we have space left directly call the
603 * callback (from idle) otherwise schedule a buffer
604 * flush in the thread. In both cases the actual
605 * copying of the data to the buffer will be done in
606 * the write_finish () func since that should
608 if (priv->len - priv->pos > 0)
610 g_simple_async_result_complete_in_idle (res);
614 wdata->fdata.flush_stream = FALSE;
615 wdata->fdata.close_stream = FALSE;
616 g_simple_async_result_run_in_thread (res,
620 g_object_unref (res);
625 g_buffered_output_stream_write_finish (GOutputStream *stream,
626 GAsyncResult *result,
629 GBufferedOutputStreamPrivate *priv;
630 GBufferedOutputStream *buffered_stream;
631 GSimpleAsyncResult *simple;
635 simple = G_SIMPLE_ASYNC_RESULT (result);
636 buffered_stream = G_BUFFERED_OUTPUT_STREAM (stream);
637 priv = buffered_stream->priv;
639 g_assert (g_simple_async_result_get_source_tag (simple) ==
640 g_buffered_output_stream_write_async);
642 wdata = g_simple_async_result_get_op_res_gpointer (simple);
644 /* Now do the real copying of data to the buffer */
645 count = priv->len - priv->pos;
646 count = MIN (wdata->count, count);
648 memcpy (priv->buffer + priv->pos, wdata->buffer, count);
656 g_buffered_output_stream_flush_async (GOutputStream *stream,
658 GCancellable *cancellable,
659 GAsyncReadyCallback callback,
662 GSimpleAsyncResult *res;
665 fdata = g_slice_new (FlushData);
666 fdata->flush_stream = TRUE;
667 fdata->close_stream = FALSE;
669 res = g_simple_async_result_new (G_OBJECT (stream),
672 g_buffered_output_stream_flush_async);
674 g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
676 g_simple_async_result_run_in_thread (res,
680 g_object_unref (res);
684 g_buffered_output_stream_flush_finish (GOutputStream *stream,
685 GAsyncResult *result,
688 GSimpleAsyncResult *simple;
690 simple = G_SIMPLE_ASYNC_RESULT (result);
692 g_assert (g_simple_async_result_get_source_tag (simple) ==
693 g_buffered_output_stream_flush_async);
699 g_buffered_output_stream_close_async (GOutputStream *stream,
701 GCancellable *cancellable,
702 GAsyncReadyCallback callback,
705 GSimpleAsyncResult *res;
708 fdata = g_slice_new (FlushData);
709 fdata->close_stream = TRUE;
711 res = g_simple_async_result_new (G_OBJECT (stream),
714 g_buffered_output_stream_close_async);
716 g_simple_async_result_set_op_res_gpointer (res, fdata, free_flush_data);
718 g_simple_async_result_run_in_thread (res,
722 g_object_unref (res);
726 g_buffered_output_stream_close_finish (GOutputStream *stream,
727 GAsyncResult *result,
730 GSimpleAsyncResult *simple;
732 simple = G_SIMPLE_ASYNC_RESULT (result);
734 g_assert (g_simple_async_result_get_source_tag (simple) ==
735 g_buffered_output_stream_flush_async);
740 #define __G_BUFFERED_OUTPUT_STREAM_C__
741 #include "gioaliasdef.c"