cleanup
[platform/upstream/glib.git] / gio / gmemoryinputstream.c
index ee29df1..d822588 100644 (file)
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General
- * Public License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
  *
  * Author: Christian Kellner <gicmo@gnome.org> 
  */
 
-#include <config.h>
+#include "config.h"
 #include "gmemoryinputstream.h"
+#include "gpollableinputstream.h"
 #include "ginputstream.h"
 #include "gseekable.h"
 #include "string.h"
-#include "gsimpleasyncresult.h"
+#include "gtask.h"
+#include "gioerror.h"
 #include "glibintl.h"
 
+
 /**
  * SECTION:gmemoryinputstream
- * @short_description: streaming input operations on memory chunks
- * @see_also: #GMemoryOutputStream.
+ * @short_description: Streaming input operations on memory chunks
+ * @include: gio/gio.h
+ * @see_also: #GMemoryOutputStream
  *
  * #GMemoryInputStream is a class for using arbitrary
  * memory chunks as input for GIO streaming input operations.
  *
+ * As of GLib 2.34, #GMemoryInputStream implements
+ * #GPollableInputStream.
  */
 
 struct _GMemoryInputStreamPrivate {
-  guint8 *buffer;      
-  gsize   pos;
+  GSList *chunks;
   gsize   len;
-  gboolean free_data;
+  gsize   pos;
 };
 
 static gssize   g_memory_input_stream_read         (GInputStream         *stream,
@@ -57,16 +60,6 @@ static gssize   g_memory_input_stream_skip         (GInputStream         *stream
 static gboolean g_memory_input_stream_close        (GInputStream         *stream,
                                                    GCancellable         *cancellable,
                                                    GError              **error);
-static void     g_memory_input_stream_read_async   (GInputStream         *stream,
-                                                   void                 *buffer,
-                                                   gsize                 count,
-                                                   int                   io_priority,
-                                                   GCancellable         *cancellable,
-                                                   GAsyncReadyCallback   callback,
-                                                   gpointer              user_data);
-static gssize   g_memory_input_stream_read_finish  (GInputStream         *stream,
-                                                   GAsyncResult         *result,
-                                                   GError              **error);
 static void     g_memory_input_stream_skip_async   (GInputStream         *stream,
                                                    gsize                 count,
                                                    int                   io_priority,
@@ -98,11 +91,21 @@ static gboolean g_memory_input_stream_truncate            (GSeekable       *seek
                                                            goffset          offset,
                                                            GCancellable    *cancellable,
                                                            GError         **error);
+
+static void     g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface);
+static gboolean g_memory_input_stream_is_readable         (GPollableInputStream *stream);
+static GSource *g_memory_input_stream_create_source       (GPollableInputStream *stream,
+                                                          GCancellable          *cancellable);
+
 static void     g_memory_input_stream_finalize            (GObject         *object);
 
 G_DEFINE_TYPE_WITH_CODE (GMemoryInputStream, g_memory_input_stream, G_TYPE_INPUT_STREAM,
+                         G_ADD_PRIVATE (GMemoryInputStream)
                          G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,
-                                                g_memory_input_stream_seekable_iface_init))
+                                                g_memory_input_stream_seekable_iface_init);
+                         G_IMPLEMENT_INTERFACE (G_TYPE_POLLABLE_INPUT_STREAM,
+                                                g_memory_input_stream_pollable_iface_init);
+                        )
 
 
 static void
@@ -111,18 +114,14 @@ g_memory_input_stream_class_init (GMemoryInputStreamClass *klass)
   GObjectClass *object_class;
   GInputStreamClass *istream_class;
 
-  g_type_class_add_private (klass, sizeof (GMemoryInputStreamPrivate));
-
   object_class = G_OBJECT_CLASS (klass);
   object_class->finalize     = g_memory_input_stream_finalize;
   
   istream_class = G_INPUT_STREAM_CLASS (klass);
-  istream_class->read  = g_memory_input_stream_read;
+  istream_class->read_fn  = g_memory_input_stream_read;
   istream_class->skip  = g_memory_input_stream_skip;
-  istream_class->close = g_memory_input_stream_close;
+  istream_class->close_fn = g_memory_input_stream_close;
 
-  istream_class->read_async  = g_memory_input_stream_read_async;
-  istream_class->read_finish  = g_memory_input_stream_read_finish;
   istream_class->skip_async  = g_memory_input_stream_skip_async;
   istream_class->skip_finish  = g_memory_input_stream_skip_finish;
   istream_class->close_async = g_memory_input_stream_close_async;
