Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gmemoryoutputstream.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
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General
18
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
 *
20
 * Authors:
21
 *   Christian Kellner <gicmo@gnome.org>
22
 *   Krzysztof KosiƄski <tweenk.pl@gmail.com>
23
 */
24
25
#include "config.h"
26
#include "gmemoryoutputstream.h"
27
#include "goutputstream.h"
28
#include "gpollableoutputstream.h"
29
#include "gseekable.h"
30
#include "gtask.h"
31
#include "gioerror.h"
32
#include "string.h"
33
#include "glibintl.h"
34
#include "gutilsprivate.h"
35
36
37
/**
38
 * GMemoryOutputStream:
39
 *
40
 * `GMemoryOutputStream` is a class for using arbitrary
41
 * memory chunks as output for GIO streaming output operations.
42
 *
43
 * As of GLib 2.34, `GMemoryOutputStream` trivially implements
44
 * [iface@Gio.PollableOutputStream]: it always polls as ready.
45
 */
46
47
#define MIN_ARRAY_SIZE  16
48
49
enum {
50
  PROP_0,
51
  PROP_DATA,
52
  PROP_SIZE,
53
  PROP_DATA_SIZE,
54
  PROP_REALLOC_FUNCTION,
55
  PROP_DESTROY_FUNCTION
56
};
57
58
struct _GMemoryOutputStreamPrivate
59
{
60
  gpointer       data; /* Write buffer */
61
  gsize          len; /* Current length of the data buffer. Can change with resizing. */
62
  gsize          valid_len; /* The part of data that has been written to */
63
  gsize          pos; /* Current position in the stream. Distinct from valid_len,
64
                         because the stream is seekable. */
65
66
  GReallocFunc   realloc_fn;
67
  GDestroyNotify destroy;
68
};
69
70
static void     g_memory_output_stream_set_property (GObject      *object,
71
                                                     guint         prop_id,
72
                                                     const GValue *value,
73
                                                     GParamSpec   *pspec);
74
static void     g_memory_output_stream_get_property (GObject      *object,
75
                                                     guint         prop_id,
76
                                                     GValue       *value,
77
                                                     GParamSpec   *pspec);
78
static void     g_memory_output_stream_finalize     (GObject      *object);
79
80
static gssize   g_memory_output_stream_write       (GOutputStream *stream,
81
                                                    const void    *buffer,
82
                                                    gsize          count,
83
                                                    GCancellable  *cancellable,
84
                                                    GError       **error);
85
86
static gboolean g_memory_output_stream_close       (GOutputStream  *stream,
87
                                                    GCancellable   *cancellable,
88
                                                    GError        **error);
89
90
static void     g_memory_output_stream_close_async  (GOutputStream        *stream,
91
                                                     int                   io_priority,
92
                                                     GCancellable         *cancellable,
93
                                                     GAsyncReadyCallback   callback,
94
                                                     gpointer              data);
95
static gboolean g_memory_output_stream_close_finish (GOutputStream        *stream,
96
                                                     GAsyncResult         *result,
97
                                                     GError              **error);
98
99
static void     g_memory_output_stream_seekable_iface_init (GSeekableIface  *iface);
100
static goffset  g_memory_output_stream_tell                (GSeekable       *seekable);
101
static gboolean g_memory_output_stream_can_seek            (GSeekable       *seekable);
102
static gboolean g_memory_output_stream_seek                (GSeekable       *seekable,
103
                                                           goffset          offset,
104
                                                           GSeekType        type,
105
                                                           GCancellable    *cancellable,
106
                                                           GError         **error);
107
static gboolean g_memory_output_stream_can_truncate        (GSeekable       *seekable);
108
static gboolean g_memory_output_stream_truncate            (GSeekable       *seekable,
109
                                                           goffset          offset,
110
                                                           GCancellable    *cancellable,
111
                                                           GError         **error);
112
113
static gboolean g_memory_output_stream_is_writable       (GPollableOutputStream *stream);
114
static GSource *g_memory_output_stream_create_source     (GPollableOutputStream *stream,
115
                                                          GCancellable          *cancellable);
