gmemoryoutputstream.c 27.9 KB
Newer Older
1 2 3 4 5 6 7
/* GIO - GLib Input, Output and Streaming Library
 * 
 * Copyright (C) 2006-2007 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9 10 11 12 13 14 15
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
16
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17
 *
18 19 20
 * Authors:
 *   Christian Kellner <gicmo@gnome.org>
 *   Krzysztof Kosiński <tweenk.pl@gmail.com>
21 22
 */

23
#include "config.h"
24 25
#include "gmemoryoutputstream.h"
#include "goutputstream.h"
26
#include "gpollableoutputstream.h"
27
#include "gseekable.h"
28
#include "gtask.h"
29
#include "gioerror.h"
30 31 32
#include "string.h"
#include "glibintl.h"

33

34 35
/**
 * SECTION:gmemoryoutputstream
Matthias Clasen's avatar
Matthias Clasen committed
36
 * @short_description: Streaming output operations on memory chunks
Matthias Clasen's avatar
Matthias Clasen committed
37
 * @include: gio/gio.h
38
 * @see_also: #GMemoryInputStream
39 40 41 42
 *
 * #GMemoryOutputStream is a class for using arbitrary
 * memory chunks as output for GIO streaming output operations.
 *
43 44
 * As of GLib 2.34, #GMemoryOutputStream trivially implements
 * #GPollableOutputStream: it always polls as ready.
45 46
 */

47 48
#define MIN_ARRAY_SIZE  16

49 50 51 52 53 54 55 56 57
enum {
  PROP_0,
  PROP_DATA,
  PROP_SIZE,
  PROP_DATA_SIZE,
  PROP_REALLOC_FUNCTION,
  PROP_DESTROY_FUNCTION
};

58 59
struct _GMemoryOutputStreamPrivate
{
60 61
  gpointer       data; /* Write buffer */
  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 64
  gsize          pos; /* Current position in the stream. Distinct from valid_len,
                         because the stream is seekable. */
65

66 67
  GReallocFunc   realloc_fn;
  GDestroyNotify destroy;
68 69
};

70 71 72 73 74 75 76 77
static void     g_memory_output_stream_set_property (GObject      *object,
                                                     guint         prop_id,
                                                     const GValue *value,
                                                     GParamSpec   *pspec);
static void     g_memory_output_stream_get_property (GObject      *object,
                                                     guint         prop_id,
                                                     GValue       *value,
                                                     GParamSpec   *pspec);
78
static void     g_memory_output_stream_finalize     (GObject      *object);
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

static gssize   g_memory_output_stream_write       (GOutputStream *stream,
                                                    const void    *buffer,
                                                    gsize          count,
                                                    GCancellable  *cancellable,
                                                    GError       **error);

static gboolean g_memory_output_stream_close       (GOutputStream  *stream,
                                                    GCancellable   *cancellable,
                                                    GError        **error);

static void     g_memory_output_stream_close_async  (GOutputStream        *stream,
                                                     int                   io_priority,
                                                     GCancellable         *cancellable,
                                                     GAsyncReadyCallback   callback,
                                                     gpointer              data);
static gboolean g_memory_output_stream_close_finish (GOutputStream        *stream,
                                                     GAsyncResult         *result,
                                                     GError              **error);

static void     g_memory_output_stream_seekable_iface_init (GSeekableIface  *iface);
static goffset  g_memory_output_stream_tell                (GSeekable       *seekable);
static gboolean g_memory_output_stream_can_seek            (GSeekable       *seekable);
static gboolean g_memory_output_stream_seek                (GSeekable       *seekable,
                                                           goffset          offset,
                                                           GSeekType        type,
                                                           GCancellable    *cancellable,
                                                           GError         **error);
static gboolean g_memory_output_stream_can_truncate        (GSeekable       *seekable);
static gboolean g_memory_output_stream_truncate            (GSeekable       *seekable,
                                                           goffset          offset,
                                                           GCancellable    *cancellable,
                                                           GError         **error);