@@ -133,14 +132,14 @@ static void
 g_memory_input_stream_finalize (GObject *object)
 {
   GMemoryInputStream        *stream;
+  GMemoryInputStreamPrivate *priv;
 
   stream = G_MEMORY_INPUT_STREAM (object);
+  priv = stream->priv;
 
-  if (stream->priv->free_data)
-    g_free (stream->priv->buffer);
+  g_slist_free_full (priv->chunks, (GDestroyNotify)g_bytes_unref);
 
-  if (G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize)
-    (*G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize) (object);
+  G_OBJECT_CLASS (g_memory_input_stream_parent_class)->finalize (object);
 }
 
 static void
@@ -150,229 +149,271 @@ g_memory_input_stream_seekable_iface_init (GSeekableIface *iface)
   iface->can_seek     = g_memory_input_stream_can_seek;
   iface->seek         = g_memory_input_stream_seek;
   iface->can_truncate = g_memory_input_stream_can_truncate;
-  iface->truncate     = g_memory_input_stream_truncate;
+  iface->truncate_fn  = g_memory_input_stream_truncate;
+}
+
+static void
+g_memory_input_stream_pollable_iface_init (GPollableInputStreamInterface *iface)
+{
+  iface->is_readable   = g_memory_input_stream_is_readable;
+  iface->create_source = g_memory_input_stream_create_source;
 }
 
 static void
 g_memory_input_stream_init (GMemoryInputStream *stream)
 {
-  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
-                                              G_TYPE_MEMORY_INPUT_STREAM,
-                                              GMemoryInputStreamPrivate);
+  stream->priv = g_memory_input_stream_get_instance_private (stream);
 }
 
 /**
- * g_memory_input_stream_set_free_data:
- * @stream:
- * @free_data:
- * 
- **/
-void
-g_memory_input_stream_set_free_data (GMemoryInputStream *stream,
-                                    gboolean free_data)
+ * g_memory_input_stream_new:
+ *
+ * Creates a new empty #GMemoryInputStream. 
+ *
+ * Returns: a new #GInputStream
+ */
+GInputStream *
+g_memory_input_stream_new (void)
 {
-  g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
+  GInputStream *stream;
+
+  stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
 
-  stream->priv->free_data = free_data;
+  return stream;
 }
 
 /**
- * g_memory_input_stream_from_data:
- * @data: input data.
- * @len: length of the data.
+ * g_memory_input_stream_new_from_data:
+ * @data: (array length=len) (element-type guint8) (transfer full): input data
+ * @len: length of the data, may be -1 if @data is a nul-terminated string
+ * @destroy: (allow-none): function that is called to free @data, or %NULL
+ *
+ * Creates a new #GMemoryInputStream with data in memory of a given size.
  * 
  * Returns: new #GInputStream read from @data of @len bytes.
  **/
 GInputStream *
-g_memory_input_stream_from_data (const void *data, gssize len)
+g_memory_input_stream_new_from_data (const void     *data, 
+                                     gssize          len,
+                                     GDestroyNotify  destroy)
 {
   GInputStream *stream;
-  GMemoryInputStream *memory_stream;
 
-  g_return_val_if_fail (data != NULL, NULL);
+  stream = g_memory_input_stream_new ();
 
-  stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
-  memory_stream = G_MEMORY_INPUT_STREAM (stream);
-
-  if (len == -1)
-    len = strlen (data);
-  
-  memory_stream->priv->buffer = (guint8 *)data;
-  memory_stream->priv->len = len;
+  g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
+                                  data, len, destroy);
 
   return stream;
 }
 
-static gssize
-g_memory_input_stream_read (GInputStream *stream,
-                            void         *buffer,
-                            gsize         count,
-                            GCancellable *cancellable,
-                            GError      **error)
+/**
+ * g_memory_input_stream_new_from_bytes:
+ * @bytes: a #GBytes
+ *
+ * Creates a new #GMemoryInputStream with data from the given @bytes.
+ *
+ * Returns: new #GInputStream read from @bytes
+ *
+ * Since: 2.34
+ **/
+GInputStream *
+g_memory_input_stream_new_from_bytes (GBytes  *bytes)
 {
-  GMemoryInputStream *memory_stream;
-  GMemoryInputStreamPrivate * priv;
+  
+  GInputStream *stream;
 
-  memory_stream = G_MEMORY_INPUT_STREAM (stream);
-  priv = memory_stream->priv;
+  stream = g_memory_input_stream_new ();
 
-  count = MIN (count, priv->len - priv->pos);
-  memcpy (buffer, priv->buffer + priv->pos, count);
-  priv->pos += count;
+  g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
+                                  bytes);
 