116
117
static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);
118
119
G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
120
                         G_ADD_PRIVATE (GMemoryOutputStream)
121
                         G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
122
                                                g_memory_output_stream_seekable_iface_init);
123
                         G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
124
                                                g_memory_output_stream_pollable_iface_init))
125
126
127
static void
128
g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
129
0
{
130
0
  GOutputStreamClass *ostream_class;
131
0
  GObjectClass *gobject_class;
132
133
0
  gobject_class = G_OBJECT_CLASS (klass);
134
0
  gobject_class->set_property = g_memory_output_stream_set_property;
135
0
  gobject_class->get_property = g_memory_output_stream_get_property;
136
0
  gobject_class->finalize     = g_memory_output_stream_finalize;
137
138
0
  ostream_class = G_OUTPUT_STREAM_CLASS (klass);
139
140
0
  ostream_class->write_fn = g_memory_output_stream_write;
141
0
  ostream_class->close_fn = g_memory_output_stream_close;
142
0
  ostream_class->close_async  = g_memory_output_stream_close_async;
143
0
  ostream_class->close_finish = g_memory_output_stream_close_finish;
144
145
  /**
146
   * GMemoryOutputStream:data:
147
   *
148
   * Pointer to buffer where data will be written.
149
   *
150
   * Since: 2.24
151
   **/
152
0
  g_object_class_install_property (gobject_class,
153
0
                                   PROP_DATA,
154
0
                                   g_param_spec_pointer ("data", NULL, NULL,
155
0
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
156
0
                                                         G_PARAM_STATIC_STRINGS));
157
158
  /**
159
   * GMemoryOutputStream:size:
160
   *
161
   * Current size of the data buffer.
162
   *
163
   * Since: 2.24
164
   **/
165
0
  g_object_class_install_property (gobject_class,
166
0
                                   PROP_SIZE,
167
0
                                   g_param_spec_ulong ("size", NULL, NULL,
168
0
                                                       0, G_MAXULONG, 0,
169
0
                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
170
0
                                                       G_PARAM_STATIC_STRINGS));
171
172
  /**
173
   * GMemoryOutputStream:data-size:
174
   *
175
   * Size of data written to the buffer.
176
   *
177
   * Since: 2.24
178
   **/
179
0
  g_object_class_install_property (gobject_class,
180
0
                                   PROP_DATA_SIZE,
181
0
                                   g_param_spec_ulong ("data-size", NULL, NULL,
182
0
                                                       0, G_MAXULONG, 0,
183
0
                                                       G_PARAM_READABLE |
184
0
                                                       G_PARAM_STATIC_STRINGS));
185
186
  /**
187
   * GMemoryOutputStream:realloc-function: (skip)
188
   *
189
   * Function with realloc semantics called to enlarge the buffer.
190
   *
191
   * Since: 2.24
192
   **/
193
0
  g_object_class_install_property (gobject_class,
194
0
                                   PROP_REALLOC_FUNCTION,
195
0
                                   g_param_spec_pointer ("realloc-function", NULL, NULL,
196
0
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
197
0
                                                         G_PARAM_STATIC_STRINGS));
198
199
  /**
200
   * GMemoryOutputStream:destroy-function: (skip)
201
   *
202
   * Function called with the buffer as argument when the stream is destroyed.
203
   *
204
   * Since: 2.24
205
   **/
206
0
  g_object_class_install_property (gobject_class,
207
0
                                   PROP_DESTROY_FUNCTION,
208
0
                                   g_param_spec_pointer ("destroy-function", NULL, NULL,
209
0
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
210
0
                                                         G_PARAM_STATIC_STRINGS));
211
0
}
212
213
static void
214
g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
215
0
{
216
0
  iface->is_writable = g_memory_output_stream_is_writable;
217
0
  iface->create_source = g_memory_output_stream_create_source;
218
0
}
219
220
static void
221
g_memory_output_stream_set_property (GObject      *object,
222
                                     guint         prop_id,
223
                                     const GValue *value,
224
                                     GParamSpec   *pspec)
