Coverage Report

Created: 2025-06-13 06:55

/src/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
 * SECTION:gbufferedinputstream
38
 * @short_description: Buffered Input Stream
39
 * @include: gio/gio.h
40
 * @see_also: #GFilterInputStream, #GInputStream
41
 *
42
 * Buffered input stream implements #GFilterInputStream and provides
43
 * for buffered reads.
44
 *
45
 * By default, #GBufferedInputStream's buffer size is set at 4 kilobytes.
46
 *
47
 * To create a buffered input stream, use g_buffered_input_stream_new(),
48
 * or g_buffered_input_stream_new_sized() to specify the buffer's size at
49
 * construction.
50
 *
51
 * To get the size of a buffer within a buffered input stream, use
52
 * g_buffered_input_stream_get_buffer_size(). To change the size of a
53
 * buffered input stream's buffer, use
54
 * g_buffered_input_stream_set_buffer_size(). Note that the buffer's size
55
 * cannot be reduced below the size of the data within the buffer.
56
 */
57
58
59
0
#define DEFAULT_BUFFER_SIZE 4096
60
61
struct _GBufferedInputStreamPrivate {
62
  guint8 *buffer;
63
  gsize   len;
64
  gsize   pos;
65
  gsize   end;
66
  GAsyncReadyCallback outstanding_callback;
67
};
68
69
enum {
70
  PROP_0,
71
  PROP_BUFSIZE
72
};
73
74
static void g_buffered_input_stream_set_property  (GObject      *object,
75
                                                   guint         prop_id,
76
                                                   const GValue *value,
77
                                                   GParamSpec   *pspec);
78
79
static void g_buffered_input_stream_get_property  (GObject      *object,
80
                                                   guint         prop_id,
81
                                                   GValue       *value,
82
                                                   GParamSpec   *pspec);
83
static void g_buffered_input_stream_finalize      (GObject *object);
84
85
86
static gssize g_buffered_input_stream_skip             (GInputStream          *stream,
87
                                                        gsize                  count,
88
                                                        GCancellable          *cancellable,
89
                                                        GError               **error);
90
static void   g_buffered_input_stream_skip_async       (GInputStream          *stream,
91
                                                        gsize                  count,
92
                                                        int                    io_priority,
93
                                                        GCancellable          *cancellable,
94
                                                        GAsyncReadyCallback    callback,
95
                                                        gpointer               user_data);
96
static gssize g_buffered_input_stream_skip_finish      (GInputStream          *stream,
97
                                                        GAsyncResult          *result,
98
                                                        GError               **error);
99
static gssize g_buffered_input_stream_read             (GInputStream          *stream,
100
                                                        void                  *buffer,
101
                                                        gsize                  count,
102
                                                        GCancellable          *cancellable,
103
                                                        GError               **error);
104
static gssize g_buffered_input_stream_real_fill        (GBufferedInputStream  *stream,
105
                                                        gssize                 count,
106
                                                        GCancellable          *cancellable,
107
                                                        GError               **error);
108
static void   g_buffered_input_stream_real_fill_async  (GBufferedInputStream  *stream,
109
                                                        gssize                 count,
110
                                                        int                    io_priority,
111
                                                        GCancellable          *cancellable,
112
                                                        GAsyncReadyCallback    callback,
113
                                                        gpointer               user_data);
114
static gssize g_buffered_input_stream_real_fill_finish (GBufferedInputStream  *stream,
115
                                                        GAsyncResult          *result,
116
                                                        GError               **error);
117
118
static void     g_buffered_input_stream_seekable_iface_init (GSeekableIface  *iface);
119
static goffset  g_buffered_input_stream_tell                (GSeekable       *seekable);
120
static gboolean g_buffered_input_stream_can_seek            (GSeekable       *seekable);
121
static gboolean g_buffered_input_stream_seek                (GSeekable       *seekable,
122
                   goffset          offset,
123
                   GSeekType        type,
124
                   GCancellable    *cancellable,
125
                   GError         **error);
126
static gboolean g_buffered_input_stream_can_truncate        (GSeekable       *seekable);
127
static gboolean g_buffered_input_stream_truncate            (GSeekable       *seekable,
128
                   goffset          offset,
129
                   GCancellable    *cancellable,
130
                   GError         **error);
131
132
static void compact_buffer (GBufferedInputStream *stream);
133
134
G_DEFINE_TYPE_WITH_CODE (GBufferedInputStream,
135
       g_buffered_input_stream,
136
       G_TYPE_FILTER_INPUT_STREAM,
137
                         G_ADD_PRIVATE (GBufferedInputStream)
138
       G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
139
            g_buffered_input_stream_seekable_iface_init))
