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, see <http://www.gnu.org/licenses/>.
18 * Author: Christian Kellner <gicmo@gnome.org>
22 #include "gmemoryinputstream.h"
23 #include "gpollableinputstream.h"
24 #include "ginputstream.h"
25 #include "gseekable.h"
33 * SECTION:gmemoryinputstream
34 * @short_description: Streaming input operations on memory chunks
36 * @see_also: #GMemoryOutputStream
38 * #GMemoryInputStream is a class for using arbitrary
39 * memory chunks as input for GIO streaming input operations.
41 * As of GLib 2.34, #GMemoryInputStream implements
42 * #GPollableInputStream.
45 struct _GMemoryInputStreamPrivate {
51 static gssize g_memory_input_stream_read (GInputStream *stream,
54 GCancellable *cancellable,
56 static gssize g_memory_input_stream_skip (GInputStream *stream,
58 GCancellable *cancellable,
60 static gboolean g_memory_input_stream_close (GInputStream *stream,
61 GCancellable *cancellable,
63 static void g_memory_input_stream_skip_async (GInputStream *stream,
66 GCancellable *cancellabl,
67 GAsyncReadyCallback callback,
69 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
72 static void g_memory_input_stream_close_async (GInputStream *stream,
74 GCancellable *cancellabl,
75 GAsyncReadyCallback callback,
77 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
81 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface);
82 static goffset g_memory_input_stream_tell (GSeekable *seekable);
83 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable);
84 static gboolean g_memory_input_stream_seek (GSeekable *seekable,
87 GCancellable *cancellable,
89 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
90 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
92 GCancellable *cancellable,
95 static void g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
96 static gboolean g_memory_input_stream_is_readable (GPollableInputStream *stream);
97 static GSource *g_memory_input_stream_create_source (GPollableInputStream *stream,
98 GCancellable *cancellable);
100 static void g_memory_input_stream_finalize (GObject *object);
102 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
103 G_ADD_PRIVATE (GMemoryInputStream)
104 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
105 g_memory_input_stream_seekable_iface_init);
106 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
107 g_memory_input_stream_pollable_iface_init);
112 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
114 GObjectClass *object_class;
115 GInputStreamClass *istream_class;
117 object_class = G_OBJECT_CLASS (klass);
118 object_class->finalize = g_memory_input_stream_finalize;
120 istream_class = G_INPUT_STREAM_CLASS (klass);
121 istream_class->read_fn = g_memory_input_stream_read;
122 istream_class->skip = g_memory_input_stream_skip;
123 istream_class->close_fn = g_memory_input_stream_close;
125 istream_class->skip_async = g_memory_input_stream_skip_async;
126 istream_class->skip_finish = g_memory_input_stream_skip_finish;
127 istream_class->close_async = g_memory_input_stream_close_async;
128 istream_class->close_finish = g_memory_input_stream_close_finish;
132 g_memory_input_stream_finalize (GObject *object)
134 GMemoryInputStream *stream;
135 GMemoryInputStreamPrivate *priv;
137 stream = G_MEMORY_INPUT_STREAM (object);
140 g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
142 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
146 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
148 iface->tell = g_memory_input_stream_tell;
149 iface->can_seek = g_memory_input_stream_can_seek;
150 iface->seek = g_memory_input_stream_seek;
151 iface->can_truncate = g_memory_input_stream_can_truncate;
152 iface->truncate_fn = g_memory_input_stream_truncate;
156 g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
158 iface->is_readable = g_memory_input_stream_is_readable;
159 iface->create_source = g_memory_input_stream_create_source;
163 g_memory_input_stream_init (GMemoryInputStream *stream)
165 stream->priv = g_memory_input_stream_get_instance_private (stream);
169 * g_memory_input_stream_new:
171 * Creates a new empty #GMemoryInputStream.
173 * Returns: a new #GInputStream
176 g_memory_input_stream_new (void)
178 GInputStream *stream;
180 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
186 * g_memory_input_stream_new_from_data:
187 * @data: (array length=len) (element-type guint8) (transfer full): input data
188 * @len: length of the data, may be -1 if @data is a nul-terminated string
189 * @destroy: (allow-none): function that is called to free @data, or %NULL
191 * Creates a new #GMemoryInputStream with data in memory of a given size.
193 * Returns: new #GInputStream read from @data of @len bytes.
196 g_memory_input_stream_new_from_data (const void *data,
198 GDestroyNotify destroy)
200 GInputStream *stream;
202 stream = g_memory_input_stream_new ();
204 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
211 * g_memory_input_stream_new_from_bytes:
214 * Creates a new #GMemoryInputStream with data from the given @bytes.
216 * Returns: new #GInputStream read from @bytes
221 g_memory_input_stream_new_from_bytes (GBytes *bytes)
224 GInputStream *stream;
226 stream = g_memory_input_stream_new ();
228 g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
235 * g_memory_input_stream_add_data:
236 * @stream: a #GMemoryInputStream
237 * @data: (array length=len) (element-type guint8) (transfer full): input data
238 * @len: length of the data, may be -1 if @data is a nul-terminated string
239 * @destroy: (allow-none): function that is called to free @data, or %NULL
241 * Appends @data to data that can be read from the input stream
244 g_memory_input_stream_add_data (GMemoryInputStream *stream,
247 GDestroyNotify destroy)
254 /* It's safe to discard the const here because we're chaining the
257 bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data);
259 g_memory_input_stream_add_bytes (stream, bytes);
261 g_bytes_unref (bytes);
265 * g_memory_input_stream_add_bytes:
266 * @stream: a #GMemoryInputStream
269 * Appends @bytes to data that can be read from the input stream.
274 g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
277 GMemoryInputStreamPrivate *priv;
279 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
280 g_return_if_fail (bytes != NULL);
284 priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
285 priv->len += g_bytes_get_size (bytes);
289 g_memory_input_stream_read (GInputStream *stream,
292 GCancellable *cancellable,
295 GMemoryInputStream *memory_stream;
296 GMemoryInputStreamPrivate *priv;
300 gsize offset, start, rest, size;
302 memory_stream = G_MEMORY_INPUT_STREAM (stream);
303 priv = memory_stream->priv;
305 count = MIN (count, priv->len - priv->pos);
308 for (l = priv->chunks; l; l = l->next)
310 chunk = (GBytes *)l->data;
311 len = g_bytes_get_size (chunk);
313 if (offset + len > priv->pos)
319 start = priv->pos - offset;
322 for (; l && rest > 0; l = l->next)
324 const guint8* chunk_data;
325 chunk = (GBytes *)l->data;
327 chunk_data = g_bytes_get_data (chunk, &len);
329 size = MIN (rest, len - start);
331 memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
343 g_memory_input_stream_skip (GInputStream *stream,
345 GCancellable *cancellable,
348 GMemoryInputStream *memory_stream;
349 GMemoryInputStreamPrivate *priv;
351 memory_stream = G_MEMORY_INPUT_STREAM (stream);
352 priv = memory_stream->priv;
354 count = MIN (count, priv->len - priv->pos);
361 g_memory_input_stream_close (GInputStream *stream,
362 GCancellable *cancellable,
369 g_memory_input_stream_skip_async (GInputStream *stream,
372 GCancellable *cancellable,
373 GAsyncReadyCallback callback,
378 GError *error = NULL;
380 nskipped = G_INPUT_STREAM_GET_CLASS (stream)->skip (stream, count, cancellable, &error);
381 task = g_task_new (stream, cancellable, callback, user_data);
383 g_task_return_error (task, error);
385 g_task_return_int (task, nskipped);
386 g_object_unref (task);
390 g_memory_input_stream_skip_finish (GInputStream *stream,
391 GAsyncResult *result,
394 g_return_val_if_fail (g_task_is_valid (result, stream), -1);
396 return g_task_propagate_int (G_TASK (result), error);
400 g_memory_input_stream_close_async (GInputStream *stream,
402 GCancellable *cancellable,
403 GAsyncReadyCallback callback,
408 task = g_task_new (stream, cancellable, callback, user_data);
409 g_task_return_boolean (task, TRUE);
410 g_object_unref (task);
414 g_memory_input_stream_close_finish (GInputStream *stream,
415 GAsyncResult *result,
422 g_memory_input_stream_tell (GSeekable *seekable)
424 GMemoryInputStream *memory_stream;
425 GMemoryInputStreamPrivate *priv;
427 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
428 priv = memory_stream->priv;
434 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
440 g_memory_input_stream_seek (GSeekable *seekable,
443 GCancellable *cancellable,
446 GMemoryInputStream *memory_stream;
447 GMemoryInputStreamPrivate *priv;
450 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
451 priv = memory_stream->priv;
456 absolute = priv->pos + offset;
464 absolute = priv->len + offset;
468 g_set_error_literal (error,
470 G_IO_ERROR_INVALID_ARGUMENT,
471 _("Invalid GSeekType supplied"));
476 if (absolute < 0 || absolute > priv->len)
478 g_set_error_literal (error,
480 G_IO_ERROR_INVALID_ARGUMENT,
481 _("Invalid seek request"));
485 priv->pos = absolute;
491 g_memory_input_stream_can_truncate (GSeekable *seekable)
497 g_memory_input_stream_truncate (GSeekable *seekable,
499 GCancellable *cancellable,
502 g_set_error_literal (error,
504 G_IO_ERROR_NOT_SUPPORTED,
505 _("Cannot truncate GMemoryInputStream"));
510 g_memory_input_stream_is_readable (GPollableInputStream *stream)
516 g_memory_input_stream_create_source (GPollableInputStream *stream,
517 GCancellable *cancellable)
519 GSource *base_source, *pollable_source;
521 base_source = g_timeout_source_new (0);
522 pollable_source = g_pollable_source_new_full (stream, base_source,
524 g_source_unref (base_source);
526 return pollable_source;