225
0
{
226
0
  GMemoryOutputStream        *stream;
227
0
  GMemoryOutputStreamPrivate *priv;
228
229
0
  stream = G_MEMORY_OUTPUT_STREAM (object);
230
0
  priv = stream->priv;
231
232
0
  switch (prop_id)
233
0
    {
234
0
    case PROP_DATA:
235
0
      priv->data = g_value_get_pointer (value);
236
0
      break;
237
0
    case PROP_SIZE:
238
0
      priv->len = g_value_get_ulong (value);
239
0
      break;
240
0
    case PROP_REALLOC_FUNCTION:
241
0
      priv->realloc_fn = g_value_get_pointer (value);
242
0
      break;
243
0
    case PROP_DESTROY_FUNCTION:
244
0
      priv->destroy = g_value_get_pointer (value);
245
0
      break;
246
0
    default:
247
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
248
0
      break;
249
0
    }
250
0
}
251
252
static void
253
g_memory_output_stream_get_property (GObject      *object,
254
                                     guint         prop_id,
255
                                     GValue       *value,
256
                                     GParamSpec   *pspec)
257
0
{
258
0
  GMemoryOutputStream        *stream;
259
0
  GMemoryOutputStreamPrivate *priv;
260
261
0
  stream = G_MEMORY_OUTPUT_STREAM (object);
262
0
  priv = stream->priv;
263
264
0
  switch (prop_id)
265
0
    {
266
0
    case PROP_DATA:
267
0
      g_value_set_pointer (value, priv->data);
268
0
      break;
269
0
    case PROP_SIZE:
270
0
      g_value_set_ulong (value, priv->len);
271
0
      break;
272
0
    case PROP_DATA_SIZE:
273
0
      g_value_set_ulong (value, priv->valid_len);
274
0
      break;
275
0
    case PROP_REALLOC_FUNCTION:
276
0
      g_value_set_pointer (value, priv->realloc_fn);
277
0
      break;
278
0
    case PROP_DESTROY_FUNCTION:
279
0
      g_value_set_pointer (value, priv->destroy);
280
0
      break;
281
0
    default:
282
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
283
0
      break;
284
0
    }
285
0
}
286
287
static void
288
g_memory_output_stream_finalize (GObject *object)
289
0
{
290
0
  GMemoryOutputStream        *stream;
291
0
  GMemoryOutputStreamPrivate *priv;
292
293
0
  stream = G_MEMORY_OUTPUT_STREAM (object);
294
0
  priv = stream->priv;
295
  
296
0
  if (priv->destroy)
297
0
    priv->destroy (priv->data);
298
299
0
  G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
300
0
}
301
302
static void
303
g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
304
0
{
305
0
  iface->tell         = g_memory_output_stream_tell;
306
0
  iface->can_seek     = g_memory_output_stream_can_seek;
307
0
  iface->seek         = g_memory_output_stream_seek;
308
0
  iface->can_truncate = g_memory_output_stream_can_truncate;
309
0
  iface->truncate_fn  = g_memory_output_stream_truncate;
310
0
}
311
312
313
static void
314
g_memory_output_stream_init (GMemoryOutputStream *stream)
315
0
{
316
0
  stream->priv = g_memory_output_stream_get_instance_private (stream);
317
0
  stream->priv->pos = 0;
318
0
  stream->priv->valid_len = 0;
319
0
}
320
321
/**
322
 * g_memory_output_stream_new: (skip)
323
 * @data: (nullable): pointer to a chunk of memory to use, or %NULL
324
 * @size: the size of @data
325
 * @realloc_function: (nullable): a function with realloc() semantics (like g_realloc())
326
 *     to be called when @data needs to be grown, or %NULL
327
 * @destroy_function: (nullable): a function to be called on @data when the stream is
328
 *     finalized, or %NULL
329
 *
330
 * Creates a new #GMemoryOutputStream.
331
 *
332
 * In most cases this is not the function you want.  See
333
 * g_memory_output_stream_new_resizable() instead.
334
 *
335
 * If @data is non-%NULL, the stream will use that for its internal storage.
336
 *
337
 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
338
 * storage when necessary and the stream will be considered resizable.
339
 * In that case, the stream will start out being (conceptually) empty.
340
 * @size is used only as a hint for how big @data is.  Specifically,
341
 * seeking to the end of a newly-created stream will seek to zero, not
342
 * @size.  Seeking past the end of the stream and then writing will
343
 * introduce a zero-filled gap.
344
 *
345
 * If @realloc_fn is %NULL then the stream is fixed-sized.  Seeking to
346
 * the end will seek to @size exactly.  Writing past the end will give
347
 * an 'out of space' error.  Attempting to seek past the end will fail.
348
 * Unlike the resizable case, seeking to an offset within the stream and
349
 * writing will preserve the bytes passed in as @data before that point
350
 * and will return them as part of g_memory_output_stream_steal_data().
351
 * If you intend to seek you should probably therefore ensure that @data
352
 * is properly initialised.
353
 *
354
 * It is probably only meaningful to provide @data and @size in the case
355
 * that you want a fixed-sized stream.  Put another way: if @realloc_fn
356
 * is non-%NULL then it makes most sense to give @data as %NULL and
357
 * @size as 0 (allowing #GMemoryOutputStream to do the initial
358
 * allocation for itself).
359
 *
360
 * |[<!-- language="C" -->
361
 * // a stream that can grow
362
 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
363
 *
364
 * // another stream that can grow
365
 * stream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
366
 *
367
 * // a fixed-size stream
368
 * data = malloc (200);
369
 * stream3 = g_memory_output_stream_new (data, 200, NULL, free);
370
 * ]|
371
 *
372
 * Returns: A newly created #GMemoryOutputStream object.
373
 **/
