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 : 3922015 : 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 : 106 : g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
139 : : {
140 : : GObjectClass *object_class;
141 : : GInputStreamClass *istream_class;
142 : : GBufferedInputStreamClass *bstream_class;
143 : :
144 : 106 : object_class = G_OBJECT_CLASS (klass);
145 : 106 : object_class->get_property = g_buffered_input_stream_get_property;
146 : 106 : object_class->set_property = g_buffered_input_stream_set_property;
147 : 106 : object_class->finalize = g_buffered_input_stream_finalize;
148 : :
149 : 106 : istream_class = G_INPUT_STREAM_CLASS (klass);
150 : 106 : istream_class->skip = g_buffered_input_stream_skip;
151 : 106 : istream_class->skip_async = g_buffered_input_stream_skip_async;
152 : 106 : istream_class->skip_finish = g_buffered_input_stream_skip_finish;
153 : 106 : istream_class->read_fn = g_buffered_input_stream_read;
154 : :
155 : 106 : bstream_class = G_BUFFERED_INPUT_STREAM_CLASS (klass);
156 : 106 : bstream_class->fill = g_buffered_input_stream_real_fill;
157 : 106 : bstream_class->fill_async = g_buffered_input_stream_real_fill_async;
158 : 106 : 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 : 106 : 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 : 106 : }
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 : 6894 : g_buffered_input_stream_get_buffer_size (GBufferedInputStream *stream)
187 : : {
188 : 6894 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
189 : :
190 : 6894 : 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 : 1884 : 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 : 1884 : g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
211 : :
212 : 1884 : priv = stream->priv;
213 : :
214 : 1884 : if (priv->len == size)
215 : 0 : return;
216 : :
217 : 1884 : 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 : 1882 : priv->len = size;
235 : 1882 : priv->pos = 0;
236 : 1882 : priv->end = 0;
237 : 1882 : priv->buffer = g_malloc (size);
238 : : }
239 : :
240 : 1884 : g_object_notify (G_OBJECT (stream), "buffer-size");
241 : : }
242 : :
243 : : static void
244 : 1882 : 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 : 1882 : bstream = G_BUFFERED_INPUT_STREAM (object);
252 : :
253 : 1882 : switch (prop_id)
254 : : {
255 : 1882 : case PROP_BUFSIZE:
256 : 1882 : g_buffered_input_stream_set_buffer_size (bstream, g_value_get_uint (value));
257 : 1882 : break;
258 : :
259 : 0 : default:
260 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261 : 0 : break;
262 : : }
263 : 1882 : }
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 : 1882 : g_buffered_input_stream_finalize (GObject *object)
291 : : {
292 : : GBufferedInputStreamPrivate *priv;
293 : : GBufferedInputStream *stream;
294 : :
295 : 1882 : stream = G_BUFFERED_INPUT_STREAM (object);
296 : 1882 : priv = stream->priv;
297 : :
298 : 1882 : g_free (priv->buffer);
299 : :
300 : 1882 : G_OBJECT_CLASS (g_buffered_input_stream_parent_class)->finalize (object);
301 : 1882 : }
302 : :
303 : : static void
304 : 106 : g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface)
305 : : {
306 : 106 : iface->tell = g_buffered_input_stream_tell;
307 : 106 : iface->can_seek = g_buffered_input_stream_can_seek;
308 : 106 : iface->seek = g_buffered_input_stream_seek;
309 : 106 : iface->can_truncate = g_buffered_input_stream_can_truncate;
310 : 106 : iface->truncate_fn = g_buffered_input_stream_truncate;
311 : 106 : }
312 : :
313 : : static void
314 : 1882 : g_buffered_input_stream_init (GBufferedInputStream *stream)
315 : : {
316 : 1882 : stream->priv = g_buffered_input_stream_get_instance_private (stream);
317 : 1882 : }
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 : 547561 : 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 : 547561 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
416 : :
417 : 547561 : input_stream = G_INPUT_STREAM (stream);
418 : :
419 : 547561 : 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 : 547561 : if (!g_input_stream_set_pending (input_stream, error))
427 : 0 : return -1;
428 : :
429 : 547561 : if (cancellable)
430 : 22 : g_cancellable_push_current (cancellable);
431 : :
432 : 547561 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
433 : 547561 : res = class->fill (stream, count, cancellable, error);
434 : :
435 : 547561 : if (cancellable)
436 : 22 : g_cancellable_pop_current (cancellable);
437 : :
438 : 547561 : g_input_stream_clear_pending (input_stream);
439 : :
440 : 547561 : 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 : 1088487 : g_buffered_input_stream_get_available (GBufferedInputStream *stream)
560 : : {
561 : 1088487 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
562 : :
563 : 1088487 : 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
571 : : * @offset: a #gsize
572 : : * @count: a #gsize
573 : : *
574 : : * Peeks in the buffer, copying data of size @count into @buffer,
575 : : * offset @offset bytes.
576 : : *
577 : : * Returns: a #gsize of the number of bytes peeked, or `-1` on error.
578 : : */
579 : : gsize
580 : 3 : g_buffered_input_stream_peek (GBufferedInputStream *stream,
581 : : void *buffer,
582 : : gsize offset,
583 : : gsize count)
584 : : {
585 : : gsize available;
586 : : gsize end;
587 : :
588 : 3 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
589 : 3 : g_return_val_if_fail (buffer != NULL, -1);
590 : :
591 : 3 : available = g_buffered_input_stream_get_available (stream);
592 : :
593 : 3 : if (offset > available)
594 : 1 : return 0;
595 : :
596 : 2 : end = MIN (offset + count, available);
597 : 2 : count = end - offset;
598 : :
599 : 2 : memcpy (buffer, stream->priv->buffer + stream->priv->pos + offset, count);
600 : 2 : return count;
601 : : }
602 : :
603 : : /**
604 : : * g_buffered_input_stream_peek_buffer:
605 : : * @stream: a [class@Gio.BufferedInputStream]
606 : : * @count: (out): a #gsize to get the number of bytes available in the buffer
607 : : *
608 : : * Returns the buffer with the currently available bytes. The returned
609 : : * buffer must not be modified and will become invalid when reading from
610 : : * the stream or filling the buffer.
611 : : *
612 : : * Returns: (array length=count) (element-type guint8) (transfer none):
613 : : * read-only buffer
614 : : */
615 : : const void*
616 : 30337 : g_buffered_input_stream_peek_buffer (GBufferedInputStream *stream,
617 : : gsize *count)
618 : : {
619 : : GBufferedInputStreamPrivate *priv;
620 : :
621 : 30337 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), NULL);
622 : :
623 : 30337 : priv = stream->priv;
624 : :
625 : 30337 : if (count)
626 : 30337 : *count = priv->end - priv->pos;
627 : :
628 : 30337 : return priv->buffer + priv->pos;
629 : : }
630 : :
631 : : static void
632 : 5323 : compact_buffer (GBufferedInputStream *stream)
633 : : {
634 : : GBufferedInputStreamPrivate *priv;
635 : : gsize current_size;
636 : :
637 : 5323 : priv = stream->priv;
638 : :
639 : 5323 : current_size = priv->end - priv->pos;
640 : :
641 : 5323 : memmove (priv->buffer, priv->buffer + priv->pos, current_size);
642 : :
643 : 5323 : priv->pos = 0;
644 : 5323 : priv->end = current_size;
645 : 5323 : }
646 : :
647 : : static gssize
648 : 547579 : g_buffered_input_stream_real_fill (GBufferedInputStream *stream,
649 : : gssize count,
650 : : GCancellable *cancellable,
651 : : GError **error)
652 : : {
653 : : GBufferedInputStreamPrivate *priv;
654 : : GInputStream *base_stream;
655 : : gssize nread;
656 : : gsize in_buffer;
657 : :
658 : 547579 : priv = stream->priv;
659 : :
660 : 547579 : if (count == -1)
661 : 6864 : count = priv->len;
662 : :
663 : 547579 : in_buffer = priv->end - priv->pos;
664 : :
665 : : /* Never fill more than can fit in the buffer */
666 : 547579 : count = MIN ((gsize) count, priv->len - in_buffer);
667 : :
668 : : /* If requested length does not fit at end, compact */
669 : 547579 : if (priv->len - priv->end < (gsize) count)
670 : 5299 : compact_buffer (stream);
671 : :
672 : 547579 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
673 : 547579 : nread = g_input_stream_read (base_stream,
674 : 547579 : priv->buffer + priv->end,
675 : : count,
676 : : cancellable,
677 : : error);
678 : :
679 : 547579 : if (nread > 0)
680 : 547507 : priv->end += nread;
681 : :
682 : 547579 : return nread;
683 : : }
684 : :
685 : : static gssize
686 : 117 : g_buffered_input_stream_skip (GInputStream *stream,
687 : : gsize count,
688 : : GCancellable *cancellable,
689 : : GError **error)
690 : : {
691 : : GBufferedInputStream *bstream;
692 : : GBufferedInputStreamPrivate *priv;
693 : : GBufferedInputStreamClass *class;
694 : : GInputStream *base_stream;
695 : : gsize available, bytes_skipped;
696 : : gssize nread;
697 : :
698 : 117 : bstream = G_BUFFERED_INPUT_STREAM (stream);
699 : 117 : priv = bstream->priv;
700 : :
701 : 117 : available = priv->end - priv->pos;
702 : :
703 : 117 : if (count <= available)
704 : : {
705 : 112 : priv->pos += count;
706 : 112 : return count;
707 : : }
708 : :
709 : : /* Full request not available, skip all currently available and
710 : : * request refill for more
711 : : */
712 : :
713 : 5 : priv->pos = 0;
714 : 5 : priv->end = 0;
715 : 5 : bytes_skipped = available;
716 : 5 : count -= available;
717 : :
718 : 5 : if (bytes_skipped > 0)
719 : 4 : error = NULL; /* Ignore further errors if we already read some data */
720 : :
721 : 5 : if (count > priv->len)
722 : : {
723 : : /* Large request, shortcut buffer */
724 : :
725 : 4 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
726 : :
727 : 4 : nread = g_input_stream_skip (base_stream,
728 : : count,
729 : : cancellable,
730 : : error);
731 : :
732 : 4 : if (nread < 0 && bytes_skipped == 0)
733 : 0 : return -1;
734 : :
735 : 4 : if (nread > 0)
736 : 3 : bytes_skipped += nread;
737 : :
738 : 4 : return bytes_skipped;
739 : : }
740 : :
741 : 1 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
742 : 1 : nread = class->fill (bstream, priv->len, cancellable, error);
743 : :
744 : 1 : if (nread < 0)
745 : : {
746 : 0 : if (bytes_skipped == 0)
747 : 0 : return -1;
748 : : else
749 : 0 : return bytes_skipped;
750 : : }
751 : :
752 : 1 : available = priv->end - priv->pos;
753 : 1 : count = MIN (count, available);
754 : :
755 : 1 : bytes_skipped += count;
756 : 1 : priv->pos += count;
757 : :
758 : 1 : return bytes_skipped;
759 : : }
760 : :
761 : : static gssize
762 : 564299 : g_buffered_input_stream_read (GInputStream *stream,
763 : : void *buffer,
764 : : gsize count,
765 : : GCancellable *cancellable,
766 : : GError **error)
767 : : {
768 : : GBufferedInputStream *bstream;
769 : : GBufferedInputStreamPrivate *priv;
770 : : GBufferedInputStreamClass *class;
771 : : GInputStream *base_stream;
772 : : gsize available, bytes_read;
773 : : gssize nread;
774 : :
775 : 564299 : bstream = G_BUFFERED_INPUT_STREAM (stream);
776 : 564299 : priv = bstream->priv;
777 : :
778 : 564299 : available = priv->end - priv->pos;
779 : :
780 : 564299 : if (count <= available)
781 : : {
782 : 564286 : memcpy (buffer, priv->buffer + priv->pos, count);
783 : 564286 : priv->pos += count;
784 : 564286 : return count;
785 : : }
786 : :
787 : : /* Full request not available, read all currently available and
788 : : * request refill for more
789 : : */
790 : :
791 : 13 : memcpy (buffer, priv->buffer + priv->pos, available);
792 : 13 : priv->pos = 0;
793 : 13 : priv->end = 0;
794 : 13 : bytes_read = available;
795 : 13 : count -= available;
796 : :
797 : 13 : if (bytes_read > 0)
798 : 3 : error = NULL; /* Ignore further errors if we already read some data */
799 : :
800 : 13 : if (count > priv->len)
801 : : {
802 : : /* Large request, shortcut buffer */
803 : :
804 : 11 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
805 : :
806 : 11 : nread = g_input_stream_read (base_stream,
807 : : (char *)buffer + bytes_read,
808 : : count,
809 : : cancellable,
810 : : error);
811 : :
812 : 11 : if (nread < 0 && bytes_read == 0)
813 : 0 : return -1;
814 : :
815 : 11 : if (nread > 0)
816 : 9 : bytes_read += nread;
817 : :
818 : 11 : return bytes_read;
819 : : }
820 : :
821 : 2 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
822 : 2 : nread = class->fill (bstream, priv->len, cancellable, error);
823 : 2 : if (nread < 0)
824 : : {
825 : 0 : if (bytes_read == 0)
826 : 0 : return -1;
827 : : else
828 : 0 : return bytes_read;
829 : : }
830 : :
831 : 2 : available = priv->end - priv->pos;
832 : 2 : count = MIN (count, available);
833 : :
834 : 2 : memcpy ((char *)buffer + bytes_read, (char *)priv->buffer + priv->pos, count);
835 : 2 : bytes_read += count;
836 : 2 : priv->pos += count;
837 : :
838 : 2 : return bytes_read;
839 : : }
840 : :
841 : : static goffset
842 : 14 : g_buffered_input_stream_tell (GSeekable *seekable)
843 : : {
844 : : GBufferedInputStream *bstream;
845 : : GBufferedInputStreamPrivate *priv;
846 : : GInputStream *base_stream;
847 : : GSeekable *base_stream_seekable;
848 : : gsize available;
849 : : goffset base_offset;
850 : :
851 : 14 : bstream = G_BUFFERED_INPUT_STREAM (seekable);
852 : 14 : priv = bstream->priv;
853 : :
854 : 14 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
855 : 14 : if (!G_IS_SEEKABLE (base_stream))
856 : 0 : return 0;
857 : 14 : base_stream_seekable = G_SEEKABLE (base_stream);
858 : :
859 : 14 : available = priv->end - priv->pos;
860 : 14 : base_offset = g_seekable_tell (base_stream_seekable);
861 : :
862 : 14 : return base_offset - available;
863 : : }
864 : :
865 : : static gboolean
866 : 0 : g_buffered_input_stream_can_seek (GSeekable *seekable)
867 : : {
868 : : GInputStream *base_stream;
869 : :
870 : 0 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
871 : 0 : return G_IS_SEEKABLE (base_stream) && g_seekable_can_seek (G_SEEKABLE (base_stream));
872 : : }
873 : :
874 : : static gboolean
875 : 6 : g_buffered_input_stream_seek (GSeekable *seekable,
876 : : goffset offset,
877 : : GSeekType type,
878 : : GCancellable *cancellable,
879 : : GError **error)
880 : : {
881 : : GBufferedInputStream *bstream;
882 : : GBufferedInputStreamPrivate *priv;
883 : : GInputStream *base_stream;
884 : : GSeekable *base_stream_seekable;
885 : :
886 : 6 : bstream = G_BUFFERED_INPUT_STREAM (seekable);
887 : 6 : priv = bstream->priv;
888 : :
889 : 6 : base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
890 : 6 : if (!G_IS_SEEKABLE (base_stream))
891 : : {
892 : 0 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
893 : : _("Seek not supported on base stream"));
894 : 0 : return FALSE;
895 : : }
896 : :
897 : 6 : base_stream_seekable = G_SEEKABLE (base_stream);
898 : :
899 : 6 : if (type == G_SEEK_CUR)
900 : : {
901 : 4 : if (offset <= (goffset) (priv->end - priv->pos) &&
902 : 3 : offset >= (goffset) -priv->pos)
903 : : {
904 : 2 : priv->pos += offset;
905 : 2 : return TRUE;
906 : : }
907 : : else
908 : : {
909 : 2 : offset -= priv->end - priv->pos;
910 : : }
911 : : }
912 : :
913 : 4 : if (g_seekable_seek (base_stream_seekable, offset, type, cancellable, error))
914 : : {
915 : 4 : priv->pos = 0;
916 : 4 : priv->end = 0;
917 : 4 : return TRUE;
918 : : }
919 : : else
920 : : {
921 : 0 : return FALSE;
922 : : }
923 : : }
924 : :
925 : : static gboolean
926 : 0 : g_buffered_input_stream_can_truncate (GSeekable *seekable)
927 : : {
928 : 0 : return FALSE;
929 : : }
930 : :
931 : : static gboolean
932 : 0 : g_buffered_input_stream_truncate (GSeekable *seekable,
933 : : goffset offset,
934 : : GCancellable *cancellable,
935 : : GError **error)
936 : : {
937 : 0 : g_set_error_literal (error,
938 : : G_IO_ERROR,
939 : : G_IO_ERROR_NOT_SUPPORTED,
940 : : _("Cannot truncate GBufferedInputStream"));
941 : 0 : return FALSE;
942 : : }
943 : :
944 : : /**
945 : : * g_buffered_input_stream_read_byte:
946 : : * @stream: a [class@Gio.BufferedInputStream]
947 : : * @cancellable: (nullable): optional [class@Gio.Cancellable] object, `NULL` to ignore
948 : : * @error: location to store the error occurring, or `NULL` to ignore
949 : : *
950 : : * Tries to read a single byte from the stream or the buffer. Will block
951 : : * during this read.
952 : : *
953 : : * On success, the byte read from the stream is returned. On end of stream
954 : : * `-1` is returned but it's not an exceptional error and @error is not set.
955 : : *
956 : : * If @cancellable is not `NULL`, then the operation can be cancelled by
957 : : * triggering the cancellable object from another thread. If the operation
958 : : * was cancelled, the error [error@Gio.IOErrorEnum.CANCELLED] will be returned.
959 : : * If an operation was partially finished when the operation was cancelled the
960 : : * partial result will be returned, without an error.
961 : : *
962 : : * On error `-1` is returned and @error is set accordingly.
963 : : *
964 : : * Returns: the byte read from the @stream, or `-1` on end of stream or error.
965 : : */
966 : : int
967 : 26 : g_buffered_input_stream_read_byte (GBufferedInputStream *stream,
968 : : GCancellable *cancellable,
969 : : GError **error)
970 : : {
971 : : GBufferedInputStreamPrivate *priv;
972 : : GBufferedInputStreamClass *class;
973 : : GInputStream *input_stream;
974 : : gsize available;
975 : : gssize nread;
976 : :
977 : 26 : g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
978 : :
979 : 26 : priv = stream->priv;
980 : 26 : input_stream = G_INPUT_STREAM (stream);
981 : :
982 : 26 : if (g_input_stream_is_closed (input_stream))
983 : : {
984 : 1 : g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
985 : : _("Stream is already closed"));
986 : 1 : return -1;
987 : : }
988 : :
989 : 25 : if (!g_input_stream_set_pending (input_stream, error))
990 : 0 : return -1;
991 : :
992 : 25 : available = priv->end - priv->pos;
993 : :
994 : 25 : if (available != 0)
995 : : {
996 : 10 : g_input_stream_clear_pending (input_stream);
997 : 10 : return priv->buffer[priv->pos++];
998 : : }
999 : :
1000 : : /* Byte not available, request refill for more */
1001 : :
1002 : 15 : if (cancellable)
1003 : 0 : g_cancellable_push_current (cancellable);
1004 : :
1005 : 15 : priv->pos = 0;
1006 : 15 : priv->end = 0;
1007 : :
1008 : 15 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1009 : 15 : nread = class->fill (stream, priv->len, cancellable, error);
1010 : :
1011 : 15 : if (cancellable)
1012 : 0 : g_cancellable_pop_current (cancellable);
1013 : :
1014 : 15 : g_input_stream_clear_pending (input_stream);
1015 : :
1016 : 15 : if (nread <= 0)
1017 : 1 : return -1; /* error or end of stream */
1018 : :
1019 : 14 : return priv->buffer[priv->pos++];
1020 : : }
1021 : :
1022 : : /* ************************** */
1023 : : /* Async stuff implementation */
1024 : : /* ************************** */
1025 : :
1026 : : static void
1027 : 32 : fill_async_callback (GObject *source_object,
1028 : : GAsyncResult *result,
1029 : : gpointer user_data)
1030 : : {
1031 : : GError *error;
1032 : : gssize res;
1033 : 32 : GTask *task = user_data;
1034 : :
1035 : 32 : error = NULL;
1036 : 32 : res = g_input_stream_read_finish (G_INPUT_STREAM (source_object),
1037 : : result, &error);
1038 : 32 : if (res == -1)
1039 : 0 : g_task_return_error (task, error);
1040 : : else
1041 : : {
1042 : : GBufferedInputStream *stream;
1043 : : GBufferedInputStreamPrivate *priv;
1044 : :
1045 : 32 : stream = g_task_get_source_object (task);
1046 : 32 : priv = G_BUFFERED_INPUT_STREAM (stream)->priv;
1047 : :
1048 : 32 : g_assert_cmpint (priv->end + res, <=, priv->len);
1049 : 32 : priv->end += res;
1050 : :
1051 : 32 : g_task_return_int (task, res);
1052 : : }
1053 : :
1054 : 32 : g_object_unref (task);
1055 : 32 : }
1056 : :
1057 : : static void
1058 : 32 : g_buffered_input_stream_real_fill_async (GBufferedInputStream *stream,
1059 : : gssize count,
1060 : : int io_priority,
1061 : : GCancellable *cancellable,
1062 : : GAsyncReadyCallback callback,
1063 : : gpointer user_data)
1064 : : {
1065 : : GBufferedInputStreamPrivate *priv;
1066 : : GInputStream *base_stream;
1067 : : GTask *task;
1068 : : gsize in_buffer;
1069 : :
1070 : 32 : priv = stream->priv;
1071 : :
1072 : 32 : if (count == -1)
1073 : 27 : count = priv->len;
1074 : :
1075 : 32 : in_buffer = priv->end - priv->pos;
1076 : :
1077 : : /* Never fill more than can fit in the buffer */
1078 : 32 : count = MIN ((gsize) count, priv->len - in_buffer);
1079 : :
1080 : : /* If requested length does not fit at end, compact */
1081 : 32 : if (priv->len - priv->end < (gsize) count)
1082 : 24 : compact_buffer (stream);
1083 : :
1084 : 32 : task = g_task_new (stream, cancellable, callback, user_data);
1085 : 32 : g_task_set_source_tag (task, g_buffered_input_stream_real_fill_async);
1086 : :
1087 : 32 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
1088 : 32 : g_input_stream_read_async (base_stream,
1089 : 32 : priv->buffer + priv->end,
1090 : : count,
1091 : : io_priority,
1092 : : cancellable,
1093 : : fill_async_callback,
1094 : : task);
1095 : 32 : }
1096 : :
1097 : : static gssize
1098 : 32 : g_buffered_input_stream_real_fill_finish (GBufferedInputStream *stream,
1099 : : GAsyncResult *result,
1100 : : GError **error)
1101 : : {
1102 : 32 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1103 : :
1104 : 32 : return g_task_propagate_int (G_TASK (result), error);
1105 : : }
1106 : :
1107 : : typedef struct
1108 : : {
1109 : : gsize bytes_skipped;
1110 : : gsize count;
1111 : : } SkipAsyncData;
1112 : :
1113 : : static void
1114 : 9 : free_skip_async_data (gpointer _data)
1115 : : {
1116 : 9 : SkipAsyncData *data = _data;
1117 : 9 : g_slice_free (SkipAsyncData, data);
1118 : 9 : }
1119 : :
1120 : : static void
1121 : 5 : large_skip_callback (GObject *source_object,
1122 : : GAsyncResult *result,
1123 : : gpointer user_data)
1124 : : {
1125 : 5 : GTask *task = G_TASK (user_data);
1126 : : SkipAsyncData *data;
1127 : : GError *error;
1128 : : gssize nread;
1129 : :
1130 : 5 : data = g_task_get_task_data (task);
1131 : :
1132 : 5 : error = NULL;
1133 : 5 : nread = g_input_stream_skip_finish (G_INPUT_STREAM (source_object),
1134 : : result, &error);
1135 : :
1136 : : /* Only report the error if we've not already read some data */
1137 : 5 : if (nread < 0 && data->bytes_skipped == 0)
1138 : 0 : g_task_return_error (task, error);
1139 : : else
1140 : : {
1141 : 5 : if (error)
1142 : 0 : g_error_free (error);
1143 : :
1144 : 5 : if (nread > 0)
1145 : 4 : data->bytes_skipped += nread;
1146 : :
1147 : 5 : g_task_return_int (task, data->bytes_skipped);
1148 : : }
1149 : :
1150 : 5 : g_object_unref (task);
1151 : 5 : }
1152 : :
1153 : : static void
1154 : 4 : skip_fill_buffer_callback (GObject *source_object,
1155 : : GAsyncResult *result,
1156 : : gpointer user_data)
1157 : : {
1158 : 4 : GTask *task = G_TASK (user_data);
1159 : : GBufferedInputStream *bstream;
1160 : : GBufferedInputStreamPrivate *priv;
1161 : : SkipAsyncData *data;
1162 : : GError *error;
1163 : : gssize nread;
1164 : : gsize available;
1165 : :
1166 : 4 : bstream = G_BUFFERED_INPUT_STREAM (source_object);
1167 : 4 : priv = bstream->priv;
1168 : :
1169 : 4 : data = g_task_get_task_data (task);
1170 : :
1171 : 4 : error = NULL;
1172 : 4 : nread = g_buffered_input_stream_fill_finish (bstream,
1173 : : result, &error);
1174 : :
1175 : 4 : if (nread < 0 && data->bytes_skipped == 0)
1176 : 0 : g_task_return_error (task, error);
1177 : : else
1178 : : {
1179 : 4 : if (error)
1180 : 0 : g_error_free (error);
1181 : :
1182 : 4 : if (nread > 0)
1183 : : {
1184 : 4 : available = priv->end - priv->pos;
1185 : 4 : data->count = MIN (data->count, available);
1186 : :
1187 : 4 : data->bytes_skipped += data->count;
1188 : 4 : priv->pos += data->count;
1189 : : }
1190 : :
1191 : 4 : g_assert (data->bytes_skipped <= G_MAXSSIZE);
1192 : 4 : g_task_return_int (task, data->bytes_skipped);
1193 : : }
1194 : :
1195 : 4 : g_object_unref (task);
1196 : 4 : }
1197 : :
1198 : : static void
1199 : 9 : g_buffered_input_stream_skip_async (GInputStream *stream,
1200 : : gsize count,
1201 : : int io_priority,
1202 : : GCancellable *cancellable,
1203 : : GAsyncReadyCallback callback,
1204 : : gpointer user_data)
1205 : : {
1206 : : GBufferedInputStream *bstream;
1207 : : GBufferedInputStreamPrivate *priv;
1208 : : GBufferedInputStreamClass *class;
1209 : : GInputStream *base_stream;
1210 : : gsize available;
1211 : : GTask *task;
1212 : : SkipAsyncData *data;
1213 : :
1214 : 9 : bstream = G_BUFFERED_INPUT_STREAM (stream);
1215 : 9 : priv = bstream->priv;
1216 : :
1217 : 9 : data = g_slice_new (SkipAsyncData);
1218 : 9 : data->bytes_skipped = 0;
1219 : 9 : task = g_task_new (stream, cancellable, callback, user_data);
1220 : 9 : g_task_set_source_tag (task, g_buffered_input_stream_skip_async);
1221 : 9 : g_task_set_task_data (task, data, free_skip_async_data);
1222 : :
1223 : 9 : available = priv->end - priv->pos;
1224 : :
1225 : 9 : if (count <= available)
1226 : : {
1227 : 0 : priv->pos += count;
1228 : :
1229 : 0 : g_task_return_int (task, count);
1230 : 0 : g_object_unref (task);
1231 : 0 : return;
1232 : : }
1233 : :
1234 : : /* Full request not available, skip all currently available
1235 : : * and request refill for more
1236 : : */
1237 : :
1238 : 9 : priv->pos = 0;
1239 : 9 : priv->end = 0;
1240 : :
1241 : 9 : count -= available;
1242 : :
1243 : 9 : data->bytes_skipped = available;
1244 : 9 : data->count = count;
1245 : :
1246 : 9 : if (count > priv->len)
1247 : : {
1248 : : /* Large request, shortcut buffer */
1249 : 5 : base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
1250 : :
1251 : : /* If 'count > G_MAXSSIZE then 'g_input_stream_skip_async()'
1252 : : * will return an error anyway before calling this.
1253 : : * Assert that this is never called for too big `count` for clarity. */
1254 : 5 : g_assert ((gssize) count >= 0);
1255 : 5 : g_input_stream_skip_async (base_stream,
1256 : : count,
1257 : : io_priority, cancellable,
1258 : : large_skip_callback,
1259 : : task);
1260 : : }
1261 : : else
1262 : : {
1263 : 4 : class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1264 : 4 : class->fill_async (bstream, priv->len, io_priority, cancellable,
1265 : : skip_fill_buffer_callback, task);
1266 : : }
1267 : : }
1268 : :
1269 : : static gssize
1270 : 9 : g_buffered_input_stream_skip_finish (GInputStream *stream,
1271 : : GAsyncResult *result,
1272 : : GError **error)
1273 : : {
1274 : 9 : g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1275 : :
1276 : 9 : return g_task_propagate_int (G_TASK (result), error);
1277 : : }
|