* 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"
-#include "gioalias.h"
/**
* SECTION:gmemoryinputstream
* @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,
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,
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
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->skip = g_memory_input_stream_skip;
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;
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
}
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: a #GMemoryInputStream.
- * @free_data: a #gboolean. If %TRUE, frees the data within @stream.
- *
- * Sets if the data within the @stream should be freed when the stream
- * is freed.
- **/
-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->priv->free_data = free_data;
+ stream = g_object_new (G_TYPE_MEMORY_INPUT_STREAM, NULL);
+
+ 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);
+ g_memory_input_stream_add_data (G_MEMORY_INPUT_STREAM (stream),
+ data, len, destroy);
+
+ return stream;
+}
+
+/**
+ * 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)
+{
+
+ GInputStream *stream;
+
+ stream = g_memory_input_stream_new ();
+
+ g_memory_input_stream_add_bytes (G_MEMORY_INPUT_STREAM (stream),
+ bytes);
+
+ return 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)
+{
+ GBytes *bytes;
if (len == -1)
len = strlen (data);
+
+ /* 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);
- memory_stream->priv->buffer = (guint8 *)data;
- memory_stream->priv->len = len;
+ g_bytes_unref (bytes);
+}
- return 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)
+{
+ GMemoryInputStreamPrivate *priv;
+
+ g_return_if_fail (G_IS_MEMORY_INPUT_STREAM (stream));
+ g_return_if_fail (bytes != NULL);
+
+ priv = stream->priv;
+
+ priv->chunks = g_slist_append (priv->chunks, g_bytes_ref (bytes));
+ priv->len += g_bytes_get_size (bytes);
}
static gssize
GError **error)
{
GMemoryInputStream *memory_stream;
- GMemoryInputStreamPrivate * priv;
+ 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);
- memcpy (buffer, priv->buffer + priv->pos, count);
- priv->pos += count;
- return count;
-}
+ offset = 0;
+ for (l = priv->chunks; l; l = l->next)
+ {
+ chunk = (GBytes *)l->data;
+ len = g_bytes_get_size (chunk);
-/**
- * g_memory_input_stream_get_data:
- * @stream: a #GMemoryInputStream
- *
- * Gets a pointer to the data within the #GMemoryInputStream.
- *
- * Returns: a pointer to the memory in the @stream.
- **/
-const void *
-g_memory_input_stream_get_data (GMemoryInputStream *stream)
-{
- g_return_val_if_fail (G_IS_MEMORY_INPUT_STREAM (stream), NULL);
+ if (offset + len > priv->pos)
+ break;
- return stream->priv->buffer;
-}
+ offset += len;
+ }
+
+ start = priv->pos - offset;
+ rest = count;
-/**
- * g_memory_input_stream_get_data_size:
- * @stream: a #GMemoryInputStream
- *
- * Gets the size of the data within the #GMemoryInputStream.
- *
- * Returns: a gsize with the size of the data in @stream, or -1
- * on error.
- **/
-gsize
-g_memory_input_stream_get_data_size (GMemoryInputStream *stream)
-{
- g_return_val_if_fail (G_IS_MEMORY_INPUT_STREAM (stream), -1);
+ for (; l && rest > 0; l = l->next)
+ {
+ const guint8* chunk_data;
+ chunk = (GBytes *)l->data;
+
+ chunk_data = g_bytes_get_data (chunk, &len);
- return stream->priv->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 gssize
priv->pos += count;
return count;
-
-
}
static gboolean
}
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);
-}
-
-static gssize
-g_memory_input_stream_read_finish (GInputStream *stream,
- GAsyncResult *result,
- 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;
-}
-
-static void
g_memory_input_stream_skip_async (GInputStream *stream,
gsize count,
int io_priority,
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
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
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_tell (GSeekable *seekable)
{
GMemoryInputStream *memory_stream;
- GMemoryInputStreamPrivate * priv;
+ GMemoryInputStreamPrivate *priv;
memory_stream = G_MEMORY_INPUT_STREAM (seekable);
priv = memory_stream->priv;
GError **error)
{
GMemoryInputStream *memory_stream;
- GMemoryInputStreamPrivate * priv;
+ GMemoryInputStreamPrivate *priv;
goffset absolute;
memory_stream = G_MEMORY_INPUT_STREAM (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;
}
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;
}
-#define __G_MEMORY_INPUT_STREAM_C__
-#include "gioaliasdef.c"
+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;
+}