374
GOutputStream *
375
g_memory_output_stream_new (gpointer       data,
376
                            gsize          size,
377
                            GReallocFunc   realloc_function,
378
                            GDestroyNotify destroy_function)
379
0
{
380
0
  GOutputStream *stream;
381
382
0
  stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM,
383
0
                         "data", data,
384
0
                         "size", size,
385
0
                         "realloc-function", realloc_function,
386
0
                         "destroy-function", destroy_function,
387
0
                         NULL);
388
389
0
  return stream;
390
0
}
391
392
/**
393
 * g_memory_output_stream_new_resizable:
394
 *
395
 * Creates a new #GMemoryOutputStream, using g_realloc() and g_free()
396
 * for memory allocation.
397
 *
398
 * Since: 2.36
399
 */
400
GOutputStream *
401
g_memory_output_stream_new_resizable (void)
402
0
{
403
0
  return g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
404
0
}
405
406
/**
407
 * g_memory_output_stream_get_data:
408
 * @ostream: a #GMemoryOutputStream
409
 *
410
 * Gets any loaded data from the @ostream.
411
 *
412
 * Note that the returned pointer may become invalid on the next
413
 * write or truncate operation on the stream.
414
 *
415
 * Returns: (transfer none): pointer to the stream's data, or %NULL if the data
416
 *    has been stolen
417
 **/
418
gpointer
419
g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
420
0
{
421
0
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
422
423
0
  return ostream->priv->data;
424
0
}
425
426
/**
427
 * g_memory_output_stream_get_size:
428
 * @ostream: a #GMemoryOutputStream
429
 *
430
 * Gets the size of the currently allocated data area (available from
431
 * g_memory_output_stream_get_data()).
432
 *
433
 * You probably don't want to use this function on resizable streams.
434
 * See g_memory_output_stream_get_data_size() instead.  For resizable
435
 * streams the size returned by this function is an implementation
436
 * detail and may be change at any time in response to operations on the
437
 * stream.
438
 *
439
 * If the stream is fixed-sized (ie: no realloc was passed to
440
 * g_memory_output_stream_new()) then this is the maximum size of the
441
 * stream and further writes will return %G_IO_ERROR_NO_SPACE.
442
 *
443
 * In any case, if you want the number of bytes currently written to the
444
 * stream, use g_memory_output_stream_get_data_size().
445
 *
446
 * Returns: the number of bytes allocated for the data buffer
447
 */
448
gsize
449
g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
450
0
{
451
0
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
452
453
0
  return ostream->priv->len;
454
0
}
455
456
/**
457
 * g_memory_output_stream_get_data_size:
458
 * @ostream: a #GMemoryOutputStream
459
 *
460
 * Returns the number of bytes from the start up to including the last
461
 * byte written in the stream that has not been truncated away.
462
 *
463
 * Returns: the number of bytes written to the stream
464
 *
465
 * Since: 2.18
466
 */
