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 G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
144 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
146 iface->tell = g_memory_output_stream_tell;
147 iface->can_seek = g_memory_output_stream_can_seek;
148 iface->seek = g_memory_output_stream_seek;
149 iface->can_truncate = g_memory_output_stream_can_truncate;
150 iface->truncate_fn = g_memory_output_stream_truncate;
155 g_memory_output_stream_init (GMemoryOutputStream *stream)
157 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
158 G_TYPE_MEMORY_OUTPUT_STREAM,
159 GMemoryOutputStreamPrivate);
163 * g_memory_output_stream_new:
164 * @data: pointer to a chunk of memory to use, or %NULL
165 * @len: the size of @data
166 * @realloc_fn: a function with realloc() semantics to be called when
167 * @data needs to be grown, or %NULL
168 * @destroy: a function to be called on @data when the stream is finalized,
171 * Creates a new #GMemoryOutputStream.
173 * If @data is non-%NULL, the stream will use that for its internal storage.
174 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
175 * storage when necessary. To construct a fixed-size output stream,
176 * pass %NULL as @realloc_fn.
178 * /* a stream that can grow */
179 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
181 * /* a fixed-size stream */
182 * data = malloc (200);
183 * stream2 = g_memory_output_stream_new (data, 200, NULL, free);
186 * Return value: A newly created #GMemoryOutputStream object.
189 g_memory_output_stream_new (gpointer data,
191 GReallocFunc realloc_fn,
192 GDestroyNotify destroy)
194 GOutputStream *stream;
195 GMemoryOutputStreamPrivate *priv;
197 stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, NULL);
199 priv = G_MEMORY_OUTPUT_STREAM (stream)->priv;
203 priv->realloc_fn = realloc_fn;
204 priv->destroy = destroy;
212 * g_memory_output_stream_get_data:
213 * @ostream: a #GMemoryOutputStream
215 * Gets any loaded data from the @ostream.
217 * Note that the returned pointer may become invalid on the next
218 * write or truncate operation on the stream.
220 * Returns: pointer to the stream's data
223 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
225 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
227 return ostream->priv->data;
231 * g_memory_output_stream_get_size:
232 * @ostream: a #GMemoryOutputStream
234 * Gets the size of the currently allocated data area (availible from
235 * g_memory_output_stream_get_data()). If the stream isn't
236 * growable (no realloc was passed to g_memory_output_stream_new()) then
237 * this is the maximum size of the stream and further writes
238 * will return %G_IO_ERROR_NO_SPACE.
240 * Note that for growable streams the returned size may become invalid on
241 * the next write or truncate operation on the stream.
243 * If you want the number of bytes currently written to the stream, use
244 * g_memory_output_stream_get_data_size().
246 * Returns: the number of bytes allocated for the data buffer
249 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
251 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
253 return ostream->priv->len;
257 * g_memory_output_stream_get_data_size:
258 * @ostream: a #GMemoryOutputStream
260 * Returns the number of bytes from the start up
261 * to including the last byte written in the stream
262 * that has not been truncated away.
264 * Returns: the number of bytes written to the stream
269 g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
271 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
273 return ostream->priv->pos;
278 array_check_boundary (GMemoryOutputStream *stream,
282 if (size > G_MAXUINT)
284 g_set_error_literal (error,
287 _("Reached maximum data array limit"));
296 array_resize (GMemoryOutputStream *ostream,
298 gboolean allow_partial,
301 GMemoryOutputStreamPrivate *priv;
305 priv = ostream->priv;
307 if (!array_check_boundary (ostream, size, error))
310 if (priv->len == size)
313 if (!priv->realloc_fn)
316 priv->pos < priv->len)
317 return TRUE; /* Short write */
319 g_set_error_literal (error,
322 _("Memory output stream not resizable"));
327 data = priv->realloc_fn (priv->data, size);
332 priv->pos < priv->len)
333 return TRUE; /* Short write */
335 g_set_error_literal (error,
338 _("Failed to resize memory output stream"));
343 memset ((guint8 *)data + len, 0, size - len);
352 g_nearest_pow (gint num)
363 g_memory_output_stream_write (GOutputStream *stream,
366 GCancellable *cancellable,
369 GMemoryOutputStream *ostream;
370 GMemoryOutputStreamPrivate *priv;
374 ostream = G_MEMORY_OUTPUT_STREAM (stream);
375 priv = ostream->priv;
380 if (priv->pos + count > priv->len)
382 /* At least enought to fit the write, rounded up
383 for greater than linear growth */
384 new_size = g_nearest_pow (priv->pos + count);
385 new_size = MAX (new_size, MIN_ARRAY_SIZE);
387 if (!array_resize (ostream, new_size, TRUE, error))
391 /* Make sure we handle short writes if the array_resize
392 only added part of the required memory */
393 count = MIN (count, priv->len - priv->pos);
395 dest = (guint8 *)priv->data + priv->pos;
396 memcpy (dest, buffer, count);
403 g_memory_output_stream_close (GOutputStream *stream,
404 GCancellable *cancellable,
411 g_memory_output_stream_write_async (GOutputStream *stream,
415 GCancellable *cancellable,
416 GAsyncReadyCallback callback,
419 GSimpleAsyncResult *simple;
422 nwritten = g_memory_output_stream_write (stream,
429 simple = g_simple_async_result_new (G_OBJECT (stream),
432 g_memory_output_stream_write_async);
434 g_simple_async_result_set_op_res_gssize (simple, nwritten);
435 g_simple_async_result_complete_in_idle (simple);
436 g_object_unref (simple);
440 g_memory_output_stream_write_finish (GOutputStream *stream,
441 GAsyncResult *result,
444 GSimpleAsyncResult *simple;
447 simple = G_SIMPLE_ASYNC_RESULT (result);
449 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
450 g_memory_output_stream_write_async);
452 nwritten = g_simple_async_result_get_op_res_gssize (simple);
458 g_memory_output_stream_close_async (GOutputStream *stream,
460 GCancellable *cancellable,
461 GAsyncReadyCallback callback,
464 GSimpleAsyncResult *simple;
466 simple = g_simple_async_result_new (G_OBJECT (stream),
469 g_memory_output_stream_close_async);
472 /* will always return TRUE */
473 g_memory_output_stream_close (stream, cancellable, NULL);
475 g_simple_async_result_complete_in_idle (simple);
476 g_object_unref (simple);
480 g_memory_output_stream_close_finish (GOutputStream *stream,
481 GAsyncResult *result,
484 GSimpleAsyncResult *simple;
486 simple = G_SIMPLE_ASYNC_RESULT (result);
488 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
489 g_memory_output_stream_close_async);
495 g_memory_output_stream_tell (GSeekable *seekable)
497 GMemoryOutputStream *stream;
498 GMemoryOutputStreamPrivate *priv;
500 stream = G_MEMORY_OUTPUT_STREAM (seekable);
507 g_memory_output_stream_can_seek (GSeekable *seekable)
513 g_memory_output_stream_seek (GSeekable *seekable,
516 GCancellable *cancellable,
519 GMemoryOutputStream *stream;
520 GMemoryOutputStreamPrivate *priv;
523 stream = G_MEMORY_OUTPUT_STREAM (seekable);
529 absolute = priv->pos + offset;
537 absolute = priv->len + offset;
541 g_set_error_literal (error,
543 G_IO_ERROR_INVALID_ARGUMENT,
544 _("Invalid GSeekType supplied"));
551 g_set_error_literal (error,
553 G_IO_ERROR_INVALID_ARGUMENT,
554 _("Invalid seek request"));
558 if (!array_check_boundary (stream, absolute, error))
561 priv->pos = absolute;
567 g_memory_output_stream_can_truncate (GSeekable *seekable)
569 GMemoryOutputStream *ostream;
570 GMemoryOutputStreamPrivate *priv;
572 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
573 priv = ostream->priv;
575 return priv->realloc_fn != NULL;
579 g_memory_output_stream_truncate (GSeekable *seekable,
581 GCancellable *cancellable,
584 GMemoryOutputStream *ostream;
585 GMemoryOutputStreamPrivate *priv;
587 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
588 priv = ostream->priv;
590 if (!array_resize (ostream, offset, FALSE, error))
596 #define __G_MEMORY_OUTPUT_STREAM_C__
597 #include "gioaliasdef.c"