-  return count;
+  return stream;
 }
 
 /**
- * g_memory_input_stream_get_data:
- * @stream:
- * 
- * Returns: 
- **/
-const void *
-g_memory_input_stream_get_data (GMemoryInputStream *stream)
+ * g_memory_input_stream_add_data:
+ * @stream: a #GMemoryInputStream
+ * @data: (array length=len) (element-type guint8) (transfer full): input data
+ * @len: length of the data, may be -1 if @data is a nul-terminated string
+ * @destroy: (allow-none): function that is called to free @data, or %NULL
+ *
+ * Appends @data to data that can be read from the input stream
+ */
+void
+g_memory_input_stream_add_data (GMemoryInputStream *stream,
+                                const void         *data,
+                                gssize              len,
+                                GDestroyNotify      destroy)
 {
-  g_return_val_if_fail (G_IS_MEMORY_INPUT_STREAM (stream), NULL);
+  GBytes *bytes;
+
+  if (len == -1)
+    len = strlen (data);
 
-  return stream->priv->buffer;
+  /* It's safe to discard the const here because we're chaining the
+   * destroy callback.
+   */
+  bytes = g_bytes_new_with_free_func (data, len, destroy, (void*)data);
+
+  g_memory_input_stream_add_bytes (stream, bytes);
+  
+  g_bytes_unref (bytes);
 }
 
 /**
- * g_memory_input_stream_get_data_size:
- * @stream:
- * 
- * Returns: 
- **/
-gsize
-g_memory_input_stream_get_data_size (GMemoryInputStream *stream)
+ * g_memory_input_stream_add_bytes:
+ * @stream: a #GMemoryInputStream
+ * @bytes: input data
+ *
+ * Appends @bytes to data that can be read from the input stream.
+ *
+ * Since: 2.34
+ */
+void
+g_memory_input_stream_add_bytes (GMemoryInputStream *stream,
+                                GBytes             *bytes)
 {
-  g_return_val_if_fail (G_IS_MEMORY_INPUT_STREAM (stream), -1);
+  GMemoryInputStreamPrivate *priv;
+  g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
+  g_return_if_fail (bytes != NULL);
+
+  priv = stream->priv;
 
-  return stream->priv->len;
+  priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
+  priv->len += g_bytes_get_size (bytes);
 }
 
 static gssize
-g_memory_input_stream_skip (GInputStream              *stream,
-                            gsize                      count,
-                            GCancellable              *cancellable,
-                            GError                   **error)
+g_memory_input_stream_read (GInputStream  *stream,
+                            void          *buffer,
+                            gsize          count,
+                            GCancellable  *cancellable,
+                            GError       **error)
 {
   GMemoryInputStream *memory_stream;
   GMemoryInputStreamPrivate *priv;
+  GSList *l;
+  GBytes *chunk;
+  gsize len;
+  gsize offset, start, rest, size;
 
   memory_stream = G_MEMORY_INPUT_STREAM (stream);
   priv = memory_stream->priv;
 
   count = MIN (count, priv->len - priv->pos);
+
+  offset = 0;
+  for (l = priv->chunks; l; l = l->next) 
+    {
+      chunk = (GBytes *)l->data;
+      len = g_bytes_get_size (chunk);
+
+      if (offset + len > priv->pos)
+        break;
+
+      offset += len;
+    }
+  
+  start = priv->pos - offset;
+  rest = count;
+
+  for (; l && rest > 0; l = l->next)
+    {
+      const guint8* chunk_data;
+      chunk = (GBytes *)l->data;
+
+      chunk_data = g_bytes_get_data (chunk, &len);
+
+      size = MIN (rest, len - start);
+
+      memcpy ((guint8 *)buffer + (count - rest), chunk_data + start, size);
+      rest -= size;
+
+      start = 0;
+    }
+
   priv->pos += count;
 
   return count;
-
 }
 