113 114
static gboolean g_memory_output_stream_is_writable       (GPollableOutputStream *stream);
static GSource *g_memory_output_stream_create_source     (GPollableOutputStream *stream,
115
                                                          GCancellable          *cancellable);
116 117 118

static void g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface);

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 123 124
                                                g_memory_output_stream_seekable_iface_init);
                         G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_OUTPUT_STREAM,
                                                g_memory_output_stream_pollable_iface_init))
125 126 127 128 129 130 131 132 133


static void
g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
{
  GOutputStreamClass *ostream_class;
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
134 135 136
  gobject_class->set_property = g_memory_output_stream_set_property;
  gobject_class->get_property = g_memory_output_stream_get_property;
  gobject_class->finalize     = g_memory_output_stream_finalize;
137 138 139

  ostream_class = G_OUTPUT_STREAM_CLASS (klass);

140 141
  ostream_class->write_fn = g_memory_output_stream_write;
  ostream_class->close_fn = g_memory_output_stream_close;
142 143
  ostream_class->close_async  = g_memory_output_stream_close_async;
  ostream_class->close_finish = g_memory_output_stream_close_finish;
144

145 146 147 148 149 150 151
  /**
   * GMemoryOutputStream:data:
   *
   * Pointer to buffer where data will be written.
   *
   * Since: 2.24
   **/
152 153 154 155 156 157 158 159
  g_object_class_install_property (gobject_class,
                                   PROP_DATA,
                                   g_param_spec_pointer ("data",
                                                         P_("Data Buffer"),
                                                         P_("Pointer to buffer where data will be written."),
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));

160 161 162 163 164 165 166
  /**
   * GMemoryOutputStream:size:
   *
   * Current size of the data buffer.
   *
   * Since: 2.24
   **/
167 168 169 170 171 172 173 174 175
  g_object_class_install_property (gobject_class,
                                   PROP_SIZE,
                                   g_param_spec_ulong ("size",
                                                       P_("Data Buffer Size"),
                                                       P_("Current size of the data buffer."),
                                                       0, G_MAXULONG, 0,
                                                       G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                                       G_PARAM_STATIC_STRINGS));

176 177 178 179 180 181 182
  /**
   * GMemoryOutputStream:data-size:
   *
   * Size of data written to the buffer.
   *
   * Since: 2.24
   **/
183 184 185 186 187 188 189 190 191
  g_object_class_install_property (gobject_class,
                                   PROP_DATA_SIZE,
                                   g_param_spec_ulong ("data-size",
                                                       P_("Data Size"),
                                                       P_("Size of data written to the buffer."),
                                                       0, G_MAXULONG, 0,
                                                       G_PARAM_READABLE |
                                                       G_PARAM_STATIC_STRINGS));

192
  /**
193
   * GMemoryOutputStream:realloc-function: (skip)
194 195 196 197 198
   *
   * Function with realloc semantics called to enlarge the buffer.
   *
   * Since: 2.24
   **/
199 200 201 202 203 204 205 206
  g_object_class_install_property (gobject_class,
                                   PROP_REALLOC_FUNCTION,
                                   g_param_spec_pointer ("realloc-function",
                                                         P_("Memory Reallocation Function"),
                                                         P_("Function with realloc semantics called to enlarge the buffer."),
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));

207
  /**
208
   * GMemoryOutputStream:destroy-function: (skip)
209 210 211 212 213
   *
   * Function called with the buffer as argument when the stream is destroyed.
   *
   * Since: 2.24
   **/
214 215 216 217 218 219 220 221 222
  g_object_class_install_property (gobject_class,
                                   PROP_DESTROY_FUNCTION,
                                   g_param_spec_pointer ("destroy-function",
                                                         P_("Destroy Notification Function"),
                                                         P_("Function called with the buffer as argument when the stream is destroyed."),
                                                         G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));
}

