Release GLib 2.20.1
[glib.git] / gio / gmemoryinputstream.c
blobbb6001bb49af06cd56827b11c229373926b72da7
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, 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>
23 #include "config.h"
24 #include "gmemoryinputstream.h"
25 #include "ginputstream.h"
26 #include "gseekable.h"
27 #include "string.h"
28 #include "gsimpleasyncresult.h"
29 #include "gioerror.h"
30 #include "glibintl.h"
32 #include "gioalias.h"
34 /**
35 * SECTION:gmemoryinputstream
36 * @short_description: Streaming input operations on memory chunks
37 * @include: gio/gio.h
38 * @see_also: #GMemoryOutputStream
40 * #GMemoryInputStream is a class for using arbitrary
41 * memory chunks as input for GIO streaming input operations.
45 typedef struct _Chunk Chunk;
47 struct _Chunk {
48 guint8 *data;
49 gsize len;
50 GDestroyNotify destroy;
53 struct _GMemoryInputStreamPrivate {
54 GSList *chunks;
55 gsize len;
56 gsize pos;
59 static gssize g_memory_input_stream_read (GInputStream *stream,
60 void *buffer,
61 gsize count,
62 GCancellable *cancellable,
63 GError **error);
64 static gssize g_memory_input_stream_skip (GInputStream *stream,
65 gsize count,
66 GCancellable *cancellable,
67 GError **error);
68 static gboolean g_memory_input_stream_close (GInputStream *stream,
69 GCancellable *cancellable,
70 GError **error);
71 static void g_memory_input_stream_read_async (GInputStream *stream,
72 void *buffer,
73 gsize count,
74 int io_priority,
75 GCancellable *cancellable,
76 GAsyncReadyCallback callback,
77 gpointer user_data);
78 static gssize g_memory_input_stream_read_finish (GInputStream *stream,
79 GAsyncResult *result,
80 GError **error);
81 static void g_memory_input_stream_skip_async (GInputStream *stream,
82 gsize count,
83 int io_priority,
84 GCancellable *cancellabl,
85 GAsyncReadyCallback callback,
86 gpointer datae);
87 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
88 GAsyncResult *result,
89 GError **error);
90 static void g_memory_input_stream_close_async (GInputStream *stream,
91 int io_priority,
92 GCancellable *cancellabl,
93 GAsyncReadyCallback callback,
94 gpointer data);
95 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
96 GAsyncResult *result,
97 GError **error);
99 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface);
100 static goffset g_memory_input_stream_tell (GSeekable *seekable);
101 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable);
102 static gboolean g_memory_input_stream_seek (GSeekable *seekable,
103 goffset offset,
104 GSeekType type,
105 GCancellable *cancellable,
106 GError **error);
107 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
108 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
109 goffset offset,
110 GCancellable *cancellable,
111 GError **error);
112 static void g_memory_input_stream_finalize (GObject *object);
114 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
115 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
116 g_memory_input_stream_seekable_iface_init))
119 static void
120 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
122 GObjectClass *object_class;
123 GInputStreamClass *istream_class;
125 g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
127 object_class = G_OBJECT_CLASS (klass);
128 object_class->finalize = g_memory_input_stream_finalize;
130 istream_class = G_INPUT_STREAM_CLASS (klass);
131 istream_class->read_fn = g_memory_input_stream_read;
132 istream_class->skip = g_memory_input_stream_skip;
133 istream_class->close_fn = g_memory_input_stream_close;
135 istream_class->read_async = g_memory_input_stream_read_async;
136 istream_class->read_finish = g_memory_input_stream_read_finish;
137 istream_class->skip_async = g_memory_input_stream_skip_async;
138 istream_class->skip_finish = g_memory_input_stream_skip_finish;
139 istream_class->close_async = g_memory_input_stream_close_async;
140 istream_class->close_finish = g_memory_input_stream_close_finish;
143 static void
144 free_chunk (gpointer data,
145 gpointer user_data)
147 Chunk *chunk = data;
149 if (chunk->destroy)
150 chunk->destroy (chunk->data);
152 g_slice_free (Chunk, chunk);
155 static void
156 g_memory_input_stream_finalize (GObject *object)
158 GMemoryInputStream *stream;
159 GMemoryInputStreamPrivate *priv;
161 stream = G_MEMORY_INPUT_STREAM (object);
162 priv = stream->priv;
164 g_slist_foreach (priv->chunks, free_chunk, NULL);
165 g_slist_free (priv->chunks);
167 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
170 static void
171 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
173 iface->tell = g_memory_input_stream_tell;
174 iface->can_seek = g_memory_input_stream_can_seek;
175 iface->seek = g_memory_input_stream_seek;
176 iface->can_truncate = g_memory_input_stream_can_truncate;
177 iface->truncate_fn = g_memory_input_stream_truncate;
180 static void
181 g_memory_input_stream_init (GMemoryInputStream *stream)
183 stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
184 G_TYPE_MEMORY_INPUT_STREAM,
185 GMemoryInputStreamPrivate);
189 * g_memory_input_stream_new:
191 * Creates a new empty #GMemoryInputStream.
193 * Returns: a new #GInputStream
195 GInputStream *
196 g_memory_input_stream_new (void)
198 GInputStream *stream;
200 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
202 return stream;
206 * g_memory_input_stream_new_from_data:
207 * @data: input data
208 * @len: length of the data, may be -1 if @data is a nul-terminated string
209 * @destroy: function that is called to free @data, or %NULL
211 * Creates a new #GMemoryInputStream with data in memory of a given size.
213 * Returns: new #GInputStream read from @data of @len bytes.
215 GInputStream *
216 g_memory_input_stream_new_from_data (const void *data,
217 gssize len,
218 GDestroyNotify destroy)
220 GInputStream *stream;
222 stream = g_memory_input_stream_new ();
224 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
225 data, len, destroy);
227 return stream;
231 * g_memory_input_stream_add_data:
232 * @stream: a #GMemoryInputStream
233 * @data: input data
234 * @len: length of the data, may be -1 if @data is a nul-terminated string
235 * @destroy: function that is called to free @data, or %NULL
237 * Appends @data to data that can be read from the input stream
239 void
240 g_memory_input_stream_add_data (GMemoryInputStream *stream,
241 const void *data,
242 gssize len,
243 GDestroyNotify destroy)
245 GMemoryInputStreamPrivate *priv;
246 Chunk *chunk;
248 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
249 g_return_if_fail (data != NULL);
251 priv = stream->priv;
253 if (len == -1)
254 len = strlen (data);
256 chunk = g_slice_new (Chunk);
257 chunk->data = (guint8 *)data;
258 chunk->len = len;
259 chunk->destroy = destroy;
261 priv->chunks = g_slist_append (priv->chunks, chunk);
262 priv->len += chunk->len;
265 static gssize
266 g_memory_input_stream_read (GInputStream *stream,
267 void *buffer,
268 gsize count,
269 GCancellable *cancellable,
270 GError **error)
272 GMemoryInputStream *memory_stream;
273 GMemoryInputStreamPrivate *priv;
274 GSList *l;
275 Chunk *chunk;
276 gsize offset, start, rest, size;
278 memory_stream = G_MEMORY_INPUT_STREAM (stream);
279 priv = memory_stream->priv;
281 count = MIN (count, priv->len - priv->pos);
283 offset = 0;
284 for (l = priv->chunks; l; l = l->next)
286 chunk = (Chunk *)l->data;
288 if (offset + chunk->len > priv->pos)
289 break;
291 offset += chunk->len;
294 start = priv->pos - offset;
295 rest = count;
297 for (; l && rest > 0; l = l->next)
299 chunk = (Chunk *)l->data;
300 size = MIN (rest, chunk->len - start);
302 memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
303 rest -= size;
305 start = 0;
308 priv->pos += count;
310 return count;
313 static gssize
314 g_memory_input_stream_skip (GInputStream *stream,
315 gsize count,
316 GCancellable *cancellable,
317 GError **error)
319 GMemoryInputStream *memory_stream;
320 GMemoryInputStreamPrivate *priv;
322 memory_stream = G_MEMORY_INPUT_STREAM (stream);
323 priv = memory_stream->priv;
325 count = MIN (count, priv->len - priv->pos);
326 priv->pos += count;
328 return count;
331 static gboolean
332 g_memory_input_stream_close (GInputStream *stream,
333 GCancellable *cancellable,
334 GError **error)
336 return TRUE;
339 static void
340 g_memory_input_stream_read_async (GInputStream *stream,
341 void *buffer,
342 gsize count,
343 int io_priority,
344 GCancellable *cancellable,
345 GAsyncReadyCallback callback,
346 gpointer user_data)
348 GSimpleAsyncResult *simple;
349 gssize nread;
351 nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
352 simple = g_simple_async_result_new (G_OBJECT (stream),
353 callback,
354 user_data,
355 g_memory_input_stream_read_async);
356 g_simple_async_result_set_op_res_gssize (simple, nread);
357 g_simple_async_result_complete_in_idle (simple);
358 g_object_unref (simple);
361 static gssize
362 g_memory_input_stream_read_finish (GInputStream *stream,
363 GAsyncResult *result,
364 GError **error)
366 GSimpleAsyncResult *simple;
367 gssize nread;
369 simple = G_SIMPLE_ASYNC_RESULT (result);
370 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
372 nread = g_simple_async_result_get_op_res_gssize (simple);
373 return nread;
376 static void
377 g_memory_input_stream_skip_async (GInputStream *stream,
378 gsize count,
379 int io_priority,
380 GCancellable *cancellable,
381 GAsyncReadyCallback callback,
382 gpointer user_data)
384 GSimpleAsyncResult *simple;
385 gssize nskipped;
387 nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
388 simple = g_simple_async_result_new (G_OBJECT (stream),
389 callback,
390 user_data,
391 g_memory_input_stream_skip_async);
392 g_simple_async_result_set_op_res_gssize (simple, nskipped);
393 g_simple_async_result_complete_in_idle (simple);
394 g_object_unref (simple);
397 static gssize
398 g_memory_input_stream_skip_finish (GInputStream *stream,
399 GAsyncResult *result,
400 GError **error)
402 GSimpleAsyncResult *simple;
403 gssize nskipped;
405 simple = G_SIMPLE_ASYNC_RESULT (result);
406 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
408 nskipped = g_simple_async_result_get_op_res_gssize (simple);
409 return nskipped;
412 static void
413 g_memory_input_stream_close_async (GInputStream *stream,
414 int io_priority,
415 GCancellable *cancellable,
416 GAsyncReadyCallback callback,
417 gpointer user_data)
419 GSimpleAsyncResult *simple;
421 simple = g_simple_async_result_new (G_OBJECT (stream),
422 callback,
423 user_data,
424 g_memory_input_stream_close_async);
425 g_simple_async_result_complete_in_idle (simple);
426 g_object_unref (simple);
429 static gboolean
430 g_memory_input_stream_close_finish (GInputStream *stream,
431 GAsyncResult *result,
432 GError **error)
434 return TRUE;
437 static goffset
438 g_memory_input_stream_tell (GSeekable *seekable)
440 GMemoryInputStream *memory_stream;
441 GMemoryInputStreamPrivate *priv;
443 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
444 priv = memory_stream->priv;
446 return priv->pos;
449 static
450 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
452 return TRUE;
455 static gboolean
456 g_memory_input_stream_seek (GSeekable *seekable,
457 goffset offset,
458 GSeekType type,
459 GCancellable *cancellable,
460 GError **error)
462 GMemoryInputStream *memory_stream;
463 GMemoryInputStreamPrivate *priv;
464 goffset absolute;
466 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
467 priv = memory_stream->priv;
469 switch (type)
471 case G_SEEK_CUR:
472 absolute = priv->pos + offset;
473 break;
475 case G_SEEK_SET:
476 absolute = offset;
477 break;
479 case G_SEEK_END:
480 absolute = priv->len + offset;
481 break;
483 default:
484 g_set_error_literal (error,
485 G_IO_ERROR,
486 G_IO_ERROR_INVALID_ARGUMENT,
487 _("Invalid GSeekType supplied"));
489 return FALSE;
492 if (absolute < 0 || absolute > priv->len)
494 g_set_error_literal (error,
495 G_IO_ERROR,
496 G_IO_ERROR_INVALID_ARGUMENT,
497 _("Invalid seek request"));
498 return FALSE;
501 priv->pos = absolute;
503 return TRUE;
506 static gboolean
507 g_memory_input_stream_can_truncate (GSeekable *seekable)
509 return FALSE;
512 static gboolean
513 g_memory_input_stream_truncate (GSeekable *seekable,
514 goffset offset,
515 GCancellable *cancellable,
516 GError **error)
518 g_set_error_literal (error,
519 G_IO_ERROR,
520 G_IO_ERROR_NOT_SUPPORTED,
521 _("Cannot truncate GMemoryInputStream"));
522 return FALSE;
525 #define __G_MEMORY_INPUT_STREAM_C__
526 #include "gioaliasdef.c"