140
141
static void
142
g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass)
143
0
{
144
0
  GObjectClass *object_class;
145
0
  GInputStreamClass *istream_class;
146
0
  GBufferedInputStreamClass *bstream_class;
147
148
0
  object_class = G_OBJECT_CLASS (klass);
149
0
  object_class->get_property = g_buffered_input_stream_get_property;
150
0
  object_class->set_property = g_buffered_input_stream_set_property;
151
0
  object_class->finalize     = g_buffered_input_stream_finalize;
152
153
0
  istream_class = G_INPUT_STREAM_CLASS (klass);
154
0
  istream_class->skip = g_buffered_input_stream_skip;
155
0
  istream_class->skip_async  = g_buffered_input_stream_skip_async;
156
0
  istream_class->skip_finish = g_buffered_input_stream_skip_finish;
157
0
  istream_class->read_fn = g_buffered_input_stream_read;
158
159
0
  bstream_class = G_BUFFERED_INPUT_STREAM_CLASS (klass);
160
0
  bstream_class->fill = g_buffered_input_stream_real_fill;
161
0
  bstream_class->fill_async = g_buffered_input_stream_real_fill_async;
162
0
  bstream_class->fill_finish = g_buffered_input_stream_real_fill_finish;
163
164
0
  g_object_class_install_property (object_class,
165
0
                                   PROP_BUFSIZE,
166
0
                                   g_param_spec_uint ("buffer-size",
167
0
                                                      P_("Buffer Size"),
168
0
                                                      P_("The size of the backend buffer"),
169
0
                                                      1,
170
0
                                                      G_MAXUINT,
171
0
                                                      DEFAULT_BUFFER_SIZE,
172
0
                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT |
173
0
                                                      G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB));
174
175
176
0
}
177
178
/**
179
 * g_buffered_input_stream_get_buffer_size:
180
 * @stream: a #GBufferedInputStream
181
 *
182
 * Gets the size of the input buffer.
183
 *
184
 * Returns: the current buffer size.
185
 */
186
gsize
187
g_buffered_input_stream_get_buffer_size (GBufferedInputStream  *stream)
188
0
{
189
0
  g_return_val_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream), 0);
190
191
0
  return stream->priv->len;
192
0
}
193
194
/**
195
 * g_buffered_input_stream_set_buffer_size:
196
 * @stream: a #GBufferedInputStream
197
 * @size: a #gsize
198
 *
199
 * Sets the size of the internal buffer of @stream to @size, or to the
200
 * size of the contents of the buffer. The buffer can never be resized
201
 * smaller than its current contents.
202
 */
203
void
204
g_buffered_input_stream_set_buffer_size (GBufferedInputStream *stream,
205
                                         gsize                 size)
206
0
{
207
0
  GBufferedInputStreamPrivate *priv;
208
0
  gsize in_buffer;
209
0
  guint8 *buffer;
210
211
0
  g_return_if_fail (G_IS_BUFFERED_INPUT_STREAM (stream));
212
213
0
  priv = stream->priv;
214
215
0
  if (priv->len == size)
216
0
    return;
217
218
0
  if (priv->buffer)
219
0
    {
220
0
      in_buffer = priv->end - priv->pos;
221
222
      /* Never resize smaller than current buffer contents */
223
0
      size = MAX (size, in_buffer);
224
225
0
      buffer = g_malloc (size);
226
0
      memcpy (buffer, priv->buffer + priv->pos, in_buffer);
227
0
      priv->len = size;
228
0
      priv->pos = 0;
229
0
      priv->end = in_buffer;
230
0
      g_free (priv->buffer);
231
0
      priv->buffer = buffer;
232
0
    }
233
0
  else
234
0
    {
235
0
      priv->len = size;
236
0
      priv->pos = 0;
237
0
      priv->end = 0;
238
0
      priv->buffer = g_malloc (size);
239
0
    }
240
241
0
  g_object_notify (G_OBJECT (stream), "buffer-size");
242
0
}
243
244
static void
245
g_buffered_input_stream_set_property (GObject      *object,
246
                                      guint         prop_id,
247
                                      const GValue *value,
248
                                      GParamSpec   *pspec)
249
0
{
250
0
  GBufferedInputStream        *bstream;
251
252
0
  bstream = G_BUFFERED_INPUT_STREAM (object);
253
254
0
  switch (prop_id)
255
0
    {
256
0
    case PROP_BUFSIZE:
257
0
      g_buffered_input_stream_set_buffer_size (bstream, g_value_get_uint (value));
258
0
      break;
259
260
0
    default:
261
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262
0
      break;
263
0
    }
264
0
}
265
266
static void
267
g_buffered_input_stream_get_property (GObject    *object,
268
                                      guint       prop_id,
269
                                      GValue     *value,
270
                                      GParamSpec *pspec)