223 224 225 226 227 228 229
static void
g_memory_output_stream_pollable_iface_init (GPollableOutputStreamInterface *iface)
{
  iface->is_writable = g_memory_output_stream_is_writable;
  iface->create_source = g_memory_output_stream_create_source;
}

230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
static void
g_memory_output_stream_set_property (GObject      *object,
                                     guint         prop_id,
                                     const GValue *value,
                                     GParamSpec   *pspec)
{
  GMemoryOutputStream        *stream;
  GMemoryOutputStreamPrivate *priv;

  stream = G_MEMORY_OUTPUT_STREAM (object);
  priv = stream->priv;

  switch (prop_id)
    {
    case PROP_DATA:
      priv->data = g_value_get_pointer (value);
      break;
    case PROP_SIZE:
      priv->len = g_value_get_ulong (value);
      break;
    case PROP_REALLOC_FUNCTION:
      priv->realloc_fn = g_value_get_pointer (value);
      break;
    case PROP_DESTROY_FUNCTION:
      priv->destroy = g_value_get_pointer (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
g_memory_output_stream_get_property (GObject      *object,
                                     guint         prop_id,
                                     GValue       *value,
                                     GParamSpec   *pspec)
{
  GMemoryOutputStream        *stream;
  GMemoryOutputStreamPrivate *priv;

  stream = G_MEMORY_OUTPUT_STREAM (object);
  priv = stream->priv;

  switch (prop_id)
    {
    case PROP_DATA:
      g_value_set_pointer (value, priv->data);
      break;
    case PROP_SIZE:
      g_value_set_ulong (value, priv->len);
      break;
    case PROP_DATA_SIZE:
      g_value_set_ulong (value, priv->valid_len);
      break;
    case PROP_REALLOC_FUNCTION:
      g_value_set_pointer (value, priv->realloc_fn);
      break;
    case PROP_DESTROY_FUNCTION:
      g_value_set_pointer (value, priv->destroy);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
295 296 297 298 299 300
}

static void
g_memory_output_stream_finalize (GObject *object)
{
  GMemoryOutputStream        *stream;
301
  GMemoryOutputStreamPrivate *priv;
302 303

  stream = G_MEMORY_OUTPUT_STREAM (object);
304
  priv = stream->priv;
305
  
306 307
  if (priv->destroy)
    priv->destroy (priv->data);
308 309

  G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
310 311 312 313 314 315 316 317 318
}

static void
g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
{
  iface->tell         = g_memory_output_stream_tell;
  iface->can_seek     = g_memory_output_stream_can_seek;
  iface->seek         = g_memory_output_stream_seek;
  iface->can_truncate = g_memory_output_stream_can_truncate;
319
  iface->truncate_fn  = g_memory_output_stream_truncate;
320 321 322 323 324 325
}


static void
g_memory_output_stream_init (GMemoryOutputStream *stream)
{
326
  stream->priv = g_memory_output_stream_get_instance_private (stream);
327 328
  stream->priv->pos = 0;
  stream->priv->valid_len = 0;
329 330 331
}

/**
332
 * g_memory_output_stream_new: (skip)
333
 * @data: (nullable): pointer to a chunk of memory to use, or %NULL
334
 * @size: the size of @data
335
 * @realloc_function: (nullable): a function with realloc() semantics (like g_realloc())
336
 *     to be called when @data needs to be grown, or %NULL
337
 * @destroy_function: (nullable): a function to be called on @data when the stream is
338
 *     finalized, or %NULL
339
 *
340
 * Creates a new #GMemoryOutputStream.
341
 *
342 343 344 345 346
 * In most cases this is not the function you want.  See
 * g_memory_output_stream_new_resizable() instead.
 *
 * If @data is non-%NULL, the stream will use that for its internal storage.
 *
347
 * If @realloc_fn is non-%NULL, it will be used for resizing the internal
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
 * storage when necessary and the stream will be considered resizable.
 * In that case, the stream will start out being (conceptually) empty.
 * @size is used only as a hint for how big @data is.  Specifically,
 * seeking to the end of a newly-created stream will seek to zero, not
 * @size.  Seeking past the end of the stream and then writing will
 * introduce a zero-filled gap.
 *
 * If @realloc_fn is %NULL then the stream is fixed-sized.  Seeking to
 * the end will seek to @size exactly.  Writing past the end will give
 * an 'out of space' error.  Attempting to seek past the end will fail.
 * Unlike the resizable case, seeking to an offset within the stream and
 * writing will preserve the bytes passed in as @data before that point
 * and will return them as part of g_memory_output_stream_steal_data().
 * If you intend to seek you should probably therefore ensure that @data
 * is properly initialised.
 *
 * It is probably only meaningful to provide @data and @size in the case
 * that you want a fixed-sized stream.  Put another way: if @realloc_fn
 * is non-%NULL then it makes most sense to give @data as %NULL and
 * @size as 0 (allowing #GMemoryOutputStream to do the initial
 * allocation for itself).
369
 *
370
 * |[<!-- language="C" -->
Matthias Clasen's avatar
Matthias Clasen committed
371
 * // a stream that can grow
372
 * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
373
 *
Matthias Clasen's avatar
Matthias Clasen committed
374
 * // another stream that can grow
375 376
 * stream2 = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
 *
Matthias Clasen's avatar
Matthias Clasen committed
377
 * // a fixed-size stream
378
 * data = malloc (200);
379
 * stream3 = g_memory_output_stream_new (data, 200, NULL, free);
380
 * ]|
381
 *
382
 * Returns: A newly created #GMemoryOutputStream object.
383 384
 **/
GOutputStream *
385
g_memory_output_stream_new (gpointer       data,
386 387 388
                            gsize          size,
                            GReallocFunc   realloc_function,
                            GDestroyNotify destroy_function)
389 390 391
{
  GOutputStream *stream;

392 393 394 395 396 397
  stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM,
                         "data", data,
                         "size", size,
                         "realloc-function", realloc_function,
                         "destroy-function", destroy_function,
                         NULL);
398

399
  return stream;
400 401
}

402 403 404 405 406 407 408 409 410 411 412 413 414 415
/**
 * g_memory_output_stream_new_resizable:
 *
 * Creates a new #GMemoryOutputStream, using g_realloc() and g_free()
 * for memory allocation.
 *
 * Since: 2.36
 */
GOutputStream *
g_memory_output_stream_new_resizable (void)
{
  return g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
}

416
/**
417
 * g_memory_output_stream_get_data:
418 419
 * @ostream: a #GMemoryOutputStream
 *
420 421 422 423
 * Gets any loaded data from the @ostream.
 *
 * Note that the returned pointer may become invalid on the next
 * write or truncate operation on the stream.
424
 *
425 426
 * Returns: (transfer none): pointer to the stream's data, or %NULL if the data
 *    has been stolen
427
 **/
428
gpointer
429 430 431 432 433 434 435
g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
{
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);

  return ostream->priv->data;
}

436 437 438 439
/**
 * g_memory_output_stream_get_size:
 * @ostream: a #GMemoryOutputStream
 *
440
 * Gets the size of the currently allocated data area (available from
441 442 443 444 445 446 447
 * g_memory_output_stream_get_data()).
 *
 * You probably don't want to use this function on resizable streams.
 * See g_memory_output_stream_get_data_size() instead.  For resizable
 * streams the size returned by this function is an implementation
 * detail and may be change at any time in response to operations on the
 * stream.
448
 *
449 450 451
 * If the stream is fixed-sized (ie: no realloc was passed to
 * g_memory_output_stream_new()) then this is the maximum size of the
 * stream and further writes will return %G_IO_ERROR_NO_SPACE.
452
 *
453 454
 * In any case, if you want the number of bytes currently written to the
 * stream, use g_memory_output_stream_get_data_size().
455
 *
456
 * Returns: the number of bytes allocated for the data buffer
457 458 459 460 461
 */
gsize
g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
{
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
462

463 464
  return ostream->priv->len;
}
465

466 467 468 469
/**
 * g_memory_output_stream_get_data_size:
 * @ostream: a #GMemoryOutputStream
 *
470 471
 * Returns the number of bytes from the start up to including the last
 * byte written in the stream that has not been truncated away.
472
 *
473 474 475 476 477 478 479 480 481
 * Returns: the number of bytes written to the stream
 *
 * Since: 2.18
 */
gsize
g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
{
  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);

482
  return ostream->priv->valid_len;
483 484
}

485 486 487 488 489 490 491 492 493 494 495
/**
 * g_memory_output_stream_steal_data:
 * @ostream: a #GMemoryOutputStream
 *
 * Gets any loaded data from the @ostream. Ownership of the data
 * is transferred to the caller; when no longer needed it must be
 * freed using the free function set in @ostream's
 * #GMemoryOutputStream:destroy-function property.
 *
 * @ostream must be closed before calling this function.
 *
496 497
 * Returns: (transfer full): the stream's data, or %NULL if it has previously
 *    been stolen
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
 *
 * Since: 2.26
 **/
gpointer
g_memory_output_stream_steal_data (GMemoryOutputStream *ostream)
{
  gpointer data;

  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
  g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);

  data = ostream->priv->data;
  ostream->priv->data = NULL;

  return data;
}

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
/**
 * g_memory_output_stream_steal_as_bytes:
 * @ostream: a #GMemoryOutputStream
 *
 * Returns data from the @ostream as a #GBytes. @ostream must be
 * closed before calling this function.
 *
 * Returns: (transfer full): the stream's data
 *
 * Since: 2.34
 **/
