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
;
52 struct _GMemoryInputStreamPrivate
{
58 static gssize
g_memory_input_stream_read (GInputStream
*stream
,
61 GCancellable
*cancellable
,
63 static gssize
g_memory_input_stream_skip (GInputStream
*stream
,
65 GCancellable
*cancellable
,
67 static gboolean
g_memory_input_stream_close (GInputStream
*stream
,
68 GCancellable
*cancellable
,
70 static void g_memory_input_stream_read_async (GInputStream
*stream
,
74 GCancellable
*cancellable
,
75 GAsyncReadyCallback callback
,
77 static gssize
g_memory_input_stream_read_finish (GInputStream
*stream
,
80 static void g_memory_input_stream_skip_async (GInputStream
*stream
,
83 GCancellable
*cancellabl
,
84 GAsyncReadyCallback callback
,
86 static gssize
g_memory_input_stream_skip_finish (GInputStream
*stream
,
89 static void g_memory_input_stream_close_async (GInputStream
*stream
,
91 GCancellable
*cancellabl
,
92 GAsyncReadyCallback callback
,
94 static gboolean
g_memory_input_stream_close_finish (GInputStream
*stream
,
98 static void g_memory_input_stream_seekable_iface_init (GSeekableIface
*iface
);
99 static goffset
g_memory_input_stream_tell (GSeekable
*seekable
);
100 static gboolean
g_memory_input_stream_can_seek (GSeekable
*seekable
);
101 static gboolean
g_memory_input_stream_seek (GSeekable
*seekable
,
104 GCancellable
*cancellable
,
106 static gboolean
g_memory_input_stream_can_truncate (GSeekable
*seekable
);
107 static gboolean
g_memory_input_stream_truncate (GSeekable
*seekable
,
109 GCancellable
*cancellable
,
111 static void g_memory_input_stream_finalize (GObject
*object
);
113 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream
, g_memory_input_stream
, G_TYPE_INPUT_STREAM
,
114 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE
,
115 g_memory_input_stream_seekable_iface_init
))
119 g_memory_input_stream_class_init (GMemoryInputStreamClass
*klass
)
121 GObjectClass
*object_class
;
122 GInputStreamClass
*istream_class
;
124 g_type_class_add_private (klass
, sizeof (GMemoryInputStreamPrivate
));
126 object_class
= G_OBJECT_CLASS (klass
);
127 object_class
->finalize
= g_memory_input_stream_finalize
;
129 istream_class
= G_INPUT_STREAM_CLASS (klass
);
130 istream_class
->read_fn
= g_memory_input_stream_read
;
131 istream_class
->skip
= g_memory_input_stream_skip
;
132 istream_class
->close_fn
= g_memory_input_stream_close
;
134 istream_class
->read_async
= g_memory_input_stream_read_async
;
135 istream_class
->read_finish
= g_memory_input_stream_read_finish
;
136 istream_class
->skip_async
= g_memory_input_stream_skip_async
;
137 istream_class
->skip_finish
= g_memory_input_stream_skip_finish
;
138 istream_class
->close_async
= g_memory_input_stream_close_async
;
139 istream_class
->close_finish
= g_memory_input_stream_close_finish
;
143 free_chunk (gpointer data
,
149 chunk
->destroy (chunk
->data
);
151 g_slice_free (Chunk
, chunk
);
155 g_memory_input_stream_finalize (GObject
*object
)
157 GMemoryInputStream
*stream
;
158 GMemoryInputStreamPrivate
*priv
;
160 stream
= G_MEMORY_INPUT_STREAM (object
);
163 g_slist_foreach (priv
->chunks
, free_chunk
, NULL
);
164 g_slist_free (priv
->chunks
);
166 G_OBJECT_CLASS (g_memory_input_stream_parent_class
)->finalize (object
);
170 g_memory_input_stream_seekable_iface_init (GSeekableIface
*iface
)
172 iface
->tell
= g_memory_input_stream_tell
;
173 iface
->can_seek
= g_memory_input_stream_can_seek
;
174 iface
->seek
= g_memory_input_stream_seek
;
175 iface
->can_truncate
= g_memory_input_stream_can_truncate
;
176 iface
->truncate_fn
= g_memory_input_stream_truncate
;
180 g_memory_input_stream_init (GMemoryInputStream
*stream
)
182 stream
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (stream
,
183 G_TYPE_MEMORY_INPUT_STREAM
,
184 GMemoryInputStreamPrivate
);
188 * g_memory_input_stream_new:
190 * Creates a new empty #GMemoryInputStream.
192 * Returns: a new #GInputStream
195 g_memory_input_stream_new (void)
197 GInputStream
*stream
;
199 stream
= g_object_new (G_TYPE_MEMORY_INPUT_STREAM
, NULL
);
205 * g_memory_input_stream_new_from_data:
206 * @data: (array length=len) (element-type guint8): input data
207 * @len: length of the data, may be -1 if @data is a nul-terminated string
208 * @destroy: (allow-none): function that is called to free @data, or %NULL
210 * Creates a new #GMemoryInputStream with data in memory of a given size.
212 * Returns: new #GInputStream read from @data of @len bytes.
215 g_memory_input_stream_new_from_data (const void *data
,
217 GDestroyNotify destroy
)
219 GInputStream
*stream
;
221 stream
= g_memory_input_stream_new ();
223 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream
),
230 * g_memory_input_stream_add_data:
231 * @stream: a #GMemoryInputStream
232 * @data: (array length=len) (element-type guint8): input data
233 * @len: length of the data, may be -1 if @data is a nul-terminated string
234 * @destroy: (allow-none): function that is called to free @data, or %NULL
236 * Appends @data to data that can be read from the input stream
239 g_memory_input_stream_add_data (GMemoryInputStream
*stream
,
242 GDestroyNotify destroy
)
244 GMemoryInputStreamPrivate
*priv
;
247 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream
));
248 g_return_if_fail (data
!= NULL
);
255 chunk
= g_slice_new (Chunk
);
256 chunk
->data
= (guint8
*)data
;
258 chunk
->destroy
= destroy
;
260 priv
->chunks
= g_slist_append (priv
->chunks
, chunk
);
261 priv
->len
+= chunk
->len
;
265 g_memory_input_stream_read (GInputStream
*stream
,
268 GCancellable
*cancellable
,
271 GMemoryInputStream
*memory_stream
;
272 GMemoryInputStreamPrivate
*priv
;
275 gsize offset
, start
, rest
, size
;
277 memory_stream
= G_MEMORY_INPUT_STREAM (stream
);
278 priv
= memory_stream
->priv
;
280 count
= MIN (count
, priv
->len
- priv
->pos
);
283 for (l
= priv
->chunks
; l
; l
= l
->next
)
285 chunk
= (Chunk
*)l
->data
;
287 if (offset
+ chunk
->len
> priv
->pos
)
290 offset
+= chunk
->len
;
293 start
= priv
->pos
- offset
;
296 for (; l
&& rest
> 0; l
= l
->next
)
298 chunk
= (Chunk
*)l
->data
;
299 size
= MIN (rest
, chunk
->len
- start
);
301 memcpy ((guint8
*)buffer
+ (count
- rest
), chunk
->data
+ start
, size
);
313 g_memory_input_stream_skip (GInputStream
*stream
,
315 GCancellable
*cancellable
,
318 GMemoryInputStream
*memory_stream
;
319 GMemoryInputStreamPrivate
*priv
;
321 memory_stream
= G_MEMORY_INPUT_STREAM (stream
);
322 priv
= memory_stream
->priv
;
324 count
= MIN (count
, priv
->len
- priv
->pos
);
331 g_memory_input_stream_close (GInputStream
*stream
,
332 GCancellable
*cancellable
,
339 g_memory_input_stream_read_async (GInputStream
*stream
,
343 GCancellable
*cancellable
,
344 GAsyncReadyCallback callback
,
347 GSimpleAsyncResult
*simple
;
350 nread
= g_input_stream_read (stream
, buffer
, count
, cancellable
, NULL
);
351 simple
= g_simple_async_result_new (G_OBJECT (stream
),
354 g_memory_input_stream_read_async
);
355 g_simple_async_result_set_op_res_gssize (simple
, nread
);
356 g_simple_async_result_complete_in_idle (simple
);
357 g_object_unref (simple
);
361 g_memory_input_stream_read_finish (GInputStream
*stream
,
362 GAsyncResult
*result
,
365 GSimpleAsyncResult
*simple
;
368 simple
= G_SIMPLE_ASYNC_RESULT (result
);
369 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) == g_memory_input_stream_read_async
);
371 nread
= g_simple_async_result_get_op_res_gssize (simple
);
376 g_memory_input_stream_skip_async (GInputStream
*stream
,
379 GCancellable
*cancellable
,
380 GAsyncReadyCallback callback
,
383 GSimpleAsyncResult
*simple
;
386 nskipped
= g_input_stream_skip (stream
, count
, cancellable
, NULL
);
387 simple
= g_simple_async_result_new (G_OBJECT (stream
),
390 g_memory_input_stream_skip_async
);
391 g_simple_async_result_set_op_res_gssize (simple
, nskipped
);
392 g_simple_async_result_complete_in_idle (simple
);
393 g_object_unref (simple
);
397 g_memory_input_stream_skip_finish (GInputStream
*stream
,
398 GAsyncResult
*result
,
401 GSimpleAsyncResult
*simple
;
404 simple
= G_SIMPLE_ASYNC_RESULT (result
);
405 g_warn_if_fail (g_simple_async_result_get_source_tag (simple
) == g_memory_input_stream_skip_async
);
407 nskipped
= g_simple_async_result_get_op_res_gssize (simple
);
412 g_memory_input_stream_close_async (GInputStream
*stream
,
414 GCancellable
*cancellable
,
415 GAsyncReadyCallback callback
,
418 GSimpleAsyncResult
*simple
;
420 simple
= g_simple_async_result_new (G_OBJECT (stream
),
423 g_memory_input_stream_close_async
);
424 g_simple_async_result_complete_in_idle (simple
);
425 g_object_unref (simple
);
429 g_memory_input_stream_close_finish (GInputStream
*stream
,
430 GAsyncResult
*result
,
437 g_memory_input_stream_tell (GSeekable
*seekable
)
439 GMemoryInputStream
*memory_stream
;
440 GMemoryInputStreamPrivate
*priv
;
442 memory_stream
= G_MEMORY_INPUT_STREAM (seekable
);
443 priv
= memory_stream
->priv
;
449 gboolean
g_memory_input_stream_can_seek (GSeekable
*seekable
)
455 g_memory_input_stream_seek (GSeekable
*seekable
,
458 GCancellable
*cancellable
,
461 GMemoryInputStream
*memory_stream
;
462 GMemoryInputStreamPrivate
*priv
;
465 memory_stream
= G_MEMORY_INPUT_STREAM (seekable
);
466 priv
= memory_stream
->priv
;
471 absolute
= priv
->pos
+ offset
;
479 absolute
= priv
->len
+ offset
;
483 g_set_error_literal (error
,
485 G_IO_ERROR_INVALID_ARGUMENT
,
486 _("Invalid GSeekType supplied"));
491 if (absolute
< 0 || absolute
> priv
->len
)
493 g_set_error_literal (error
,
495 G_IO_ERROR_INVALID_ARGUMENT
,
496 _("Invalid seek request"));
500 priv
->pos
= absolute
;
506 g_memory_input_stream_can_truncate (GSeekable
*seekable
)
512 g_memory_input_stream_truncate (GSeekable
*seekable
,
514 GCancellable
*cancellable
,
517 g_set_error_literal (error
,
519 G_IO_ERROR_NOT_SUPPORTED
,
520 _("Cannot truncate GMemoryInputStream"));