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.1 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: (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.
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: (nullable): 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
);
382 g_task_set_source_tag (task
, g_memory_input_stream_skip_async
);
385 g_task_return_error (task
, error
);
387 g_task_return_int (task
, nskipped
);
388 g_object_unref (task
);
392 g_memory_input_stream_skip_finish (GInputStream
*stream
,
393 GAsyncResult
*result
,
396 g_return_val_if_fail (g_task_is_valid (result
, stream
), -1);
398 return g_task_propagate_int (G_TASK (result
), error
);
402 g_memory_input_stream_close_async (GInputStream
*stream
,
404 GCancellable
*cancellable
,
405 GAsyncReadyCallback callback
,
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
);
417 g_memory_input_stream_close_finish (GInputStream
*stream
,
418 GAsyncResult
*result
,
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
;
437 gboolean
g_memory_input_stream_can_seek (GSeekable
*seekable
)
443 g_memory_input_stream_seek (GSeekable
*seekable
,
446 GCancellable
*cancellable
,
449 GMemoryInputStream
*memory_stream
;
450 GMemoryInputStreamPrivate
*priv
;
453 memory_stream
= G_MEMORY_INPUT_STREAM (seekable
);
454 priv
= memory_stream
->priv
;
459 absolute
= priv
->pos
+ offset
;
467 absolute
= priv
->len
+ offset
;
471 g_set_error_literal (error
,
473 G_IO_ERROR_INVALID_ARGUMENT
,
474 _("Invalid GSeekType supplied"));
479 if (absolute
< 0 || absolute
> priv
->len
)
481 g_set_error_literal (error
,
483 G_IO_ERROR_INVALID_ARGUMENT
,
484 _("Invalid seek request"));
488 priv
->pos
= absolute
;
494 g_memory_input_stream_can_truncate (GSeekable
*seekable
)
500 g_memory_input_stream_truncate (GSeekable
*seekable
,
502 GCancellable
*cancellable
,
505 g_set_error_literal (error
,
507 G_IO_ERROR_NOT_SUPPORTED
,
508 _("Cannot truncate GMemoryInputStream"));
513 g_memory_input_stream_is_readable (GPollableInputStream
*stream
)
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
,
527 g_source_unref (base_source
);
529 return pollable_source
;