-static gboolean
-g_memory_input_stream_close (GInputStream *stream,
-                             GCancellable *cancellable,
-                             GError      **error)
+static gssize
+g_memory_input_stream_skip (GInputStream  *stream,
+                            gsize          count,
+                            GCancellable  *cancellable,
+                            GError       **error)
 {
-  return TRUE;
-}
+  GMemoryInputStream *memory_stream;
+  GMemoryInputStreamPrivate *priv;
 
-static void
-g_memory_input_stream_read_async (GInputStream              *stream,
-                                  void                      *buffer,
-                                  gsize                      count,
-                                  int                        io_priority,
-                                  GCancellable              *cancellable,
-                                  GAsyncReadyCallback        callback,
-                                  gpointer                   user_data)
-{
-  GSimpleAsyncResult *simple;
-  gssize nread;
-
-  nread =  g_memory_input_stream_read (stream, buffer, count, cancellable, NULL);
-  simple = g_simple_async_result_new (G_OBJECT (stream),
-                                     callback,
-                                     user_data,
-                                     g_memory_input_stream_read_async);
-  g_simple_async_result_set_op_res_gssize (simple, nread);
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+  memory_stream = G_MEMORY_INPUT_STREAM (stream);
+  priv = memory_stream->priv;
+
+  count = MIN (count, priv->len - priv->pos);
+  priv->pos += count;
+
+  return count;
 }
 
-static gssize
-g_memory_input_stream_read_finish (GInputStream              *stream,
-                                  GAsyncResult              *result,
-                                  GError                   **error)
+static gboolean
+g_memory_input_stream_close (GInputStream  *stream,
+                             GCancellable  *cancellable,
+                             GError       **error)
 {
-  GSimpleAsyncResult *simple;
-  gssize nread;
-
-  simple = G_SIMPLE_ASYNC_RESULT (result);
-  g_assert (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_read_async);
-  
-  nread = g_simple_async_result_get_op_res_gssize (simple);
-  return nread;
+  return TRUE;
 }
 
 static void
-g_memory_input_stream_skip_async (GInputStream              *stream,
-                                  gsize                      count,
-                                  int                        io_priority,
-                                  GCancellable              *cancellable,
-                                  GAsyncReadyCallback        callback,
-                                  gpointer                   user_data)
+g_memory_input_stream_skip_async (GInputStream        *stream,
+                                  gsize                count,
+                                  int                  io_priority,
+                                  GCancellable        *cancellable,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             user_data)
 {
-  GSimpleAsyncResult *simple;
+  GTask *task;
   gssize nskipped;
-
-  nskipped = g_memory_input_stream_skip (stream, count, cancellable, NULL);
-  simple = g_simple_async_result_new (G_OBJECT (stream),
-                                     callback,
-                                     user_data,
-                                     g_memory_input_stream_skip_async);
-  g_simple_async_result_set_op_res_gssize (simple, nskipped);
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+  GError *error = NULL;
+
+  nskipped = G_INPUT_STREAM_GET_CLASS (stream)->skip (stream, count, cancellable, &error);
+  task = g_task_new (stream, cancellable, callback, user_data);
+  if (error)
+    g_task_return_error (task, error);
+  else
+    g_task_return_int (task, nskipped);
+  g_object_unref (task);
 }
 
 static gssize
-g_memory_input_stream_skip_finish (GInputStream              *stream,
-                                  GAsyncResult              *result,
-                                  GError                   **error)
+g_memory_input_stream_skip_finish (GInputStream  *stream,
+                                   GAsyncResult  *result,
+                                   GError       **error)
 {
-  GSimpleAsyncResult *simple;
-  gssize nskipped;
+  g_return_val_if_fail (g_task_is_valid (result, stream), -1);
 
-  simple = G_SIMPLE_ASYNC_RESULT (result);
-  g_assert (g_simple_async_result_get_source_tag (simple) == g_memory_input_stream_skip_async);
-  
-  nskipped = g_simple_async_result_get_op_res_gssize (simple);
-  return nskipped;
+  return g_task_propagate_int (G_TASK (result), error);
 }
 
 static void