467
gsize
468
g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
469
0
{
470
0
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
471
472
0
  return ostream->priv->valid_len;
473
0
}
474
475
/**
476
 * g_memory_output_stream_steal_data:
477
 * @ostream: a #GMemoryOutputStream
478
 *
479
 * Gets any loaded data from the @ostream. Ownership of the data
480
 * is transferred to the caller; when no longer needed it must be
481
 * freed using the free function set in @ostream's
482
 * #GMemoryOutputStream:destroy-function property.
483
 *
484
 * @ostream must be closed before calling this function.
485
 *
486
 * Returns: (transfer full): the stream's data, or %NULL if it has previously
487
 *    been stolen
488
 *
489
 * Since: 2.26
490
 **/
491
gpointer
492
g_memory_output_stream_steal_data (GMemoryOutputStream *ostream)
493
0
{
494
0
  gpointer data;
495
496
0
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
497
0
  g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
498
499
0
  data = ostream->priv->data;
500
0
  ostream->priv->data = NULL;
501
502
0
  return data;
503
0
}
504
505
/**
506
 * g_memory_output_stream_steal_as_bytes:
507
 * @ostream: a #GMemoryOutputStream
508
 *
509
 * Returns data from the @ostream as a #GBytes. @ostream must be
510
 * closed before calling this function.
511
 *
512
 * Returns: (transfer full): the stream's data
513
 *
514
 * Since: 2.34
515
 **/
516
GBytes *
517
g_memory_output_stream_steal_as_bytes (GMemoryOutputStream *ostream)
518
0
{
519
0
  GBytes *result;
520
521
0
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
522
0
  g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);
523
524
0
  result = g_bytes_new_with_free_func (ostream->priv->data,
525
0
                                       ostream->priv->valid_len,
526
0
                                       ostream->priv->destroy,
527
0
                                       ostream->priv->data);
528
0
  ostream->priv->data = NULL;
529
530
0
  return result;
531
0
}
532
533
static gboolean
534
array_resize (GMemoryOutputStream  *ostream,
535
              gsize                 size,
536
              gboolean              allow_partial,
537
              GError              **error)
538
0
{
539
0
  GMemoryOutputStreamPrivate *priv;
540
0
  gpointer data;
541
0
  gsize len;
542
543
0
  priv = ostream->priv;
544
545
0
  if (priv->len == size)
546
0
    return TRUE;
547
548
0
  if (!priv->realloc_fn)
549
0
    {
550
0
      if (allow_partial &&
551
0
          priv->pos < priv->len)
552
0
        return TRUE; /* Short write */
553
554
0
      g_set_error_literal (error,
555
0
                           G_IO_ERROR,
556
0
                           G_IO_ERROR_NO_SPACE,
557
0
                           _("Memory output stream not resizable"));
558
0
      return FALSE;
559
0
    }
560
561
0
  len = priv->len;
562
0
  data = priv->realloc_fn (priv->data, size);
563
564
0
  if (size > 0 && !data)
565
0
    {
566
0
      if (allow_partial &&
567
0
          priv->pos < priv->len)
568
0
        return TRUE; /* Short write */
569
570
0
      g_set_error_literal (error,
571
0
                           G_IO_ERROR,
572
0
                           G_IO_ERROR_NO_SPACE,
573
0
                           _("Failed to resize memory output stream"));
574
0
      return FALSE;
575
0
    }
576
577
0
  if (size > len)
578
0
    memset ((guint8 *)data + len, 0, size - len);
579
580
0
  priv->data = data;
581
0
  priv->len = size;
582
583
0
  if (priv->len < priv->valid_len)
584
0
    priv->valid_len = priv->len;
585
586
0
  return TRUE;
587
0
}
588
589
static gssize
590
g_memory_output_stream_write (GOutputStream  *stream,
591
                              const void     *buffer,
592
                              gsize           count,
593
                              GCancellable   *cancellable,
594
                              GError        **error)
