1 /* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright (C) 2006-2007 Red Hat, Inc.
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Author: Christian Kellner <gicmo@gnome.org>
21 */
22
23 #include "config.h"
24 #include "gmemoryinputstream.h"
25 #include "gpollableinputstream.h"
26 #include "ginputstream.h"
27 #include "gseekable.h"
28 #include "string.h"
29 #include "gtask.h"
30 #include "gioerror.h"
31 #include "glibintl.h"
32
33
34 /**
35 * GMemoryInputStream:
36 *
37 * `GMemoryInputStream` is a class for using arbitrary
38 * memory chunks as input for GIO streaming input operations.
39 *
40 * As of GLib 2.34, `GMemoryInputStream` implements
41 * [iface@Gio.PollableInputStream].
42 */
43
44 struct _GMemoryInputStreamPrivate {
45 GSList *chunks;
46 gsize len;
47 gsize pos;
48 };
49
50 static gssize g_memory_input_stream_read (GInputStream *stream,
51 void *buffer,
52 gsize count,
53 GCancellable *cancellable,
54 GError **error);
55 static gssize g_memory_input_stream_skip (GInputStream *stream,
56 gsize count,
57 GCancellable *cancellable,
58 GError **error);
59 static gboolean g_memory_input_stream_close (GInputStream *stream,
60 GCancellable *cancellable,
61 GError **error);
62 static void g_memory_input_stream_skip_async (GInputStream *stream,
63 gsize count,
64 int io_priority,
65 GCancellable *cancellabl,
66 GAsyncReadyCallback callback,
67 gpointer datae);
68 static gssize g_memory_input_stream_skip_finish (GInputStream *stream,
69 GAsyncResult *result,
70 GError **error);
71 static void g_memory_input_stream_close_async (GInputStream *stream,
72 int io_priority,
73 GCancellable *cancellabl,
74 GAsyncReadyCallback callback,
75 gpointer data);
76 static gboolean g_memory_input_stream_close_finish (GInputStream *stream,
77 GAsyncResult *result,
78 GError **error);
79
80 static void g_memory_input_stream_seekable_iface_init (GSeekableIface *iface);
81 static goffset g_memory_input_stream_tell (GSeekable *seekable);
82 static gboolean g_memory_input_stream_can_seek (GSeekable *seekable);
83 static gboolean g_memory_input_stream_seek (GSeekable *seekable,
84 goffset offset,
85 GSeekType type,
86 GCancellable *cancellable,
87 GError **error);
88 static gboolean g_memory_input_stream_can_truncate (GSeekable *seekable);
89 static gboolean g_memory_input_stream_truncate (GSeekable *seekable,
90 goffset offset,
91 GCancellable *cancellable,
92 GError **error);
93
94 static void g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
95 static gboolean g_memory_input_stream_is_readable (GPollableInputStream *stream);
96 static GSource *g_memory_input_stream_create_source (GPollableInputStream *stream,
97 GCancellable *cancellable);
98
99 static void g_memory_input_stream_finalize (GObject *object);
100
101 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
102 G_ADD_PRIVATE (GMemoryInputStream)
103 G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
104 g_memory_input_stream_seekable_iface_init);
105 G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
106 g_memory_input_stream_pollable_iface_init);
107 )
108
109
110 static void
111 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
112 {
113 GObjectClass *object_class;
114 GInputStreamClass *istream_class;
115
116 object_class = G_OBJECT_CLASS (klass);
117 object_class->finalize = g_memory_input_stream_finalize;
118
119 istream_class = G_INPUT_STREAM_CLASS (klass);
120 istream_class->read_fn = g_memory_input_stream_read;
121 istream_class->skip = g_memory_input_stream_skip;
122 istream_class->close_fn = g_memory_input_stream_close;
123
124 istream_class->skip_async = g_memory_input_stream_skip_async;
125 istream_class->skip_finish = g_memory_input_stream_skip_finish;
126 istream_class->close_async = g_memory_input_stream_close_async;
127 istream_class->close_finish = g_memory_input_stream_close_finish;
128 }
129
130 static void
131 g_memory_input_stream_finalize (GObject *object)
132 {
133 GMemoryInputStream *stream;
134 GMemoryInputStreamPrivate *priv;
135
136 stream = G_MEMORY_INPUT_STREAM (object);
137 priv = stream->priv;
138
139 g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
140
141 G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
142 }
143
144 static void
145 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
146 {
147 iface->tell = g_memory_input_stream_tell;
148 iface->can_seek = g_memory_input_stream_can_seek;
149 iface->seek = g_memory_input_stream_seek;
150 iface->can_truncate = g_memory_input_stream_can_truncate;
151 iface->truncate_fn = g_memory_input_stream_truncate;
152 }
153
154 static void
155 g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
156 {
157 iface->is_readable = g_memory_input_stream_is_readable;
158 iface->create_source = g_memory_input_stream_create_source;
159 }
160
161 static void
162 g_memory_input_stream_init (GMemoryInputStream *stream)
163 {
164 stream->priv = g_memory_input_stream_get_instance_private (stream);
165 }
166
167 /**
168 * g_memory_input_stream_new:
169 *
170 * Creates a new empty #GMemoryInputStream.
171 *
172 * Returns: a new #GInputStream
173 */
174 GInputStream *
175 g_memory_input_stream_new (void)
176 {
177 GInputStream *stream;
178
179 stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
180
181 return stream;
182 }
183
184 /**
185 * g_memory_input_stream_new_from_data:
186 * @data: (array length=len) (element-type guint8) (transfer full): input data
187 * @len: length of the data, may be -1 if @data is a nul-terminated string
188 * @destroy: (nullable): function that is called to free @data, or %NULL
189 *
190 * Creates a new #GMemoryInputStream with data in memory of a given size.
191 *
192 * Returns: new #GInputStream read from @data of @len bytes.
193 **/
194 GInputStream *
195 g_memory_input_stream_new_from_data (const void *data,
196 gssize len,
197 GDestroyNotify destroy)
198 {
199 GInputStream *stream;
200
201 stream = g_memory_input_stream_new ();
202
203 g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
204 data, len, destroy);
205
206 return stream;
207 }
208
209 /**
210 * g_memory_input_stream_new_from_bytes:
211 * @bytes: a #GBytes
212 *
213 * Creates a new #GMemoryInputStream with data from the given @bytes.
214 *
215 * Returns: new #GInputStream read from @bytes
216 *
217 * Since: 2.34
218 **/
219 GInputStream *
220 g_memory_input_stream_new_from_bytes (GBytes *bytes)
221 {
222
223 GInputStream *stream;
224
225 stream = g_memory_input_stream_new ();
226
227 g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
228 bytes);
229
230 return stream;
231 }
232
233 /**
234 * g_memory_input_stream_add_data:
235 * @stream: a #GMemoryInputStream
236 * @data: (array length=len) (element-type guint8) (transfer full): input data
237 * @len: length of the data, may be -1 if @data is a nul-terminated string
238 * @destroy: (nullable): function that is called to free @data, or %NULL
239 *
240 * Appends @data to data that can be read from the input stream
241 */
242 void
243 g_memory_input_stream_add_data (GMemoryInputStream *stream,
244 const void *data,
245 gssize len,
246 GDestroyNotify destroy)
247 {
248 GBytes *bytes;
249
250 if (len == -1)
251 len = strlen (data);
252
253 /* It's safe to discard the const here because we're chaining the
254 * destroy callback.
255 */
256 bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data);
257
258 g_memory_input_stream_add_bytes (stream, bytes);
259
260 g_bytes_unref (bytes);
261 }
262
263 /**
264 * g_memory_input_stream_add_bytes:
265 * @stream: a #GMemoryInputStream
266 * @bytes: input data
267 *
268 * Appends @bytes to data that can be read from the input stream.
269 *
270 * Since: 2.34
271 */
272 void
273 g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
274 GBytes *bytes)
275 {
276 GMemoryInputStreamPrivate *priv;
277
278 g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
279 g_return_if_fail (bytes != NULL);
280
281 priv = stream->priv;
282
283 priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
284 priv->len += g_bytes_get_size (bytes);
285 }
286
287 static gssize
288 g_memory_input_stream_read (GInputStream *stream,
289 void *buffer,
290 gsize count,
291 GCancellable *cancellable,
292 GError **error)
293 {
294 GMemoryInputStream *memory_stream;
295 GMemoryInputStreamPrivate *priv;
296 GSList *l;
297 GBytes *chunk;
298 gsize len;
299 gsize offset, start, rest, size;
300
301 memory_stream = G_MEMORY_INPUT_STREAM (stream);
302 priv = memory_stream->priv;
303
304 count = MIN (count, priv->len - priv->pos);
305
306 offset = 0;
307 for (l = priv->chunks; l; l = l->next)
308 {
309 chunk = (GBytes *)l->data;
310 len = g_bytes_get_size (chunk);
311
312 if (offset + len > priv->pos)
313 break;
314
315 offset += len;
316 }
317
318 start = priv->pos - offset;
319 rest = count;
320
321 for (; l && rest > 0; l = l->next)
322 {
323 const guint8* chunk_data;
324 chunk = (GBytes *)l->data;
325
326 chunk_data = g_bytes_get_data (chunk, &len);
327
328 size = MIN (rest, len - start);
329
330 memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
331 rest -= size;
332
333 start = 0;
334 }
335
336 priv->pos += count;
337
338 return count;
339 }
340
341 static gssize
342 g_memory_input_stream_skip (GInputStream *stream,
343 gsize count,
344 GCancellable *cancellable,
345 GError **error)
346 {
347 GMemoryInputStream *memory_stream;
348 GMemoryInputStreamPrivate *priv;
349
350 memory_stream = G_MEMORY_INPUT_STREAM (stream);
351 priv = memory_stream->priv;
352
353 count = MIN (count, priv->len - priv->pos);
354 priv->pos += count;
355
356 return count;
357 }
358
359 static gboolean
360 g_memory_input_stream_close (GInputStream *stream,
361 GCancellable *cancellable,
362 GError **error)
363 {
364 return TRUE;
365 }
366
367 static void
368 g_memory_input_stream_skip_async (GInputStream *stream,
369 gsize count,
370 int io_priority,
371 GCancellable *cancellable,
372 GAsyncReadyCallback callback,
373 gpointer user_data)
374 {
375 GTask *task;
376 gssize nskipped;
377 GError *error = NULL;
378
379 nskipped = G_INPUT_STREAM_GET_CLASS (stream)->skip (stream, count, cancellable, &error);
380 task = g_task_new (stream, cancellable, callback, user_data);
381 g_task_set_source_tag (task, g_memory_input_stream_skip_async);
382
383 if (error)
384 g_task_return_error (task, error);
385 else
386 g_task_return_int (task, nskipped);
387 g_object_unref (task);
388 }
389
390 static gssize
391 g_memory_input_stream_skip_finish (GInputStream *stream,
392 GAsyncResult *result,
393 GError **error)
394 {
395 g_return_val_if_fail (g_task_is_valid (result, stream), -1);
396
397 return g_task_propagate_int (G_TASK (result), error);
398 }
399
400 static void
401 g_memory_input_stream_close_async (GInputStream *stream,
402 int io_priority,
403 GCancellable *cancellable,
404 GAsyncReadyCallback callback,
405 gpointer user_data)
406 {
407 GTask *task;
408
409 task = g_task_new (stream, cancellable, callback, user_data);
410 g_task_set_source_tag (task, g_memory_input_stream_close_async);
411 g_task_return_boolean (task, TRUE);
412 g_object_unref (task);
413 }
414
415 static gboolean
416 g_memory_input_stream_close_finish (GInputStream *stream,
417 GAsyncResult *result,
418 GError **error)
419 {
420 return TRUE;
421 }
422
423 static goffset
424 g_memory_input_stream_tell (GSeekable *seekable)
425 {
426 GMemoryInputStream *memory_stream;
427 GMemoryInputStreamPrivate *priv;
428
429 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
430 priv = memory_stream->priv;
431
432 return priv->pos;
433 }
434
435 static
436 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
437 {
438 return TRUE;
439 }
440
441 static gboolean
442 g_memory_input_stream_seek (GSeekable *seekable,
443 goffset offset,
444 GSeekType type,
445 GCancellable *cancellable,
446 GError **error)
447 {
448 GMemoryInputStream *memory_stream;
449 GMemoryInputStreamPrivate *priv;
450 goffset absolute;
451
452 memory_stream = G_MEMORY_INPUT_STREAM (seekable);
453 priv = memory_stream->priv;
454
455 switch (type)
456 {
457 case G_SEEK_CUR:
458 absolute = priv->pos + offset;
459 break;
460
461 case G_SEEK_SET:
462 absolute = offset;
463 break;
464
465 case G_SEEK_END:
466 absolute = priv->len + offset;
467 break;
468
469 default:
470 g_set_error_literal (error,
471 G_IO_ERROR,
472 G_IO_ERROR_INVALID_ARGUMENT,
473 _("Invalid GSeekType supplied"));
474
475 return FALSE;
476 }
477
478 if (absolute < 0 || (gsize) absolute > priv->len)
479 {
480 g_set_error_literal (error,
481 G_IO_ERROR,
482 G_IO_ERROR_INVALID_ARGUMENT,
483 _("Invalid seek request"));
484 return FALSE;
485 }
486
487 priv->pos = absolute;
488
489 return TRUE;
490 }
491
492 static gboolean
493 g_memory_input_stream_can_truncate (GSeekable *seekable)
494 {
495 return FALSE;
496 }
497
498 static gboolean
499 g_memory_input_stream_truncate (GSeekable *seekable,
500 goffset offset,
501 GCancellable *cancellable,
502 GError **error)
503 {
504 g_set_error_literal (error,
505 G_IO_ERROR,
506 G_IO_ERROR_NOT_SUPPORTED,
507 _("Cannot truncate GMemoryInputStream"));
508 return FALSE;
509 }
510
511 static gboolean
512 g_memory_input_stream_is_readable (GPollableInputStream *stream)
513 {
514 return TRUE;
515 }
516
517 static GSource *
518 g_memory_input_stream_create_source (GPollableInputStream *stream,
519 GCancellable *cancellable)
520 {
521 GSource *base_source, *pollable_source;
522
523 base_source = g_timeout_source_new (0);
524 pollable_source = g_pollable_source_new_full (stream, base_source,
525 cancellable);
526 g_source_unref (base_source);
527
528 return pollable_source;
529 }