Coverage Report

Created: 2026-06-14 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/gio/gbufferedinputstream.c
Line
Count
Source
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
3
#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
61.4k
G_DEFINE_TYPE_WITH_CODE (GBufferedInputStream,
131
61.4k
       g_buffered_input_stream,
132
61.4k
       G_TYPE_FILTER_INPUT_STREAM,
133
61.4k
                         G_ADD_PRIVATE (GBufferedInputStream)
134
61.4k
       G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
135
61.4k
            g_buffered_input_stream_seekable_iface_init))
136
61.4k
137
61.4k
static void
138
61.4k
g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
139
61.4k
{
140
3
  GObjectClass *object_class;
141
3
  GInputStreamClass *istream_class;
142
3
  GBufferedInputStreamClass *bstream_class;
143
144
3
  object_class = G_OBJECT_CLASS (klass);
145
3
  object_class->get_property = g_buffered_input_stream_get_property;
146
3
  object_class->set_property = g_buffered_input_stream_set_property;
147
3
  object_class->finalize     = g_buffered_input_stream_finalize;
148
149
3
  istream_class = G_INPUT_STREAM_CLASS (klass);
150
3
  istream_class->skip = g_buffered_input_stream_skip;
151
3
  istream_class->skip_async  = g_buffered_input_stream_skip_async;
152
3
  istream_class->skip_finish = g_buffered_input_stream_skip_finish;
153
3
  istream_class->read_fn = g_buffered_input_stream_read;
154
155
3
  bstream_class = G_BUFFERED_INPUT_STREAM_CLASS (klass);
156
3
  bstream_class->fill = g_buffered_input_stream_real_fill;
157
3
  bstream_class->fill_async = g_buffered_input_stream_real_fill_async;
158
3
  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
3
  g_object_class_install_property (object_class,
166
3
                                   PROP_BUFSIZE,
167
3
                                   g_param_spec_uint ("buffer-size", NULL, NULL,
168
3
                                                      1,
169
3
                                                      G_MAXUINT,
170
3
                                                      DEFAULT_BUFFER_SIZE,
171
3
                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
172
3
                                                      G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
173
174
175
3
}
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
g_buffered_input_stream_get_buffer_size (GBufferedInputStream  *stream)
187
5.37k
{
188
5.37k
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
189
190
5.37k
  return stream->priv->len;
191
5.37k
}
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
g_buffered_input_stream_set_buffer_size (GBufferedInputStream *stream,
204
                                         gsize                 size)
205
2.82k
{
206
2.82k
  GBufferedInputStreamPrivate *priv;
207
2.82k
  gsize in_buffer;
208
2.82k
  guint8 *buffer;
209
210
2.82k
  g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
211
212
2.82k
  priv = stream->priv;
213
214
2.82k
  if (priv->len == size)
215
0
    return;
216
217
2.82k
  if (priv->buffer)
218
1.67k
    {
219
1.67k
      in_buffer = priv->end - priv->pos;
220
221
      /* Never resize smaller than current buffer contents */
222
1.67k
      size = MAX (size, in_buffer);
223
224
1.67k
      buffer = g_malloc (size);
225
1.67k
      memcpy (buffer, priv->buffer + priv->pos, in_buffer);
226
1.67k
      priv->len = size;
227
1.67k
      priv->pos = 0;
228
1.67k
      priv->end = in_buffer;
229
1.67k
      g_free (priv->buffer);
230
1.67k
      priv->buffer = buffer;
231
1.67k
    }
232
1.14k
  else
233
1.14k
    {
234
1.14k
      priv->len = size;
235
1.14k
      priv->pos = 0;
236
1.14k
      priv->end = 0;
237
1.14k
      priv->buffer = g_malloc (size);
238
1.14k
    }
239
240
2.82k
  g_object_notify (G_OBJECT (stream), "buffer-size");
241
2.82k
}
242
243
static void
244
g_buffered_input_stream_set_property (GObject      *object,
245
                                      guint         prop_id,
246
                                      const GValue *value,
247
                                      GParamSpec   *pspec)
248
1.14k
{
249
1.14k
  GBufferedInputStream        *bstream;
250
251
1.14k
  bstream = G_BUFFERED_INPUT_STREAM (object);
252
253
1.14k
  switch (prop_id)
254
1.14k
    {
255
1.14k
    case PROP_BUFSIZE:
256
1.14k
      g_buffered_input_stream_set_buffer_size (bstream, g_value_get_uint (value));
257
1.14k
      break;
258
259
0
    default:
260
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261
0
      break;
262
1.14k
    }
263
1.14k
}
264
265
static void
266
g_buffered_input_stream_get_property (GObject    *object,
267
                                      guint       prop_id,
268
                                      GValue     *value,
269
                                      GParamSpec *pspec)
270
0
{
271
0
  GBufferedInputStreamPrivate *priv;
272
0
  GBufferedInputStream        *bstream;
273
274
0
  bstream = G_BUFFERED_INPUT_STREAM (object);
275
0
  priv = bstream->priv;
276
277
0
  switch (prop_id)
278
0
    {
279
0
    case PROP_BUFSIZE:
280
0
      g_value_set_uint (value, priv->len);
281
0
      break;
282
283
0
    default:
284
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285
0
      break;
286
0
    }
287
0
}
288
289
static void
290
g_buffered_input_stream_finalize (GObject *object)
291
1.14k
{
292
1.14k
  GBufferedInputStreamPrivate *priv;
293
1.14k
  GBufferedInputStream        *stream;
294
295
1.14k
  stream = G_BUFFERED_INPUT_STREAM (object);
296
1.14k
  priv = stream->priv;
297
298
1.14k
  g_free (priv->buffer);
299
300
1.14k
  G_OBJECT_CLASS (g_buffered_input_stream_parent_class)->finalize (object);
301
1.14k
}
302
303
static void
304
g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface)
305
3
{
306
3
  iface->tell         = g_buffered_input_stream_tell;
307
3
  iface->can_seek     = g_buffered_input_stream_can_seek;
308
3
  iface->seek         = g_buffered_input_stream_seek;
309
3
  iface->can_truncate = g_buffered_input_stream_can_truncate;
310
3
  iface->truncate_fn  = g_buffered_input_stream_truncate;
311
3
}
312
313
static void
314
g_buffered_input_stream_init (GBufferedInputStream *stream)
315
1.14k
{
316
1.14k
  stream->priv = g_buffered_input_stream_get_instance_private (stream);
317
1.14k
}
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
g_buffered_input_stream_new (GInputStream *base_stream)
331
0
{
332
0
  GInputStream *stream;
333
334
0
  g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
335
336
0
  stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
337
0
                         "base-stream", base_stream,
338
0
                         NULL);
339
340
0
  return stream;
341
0
}
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
g_buffered_input_stream_new_sized (GInputStream *base_stream,
355
                                   gsize         size)
