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
36 * @see_also: #GFilterOutputStream, #GOutputStream
38 * Buffered output stream implements #GFilterOutputStream and provides
39 * for buffered writes.
41 * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes.
43 * To create a buffered output stream, use g_buffered_output_stream_new(),
44 * or g_buffered_output_stream_new_sized() to specify the buffer's size
47 * To get the size of a buffer within a buffered input stream, use
48 * g_buffered_output_stream_get_buffer_size(). To change the size of a
49 * buffered output stream's buffer, use
50 * g_buffered_output_stream_set_buffer_size(). Note that the buffer's
51 * size cannot be reduced below the size of the data within the buffer.
54 #define DEFAULT_BUFFER_SIZE 4096
56 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_fn
= g_buffered_output_stream_write
;
140 ostream_class
->flush
= g_buffered_output_stream_flush
;
141 ostream_class
->close_fn
= 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
|
158 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
160 g_object_class_install_property (object_class
,
162 g_param_spec_boolean ("auto-grow",
164 P_("Whether the buffer should automatically grow"),
167 G_PARAM_STATIC_NAME
|G_PARAM_STATIC_NICK
|G_PARAM_STATIC_BLURB
));
172 * g_buffered_output_stream_get_buffer_size:
173 * @stream: a #GBufferedOutputStream.
175 * Gets the size of the buffer in the @stream.
177 * Returns: the current size of the buffer.
180 g_buffered_output_stream_get_buffer_size (GBufferedOutputStream
*stream
)
182 g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream
), -1);
184 return stream
->priv
->len
;
188 * g_buffered_output_stream_set_buffer_size:
189 * @stream: a #GBufferedOutputStream.
192 * Sets the size of the internal buffer to @size.
195 g_buffered_output_stream_set_buffer_size (GBufferedOutputStream
*stream
,
198 GBufferedOutputStreamPrivate
*priv
;
201 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream
));
205 if (size
== priv
->len
)
210 size
= MAX (size
, priv
->pos
);
212 buffer
= g_malloc (size
);
213 memcpy (buffer
, priv
->buffer
, priv
->pos
);
214 g_free (priv
->buffer
);
215 priv
->buffer
= buffer
;
221 priv
->buffer
= g_malloc (size
);
226 g_object_notify (G_OBJECT (stream
), "buffer-size");
230 * g_buffered_output_stream_get_auto_grow:
231 * @stream: a #GBufferedOutputStream.
233 * Checks if the buffer automatically grows as data is added.
235 * Returns: %TRUE if the @stream's buffer automatically grows,
239 g_buffered_output_stream_get_auto_grow (GBufferedOutputStream
*stream
)
241 g_return_val_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream
), FALSE
);
243 return stream
->priv
->auto_grow
;
247 * g_buffered_output_stream_set_auto_grow:
248 * @stream: a #GBufferedOutputStream.
249 * @auto_grow: a #gboolean.
251 * Sets whether or not the @stream's buffer should automatically grow.
252 * If @auto_grow is true, then each write will just make the buffer
253 * larger, and you must manually flush the buffer to actually write out
254 * the data to the underlying stream.
257 g_buffered_output_stream_set_auto_grow (GBufferedOutputStream
*stream
,
260 GBufferedOutputStreamPrivate
*priv
;
261 g_return_if_fail (G_IS_BUFFERED_OUTPUT_STREAM (stream
));
263 auto_grow
= auto_grow
!= FALSE
;
264 if (priv
->auto_grow
!= auto_grow
)
266 priv
->auto_grow
= auto_grow
;
267 g_object_notify (G_OBJECT (stream
), "auto-grow");
272 g_buffered_output_stream_set_property (GObject
*object
,
277 GBufferedOutputStream
*stream
;
279 stream
= G_BUFFERED_OUTPUT_STREAM (object
);
284 g_buffered_output_stream_set_buffer_size (stream
, g_value_get_uint (value
));
288 g_buffered_output_stream_set_auto_grow (stream
, g_value_get_boolean (value
));
292 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
299 g_buffered_output_stream_get_property (GObject
*object
,
304 GBufferedOutputStream
*buffered_stream
;
305 GBufferedOutputStreamPrivate
*priv
;
307 buffered_stream
= G_BUFFERED_OUTPUT_STREAM (object
);
308 priv
= buffered_stream
->priv
;
313 g_value_set_uint (value
, priv
->len
);
317 g_value_set_boolean (value
, priv
->auto_grow
);
321 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
328 g_buffered_output_stream_finalize (GObject
*object
)
330 GBufferedOutputStream
*stream
;
331 GBufferedOutputStreamPrivate
*priv
;
333 stream
= G_BUFFERED_OUTPUT_STREAM (object
);
336 g_free (priv
->buffer
);
338 G_OBJECT_CLASS (g_buffered_output_stream_parent_class
)->finalize (object
);
342 g_buffered_output_stream_init (GBufferedOutputStream
*stream
)
344 stream
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (stream
,
345 G_TYPE_BUFFERED_OUTPUT_STREAM
,
346 GBufferedOutputStreamPrivate
);
351 * g_buffered_output_stream_new:
352 * @base_stream: a #GOutputStream.
354 * Creates a new buffered output stream for a base stream.
356 * Returns: a #GOutputStream for the given @base_stream.
359 g_buffered_output_stream_new (GOutputStream
*base_stream
)
361 GOutputStream
*stream
;
363 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream
), NULL
);
365 stream
= g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM
,
366 "base-stream", base_stream
,
373 * g_buffered_output_stream_new_sized:
374 * @base_stream: a #GOutputStream.
377 * Creates a new buffered output stream with a given buffer size.
379 * Returns: a #GOutputStream with an internal buffer set to @size.
382 g_buffered_output_stream_new_sized (GOutputStream
*base_stream
,
385 GOutputStream
*stream
;
387 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream
), NULL
);
389 stream
= g_object_new (G_TYPE_BUFFERED_OUTPUT_STREAM
,
390 "base-stream", base_stream
,
398 flush_buffer (GBufferedOutputStream
*stream
,
399 GCancellable
*cancellable
,
402 GBufferedOutputStreamPrivate
*priv
;
403 GOutputStream
*base_stream
;
410 base_stream
= G_FILTER_OUTPUT_STREAM (stream
)->base_stream
;
412 g_return_val_if_fail (G_IS_OUTPUT_STREAM (base_stream
), FALSE
);
414 res
= g_output_stream_write_all (base_stream
,
421 count
= priv
->pos
- bytes_written
;
424 g_memmove (priv
->buffer
, priv
->buffer
+ bytes_written
, count
);
426 priv
->pos
-= bytes_written
;
432 g_buffered_output_stream_write (GOutputStream
*stream
,
435 GCancellable
*cancellable
,
438 GBufferedOutputStream
*bstream
;
439 GBufferedOutputStreamPrivate
*priv
;
444 bstream
= G_BUFFERED_OUTPUT_STREAM (stream
);
445 priv
= bstream
->priv
;
447 n
= priv
->len
- priv
->pos
;
449 if (priv
->auto_grow
&& n
< count
)
451 new_size
= MAX (priv
->len
* 2, priv
->len
+ count
);
452 g_buffered_output_stream_set_buffer_size (bstream
, new_size
);
456 res
= flush_buffer (bstream
, cancellable
, error
);
462 n
= priv
->len
- priv
->pos
;
464 count
= MIN (count
, n
);
465 memcpy (priv
->buffer
+ priv
->pos
, buffer
, count
);
472 g_buffered_output_stream_flush (GOutputStream
*stream
,
473 GCancellable
*cancellable
,
476 GBufferedOutputStream
*bstream
;
477 GBufferedOutputStreamPrivate
*priv
;
478 GOutputStream
*base_stream
;
481 bstream
= G_BUFFERED_OUTPUT_STREAM (stream
);
482 priv
= bstream
->priv
;
483 base_stream
= G_FILTER_OUTPUT_STREAM (stream
)->base_stream
;
485 res
= flush_buffer (bstream
, cancellable
, error
);
490 res
= g_output_stream_flush (base_stream
, cancellable
, error
);
496 g_buffered_output_stream_close (GOutputStream
*stream
,
497 GCancellable
*cancellable
,
500 GBufferedOutputStream
*bstream
;
501 GBufferedOutputStreamPrivate
*priv
;
502 GOutputStream
*base_stream
;
505 bstream
= G_BUFFERED_OUTPUT_STREAM (stream
);
506 priv
= bstream
->priv
;
507 base_stream
= G_FILTER_OUTPUT_STREAM (bstream
)->base_stream
;
509 res
= flush_buffer (bstream
, cancellable
, error
);
511 /* report the first error but still close the stream */
513 res
= g_output_stream_close (base_stream
, cancellable
, error
);
515 g_output_stream_close (base_stream
, cancellable
, NULL
);
520 /* ************************** */
521 /* Async stuff implementation */
522 /* ************************** */
524 /* TODO: This should be using the base class async ops, not threads */
528 guint flush_stream
: 1;
529 guint close_stream
: 1;
534 free_flush_data (gpointer data
)
536 g_slice_free (FlushData
, data
);
539 /* This function is used by all three (i.e.
540 * _write, _flush, _close) functions since
541 * all of them will need to flush the buffer
542 * and so closing and writing is just a special
543 * case of flushing + some addition stuff */
545 flush_buffer_thread (GSimpleAsyncResult
*result
,
547 GCancellable
*cancellable
)
549 GBufferedOutputStream
*stream
;
550 GOutputStream
*base_stream
;
553 GError
*error
= NULL
;
555 stream
= G_BUFFERED_OUTPUT_STREAM (object
);
556 fdata
= g_simple_async_result_get_op_res_gpointer (result
);
557 base_stream
= G_FILTER_OUTPUT_STREAM (stream
)->base_stream
;
559 res
= flush_buffer (stream
, cancellable
, &error
);
561 /* if flushing the buffer didn't work don't even bother
562 * to flush the stream but just report that error */
563 if (res
&& fdata
->flush_stream
)
564 res
= g_output_stream_flush (base_stream
, cancellable
, &error
);
566 if (fdata
->close_stream
)
569 /* if flushing the buffer or the stream returned
570 * an error report that first error but still try
571 * close the stream */
573 g_output_stream_close (base_stream
, cancellable
, NULL
);
575 res
= g_output_stream_close (base_stream
, cancellable
, &error
);
580 g_simple_async_result_set_from_error (result
, error
);
581 g_error_free (error
);
595 free_write_data (gpointer data
)
597 g_slice_free (WriteData
, data
);
601 g_buffered_output_stream_write_async (GOutputStream
*stream
,
605 GCancellable
*cancellable
,
606 GAsyncReadyCallback callback
,
609 GBufferedOutputStream
*buffered_stream
;
610 GBufferedOutputStreamPrivate
*priv
;
611 GSimpleAsyncResult
*res
;
614 buffered_stream
= G_BUFFERED_OUTPUT_STREAM (stream
);
615 priv
= buffered_stream
->priv
;
617 wdata
= g_slice_new (WriteData
);
618 wdata
->count
= count
;
619 wdata
->buffer
= buffer
;
621 res
= g_simple_async_result_new (G_OBJECT (stream
),
624 g_buffered_output_stream_write_async
);
626 g_simple_async_result_set_op_res_gpointer (res
, wdata
, free_write_data
);
628 /* if we have space left directly call the
629 * callback (from idle) otherwise schedule a buffer
630 * flush in the thread. In both cases the actual
631 * copying of the data to the buffer will be done in
632 * the write_finish () func since that should
634 if (priv
->len
- priv
->pos
> 0)
636 g_simple_async_result_complete_in_idle (res
);
640 wdata
->fdata
.flush_stream
= FALSE
;
641 wdata
->fdata
.close_stream
= FALSE
;
642 g_simple_async_result_run_in_thread (res
,
646 g_object_unref (res
);
651 g_buffered_output_stream_write_finish (GOutputStream
*stream
,
652 GAsyncResult
*result
,
655 GBufferedOutputStreamPrivate
*priv
;
656 GBufferedOutputStream
*buffered_stream
;
657 GSimpleAsyncResult
*simple
;
661 simple
= G_SIMPLE_ASYNC_RESULT (result
);
662 buffered_stream
= G_BUFFERED_OUTPUT_STREAM (stream
);
663 priv
= buffered_stream
->priv
;
665 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) ==
666 g_buffered_output_stream_write_async
);
668 wdata
= g_simple_async_result_get_op_res_gpointer (simple
);
670 /* Now do the real copying of data to the buffer */
671 count
= priv
->len
- priv
->pos
;
672 count
= MIN (wdata
->count
, count
);
674 memcpy (priv
->buffer
+ priv
->pos
, wdata
->buffer
, count
);
682 g_buffered_output_stream_flush_async (GOutputStream
*stream
,
684 GCancellable
*cancellable
,
685 GAsyncReadyCallback callback
,
688 GSimpleAsyncResult
*res
;
691 fdata
= g_slice_new (FlushData
);
692 fdata
->flush_stream
= TRUE
;
693 fdata
->close_stream
= FALSE
;
695 res
= g_simple_async_result_new (G_OBJECT (stream
),
698 g_buffered_output_stream_flush_async
);
700 g_simple_async_result_set_op_res_gpointer (res
, fdata
, free_flush_data
);
702 g_simple_async_result_run_in_thread (res
,
706 g_object_unref (res
);
710 g_buffered_output_stream_flush_finish (GOutputStream
*stream
,
711 GAsyncResult
*result
,
714 GSimpleAsyncResult
*simple
;
716 simple
= G_SIMPLE_ASYNC_RESULT (result
);
718 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) ==
719 g_buffered_output_stream_flush_async
);
725 g_buffered_output_stream_close_async (GOutputStream
*stream
,
727 GCancellable
*cancellable
,
728 GAsyncReadyCallback callback
,
731 GSimpleAsyncResult
*res
;
734 fdata
= g_slice_new (FlushData
);
735 fdata
->close_stream
= TRUE
;
737 res
= g_simple_async_result_new (G_OBJECT (stream
),
740 g_buffered_output_stream_close_async
);
742 g_simple_async_result_set_op_res_gpointer (res
, fdata
, free_flush_data
);
744 g_simple_async_result_run_in_thread (res
,
748 g_object_unref (res
);
752 g_buffered_output_stream_close_finish (GOutputStream
*stream
,
753 GAsyncResult
*result
,
756 GSimpleAsyncResult
*simple
;
758 simple
= G_SIMPLE_ASYNC_RESULT (result
);
760 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) ==
761 g_buffered_output_stream_flush_async
);
766 #define __G_BUFFERED_OUTPUT_STREAM_C__
767 #include "gioaliasdef.c"