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"
35 * SECTION:gmemoryoutputstream
36 * @short_description: Streaming output operations on memory chunks
38 * @see_also: #GMemoryInputStream
40 * #GMemoryOutputStream is a class for using arbitrary
41 * memory chunks as output for GIO streaming output operations.
45 #define MIN_ARRAY_SIZE 16
47 struct _GMemoryOutputStreamPrivate {
54 GReallocFunc realloc_fn;
55 GDestroyNotify destroy;
58 static void g_memory_output_stream_finalize (GObject *object);
60 static gssize g_memory_output_stream_write (GOutputStream *stream,
63 GCancellable *cancellable,
66 static gboolean g_memory_output_stream_close (GOutputStream *stream,
67 GCancellable *cancellable,
70 static void g_memory_output_stream_write_async (GOutputStream *stream,
74 GCancellable *cancellable,
75 GAsyncReadyCallback callback,
77 static gssize g_memory_output_stream_write_finish (GOutputStream *stream,
80 static void g_memory_output_stream_close_async (GOutputStream *stream,
82 GCancellable *cancellable,
83 GAsyncReadyCallback callback,
85 static gboolean g_memory_output_stream_close_finish (GOutputStream *stream,
89 static void g_memory_output_stream_seekable_iface_init (GSeekableIface *iface);
90 static goffset g_memory_output_stream_tell (GSeekable *seekable);
91 static gboolean g_memory_output_stream_can_seek (GSeekable *seekable);
92 static gboolean g_memory_output_stream_seek (GSeekable *seekable,
95 GCancellable *cancellable,
97 static gboolean g_memory_output_stream_can_truncate (GSeekable *seekable);
98 static gboolean g_memory_output_stream_truncate (GSeekable *seekable,
100 GCancellable *cancellable,
103 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
104 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
105 g_memory_output_stream_seekable_iface_init))
109 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
111 GOutputStreamClass *ostream_class;
112 GObjectClass *gobject_class;
114 g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
116 gobject_class = G_OBJECT_CLASS (klass);
117 gobject_class->finalize = g_memory_output_stream_finalize;
119 ostream_class = G_OUTPUT_STREAM_CLASS (klass);
121 ostream_class->write_fn = g_memory_output_stream_write;
122 ostream_class->close_fn = g_memory_output_stream_close;
123 ostream_class->write_async = g_memory_output_stream_write_async;
124 ostream_class->write_finish = g_memory_output_stream_write_finish;
125 ostream_class->close_async = g_memory_output_stream_close_async;
126 ostream_class->close_finish = g_memory_output_stream_close_finish;
130 g_memory_output_stream_finalize (GObject *object)
132 GMemoryOutputStream *stream;
133 GMemoryOutputStreamPrivate *priv;
135 stream = G_MEMORY_OUTPUT_STREAM (object);
139 priv->destroy (priv->data);
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 currently allocated data area (availible from
236 * g_memory_output_stream_get_data()). If the stream isn't
237 * growable (no realloc was passed to g_memory_output_stream_new()) then
238 * this is the maximum size of the stream and further writes
239 * will return %G_IO_ERROR_NO_SPACE.
241 * Note that for growable streams the returned size may become invalid on
242 * the next write or truncate operation on the stream.
244 * If you want the number of bytes currently written to the stream, use
245 * g_memory_output_stream_get_data_size().
247 * Returns: the number of bytes allocated for the data buffer
250 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
252 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
254 return ostream->priv->len;
258 * g_memory_output_stream_get_data_size:
259 * @ostream: a #GMemoryOutputStream
261 * Returns the number of bytes from the start up
262 * to including the last byte written in the stream
263 * that has not been truncated away.
265 * Returns: the number of bytes written to the stream
270 g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
272 g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
274 return ostream->priv->pos;
279 array_check_boundary (GMemoryOutputStream *stream,
283 if (size > G_MAXUINT)
285 g_set_error_literal (error,
288 _("Reached maximum data array limit"));
297 array_resize (GMemoryOutputStream *ostream,
299 gboolean allow_partial,
302 GMemoryOutputStreamPrivate *priv;
306 priv = ostream->priv;
308 if (!array_check_boundary (ostream, size, error))
311 if (priv->len == size)
314 if (!priv->realloc_fn)
317 priv->pos < priv->len)
318 return TRUE; /* Short write */
320 g_set_error_literal (error,
323 _("Memory output stream not resizable"));
328 data = priv->realloc_fn (priv->data, size);
330 if (size > 0 && !data)
333 priv->pos < priv->len)
334 return TRUE; /* Short write */
336 g_set_error_literal (error,
339 _("Failed to resize memory output stream"));
344 memset ((guint8 *)data + len, 0, size - len);
353 g_nearest_pow (gint num)
364 g_memory_output_stream_write (GOutputStream *stream,
367 GCancellable *cancellable,
370 GMemoryOutputStream *ostream;
371 GMemoryOutputStreamPrivate *priv;
375 ostream = G_MEMORY_OUTPUT_STREAM (stream);
376 priv = ostream->priv;
381 if (priv->pos + count > priv->len)
383 /* At least enought to fit the write, rounded up
384 for greater than linear growth */
385 new_size = g_nearest_pow (priv->pos + count);
386 new_size = MAX (new_size, MIN_ARRAY_SIZE);
388 if (!array_resize (ostream, new_size, TRUE, error))
392 /* Make sure we handle short writes if the array_resize
393 only added part of the required memory */
394 count = MIN (count, priv->len - priv->pos);
396 dest = (guint8 *)priv->data + priv->pos;
397 memcpy (dest, buffer, count);
404 g_memory_output_stream_close (GOutputStream *stream,
405 GCancellable *cancellable,
412 g_memory_output_stream_write_async (GOutputStream *stream,
416 GCancellable *cancellable,
417 GAsyncReadyCallback callback,
420 GSimpleAsyncResult *simple;
423 nwritten = g_memory_output_stream_write (stream,
430 simple = g_simple_async_result_new (G_OBJECT (stream),
433 g_memory_output_stream_write_async);
435 g_simple_async_result_set_op_res_gssize (simple, nwritten);
436 g_simple_async_result_complete_in_idle (simple);
437 g_object_unref (simple);
441 g_memory_output_stream_write_finish (GOutputStream *stream,
442 GAsyncResult *result,
445 GSimpleAsyncResult *simple;
448 simple = G_SIMPLE_ASYNC_RESULT (result);
450 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
451 g_memory_output_stream_write_async);
453 nwritten = g_simple_async_result_get_op_res_gssize (simple);
459 g_memory_output_stream_close_async (GOutputStream *stream,
461 GCancellable *cancellable,
462 GAsyncReadyCallback callback,
465 GSimpleAsyncResult *simple;
467 simple = g_simple_async_result_new (G_OBJECT (stream),
470 g_memory_output_stream_close_async);
473 /* will always return TRUE */
474 g_memory_output_stream_close (stream, cancellable, NULL);
476 g_simple_async_result_complete_in_idle (simple);
477 g_object_unref (simple);
481 g_memory_output_stream_close_finish (GOutputStream *stream,
482 GAsyncResult *result,
485 GSimpleAsyncResult *simple;
487 simple = G_SIMPLE_ASYNC_RESULT (result);
489 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
490 g_memory_output_stream_close_async);
496 g_memory_output_stream_tell (GSeekable *seekable)
498 GMemoryOutputStream *stream;
499 GMemoryOutputStreamPrivate *priv;
501 stream = G_MEMORY_OUTPUT_STREAM (seekable);
508 g_memory_output_stream_can_seek (GSeekable *seekable)
514 g_memory_output_stream_seek (GSeekable *seekable,
517 GCancellable *cancellable,
520 GMemoryOutputStream *stream;
521 GMemoryOutputStreamPrivate *priv;
524 stream = G_MEMORY_OUTPUT_STREAM (seekable);
530 absolute = priv->pos + offset;
538 absolute = priv->len + offset;
542 g_set_error_literal (error,
544 G_IO_ERROR_INVALID_ARGUMENT,
545 _("Invalid GSeekType supplied"));
552 g_set_error_literal (error,
554 G_IO_ERROR_INVALID_ARGUMENT,
555 _("Invalid seek request"));
559 if (!array_check_boundary (stream, absolute, error))
562 priv->pos = absolute;
568 g_memory_output_stream_can_truncate (GSeekable *seekable)
570 GMemoryOutputStream *ostream;
571 GMemoryOutputStreamPrivate *priv;
573 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
574 priv = ostream->priv;
576 return priv->realloc_fn != NULL;
580 g_memory_output_stream_truncate (GSeekable *seekable,
582 GCancellable *cancellable,
585 GMemoryOutputStream *ostream;
586 GMemoryOutputStreamPrivate *priv;
588 ostream = G_MEMORY_OUTPUT_STREAM (seekable);
589 priv = ostream->priv;
591 if (!array_resize (ostream, offset, FALSE, error))
597 #define __G_MEMORY_OUTPUT_STREAM_C__
598 #include "gioaliasdef.c"