#include <string.h>
#include "gskmemory.h"
/* === GskMemoryBufferSource === */
typedef struct _GskMemoryBufferSource GskMemoryBufferSource;
typedef struct _GskMemoryBufferSourceClass GskMemoryBufferSourceClass;
static GType gsk_memory_buffer_source_get_type(void) G_GNUC_CONST;
#define GSK_TYPE_MEMORY_BUFFER_SOURCE (gsk_memory_buffer_source_get_type ())
#define GSK_MEMORY_BUFFER_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_MEMORY_BUFFER_SOURCE, GskMemoryBufferSource))
#define GSK_MEMORY_BUFFER_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_MEMORY_BUFFER_SOURCE, GskMemoryBufferSourceClass))
#define GSK_MEMORY_BUFFER_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_MEMORY_BUFFER_SOURCE, GskMemoryBufferSourceClass))
#define GSK_IS_MEMORY_BUFFER_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_MEMORY_BUFFER_SOURCE))
#define GSK_IS_MEMORY_BUFFER_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_MEMORY_BUFFER_SOURCE))
struct _GskMemoryBufferSourceClass
{
GskStreamClass stream_class;
};
struct _GskMemoryBufferSource
{
GskStream stream;
GskBuffer buffer;
};
static GObjectClass *global_stream_class = NULL;
static guint
gsk_memory_buffer_source_raw_read (GskStream *stream,
gpointer data,
guint length,
GError **error)
{
GskMemoryBufferSource *source = GSK_MEMORY_BUFFER_SOURCE (stream);
guint rv = gsk_buffer_read (&source->buffer, data, length);
if (rv == 0 && source->buffer.size == 0)
gsk_io_notify_read_shutdown (stream);
return rv;
}
static guint
gsk_memory_buffer_source_raw_read_buffer (GskStream *stream,
GskBuffer *buffer,
GError **error)
{
GskMemoryBufferSource *source = GSK_MEMORY_BUFFER_SOURCE (stream);
guint rv = gsk_buffer_drain (buffer, &source->buffer);
if (rv == 0)
gsk_io_notify_read_shutdown (stream);
return rv;
}
static void
gsk_memory_buffer_source_finalize(GObject *object)
{
GskMemoryBufferSource *source = GSK_MEMORY_BUFFER_SOURCE (object);
gsk_buffer_destruct (&source->buffer);
(*global_stream_class->finalize) (object);
}
static void
gsk_memory_buffer_source_init (GskMemoryBufferSource *memory_buffer_source)
{
gsk_stream_mark_is_readable (memory_buffer_source);
gsk_stream_mark_never_blocks_read (memory_buffer_source);
}
static void
gsk_memory_buffer_source_class_init (GskMemoryBufferSourceClass *class)
{
GskStreamClass *stream_class = GSK_STREAM_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
global_stream_class = g_type_class_peek_parent (class);
stream_class->raw_read = gsk_memory_buffer_source_raw_read;
stream_class->raw_read_buffer = gsk_memory_buffer_source_raw_read_buffer;
object_class->finalize = gsk_memory_buffer_source_finalize;
}
static GType gsk_memory_buffer_source_get_type()
{
static GType memory_buffer_source_type = 0;
if (!memory_buffer_source_type)
{
static const GTypeInfo memory_buffer_source_info =
{
sizeof(GskMemoryBufferSourceClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_memory_buffer_source_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskMemoryBufferSource),
0, /* n_preallocs */
(GInstanceInitFunc) gsk_memory_buffer_source_init,
NULL /* value_table */
};
memory_buffer_source_type = g_type_register_static (GSK_TYPE_STREAM,
"GskMemoryBufferSource",
&memory_buffer_source_info, 0);
}
return memory_buffer_source_type;
}
/**
* gsk_memory_buffer_source_new:
* @buffer: buffer whose contents should be readable from the new stream.
* It will be immediately (before the function returns) drained of all
* data, and will not be used any more by the stream.
*
* Create a read-only #GskStream that will drain the
* data from @buffer and may it available for reading on the stream.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_buffer_source_new (GskBuffer *buffer)
{
GskMemoryBufferSource *source;
g_return_val_if_fail (buffer != NULL, NULL);
source = g_object_new (GSK_TYPE_MEMORY_BUFFER_SOURCE, NULL);
gsk_buffer_drain (&source->buffer, buffer);
return GSK_STREAM (source);
}
/* === GskMemorySlabSource === */
typedef struct _GskMemorySlabSource GskMemorySlabSource;
typedef struct _GskMemorySlabSourceClass GskMemorySlabSourceClass;
GType gsk_memory_slab_source_get_type(void) G_GNUC_CONST;
#define GSK_TYPE_MEMORY_SLAB_SOURCE (gsk_memory_slab_source_get_type ())
#define GSK_MEMORY_SLAB_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_MEMORY_SLAB_SOURCE, GskMemorySlabSource))
#define GSK_MEMORY_SLAB_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_MEMORY_SLAB_SOURCE, GskMemorySlabSourceClass))
#define GSK_MEMORY_SLAB_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_MEMORY_SLAB_SOURCE, GskMemorySlabSourceClass))
#define GSK_IS_MEMORY_SLAB_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_MEMORY_SLAB_SOURCE))
#define GSK_IS_MEMORY_SLAB_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_MEMORY_SLAB_SOURCE))
struct _GskMemorySlabSourceClass
{
GskStreamClass stream_class;
};
struct _GskMemorySlabSource
{
GskStream stream;
gconstpointer data;
guint data_len;
GDestroyNotify destroy;
gpointer destroy_data;
};
static guint
gsk_memory_slab_source_raw_read (GskStream *stream,
gpointer data,
guint length,
GError **error)
{
GskMemorySlabSource *source = GSK_MEMORY_SLAB_SOURCE (stream);
guint rv = MIN (source->data_len, length);
if (rv != 0)
{
memcpy (data, source->data, rv);
source->data = ((const char *)source->data) + rv;
source->data_len -= rv;
}
if (source->data_len == 0)
gsk_io_notify_read_shutdown (stream);
return rv;
}
static guint
gsk_memory_slab_source_raw_read_buffer (GskStream *stream,
GskBuffer *buffer,
GError **error)
{
GskMemorySlabSource *source = GSK_MEMORY_SLAB_SOURCE (stream);
guint rv = source->data_len;
if (rv != 0)
{
gsk_buffer_append_foreign (buffer, source->data, source->data_len,
source->destroy, source->destroy_data);
source->data_len = 0;
source->destroy = NULL;
}
gsk_io_notify_read_shutdown (stream);
return rv;
}
static void
gsk_memory_slab_source_finalize (GObject *object)
{
GskMemorySlabSource *source = GSK_MEMORY_SLAB_SOURCE (object);
if (source->destroy)
source->destroy (source->destroy_data);
global_stream_class->finalize (object);
}
static void
gsk_memory_slab_source_init (GskMemorySlabSource *memory_slab_source)
{
gsk_stream_mark_is_readable (memory_slab_source);
gsk_stream_mark_never_blocks_read (memory_slab_source);
}
static void
gsk_memory_slab_source_class_init (GskMemorySlabSourceClass *class)
{
GskStreamClass *stream_class = GSK_STREAM_CLASS (class);
GObjectClass *object_class = G_OBJECT_CLASS (class);
global_stream_class = g_type_class_peek_parent (class);
stream_class->raw_read = gsk_memory_slab_source_raw_read;
stream_class->raw_read_buffer = gsk_memory_slab_source_raw_read_buffer;
object_class->finalize = gsk_memory_slab_source_finalize;
}
GType gsk_memory_slab_source_get_type()
{
static GType memory_slab_source_type = 0;
if (!memory_slab_source_type)
{
static const GTypeInfo memory_slab_source_info =
{
sizeof(GskMemorySlabSourceClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_memory_slab_source_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskMemorySlabSource),
0, /* n_preallocs */
(GInstanceInitFunc) gsk_memory_slab_source_init,
NULL /* value_table */
};
memory_slab_source_type = g_type_register_static (GSK_TYPE_STREAM,
"GskMemorySlabSource",
&memory_slab_source_info, 0);
}
return memory_slab_source_type;
}
/**
* gsk_memory_slab_source_new:
* @data: binary data which will be readable from the returned stream.
* @data_len: length of the returned stream.
* @destroy: method called by the stream once @data is completely used
* (ie, the user has read all the data or shutdown the stream)
* @destroy_data: data passed to @destroy.
*
* Create a read-only stream which has certain, given data available for reading.
*
* For efficiency, this code does not copy the data, but rather calls
* a user-supplied destroy method when we are done.
*
* One possibility if you need the data copied, is to call
* g_memdup on data, then pass in g_free for @destroy and the copy of the data
* as @destroy_data.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_slab_source_new (gconstpointer data,
guint data_len,
GDestroyNotify destroy,
gpointer destroy_data)
{
GskMemorySlabSource *slab_source;
slab_source = g_object_new (GSK_TYPE_MEMORY_SLAB_SOURCE, NULL);
slab_source->data = data;
slab_source->data_len = data_len;
slab_source->destroy = destroy;
slab_source->destroy_data = destroy_data;
return GSK_STREAM (slab_source);
}
/**
* gsk_memory_source_new_printf:
* @format: a printf(3) format string.
* @...: arguments, as used by printf(3).
*
* Create a read-only stream which has the result of doing the
* sprintf available for reading.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_source_new_printf (const char *format,
...)
{
char *str;
va_list args;
va_start (args, format);
str = g_strdup_vprintf (format, args);
va_end (args);
return gsk_memory_slab_source_new (str, strlen (str), g_free, str);
}
/**
* gsk_memory_source_new_vprintf:
* @format: a printf(3) format string.
* @args: arguments, as used by vprintf(3).
*
* Create a read-only stream which has the result of doing the
* vsprintf available for reading. This is useful for
* chaining from other printf-like functions.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_source_new_vprintf (const char *format,
va_list args)
{
char *str = g_strdup_vprintf (format, args);
return gsk_memory_slab_source_new (str, strlen (str), g_free, str);
}
/**
* gsk_memory_source_static_string:
* @str: the static string which is the content of the stream.
*
* Create a read-only stream which has @str available
* for reading.
*
* Note that the NUL will not be read from the stream.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_source_static_string (const char *str)
{
return gsk_memory_slab_source_new (str, strlen (str), NULL, NULL);
}
/**
* gsk_memory_source_static_string_n:
* @str: the static string or binary-data which is the content of the stream.
* @length: length of the stream in bytes.
*
* Create a read-only stream which has @length bytes starting at @str available
* for reading.
*
* returns: the new read-only stream.
*/
GskStream *
gsk_memory_source_static_string_n (const char *str,
guint length)
{
return gsk_memory_slab_source_new (str, length, NULL, NULL);
}
/* --- streams which can be written to --- */
/* === GskMemorySink === */
/* Insert header here. */
typedef struct _GskMemorySink GskMemorySink;
typedef struct _GskMemorySinkClass GskMemorySinkClass;
GType gsk_memory_sink_get_type(void) G_GNUC_CONST;
#define GSK_TYPE_MEMORY_SINK (gsk_memory_sink_get_type ())
#define GSK_MEMORY_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSK_TYPE_MEMORY_SINK, GskMemorySink))
#define GSK_MEMORY_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSK_TYPE_MEMORY_SINK, GskMemorySinkClass))
#define GSK_MEMORY_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSK_TYPE_MEMORY_SINK, GskMemorySinkClass))
#define GSK_IS_MEMORY_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSK_TYPE_MEMORY_SINK))
#define GSK_IS_MEMORY_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSK_TYPE_MEMORY_SINK))
struct _GskMemorySinkClass
{
GskStreamClass stream_class;
};
struct _GskMemorySink
{
GskStream stream;
/* underlying data store */
GskBuffer buffer;
/* from the user; callback and destroy are set to NULL when they are
run, since they should only be run once. */
GskMemoryBufferCallback callback;
gpointer data;
GDestroyNotify destroy;
};
static guint
gsk_memory_sink_raw_write (GskStream *stream,
gconstpointer data,
guint length,
GError **error)
{
gsk_buffer_append (&GSK_MEMORY_SINK (stream)->buffer, data, length);
return length;
}
static guint
gsk_memory_sink_raw_write_buffer(GskStream *stream,
GskBuffer *buffer,
GError **error)
{
return gsk_buffer_drain (&GSK_MEMORY_SINK (stream)->buffer, buffer);
}
static gboolean
gsk_memory_sink_shutdown_write(GskIO *io,
GError **error)
{
GskMemorySink *sink = GSK_MEMORY_SINK (io);
if (sink->callback)
{
GskMemoryBufferCallback callback = sink->callback;
sink->callback = NULL;
(*callback) (&sink->buffer, sink->data);
}
gsk_buffer_destruct (&sink->buffer);
return TRUE;
}
static void
gsk_memory_sink_finalize (GObject *object)
{
GskMemorySink *sink = GSK_MEMORY_SINK (object);
gsk_buffer_destruct (&sink->buffer);
if (sink->destroy != NULL)
(*sink->destroy) (sink->data);
(*global_stream_class->finalize) (object);
}
static void
gsk_memory_sink_init (GskMemorySink *memory_sink)
{
gsk_io_mark_is_writable (memory_sink);
gsk_stream_mark_never_blocks_write (memory_sink);
gsk_stream_mark_never_partial_writes (memory_sink);
}
static void
gsk_memory_sink_class_init (GskMemorySinkClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GskIOClass *io_class = GSK_IO_CLASS (class);
GskStreamClass *stream_class = GSK_STREAM_CLASS (class);
global_stream_class = g_type_class_peek_parent (class);
object_class->finalize = gsk_memory_sink_finalize;
io_class->shutdown_write = gsk_memory_sink_shutdown_write;
stream_class->raw_write = gsk_memory_sink_raw_write;
stream_class->raw_write_buffer = gsk_memory_sink_raw_write_buffer;
}
GType gsk_memory_sink_get_type()
{
static GType memory_sink_type = 0;
if (!memory_sink_type)
{
static const GTypeInfo memory_sink_info =
{
sizeof(GskMemorySinkClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) gsk_memory_sink_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GskMemorySink),
0, /* n_preallocs */
(GInstanceInitFunc) gsk_memory_sink_init,
NULL /* value_table */
};
memory_sink_type = g_type_register_static (GSK_TYPE_STREAM,
"GskMemorySink",
&memory_sink_info, 0);
}
return memory_sink_type;
}
/**
* gsk_memory_buffer_sink_new:
* @callback: function to call when the buffer has been filled.
* @data: user-data to pass to the @callback.
* @destroy: function to call when we are done with the data.
*
* Create a sink for binary data which just fills
* a binary buffer. When the stream is done,
* the @callback will be run with the full buffer.
*
* returns: the writable stream whose destination is a #GskBuffer.
*/
GskStream *gsk_memory_buffer_sink_new (GskMemoryBufferCallback callback,
gpointer data,
GDestroyNotify destroy)
{
GskMemorySink *sink = g_object_new (GSK_TYPE_MEMORY_SINK, NULL);
sink->callback = callback;
sink->data = data;
sink->destroy = destroy;
return GSK_STREAM (sink);
}
syntax highlighted by Code2HTML, v. 0.9.1