595
0
{
596
0
  GMemoryOutputStream        *ostream;
597
0
  GMemoryOutputStreamPrivate *priv;
598
0
  guint8   *dest;
599
0
  gsize new_size;
600
601
0
  ostream = G_MEMORY_OUTPUT_STREAM (stream);
602
0
  priv = ostream->priv;
603
604
0
  if (count == 0)
605
0
    return 0;
606
607
  /* Check for address space overflow, but only if the buffer is resizable.
608
     Otherwise we just do a short write and don't worry. */
609
0
  if (priv->realloc_fn && priv->pos + count < priv->pos)
610
0
    goto overflow;
611
612
0
  if (priv->pos + count > priv->len)
613
0
    {
614
      /* At least enough to fit the write, rounded up for greater than
615
       * linear growth.
616
       *
617
       * Assuming that we're using something like realloc(), the kernel
618
       * will overcommit memory to us, so doubling the size each time
619
       * will keep the number of realloc calls low without wasting too
620
       * much memory.
621
       */
622
0
      new_size = g_nearest_pow (priv->pos + count);
623
      /* Check for overflow again. We have checked if
624
         pos + count > G_MAXSIZE, but now check if g_nearest_pow () has
625
         overflowed */
626
0
      if (new_size == 0)
627
0
        goto overflow;
628
629
0
      new_size = MAX (new_size, MIN_ARRAY_SIZE);
630
0
      if (!array_resize (ostream, new_size, TRUE, error))
631
0
        return -1;
632
0
    }
633
634
  /* Make sure we handle short writes if the array_resize
635
     only added part of the required memory */
636
0
  count = MIN (count, priv->len - priv->pos);
637
638
0
  dest = (guint8 *)priv->data + priv->pos;
639
0
  memcpy (dest, buffer, count);
640
0
  priv->pos += count;
641
642
0
  if (priv->pos > priv->valid_len)
643
0
    priv->valid_len = priv->pos;
644
645
0
  return count;
646
647
0
 overflow:
648
  /* Overflow: buffer size would need to be bigger than G_MAXSIZE. */
649
0
  g_set_error_literal (error,
650
0
                       G_IO_ERROR,
651
0
                       G_IO_ERROR_NO_SPACE,
652
0
                       _("Amount of memory required to process the write is "
653
0
                         "larger than available address space"));
654
0
  return -1;
655
0
}
656
657
static gboolean
658
g_memory_output_stream_close (GOutputStream  *stream,
659
                              GCancellable   *cancellable,
660
                              GError        **error)
661
0
{
662
0
  return TRUE;
663
0
}
664
665
static void
666
g_memory_output_stream_close_async (GOutputStream       *stream,
667
                                    int                  io_priority,
668
                                    GCancellable        *cancellable,
669
                                    GAsyncReadyCallback  callback,
670
                                    gpointer             data)
671
0
{
672
0
  GTask *task;
673
674
0
  task = g_task_new (stream, cancellable, callback, data);
675
0
  g_task_set_source_tag (task, g_memory_output_stream_close_async);
676
677
  /* will always return TRUE */
678
0
  g_memory_output_stream_close (stream, cancellable, NULL);
679
680
0
  g_task_return_boolean (task, TRUE);
681
0
  g_object_unref (task);
682
0
}
683
684
static gboolean
685
g_memory_output_stream_close_finish (GOutputStream  *stream,
686
                                     GAsyncResult   *result,
687
                                     GError        **error)
688
0
{
689
0
  g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
690
691
0
  return g_task_propagate_boolean (G_TASK (result), error);
692
0
}
693
694
static goffset
695
g_memory_output_stream_tell (GSeekable *seekable)
696
0
{
697
0
  GMemoryOutputStream *stream;
698
0
  GMemoryOutputStreamPrivate *priv;
699
700
0
  stream = G_MEMORY_OUTPUT_STREAM (seekable);
701
0
  priv = stream->priv;
702
703
0
  return priv->pos;
704
0
}
705
706
static gboolean
707
g_memory_output_stream_can_seek (GSeekable *seekable)
708
0
{
709
0
  return TRUE;
710
0
}
711
712
static gboolean
713
g_memory_output_stream_seek (GSeekable    *seekable,
714
                             goffset        offset,
715
                             GSeekType      type,
716
                             GCancellable  *cancellable,
717
                             GError       **error)