356
0
{
357
0
  GInputStream *stream;
358
359
0
  g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
360
361
0
  stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
362
0
                         "base-stream", base_stream,
363
0
                         "buffer-size", (guint)size,
364
0
                         NULL);
365
366
0
  return stream;
367
0
}
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
g_buffered_input_stream_fill (GBufferedInputStream  *stream,
407
                              gssize                 count,
408
                              GCancellable          *cancellable,
409
                              GError               **error)
410
3.70k
{
411
3.70k
  GBufferedInputStreamClass *class;
412
3.70k
  GInputStream *input_stream;
413
3.70k
  gssize res;
414
415
3.70k
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
416
417
3.70k
  input_stream = G_INPUT_STREAM (stream);
418
419
3.70k
  if (count < -1)
420
0
    {
421
0
      g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
422
0
                   _("Too large count value passed to %s"), G_STRFUNC);
423
0
      return -1;
424
0
    }
425
426
3.70k
  if (!g_input_stream_set_pending (input_stream, error))
427
0
    return -1;
428
429
3.70k
  if (cancellable)
430
0
    g_cancellable_push_current (cancellable);
431
432
3.70k
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
433
3.70k
  res = class->fill (stream, count, cancellable, error);
434
435
3.70k
  if (cancellable)
436
0
    g_cancellable_pop_current (cancellable);
