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 "gmemoryinputstream.h"
     25 #include "ginputstream.h"
     26 #include "gseekable.h"
     27 #include "string.h"
     28 #include "gsimpleasyncresult.h"
     29 #include "gioerror.h"
     30 #include "glibintl.h"
     31 
     32 #include "gioalias.h"
     33 
     34 /**
     35  * SECTION:gmemoryinputstream
     36  * @short_description: Streaming input operations on memory chunks
     37  * @include: gio/gio.h
     38  * @see_also: #GMemoryOutputStream
     39  *
     40  * #GMemoryInputStream is a class for using arbitrary
     41  * memory chunks as input for GIO streaming input operations.
     42  *
     43  */
     44 
     45 typedef struct _Chunk Chunk;
     46 
     47 struct _Chunk {
     48   guint8         *data;
     49   gsize           len;
     50   GDestroyNotify  destroy;
     51 };
     52 
     53 struct _GMemoryInputStreamPrivate {
     54   GSList *chunks;
     55   gsize   len;
     56   gsize   pos;
     57 };
     58 
     59 static gssize   g_memory_input_stream_read         (GInputStream         *stream,
     60 						    void                 *buffer,
     61 						    gsize                 count,
     62 						    GCancellable         *cancellable,
     63 						    GError              **error);
     64 static gssize   g_memory_input_stream_skip         (GInputStream         *stream,
     65 						    gsize                 count,
     66 						    GCancellable         *cancellable,
     67 						    GError              **error);
     68 static gboolean g_memory_input_stream_close        (GInputStream         *stream,
     69 						    GCancellable         *cancellable,
     70 						    GError              **error);
     71 static void     g_memory_input_stream_read_async   (GInputStream         *stream,
     72 						    void                 *buffer,
     73 						    gsize                 count,
     74 						    int                   io_priority,
     75 						    GCancellable         *cancellable,
     76 						    GAsyncReadyCallback   callback,
     77 						    gpointer              user_data);
     78 static gssize   g_memory_input_stream_read_finish  (GInputStream         *stream,
     79 						    GAsyncResult         *result,
     80 						    GError              **error);
     81 static void     g_memory_input_stream_skip_async   (GInputStream         *stream,
     82 						    gsize                 count,
     83 						    int                   io_priority,
     84 						    GCancellable         *cancellabl,
     85 						    GAsyncReadyCallback   callback,
     86 						    gpointer              datae);
     87 static gssize   g_memory_input_stream_skip_finish  (GInputStream         *stream,
     88 						    GAsyncResult         *result,
     89 						    GError              **error);
     90 static void     g_memory_input_stream_close_async  (GInputStream         *stream,
     91 						    int                   io_priority,
     92 						    GCancellable         *cancellabl,
     93 						    GAsyncReadyCallback   callback,
     94 						    gpointer              data);
     95 static gboolean g_memory_input_stream_close_finish (GInputStream         *stream,
     96 						    GAsyncResult         *result,
     97 						    GError              **error);
     98 
     99 static void     g_memory_input_stream_seekable_iface_init (GSeekableIface  *iface);
    100 static goffset  g_memory_input_stream_tell                (GSeekable       *seekable);
    101 static gboolean g_memory_input_stream_can_seek            (GSeekable       *seekable);
    102 static gboolean g_memory_input_stream_seek                (GSeekable       *seekable,
    103                                                            goffset          offset,
    104                                                            GSeekType        type,
    105                                                            GCancellable    *cancellable,
    106                                                            GError         **error);
    107 static gboolean g_memory_input_stream_can_truncate        (GSeekable       *seekable);
    108 static gboolean g_memory_input_stream_truncate            (GSeekable       *seekable,
    109                                                            goffset          offset,
    110                                                            GCancellable    *cancellable,
    111                                                            GError         **error);
    112 static void     g_memory_input_stream_finalize            (GObject         *object);
    113 
    114 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
    115                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
    116                                                 g_memory_input_stream_seekable_iface_init))
    117 
    118 
    119 static void
    120 g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
    121 {
    122   GObjectClass *object_class;
    123   GInputStreamClass *istream_class;
    124 
    125   g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
    126 
    127   object_class = G_OBJECT_CLASS (klass);
    128   object_class->finalize     = g_memory_input_stream_finalize;
    129 
    130   istream_class = G_INPUT_STREAM_CLASS (klass);
    131   istream_class->read_fn  = g_memory_input_stream_read;
    132   istream_class->skip  = g_memory_input_stream_skip;
    133   istream_class->close_fn = g_memory_input_stream_close;
    134 
    135   istream_class->read_async  = g_memory_input_stream_read_async;
    136   istream_class->read_finish  = g_memory_input_stream_read_finish;
    137   istream_class->skip_async  = g_memory_input_stream_skip_async;
    138   istream_class->skip_finish  = g_memory_input_stream_skip_finish;
    139   istream_class->close_async = g_memory_input_stream_close_async;
    140   istream_class->close_finish = g_memory_input_stream_close_finish;
    141 }
    142 
    143 static void
    144 free_chunk (gpointer data,
    145             gpointer user_data)
    146 {
    147   Chunk *chunk = data;
    148 
    149   if (chunk->destroy)
    150     chunk->destroy (chunk->data);
    151 
    152   g_slice_free (Chunk, chunk);
    153 }
    154 
    155 static void
    156 g_memory_input_stream_finalize (GObject *object)
    157 {
    158   GMemoryInputStream        *stream;
    159   GMemoryInputStreamPrivate *priv;
    160 
    161   stream = G_MEMORY_INPUT_STREAM (object);
    162   priv = stream->priv;
    163 
    164   g_slist_foreach (priv->chunks, free_chunk, NULL);
    165   g_slist_free (priv->chunks);
    166 
    167   G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
    168 }
    169 
    170 static void
    171 g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
    172 {
    173   iface->tell         = g_memory_input_stream_tell;
    174   iface->can_seek     = g_memory_input_stream_can_seek;
    175   iface->seek         = g_memory_input_stream_seek;
    176   iface->can_truncate = g_memory_input_stream_can_truncate;
    177   iface->truncate_fn  = g_memory_input_stream_truncate;
    178 }
    179 
    180 static void
    181 g_memory_input_stream_init (GMemoryInputStream *stream)
    182 {
    183   stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
    184                                               G_TYPE_MEMORY_INPUT_STREAM,
    185                                               GMemoryInputStreamPrivate);
    186 }
    187 
    188 /**
    189  * g_memory_input_stream_new:
    190  *
    191  * Creates a new empty #GMemoryInputStream.
    192  *
    193  * Returns: a new #GInputStream
    194  */
    195 GInputStream *
    196 g_memory_input_stream_new (void)
    197 {
    198   GInputStream *stream;
    199 
    200   stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
    201 
    202   return stream;
    203 }
    204 
    205 /**
    206  * g_memory_input_stream_new_from_data:
    207  * @data: input data
    208  * @len: length of the data, may be -1 if @data is a nul-terminated string
    209  * @destroy: function that is called to free @data, or %NULL
    210  *
    211  * Creates a new #GMemoryInputStream with data in memory of a given size.
    212  *
    213  * Returns: new #GInputStream read from @data of @len bytes.
    214  **/
    215 GInputStream *
    216 g_memory_input_stream_new_from_data (const void     *data,
    217                                      gssize          len,
    218                                      GDestroyNotify  destroy)
    219 {
    220   GInputStream *stream;
    221 
    222   stream = g_memory_input_stream_new ();
    223 
    224   g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
    225                                   data, len, destroy);
    226 
    227   return stream;
    228 }
    229 
    230 /**
    231  * g_memory_input_stream_add_data:
    232  * @stream: a #GMemoryInputStream
    233  * @data: input data
    234  * @len: length of the data, may be -1 if @data is a nul-terminated string
    235  * @destroy: function that is called to free @data, or %NULL
    236  *
    237  * Appends @data to data that can be read from the input stream
    238  */
    239 void
    240 g_memory_input_stream_add_data (GMemoryInputStream *stream,
    241                                 const void         *data,
    242                                 gssize              len,
    243                                 GDestroyNotify      destroy)
    244 {
    245   GMemoryInputStreamPrivate *priv;
    246   Chunk *chunk;
    247 
    248   g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
    249   g_return_if_fail (data != NULL);
    250 
    251   priv = stream->priv;
    252 
    253   if (len == -1)
    254     len = strlen (data);
    255 
    256   chunk = g_slice_new (Chunk);
    257   chunk->data = (guint8 *)data;
    258   chunk->len = len;
    259   chunk->destroy = destroy;
    260 
    261   priv->chunks = g_slist_append (priv->chunks, chunk);
    262   priv->len += chunk->len;
    263 }
    264 
    265 static gssize
    266 g_memory_input_stream_read (GInputStream  *stream,
    267                             void          *buffer,
    268                             gsize          count,
    269                             GCancellable  *cancellable,
    270                             GError       **error)
    271 {
    272   GMemoryInputStream *memory_stream;
    273   GMemoryInputStreamPrivate *priv;
    274   GSList *l;
    275   Chunk *chunk;
    276   gsize offset, start, rest, size;
    277 
    278   memory_stream = G_MEMORY_INPUT_STREAM (stream);
    279   priv = memory_stream->priv;
    280 
    281   count = MIN (count, priv->len - priv->pos);
    282 
    283   offset = 0;
    284   for (l = priv->chunks; l; l = l->next)
    285     {
    286       chunk = (Chunk *)l->data;
    287 
    288       if (offset + chunk->len > priv->pos)
    289         break;
    290 
    291       offset += chunk->len;
    292     }
    293 
    294   start = priv->pos - offset;
    295   rest = count;
    296 
    297   for (; l && rest > 0; l = l->next)
    298     {
    299       chunk = (Chunk *)l->data;
    300       size = MIN (rest, chunk->len - start);
    301 
    302       memcpy ((guint8 *)buffer + (count - rest), chunk->data + start, size);
    303       rest -= size;
    304 
    305       start = 0;
    306     }
    307 
    308   priv->pos += count;
    309 
    310   return count;
    311 }
    312 
    313 static gssize
    314 g_memory_input_stream_skip (GInputStream  *stream,
    315                             gsize          count,
    316                             GCancellable  *cancellable,
    317                             GError       **error)
    318 {
    319   GMemoryInputStream *memory_stream;
    320   GMemoryInputStreamPrivate *priv;
    321 
    322   memory_stream = G_MEMORY_INPUT_STREAM (stream);
    323   priv = memory_stream->priv;
    324 
    325   count = MIN (count, priv->len - priv->pos);
    326   priv->pos += count;
    327 
    328   return count;
    329 }
    330 
    331 static gboolean
    332 g_memory_input_stream_close (GInputStream  *stream,
    333                              GCancellable  *cancellable,
    334                              GError       **error)
    335 {
    336   return TRUE;
    337 }
    338 
    339 static void
    340 g_memory_input_stream_read_async (GInputStream        *stream,
    341                                   void                *buffer,
    342                                   gsize                count,
    343                                   int                  io_priority,
    344                                   GCancellable        *cancellable,
    345                                   GAsyncReadyCallback  callback,
    346                                   gpointer             user_data)
    347 {
    348   GSimpleAsyncResult *simple;
    349   gssize nread;
    350 
    351   nread = g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
    352   simple = g_simple_async_result_new (G_OBJECT (stream),
    353 				      callback,
    354 				      user_data,
    355 				      g_memory_input_stream_read_async);
    356   g_simple_async_result_set_op_res_gssize (simple, nread);
    357   g_simple_async_result_complete_in_idle (simple);
    358   g_object_unref (simple);
    359 }
    360 
    361 static gssize
    362 g_memory_input_stream_read_finish (GInputStream  *stream,
    363                                    GAsyncResult  *result,
    364                                    GError       **error)
    365 {
    366   GSimpleAsyncResult *simple;
    367   gssize nread;
    368 
    369   simple = G_SIMPLE_ASYNC_RESULT (result);
    370   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
    371 
    372   nread = g_simple_async_result_get_op_res_gssize (simple);
    373   return nread;
    374 }
    375 
    376 static void
    377 g_memory_input_stream_skip_async (GInputStream        *stream,
    378                                   gsize                count,
    379                                   int                  io_priority,
    380                                   GCancellable        *cancellable,
    381                                   GAsyncReadyCallback  callback,
    382                                   gpointer             user_data)
    383 {
    384   GSimpleAsyncResult *simple;
    385   gssize nskipped;
    386 
    387   nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
    388   simple = g_simple_async_result_new (G_OBJECT (stream),
    389                                       callback,
    390                                       user_data,
    391                                       g_memory_input_stream_skip_async);
    392   g_simple_async_result_set_op_res_gssize (simple, nskipped);
    393   g_simple_async_result_complete_in_idle (simple);
    394   g_object_unref (simple);
    395 }
    396 
    397 static gssize
    398 g_memory_input_stream_skip_finish (GInputStream  *stream,
    399                                    GAsyncResult  *result,
    400                                    GError       **error)
    401 {
    402   GSimpleAsyncResult *simple;
    403   gssize nskipped;
    404 
    405   simple = G_SIMPLE_ASYNC_RESULT (result);
    406   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
    407 
    408   nskipped = g_simple_async_result_get_op_res_gssize (simple);
    409   return nskipped;
    410 }
    411 
    412 static void
    413 g_memory_input_stream_close_async (GInputStream        *stream,
    414                                    int                  io_priority,
    415                                    GCancellable        *cancellable,
    416                                    GAsyncReadyCallback  callback,
    417                                    gpointer             user_data)
    418 {
    419   GSimpleAsyncResult *simple;
    420 
    421   simple = g_simple_async_result_new (G_OBJECT (stream),
    422 				      callback,
    423 				      user_data,
    424 				      g_memory_input_stream_close_async);
    425   g_simple_async_result_complete_in_idle (simple);
    426   g_object_unref (simple);
    427 }
    428 
    429 static gboolean
    430 g_memory_input_stream_close_finish (GInputStream  *stream,
    431                                     GAsyncResult  *result,
    432                                     GError       **error)
    433 {
    434   return TRUE;
    435 }
    436 
    437 static goffset
    438 g_memory_input_stream_tell (GSeekable *seekable)
    439 {
    440   GMemoryInputStream *memory_stream;
    441   GMemoryInputStreamPrivate *priv;
    442 
    443   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
    444   priv = memory_stream->priv;
    445 
    446   return priv->pos;
    447 }
    448 
    449 static
    450 gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
    451 {
    452   return TRUE;
    453 }
    454 
    455 static gboolean
    456 g_memory_input_stream_seek (GSeekable     *seekable,
    457                             goffset        offset,
    458                             GSeekType      type,
    459                             GCancellable  *cancellable,
    460                             GError       **error)
    461 {
    462   GMemoryInputStream *memory_stream;
    463   GMemoryInputStreamPrivate *priv;
    464   goffset absolute;
    465 
    466   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
    467   priv = memory_stream->priv;
    468 
    469   switch (type)
    470     {
    471     case G_SEEK_CUR:
    472       absolute = priv->pos + offset;
    473       break;
    474 
    475     case G_SEEK_SET:
    476       absolute = offset;
    477       break;
    478 
    479     case G_SEEK_END:
    480       absolute = priv->len + offset;
    481       break;
    482 
    483     default:
    484       g_set_error_literal (error,
    485                            G_IO_ERROR,
    486                            G_IO_ERROR_INVALID_ARGUMENT,
    487                            _("Invalid GSeekType supplied"));
    488 
    489       return FALSE;
    490     }
    491 
    492   if (absolute < 0 || absolute > priv->len)
    493     {
    494       g_set_error_literal (error,
    495                            G_IO_ERROR,
    496                            G_IO_ERROR_INVALID_ARGUMENT,
    497                            _("Invalid seek request"));
    498       return FALSE;
    499     }
    500 
    501   priv->pos = absolute;
    502 
    503   return TRUE;
    504 }
    505 
    506 static gboolean
    507 g_memory_input_stream_can_truncate (GSeekable *seekable)
    508 {
    509   return FALSE;
    510 }
    511 
    512 static gboolean
    513 g_memory_input_stream_truncate (GSeekable     *seekable,
    514                                 goffset        offset,
    515                                 GCancellable  *cancellable,
    516                                 GError       **error)
    517 {
    518   g_set_error_literal (error,
    519                        G_IO_ERROR,
    520                        G_IO_ERROR_NOT_SUPPORTED,
    521                        _("Cannot truncate GMemoryInputStream"));
    522   return FALSE;
    523 }
    524 
    525 #define __G_MEMORY_INPUT_STREAM_C__
    526 #include "gioaliasdef.c"
    527