gmemoryoutputstream.c 27.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/* 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
 * version 2 of the License, or (at your option) any later version.
 *
 * 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
 */

Alexander Larsson's avatar
Alexander Larsson committed
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

Alexander Larsson's avatar
Alexander Larsson committed
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);
Alexander Larsson's avatar
Alexander Larsson committed
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;
Alexander Larsson's avatar
Alexander Larsson committed
301
  GMemoryOutputStreamPrivate *priv;
302 303

  stream = G_MEMORY_OUTPUT_STREAM (object);
Alexander Larsson's avatar
Alexander Larsson committed
304
  priv = stream->priv;
305
  
Alexander Larsson's avatar
Alexander Larsson committed
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;
Alexander Larsson's avatar
Alexander Larsson committed
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: (allow-none): pointer to a chunk of memory to use, or %NULL
334
 * @size: the size of @data
335
 * @realloc_function: (allow-none): a function with realloc() semantics (like g_realloc())
Matthias Clasen's avatar
Matthias Clasen committed
336
 *     to be called when @data needs to be grown, or %NULL
337
 * @destroy_function: (allow-none): a function to be called on @data when the stream is
338
 *     finalized, or %NULL
Alexander Larsson's avatar
Alexander Larsson committed
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.
 *
Alexander Larsson's avatar
Alexander Larsson committed
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).
Matthias Clasen's avatar
Matthias Clasen committed
369
 *
370
 * |[<!-- language="C" -->
Matthias Clasen's avatar
Matthias Clasen committed
371
 * // a stream that can grow
Alexander Larsson's avatar
Alexander Larsson committed
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
Matthias Clasen's avatar
Matthias Clasen committed
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
Alexander Larsson's avatar
Alexander Larsson committed
378
 * data = malloc (200);
Matthias Clasen's avatar
Matthias Clasen committed
379
 * stream3 = g_memory_output_stream_new (data, 200, NULL, free);
Alexander Larsson's avatar
Alexander Larsson committed
380
 * ]|
381
 *
382
 * Returns: A newly created #GMemoryOutputStream object.
383 384
 **/
GOutputStream *
Alexander Larsson's avatar
Alexander Larsson committed
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

Alexander Larsson's avatar
Alexander Larsson committed
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.
Alexander Larsson's avatar
Alexander Larsson committed
424
 *
425 426
 * Returns: (transfer none): pointer to the stream's data, or %NULL if the data
 *    has been stolen
427
 **/
Alexander Larsson's avatar
Alexander Larsson committed
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;
}

Alexander Larsson's avatar
Alexander Larsson committed
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.
Alexander Larsson's avatar
Alexander Larsson committed
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.
Alexander Larsson's avatar
Alexander Larsson committed
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
Alexander Larsson's avatar
Alexander Larsson committed
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

Alexander Larsson's avatar
Alexander Larsson committed
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;
}

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

Alexander Larsson's avatar
Alexander Larsson committed
553
  priv = ostream->priv;
554

Alexander Larsson's avatar
Alexander Larsson committed
555 556
  if (priv->len == size)
    return TRUE;
557

Alexander Larsson's avatar
Alexander Larsson committed
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"));
Alexander Larsson's avatar
Alexander Larsson committed
568 569 570 571 572 573
      return FALSE;
    }

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

574
  if (size > 0 && !data)
Alexander Larsson's avatar
Alexander Larsson committed
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"));
Alexander Larsson's avatar
Alexander Larsson committed
584 585 586 587
      return FALSE;
    }

  if (size > len)
588
    memset ((guint8 *)data + len, 0, size - len);
Alexander Larsson's avatar
Alexander Larsson committed
589 590 591

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

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

Alexander Larsson's avatar
Alexander Larsson committed
596 597
  return TRUE;
}
598