718
0
{
719
0
  GMemoryOutputStream        *stream;
720
0
  GMemoryOutputStreamPrivate *priv;
721
0
  goffset absolute;
722
723
0
  stream = G_MEMORY_OUTPUT_STREAM (seekable);
724
0
  priv = stream->priv;
725
726
0
  switch (type)
727
0
    {
728
0
    case G_SEEK_CUR:
729
0
      absolute = priv->pos + offset;
730
0
      break;
731
732
0
    case G_SEEK_SET:
733
0
      absolute = offset;
734
0
      break;
735
736
0
    case G_SEEK_END:
737
      /* For resizable streams, we consider the end to be the data
738
       * length.  For fixed-sized streams, we consider the end to be the
739
       * size of the buffer.
740
       */
741
0
      if (priv->realloc_fn)
742
0
        absolute = priv->valid_len + offset;
743
0
      else
744
0
        absolute = priv->len + offset;
745
0
      break;
746
747
0
    default:
748
0
      g_set_error_literal (error,
749
0
                           G_IO_ERROR,
750
0
                           G_IO_ERROR_INVALID_ARGUMENT,
751
0
                           _("Invalid GSeekType supplied"));
752
753
0
      return FALSE;
754
0
    }
755
756
0
  if (absolute < 0)
757
0
    {
758
0
      g_set_error_literal (error,
759
0
                           G_IO_ERROR,
760
0
                           G_IO_ERROR_INVALID_ARGUMENT,
761
0
                           _("Requested seek before the beginning of the stream"));
762
0
      return FALSE;
763
0
    }
764
765
  /* Can't seek past the end of a fixed-size stream.
766
   *
767
   * Note: seeking to the non-existent byte at the end of a fixed-sized
768
   * stream is valid (eg: a 1-byte fixed sized stream can have position
769
   * 0 or 1).  Therefore '>' is what we want.
770
   * */
771
0
  if (priv->realloc_fn == NULL && (gsize) absolute > priv->len)
772
0
    {
773
0
      g_set_error_literal (error,
774
0
                           G_IO_ERROR,
775
0
                           G_IO_ERROR_INVALID_ARGUMENT,
776
0
                           _("Requested seek beyond the end of the stream"));
777
0
      return FALSE;
778
0
    }
779
780
0
  priv->pos = absolute;
781
782
0
  return TRUE;
783
0
}
784
785
static gboolean
786
g_memory_output_stream_can_truncate (GSeekable *seekable)
787
0
{
788
0
  GMemoryOutputStream *ostream;
789
0
  GMemoryOutputStreamPrivate *priv;
790
791
0
  ostream = G_MEMORY_OUTPUT_STREAM (seekable);
792
0
  priv = ostream->priv;
793
794
  /* We do not allow truncation of fixed-sized streams */
795
0
  return priv->realloc_fn != NULL;
796
0
}
797
798
static gboolean
799
g_memory_output_stream_truncate (GSeekable     *seekable,
800
                                 goffset        offset,
801
                                 GCancellable  *cancellable,
802
                                 GError       **error)
803
0
{
804
0
  GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
805
806
0
  if (!array_resize (ostream, offset, FALSE, error))
807
0
    return FALSE;
808
809
0
  ostream->priv->valid_len = offset;
810
811
0
  return TRUE;
812
0
}
813
814
static gboolean
815
g_memory_output_stream_is_writable (GPollableOutputStream *stream)
816
0
{
817
0
  return TRUE;
818
0
}
819
820
static GSource *
821
g_memory_output_stream_create_source (GPollableOutputStream *stream,
822
                                      GCancellable          *cancellable)
823
0
{
824
0
  GSource *base_source, *pollable_source;
825
826
0
  base_source = g_timeout_source_new (0);
827
0
  pollable_source = g_pollable_source_new_full (stream, base_source, cancellable);
828
0
  g_source_unref (base_source);
829
830
0
  return pollable_source;
831
0
}