GBytes *
g_memory_output_stream_steal_as_bytes (GMemoryOutputStream *ostream)
{
  GBytes *result;

  g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
  g_return_val_if_fail (g_output_stream_is_closed (G_OUTPUT_STREAM (ostream)), NULL);

  result = g_bytes_new_with_free_func (ostream->priv->data,
535 536 537
                                       ostream->priv->valid_len,
                                       ostream->priv->destroy,
                                       ostream->priv->data);
538
  ostream->priv->data = NULL;
539

540 541 542
  return result;
}

543 544 545
static gboolean
array_resize (GMemoryOutputStream  *ostream,
              gsize                 size,
546
              gboolean              allow_partial,
547 548 549
              GError              **error)
{
  GMemoryOutputStreamPrivate *priv;
550
  gpointer data;
551
  gsize len;
552

553
  priv = ostream->priv;
554

555 556
  if (priv->len == size)
    return TRUE;
557

558 559 560
  if (!priv->realloc_fn)
    {
      if (allow_partial &&
561 562 563
          priv->pos < priv->len)
        return TRUE; /* Short write */

564 565 566 567
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_NO_SPACE,
                           _("Memory output stream not resizable"));
568 569 570 571 572 573
      return FALSE;
    }

  len = priv->len;
  data = priv->realloc_fn (priv->data, size);

