gtestutils: Fix a typo in a documentation comment
[glib.git] / gio / gmemoryinputstream.c
blobc77aeb7d84e51b20ba56df479bac22ef1f9a9356
1 /* GIO - GLib Input, Output and Streaming Library
2 *
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>
21 #include "config.h"
22 #include "gmemoryinputstream.h"
23 #include "gpollableinputstream.h"
24 #include "ginputstream.h"
25 #include "gseekable.h"
26 #include "string.h"
27 #include "gtask.h"
28 #include "gioerror.h"
29 #include "glibintl.h"
32 /**
33 * SECTION:gmemoryinputstream
34 * @short_description: Streaming input operations on memory chunks
35 * @include: gio/gio.h
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 {
46 GSList *chunks;
47 gsize len;
48 gsize pos;
51 static gssize g_memory_input_stream_read (GInputStream *stream,
52 void *buffer,
53 gsize count,
54 GCancellable *cancellable,
55 GError **error);
56 static gssize g_memory_input_stream_skip (GInputStream *stream,
57 gsize count,
58 GCancellable *cancellable,
59 GError **error);
60 static gboolean g_memory_input_stream_close (GInputStream *stream,
61 GCancellable *cancellable,
62 GError **error);
63 static void g_memory_input_stream_skip_async (GInputStream *stream,
64 gsize count,
65 int io_priority,
66 GCancellable *cancellabl,
67 GAsyncReadyCallback callback,
68 gpointer datae);
69 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
70 GAsyncResult *result,
71 GError **error);
72 static void g_memory_input_stream_close_async (GInputStream *stream,
73 int io_priority,
74 GCancellable *cancellabl,
75 GAsyncReadyCallback callback,
76 gpointer data);
77 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
78 GAsyncResult *result,
79 GError **error);
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,
85 goffset offset,
86 GSeekType type,
87 GCancellable *cancellable,
88 GError **error);
89 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
90 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
91 goffset offset,
92 GCancellable *cancellable,
93 GError **error);
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);
111 static void
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;
131 static void
132 g_memory_input_stream_finalize (GObject *object)
134 GMemoryInputStream *stream;
135 GMemoryInputStreamPrivate *priv;
137 stream = G_MEMORY_INPUT_STREAM (object);
138 priv = stream->priv;
140 g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
142 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
145 static void
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;
155 static void
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;
162 static void
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
175 GInputStream *
176 g_memory_input_stream_new (void)
178 GInputStream *stream;
180 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
182 return stream;
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: (nullable): 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.
195 GInputStream *
196 g_memory_input_stream_new_from_data (const void *data,
197 gssize len,
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),
205 data, len, destroy);
207 return stream;
211 * g_memory_input_stream_new_from_bytes:
212 * @bytes: a #GBytes
214 * Creates a new #GMemoryInputStream with data from the given @bytes.
216 * Returns: new #GInputStream read from @bytes
218 * Since: 2.34
220 GInputStream *
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),
229 bytes);
231 return 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: (nullable): function that is called to free @data, or %NULL
241 * Appends @data to data that can be read from the input stream
243 void
244 g_memory_input_stream_add_data (GMemoryInputStream *stream,
245 const void *data,
246 gssize len,
247 GDestroyNotify destroy)
249 GBytes *bytes;
251 if (len == -1)
252 len = strlen (data);
254 /* It's safe to discard the const here because we're chaining the
255 * destroy callback.
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
267 * @bytes: input data
269 * Appends @bytes to data that can be read from the input stream.
271 * Since: 2.34
273 void
274 g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
275 GBytes *bytes)
277 GMemoryInputStreamPrivate *priv;
279 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
280 g_return_if_fail (bytes != NULL);
282 priv = stream->priv;
284 priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
285 priv->len += g_bytes_get_size (bytes);
288 static gssize
289 g_memory_input_stream_read (GInputStream *stream,
290 void *buffer,
291 gsize count,
292 GCancellable *cancellable,
293 GError **error)
295 GMemoryInputStream *memory_stream;
296 GMemoryInputStreamPrivate *priv;
297 GSList *l;
298 GBytes *chunk;
299 gsize len;
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);
307 offset = 0;
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)
314 break;
316 offset += len;
319 start = priv->pos - offset;
320 rest = count;
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);
332 rest -= size;
334 start = 0;
337 priv->pos += count;
339 return count;
342 static gssize
343 g_memory_input_stream_skip (GInputStream *stream,
344 gsize count,
345 GCancellable *cancellable,
346 GError **error)
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);
355 priv->pos += count;
357 return count;
360 static gboolean
361 g_memory_input_stream_close (GInputStream *stream,
362 GCancellable *cancellable,
363 GError **error)
365 return TRUE;
368 static void
369 g_memory_input_stream_skip_async (GInputStream *stream,
370 gsize count,
371 int io_priority,
372 GCancellable *cancellable,
373 GAsyncReadyCallback callback,
374 gpointer user_data)
376 GTask *task;
377 gssize nskipped;
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);
382 g_task_set_source_tag (task, g_memory_input_stream_skip_async);
384 if (error)
385 g_task_return_error (task, error);
386 else
387 g_task_return_int (task, nskipped);
388 g_object_unref (task);
391 static gssize
392 g_memory_input_stream_skip_finish (GInputStream *stream,
393 GAsyncResult *result,
394 GError **error)
396 g_return_val_if_fail (g_task_is_valid (result, stream), -1);
398 return g_task_propagate_int (G_TASK (result), error);
401 static void
402 g_memory_input_stream_close_async (GInputStream *stream,
403 int io_priority,
404 GCancellable *cancellable,
405 GAsyncReadyCallback callback,
406 gpointer user_data)
408 GTask *task;
410 task = g_task_new (stream, cancellable, callback, user_data);
411 g_task_set_source_tag (task, g_memory_input_stream_close_async);
412 g_task_return_boolean (task, TRUE);
413 g_object_unref (task);
416 static gboolean
417 g_memory_input_stream_close_finish (GInputStream *stream,
418 GAsyncResult *result,
419 GError **error)
421 return TRUE;
424 static goffset
425 g_memory_input_stream_tell (GSeekable *seekable)
427 GMemoryInputStream *memory_stream;
428 GMemoryInputStreamPrivate *priv;
430 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
431 priv = memory_stream->priv;
433 return priv->pos;
436 static
437 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
439 return TRUE;
442 static gboolean
443 g_memory_input_stream_seek (GSeekable *seekable,
444 goffset offset,
445 GSeekType type,
446 GCancellable *cancellable,
447 GError **error)
449 GMemoryInputStream *memory_stream;
450 GMemoryInputStreamPrivate *priv;
451 goffset absolute;
453 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
454 priv = memory_stream->priv;
456 switch (type)
458 case G_SEEK_CUR:
459 absolute = priv->pos + offset;
460 break;
462 case G_SEEK_SET:
463 absolute = offset;
464 break;
466 case G_SEEK_END:
467 absolute = priv->len + offset;
468 break;
470 default:
471 g_set_error_literal (error,
472 G_IO_ERROR,
473 G_IO_ERROR_INVALID_ARGUMENT,
474 _("Invalid GSeekType supplied"));
476 return FALSE;
479 if (absolute < 0 || absolute > priv->len)
481 g_set_error_literal (error,
482 G_IO_ERROR,
483 G_IO_ERROR_INVALID_ARGUMENT,
484 _("Invalid seek request"));
485 return FALSE;
488 priv->pos = absolute;
490 return TRUE;
493 static gboolean
494 g_memory_input_stream_can_truncate (GSeekable *seekable)
496 return FALSE;
499 static gboolean
500 g_memory_input_stream_truncate (GSeekable *seekable,
501 goffset offset,
502 GCancellable *cancellable,
503 GError **error)
505 g_set_error_literal (error,
506 G_IO_ERROR,
507 G_IO_ERROR_NOT_SUPPORTED,
508 _("Cannot truncate GMemoryInputStream"));
509 return FALSE;
512 static gboolean
513 g_memory_input_stream_is_readable (GPollableInputStream *stream)
515 return TRUE;
518 static GSource *
519 g_memory_input_stream_create_source (GPollableInputStream *stream,
520 GCancellable *cancellable)
522 GSource *base_source, *pollable_source;
524 base_source = g_timeout_source_new (0);
525 pollable_source = g_pollable_source_new_full (stream, base_source,
526 cancellable);
527 g_source_unref (base_source);
529 return pollable_source;