Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright (C) 2006-2007 Red Hat, Inc.
4 : : * Copyright (C) 2007 Jürg Billeter
5 : : *
6 : : * SPDX-License-Identifier: LGPL-2.1-or-later
7 : : *
8 : : * This library is free software; you can redistribute it and/or
9 : : * modify it under the terms of the GNU Lesser General Public
10 : : * License as published by the Free Software Foundation; either
11 : : * version 2.1 of the License, or (at your option) any later version.
12 : : *
13 : : * This library is distributed in the hope that it will be useful,
14 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : : * Lesser General Public License for more details.
17 : : *
18 : : * You should have received a copy of the GNU Lesser General
19 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 : : *
21 : : * Author: Christian Kellner <gicmo@gnome.org>
22 : : */
23 : :
24 : : #include "config.h"
25 : : #include "gbufferedinputstream.h"
26 : : #include "ginputstream.h"
27 : : #include "gcancellable.h"
28 : : #include "gasyncresult.h"
29 : : #include "gtask.h"
30 : : #include "gseekable.h"
31 : : #include "gioerror.h"
32 : : #include <string.h>
33 : : #include "glibintl.h"
34 : :
35 : :
36 : : /**
37 : : * GBufferedInputStream:
38 : : *
39 : : * Buffered input stream implements [class@Gio.FilterInputStream] and provides
40 : : * for buffered reads.
41 : : *
42 : : * By default, `GBufferedInputStream`'s buffer size is set at 4 kilobytes.
43 : : *
44 : : * To create a buffered input stream, use [ctor@Gio.BufferedInputStream.new],
45 : : * or [ctor@Gio.BufferedInputStream.new_sized] to specify the buffer's size at
46 : : * construction.
47 : : *
48 : : * To get the size of a buffer within a buffered input stream, use
49 : : * [method@Gio.BufferedInputStream.get_buffer_size]. To change the size of a
50 : : * buffered input stream's buffer, use [method@Gio.BufferedInputStream.set_buffer_size].
51 : : * Note that the buffer's size cannot be reduced below the size of the data within the buffer.
52 : : */
53 : :
54 : :
55 : : #define DEFAULT_BUFFER_SIZE 4096
56 : :
57 : : struct _GBufferedInputStreamPrivate {
58 : : guint8 *buffer;
59 : : gsize len;
60 : : gsize pos;
61 : : gsize end;
62 : : GAsyncReadyCallback outstanding_callback;
63 : : };
64 : :
65 : : enum {
66 : : PROP_0,
67 : : PROP_BUFSIZE
68 : : };
69 : :
70 : : static void g_buffered_input_stream_set_property (GObject *object,
71 : : guint prop_id,
72 : : const GValue *value,
73 : : GParamSpec *pspec);
74 : :
75 : : static void g_buffered_input_stream_get_property (GObject *object,
76 : : guint prop_id,
77 : : GValue *value,
78 : : GParamSpec *pspec);
79 : : static void g_buffered_input_stream_finalize (GObject *object);
80 : :
81 : :
82 : : static gssize g_buffered_input_stream_skip (GInputStream *stream,
83 : : gsize count,
84 : : GCancellable *cancellable,
85 : : GError **error);
86 : : static void g_buffered_input_stream_skip_async (GInputStream *stream,
87 : : gsize count,
88 : : int io_priority,
89 : : GCancellable *cancellable,
90 : : GAsyncReadyCallback callback,
91 : : gpointer user_data);
92 : : static gssize g_buffered_input_stream_skip_finish (GInputStream *stream,
93 : : GAsyncResult *result,
94 : : GError **error);
95 : : static gssize g_buffered_input_stream_read (GInputStream *stream,
96 : : void *buffer,
97 : : gsize count,
98 : : GCancellable *cancellable,
99 : : GError **error);
100 : : static gssize g_buffered_input_stream_real_fill (GBufferedInputStream *stream,
101 : : gssize count,
102 : : GCancellable *cancellable,
103 : : GError **error);
104 : : static void g_buffered_input_stream_real_fill_async (GBufferedInputStream *stream,
105 : : gssize count,
106 : : int io_priority,
107 : : GCancellable *cancellable,
108 : : GAsyncReadyCallback callback,
109 : : gpointer user_data);
110 : : static gssize g_buffered_input_stream_real_fill_finish (GBufferedInputStream *stream,
111 : : GAsyncResult *result,
112 : : GError **error);
113 : :
114 : : static void g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface);
115 : : static goffset g_buffered_input_stream_tell (GSeekable *seekable);
116 : : static gboolean g_buffered_input_stream_can_seek (GSeekable *seekable);
117 : : static gboolean g_buffered_input_stream_seek (GSeekable *seekable,
118 : : goffset offset,
119 : : GSeekType type,
120 : : GCancellable *cancellable,
121 : : GError **error);
122 : : static gboolean g_buffered_input_stream_can_truncate (GSeekable *seekable);
123 : : static gboolean g_buffered_input_stream_truncate (GSeekable *seekable,
124 : : goffset offset,
125 : : GCancellable *cancellable,
126 : : GError **error);
127 : :
128 : : static void compact_buffer (GBufferedInputStream *stream);
129 : :
130 : 3919385 : G_DEFINE_TYPE_WITH_CODE (GBufferedInputStream,
131 : : g_buffered_input_stream,
132 : : G_TYPE_FILTER_INPUT_STREAM,
133 : : G_ADD_PRIVATE (GBufferedInputStream)
134 : : G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
135 : : g_buffered_input_stream_seekable_iface_init))
136 : :
137 : : static void
138 : 109 : g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
139 : : {
140 : : GObjectClass *object_class;
141 : : GInputStreamClass *istream_class;
142 : : GBufferedInputStreamClass *bstream_class;
143 : :
144 : 109 : object_class = G_OBJECT_CLASS (klass);
145 : 109 : object_class->get_property = g_buffered_input_stream_get_property;
146 : 109 : object_class->set_property = g_buffered_input_stream_set_property;
147 : 109 : object_class->finalize = g_buffered_input_stream_finalize;
148 : :
149 : 109 : istream_class = G_INPUT_STREAM_CLASS (klass);
150 : 109 : istream_class->skip = g_buffered_input_stream_skip;
151 : 109 : istream_class->skip_async = g_buffered_input_stream_skip_async;
152 : 109 : istream_class->skip_finish = g_buffered_input_stream_skip_finish;
153 : 109 : istream_class->read_fn = g_buffered_input_stream_read;
154 : :
155 : 109 : bstream_class = G_BUFFERED_INPUT_STREAM_CLASS (klass);
156 : 109 : bstream_class->fill = g_buffered_input_stream_real_fill;
157 : 109 : bstream_class->fill_async = g_buffered_input_stream_real_fill_async;
158 : 109 : bstream_class->fill_finish = g_buffered_input_stream_real_fill_finish;
159 : :
160 : : /**
161 : : * GBufferedInputStream:buffer-size:
162 : : *
163 : : * The size of the backend buffer, in bytes.
164 : : */
165 : 109 : g_object_class_install_property (object_class,
166 : : PROP_BUFSIZE,
167 : : g_param_spec_uint ("buffer-size", NULL, NULL,
168 : : 1,
169 : : G_MAXUINT,
170 : : DEFAULT_BUFFER_SIZE,
171 : : G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
172 : : G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
173 : :
174 : :
175 : 109 : }
176 : :
177 : : /**
178 : : * g_buffered_input_stream_get_buffer_size:
179 : : * @stream: a [class@Gio.BufferedInputStream]
180 : : *
181 : : * Gets the size of the input buffer.
182 : : *
183 : : * Returns: the current buffer size.
184 : : */
185 : : gsize
186 : 6626 : g_buffered_input_stream_get_buffer_size (GBufferedInputStream *stream)
187 : : {
188 : 6626 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
189 : :
190 : 6626 : return stream->priv->len;
191 : : }
192 : :
193 : : /**
194 : : * g_buffered_input_stream_set_buffer_size:
195 : : * @stream: a [class@Gio.BufferedInputStream]
196 : : * @size: a #gsize
197 : : *
198 : : * Sets the size of the internal buffer of @stream to @size, or to the
199 : : * size of the contents of the buffer. The buffer can never be resized
200 : : * smaller than its current contents.
201 : : */
202 : : void
203 : 1819 : g_buffered_input_stream_set_buffer_size (GBufferedInputStream *stream,
204 : : gsize size)
205 : : {
206 : : GBufferedInputStreamPrivate *priv;
207 : : gsize in_buffer;
208 : : guint8 *buffer;
209 : :
210 : 1819 : g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
211 : :
212 : 1819 : priv = stream->priv;
213 : :
214 : 1819 : if (priv->len == size)
215 : 0 : return;
216 : :
217 : 1819 : if (priv->buffer)
218 : : {
219 : 2 : in_buffer = priv->end - priv->pos;
220 : :
221 : : /* Never resize smaller than current buffer contents */
222 : 2 : size = MAX (size, in_buffer);
223 : :
224 : 2 : buffer = g_malloc (size);
225 : 2 : memcpy (buffer, priv->buffer + priv->pos, in_buffer);
226 : 2 : priv->len = size;
227 : 2 : priv->pos = 0;
228 : 2 : priv->end = in_buffer;
229 : 2 : g_free (priv->buffer);
230 : 2 : priv->buffer = buffer;
231 : : }
232 : : else
233 : : {
234 : 1817 : priv->len = size;
235 : 1817 : priv->pos = 0;
236 : 1817 : priv->end = 0;
237 : 1817 : priv->buffer = g_malloc (size);
238 : : }
239 : :
240 : 1819 : g_object_notify (G_OBJECT (stream), "buffer-size");
241 : : }
242 : :
243 : : static void
244 : 1817 : g_buffered_input_stream_set_property (GObject *object,
245 : : guint prop_id,
246 : : const GValue *value,
247 : : GParamSpec *pspec)
248 : : {
249 : : GBufferedInputStream *bstream;
250 : :
251 : 1817 : bstream = G_BUFFERED_INPUT_STREAM (object);
252 : :
253 : 1817 : switch (prop_id)
254 : : {
255 : 1817 : case PROP_BUFSIZE:
256 : 1817 : g_buffered_input_stream_set_buffer_size (bstream, g_value_get_uint (value));
257 : 1817 : break;
258 : :
259 : 0 : default:
260 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261 : 0 : break;
262 : : }
263 : 1817 : }
264 : :
265 : : static void
266 : 1 : g_buffered_input_stream_get_property (GObject *object,
267 : : guint prop_id,
268 : : GValue *value,
269 : : GParamSpec *pspec)
270 : : {
271 : : GBufferedInputStreamPrivate *priv;
272 : : GBufferedInputStream *bstream;
273 : :
274 : 1 : bstream = G_BUFFERED_INPUT_STREAM (object);
275 : 1 : priv = bstream->priv;
276 : :
277 : 1 : switch (prop_id)
278 : : {
279 : 1 : case PROP_BUFSIZE:
280 : 1 : g_value_set_uint (value, priv->len);
281 : 1 : break;
282 : :
283 : 0 : default:
284 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285 : 0 : break;
286 : : }
287 : 1 : }
288 : :
289 : : static void
290 : 1817 : g_buffered_input_stream_finalize (GObject *object)
291 : : {
292 : : GBufferedInputStreamPrivate *priv;
293 : : GBufferedInputStream *stream;
294 : :
295 : 1817 : stream = G_BUFFERED_INPUT_STREAM (object);
296 : 1817 : priv = stream->priv;
297 : :
298 : 1817 : g_free (priv->buffer);
299 : :
300 : 1817 : G_OBJECT_CLASS (g_buffered_input_stream_parent_class)->finalize (object);
301 : 1817 : }
302 : :
303 : : static void
304 : 109 : g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface)
305 : : {
306 : 109 : iface->tell = g_buffered_input_stream_tell;
307 : 109 : iface->can_seek = g_buffered_input_stream_can_seek;
308 : 109 : iface->seek = g_buffered_input_stream_seek;
309 : 109 : iface->can_truncate = g_buffered_input_stream_can_truncate;
310 : 109 : iface->truncate_fn = g_buffered_input_stream_truncate;
311 : 109 : }
312 : :
313 : : static void
314 : 1817 : g_buffered_input_stream_init (GBufferedInputStream *stream)
315 : : {
316 : 1817 : stream->priv = g_buffered_input_stream_get_instance_private (stream);
317 : 1817 : }
318 : :
319 : :
320 : : /**
321 : : * g_buffered_input_stream_new:
322 : : * @base_stream: a [class@Gio.InputStream]
323 : : *
324 : : * Creates a new [class@Gio.InputStream] from the given @base_stream, with
325 : : * a buffer set to the default size (4 kilobytes).
326 : : *
327 : : * Returns: a [class@Gio.InputStream] for the given @base_stream.
328 : : */
329 : : GInputStream *
330 : 5 : g_buffered_input_stream_new (GInputStream *base_stream)
331 : : {
332 : : GInputStream *stream;
333 : :
334 : 5 : g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
335 : :
336 : 5 : stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
337 : : "base-stream", base_stream,
338 : : NULL);
339 : :
340 : 5 : return stream;
341 : : }
342 : :
343 : : /**
344 : : * g_buffered_input_stream_new_sized:
345 : : * @base_stream: a [class@Gio.InputStream]
346 : : * @size: a #gsize
347 : : *
348 : : * Creates a new [class@Gio.BufferedInputStream] from the given @base_stream,
349 : : * with a buffer set to @size.
350 : : *
351 : : * Returns: a [class@Gio.InputStream].
352 : : */
353 : : GInputStream *
354 : 11 : g_buffered_input_stream_new_sized (GInputStream *base_stream,
355 : : gsize size)
356 : : {
357 : : GInputStream *stream;
358 : :
359 : 11 : g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
360 : :
361 : 11 : stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
362 : : "base-stream", base_stream,
363 : : "buffer-size", (guint)size,
364 : : NULL);
365 : :
366 : 11 : return stream;
367 : : }
368 : :
369 : : /**
370 : : * g_buffered_input_stream_fill:
371 : : * @stream: a [class@Gio.BufferedInputStream]
372 : : * @count: the number of bytes that will be read from the stream
373 : : * @cancellable: (nullable): optional [class@Gio.Cancellable] object, `NULL` to ignore
374 : : * @error: location to store the error occurring, or `NULL` to ignore
375 : : *
376 : : * Tries to read @count bytes from the stream into the buffer.
377 : : * Will block during this read.
378 : : *
379 : : * If @count is zero, returns zero and does nothing. A value of @count
380 : : * larger than `G_MAXSSIZE` will cause a
381 : : * [error@Gio.IOErrorEnum.INVALID_ARGUMENT] error.
382 : : *
383 : : * On success, the number of bytes read into the buffer is returned.
384 : : * It is not an error if this is not the same as the requested size, as it
385 : : * can happen e.g. near the end of a file. Zero is returned on end of file
386 : : * (or if @count is zero), but never otherwise.
387 : : *
388 : : * If @count is -1 then the attempted read size is equal to the number of
389 : : * bytes that are required to fill the buffer.
390 : : *
391 : : * If @cancellable is not `NULL`, then the operation can be cancelled by
392 : : * triggering the cancellable object from another thread. If the operation
393 : : * was cancelled, the error [error@Gio.IOErrorEnum.CANCELLED] will be returned.
394 : : * If an operation was partially finished when the operation was cancelled the
395 : : * partial result will be returned, without an error.
396 : : *
397 : : * On error `-1` is returned and @error is set accordingly.
398 : : *
399 : : * For the asynchronous, non-blocking, version of this function, see
400 : : * [method@Gio.BufferedInputStream.fill_async].
401 : : *
402 : : * Returns: the number of bytes read into @stream's buffer, up to @count,
403 : : * or `-1` on error.
404 : : */
405 : : gssize
406 : 547293 : g_buffered_input_stream_fill (GBufferedInputStream *stream,
407 : : gssize count,
408 : : GCancellable *cancellable,
409 : : GError **error)
410 : : {
411 : : GBufferedInputStreamClass *class;
412 : : GInputStream *input_stream;
413 : : gssize res;
414 : :
415 : 547293 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
416 : :
417 : 547293 : input_stream = G_INPUT_STREAM (stream);
418 : :
419 : 547293 : if (count < -1)
420 : : {
421 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
422 : : _("Too large count value passed to %s"), G_STRFUNC);
423 : 0 : return -1;
424 : : }
425 : :
426 : 547293 : if (!g_input_stream_set_pending (input_stream, error))
427 : 0 : return -1;
428 : :
429 : 547293 : if (cancellable)
430 : 49 : g_cancellable_push_current (cancellable);
431 : :
432 : 547293 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
433 : 547293 : res = class->fill (stream, count, cancellable, error);
434 : :
435 : 547293 : if (cancellable)
436 : 49 : g_cancellable_pop_current (cancellable);
437 : :
438 : 547293 : g_input_stream_clear_pending (input_stream);
439 : :
440 : 547293 : return res;
441 : : }
442 : :
443 : : static void
444 : 28 : async_fill_callback_wrapper (GObject *source_object,
445 : : GAsyncResult *res,
446 : : gpointer user_data)
447 : : {
448 : 28 : GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (source_object);
449 : :
450 : 28 : g_input_stream_clear_pending (G_INPUT_STREAM (stream));
451 : 28 : (*stream->priv->outstanding_callback) (source_object, res, user_data);
452 : 28 : g_object_unref (stream);
453 : 28 : }
454 : :
455 : : /**
456 : : * g_buffered_input_stream_fill_async:
457 : : * @stream: a [class@Gio.BufferedInputStream]
458 : : * @count: the number of bytes that will be read from the stream
459 : : * @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the request
460 : : * @cancellable: (nullable): optional [class@Gio.Cancellable] object
461 : : * @callback: (scope async) (closure user_data): a [callback@Gio.AsyncReadyCallback]
462 : : * @user_data: a #gpointer
463 : : *
464 : : * Reads data into @stream's buffer asynchronously, up to @count size.
465 : : * @io_priority can be used to prioritize reads. For the synchronous
466 : : * version of this function, see [method@Gio.BufferedInputStream.fill].
467 : : *
468 : : * If @count is `-1` then the attempted read size is equal to the number
469 : : * of bytes that are required to fill the buffer.
470 : : */
471 : : void
472 : 28 : g_buffered_input_stream_fill_async (GBufferedInputStream *stream,
473 : : gssize count,
474 : : int io_priority,
475 : : GCancellable *cancellable,
476 : : GAsyncReadyCallback callback,
477 : : gpointer user_data)
478 : : {
479 : : GBufferedInputStreamClass *class;
480 : 28 : GError *error = NULL;
481 : :
482 : 28 : g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
483 : :
484 : 28 : if (count == 0)
485 : : {
486 : : GTask *task;
487 : :
488 : 0 : task = g_task_new (stream, cancellable, callback, user_data);
489 : 0 : g_task_set_source_tag (task, g_buffered_input_stream_fill_async);
490 : 0 : g_task_return_int (task, 0);
491 : 0 : g_object_unref (task);
492 : 0 : return;
493 : : }
494 : :
495 : 28 : if (count < -1)
496 : : {
497 : 0 : g_task_report_new_error (stream, callback, user_data,
498 : : g_buffered_input_stream_fill_async,
499 : : G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
500 : 0 : _("Too large count value passed to %s"),
501 : : G_STRFUNC);
502 : 0 : return;
503 : : }
504 : :
505 : 28 : if (!g_input_stream_set_pending (G_INPUT_STREAM (stream), &error))
506 : : {
507 : 0 : g_task_report_error (stream, callback, user_data,
508 : : g_buffered_input_stream_fill_async,
509 : : error);
510 : 0 : return;
511 : : }
512 : :
513 : 28 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
514 : :
515 : 28 : stream->priv->outstanding_callback = callback;
516 : 28 : g_object_ref (stream);
517 : 28 : class->fill_async (stream, count, io_priority, cancellable,
518 : : async_fill_callback_wrapper, user_data);
519 : : }
520 : :
521 : : /**
522 : : * g_buffered_input_stream_fill_finish:
523 : : * @stream: a [class@Gio.BufferedInputStream]
524 : : * @result: a [iface@Gio.AsyncResult]
525 : : * @error: a [type@GLib.Error]
526 : : *
527 : : * Finishes an asynchronous read.
528 : : *
529 : : * Returns: a #gssize of the read stream, or `-1` on an error.
530 : : */
531 : : gssize
532 : 32 : g_buffered_input_stream_fill_finish (GBufferedInputStream *stream,
533 : : GAsyncResult *result,
534 : : GError **error)
535 : : {
536 : : GBufferedInputStreamClass *class;
537 : :
538 : 32 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
539 : 32 : g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1);
540 : :
541 : 32 : if (g_async_result_legacy_propagate_error (result, error))
542 : 0 : return -1;
543 : 32 : else if (g_async_result_is_tagged (result, g_buffered_input_stream_fill_async))
544 : 0 : return g_task_propagate_int (G_TASK (result), error);
545 : :
546 : 32 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
547 : 32 : return class->fill_finish (stream, result, error);
548 : : }
549 : :
550 : : /**
551 : : * g_buffered_input_stream_get_available:
552 : : * @stream: [class@Gio.BufferedInputStream]
553 : : *
554 : : * Gets the size of the available data within the stream.
555 : : *
556 : : * Returns: size of the available stream.
557 : : */
558 : : gsize
559 : 1088219 : g_buffered_input_stream_get_available (GBufferedInputStream *stream)
560 : : {
561 : 1088219 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
562 : :
563 : 1088219 : return stream->priv->end - stream->priv->pos;
564 : : }
565 : :
566 : : /**
567 : : * g_buffered_input_stream_peek:
568 : : * @stream: a [class@Gio.BufferedInputStream]
569 : : * @buffer: (array length=count) (element-type guint8): a pointer to
570 : : * an allocated chunk of memory, which must be at least @count bytes long
571 : : * @offset: offset into the buffered input to peek from, or zero to peek from
572 : : * the next byte in the buffered input onwards
573 : : * @count: number of bytes to peek
574 : : *
575 : : * Peeks in the buffered input, copying @count bytes of data from @offset bytes
576 : : * in the buffered input into @buffer.
577 : : *
578 : : * Returns: the number of bytes copied, which may be zero
579 : : */
580 : : gsize
581 : 5 : g_buffered_input_stream_peek (GBufferedInputStream *stream,
582 : : void *buffer,
583 : : gsize offset,
584 : : gsize count)
585 : : {
586 : : gsize available;
587 : : gsize end;
588 : :
589 : 5 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
590 : 5 : g_return_val_if_fail (buffer != NULL, 0);
591 : :
592 : 5 : available = g_buffered_input_stream_get_available (stream);
593 : :
594 : 5 : if (offset > available || offset > G_MAXSIZE - count)
595 : 2 : return 0;
596 : :
597 : 3 : end = MIN (offset + count, available);
598 : 3 : count = end - offset;
599 : :
600 : 3 : memcpy (buffer, stream->priv->buffer + stream->priv->pos + offset, count);
601 : 3 : return count;
602 : : }
603 : :
604 : : /**
605 : : * g_buffered_input_stream_peek_buffer:
606 : : * @stream: a [class@Gio.BufferedInputStream]
607 : : * @count: (out): a #gsize to get the number of bytes available in the buffer
608 : : *
609 : : * Returns the buffer with the currently available bytes. The returned
610 : : * buffer must not be modified and will become invalid when reading from
611 : : * the stream or filling the buffer.
612 : : *
613 : : * Returns: (array length=count) (element-type guint8) (transfer none):
614 : : * read-only buffer
615 : : */
616 : : const void*
617 : 29808 : g_buffered_input_stream_peek_buffer (GBufferedInputStream *stream,
618 : : gsize *count)
619 : : {
620 : : GBufferedInputStreamPrivate *priv;
621 : :
622 : 29808 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), NULL);
623 : :
624 : 29808 : priv = stream->priv;
625 : :
626 : 29808 : if (count)
627 : 29808 : *count = priv->end - priv->pos;
628 : :
629 : 29808 : return priv->buffer + priv->pos;
630 : : }
631 : :
632 : : static void
633 : 5121 : compact_buffer (GBufferedInputStream *stream)
634 : : {
635 : : GBufferedInputStreamPrivate *priv;
636 : : gsize current_size;
637 : :
638 : 5121 : priv = stream->priv;
639 : :
640 : 5121 : current_size = priv->end - priv->pos;
641 : :
642 : 5121 : memmove (priv->buffer, priv->buffer + priv->pos, current_size);
643 : :
644 : 5121 : priv->pos = 0;
645 : 5121 : priv->end = current_size;
646 : 5121 : }
647 : :
648 : : static gssize
649 : 547311 : g_buffered_input_stream_real_fill (GBufferedInputStream *stream,
650 : : gssize count,
651 : : GCancellable *cancellable,
652 : : GError **error)
653 : : {
654 : : GBufferedInputStreamPrivate *priv;
655 : : GInputStream *base_stream;
656 : : gssize nread;
657 : : gsize in_buffer;
658 : :
659 : 547311 : priv = stream->priv;
660 : :
661 : 547311 : if (count == -1)
662 : 6596 : count = priv->len;
663 : :
664 : 547311 : in_buffer = priv->end - priv->pos;
665 : :
666 : : /* Never fill more than can fit in the buffer */
667 : 547311 : count = MIN ((gsize) count, priv->len - in_buffer);
668 : :
669 : : /* If requested length does not fit at end, compact */
670 : 547311 : if (priv->len - priv->end < (gsize) count)
671 : 5097 : compact_buffer (stream);
672 : :
673 : 547311 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
674 : 547311 : nread = g_input_stream_read (base_stream,
675 : 547311 : priv->buffer + priv->end,
676 : : count,
677 : : cancellable,
678 : : error);
679 : :
680 : 547311 : if (nread > 0)
681 : 547241 : priv->end += nread;
682 : :
683 : 547311 : return nread;
684 : : }
685 : :
686 : : static gssize
687 : 119 : g_buffered_input_stream_skip (GInputStream *stream,
688 : : gsize count,
689 : : GCancellable *cancellable,
690 : : GError **error)
691 : : {
692 : : GBufferedInputStream *bstream;
693 : : GBufferedInputStreamPrivate *priv;
694 : : GBufferedInputStreamClass *class;
695 : : GInputStream *base_stream;
696 : : gsize available, bytes_skipped;
697 : : gssize nread;
698 : :
699 : 119 : bstream = G_BUFFERED_INPUT_STREAM (stream);
700 : 119 : priv = bstream->priv;
701 : :
702 : 119 : available = priv->end - priv->pos;
703 : :
704 : 119 : if (count <= available)
705 : : {
706 : 114 : priv->pos += count;
707 : 114 : return count;
708 : : }
709 : :
710 : : /* Full request not available, skip all currently available and
711 : : * request refill for more
712 : : */
713 : :
714 : 5 : priv->pos = 0;
715 : 5 : priv->end = 0;
716 : 5 : bytes_skipped = available;
717 : 5 : count -= available;
718 : :
719 : 5 : if (bytes_skipped > 0)
720 : 4 : error = NULL; /* Ignore further errors if we already read some data */
721 : :
722 : 5 : if (count > priv->len)
723 : : {
724 : : /* Large request, shortcut buffer */
725 : :
726 : 4 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
727 : :
728 : 4 : nread = g_input_stream_skip (base_stream,
729 : : count,
730 : : cancellable,
731 : : error);
732 : :
733 : 4 : if (nread < 0 && bytes_skipped == 0)
734 : 0 : return -1;
735 : :
736 : 4 : if (nread > 0)
737 : 3 : bytes_skipped += nread;
738 : :
739 : 4 : return bytes_skipped;
740 : : }
741 : :
742 : 1 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
743 : 1 : nread = class->fill (bstream, priv->len, cancellable, error);
744 : :
745 : 1 : if (nread < 0)
746 : : {
747 : 0 : if (bytes_skipped == 0)
748 : 0 : return -1;
749 : : else
750 : 0 : return bytes_skipped;
751 : : }
752 : :
753 : 1 : available = priv->end - priv->pos;
754 : 1 : count = MIN (count, available);
755 : :
756 : 1 : bytes_skipped += count;
757 : 1 : priv->pos += count;
758 : :
759 : 1 : return bytes_skipped;
760 : : }
761 : :
762 : : static gssize
763 : 564034 : g_buffered_input_stream_read (GInputStream *stream,
764 : : void *buffer,
765 : : gsize count,
766 : : GCancellable *cancellable,
767 : : GError **error)
768 : : {
769 : : GBufferedInputStream *bstream;
770 : : GBufferedInputStreamPrivate *priv;
771 : : GBufferedInputStreamClass *class;
772 : : GInputStream *base_stream;
773 : : gsize available, bytes_read;
774 : : gssize nread;
775 : :
776 : 564034 : bstream = G_BUFFERED_INPUT_STREAM (stream);
777 : 564034 : priv = bstream->priv;
778 : :
779 : 564034 : available = priv->end - priv->pos;
780 : :
781 : 564034 : if (count <= available)
782 : : {
783 : 564021 : memcpy (buffer, priv->buffer + priv->pos, count);
784 : 564021 : priv->pos += count;
785 : 564021 : return count;
786 : : }
787 : :
788 : : /* Full request not available, read all currently available and
789 : : * request refill for more
790 : : */
791 : :
792 : 13 : memcpy (buffer, priv->buffer + priv->pos, available);
793 : 13 : priv->pos = 0;
794 : 13 : priv->end = 0;
795 : 13 : bytes_read = available;
796 : 13 : count -= available;
797 : :
798 : 13 : if (bytes_read > 0)
799 : 3 : error = NULL; /* Ignore further errors if we already read some data */
800 : :
801 : 13 : if (count > priv->len)
802 : : {
803 : : /* Large request, shortcut buffer */
804 : :
805 : 11 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
806 : :
807 : 11 : nread = g_input_stream_read (base_stream,
808 : : (char *)buffer + bytes_read,
809 : : count,
810 : : cancellable,
811 : : error);
812 : :
813 : 11 : if (nread < 0 && bytes_read == 0)
814 : 0 : return -1;
815 : :
816 : 11 : if (nread > 0)
817 : 9 : bytes_read += nread;
818 : :
819 : 11 : return bytes_read;
820 : : }
821 : :
822 : 2 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
823 : 2 : nread = class->fill (bstream, priv->len, cancellable, error);
824 : 2 : if (nread < 0)
825 : : {
826 : 0 : if (bytes_read == 0)
827 : 0 : return -1;
828 : : else
829 : 0 : return bytes_read;
830 : : }
831 : :
832 : 2 : available = priv->end - priv->pos;
833 : 2 : count = MIN (count, available);
834 : :
835 : 2 : memcpy ((char *)buffer + bytes_read, (char *)priv->buffer + priv->pos, count);
836 : 2 : bytes_read += count;
837 : 2 : priv->pos += count;
838 : :
839 : 2 : return bytes_read;
840 : : }
841 : :
842 : : static goffset
843 : 14 : g_buffered_input_stream_tell (GSeekable *seekable)
844 : : {
845 : : GBufferedInputStream *bstream;
846 : : GBufferedInputStreamPrivate *priv;
847 : : GInputStream *base_stream;
848 : : GSeekable *base_stream_seekable;
849 : : gsize available;
850 : : goffset base_offset;
851 : :
852 : 14 : bstream = G_BUFFERED_INPUT_STREAM (seekable);
853 : 14 : priv = bstream->priv;
854 : :
855 : 14 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
856 : 14 : if (!G_IS_SEEKABLE (base_stream))
857 : 0 : return 0;
858 : 14 : base_stream_seekable = G_SEEKABLE (base_stream);
859 : :
860 : 14 : available = priv->end - priv->pos;
861 : 14 : base_offset = g_seekable_tell (base_stream_seekable);
862 : :
863 : 14 : return base_offset - available;
864 : : }
865 : :
866 : : static gboolean
867 : 0 : g_buffered_input_stream_can_seek (GSeekable *seekable)
868 : : {
869 : : GInputStream *base_stream;
870 : :
871 : 0 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
872 : 0 : return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream));
873 : : }
874 : :
875 : : static gboolean
876 : 6 : g_buffered_input_stream_seek (GSeekable *seekable,
877 : : goffset offset,
878 : : GSeekType type,
879 : : GCancellable *cancellable,
880 : : GError **error)
881 : : {
882 : : GBufferedInputStream *bstream;
883 : : GBufferedInputStreamPrivate *priv;
884 : : GInputStream *base_stream;
885 : : GSeekable *base_stream_seekable;
886 : :
887 : 6 : bstream = G_BUFFERED_INPUT_STREAM (seekable);
888 : 6 : priv = bstream->priv;
889 : :
890 : 6 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
891 : 6 : if (!G_IS_SEEKABLE (base_stream))
892 : : {
893 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
894 : : _("Seek not supported on base stream"));
895 : 0 : return FALSE;
896 : : }
897 : :
898 : 6 : base_stream_seekable = G_SEEKABLE (base_stream);
899 : :
900 : 6 : if (type == G_SEEK_CUR)
901 : : {
902 : 4 : if (offset <= (goffset) (priv->end - priv->pos) &&
903 : 3 : offset >= (goffset) -priv->pos)
904 : : {
905 : 2 : priv->pos += offset;
906 : 2 : return TRUE;
907 : : }
908 : : else
909 : : {
910 : 2 : offset -= priv->end - priv->pos;
911 : : }
912 : : }
913 : :
914 : 4 : if (g_seekable_seek (base_stream_seekable, offset, type, cancellable, error))
915 : : {
916 : 4 : priv->pos = 0;
917 : 4 : priv->end = 0;
918 : 4 : return TRUE;
919 : : }
920 : : else
921 : : {
922 : 0 : return FALSE;
923 : : }
924 : : }
925 : :
926 : : static gboolean
927 : 0 : g_buffered_input_stream_can_truncate (GSeekable *seekable)
928 : : {
929 : 0 : return FALSE;
930 : : }
931 : :
932 : : static gboolean
933 : 0 : g_buffered_input_stream_truncate (GSeekable *seekable,
934 : : goffset offset,
935 : : GCancellable *cancellable,
936 : : GError **error)
937 : : {
938 : 0 : g_set_error_literal (error,
939 : : G_IO_ERROR,
940 : : G_IO_ERROR_NOT_SUPPORTED,
941 : : _("Cannot truncate GBufferedInputStream"));
942 : 0 : return FALSE;
943 : : }
944 : :
945 : : /**
946 : : * g_buffered_input_stream_read_byte:
947 : : * @stream: a [class@Gio.BufferedInputStream]
948 : : * @cancellable: (nullable): optional [class@Gio.Cancellable] object, `NULL` to ignore
949 : : * @error: location to store the error occurring, or `NULL` to ignore
950 : : *
951 : : * Tries to read a single byte from the stream or the buffer. Will block
952 : : * during this read.
953 : : *
954 : : * On success, the byte read from the stream is returned. On end of stream
955 : : * `-1` is returned but it's not an exceptional error and @error is not set.
956 : : *
957 : : * If @cancellable is not `NULL`, then the operation can be cancelled by
958 : : * triggering the cancellable object from another thread. If the operation
959 : : * was cancelled, the error [error@Gio.IOErrorEnum.CANCELLED] will be returned.
960 : : * If an operation was partially finished when the operation was cancelled the
961 : : * partial result will be returned, without an error.
962 : : *
963 : : * On error `-1` is returned and @error is set accordingly.
964 : : *
965 : : * Returns: the byte read from the @stream, or `-1` on end of stream or error.
966 : : */
967 : : int
968 : 26 : g_buffered_input_stream_read_byte (GBufferedInputStream *stream,
969 : : GCancellable *cancellable,
970 : : GError **error)
971 : : {
972 : : GBufferedInputStreamPrivate *priv;
973 : : GBufferedInputStreamClass *class;
974 : : GInputStream *input_stream;
975 : : gsize available;
976 : : gssize nread;
977 : :
978 : 26 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
979 : :
980 : 26 : priv = stream->priv;
981 : 26 : input_stream = G_INPUT_STREAM (stream);
982 : :
983 : 26 : if (g_input_stream_is_closed (input_stream))
984 : : {
985 : 1 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
986 : : _("Stream is already closed"));
987 : 1 : return -1;
988 : : }
989 : :
990 : 25 : if (!g_input_stream_set_pending (input_stream, error))
991 : 0 : return -1;
992 : :
993 : 25 : available = priv->end - priv->pos;
994 : :
995 : 25 : if (available != 0)
996 : : {
997 : 10 : g_input_stream_clear_pending (input_stream);
998 : 10 : return priv->buffer[priv->pos++];
999 : : }
1000 : :
1001 : : /* Byte not available, request refill for more */
1002 : :
1003 : 15 : if (cancellable)
1004 : 0 : g_cancellable_push_current (cancellable);
1005 : :
1006 : 15 : priv->pos = 0;
1007 : 15 : priv->end = 0;
1008 : :
1009 : 15 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1010 : 15 : nread = class->fill (stream, priv->len, cancellable, error);
1011 : :
1012 : 15 : if (cancellable)
1013 : 0 : g_cancellable_pop_current (cancellable);
1014 : :
1015 : 15 : g_input_stream_clear_pending (input_stream);
1016 : :
1017 : 15 : if (nread <= 0)
1018 : 1 : return -1; /* error or end of stream */
1019 : :
1020 : 14 : return priv->buffer[priv->pos++];
1021 : : }
1022 : :
1023 : : /* ************************** */
1024 : : /* Async stuff implementation */
1025 : : /* ************************** */
1026 : :
1027 : : static void
1028 : 32 : fill_async_callback (GObject *source_object,
1029 : : GAsyncResult *result,
1030 : : gpointer user_data)
1031 : : {
1032 : : GError *error;
1033 : : gssize res;
1034 : 32 : GTask *task = user_data;
1035 : :
1036 : 32 : error = NULL;
1037 : 32 : res = g_input_stream_read_finish (G_INPUT_STREAM (source_object),
1038 : : result, &error);
1039 : 32 : if (res == -1)
1040 : 0 : g_task_return_error (task, error);
1041 : : else
1042 : : {
1043 : : GBufferedInputStream *stream;
1044 : : GBufferedInputStreamPrivate *priv;
1045 : :
1046 : 32 : stream = g_task_get_source_object (task);
1047 : 32 : priv = G_BUFFERED_INPUT_STREAM (stream)->priv;
1048 : :
1049 : 32 : g_assert (priv->end + res <= priv->len);
1050 : 32 : priv->end += res;
1051 : :
1052 : 32 : g_task_return_int (task, res);
1053 : : }
1054 : :
1055 : 32 : g_object_unref (task);
1056 : 32 : }
1057 : :
1058 : : static void
1059 : 32 : g_buffered_input_stream_real_fill_async (GBufferedInputStream *stream,
1060 : : gssize count,
1061 : : int io_priority,
1062 : : GCancellable *cancellable,
1063 : : GAsyncReadyCallback callback,
1064 : : gpointer user_data)
1065 : : {
1066 : : GBufferedInputStreamPrivate *priv;
1067 : : GInputStream *base_stream;
1068 : : GTask *task;
1069 : : gsize in_buffer;
1070 : :
1071 : 32 : priv = stream->priv;
1072 : :
1073 : 32 : if (count == -1)
1074 : 27 : count = priv->len;
1075 : :
1076 : 32 : in_buffer = priv->end - priv->pos;
1077 : :
1078 : : /* Never fill more than can fit in the buffer */
1079 : 32 : count = MIN ((gsize) count, priv->len - in_buffer);
1080 : :
1081 : : /* If requested length does not fit at end, compact */
1082 : 32 : if (priv->len - priv->end < (gsize) count)
1083 : 24 : compact_buffer (stream);
1084 : :
1085 : 32 : task = g_task_new (stream, cancellable, callback, user_data);
1086 : 32 : g_task_set_source_tag (task, g_buffered_input_stream_real_fill_async);
1087 : :
1088 : 32 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
1089 : 32 : g_input_stream_read_async (base_stream,
1090 : 32 : priv->buffer + priv->end,
1091 : : count,
1092 : : io_priority,
1093 : : cancellable,
1094 : : fill_async_callback,
1095 : : task);
1096 : 32 : }
1097 : :
1098 : : static gssize
1099 : 32 : g_buffered_input_stream_real_fill_finish (GBufferedInputStream *stream,
1100 : : GAsyncResult *result,
1101 : : GError **error)
1102 : : {
1103 : 32 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1104 : :
1105 : 32 : return g_task_propagate_int (G_TASK (result), error);
1106 : : }
1107 : :
1108 : : typedef struct
1109 : : {
1110 : : gsize bytes_skipped;
1111 : : gsize count;
1112 : : } SkipAsyncData;
1113 : :
1114 : : static void
1115 : 9 : free_skip_async_data (gpointer _data)
1116 : : {
1117 : 9 : SkipAsyncData *data = _data;
1118 : 9 : g_slice_free (SkipAsyncData, data);
1119 : 9 : }
1120 : :
1121 : : static void
1122 : 5 : large_skip_callback (GObject *source_object,
1123 : : GAsyncResult *result,
1124 : : gpointer user_data)
1125 : : {
1126 : 5 : GTask *task = G_TASK (user_data);
1127 : : SkipAsyncData *data;
1128 : : GError *error;
1129 : : gssize nread;
1130 : :
1131 : 5 : data = g_task_get_task_data (task);
1132 : :
1133 : 5 : error = NULL;
1134 : 5 : nread = g_input_stream_skip_finish (G_INPUT_STREAM (source_object),
1135 : : result, &error);
1136 : :
1137 : : /* Only report the error if we've not already read some data */
1138 : 5 : if (nread < 0 && data->bytes_skipped == 0)
1139 : 0 : g_task_return_error (task, error);
1140 : : else
1141 : : {
1142 : 5 : if (error)
1143 : 0 : g_error_free (error);
1144 : :
1145 : 5 : if (nread > 0)
1146 : 4 : data->bytes_skipped += nread;
1147 : :
1148 : 5 : g_task_return_int (task, data->bytes_skipped);
1149 : : }
1150 : :
1151 : 5 : g_object_unref (task);
1152 : 5 : }
1153 : :
1154 : : static void
1155 : 4 : skip_fill_buffer_callback (GObject *source_object,
1156 : : GAsyncResult *result,
1157 : : gpointer user_data)
1158 : : {
1159 : 4 : GTask *task = G_TASK (user_data);
1160 : : GBufferedInputStream *bstream;
1161 : : GBufferedInputStreamPrivate *priv;
1162 : : SkipAsyncData *data;
1163 : : GError *error;
1164 : : gssize nread;
1165 : : gsize available;
1166 : :
1167 : 4 : bstream = G_BUFFERED_INPUT_STREAM (source_object);
1168 : 4 : priv = bstream->priv;
1169 : :
1170 : 4 : data = g_task_get_task_data (task);
1171 : :
1172 : 4 : error = NULL;
1173 : 4 : nread = g_buffered_input_stream_fill_finish (bstream,
1174 : : result, &error);
1175 : :
1176 : 4 : if (nread < 0 && data->bytes_skipped == 0)
1177 : 0 : g_task_return_error (task, error);
1178 : : else
1179 : : {
1180 : 4 : if (error)
1181 : 0 : g_error_free (error);
1182 : :
1183 : 4 : if (nread > 0)
1184 : : {
1185 : 4 : available = priv->end - priv->pos;
1186 : 4 : data->count = MIN (data->count, available);
1187 : :
1188 : 4 : data->bytes_skipped += data->count;
1189 : 4 : priv->pos += data->count;
1190 : : }
1191 : :
1192 : 4 : g_assert (data->bytes_skipped <= G_MAXSSIZE);
1193 : 4 : g_task_return_int (task, data->bytes_skipped);
1194 : : }
1195 : :
1196 : 4 : g_object_unref (task);
1197 : 4 : }
1198 : :
1199 : : static void
1200 : 9 : g_buffered_input_stream_skip_async (GInputStream *stream,
1201 : : gsize count,
1202 : : int io_priority,
1203 : : GCancellable *cancellable,
1204 : : GAsyncReadyCallback callback,
1205 : : gpointer user_data)
1206 : : {
1207 : : GBufferedInputStream *bstream;
1208 : : GBufferedInputStreamPrivate *priv;
1209 : : GBufferedInputStreamClass *class;
1210 : : GInputStream *base_stream;
1211 : : gsize available;
1212 : : GTask *task;
1213 : : SkipAsyncData *data;
1214 : :
1215 : 9 : bstream = G_BUFFERED_INPUT_STREAM (stream);
1216 : 9 : priv = bstream->priv;
1217 : :
1218 : 9 : data = g_slice_new (SkipAsyncData);
1219 : 9 : data->bytes_skipped = 0;
1220 : 9 : task = g_task_new (stream, cancellable, callback, user_data);
1221 : 9 : g_task_set_source_tag (task, g_buffered_input_stream_skip_async);
1222 : 9 : g_task_set_task_data (task, data, free_skip_async_data);
1223 : :
1224 : 9 : available = priv->end - priv->pos;
1225 : :
1226 : 9 : if (count <= available)
1227 : : {
1228 : 0 : priv->pos += count;
1229 : :
1230 : 0 : g_task_return_int (task, count);
1231 : 0 : g_object_unref (task);
1232 : 0 : return;
1233 : : }
1234 : :
1235 : : /* Full request not available, skip all currently available
1236 : : * and request refill for more
1237 : : */
1238 : :
1239 : 9 : priv->pos = 0;
1240 : 9 : priv->end = 0;
1241 : :
1242 : 9 : count -= available;
1243 : :
1244 : 9 : data->bytes_skipped = available;
1245 : 9 : data->count = count;
1246 : :
1247 : 9 : if (count > priv->len)
1248 : : {
1249 : : /* Large request, shortcut buffer */
1250 : 5 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
1251 : :
1252 : : /* If 'count > G_MAXSSIZE then 'g_input_stream_skip_async()'
1253 : : * will return an error anyway before calling this.
1254 : : * Assert that this is never called for too big `count` for clarity. */
1255 : 5 : g_assert ((gssize) count >= 0);
1256 : 5 : g_input_stream_skip_async (base_stream,
1257 : : count,
1258 : : io_priority, cancellable,
1259 : : large_skip_callback,
1260 : : task);
1261 : : }
1262 : : else
1263 : : {
1264 : 4 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1265 : 4 : class->fill_async (bstream, priv->len, io_priority, cancellable,
1266 : : skip_fill_buffer_callback, task);
1267 : : }
1268 : : }
1269 : :
1270 : : static gssize
1271 : 9 : g_buffered_input_stream_skip_finish (GInputStream *stream,
1272 : : GAsyncResult *result,
1273 : : GError **error)
1274 : : {
1275 : 9 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1276 : :
1277 : 9 : return g_task_propagate_int (G_TASK (result), error);
1278 : : }
|