1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
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.
9 *
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.
14 *
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/>.
17 *
18 * Author: Christian Kellner <gicmo@gnome.org>
19 */
20
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"
30
31
32 /**
33 * SECTION:gmemoryinputstream
34 * @short_description: Streaming input operations on memory chunks
35 * @include: gio/gio.h
36 * @see_also: #GMemoryOutputStream
37 *
38 * #GMemoryInputStream is a class for using arbitrary
39 * memory chunks as input for GIO streaming input operations.
40 *
41 * As of GLib 2.34, #GMemoryInputStream implements
42 * #GPollableInputStream.
43 */
44
45 struct _GMemoryInputStreamPrivate {
46 GSList *chunks;
47 gsize len;
48 gsize pos;
49 };
50
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);
80
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);
94
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);
99
100 static void g_memory_input_stream_finalize (GObject *object);
101
G_DEFINE_TYPE_WITH_CODE(GMemoryInputStream,g_memory_input_stream,G_TYPE_INPUT_STREAM,G_ADD_PRIVATE (GMemoryInputStream)G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,g_memory_input_stream_seekable_iface_init);G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,g_memory_input_stream_pollable_iface_init);)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);
108 )
109
110
111 static void
112 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
113 {
114 GObjectClass *object_class;
115 GInputStreamClass *istream_class;
116
117 object_class = G_OBJECT_CLASS (klass);
118 object_class->finalize = g_memory_input_stream_finalize;
119
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;
124
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;
129 }
130
131 static void
g_memory_input_stream_finalize(GObject * object)132 g_memory_input_stream_finalize (GObject *object)
133 {
134 GMemoryInputStream *stream;
135 GMemoryInputStreamPrivate *priv;
136
137 stream = G_MEMORY_INPUT_STREAM (object);
138 priv = stream->priv;
139
140 g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
141
142 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
143 }
144
145 static void
g_memory_input_stream_seekable_iface_init(GSeekableIface * iface)146 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
147 {
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;
153 }
154
155 static void
g_memory_input_stream_pollable_iface_init(GPollableInputStreamInterface * iface)156 g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
157 {
158 iface->is_readable = g_memory_input_stream_is_readable;
159 iface->create_source = g_memory_input_stream_create_source;
160 }
161
162 static void
g_memory_input_stream_init(GMemoryInputStream * stream)163 g_memory_input_stream_init (GMemoryInputStream *stream)
164 {
165 stream->priv = g_memory_input_stream_get_instance_private (stream);
166 }
167
168 /**
169 * g_memory_input_stream_new:
170 *
171 * Creates a new empty #GMemoryInputStream.
172 *
173 * Returns: a new #GInputStream
174 */
175 GInputStream *
g_memory_input_stream_new(void)176 g_memory_input_stream_new (void)
177 {
178 GInputStream *stream;
179
180 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
181
182 return stream;
183 }
184
185 /**
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
190 *
191 * Creates a new #GMemoryInputStream with data in memory of a given size.
192 *
193 * Returns: new #GInputStream read from @data of @len bytes.
194 **/
195 GInputStream *
g_memory_input_stream_new_from_data(const void * data,gssize len,GDestroyNotify destroy)196 g_memory_input_stream_new_from_data (const void *data,
197 gssize len,
198 GDestroyNotify destroy)
199 {
200 GInputStream *stream;
201
202 stream = g_memory_input_stream_new ();
203
204 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
205 data, len, destroy);
206
207 return stream;
208 }
209
210 /**
211 * g_memory_input_stream_new_from_bytes:
212 * @bytes: a #GBytes
213 *
214 * Creates a new #GMemoryInputStream with data from the given @bytes.
215 *
216 * Returns: new #GInputStream read from @bytes
217 *
218 * Since: 2.34
219 **/
220 GInputStream *
g_memory_input_stream_new_from_bytes(GBytes * bytes)221 g_memory_input_stream_new_from_bytes (GBytes *bytes)
222 {
223
224 GInputStream *stream;
225
226 stream = g_memory_input_stream_new ();
227
228 g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
229 bytes);
230
231 return stream;
232 }
233
234 /**
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
240 *
241 * Appends @data to data that can be read from the input stream
242 */
243 void
g_memory_input_stream_add_data(GMemoryInputStream * stream,const void * data,gssize len,GDestroyNotify destroy)244 g_memory_input_stream_add_data (GMemoryInputStream *stream,
245 const void *data,
246 gssize len,
247 GDestroyNotify destroy)
248 {
249 GBytes *bytes;
250
251 if (len == -1)
252 len = strlen (data);
253
254 /* It's safe to discard the const here because we're chaining the
255 * destroy callback.
256 */
257 bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data);
258
259 g_memory_input_stream_add_bytes (stream, bytes);
260
261 g_bytes_unref (bytes);
262 }
263
264 /**
265 * g_memory_input_stream_add_bytes:
266 * @stream: a #GMemoryInputStream
267 * @bytes: input data
268 *
269 * Appends @bytes to data that can be read from the input stream.
270 *
271 * Since: 2.34
272 */
273 void
g_memory_input_stream_add_bytes(GMemoryInputStream * stream,GBytes * bytes)274 g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
275 GBytes *bytes)
276 {
277 GMemoryInputStreamPrivate *priv;
278
279 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
280 g_return_if_fail (bytes != NULL);
281
282 priv = stream->priv;
283
284 priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
285 priv->len += g_bytes_get_size (bytes);
286 }
287
288 static gssize
g_memory_input_stream_read(GInputStream * stream,void * buffer,gsize count,GCancellable * cancellable,GError ** error)289 g_memory_input_stream_read (GInputStream *stream,
290 void *buffer,
291 gsize count,
292 GCancellable *cancellable,
293 GError **error)
294 {
295 GMemoryInputStream *memory_stream;
296 GMemoryInputStreamPrivate *priv;
297 GSList *l;
298 GBytes *chunk;
299 gsize len;
300 gsize offset, start, rest, size;
301
302 memory_stream = G_MEMORY_INPUT_STREAM (stream);
303 priv = memory_stream->priv;
304
305 count = MIN (count, priv->len - priv->pos);
306
307 offset = 0;
308 for (l = priv->chunks; l; l = l->next)
309 {
310 chunk = (GBytes *)l->data;
311 len = g_bytes_get_size (chunk);
312
313 if (offset + len > priv->pos)
314 break;
315
316 offset += len;
317 }
318
319 start = priv->pos - offset;
320 rest = count;
321
322 for (; l && rest > 0; l = l->next)
323 {
324 const guint8* chunk_data;
325 chunk = (GBytes *)l->data;
326
327 chunk_data = g_bytes_get_data (chunk, &len);
328
329 size = MIN (rest, len - start);
330
331 memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
332 rest -= size;
333
334 start = 0;
335 }
336
337 priv->pos += count;
338
339 return count;
340 }
341
342 static gssize
g_memory_input_stream_skip(GInputStream * stream,gsize count,GCancellable * cancellable,GError ** error)343 g_memory_input_stream_skip (GInputStream *stream,
344 gsize count,
345 GCancellable *cancellable,
346 GError **error)
347 {
348 GMemoryInputStream *memory_stream;
349 GMemoryInputStreamPrivate *priv;
350
351 memory_stream = G_MEMORY_INPUT_STREAM (stream);
352 priv = memory_stream->priv;
353
354 count = MIN (count, priv->len - priv->pos);
355 priv->pos += count;
356
357 return count;
358 }
359
360 static gboolean
g_memory_input_stream_close(GInputStream * stream,GCancellable * cancellable,GError ** error)361 g_memory_input_stream_close (GInputStream *stream,
362 GCancellable *cancellable,
363 GError **error)
364 {
365 return TRUE;
366 }
367
368 static void
g_memory_input_stream_skip_async(GInputStream * stream,gsize count,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)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)
375 {
376 GTask *task;
377 gssize nskipped;
378 GError *error = NULL;
379
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);
383
384 if (error)
385 g_task_return_error (task, error);
386 else
387 g_task_return_int (task, nskipped);
388 g_object_unref (task);
389 }
390
391 static gssize
g_memory_input_stream_skip_finish(GInputStream * stream,GAsyncResult * result,GError ** error)392 g_memory_input_stream_skip_finish (GInputStream *stream,
393 GAsyncResult *result,
394 GError **error)
395 {
396 g_return_val_if_fail (g_task_is_valid (result, stream), -1);
397
398 return g_task_propagate_int (G_TASK (result), error);
399 }
400
401 static void
g_memory_input_stream_close_async(GInputStream * stream,int io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)402 g_memory_input_stream_close_async (GInputStream *stream,
403 int io_priority,
404 GCancellable *cancellable,
405 GAsyncReadyCallback callback,
406 gpointer user_data)
407 {
408 GTask *task;
409
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);
414 }
415
416 static gboolean
g_memory_input_stream_close_finish(GInputStream * stream,GAsyncResult * result,GError ** error)417 g_memory_input_stream_close_finish (GInputStream *stream,
418 GAsyncResult *result,
419 GError **error)
420 {
421 return TRUE;
422 }
423
424 static goffset
g_memory_input_stream_tell(GSeekable * seekable)425 g_memory_input_stream_tell (GSeekable *seekable)
426 {
427 GMemoryInputStream *memory_stream;
428 GMemoryInputStreamPrivate *priv;
429
430 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
431 priv = memory_stream->priv;
432
433 return priv->pos;
434 }
435
436 static
g_memory_input_stream_can_seek(GSeekable * seekable)437 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
438 {
439 return TRUE;
440 }
441
442 static gboolean
g_memory_input_stream_seek(GSeekable * seekable,goffset offset,GSeekType type,GCancellable * cancellable,GError ** error)443 g_memory_input_stream_seek (GSeekable *seekable,
444 goffset offset,
445 GSeekType type,
446 GCancellable *cancellable,
447 GError **error)
448 {
449 GMemoryInputStream *memory_stream;
450 GMemoryInputStreamPrivate *priv;
451 goffset absolute;
452
453 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
454 priv = memory_stream->priv;
455
456 switch (type)
457 {
458 case G_SEEK_CUR:
459 absolute = priv->pos + offset;
460 break;
461
462 case G_SEEK_SET:
463 absolute = offset;
464 break;
465
466 case G_SEEK_END:
467 absolute = priv->len + offset;
468 break;
469
470 default:
471 g_set_error_literal (error,
472 G_IO_ERROR,
473 G_IO_ERROR_INVALID_ARGUMENT,
474 _("Invalid GSeekType supplied"));
475
476 return FALSE;
477 }
478
479 if (absolute < 0 || (gsize) absolute > priv->len)
480 {
481 g_set_error_literal (error,
482 G_IO_ERROR,
483 G_IO_ERROR_INVALID_ARGUMENT,
484 _("Invalid seek request"));
485 return FALSE;
486 }
487
488 priv->pos = absolute;
489
490 return TRUE;
491 }
492
493 static gboolean
g_memory_input_stream_can_truncate(GSeekable * seekable)494 g_memory_input_stream_can_truncate (GSeekable *seekable)
495 {
496 return FALSE;
497 }
498
499 static gboolean
g_memory_input_stream_truncate(GSeekable * seekable,goffset offset,GCancellable * cancellable,GError ** error)500 g_memory_input_stream_truncate (GSeekable *seekable,
501 goffset offset,
502 GCancellable *cancellable,
503 GError **error)
504 {
505 g_set_error_literal (error,
506 G_IO_ERROR,
507 G_IO_ERROR_NOT_SUPPORTED,
508 _("Cannot truncate GMemoryInputStream"));
509 return FALSE;
510 }
511
512 static gboolean
g_memory_input_stream_is_readable(GPollableInputStream * stream)513 g_memory_input_stream_is_readable (GPollableInputStream *stream)
514 {
515 return TRUE;
516 }
517
518 static GSource *
g_memory_input_stream_create_source(GPollableInputStream * stream,GCancellable * cancellable)519 g_memory_input_stream_create_source (GPollableInputStream *stream,
520 GCancellable *cancellable)
521 {
522 GSource *base_source, *pollable_source;
523
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);
528
529 return pollable_source;
530 }
531