Home | History | Annotate | Download | only in gio
      1 /* GIO - GLib Input, Output and Streaming Library
      2  *
      3  * Copyright (C) 2006-2007 Red Hat, Inc.
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Lesser General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2 of the License, or (at your option) any later version.
      9  *
     10  * This library is distributed in the hope that it will be useful,
     11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13  * Lesser General Public License for more details.
     14  *
     15  * You should have received a copy of the GNU Lesser General
     16  * Public License along with this library; if not, write to the
     17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     18  * Boston, MA 02111-1307, USA.
     19  *
     20  * Author: Christian Kellner <gicmo (at) gnome.org>
     21  */
     22 
     23 #include "config.h"
     24 #include "gmemoryoutputstream.h"
     25 #include "goutputstream.h"
     26 #include "gseekable.h"
     27 #include "gsimpleasyncresult.h"
     28 #include "gioerror.h"
     29 #include "string.h"
     30 #include "glibintl.h"
     31 
     32 #include "gioalias.h"
     33 
     34 /**
     35  * SECTION:gmemoryoutputstream
     36  * @short_description: Streaming output operations on memory chunks
     37  * @include: gio/gio.h
     38  * @see_also: #GMemoryInputStream
     39  *
     40  * #GMemoryOutputStream is a class for using arbitrary
     41  * memory chunks as output for GIO streaming output operations.
     42  *
     43  */
     44 
     45 #define MIN_ARRAY_SIZE  16
     46 
     47 struct _GMemoryOutputStreamPrivate {
     48 
     49   gpointer       data;
     50   gsize          len;
     51   gsize          valid_len; /* The part of data that has been written to */
     52 
     53   goffset        pos;
     54 
     55   GReallocFunc   realloc_fn;
     56   GDestroyNotify destroy;
     57 };
     58 
     59 static void     g_memory_output_stream_finalize     (GObject      *object);
     60 
     61 static gssize   g_memory_output_stream_write       (GOutputStream *stream,
     62                                                     const void    *buffer,
     63                                                     gsize          count,
     64                                                     GCancellable  *cancellable,
     65                                                     GError       **error);
     66 
     67 static gboolean g_memory_output_stream_close       (GOutputStream  *stream,
     68                                                     GCancellable   *cancellable,
     69                                                     GError        **error);
     70 
     71 static void     g_memory_output_stream_write_async  (GOutputStream        *stream,
     72                                                      const void           *buffer,
     73                                                      gsize                 count,
     74                                                      int                   io_priority,
     75                                                      GCancellable         *cancellable,
     76                                                      GAsyncReadyCallback   callback,
     77                                                      gpointer              data);
     78 static gssize   g_memory_output_stream_write_finish (GOutputStream        *stream,
     79                                                      GAsyncResult         *result,
     80                                                      GError              **error);
     81 static void     g_memory_output_stream_close_async  (GOutputStream        *stream,
     82                                                      int                   io_priority,
     83                                                      GCancellable         *cancellable,
     84                                                      GAsyncReadyCallback   callback,
     85                                                      gpointer              data);
     86 static gboolean g_memory_output_stream_close_finish (GOutputStream        *stream,
     87                                                      GAsyncResult         *result,
     88                                                      GError              **error);
     89 
     90 static void     g_memory_output_stream_seekable_iface_init (GSeekableIface  *iface);
     91 static goffset  g_memory_output_stream_tell                (GSeekable       *seekable);
     92 static gboolean g_memory_output_stream_can_seek            (GSeekable       *seekable);
     93 static gboolean g_memory_output_stream_seek                (GSeekable       *seekable,
     94                                                            goffset          offset,
     95                                                            GSeekType        type,
     96                                                            GCancellable    *cancellable,
     97                                                            GError         **error);
     98 static gboolean g_memory_output_stream_can_truncate        (GSeekable       *seekable);
     99 static gboolean g_memory_output_stream_truncate            (GSeekable       *seekable,
    100                                                            goffset          offset,
    101                                                            GCancellable    *cancellable,
    102                                                            GError         **error);
    103 
    104 G_DEFINE_TYPE_WITH_CODE (GMemoryOutputStream, g_memory_output_stream, G_TYPE_OUTPUT_STREAM,
    105                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
    106                                                 g_memory_output_stream_seekable_iface_init))
    107 
    108 
    109 static void
    110 g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass)
    111 {
    112   GOutputStreamClass *ostream_class;
    113   GObjectClass *gobject_class;
    114 
    115   g_type_class_add_private (klass, sizeof (GMemoryOutputStreamPrivate));
    116 
    117   gobject_class = G_OBJECT_CLASS (klass);
    118   gobject_class->finalize = g_memory_output_stream_finalize;
    119 
    120   ostream_class = G_OUTPUT_STREAM_CLASS (klass);
    121 
    122   ostream_class->write_fn = g_memory_output_stream_write;
    123   ostream_class->close_fn = g_memory_output_stream_close;
    124   ostream_class->write_async  = g_memory_output_stream_write_async;
    125   ostream_class->write_finish = g_memory_output_stream_write_finish;
    126   ostream_class->close_async  = g_memory_output_stream_close_async;
    127   ostream_class->close_finish = g_memory_output_stream_close_finish;
    128 }
    129 
    130 static void
    131 g_memory_output_stream_finalize (GObject *object)
    132 {
    133   GMemoryOutputStream        *stream;
    134   GMemoryOutputStreamPrivate *priv;
    135 
    136   stream = G_MEMORY_OUTPUT_STREAM (object);
    137   priv = stream->priv;
    138 
    139   if (priv->destroy)
    140     priv->destroy (priv->data);
    141 
    142   G_OBJECT_CLASS (g_memory_output_stream_parent_class)->finalize (object);
    143 }
    144 
    145 static void
    146 g_memory_output_stream_seekable_iface_init (GSeekableIface *iface)
    147 {
    148   iface->tell         = g_memory_output_stream_tell;
    149   iface->can_seek     = g_memory_output_stream_can_seek;
    150   iface->seek         = g_memory_output_stream_seek;
    151   iface->can_truncate = g_memory_output_stream_can_truncate;
    152   iface->truncate_fn  = g_memory_output_stream_truncate;
    153 }
    154 
    155 
    156 static void
    157 g_memory_output_stream_init (GMemoryOutputStream *stream)
    158 {
    159   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
    160                                               G_TYPE_MEMORY_OUTPUT_STREAM,
    161                                               GMemoryOutputStreamPrivate);
    162 }
    163 
    164 /**
    165  * g_memory_output_stream_new:
    166  * @data: pointer to a chunk of memory to use, or %NULL
    167  * @len: the size of @data
    168  * @realloc_fn: a function with realloc() semantics to be called when
    169  *     @data needs to be grown, or %NULL
    170  * @destroy: a function to be called on @data when the stream is finalized,
    171  *     or %NULL
    172  *
    173  * Creates a new #GMemoryOutputStream.
    174  *
    175  * If @data is non-%NULL, the stream  will use that for its internal storage.
    176  * If @realloc_fn is non-%NULL, it will be used for resizing the internal
    177  * storage when necessary. To construct a fixed-size output stream,
    178  * pass %NULL as @realloc_fn.
    179  * |[
    180  * /&ast; a stream that can grow &ast;/
    181  * stream = g_memory_output_stream_new (NULL, 0, realloc, free);
    182  *
    183  * /&ast; a fixed-size stream &ast;/
    184  * data = malloc (200);
    185  * stream2 = g_memory_output_stream_new (data, 200, NULL, free);
    186  * ]|
    187  *
    188  * Return value: A newly created #GMemoryOutputStream object.
    189  **/
    190 GOutputStream *
    191 g_memory_output_stream_new (gpointer       data,
    192                             gsize          len,
    193                             GReallocFunc   realloc_fn,
    194                             GDestroyNotify destroy)
    195 {
    196   GOutputStream *stream;
    197   GMemoryOutputStreamPrivate *priv;
    198 
    199   stream = g_object_new (G_TYPE_MEMORY_OUTPUT_STREAM, NULL);
    200 
    201   priv = G_MEMORY_OUTPUT_STREAM (stream)->priv;
    202 
    203   priv->data = data;
    204   priv->len = len;
    205   priv->realloc_fn = realloc_fn;
    206   priv->destroy = destroy;
    207 
    208   priv->pos = 0;
    209   priv->valid_len = 0;
    210 
    211   return stream;
    212 }
    213 
    214 /**
    215  * g_memory_output_stream_get_data:
    216  * @ostream: a #GMemoryOutputStream
    217  *
    218  * Gets any loaded data from the @ostream.
    219  *
    220  * Note that the returned pointer may become invalid on the next
    221  * write or truncate operation on the stream.
    222  *
    223  * Returns: pointer to the stream's data
    224  **/
    225 gpointer
    226 g_memory_output_stream_get_data (GMemoryOutputStream *ostream)
    227 {
    228   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), NULL);
    229 
    230   return ostream->priv->data;
    231 }
    232 
    233 /**
    234  * g_memory_output_stream_get_size:
    235  * @ostream: a #GMemoryOutputStream
    236  *
    237  * Gets the size of the currently allocated data area (availible from
    238  * g_memory_output_stream_get_data()). If the stream isn't
    239  * growable (no realloc was passed to g_memory_output_stream_new()) then
    240  * this is the maximum size of the stream and further writes
    241  * will return %G_IO_ERROR_NO_SPACE.
    242  *
    243  * Note that for growable streams the returned size may become invalid on
    244  * the next write or truncate operation on the stream.
    245  *
    246  * If you want the number of bytes currently written to the stream, use
    247  * g_memory_output_stream_get_data_size().
    248  *
    249  * Returns: the number of bytes allocated for the data buffer
    250  */
    251 gsize
    252 g_memory_output_stream_get_size (GMemoryOutputStream *ostream)
    253 {
    254   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
    255 
    256   return ostream->priv->len;
    257 }
    258 
    259 /**
    260  * g_memory_output_stream_get_data_size:
    261  * @ostream: a #GMemoryOutputStream
    262  *
    263  * Returns the number of bytes from the start up
    264  * to including the last byte written in the stream
    265  * that has not been truncated away.
    266  *
    267  * Returns: the number of bytes written to the stream
    268  *
    269  * Since: 2.18
    270  */
    271 gsize
    272 g_memory_output_stream_get_data_size (GMemoryOutputStream *ostream)
    273 {
    274   g_return_val_if_fail (G_IS_MEMORY_OUTPUT_STREAM (ostream), 0);
    275 
    276   return ostream->priv->valid_len;
    277 }
    278 
    279 
    280 static gboolean
    281 array_check_boundary (GMemoryOutputStream  *stream,
    282                       goffset               size,
    283                       GError              **error)
    284 {
    285   if (size > G_MAXUINT)
    286     {
    287       g_set_error_literal (error,
    288                            G_IO_ERROR,
    289                            G_IO_ERROR_FAILED,
    290                            _("Reached maximum data array limit"));
    291 
    292       return FALSE;
    293     }
    294 
    295   return TRUE;
    296 }
    297 
    298 static gboolean
    299 array_resize (GMemoryOutputStream  *ostream,
    300               gsize                 size,
    301 	      gboolean              allow_partial,
    302               GError              **error)
    303 {
    304   GMemoryOutputStreamPrivate *priv;
    305   gpointer data;
    306   gsize len;
    307 
    308   priv = ostream->priv;
    309 
    310   if (!array_check_boundary (ostream, size, error))
    311     return FALSE;
    312 
    313   if (priv->len == size)
    314     return TRUE;
    315 
    316   if (!priv->realloc_fn)
    317     {
    318       if (allow_partial &&
    319 	  priv->pos < priv->len)
    320 	return TRUE; /* Short write */
    321 
    322       g_set_error_literal (error,
    323                            G_IO_ERROR,
    324                            G_IO_ERROR_NO_SPACE,
    325                            _("Memory output stream not resizable"));
    326       return FALSE;
    327     }
    328 
    329   len = priv->len;
    330   data = priv->realloc_fn (priv->data, size);
    331 
    332   if (size > 0 && !data)
    333     {
    334       if (allow_partial &&
    335 	  priv->pos < priv->len)
    336 	return TRUE; /* Short write */
    337 
    338       g_set_error_literal (error,
    339                            G_IO_ERROR,
    340                            G_IO_ERROR_NO_SPACE,
    341                            _("Failed to resize memory output stream"));
    342       return FALSE;
    343     }
    344 
    345   if (size > len)
    346     memset ((guint8 *)data + len, 0, size - len);
    347 
    348   priv->data = data;
    349   priv->len = size;
    350 
    351   if (priv->len < priv->valid_len)
    352     priv->valid_len = priv->len;
    353 
    354   return TRUE;
    355 }
    356 
    357 static gint
    358 g_nearest_pow (gint num)
    359 {
    360   gint n = 1;
    361 
    362   while (n < num)
    363     n <<= 1;
    364 
    365   return n;
    366 }
    367 
    368 static gssize
    369 g_memory_output_stream_write (GOutputStream  *stream,
    370                               const void     *buffer,
    371                               gsize           count,
    372                               GCancellable   *cancellable,
    373                               GError        **error)
    374 {
    375   GMemoryOutputStream        *ostream;
    376   GMemoryOutputStreamPrivate *priv;
    377   guint8   *dest;
    378   gsize new_size;
    379 
    380   ostream = G_MEMORY_OUTPUT_STREAM (stream);
    381   priv = ostream->priv;
    382 
    383   if (count == 0)
    384     return 0;
    385 
    386   if (priv->pos + count > priv->len)
    387     {
    388       /* At least enought to fit the write, rounded up
    389 	 for greater than linear growth */
    390       new_size = g_nearest_pow (priv->pos + count);
    391       new_size = MAX (new_size, MIN_ARRAY_SIZE);
    392 
    393       if (!array_resize (ostream, new_size, TRUE, error))
    394 	return -1;
    395     }
    396 
    397   /* Make sure we handle short writes if the array_resize
    398      only added part of the required memory */
    399   count = MIN (count, priv->len - priv->pos);
    400 
    401   dest = (guint8 *)priv->data + priv->pos;
    402   memcpy (dest, buffer, count);
    403   priv->pos += count;
    404 
    405   if (priv->pos > priv->valid_len)
    406     priv->valid_len = priv->pos;
    407 
    408   return count;
    409 }
    410 
    411 static gboolean
    412 g_memory_output_stream_close (GOutputStream  *stream,
    413                               GCancellable   *cancellable,
    414                               GError        **error)
    415 {
    416   return TRUE;
    417 }
    418 
    419 static void
    420 g_memory_output_stream_write_async (GOutputStream       *stream,
    421                                     const void          *buffer,
    422                                     gsize                count,
    423                                     int                  io_priority,
    424                                     GCancellable        *cancellable,
    425                                     GAsyncReadyCallback  callback,
    426                                     gpointer             data)
    427 {
    428   GSimpleAsyncResult *simple;
    429   gssize nwritten;
    430 
    431   nwritten = g_memory_output_stream_write (stream,
    432                                            buffer,
    433                                            count,
    434                                            cancellable,
    435                                            NULL);
    436 
    437 
    438   simple = g_simple_async_result_new (G_OBJECT (stream),
    439                                       callback,
    440                                       data,
    441                                       g_memory_output_stream_write_async);
    442 
    443   g_simple_async_result_set_op_res_gssize (simple, nwritten);
    444   g_simple_async_result_complete_in_idle (simple);
    445   g_object_unref (simple);
    446 }
    447 
    448 static gssize
    449 g_memory_output_stream_write_finish (GOutputStream  *stream,
    450                                      GAsyncResult   *result,
    451                                      GError        **error)
    452 {
    453   GSimpleAsyncResult *simple;
    454   gssize nwritten;
    455 
    456   simple = G_SIMPLE_ASYNC_RESULT (result);
    457 
    458   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
    459                   g_memory_output_stream_write_async);
    460 
    461   nwritten = g_simple_async_result_get_op_res_gssize (simple);
    462 
    463   return nwritten;
    464 }
    465 
    466 static void
    467 g_memory_output_stream_close_async (GOutputStream       *stream,
    468                                     int                  io_priority,
    469                                     GCancellable        *cancellable,
    470                                     GAsyncReadyCallback  callback,
    471                                     gpointer             data)
    472 {
    473   GSimpleAsyncResult *simple;
    474 
    475   simple = g_simple_async_result_new (G_OBJECT (stream),
    476                                       callback,
    477                                       data,
    478                                       g_memory_output_stream_close_async);
    479 
    480 
    481   /* will always return TRUE */
    482   g_memory_output_stream_close (stream, cancellable, NULL);
    483 
    484   g_simple_async_result_complete_in_idle (simple);
    485   g_object_unref (simple);
    486 }
    487 
    488 static gboolean
    489 g_memory_output_stream_close_finish (GOutputStream  *stream,
    490                                      GAsyncResult   *result,
    491                                      GError        **error)
    492 {
    493   GSimpleAsyncResult *simple;
    494 
    495   simple = G_SIMPLE_ASYNC_RESULT (result);
    496 
    497   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
    498                   g_memory_output_stream_close_async);
    499 
    500   return TRUE;
    501 }
    502 
    503 static goffset
    504 g_memory_output_stream_tell (GSeekable *seekable)
    505 {
    506   GMemoryOutputStream *stream;
    507   GMemoryOutputStreamPrivate *priv;
    508 
    509   stream = G_MEMORY_OUTPUT_STREAM (seekable);
    510   priv = stream->priv;
    511 
    512   return priv->pos;
    513 }
    514 
    515 static gboolean
    516 g_memory_output_stream_can_seek (GSeekable *seekable)
    517 {
    518   return TRUE;
    519 }
    520 
    521 static gboolean
    522 g_memory_output_stream_seek (GSeekable    *seekable,
    523                             goffset        offset,
    524                             GSeekType      type,
    525                             GCancellable  *cancellable,
    526                             GError       **error)
    527 {
    528   GMemoryOutputStream        *stream;
    529   GMemoryOutputStreamPrivate *priv;
    530   goffset absolute;
    531 
    532   stream = G_MEMORY_OUTPUT_STREAM (seekable);
    533   priv = stream->priv;
    534 
    535   switch (type)
    536     {
    537     case G_SEEK_CUR:
    538       absolute = priv->pos + offset;
    539       break;
    540 
    541     case G_SEEK_SET:
    542       absolute = offset;
    543       break;
    544 
    545     case G_SEEK_END:
    546       absolute = priv->len + offset;
    547       break;
    548 
    549     default:
    550       g_set_error_literal (error,
    551                            G_IO_ERROR,
    552                            G_IO_ERROR_INVALID_ARGUMENT,
    553                            _("Invalid GSeekType supplied"));
    554 
    555       return FALSE;
    556     }
    557 
    558   if (absolute < 0)
    559     {
    560       g_set_error_literal (error,
    561                            G_IO_ERROR,
    562                            G_IO_ERROR_INVALID_ARGUMENT,
    563                            _("Invalid seek request"));
    564       return FALSE;
    565     }
    566 
    567   if (!array_check_boundary (stream, absolute, error))
    568     return FALSE;
    569 
    570   priv->pos = absolute;
    571 
    572   return TRUE;
    573 }
    574 
    575 static gboolean
    576 g_memory_output_stream_can_truncate (GSeekable *seekable)
    577 {
    578   GMemoryOutputStream *ostream;
    579   GMemoryOutputStreamPrivate *priv;
    580 
    581   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
    582   priv = ostream->priv;
    583 
    584   return priv->realloc_fn != NULL;
    585 }
    586 
    587 static gboolean
    588 g_memory_output_stream_truncate (GSeekable     *seekable,
    589                                  goffset        offset,
    590                                  GCancellable  *cancellable,
    591                                  GError       **error)
    592 {
    593   GMemoryOutputStream *ostream;
    594   GMemoryOutputStreamPrivate *priv;
    595 
    596   ostream = G_MEMORY_OUTPUT_STREAM (seekable);
    597   priv = ostream->priv;
    598 
    599   if (!array_resize (ostream, offset, FALSE, error))
    600     return FALSE;
    601 
    602   return TRUE;
    603 }
    604 
    605 #define __G_MEMORY_OUTPUT_STREAM_C__
    606 #include "gioaliasdef.c"
    607