437
438
3.70k
  g_input_stream_clear_pending (input_stream);
439
440
3.70k
  return res;
441
3.70k
}
442
443
static void
444
async_fill_callback_wrapper (GObject      *source_object,
445
                             GAsyncResult *res,
446
                             gpointer      user_data)
447
0
{
448
0
  GBufferedInputStream *stream = G_BUFFERED_INPUT_STREAM (source_object);
449
450
0
  g_input_stream_clear_pending (G_INPUT_STREAM (stream));
451
0
  (*stream->priv->outstanding_callback) (source_object, res, user_data);
452
0
  g_object_unref (stream);
453
0
}
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
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
0
{
479
0
  GBufferedInputStreamClass *class;
480
0
  GError *error = NULL;
481
482
0
  g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
483
484
0
  if (count == 0)
485
0
    {
486
0
      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
0
    }
494
495
0
  if (count < -1)
496
0
    {
497
0
      g_task_report_new_error (stream, callback, user_data,
498
0
                               g_buffered_input_stream_fill_async,
499
0
                               G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
500
0
             _("Too large count value passed to %s"),
501
0
             G_STRFUNC);
502
0
      return;
503
0
    }
504
505
0
  if (!g_input_stream_set_pending (G_INPUT_STREAM (stream), &error))
506
0
    {
507
0
      g_task_report_error (stream, callback, user_data,
508
0
                           g_buffered_input_stream_fill_async,
509
0
                           error);
510
0
      return;
511
0
    }
512
513
0
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
514
515
0
  stream->priv->outstanding_callback = callback;
516
0
  g_object_ref (stream);
517
0
  class->fill_async (stream, count, io_priority, cancellable,
518
0
                     async_fill_callback_wrapper, user_data);
519
0
}
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
g_buffered_input_stream_fill_finish (GBufferedInputStream  *stream,
533
                                     GAsyncResult          *result,
534
                                     GError               **error)
535
0
{
536
0
  GBufferedInputStreamClass *class;
537
538
0
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
539
0
  g_return_val_if_fail (G_IS_ASYNC_RESULT (result), -1);
540
541
0
  if (g_async_result_legacy_propagate_error (result, error))
542
0
    return -1;
543
0
  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
0
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
547
0
  return class->fill_finish (stream, result, error);
548
0
}
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
g_buffered_input_stream_get_available (GBufferedInputStream *stream)
560
4.72k
{
561
4.72k
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
562
563
4.72k
  return stream->priv->end - stream->priv->pos;
564
4.72k
}
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
g_buffered_input_stream_peek (GBufferedInputStream *stream,
582
                              void                 *buffer,
583
                              gsize                 offset,
584
                              gsize                 count)
585
0
{
586
0
  gsize available;
587
0
  gsize end;
588
589
0
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
590
0
  g_return_val_if_fail (buffer != NULL, 0);
591
592
0
  available = g_buffered_input_stream_get_available (stream);
593
594
0
  if (offset > available || offset > G_MAXSIZE - count)
595
0
    return 0;
596
597
0
  end = MIN (offset + count, available);
598
0
  count = end - offset;
599
600
0
  memcpy (buffer, stream->priv->buffer + stream->priv->pos + offset, count);
601
0
  return count;
602
0
}
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
g_buffered_input_stream_peek_buffer (GBufferedInputStream *stream,
618
                                     gsize                *count)
619
3.84k
{
620
3.84k
  GBufferedInputStreamPrivate *priv;
621
622
3.84k
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), NULL);
623
624
3.84k
  priv = stream->priv;
625
626
3.84k
  if (count)
627
3.84k
    *count = priv->end - priv->pos;
628
629
3.84k
  return priv->buffer + priv->pos;