574
  if (size > 0 && !data)
575 576
    {
      if (allow_partial &&
577 578 579
          priv->pos < priv->len)
        return TRUE; /* Short write */

580 581 582 583
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_NO_SPACE,
                           _("Failed to resize memory output stream"));
584 585 586 587
      return FALSE;
    }

  if (size > len)
588
    memset ((guint8 *)data + len, 0, size - len);
589 590 591

  priv->data = data;
  priv->len = size;
592

593 594
  if (priv->len < priv->valid_len)
    priv->valid_len = priv->len;
595

596 597
  return TRUE;
}
598

599 600
static gsize
g_nearest_pow (gsize num)
601
{
602
  gsize n = 1;
603

604
  while (n < num && n > 0)
605
    n <<= 1;
606

607
  return n;
608 609 610
}

static gssize
611 612 613 614 615
g_memory_output_stream_write (GOutputStream  *stream,
                              const void     *buffer,
                              gsize           count,
                              GCancellable   *cancellable,
                              GError        **error)
616 617 618 619
{
  GMemoryOutputStream        *ostream;
  GMemoryOutputStreamPrivate *priv;
  guint8   *dest;
620
  gsize new_size;
621 622 623 624

  ostream = G_MEMORY_OUTPUT_STREAM (stream);
  priv = ostream->priv;

625 626
  if (count == 0)
    return 0;
627

628 629 630 631 632 633
  /* Check for address space overflow, but only if the buffer is resizable.
     Otherwise we just do a short write and don't worry. */
  if (priv->realloc_fn && priv->pos + count < priv->pos)
    goto overflow;

  if (priv->pos + count > priv->len)
634
    {
635 636 637 638 639 640 641 642
      /* At least enough to fit the write, rounded up for greater than
       * linear growth.
       *
       * Assuming that we're using something like realloc(), the kernel
       * will overcommit memory to us, so doubling the size each time
       * will keep the number of realloc calls low without wasting too
       * much memory.
       */
643
      new_size = g_nearest_pow (priv->pos + count);
644 645 646 647
      /* Check for overflow again. We have checked if
         pos + count > G_MAXSIZE, but now check if g_nearest_pow () has
         overflowed */
      if (new_size == 0)
648 649
        goto overflow;

650 651
      new_size = MAX (new_size, MIN_ARRAY_SIZE);
      if (!array_resize (ostream, new_size, TRUE, error))
652
        return -1;
653 654
    }

655 656 657
  /* Make sure we handle short writes if the array_resize
     only added part of the required memory */
  count = MIN (count, priv->len - priv->pos);
658

659
  dest = (guint8 *)priv->data + priv->pos;
660
  memcpy (dest, buffer, count);
661
  priv->pos += count;
662

663 664
  if (priv->pos > priv->valid_len)
    priv->valid_len = priv->pos;
665

666
  return count;
667 668 669 670 671 672 673 674 675

 overflow:
  /* Overflow: buffer size would need to be bigger than G_MAXSIZE. */
  g_set_error_literal (error,
                       G_IO_ERROR,
                       G_IO_ERROR_NO_SPACE,
                       _("Amount of memory required to process the write is "
                         "larger than available address space"));
  return -1;
676 677 678 679 680 681 682 683 684 685 686
}

