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 "gmemoryinputstream.h"
25 #include "ginputstream.h"
26 #include "gseekable.h"
28 #include "gsimpleasyncresult.h"
34 * SECTION:gmemoryinputstream
35 * @short_description: Streaming input operations on memory chunks
37 * @see_also: #GMemoryOutputStream
39 * #GMemoryInputStream is a class for using arbitrary
40 * memory chunks as input for GIO streaming input operations.
44 typedef struct _Chunk Chunk;
49 GDestroyNotify destroy;
51 GDestroyNotify user_data_destroy;
54 struct _GMemoryInputStreamPrivate {
60 static gssize g_memory_input_stream_read (GInputStream *stream,
63 GCancellable *cancellable,
65 static gssize g_memory_input_stream_skip (GInputStream *stream,
67 GCancellable *cancellable,
69 static gboolean g_memory_input_stream_close (GInputStream *stream,
70 GCancellable *cancellable,
72 static void g_memory_input_stream_read_async (GInputStream *stream,
76 GCancellable *cancellable,
77 GAsyncReadyCallback callback,
79 static gssize g_memory_input_stream_read_finish (GInputStream *stream,
82 static void g_memory_input_stream_skip_async (GInputStream *stream,
85 GCancellable *cancellabl,
86 GAsyncReadyCallback callback,
88 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
91 static void g_memory_input_stream_close_async (GInputStream *stream,
93 GCancellable *cancellabl,
94 GAsyncReadyCallback callback,
96 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
100 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface);
101 static goffset g_memory_input_stream_tell (GSeekable *seekable);
102 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable);
103 static gboolean g_memory_input_stream_seek (GSeekable *seekable,
106 GCancellable *cancellable,
108 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
109 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
111 GCancellable *cancellable,
113 static void g_memory_input_stream_finalize (GObject *object);
115 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
116 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
117 g_memory_input_stream_seekable_iface_init))
121 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
123 GObjectClass *object_class;
124 GInputStreamClass *istream_class;
126 g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
128 object_class = G_OBJECT_CLASS (klass);
129 object_class->finalize = g_memory_input_stream_finalize;
131 istream_class = G_INPUT_STREAM_CLASS (klass);
132 istream_class->read_fn = g_memory_input_stream_read;
133 istream_class->skip = g_memory_input_stream_skip;
134 istream_class->close_fn = g_memory_input_stream_close;
136 istream_class->read_async = g_memory_input_stream_read_async;
137 istream_class->read_finish = g_memory_input_stream_read_finish;
138 istream_class->skip_async = g_memory_input_stream_skip_async;
139 istream_class->skip_finish = g_memory_input_stream_skip_finish;
140 istream_class->close_async = g_memory_input_stream_close_async;
141 istream_class->close_finish = g_memory_input_stream_close_finish;
145 free_chunk (gpointer data,
151 chunk->destroy (chunk->data);
153 if (chunk->user_data_destroy)
154 chunk->user_data_destroy (chunk->user_data);
156 g_slice_free (Chunk, chunk);
160 g_memory_input_stream_finalize (GObject *object)
162 GMemoryInputStream *stream;
163 GMemoryInputStreamPrivate *priv;
165 stream = G_MEMORY_INPUT_STREAM (object);
168 g_slist_foreach (priv->chunks, free_chunk, NULL);
169 g_slist_free (priv->chunks);
171 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
175 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
177 iface->tell = g_memory_input_stream_tell;
178 iface->can_seek = g_memory_input_stream_can_seek;
179 iface->seek = g_memory_input_stream_seek;
180 iface->can_truncate = g_memory_input_stream_can_truncate;
181 iface->truncate_fn = g_memory_input_stream_truncate;
185 g_memory_input_stream_init (GMemoryInputStream *stream)
187 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
188 G_TYPE_MEMORY_INPUT_STREAM,
189 GMemoryInputStreamPrivate);
193 * g_memory_input_stream_new:
195 * Creates a new empty #GMemoryInputStream.
197 * Returns: a new #GInputStream
200 g_memory_input_stream_new (void)
202 GInputStream *stream;
204 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
210 * g_memory_input_stream_new_from_data:
211 * @data: (array length=len) (element-type guint8): input data
212 * @len: length of the data, may be -1 if @data is a nul-terminated string
213 * @destroy: (allow-none): function that is called to free @data, or %NULL
215 * Creates a new #GMemoryInputStream with data in memory of a given size.
217 * Returns: new #GInputStream read from @data of @len bytes.
220 g_memory_input_stream_new_from_data (const void *data,
222 GDestroyNotify destroy)
224 return g_memory_input_stream_new_from_data_full (data, len, destroy, NULL, NULL);
228 * g_memory_input_stream_new_from_data_full:
229 * @data: (array length=len) (element-type guint8): input data
230 * @len: length of the data, may be -1 if @data is a nul-terminated string
231 * @destroy: (allow-none): function that is called to free @data, or %NULL
232 * @user_data: extra state pointer related to the chunk of data
233 * @user_data_destroy: function that is called to free @user_data, or %NULL
235 * Creates a new #GMemoryInputStream with data in memory of a given size.
237 * This function differs from g_memory_input_stream_new_from_data() only
238 * because it allows a pointer to some additional state related to
239 * the data chunk to be stored (this can be used to properly manage
240 * the life cycle of data chunks from language bindings).
242 * Returns: new #GInputStream read from @data of @len bytes.
247 g_memory_input_stream_new_from_data_full (const void *data,
249 GDestroyNotify destroy,
251 GDestroyNotify user_data_destroy)
253 GInputStream *stream;
255 stream = g_memory_input_stream_new ();
257 g_memory_input_stream_add_data_full (G_MEMORY_INPUT_STREAM (stream),
259 user_data, user_data_destroy);
265 * g_memory_input_stream_add_data:
266 * @stream: a #GMemoryInputStream
267 * @data: (array length=len) (element-type guint8): input data
268 * @len: length of the data, may be -1 if @data is a nul-terminated string
269 * @destroy: (allow-none): function that is called to free @data, or %NULL
271 * Appends @data to data that can be read from the input stream
274 g_memory_input_stream_add_data (GMemoryInputStream *stream,
277 GDestroyNotify destroy)
279 g_memory_input_stream_add_data_full (stream, data, len, destroy, NULL, NULL);
283 * g_memory_input_stream_add_data_full:
284 * @stream: a #GMemoryInputStream
285 * @data: (array length=len) (element-type guint8): input data
286 * @len: length of the data, may be -1 if @data is a nul-terminated string
287 * @destroy: (allow-none): function that is called to free @data, or %NULL
288 * @user_data: extra state pointer related to the chunk of data
289 * @user_data_destroy: function that is called to free @user_data, or %NULL
291 * Appends @data to data that can be read from the input stream
293 * This function differs from g_memory_input_stream_add_data() only
294 * because it allows a pointer to some additional state related to
295 * the data chunk to be stored (this can be used to properly manage
296 * the life cycle of data chunks from language bindings).
301 g_memory_input_stream_add_data_full (GMemoryInputStream *stream,
304 GDestroyNotify destroy,
306 GDestroyNotify user_data_destroy)
308 GMemoryInputStreamPrivate *priv;
311 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
312 g_return_if_fail (data != NULL);
319 chunk = g_slice_new (Chunk);
320 chunk->data = (guint8 *)data;
322 chunk->destroy = destroy;
323 chunk->user_data = user_data;
324 chunk->user_data_destroy = user_data_destroy;
326 priv->chunks = g_slist_append (priv->chunks, chunk);
327 priv->len += chunk->len;
331 g_memory_input_stream_read (GInputStream *stream,
334 GCancellable *cancellable,
337 GMemoryInputStream *memory_stream;
338 GMemoryInputStreamPrivate *priv;
341 gsize offset, start, rest, size;
343 memory_stream = G_MEMORY_INPUT_STREAM (stream);
344 priv = memory_stream->priv;
346 count = MIN (count, priv->len - priv->pos);
349 for (l = priv->chunks; l; l = l->next)
351 chunk = (Chunk *)l->data;
353 if (offset + chunk->len > priv->pos)
356 offset += chunk->len;
359 start = priv->pos - offset;
362 for (; l && rest > 0; l = l->next)
364 chunk = (Chunk *)l->data;
365 size = MIN (rest, chunk->len - start);
367 memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
379 g_memory_input_stream_skip (GInputStream *stream,
381 GCancellable *cancellable,
384 GMemoryInputStream *memory_stream;
385 GMemoryInputStreamPrivate *priv;
387 memory_stream = G_MEMORY_INPUT_STREAM (stream);
388 priv = memory_stream->priv;
390 count = MIN (count, priv->len - priv->pos);
397 g_memory_input_stream_close (GInputStream *stream,
398 GCancellable *cancellable,
405 g_memory_input_stream_read_async (GInputStream *stream,
409 GCancellable *cancellable,
410 GAsyncReadyCallback callback,
413 GSimpleAsyncResult *simple;
416 nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
417 simple = g_simple_async_result_new (G_OBJECT (stream),
420 g_memory_input_stream_read_async);
421 g_simple_async_result_set_op_res_gssize (simple, nread);
422 g_simple_async_result_complete_in_idle (simple);
423 g_object_unref (simple);
427 g_memory_input_stream_read_finish (GInputStream *stream,
428 GAsyncResult *result,
431 GSimpleAsyncResult *simple;
434 simple = G_SIMPLE_ASYNC_RESULT (result);
435 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
437 nread = g_simple_async_result_get_op_res_gssize (simple);
442 g_memory_input_stream_skip_async (GInputStream *stream,
445 GCancellable *cancellable,
446 GAsyncReadyCallback callback,
449 GSimpleAsyncResult *simple;
452 nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
453 simple = g_simple_async_result_new (G_OBJECT (stream),
456 g_memory_input_stream_skip_async);
457 g_simple_async_result_set_op_res_gssize (simple, nskipped);
458 g_simple_async_result_complete_in_idle (simple);
459 g_object_unref (simple);
463 g_memory_input_stream_skip_finish (GInputStream *stream,
464 GAsyncResult *result,
467 GSimpleAsyncResult *simple;
470 simple = G_SIMPLE_ASYNC_RESULT (result);
471 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
473 nskipped = g_simple_async_result_get_op_res_gssize (simple);
478 g_memory_input_stream_close_async (GInputStream *stream,
480 GCancellable *cancellable,
481 GAsyncReadyCallback callback,
484 GSimpleAsyncResult *simple;
486 simple = g_simple_async_result_new (G_OBJECT (stream),
489 g_memory_input_stream_close_async);
490 g_simple_async_result_complete_in_idle (simple);
491 g_object_unref (simple);
495 g_memory_input_stream_close_finish (GInputStream *stream,
496 GAsyncResult *result,
503 g_memory_input_stream_tell (GSeekable *seekable)
505 GMemoryInputStream *memory_stream;
506 GMemoryInputStreamPrivate *priv;
508 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
509 priv = memory_stream->priv;
515 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
521 g_memory_input_stream_seek (GSeekable *seekable,
524 GCancellable *cancellable,
527 GMemoryInputStream *memory_stream;
528 GMemoryInputStreamPrivate *priv;
531 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
532 priv = memory_stream->priv;
537 absolute = priv->pos + offset;
545 absolute = priv->len + offset;
549 g_set_error_literal (error,
551 G_IO_ERROR_INVALID_ARGUMENT,
552 _("Invalid GSeekType supplied"));
557 if (absolute < 0 || absolute > priv->len)
559 g_set_error_literal (error,
561 G_IO_ERROR_INVALID_ARGUMENT,
562 _("Invalid seek request"));
566 priv->pos = absolute;
572 g_memory_input_stream_can_truncate (GSeekable *seekable)
578 g_memory_input_stream_truncate (GSeekable *seekable,
580 GCancellable *cancellable,
583 g_set_error_literal (error,
585 G_IO_ERROR_NOT_SUPPORTED,
586 _("Cannot truncate GMemoryInputStream"));