630
3.84k
}
631
632
static void
633
compact_buffer (GBufferedInputStream *stream)
634
0
{
635
0
  GBufferedInputStreamPrivate *priv;
636
0
  gsize current_size;
637
638
0
  priv = stream->priv;
639
640
0
  current_size = priv->end - priv->pos;
641
642
0
  memmove (priv->buffer, priv->buffer + priv->pos, current_size);
643
644
0
  priv->pos = 0;
645
0
  priv->end = current_size;
646
0
}
647
648
static gssize
649
g_buffered_input_stream_real_fill (GBufferedInputStream  *stream,
650
                                   gssize                 count,
651
                                   GCancellable          *cancellable,
652
                                   GError               **error)
653
3.70k
{
654
3.70k
  GBufferedInputStreamPrivate *priv;
655
3.70k
  GInputStream *base_stream;
656
3.70k
  gssize nread;
657
3.70k
  gsize in_buffer;
658
659
3.70k
  priv = stream->priv;
660
661
3.70k
  if (count == -1)
662
3.70k
    count = priv->len;
663
664
3.70k
  in_buffer = priv->end - priv->pos;
665
666
  /* Never fill more than can fit in the buffer */
667
3.70k
  count = MIN ((gsize) count, priv->len - in_buffer);
668
669
  /* If requested length does not fit at end, compact */
670
3.70k
  if (priv->len - priv->end < (gsize) count)
671
0
    compact_buffer (stream);
672
673
3.70k
  base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
674
3.70k
  nread = g_input_stream_read (base_stream,
675
3.70k
                               priv->buffer + priv->end,
676
3.70k
                               count,
677
3.70k
                               cancellable,
678
3.70k
                               error);
679
680
3.70k
  if (nread > 0)
681
2.69k
    priv->end += nread;
682
683
3.70k
  return nread;
684
3.70k
}
685
686
static gssize
687
g_buffered_input_stream_skip (GInputStream  *stream,
688
                              gsize          count,
689
                              GCancellable  *cancellable,
690
                              GError       **error)
691
0
{
692
0
  GBufferedInputStream        *bstream;
693
0
  GBufferedInputStreamPrivate *priv;
694
0
  GBufferedInputStreamClass *class;
695
0
  GInputStream *base_stream;
696
0
  gsize available, bytes_skipped;
697
0
  gssize nread;
698
699
0
  bstream = G_BUFFERED_INPUT_STREAM (stream);
700
0
  priv = bstream->priv;
701
702
0
  available = priv->end - priv->pos;
703
704
0
  if (count <= available)
705
0
    {
706
0
      priv->pos += count;
707
0
      return count;
708
0
    }
709
710
  /* Full request not available, skip all currently available and
711
   * request refill for more
712
   */
713
714
0
  priv->pos = 0;
715
0
  priv->end = 0;
716
0
  bytes_skipped = available;
717
0
  count -= available;
718
719
0
  if (bytes_skipped > 0)
720
0
    error = NULL; /* Ignore further errors if we already read some data */
721
722
0
  if (count > priv->len)
723
0
    {
724
      /* Large request, shortcut buffer */
725
726
0
      base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
727
728
0
      nread = g_input_stream_skip (base_stream,
729
0
                                   count,
730
0
                                   cancellable,
731
0
                                   error);
732
733
0
      if (nread < 0 && bytes_skipped == 0)
734
0
        return -1;
735
736
0
      if (nread > 0)
737
0
        bytes_skipped += nread;
738
739
0
      return bytes_skipped;
740
0
    }
741
742
0
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
743
0
  nread = class->fill (bstream, priv->len, cancellable, error);
744
745
0
  if (nread < 0)
746
0
    {
747
0
      if (bytes_skipped == 0)
748
0
        return -1;
749
0
      else
750
0
        return bytes_skipped;
751
0
    }
752
753
0
  available = priv->end - priv->pos;
754
0
  count = MIN (count, available);
755
756
0
  bytes_skipped += count;
757
0
  priv->pos += count;
758
759
0
  return bytes_skipped;
760
0
}
761
762
static gssize
763
g_buffered_input_stream_read (GInputStream *stream,
764
                              void         *buffer,
765
                              gsize         count,
766
                              GCancellable *cancellable,
767
                              GError      **error)
