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"
35 * SECTION:gmemoryinputstream
36 * @short_description: Streaming input operations on memory chunks
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
;
50 GDestroyNotify destroy
;
53 struct _GMemoryInputStreamPrivate
{
59 static gssize
g_memory_input_stream_read (GInputStream
*stream
,
62 GCancellable
*cancellable
,
64 static gssize
g_memory_input_stream_skip (GInputStream
*stream
,
66 GCancellable
*cancellable
,
68 static gboolean
g_memory_input_stream_close (GInputStream
*stream
,
69 GCancellable
*cancellable
,
71 static void g_memory_input_stream_read_async (GInputStream
*stream
,
75 GCancellable
*cancellable
,
76 GAsyncReadyCallback callback
,
78 static gssize
g_memory_input_stream_read_finish (GInputStream
*stream
,
81 static void g_memory_input_stream_skip_async (GInputStream
*stream
,
84 GCancellable
*cancellabl
,
85 GAsyncReadyCallback callback
,
87 static gssize
g_memory_input_stream_skip_finish (GInputStream
*stream
,
90 static void g_memory_input_stream_close_async (GInputStream
*stream
,
92 GCancellable
*cancellabl
,
93 GAsyncReadyCallback callback
,
95 static gboolean
g_memory_input_stream_close_finish (GInputStream
*stream
,
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
,
105 GCancellable
*cancellable
,
107 static gboolean
g_memory_input_stream_can_truncate (GSeekable
*seekable
);
108 static gboolean
g_memory_input_stream_truncate (GSeekable
*seekable
,
110 GCancellable
*cancellable
,
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
))
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
;
144 free_chunk (gpointer data
,
150 chunk
->destroy (chunk
->data
);
152 g_slice_free (Chunk
, chunk
);
156 g_memory_input_stream_finalize (GObject
*object
)
158 GMemoryInputStream
*stream
;
159 GMemoryInputStreamPrivate
*priv
;
161 stream
= G_MEMORY_INPUT_STREAM (object
);
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
);
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
;
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
196 g_memory_input_stream_new (void)
198 GInputStream
*stream
;
200 stream
= g_object_new (G_TYPE_MEMORY_INPUT_STREAM
, NULL
);
206 * g_memory_input_stream_new_from_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.
216 g_memory_input_stream_new_from_data (const void *data
,
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
),
231 * g_memory_input_stream_add_data:
232 * @stream: a #GMemoryInputStream
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
240 g_memory_input_stream_add_data (GMemoryInputStream
*stream
,
243 GDestroyNotify destroy
)
245 GMemoryInputStreamPrivate
*priv
;
248 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream
));
249 g_return_if_fail (data
!= NULL
);
256 chunk
= g_slice_new (Chunk
);
257 chunk
->data
= (guint8
*)data
;
259 chunk
->destroy
= destroy
;
261 priv
->chunks
= g_slist_append (priv
->chunks
, chunk
);
262 priv
->len
+= chunk
->len
;
266 g_memory_input_stream_read (GInputStream
*stream
,
269 GCancellable
*cancellable
,
272 GMemoryInputStream
*memory_stream
;
273 GMemoryInputStreamPrivate
*priv
;
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
);
284 for (l
= priv
->chunks
; l
; l
= l
->next
)
286 chunk
= (Chunk
*)l
->data
;
288 if (offset
+ chunk
->len
> priv
->pos
)
291 offset
+= chunk
->len
;
294 start
= priv
->pos
- offset
;
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
);
314 g_memory_input_stream_skip (GInputStream
*stream
,
316 GCancellable
*cancellable
,
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
);
332 g_memory_input_stream_close (GInputStream
*stream
,
333 GCancellable
*cancellable
,
340 g_memory_input_stream_read_async (GInputStream
*stream
,
344 GCancellable
*cancellable
,
345 GAsyncReadyCallback callback
,
348 GSimpleAsyncResult
*simple
;
351 nread
= g_memory_input_stream_read (stream
, buffer
, count
, cancellable
, NULL
);
352 simple
= g_simple_async_result_new (G_OBJECT (stream
),
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
);
362 g_memory_input_stream_read_finish (GInputStream
*stream
,
363 GAsyncResult
*result
,
366 GSimpleAsyncResult
*simple
;
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
);
377 g_memory_input_stream_skip_async (GInputStream
*stream
,
380 GCancellable
*cancellable
,
381 GAsyncReadyCallback callback
,
384 GSimpleAsyncResult
*simple
;
387 nskipped
= g_memory_input_stream_skip (stream
, count
, cancellable
, NULL
);
388 simple
= g_simple_async_result_new (G_OBJECT (stream
),
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
);
398 g_memory_input_stream_skip_finish (GInputStream
*stream
,
399 GAsyncResult
*result
,
402 GSimpleAsyncResult
*simple
;
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
);
413 g_memory_input_stream_close_async (GInputStream
*stream
,
415 GCancellable
*cancellable
,
416 GAsyncReadyCallback callback
,
419 GSimpleAsyncResult
*simple
;
421 simple
= g_simple_async_result_new (G_OBJECT (stream
),
424 g_memory_input_stream_close_async
);
425 g_simple_async_result_complete_in_idle (simple
);
426 g_object_unref (simple
);
430 g_memory_input_stream_close_finish (GInputStream
*stream
,
431 GAsyncResult
*result
,
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
;
450 gboolean
g_memory_input_stream_can_seek (GSeekable
*seekable
)
456 g_memory_input_stream_seek (GSeekable
*seekable
,
459 GCancellable
*cancellable
,
462 GMemoryInputStream
*memory_stream
;
463 GMemoryInputStreamPrivate
*priv
;
466 memory_stream
= G_MEMORY_INPUT_STREAM (seekable
);
467 priv
= memory_stream
->priv
;
472 absolute
= priv
->pos
+ offset
;
480 absolute
= priv
->len
+ offset
;
484 g_set_error_literal (error
,
486 G_IO_ERROR_INVALID_ARGUMENT
,
487 _("Invalid GSeekType supplied"));
492 if (absolute
< 0 || absolute
> priv
->len
)
494 g_set_error_literal (error
,
496 G_IO_ERROR_INVALID_ARGUMENT
,
497 _("Invalid seek request"));
501 priv
->pos
= absolute
;
507 g_memory_input_stream_can_truncate (GSeekable
*seekable
)
513 g_memory_input_stream_truncate (GSeekable
*seekable
,
515 GCancellable
*cancellable
,
518 g_set_error_literal (error
,
520 G_IO_ERROR_NOT_SUPPORTED
,
521 _("Cannot truncate GMemoryInputStream"));
525 #define __G_MEMORY_INPUT_STREAM_C__
526 #include "gioaliasdef.c"