Coverage Report

Created: 2025-07-23 08:13

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