768
1.08k
{
769
1.08k
  GBufferedInputStream        *bstream;
770
1.08k
  GBufferedInputStreamPrivate *priv;
771
1.08k
  GBufferedInputStreamClass *class;
772
1.08k
  GInputStream *base_stream;
773
1.08k
  gsize available, bytes_read;
774
1.08k
  gssize nread;
775
776
1.08k
  bstream = G_BUFFERED_INPUT_STREAM (stream);
777
1.08k
  priv = bstream->priv;
778
779
1.08k
  available = priv->end - priv->pos;
780
781
1.08k
  if (count <= available)
782
1.08k
    {
783
1.08k
      memcpy (buffer, priv->buffer + priv->pos, count);
784
1.08k
      priv->pos += count;
785
1.08k
      return count;
786
1.08k
    }
787
788
  /* Full request not available, read all currently available and
789
   * request refill for more
790
   */
791
792
0
  memcpy (buffer, priv->buffer + priv->pos, available);
793
0
  priv->pos = 0;
794
0
  priv->end = 0;
795
0
  bytes_read = available;
796
0
  count -= available;
797
798
0
  if (bytes_read > 0)
799
0
    error = NULL; /* Ignore further errors if we already read some data */
800
801
0
  if (count > priv->len)
802
0
    {
803
      /* Large request, shortcut buffer */
804
805
0
      base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
806
807
0
      nread = g_input_stream_read (base_stream,
808
0
                                   (char *)buffer + bytes_read,
809
0
                                   count,
810
0
                                   cancellable,
811
0
                                   error);
812
813
0
      if (nread < 0 && bytes_read == 0)
814
0
        return -1;
815
816
0
      if (nread > 0)
817
0
        bytes_read += nread;
818
819
0
      return bytes_read;
820
0
    }
821
822
0
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
823
0
  nread = class->fill (bstream, priv->len, cancellable, error);
824
0
  if (nread < 0)
825
0
    {
826
0
      if (bytes_read == 0)
827
0
        return -1;
828
0
      else
829
0
        return bytes_read;
830
0
    }
831
832
0
  available = priv->end - priv->pos;
833
0
  count = MIN (count, available);
834
835
0
  memcpy ((char *)buffer + bytes_read, (char *)priv->buffer + priv->pos, count);
836
0
  bytes_read += count;
837
0
  priv->pos += count;
838
839
0
  return bytes_read;
840
0
}
841
842
static goffset
843
g_buffered_input_stream_tell (GSeekable *seekable)
844
0
{
845
0
  GBufferedInputStream        *bstream;
846
0
  GBufferedInputStreamPrivate *priv;
847
0
  GInputStream *base_stream;
848
0
  GSeekable    *base_stream_seekable;
849
0
  gsize available;
850
0
  goffset base_offset;
851
  
852
0
  bstream = G_BUFFERED_INPUT_STREAM (seekable);
853
0
  priv = bstream->priv;
854
855
0
  base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
856
0
  if (!G_IS_SEEKABLE (base_stream))
857
0
    return 0;
858
0
  base_stream_seekable = G_SEEKABLE (base_stream);
859
  
860
0
  available = priv->end - priv->pos;
861
0
  base_offset = g_seekable_tell (base_stream_seekable);
862
863
0
  return base_offset - available;
864
0
}
865
866
static gboolean
867
g_buffered_input_stream_can_seek (GSeekable *seekable)
868
0
{
869
0
  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
0
}
874
875
static gboolean
876
g_buffered_input_stream_seek (GSeekable     *seekable,
877
            goffset        offset,
878
            GSeekType      type,
879
            GCancellable  *cancellable,
880
            GError       **error)