static gboolean
g_memory_output_stream_close (GOutputStream  *stream,
                              GCancellable   *cancellable,
                              GError        **error)
{
  return TRUE;
}

static void
687 688 689 690 691
g_memory_output_stream_close_async (GOutputStream       *stream,
                                    int                  io_priority,
                                    GCancellable        *cancellable,
                                    GAsyncReadyCallback  callback,
                                    gpointer             data)
692
{
693
  GTask *task;
694

695
  task = g_task_new (stream, cancellable, callback, data);
696
  g_task_set_source_tag (task, g_memory_output_stream_close_async);
697 698 699

  /* will always return TRUE */
  g_memory_output_stream_close (stream, cancellable, NULL);
700

701 702
  g_task_return_boolean (task, TRUE);
  g_object_unref (task);
703 704 705
}

static gboolean
706 707 708
g_memory_output_stream_close_finish (GOutputStream  *stream,
                                     GAsyncResult   *result,
                                     GError        **error)
709
{
710
  g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
711

712
  return g_task_propagate_boolean (G_TASK (result), error);
713 714 715
}

static goffset
716
g_memory_output_stream_tell (GSeekable *seekable)
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
{
  GMemoryOutputStream *stream;
  GMemoryOutputStreamPrivate *priv;

  stream = G_MEMORY_OUTPUT_STREAM (seekable);
  priv = stream->priv;

  return priv->pos;
}

