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 "gmemoryoutputstream.h"
25 #include "goutputstream.h"
26 #include "gseekable.h"
27 #include "gsimpleasyncresult.h"
34 * SECTION:gmemoryoutputstream
35 * @short_description: Streaming output operations on memory chunks
37 * @see_also: #GMemoryInputStream
39 * #GMemoryOutputStream is a class for using arbitrary
40 * memory chunks as output for GIO streaming output operations.
44 #define MIN_ARRAY_SIZE 16
46 struct _GMemoryOutputStreamPrivate {
53 GReallocFunc realloc_fn;
54 GDestroyNotify destroy;
57 static void g_memory_output_stream_finalize (GObject *object);
59 static gssize g_memory_output_stream_write (GOutputStream *stream,
62 GCancellable *cancellable,
65 static gboolean g_memory_output_stream_close (GOutputStream *stream,
66 GCancellable *cancellable,
69 static void g_memory_output_stream_write_async (GOutputStream *stream,
73 GCancellable *cancellable,
74 GAsyncReadyCallback callback,
76 static gssize g_memory_output_stream_write_finish (GOutputStream *stream,
79 static void g_memory_output_stream_close_async (GOutputStream *stream,
81 GCancellable *cancellable,
82 GAsyncReadyCallback callback,
84 static gboolean g_memory_output_stream_close_finish (GOutputStream *stream,
88 static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface);
89 static goffset g_memory_output_stream_tell (GSeekable *seekable);
90 static gboolean g_memory_output_stream_can_seek (GSeekable *seekable);
91 static gboolean g_memory_output_stream_seek (GSeekable *seekable,
94 GCancellable *cancellable,
96 static gboolean g_memory_output_stream_can_truncate (GSeekable *seekable);
97 static gboolean g_memory_output_stream_truncate (GSeekable *seekable,
99 GCancellable *cancellable,
102 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
103 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
104 g_memory_output_stream_seekable_iface_init))
108 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
110 GOutputStreamClass *ostream_class;
111 GObjectClass *gobject_class;
113 g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
115 gobject_class = G_OBJECT_CLASS (klass);
116 gobject_class->finalize = g_memory_output_stream_finalize;
118 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
120 ostream_class->write_fn = g_memory_output_stream_write;
121 ostream_class->close_fn = g_memory_output_stream_close;
122 ostream_class->write_async = g_memory_output_stream_write_async;
123 ostream_class->write_finish = g_memory_output_stream_write_finish;
124 ostream_class->close_async = g_memory_output_stream_close_async;
125 ostream_class->close_finish = g_memory_output_stream_close_finish;
129 g_memory_output_stream_finalize (GObject *object)
131 GMemoryOutputStream *stream;
132 GMemoryOutputStreamPrivate *priv;
134 stream = G_MEMORY_OUTPUT_STREAM (object);
138 priv->destroy (priv->data);
140 if (G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize)
141 (*G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize) (object);
145 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
147 iface->tell = g_memory_output_stream_tell;
148 iface->can_seek = g_memory_output_stream_can_seek;
149 iface->seek = g_memory_output_stream_seek;
150 iface->can_truncate = g_memory_output_stream_can_truncate;
151 iface->truncate_fn = g_memory_output_stream_truncate;
156 g_memory_output_stream_init (GMemoryOutputStream *stream)
158 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
159 G_TYPE_MEMORY_OUTPUT_STREAM,
160 GMemoryOutputStreamPrivate);
164 * g_memory_output_stream_new:
165 * @data: pointer to a chunk of memory to use, or %NULL
166 * @len: the size of @data
167 * @realloc_fn: a function with realloc() semantics to be called when
168 * @data needs to be grown, or %NULL
169 * @destroy: a function to be called on @data when the stream is finalized,
172 * Creates a new #GMemoryOutputStream.
174 * If @data is non-%NULL, the stream will use that for its internal storage.
175 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
176 * storage when necessary. To construct a fixed-size output stream,
177 * pass %NULL as @realloc_fn.
179 * /* a stream that can grow */
180 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
182 * /* a fixed-size stream */
183 * data = malloc (200);
184 * stream2 = g_memory_output_stream_new (data, 200, NULL, free);
187 * Return value: A newly created #GMemoryOutputStream object.
190 g_memory_output_stream_new (gpointer data,
192 GReallocFunc realloc_fn,
193 GDestroyNotify destroy)
195 GOutputStream *stream;
196 GMemoryOutputStreamPrivate *priv;
198 stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, NULL);
200 priv = G_MEMORY_OUTPUT_STREAM (stream)->priv;
204 priv->realloc_fn = realloc_fn;
205 priv->destroy = destroy;
213 * g_memory_output_stream_get_data:
214 * @ostream: a #GMemoryOutputStream
216 * Gets any loaded data from the @ostream.
218 * Note that the returned pointer may become invalid on the next
219 * write or truncate operation on the stream.
221 * Returns: pointer to the stream's data
224 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
226 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
228 return ostream->priv->data;
232 * g_memory_output_stream_get_size:
233 * @ostream: a #GMemoryOutputStream
235 * Gets the size of the loaded data from the @ostream.
237 * Note that the returned size may become invalid on the next
238 * write or truncate operation on the stream.
240 * Returns: the size of the stream's data
243 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
245 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
247 return ostream->priv->len;
251 array_check_boundary (GMemoryOutputStream *stream,
255 if (size > G_MAXUINT)
260 _("Reached maximum data array limit"));
269 array_resize (GMemoryOutputStream *ostream,
271 gboolean allow_partial,
274 GMemoryOutputStreamPrivate *priv;
276 gsize len, increment;
278 priv = ostream->priv;
280 if (!array_check_boundary (ostream, size, error))
283 if (priv->len == size)
286 if (!priv->realloc_fn)
289 priv->pos < priv->len)
290 return TRUE; /* Short write */
295 _("Memory output stream not resizable"));
300 data = priv->realloc_fn (priv->data, size);
305 priv->pos < priv->len)
306 return TRUE; /* Short write */
311 _("Failed to resize memory output stream"));
316 memset (data + len, 0, size - len);
325 g_nearest_pow (gint num)
336 g_memory_output_stream_write (GOutputStream *stream,
339 GCancellable *cancellable,
342 GMemoryOutputStream *ostream;
343 GMemoryOutputStreamPrivate *priv;
347 ostream = G_MEMORY_OUTPUT_STREAM (stream);
348 priv = ostream->priv;
353 if (priv->pos + count > priv->len)
355 /* At least enought to fit the write, rounded up
356 for greater than linear growth */
357 new_size = g_nearest_pow (priv->pos + count);
358 new_size = MAX (new_size, MIN_ARRAY_SIZE);
360 if (!array_resize (ostream, new_size, TRUE, error))
364 /* Make sure we handle short writes if the array_resize
365 only added part of the required memory */
366 count = MIN (count, priv->len - priv->pos);
368 dest = priv->data + priv->pos;
369 memcpy (dest, buffer, count);
376 g_memory_output_stream_close (GOutputStream *stream,
377 GCancellable *cancellable,
384 g_memory_output_stream_write_async (GOutputStream *stream,
388 GCancellable *cancellable,
389 GAsyncReadyCallback callback,
392 GSimpleAsyncResult *simple;
395 nwritten = g_memory_output_stream_write (stream,
402 simple = g_simple_async_result_new (G_OBJECT (stream),
405 g_memory_output_stream_write_async);
407 g_simple_async_result_set_op_res_gssize (simple, nwritten);
408 g_simple_async_result_complete_in_idle (simple);
409 g_object_unref (simple);
413 g_memory_output_stream_write_finish (GOutputStream *stream,
414 GAsyncResult *result,
417 GSimpleAsyncResult *simple;
420 simple = G_SIMPLE_ASYNC_RESULT (result);
422 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
423 g_memory_output_stream_write_async);
425 nwritten = g_simple_async_result_get_op_res_gssize (simple);
431 g_memory_output_stream_close_async (GOutputStream *stream,
433 GCancellable *cancellable,
434 GAsyncReadyCallback callback,
437 GSimpleAsyncResult *simple;
439 simple = g_simple_async_result_new (G_OBJECT (stream),
442 g_memory_output_stream_close_async);
445 /* will always return TRUE */
446 g_memory_output_stream_close (stream, cancellable, NULL);
448 g_simple_async_result_complete_in_idle (simple);
449 g_object_unref (simple);
453 g_memory_output_stream_close_finish (GOutputStream *stream,
454 GAsyncResult *result,
457 GSimpleAsyncResult *simple;
459 simple = G_SIMPLE_ASYNC_RESULT (result);
461 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
462 g_memory_output_stream_close_async);
468 g_memory_output_stream_tell (GSeekable *seekable)
470 GMemoryOutputStream *stream;
471 GMemoryOutputStreamPrivate *priv;
473 stream = G_MEMORY_OUTPUT_STREAM (seekable);
480 g_memory_output_stream_can_seek (GSeekable *seekable)
486 g_memory_output_stream_seek (GSeekable *seekable,
489 GCancellable *cancellable,
492 GMemoryOutputStream *stream;
493 GMemoryOutputStreamPrivate *priv;
496 stream = G_MEMORY_OUTPUT_STREAM (seekable);
502 absolute = priv->pos + offset;
510 absolute = priv->len + offset;
516 G_IO_ERROR_INVALID_ARGUMENT,
517 _("Invalid GSeekType supplied"));
526 G_IO_ERROR_INVALID_ARGUMENT,
527 _("Invalid seek request"));
531 if (!array_check_boundary (stream, absolute, error))
534 priv->pos = absolute;
540 g_memory_output_stream_can_truncate (GSeekable *seekable)
542 GMemoryOutputStream *ostream;
543 GMemoryOutputStreamPrivate *priv;
545 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
546 priv = ostream->priv;
548 return priv->realloc_fn != NULL;
552 g_memory_output_stream_truncate (GSeekable *seekable,
554 GCancellable *cancellable,
557 GMemoryOutputStream *ostream;
558 GMemoryOutputStreamPrivate *priv;
560 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
561 priv = ostream->priv;
563 if (!array_resize (ostream, offset, FALSE, error))
569 #define __G_MEMORY_OUTPUT_STREAM_C__
570 #include "gioaliasdef.c"