881
0
{
882
0
  GBufferedInputStream        *bstream;
883
0
  GBufferedInputStreamPrivate *priv;
884
0
  GInputStream *base_stream;
885
0
  GSeekable *base_stream_seekable;
886
887
0
  bstream = G_BUFFERED_INPUT_STREAM (seekable);
888
0
  priv = bstream->priv;
889
890
0
  base_stream = G_FILTER_INPUT_STREAM (seekable)->base_stream;
891
0
  if (!G_IS_SEEKABLE (base_stream))
892
0
    {
893
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
894
0
                           _("Seek not supported on base stream"));
895
0
      return FALSE;
896
0
    }
897
898
0
  base_stream_seekable = G_SEEKABLE (base_stream);
899
  
900
0
  if (type == G_SEEK_CUR)
901
0
    {
902
0
      if (offset <= (goffset) (priv->end - priv->pos) &&
903
0
          offset >= (goffset) -priv->pos)
904
0
  {
905
0
    priv->pos += offset;
906
0
    return TRUE;
907
0
  }
908
0
      else
909
0
  {
910
0
    offset -= priv->end - priv->pos;
911
0
  }
912
0
    }
913
914
0
  if (g_seekable_seek (base_stream_seekable, offset, type, cancellable, error))
915
0
    {
916
0
      priv->pos = 0;
917
0
      priv->end = 0;
918
0
      return TRUE;
919
0
    }
920
0
  else
921
0
    {
922
0
      return FALSE;
923
0
    }
924
0
}
925
926
static gboolean
927
g_buffered_input_stream_can_truncate (GSeekable *seekable)
928
0
{
929
0
  return FALSE;
930
0
}
931
932
static gboolean
933
g_buffered_input_stream_truncate (GSeekable     *seekable,
934
          goffset        offset,
935
          GCancellable  *cancellable,
936
          GError       **error)
937
0
{
938
0
  g_set_error_literal (error,
939
0
           G_IO_ERROR,
940
0
           G_IO_ERROR_NOT_SUPPORTED,
941
0
           _("Cannot truncate GBufferedInputStream"));
942
0
  return FALSE;
943
0
}
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
g_buffered_input_stream_read_byte (GBufferedInputStream  *stream,
969
                                   GCancellable          *cancellable,
970
                                   GError               **error)
971
0
{
972
0
  GBufferedInputStreamPrivate *priv;
973
0
  GBufferedInputStreamClass *class;
974
0
  GInputStream *input_stream;
975
0
  gsize available;
976
0
  gssize nread;
977
978
0
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), -1);
979
980
0
  priv = stream->priv;
981
0
  input_stream = G_INPUT_STREAM (stream);
982
983
0
  if (g_input_stream_is_closed (input_stream))
984
0
    {
985
0
      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
986
0
                           _("Stream is already closed"));
987
0
      return -1;
988
0
    }
989
990
0
  if (!g_input_stream_set_pending (input_stream, error))
991
0
    return -1;
992
993
0
  available = priv->end - priv->pos;
994
995
0
  if (available != 0)
996
0
    {
997
0
      g_input_stream_clear_pending (input_stream);
998
0
      return priv->buffer[priv->pos++];
999
0
    }
1000
1001
  /* Byte not available, request refill for more */
1002
1003
0
  if (cancellable)
1004
0
    g_cancellable_push_current (cancellable);
1005
1006
0
  priv->pos = 0;
1007
0
  priv->end = 0;
1008
1009
0
  class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1010
0
  nread = class->fill (stream, priv->len, cancellable, error);
1011
1012
0
  if (cancellable)
1013
0
    g_cancellable_pop_current (cancellable);
1014
1015
0
  g_input_stream_clear_pending (input_stream);
1016
1017
0
  if (nread <= 0)
1018
0
    return -1; /* error or end of stream */
1019
1020
0
  return priv->buffer[priv->pos++];
1021
0
}
1022
1023
/* ************************** */
1024
/* Async stuff implementation */
1025
/* ************************** */
1026
1027
static void
1028
fill_async_callback (GObject      *source_object,
1029
                     GAsyncResult *result,
1030
                     gpointer      user_data)
