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.
21 * Christian Kellner <gicmo@gnome.org>
22 * Krzysztof KosiĆski <tweenk.pl@gmail.com>
26 #include "gmemoryoutputstream.h"
27 #include "goutputstream.h"
28 #include "gpollableoutputstream.h"
29 #include "gseekable.h"
30 #include "gsimpleasyncresult.h"
37 * SECTION:gmemoryoutputstream
38 * @short_description: Streaming output operations on memory chunks
40 * @see_also: #GMemoryInputStream
42 * #GMemoryOutputStream is a class for using arbitrary
43 * memory chunks as output for GIO streaming output operations.
45 * As of GLib 2.34, #GMemoryOutputStream implements
46 * #GPollableOutputStream.
49 #define MIN_ARRAY_SIZE 16
56 PROP_REALLOC_FUNCTION,
60 struct _GMemoryOutputStreamPrivate {
62 gpointer data; /* Write buffer */
63 gsize len; /* Current length of the data buffer. Can change with resizing. */
64 gsize valid_len; /* The part of data that has been written to */
65 gsize pos; /* Current position in the stream. Distinct from valid_len,
66 because the stream is seekable. */
68 GReallocFunc realloc_fn;
69 GDestroyNotify destroy;
72 static void g_memory_output_stream_set_property (GObject *object,
76 static void g_memory_output_stream_get_property (GObject *object,
80 static void g_memory_output_stream_finalize (GObject *object);
82 static gssize g_memory_output_stream_write (GOutputStream *stream,
85 GCancellable *cancellable,
88 static gboolean g_memory_output_stream_close (GOutputStream *stream,
89 GCancellable *cancellable,
92 static void g_memory_output_stream_write_async (GOutputStream *stream,
96 GCancellable *cancellable,
97 GAsyncReadyCallback callback,
99 static gssize g_memory_output_stream_write_finish (GOutputStream *stream,
100 GAsyncResult *result,
102 static void g_memory_output_stream_close_async (GOutputStream *stream,
104 GCancellable *cancellable,
105 GAsyncReadyCallback callback,
107 static gboolean g_memory_output_stream_close_finish (GOutputStream *stream,
108 GAsyncResult *result,
111 static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface);
112 static goffset g_memory_output_stream_tell (GSeekable *seekable);
113 static gboolean g_memory_output_stream_can_seek (GSeekable *seekable);
114 static gboolean g_memory_output_stream_seek (GSeekable *seekable,
117 GCancellable *cancellable,
119 static gboolean g_memory_output_stream_can_truncate (GSeekable *seekable);
120 static gboolean g_memory_output_stream_truncate (GSeekable *seekable,
122 GCancellable *cancellable,
125 static gboolean g_memory_output_stream_is_writable (GPollableOutputStream *stream);
126 static GSource *g_memory_output_stream_create_source (GPollableOutputStream *stream,
127 GCancellable *cancellable);
129 static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
131 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
132 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
133 g_memory_output_stream_seekable_iface_init);
134 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
135 g_memory_output_stream_pollable_iface_init))
139 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
141 GOutputStreamClass *ostream_class;
142 GObjectClass *gobject_class;
144 g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
146 gobject_class = G_OBJECT_CLASS (klass);
147 gobject_class->set_property = g_memory_output_stream_set_property;
148 gobject_class->get_property = g_memory_output_stream_get_property;
149 gobject_class->finalize = g_memory_output_stream_finalize;
151 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
153 ostream_class->write_fn = g_memory_output_stream_write;
154 ostream_class->close_fn = g_memory_output_stream_close;
155 ostream_class->write_async = g_memory_output_stream_write_async;
156 ostream_class->write_finish = g_memory_output_stream_write_finish;
157 ostream_class->close_async = g_memory_output_stream_close_async;
158 ostream_class->close_finish = g_memory_output_stream_close_finish;
161 * GMemoryOutputStream:data:
163 * Pointer to buffer where data will be written.
167 g_object_class_install_property (gobject_class,
169 g_param_spec_pointer ("data",
171 P_("Pointer to buffer where data will be written."),
172 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
173 G_PARAM_STATIC_STRINGS));
176 * GMemoryOutputStream:size:
178 * Current size of the data buffer.
182 g_object_class_install_property (gobject_class,
184 g_param_spec_ulong ("size",
185 P_("Data Buffer Size"),
186 P_("Current size of the data buffer."),
188 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
189 G_PARAM_STATIC_STRINGS));
192 * GMemoryOutputStream:data-size:
194 * Size of data written to the buffer.
198 g_object_class_install_property (gobject_class,
200 g_param_spec_ulong ("data-size",
202 P_("Size of data written to the buffer."),
205 G_PARAM_STATIC_STRINGS));
208 * GMemoryOutputStream:realloc-function: (skip)
210 * Function with realloc semantics called to enlarge the buffer.
214 g_object_class_install_property (gobject_class,
215 PROP_REALLOC_FUNCTION,
216 g_param_spec_pointer ("realloc-function",
217 P_("Memory Reallocation Function"),
218 P_("Function with realloc semantics called to enlarge the buffer."),
219 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
220 G_PARAM_STATIC_STRINGS));
223 * GMemoryOutputStream:destroy-function: (skip)
225 * Function called with the buffer as argument when the stream is destroyed.
229 g_object_class_install_property (gobject_class,
230 PROP_DESTROY_FUNCTION,
231 g_param_spec_pointer ("destroy-function",
232 P_("Destroy Notification Function"),
233 P_("Function called with the buffer as argument when the stream is destroyed."),
234 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
235 G_PARAM_STATIC_STRINGS));
239 g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
241 iface->is_writable = g_memory_output_stream_is_writable;
242 iface->create_source = g_memory_output_stream_create_source;
246 g_memory_output_stream_set_property (GObject *object,
251 GMemoryOutputStream *stream;
252 GMemoryOutputStreamPrivate *priv;
254 stream = G_MEMORY_OUTPUT_STREAM (object);
260 priv->data = g_value_get_pointer (value);
263 priv->len = g_value_get_ulong (value);
265 case PROP_REALLOC_FUNCTION:
266 priv->realloc_fn = g_value_get_pointer (value);
268 case PROP_DESTROY_FUNCTION:
269 priv->destroy = g_value_get_pointer (value);
272 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
278 g_memory_output_stream_get_property (GObject *object,
283 GMemoryOutputStream *stream;
284 GMemoryOutputStreamPrivate *priv;
286 stream = G_MEMORY_OUTPUT_STREAM (object);
292 g_value_set_pointer (value, priv->data);
295 g_value_set_ulong (value, priv->len);
298 g_value_set_ulong (value, priv->valid_len);
300 case PROP_REALLOC_FUNCTION:
301 g_value_set_pointer (value, priv->realloc_fn);
303 case PROP_DESTROY_FUNCTION:
304 g_value_set_pointer (value, priv->destroy);
307 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
313 g_memory_output_stream_finalize (GObject *object)
315 GMemoryOutputStream *stream;
316 GMemoryOutputStreamPrivate *priv;
318 stream = G_MEMORY_OUTPUT_STREAM (object);
322 priv->destroy (priv->data);
324 G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
328 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
330 iface->tell = g_memory_output_stream_tell;
331 iface->can_seek = g_memory_output_stream_can_seek;
332 iface->seek = g_memory_output_stream_seek;
333 iface->can_truncate = g_memory_output_stream_can_truncate;
334 iface->truncate_fn = g_memory_output_stream_truncate;
339 g_memory_output_stream_init (GMemoryOutputStream *stream)
341 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
342 G_TYPE_MEMORY_OUTPUT_STREAM,
343 GMemoryOutputStreamPrivate);
344 stream->priv->pos = 0;
345 stream->priv->valid_len = 0;
349 * g_memory_output_stream_new: (skip)
350 * @data: (allow-none): pointer to a chunk of memory to use, or %NULL
351 * @size: the size of @data
352 * @realloc_function: (allow-none): a function with realloc() semantics (like g_realloc())
353 * to be called when @data needs to be grown, or %NULL
354 * @destroy_function: (allow-none): a function to be called on @data when the stream is
355 * finalized, or %NULL
357 * Creates a new #GMemoryOutputStream.
359 * If @data is non-%NULL, the stream will use that for its internal storage.
360 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
361 * storage when necessary. To construct a fixed-size output stream,
362 * pass %NULL as @realloc_fn.
365 * /* a stream that can grow */
366 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
368 * /* another stream that can grow */
369 * stream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
371 * /* a fixed-size stream */
372 * data = malloc (200);
373 * stream3 = g_memory_output_stream_new (data, 200, NULL, free);
376 * Return value: A newly created #GMemoryOutputStream object.
379 g_memory_output_stream_new (gpointer data,
381 GReallocFunc realloc_function,
382 GDestroyNotify destroy_function)
384 GOutputStream *stream;
386 stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM,
389 "realloc-function", realloc_function,
390 "destroy-function", destroy_function,
397 * g_memory_output_stream_get_data:
398 * @ostream: a #GMemoryOutputStream
400 * Gets any loaded data from the @ostream.
402 * Note that the returned pointer may become invalid on the next
403 * write or truncate operation on the stream.
405 * Returns: (transfer none): pointer to the stream's data
408 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
410 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
412 return ostream->priv->data;
416 * g_memory_output_stream_get_size:
417 * @ostream: a #GMemoryOutputStream
419 * Gets the size of the currently allocated data area (available from
420 * g_memory_output_stream_get_data()). If the stream isn't
421 * growable (no realloc was passed to g_memory_output_stream_new()) then
422 * this is the maximum size of the stream and further writes
423 * will return %G_IO_ERROR_NO_SPACE.
425 * Note that for growable streams the returned size may become invalid on
426 * the next write or truncate operation on the stream.
428 * If you want the number of bytes currently written to the stream, use
429 * g_memory_output_stream_get_data_size().
431 * Returns: the number of bytes allocated for the data buffer
434 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
436 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
438 return ostream->priv->len;
442 * g_memory_output_stream_get_data_size:
443 * @ostream: a #GMemoryOutputStream
445 * Returns the number of bytes from the start up
446 * to including the last byte written in the stream
447 * that has not been truncated away.
449 * Returns: the number of bytes written to the stream
454 g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
456 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
458 return ostream->priv->valid_len;
462 * g_memory_output_stream_steal_data:
463 * @ostream: a #GMemoryOutputStream
465 * Gets any loaded data from the @ostream. Ownership of the data
466 * is transferred to the caller; when no longer needed it must be
467 * freed using the free function set in @ostream's
468 * #GMemoryOutputStream:destroy-function property.
470 * @ostream must be closed before calling this function.
472 * Returns: (transfer full): the stream's data
477 g_memory_output_stream_steal_data (GMemoryOutputStream *ostream)
481 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
482 g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
484 data = ostream->priv->data;
485 ostream->priv->data = NULL;
491 array_resize (GMemoryOutputStream *ostream,
493 gboolean allow_partial,
496 GMemoryOutputStreamPrivate *priv;
500 priv = ostream->priv;
502 if (priv->len == size)
505 if (!priv->realloc_fn)
508 priv->pos < priv->len)
509 return TRUE; /* Short write */
511 g_set_error_literal (error,
514 _("Memory output stream not resizable"));
519 data = priv->realloc_fn (priv->data, size);
521 if (size > 0 && !data)
524 priv->pos < priv->len)
525 return TRUE; /* Short write */
527 g_set_error_literal (error,
530 _("Failed to resize memory output stream"));
535 memset ((guint8 *)data + len, 0, size - len);
540 if (priv->len < priv->valid_len)
541 priv->valid_len = priv->len;
547 g_nearest_pow (gint num)
558 g_memory_output_stream_write (GOutputStream *stream,
561 GCancellable *cancellable,
564 GMemoryOutputStream *ostream;
565 GMemoryOutputStreamPrivate *priv;
569 ostream = G_MEMORY_OUTPUT_STREAM (stream);
570 priv = ostream->priv;
575 /* Check for address space overflow, but only if the buffer is resizable.
576 Otherwise we just do a short write and don't worry. */
577 if (priv->realloc_fn && priv->pos + count < priv->pos)
580 if (priv->pos + count > priv->len)
582 /* At least enought to fit the write, rounded up
583 for greater than linear growth.
584 TODO: This wastes a lot of memory at large stream sizes.
585 Figure out a more rational allocation strategy. */
586 new_size = g_nearest_pow (priv->pos + count);
587 /* Check for overflow again. We have only checked if
588 pos + count > G_MAXSIZE, but it only catches the case of writing
589 more than 4GiB total on a 32-bit system. There's still the problem
590 of g_nearest_pow overflowing above 0x7fffffff, so we're
591 effectively limited to 2GiB. */
592 if (new_size < priv->len)
595 new_size = MAX (new_size, MIN_ARRAY_SIZE);
596 if (!array_resize (ostream, new_size, TRUE, error))
600 /* Make sure we handle short writes if the array_resize
601 only added part of the required memory */
602 count = MIN (count, priv->len - priv->pos);
604 dest = (guint8 *)priv->data + priv->pos;
605 memcpy (dest, buffer, count);
608 if (priv->pos > priv->valid_len)
609 priv->valid_len = priv->pos;
614 /* Overflow: buffer size would need to be bigger than G_MAXSIZE. */
615 g_set_error_literal (error,
618 _("Amount of memory required to process the write is "
619 "larger than available address space"));
624 g_memory_output_stream_close (GOutputStream *stream,
625 GCancellable *cancellable,
632 g_memory_output_stream_write_async (GOutputStream *stream,
636 GCancellable *cancellable,
637 GAsyncReadyCallback callback,
640 GSimpleAsyncResult *simple;
641 GError *error = NULL;
644 nwritten = G_OUTPUT_STREAM_GET_CLASS (stream)->write_fn (stream,
650 simple = g_simple_async_result_new (G_OBJECT (stream),
653 g_memory_output_stream_write_async);
656 g_simple_async_result_take_error (simple, error);
658 g_simple_async_result_set_op_res_gssize (simple, nwritten);
659 g_simple_async_result_complete_in_idle (simple);
660 g_object_unref (simple);
664 g_memory_output_stream_write_finish (GOutputStream *stream,
665 GAsyncResult *result,
668 GSimpleAsyncResult *simple;
671 simple = G_SIMPLE_ASYNC_RESULT (result);
673 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
674 g_memory_output_stream_write_async);
676 nwritten = g_simple_async_result_get_op_res_gssize (simple);
682 g_memory_output_stream_close_async (GOutputStream *stream,
684 GCancellable *cancellable,
685 GAsyncReadyCallback callback,
688 GSimpleAsyncResult *simple;
690 simple = g_simple_async_result_new (G_OBJECT (stream),
693 g_memory_output_stream_close_async);
696 /* will always return TRUE */
697 g_memory_output_stream_close (stream, cancellable, NULL);
699 g_simple_async_result_complete_in_idle (simple);
700 g_object_unref (simple);
704 g_memory_output_stream_close_finish (GOutputStream *stream,
705 GAsyncResult *result,
708 GSimpleAsyncResult *simple;
710 simple = G_SIMPLE_ASYNC_RESULT (result);
712 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
713 g_memory_output_stream_close_async);
719 g_memory_output_stream_tell (GSeekable *seekable)
721 GMemoryOutputStream *stream;
722 GMemoryOutputStreamPrivate *priv;
724 stream = G_MEMORY_OUTPUT_STREAM (seekable);
731 g_memory_output_stream_can_seek (GSeekable *seekable)
737 g_memory_output_stream_seek (GSeekable *seekable,
740 GCancellable *cancellable,
743 GMemoryOutputStream *stream;
744 GMemoryOutputStreamPrivate *priv;
747 stream = G_MEMORY_OUTPUT_STREAM (seekable);
753 absolute = priv->pos + offset;
761 absolute = priv->len + offset;
765 g_set_error_literal (error,
767 G_IO_ERROR_INVALID_ARGUMENT,
768 _("Invalid GSeekType supplied"));
775 g_set_error_literal (error,
777 G_IO_ERROR_INVALID_ARGUMENT,
778 _("Requested seek before the beginning of the stream"));
782 if (absolute > priv->len)
784 g_set_error_literal (error,
786 G_IO_ERROR_INVALID_ARGUMENT,
787 _("Requested seek beyond the end of the stream"));
791 priv->pos = absolute;
797 g_memory_output_stream_can_truncate (GSeekable *seekable)
799 GMemoryOutputStream *ostream;
800 GMemoryOutputStreamPrivate *priv;
802 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
803 priv = ostream->priv;
805 return priv->realloc_fn != NULL;
809 g_memory_output_stream_truncate (GSeekable *seekable,
811 GCancellable *cancellable,
814 GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
816 if (!array_resize (ostream, offset, FALSE, error))
823 g_memory_output_stream_is_writable (GPollableOutputStream *stream)
829 g_memory_output_stream_create_source (GPollableOutputStream *stream,
830 GCancellable *cancellable)
832 GSource *base_source, *pollable_source;
834 base_source = g_timeout_source_new (0);
835 pollable_source = g_pollable_source_new_full (stream, base_source,
837 g_source_unref (base_source);
839 return pollable_source;