599 600
static gsize
g_nearest_pow (gsize num)
Alexander Larsson's avatar
Alexander Larsson committed
601
{
602
  gsize n = 1;
603

604
  while (n < num && n > 0)
Alexander Larsson's avatar
Alexander Larsson committed
605
    n <<= 1;
606

Alexander Larsson's avatar
Alexander Larsson committed
607
  return n;
608 609 610
}

static gssize
Matthias Clasen's avatar
Matthias Clasen committed
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;
Alexander Larsson's avatar
Alexander Larsson committed
620
  gsize new_size;
621 622 623 624

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

Alexander Larsson's avatar
Alexander Larsson committed
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.
       */
Alexander Larsson's avatar
Alexander Larsson committed
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;

Alexander Larsson's avatar
Alexander Larsson committed
650 651
      new_size = MAX (new_size, MIN_ARRAY_SIZE);
      if (!array_resize (ostream, new_size, TRUE, error))
652
        return -1;
653 654
    }

Alexander Larsson's avatar
Alexander Larsson committed
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);
Alexander Larsson's avatar
Alexander Larsson committed
661
  priv->pos += count;
662

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

Alexander Larsson's avatar
Alexander Larsson committed
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
Alexander Larsson's avatar
Alexander Larsson committed
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 697 698

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

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

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
705 706 707
g_memory_output_stream_close_finish (GOutputStream  *stream,
                                     GAsyncResult   *result,
                                     GError        **error)
708
{
709
  g_return_val_if_fail (g_task_is_valid (result, stream), FALSE);
710

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

static goffset
Matthias Clasen's avatar
Matthias Clasen committed
715
g_memory_output_stream_tell (GSeekable *seekable)
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732
{
  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
Matthias Clasen's avatar
Matthias Clasen committed
733
g_memory_output_stream_seek (GSeekable    *seekable,
734 735 736 737
                             goffset        offset,
                             GSeekType      type,
                             GCancellable  *cancellable,
                             GError       **error)
738 739 740 741 742 743 744 745
{
  GMemoryOutputStream        *stream;
  GMemoryOutputStreamPrivate *priv;
  goffset absolute;

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

746
  switch (type)
Matthias Clasen's avatar
Matthias Clasen committed
747
    {
748 749 750 751 752 753 754 755 756
    case G_SEEK_CUR:
      absolute = priv->pos + offset;
      break;

    case G_SEEK_SET:
      absolute = offset;
      break;

    case G_SEEK_END:
757 758 759 760 761 762 763 764
      /* 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;
765
      break;
766

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

      return FALSE;
Matthias Clasen's avatar
Matthias Clasen committed
774
    }
775

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

785 786 787 788 789 790 791
  /* 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)
792 793 794 795 796 797 798
    {
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_INVALID_ARGUMENT,
                           _("Requested seek beyond the end of the stream"));
      return FALSE;
    }
799 800 801 802 803 804 805 806 807

  priv->pos = absolute;

  return TRUE;
}

static gboolean
g_memory_output_stream_can_truncate (GSeekable *seekable)
{
Alexander Larsson's avatar
Alexander Larsson committed
808 809 810 811 812 813
  GMemoryOutputStream *ostream;
  GMemoryOutputStreamPrivate *priv;

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

814
  /* We do not allow truncation of fixed-sized streams */
Alexander Larsson's avatar
Alexander Larsson committed
815
  return priv->realloc_fn != NULL;
816 817 818
}

static gboolean
Matthias Clasen's avatar
Matthias Clasen committed
819 820 821 822
g_memory_output_stream_truncate (GSeekable     *seekable,
                                 goffset        offset,
                                 GCancellable  *cancellable,
                                 GError       **error)
823
{
Matthias Clasen's avatar
Matthias Clasen committed
824
  GMemoryOutputStream *ostream = G_MEMORY_OUTPUT_STREAM (seekable);
825

Alexander Larsson's avatar
Alexander Larsson committed
826
  if (!array_resize (ostream, offset, FALSE, error))
Matthias Clasen's avatar
Matthias Clasen committed
827
    return FALSE;
828

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

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

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

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

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

  return pollable_source;
}