271
0
{
272
0
  GBufferedInputStreamPrivate *priv;
273
0
  GBufferedInputStream        *bstream;
274
275
0
  bstream = G_BUFFERED_INPUT_STREAM (object);
276
0
  priv = bstream->priv;
277
278
0
  switch (prop_id)
279
0
    {
280
0
    case PROP_BUFSIZE:
281
0
      g_value_set_uint (value, priv->len);
282
0
      break;
283
284
0
    default:
285
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286
0
      break;
287
0
    }
288
0
}
289
290
static void
291
g_buffered_input_stream_finalize (GObject *object)
292
0
{
293
0
  GBufferedInputStreamPrivate *priv;
294
0
  GBufferedInputStream        *stream;
295
296
0
  stream = G_BUFFERED_INPUT_STREAM (object);
297
0
  priv = stream->priv;
298
299
0
  g_free (priv->buffer);
300
301
0
  G_OBJECT_CLASS (g_buffered_input_stream_parent_class)->finalize (object);
302
0
}
303
304
static void
305
g_buffered_input_stream_seekable_iface_init (GSeekableIface *iface)
306
0
{
307
0
  iface->tell         = g_buffered_input_stream_tell;
308
0
  iface->can_seek     = g_buffered_input_stream_can_seek;
309
0
  iface->seek         = g_buffered_input_stream_seek;
310
0
  iface->can_truncate = g_buffered_input_stream_can_truncate;
311
0
  iface->truncate_fn  = g_buffered_input_stream_truncate;
312
0
}
313
314
static void
315
g_buffered_input_stream_init (GBufferedInputStream *stream)
316
0
{
317
0
  stream->priv = g_buffered_input_stream_get_instance_private (stream);
318
0
}
319
320
321
/**
322
 * g_buffered_input_stream_new:
323
 * @base_stream: a #GInputStream
324
 *
325
 * Creates a new #GInputStream from the given @base_stream, with
326
 * a buffer set to the default size (4 kilobytes).
327
 *
328
 * Returns: a #GInputStream for the given @base_stream.
329
 */
330
GInputStream *
331
g_buffered_input_stream_new (GInputStream *base_stream)
332
0
{
333
0
  GInputStream *stream;
334
335
0
  g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
336
337
0
  stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
338
0
                         "base-stream", base_stream,
339
0
                         NULL);
340
341
0
  return stream;
342
0
}
343
344
/**
345
 * g_buffered_input_stream_new_sized:
346
 * @base_stream: a #GInputStream
347
 * @size: a #gsize
348
 *
349
 * Creates a new #GBufferedInputStream from the given @base_stream,
350
 * with a buffer set to @size.
351
 *
352
 * Returns: a #GInputStream.
353
 */
354
GInputStream *
355
g_buffered_input_stream_new_sized (GInputStream *base_stream,
356
                                   gsize         size)
357
0
{
358
0
  GInputStream *stream;
359
360
0
  g_return_val_if_fail (G_IS_INPUT_STREAM (base_stream), NULL);
361
362
0
  stream = g_object_new (G_TYPE_BUFFERED_INPUT_STREAM,
363
0
                         "base-stream", base_stream,
364
0
                         "buffer-size", (guint)size,
365
0
                         NULL);
366
367
0
  return stream;
368
0
}
369
370
/**
371
 * g_buffered_input_stream_fill:
372
 * @stream: a #GBufferedInputStream
373
 * @count: the number of bytes that will be read from the stream
374
 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore
375
 * @error: location to store the error occurring, or %NULL to ignore
376
 *
377
 * Tries to read @count bytes from the stream into the buffer.
378
 * Will block during this read.
379
 *
380
 * If @count is zero, returns zero and does nothing. A value of @count
381
 * larger than %G_MAXSSIZE will cause a %G_IO_ERROR_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 %G_IO_ERROR_CANCELLED will be returned. If an
394
 * 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
 * g_buffered_input_stream_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 #GBufferedInputStream
458
 * @count: the number of bytes that will be read from the stream
459
 * @io_priority: the [I/O priority][io-priority] of the request
460
 * @cancellable: (nullable): optional #GCancellable object
461
 * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback
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 g_buffered_input_stream_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 #GBufferedInputStream
524
 * @result: a #GAsyncResult
525
 * @error: a #GError
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: #GBufferedInputStream
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 #GBufferedInputStream
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 #GBufferedInputStream
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 #GBufferedInputStream
947
 * @cancellable: (nullable): optional #GCancellable 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 %G_IO_ERROR_CANCELLED will be returned. If an
959
 * 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
}