Branch data Line data Source code
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 : 583914 : 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 : 140 : g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
112 : : {
113 : : GObjectClass *object_class;
114 : : GInputStreamClass *istream_class;
115 : :
116 : 140 : object_class = G_OBJECT_CLASS (klass);
117 : 140 : object_class->finalize = g_memory_input_stream_finalize;
118 : :
119 : 140 : istream_class = G_INPUT_STREAM_CLASS (klass);
120 : 140 : istream_class->read_fn = g_memory_input_stream_read;
121 : 140 : istream_class->skip = g_memory_input_stream_skip;
122 : 140 : istream_class->close_fn = g_memory_input_stream_close;
123 : :
124 : 140 : istream_class->skip_async = g_memory_input_stream_skip_async;
125 : 140 : istream_class->skip_finish = g_memory_input_stream_skip_finish;
126 : 140 : istream_class->close_async = g_memory_input_stream_close_async;
127 : 140 : istream_class->close_finish = g_memory_input_stream_close_finish;
128 : 140 : }
129 : :
130 : : static void
131 : 124 : g_memory_input_stream_finalize (GObject *object)
132 : : {
133 : : GMemoryInputStream *stream;
134 : : GMemoryInputStreamPrivate *priv;
135 : :
136 : 124 : stream = G_MEMORY_INPUT_STREAM (object);
137 : 124 : priv = stream->priv;
138 : :
139 : 124 : g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
140 : :
141 : 124 : G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
142 : 124 : }
143 : :
144 : : static void
145 : 140 : g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
146 : : {
147 : 140 : iface->tell = g_memory_input_stream_tell;
148 : 140 : iface->can_seek = g_memory_input_stream_can_seek;
149 : 140 : iface->seek = g_memory_input_stream_seek;
150 : 140 : iface->can_truncate = g_memory_input_stream_can_truncate;
151 : 140 : iface->truncate_fn = g_memory_input_stream_truncate;
152 : 140 : }
153 : :
154 : : static void
155 : 140 : g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
156 : : {
157 : 140 : iface->is_readable = g_memory_input_stream_is_readable;
158 : 140 : iface->create_source = g_memory_input_stream_create_source;
159 : 140 : }
160 : :
161 : : static void
162 : 136 : g_memory_input_stream_init (GMemoryInputStream *stream)
163 : : {
164 : 136 : stream->priv = g_memory_input_stream_get_instance_private (stream);
165 : 136 : }
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 : 135 : g_memory_input_stream_new (void)
176 : : {
177 : : GInputStream *stream;
178 : :
179 : 135 : stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
180 : :
181 : 135 : 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 : 59 : g_memory_input_stream_new_from_data (const void *data,
196 : : gssize len,
197 : : GDestroyNotify destroy)
198 : : {
199 : : GInputStream *stream;
200 : :
201 : 59 : stream = g_memory_input_stream_new ();
202 : :
203 : 59 : g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
204 : : data, len, destroy);
205 : :
206 : 59 : 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 : 59 : g_memory_input_stream_new_from_bytes (GBytes *bytes)
221 : : {
222 : :
223 : : GInputStream *stream;
224 : :
225 : 59 : stream = g_memory_input_stream_new ();
226 : :
227 : 59 : g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
228 : : bytes);
229 : :
230 : 59 : 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 : 16492 : g_memory_input_stream_add_data (GMemoryInputStream *stream,
244 : : const void *data,
245 : : gssize len,
246 : : GDestroyNotify destroy)
247 : : {
248 : : GBytes *bytes;
249 : :
250 : 16492 : if (len == -1)
251 : 16424 : len = strlen (data);
252 : :
253 : : /* It's safe to discard the const here because we're chaining the
254 : : * destroy callback.
255 : : */
256 : 16492 : bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data);
257 : :
258 : 16492 : g_memory_input_stream_add_bytes (stream, bytes);
259 : :
260 : 16492 : g_bytes_unref (bytes);
261 : 16492 : }
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 : 16551 : g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
274 : : GBytes *bytes)
275 : : {
276 : : GMemoryInputStreamPrivate *priv;
277 : :
278 : 16551 : g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
279 : 16551 : g_return_if_fail (bytes != NULL);
280 : :
281 : 16551 : priv = stream->priv;
282 : :
283 : 16551 : priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
284 : 16551 : priv->len += g_bytes_get_size (bytes);
285 : : }
286 : :
287 : : static gssize
288 : 549592 : 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 : 549592 : memory_stream = G_MEMORY_INPUT_STREAM (stream);
302 : 549592 : priv = memory_stream->priv;
303 : :
304 : 549592 : count = MIN (count, priv->len - priv->pos);
305 : :
306 : 549592 : offset = 0;
307 : 658439 : for (l = priv->chunks; l; l = l->next)
308 : : {
309 : 658339 : chunk = (GBytes *)l->data;
310 : 658339 : len = g_bytes_get_size (chunk);
311 : :
312 : 658339 : if (offset + len > priv->pos)
313 : 549492 : break;
314 : :
315 : 108847 : offset += len;
316 : : }
317 : :
318 : 549592 : start = priv->pos - offset;
319 : 549592 : rest = count;
320 : :
321 : 1115589 : for (; l && rest > 0; l = l->next)
322 : : {
323 : : const guint8* chunk_data;
324 : 565997 : chunk = (GBytes *)l->data;
325 : :
326 : 565997 : chunk_data = g_bytes_get_data (chunk, &len);
327 : :
328 : 565997 : size = MIN (rest, len - start);
329 : :
330 : 565997 : memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
331 : 565997 : rest -= size;
332 : :
333 : 565997 : start = 0;
334 : : }
335 : :
336 : 549592 : priv->pos += count;
337 : :
338 : 549592 : return count;
339 : : }
340 : :
341 : : static gssize
342 : 218 : 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 : 218 : memory_stream = G_MEMORY_INPUT_STREAM (stream);
351 : 218 : priv = memory_stream->priv;
352 : :
353 : 218 : count = MIN (count, priv->len - priv->pos);
354 : 218 : priv->pos += count;
355 : :
356 : 218 : return count;
357 : : }
358 : :
359 : : static gboolean
360 : 78 : g_memory_input_stream_close (GInputStream *stream,
361 : : GCancellable *cancellable,
362 : : GError **error)
363 : : {
364 : 78 : return TRUE;
365 : : }
366 : :
367 : : static void
368 : 211 : 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 : 211 : GError *error = NULL;
378 : :
379 : 211 : nskipped = G_INPUT_STREAM_GET_CLASS (stream)->skip (stream, count, cancellable, &error);
380 : 211 : task = g_task_new (stream, cancellable, callback, user_data);
381 : 211 : g_task_set_source_tag (task, g_memory_input_stream_skip_async);
382 : :
383 : 211 : if (error)
384 : 0 : g_task_return_error (task, error);
385 : : else
386 : 211 : g_task_return_int (task, nskipped);
387 : 211 : g_object_unref (task);
388 : 211 : }
389 : :
390 : : static gssize
391 : 211 : g_memory_input_stream_skip_finish (GInputStream *stream,
392 : : GAsyncResult *result,
393 : : GError **error)
394 : : {
395 : 211 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
396 : :
397 : 211 : return g_task_propagate_int (G_TASK (result), error);
398 : : }
399 : :
400 : : static void
401 : 58 : 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 : 58 : task = g_task_new (stream, cancellable, callback, user_data);
410 : 58 : g_task_set_source_tag (task, g_memory_input_stream_close_async);
411 : 58 : g_task_return_boolean (task, TRUE);
412 : 58 : g_object_unref (task);
413 : 58 : }
414 : :
415 : : static gboolean
416 : 58 : g_memory_input_stream_close_finish (GInputStream *stream,
417 : : GAsyncResult *result,
418 : : GError **error)
419 : : {
420 : 58 : return TRUE;
421 : : }
422 : :
423 : : static goffset
424 : 20 : g_memory_input_stream_tell (GSeekable *seekable)
425 : : {
426 : : GMemoryInputStream *memory_stream;
427 : : GMemoryInputStreamPrivate *priv;
428 : :
429 : 20 : memory_stream = G_MEMORY_INPUT_STREAM (seekable);
430 : 20 : priv = memory_stream->priv;
431 : :
432 : 20 : return priv->pos;
433 : : }
434 : :
435 : : static
436 : 2 : gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
437 : : {
438 : 2 : return TRUE;
439 : : }
440 : :
441 : : static gboolean
442 : 182 : 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 : 182 : memory_stream = G_MEMORY_INPUT_STREAM (seekable);
453 : 182 : priv = memory_stream->priv;
454 : :
455 : 182 : switch (type)
456 : : {
457 : 3 : case G_SEEK_CUR:
458 : 3 : absolute = priv->pos + offset;
459 : 3 : break;
460 : :
461 : 178 : case G_SEEK_SET:
462 : 178 : absolute = offset;
463 : 178 : break;
464 : :
465 : 1 : case G_SEEK_END:
466 : 1 : absolute = priv->len + offset;
467 : 1 : break;
468 : :
469 : 0 : default:
470 : 0 : g_set_error_literal (error,
471 : : G_IO_ERROR,
472 : : G_IO_ERROR_INVALID_ARGUMENT,
473 : : _("Invalid GSeekType supplied"));
474 : :
475 : 0 : return FALSE;
476 : : }
477 : :
478 : 182 : if (absolute < 0 || (gsize) absolute > priv->len)
479 : : {
480 : 1 : g_set_error_literal (error,
481 : : G_IO_ERROR,
482 : : G_IO_ERROR_INVALID_ARGUMENT,
483 : : _("Invalid seek request"));
484 : 1 : return FALSE;
485 : : }
486 : :
487 : 181 : priv->pos = absolute;
488 : :
489 : 181 : return TRUE;
490 : : }
491 : :
492 : : static gboolean
493 : 1 : g_memory_input_stream_can_truncate (GSeekable *seekable)
494 : : {
495 : 1 : return FALSE;
496 : : }
497 : :
498 : : static gboolean
499 : 1 : g_memory_input_stream_truncate (GSeekable *seekable,
500 : : goffset offset,
501 : : GCancellable *cancellable,
502 : : GError **error)
503 : : {
504 : 1 : g_set_error_literal (error,
505 : : G_IO_ERROR,
506 : : G_IO_ERROR_NOT_SUPPORTED,
507 : : _("Cannot truncate GMemoryInputStream"));
508 : 1 : return FALSE;
509 : : }
510 : :
511 : : static gboolean
512 : 404 : g_memory_input_stream_is_readable (GPollableInputStream *stream)
513 : : {
514 : 404 : return TRUE;
515 : : }
516 : :
517 : : static GSource *
518 : 0 : g_memory_input_stream_create_source (GPollableInputStream *stream,
519 : : GCancellable *cancellable)
520 : : {
521 : : GSource *base_source, *pollable_source;
522 : :
523 : 0 : base_source = g_timeout_source_new (0);
524 : 0 : pollable_source = g_pollable_source_new_full (stream, base_source,
525 : : cancellable);
526 : 0 : g_source_unref (base_source);
527 : :
528 : 0 : return pollable_source;
529 : : }
|