1031
0
{
1032
0
  GError *error;
1033
0
  gssize res;
1034
0
  GTask *task = user_data;
1035
1036
0
  error = NULL;
1037
0
  res = g_input_stream_read_finish (G_INPUT_STREAM (source_object),
1038
0
                                    result, &error);
1039
0
  if (res == -1)
1040
0
    g_task_return_error (task, error);
1041
0
  else
1042
0
    {
1043
0
      GBufferedInputStream *stream;
1044
0
      GBufferedInputStreamPrivate *priv;
1045
1046
0
      stream = g_task_get_source_object (task);
1047
0
      priv = G_BUFFERED_INPUT_STREAM (stream)->priv;
1048
1049
0
      g_assert (priv->end + res <= priv->len);
1050
0
      priv->end += res;
1051
1052
0
      g_task_return_int (task, res);
1053
0
    }
1054
1055
0
  g_object_unref (task);
1056
0
}
1057
1058
static void
1059
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
0
{
1066
0
  GBufferedInputStreamPrivate *priv;
1067
0
  GInputStream *base_stream;
1068
0
  GTask *task;
1069
0
  gsize in_buffer;
1070
1071
0
  priv = stream->priv;
1072
1073
0
  if (count == -1)
1074
0
    count = priv->len;
1075
1076
0
  in_buffer = priv->end - priv->pos;
1077
1078
  /* Never fill more than can fit in the buffer */
1079
0
  count = MIN ((gsize) count, priv->len - in_buffer);
1080
1081
  /* If requested length does not fit at end, compact */
1082
0
  if (priv->len - priv->end < (gsize) count)
1083
0
    compact_buffer (stream);
1084
1085
0
  task = g_task_new (stream, cancellable, callback, user_data);
1086
0
  g_task_set_source_tag (task, g_buffered_input_stream_real_fill_async);
1087
1088
0
  base_stream = G_FILTER_INPUT_STREAM (stream)->base_stream;
1089
0
  g_input_stream_read_async (base_stream,
1090
0
                             priv->buffer + priv->end,
1091
0
                             count,
1092
0
                             io_priority,
1093
0
                             cancellable,
1094
0
                             fill_async_callback,
1095
0
                             task);
1096
0
}
1097
1098
static gssize
1099
g_buffered_input_stream_real_fill_finish (GBufferedInputStream *stream,
1100
                                          GAsyncResult         *result,
1101
                                          GError              **error)
1102
0
{
1103
0
  g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1104
1105
0
  return g_task_propagate_int (G_TASK (result), error);
1106
0
}
1107
1108
typedef struct
1109
{
1110
  gsize bytes_skipped;
1111
  gsize count;
1112
} SkipAsyncData;
1113
1114
static void
1115
free_skip_async_data (gpointer _data)
1116
0
{
1117
0
  SkipAsyncData *data = _data;
1118
0
  g_slice_free (SkipAsyncData, data);
1119
0
}
1120
1121
static void
1122
large_skip_callback (GObject      *source_object,
1123
                     GAsyncResult *result,
1124
                     gpointer      user_data)
1125
0
{
1126
0
  GTask *task = G_TASK (user_data);
1127
0
  SkipAsyncData *data;
1128
0
  GError *error;
1129
0
  gssize nread;
1130
1131
0
  data = g_task_get_task_data (task);
1132
1133
0
  error = NULL;
1134
0
  nread = g_input_stream_skip_finish (G_INPUT_STREAM (source_object),
1135
0
                                      result, &error);
1136
1137
  /* Only report the error if we've not already read some data */
1138
0
  if (nread < 0 && data->bytes_skipped == 0)
1139
0
    g_task_return_error (task, error);
1140
0
  else
1141
0
    {
1142
0
      if (error)
1143
0
  g_error_free (error);
1144
1145
0
      if (nread > 0)
1146
0
  data->bytes_skipped += nread;
1147
1148
0
      g_task_return_int (task, data->bytes_skipped);
1149
0
    }
1150
1151
0
  g_object_unref (task);
1152
0
}
1153
1154
static void
1155
skip_fill_buffer_callback (GObject      *source_object,
1156
                           GAsyncResult *result,
1157
                           gpointer      user_data)