static gboolean
g_memory_output_stream_can_seek (GSeekable *seekable)
{
  return TRUE;
}

static gboolean
734
g_memory_output_stream_seek (GSeekable    *seekable,
735 736 737 738
                             goffset        offset,
                             GSeekType      type,
                             GCancellable  *cancellable,
                             GError       **error)
739 740 741 742 743 744 745 746
{
  GMemoryOutputStream        *stream;
  GMemoryOutputStreamPrivate *priv;
  goffset absolute;

  stream = G_MEMORY_OUTPUT_STREAM (seekable);
  priv = stream->priv;

747
  switch (type)
748
    {
749 750 751 752 753 754 755 756 757
    case G_SEEK_CUR:
      absolute = priv->pos + offset;
      break;

    case G_SEEK_SET:
      absolute = offset;
      break;

    case G_SEEK_END:
758 759 760 761 762 763 764 765
      /* For resizable streams, we consider the end to be the data
       * length.  For fixed-sized streams, we consider the end to be the
       * size of the buffer.
       */
      if (priv->realloc_fn)
        absolute = priv->valid_len + offset;
      else
        absolute = priv->len + offset;
766
      break;
767

768
    default:
769 770 771 772
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_INVALID_ARGUMENT,
                           _("Invalid GSeekType supplied"));
773 774

      return FALSE;
775
    }
776

777
  if (absolute < 0)
778
    {
779 780 781
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_INVALID_ARGUMENT,
782
                           _("Requested seek before the beginning of the stream"));
783 784
      return FALSE;
    }
785

786 787 788 789 790 791 792
  /* Can't seek past the end of a fixed-size stream.
   *
   * Note: seeking to the non-existent byte at the end of a fixed-sized
   * stream is valid (eg: a 1-byte fixed sized stream can have position
   * 0 or 1).  Therefore '>' is what we want.
   * */
  if (priv->realloc_fn == NULL && absolute > priv->len)
793 794 795 796 797 798 799
    {
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_INVALID_ARGUMENT,
                           _("Requested seek beyond the end of the stream"));
      return FALSE;
    }
800 801 802 803 804 805 806 807 808

  priv->pos = absolute;

  return TRUE;
}

static gboolean
g_memory_output_stream_can_truncate (GSeekable *seekable)
{
809 810 811 812 813 814
  GMemoryOutputStream *ostream;
  GMemoryOutputStreamPrivate *priv;

  ostream = G_MEMORY_OUTPUT_STREAM (seekable);
  priv = ostream->priv;

815
  /* We do not allow truncation of fixed-sized streams */
816
  return priv->realloc_fn != NULL;
817 818 819
}

static gboolean
820 821 822 823
g_memory_output_stream_truncate (GSeekable     *seekable,
                                 goffset        offset,
                                 GCancellable  *cancellable,
                                 GError       **error)
824
{
825
  GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
826

827
  if (!array_resize (ostream, offset, FALSE, error))
828
    return FALSE;
829

830 831
  ostream->priv->valid_len = offset;

832 833
  return TRUE;
}
834 835 836 837 838 839 840 841 842

static gboolean
g_memory_output_stream_is_writable (GPollableOutputStream *stream)
{
  return TRUE;
}

static GSource *
g_memory_output_stream_create_source (GPollableOutputStream *stream,
843
                                      GCancellable          *cancellable)
844 845 846 847
{
  GSource *base_source, *pollable_source;

  base_source = g_timeout_source_new (0);
848
  pollable_source = g_pollable_source_new_full (stream, base_source, cancellable);
849 850 851 852
  g_source_unref (base_source);

  return pollable_source;
}