-g_memory_input_stream_close_async (GInputStream              *stream,
-                                   int                        io_priority,
-                                   GCancellable              *cancellable,
-                                   GAsyncReadyCallback        callback,
-                                   gpointer                   user_data)
+g_memory_input_stream_close_async (GInputStream        *stream,
+                                   int                  io_priority,
+                                   GCancellable        *cancellable,
+                                   GAsyncReadyCallback  callback,
+                                   gpointer             user_data)
 {
-  GSimpleAsyncResult *simple;
-  
-  simple = g_simple_async_result_new (G_OBJECT (stream),
-                                     callback,
-                                     user_data,
-                                     g_memory_input_stream_close_async);
-  g_simple_async_result_complete_in_idle (simple);
-  g_object_unref (simple);
+  GTask *task;
+
+  task = g_task_new (stream, cancellable, callback, user_data);
+  g_task_return_boolean (task, TRUE);
+  g_object_unref (task);
 }
 
 static gboolean
-g_memory_input_stream_close_finish (GInputStream              *stream,
-                                   GAsyncResult              *result,
-                                   GError                   **error)
+g_memory_input_stream_close_finish (GInputStream  *stream,
+                                    GAsyncResult  *result,
+                                    GError       **error)
 {
   return TRUE;
 }
@@ -381,7 +422,7 @@ static goffset
 g_memory_input_stream_tell (GSeekable *seekable)
 {
   GMemoryInputStream *memory_stream;
-  GMemoryInputStreamPrivate * priv;
+  GMemoryInputStreamPrivate *priv;
 
   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
   priv = memory_stream->priv;
@@ -396,21 +437,21 @@ gboolean g_memory_input_stream_can_seek (GSeekable *seekable)
 }
 
 static gboolean
-g_memory_input_stream_seek (GSeekable       *seekable,
-                            goffset          offset,
-                            GSeekType        type,
-                            GCancellable    *cancellable,
-                            GError         **error)
+g_memory_input_stream_seek (GSeekable     *seekable,
+                            goffset        offset,
+                            GSeekType      type,
+                            GCancellable  *cancellable,
+                            GError       **error)
 {
   GMemoryInputStream *memory_stream;
-  GMemoryInputStreamPrivate * priv;
+  GMemoryInputStreamPrivate *priv;
   goffset absolute;
 
   memory_stream = G_MEMORY_INPUT_STREAM (seekable);
   priv = memory_stream->priv;
 
-  switch (type) {
-
+  switch (type) 
+    {
     case G_SEEK_CUR:
       absolute = priv->pos + offset;
       break;
@@ -424,20 +465,20 @@ g_memory_input_stream_seek (GSeekable       *seekable,
       break;
   
     default:
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_INVALID_ARGUMENT,
-                   "Invalid GSeekType supplied");
+      g_set_error_literal (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_INVALID_ARGUMENT,
+                           _("Invalid GSeekType supplied"));
 
       return FALSE;
-  }
+    }
 
   if (absolute < 0 || absolute > priv->len)
     {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   G_IO_ERROR_INVALID_ARGUMENT,
-                   "Invalid seek request");
+      g_set_error_literal (error,
+                           G_IO_ERROR,
+                           G_IO_ERROR_INVALID_ARGUMENT,
+                           _("Invalid seek request"));
       return FALSE;
     }
 
@@ -453,17 +494,34 @@ g_memory_input_stream_can_truncate (GSeekable *seekable)
 }
 
 static gboolean
-g_memory_input_stream_truncate (GSeekable      *seekable,
-                                goffset          offset,
-                                GCancellable    *cancellable,
-                                GError         **error)
+g_memory_input_stream_truncate (GSeekable     *seekable,
+                                goffset        offset,
+                                GCancellable  *cancellable,
+                                GError       **error)
 {
-  g_set_error (error,
-               G_IO_ERROR,
-               G_IO_ERROR_NOT_SUPPORTED,
-               "Cannot seek on GMemoryInputStream");
+  g_set_error_literal (error,
+                       G_IO_ERROR,
+                       G_IO_ERROR_NOT_SUPPORTED,
+                       _("Cannot truncate GMemoryInputStream"));
   return FALSE;
 }
 
-/* vim: ts=2 sw=2 et */
+static gboolean
+g_memory_input_stream_is_readable (GPollableInputStream *stream)
+{
+  return TRUE;
+}
 
+static GSource *
+g_memory_input_stream_create_source (GPollableInputStream *stream,
+                                    GCancellable         *cancellable)
+{
+  GSource *base_source, *pollable_source;
+
+  base_source = g_timeout_source_new (0);
+  pollable_source = g_pollable_source_new_full (stream, base_source,
+                                               cancellable);
+  g_source_unref (base_source);
+
+  return pollable_source;
+}