1158
0
{
1159
0
  GTask *task = G_TASK (user_data);
1160
0
  GBufferedInputStream *bstream;
1161
0
  GBufferedInputStreamPrivate *priv;
1162
0
  SkipAsyncData *data;
1163
0
  GError *error;
1164
0
  gssize nread;
1165
0
  gsize available;
1166
1167
0
  bstream = G_BUFFERED_INPUT_STREAM (source_object);
1168
0
  priv = bstream->priv;
1169
1170
0
  data = g_task_get_task_data (task);
1171
1172
0
  error = NULL;
1173
0
  nread = g_buffered_input_stream_fill_finish (bstream,
1174
0
                                               result, &error);
1175
1176
0
  if (nread < 0 && data->bytes_skipped == 0)
1177
0
    g_task_return_error (task, error);
1178
0
  else
1179
0
    {
1180
0
      if (error)
1181
0
  g_error_free (error);
1182
1183
0
      if (nread > 0)
1184
0
  {
1185
0
    available = priv->end - priv->pos;
1186
0
    data->count = MIN (data->count, available);
1187
1188
0
    data->bytes_skipped += data->count;
1189
0
    priv->pos += data->count;
1190
0
  }
1191
1192
0
      g_assert (data->bytes_skipped <= G_MAXSSIZE);
1193
0
      g_task_return_int (task, data->bytes_skipped);
1194
0
    }
1195
1196
0
  g_object_unref (task);
1197
0
}
1198
1199
static void
1200
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
0
{
1207
0
  GBufferedInputStream *bstream;
1208
0
  GBufferedInputStreamPrivate *priv;
1209
0
  GBufferedInputStreamClass *class;
1210
0
  GInputStream *base_stream;
1211
0
  gsize available;
1212
0
  GTask *task;
1213
0
  SkipAsyncData *data;
1214
1215
0
  bstream = G_BUFFERED_INPUT_STREAM (stream);
1216
0
  priv = bstream->priv;
1217
1218
0
  data = g_slice_new (SkipAsyncData);
1219
0
  data->bytes_skipped = 0;
1220
0
  task = g_task_new (stream, cancellable, callback, user_data);
1221
0
  g_task_set_source_tag (task, g_buffered_input_stream_skip_async);
1222
0
  g_task_set_task_data (task, data, free_skip_async_data);
1223
1224
0
  available = priv->end - priv->pos;
1225
1226
0
  if (count <= available)
1227
0
    {
1228
0
      priv->pos += count;
1229
1230
0
      g_task_return_int (task, count);
1231
0
      g_object_unref (task);
1232
0
      return;
1233
0
    }
1234
1235
  /* Full request not available, skip all currently available
1236
   * and request refill for more
1237
   */
1238
1239
0
  priv->pos = 0;
1240
0
  priv->end = 0;
1241
1242
0
  count -= available;
1243
1244
0
  data->bytes_skipped = available;
1245
0
  data->count = count;
1246
1247
0
  if (count > priv->len)
1248
0
    {
1249
      /* Large request, shortcut buffer */
1250
0
      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
0
      g_assert ((gssize) count >= 0);
1256
0
      g_input_stream_skip_async (base_stream,
1257
0
                                 count,
1258
0
                                 io_priority, cancellable,
1259
0
                                 large_skip_callback,
1260
0
                                 task);
1261
0
    }
1262
0
  else
1263
0
    {
1264
0
      class = G_BUFFERED_INPUT_STREAM_GET_CLASS (stream);
1265
0
      class->fill_async (bstream, priv->len, io_priority, cancellable,
1266
0
                         skip_fill_buffer_callback, task);
1267
0
    }
1268
0
}
1269
1270
static gssize
1271
g_buffered_input_stream_skip_finish (GInputStream   *stream,
1272
                                     GAsyncResult   *result,
1273
                                     GError        **error)
1274
0
{
1275
0
  g_return_val_if_fail (g_task_is_valid (result, stream), -1);
1276
1277
0
  return g_task_propagate_int (G_TASK (result), error);
1278
0
}