Re: Problems with Gio implementation



El 20 de agosto de 2009 13:10, Javier Jardón<javierjc1982 gmail com> escribió:
> Hello,
>
> I'm working in the gio implementation for tinymail but I have some
> problems (sorry if some of them are obvious, I'm new in Glib/GTK+
> development):
>
> The tinymail stream  (tny-stream) [1] is a in/out stream.
> The problem is that in gio there is not in/out streams, so you have to
> use a output stream or a input stream.
>
> I try to solve this working with two streams internally, so you have to
> pass the two stream when calling the function:
>

Here a patch with a GIO implementation for tinymail.

I've tried to solve the problem with the streams creating twi
different objects: one for output stream (TnyGioOutputStream) and
other for the input streams (TnyGioInputStreams)

Now, the application developer should be aware if the TnyStream that
he wants is an output or an input stream (he already know this because
if he use Gio, he has created a input or an output stream)

Please,review it and tell me if I have to fix something.

Regards
-- 
Javier Jardón Cabezas
diff --git a/Makefile.am b/Makefile.am
index b894c2c..40a6746 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,8 @@ SUBDIRS += libtinymailui
 
 if BUILD_GNOME
 SUBDIRS += libtinymailui-gnome-keyring
-SUBDIRS += libtinymail-gnomevfs 
+SUBDIRS += libtinymail-gnomevfs
+SUBDIRS += libtinymail-gio
 endif
 
 if BUILD_UIGTK
@@ -70,6 +71,7 @@ DIST_SUBDIRS = \
 	libtinymail \
 	libtinymailui \
 	libtinymail-gnomevfs \
+	libtinymail-gio \
 	libtinymailui-gtk \
 	libtinymail-camel \
 	docs \
diff --git a/configure.ac b/configure.ac
index 68beffa..c371eb5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -417,6 +417,28 @@ fi
 AC_SUBST(LIBTINYMAIL_GNOMEVFS_CFLAGS)
 AC_SUBST(LIBTINYMAIL_GNOMEVFS_LIBS)
 
+
+dnl ### libtinymail-gio, a tnystreamiface for gio ##
+if test x$build_gnome = xtrue; then
+extragtkpkgs+=" libgnomeui-2.0 gnome-keyring-1"
+extratnypkgs+=" gio-2.0"
+  PKG_CHECK_MODULES(LIBTINYMAIL_GIO, gio-2.0)
+elif test x$build_maemo = xtrue; then
+extragtkpkgs=
+extratnypkgs+=" gio-2.0"
+  PKG_CHECK_MODULES(LIBTINYMAIL_GIO, gio-2.0)
+else
+  LIBTINYMAIL_GIO_CFLAGS=
+  LIBTINYMAIL_GIO_LIBS=
+  extragtkpkgs=
+  extratnypkgs=
+fi
+
+AC_SUBST(LIBTINYMAIL_GIO_CFLAGS)
+AC_SUBST(LIBTINYMAIL_GIO_LIBS)
+
+
+
 dnl ### libtinymailui-gtk, a gtk+ implementation of libtinymail-ui ##
 PKG_CHECK_MODULES(LIBTINYMAILUI_GTK, glib-2.0 >= 2.8 gobject-2.0 $extragtkpkgs gtk+-2.0)
 AC_SUBST(LIBTINYMAILUI_GTK_CFLAGS)
@@ -613,6 +635,8 @@ libtinymailui-mozembed/libtinymailui-mozembed.pc
 libtinymailui-gnome-keyring/Makefile
 libtinymail-gnomevfs/Makefile
 libtinymail-gnomevfs/libtinymail-gnomevfs.pc
+libtinymail-gio/Makefile
+libtinymail-gio/libtinymail-gio.pc
 libtinymail-gnome-desktop/Makefile
 libtinymail-gnome-desktop/libtinymail-gnome-desktop.pc
 libtinymail-olpc/Makefile
diff --git a/libtinymail-gio/libtinymail-gio-1.0.pc b/libtinymail-gio/libtinymail-gio-1.0.pc
new file mode 100755
index 0000000..bf20994
--- /dev/null
+++ b/libtinymail-gio/libtinymail-gio-1.0.pc
@@ -0,0 +1,11 @@
+prefix=/usr/local
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libtinymail-gio
+Description: TinyMail generic library implemented for gio
+Version: 1.0.0
+Requires: libtinymail-1.0 gio-2.0
+Libs: -L${libdir} -ltinymail-gio-1.0
+Cflags: -I${includedir}/libtinymail-gio-1.0
diff --git a/libtinymail-gio/libtinymail-gio.pc.in b/libtinymail-gio/libtinymail-gio.pc.in
new file mode 100755
index 0000000..aaff7f5
--- /dev/null
+++ b/libtinymail-gio/libtinymail-gio.pc.in
@@ -0,0 +1,11 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: libtinymail-gio
+Description: TinyMail generic library implemented for gio
+Version: @VERSION@
+Requires: libtinymail- API_VERSION@ gio-2.0
+Libs: -L${libdir} -ltinymail-gio- API_VERSION@
+Cflags: -I${includedir}/libtinymail-gio- API_VERSION@
diff --git a/libtinymail-gio/tny-gio-input-stream.c b/libtinymail-gio/tny-gio-input-stream.c
new file mode 100644
index 0000000..916ba11
--- /dev/null
+++ b/libtinymail-gio/tny-gio-input-stream.c
@@ -0,0 +1,382 @@
+/* libtinymail-gio - The Tiny Mail base library for Gio
+ * Copyright (C) 2009 Javier Jardón <javierjc1982 gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * A Gio to CamelStream mapper.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <tny-gio-input-stream.h>
+
+static GObjectClass *parent_class = NULL;
+
+typedef struct _TnyGioInputStreamPriv TnyGioInputStreamPriv;
+
+struct _TnyGioInputStreamPriv
+{
+        GInputStream *input_stream;
+	gboolean eos;
+	off_t position;		/* current postion in the input stream */
+	off_t bound_start;	/* first valid position */
+	off_t bound_end;	/* first invalid position */
+};
+
+#define TNY_GIO_INPUT_STREAM_GET_PRIVATE(o) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_GIO_INPUT_STREAM, TnyGioInputStreamPriv))
+
+
+static gssize
+tny_gio_input_stream_write_to_stream (TnyStream *self, TnyStream *output)
+{
+        g_warning (  "You can't use the tny_stream_write_to_stream API on input "
+		     "streams. This problem indicates a bug in the software");
+
+        return -1;
+}
+
+static gssize
+tny_gio_input_stream_read  (TnyStream *self, char *buffer, gsize n)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+        gssize nread = 0;
+        GError *error = NULL;
+
+	if (priv->bound_end != (~0))
+		n = MIN (priv->bound_end - priv->position, n);
+
+        nread = g_input_stream_read (priv->input_stream, buffer, n, NULL, &error);
+
+        if (nread > 0)
+		priv->position += nread;
+	else if (nread == 0)
+                priv->eos = TRUE;
+
+	return nread;
+}
+
+static gssize
+tny_gio_input_stream_write (TnyStream *self, const char *buffer, gsize n)
+{
+        g_warning (  "You can't use the tny_stream_write API on input "
+		     "streams. This problem indicates a bug in the software");
+
+        return -1;
+}
+
+static gint
+tny_gio_input_stream_close (TnyStream *self)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+	GError *error;
+
+        if (!g_input_stream_close (priv->input_stream, NULL, &error))
+                return -1;
+
+        priv->input_stream = NULL;
+        priv->eos = TRUE;
+
+	return 0;
+}
+
+
+/**
+ * tny_gio_input_stream_set_stream:
+ * @self: A #TnyGioStream instance
+ * @input_stream: the stream to read from
+ *
+ * Set the input stream to play adaptor for
+ *
+ **/
+void
+tny_gio_input_stream_set_stream (TnyGioInputStream *self, GInputStream *input_stream)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+        GError *error;
+
+        if (!input_stream)
+                return;
+
+	if (priv->input_stream) {
+                g_input_stream_close (priv->input_stream, NULL, &error);
+		priv->input_stream = NULL;
+	}
+
+	priv->input_stream = input_stream;
+	priv->eos = FALSE;
+	priv->position = 0;
+
+        g_seekable_seek (GSEEKABLE (input_stream), priv->position,
+                         G_SEEK_CUR, NULL, &error);
+
+	return;
+}
+
+/**
+ * tny_gio_input_stream_new:
+ * @input_stream: The stream to read from
+ *
+ * Create an adaptor instance between #TnyStream and #Gio input stream
+ *
+ * Return value: a new #TnyStream instance
+ **/
+TnyStream*
+tny_gio_input_stream_new (GInputStream *input_stream)
+{
+	TnyGioInputStream *self = g_object_new (TNY_TYPE_GIO_INPUT_STREAM, NULL);
+
+	tny_gio_input_stream_set_streams (self, input_stream);
+
+	return TNY_STREAM (self);
+}
+
+static void
+tny_gio_input_stream_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+	TnyGioInputStream *self = (TnyGioInputStream *)instance;
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+        priv->input_stream = NULL;
+	priv->eos = FALSE;
+	priv->bound_start = 0;
+	priv->bound_end = (~0);
+	priv->position = 0;
+
+	return;
+}
+
+static void
+tny_gio_input_stream_finalize (GObject *object)
+{
+	TnyGioInputStream *self = (TnyGioInputStream *)object;
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+        GError *error = NULL;
+
+        if (G_LIKELY (priv->input_stream))
+                g_input_stream_close (priv->input_stream, NULL, &error);
+
+	(*parent_class->finalize) (object);
+
+	return;
+}
+
+static gint
+tny_gio_input_flush (TnyStream *self)
+{
+         g_warning (  "You can't use the tny_stream_write_to_stream API on input "
+		     "streams. This problem indicates a bug in the software");
+
+        return -1;
+}
+
+static gboolean
+tny_gio_input_is_eos (TnyStream *self)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+	return priv->eos;
+}
+
+static gint
+tny_gio_input_reset (TnyStream *self)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+	gint retval = 0;
+	GError *error;
+
+	if (priv->input_stream == NULL)
+	{
+		errno = EINVAL;
+		return -1;
+	}
+
+        if (!g_seekable_seek (GSEEKABLE (priv->input_stream), 0, G_SEEK_SET, NULL, &error))
+                return -1;
+
+        priv->position = 0;
+	priv->eos = FALSE;
+
+	return 0;
+}
+
+
+
+static off_t
+tny_gio_input_seek (TnySeekable *self, off_t offset, int policy)//TODO
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+        goffset real = 0;
+        GError *error;
+
+	switch (policy) {
+	case SEEK_SET:
+		real = offset;
+		break;
+	case SEEK_CUR:
+		real = priv->position + offset;
+		break;
+	case SEEK_END:
+		if (priv->bound_end == (~0)) {
+                        if (!g_seekable_seek (G_SEEKABLE (priv->input_stream), GOFFSET (offset), G_SEEK_SET, NULL, &error))
+                                return -1;
+                        real = g_seekable_tell (G_SEEKABLE (priv->input_stream));
+			if (real != -1) {
+				if (real<priv->bound_start)
+					real = priv->bound_start;
+				priv->position = real;
+			}
+			return real;
+		}
+		real = priv->bound_end + offset;
+		break;
+	}
+
+	if (priv->bound_end != (~0))
+		real = MIN (real, priv->bound_end);
+	real = MAX (real, priv->bound_start);
+
+        if (!g_seekable_seek (G_SEEKABLE (priv->input_stream), real, G_SEEK_SET, NULL, &error))
+                return -1;
+
+	if (real != priv->position && priv->eos)
+		priv->eos = FALSE;
+
+	priv->position = real;
+
+	return real;
+}
+
+static off_t
+tny_gio_input_tell (TnySeekable *self)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+	return priv->position;
+}
+
+static gint
+tny_gio_input_set_bounds (TnySeekable *self, off_t start, off_t end)
+{
+	TnyGioInputStreamPriv *priv = TNY_GIO_INPUT_STREAM_GET_PRIVATE (self);
+
+	priv->bound_end = end;
+	priv->bound_start = start;
+
+	return 0;
+}
+
+static void
+tny_stream_init (gpointer g, gpointer iface_data)
+{
+	TnyStreamIface *klass = (TnyStreamIface *)g;
+
+	klass->reset= tny_gio_input_reset;
+	klass->flush= tny_gio_input_flush;
+	klass->is_eos= tny_gio_input_is_eos;
+	klass->read= tny_gio_input_stream_read;
+	klass->write= tny_gio_input_stream_write;
+	klass->close= tny_gio_input_stream_close;
+	klass->write_to_stream= tny_gio_input_stream_write_to_stream;
+
+	return;
+}
+
+
+static void
+tny_seekable_init (gpointer g, gpointer iface_data)
+{
+	TnySeekableIface *klass = (TnySeekableIface *)g;
+
+	klass->seek= tny_gio_input_seek;
+	klass->tell= tny_gio_input_tell;
+	klass->set_bounds= tny_gio_input_set_bounds;
+
+	return;
+}
+
+static void
+tny_gio_input_stream_class_init (TnyGioInputStreamClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	object_class = (GObjectClass*) class;
+
+	object_class->finalize = tny_gio_input_stream_finalize;
+
+	g_type_class_add_private (object_class, sizeof (TnyGioInputStreamPriv));
+
+	return;
+}
+
+static gpointer
+tny_gio_input_stream_register_type (gpointer notused)
+{
+	GType type = 0;
+
+	static const GTypeInfo info =
+		{
+			sizeof (TnyGioInputStreamClass),
+			NULL,   /* base_init */
+			NULL,   /* base_finalize */
+			(GClassInitFunc) tny_gio_input_stream_class_init,   /* class_init */
+			NULL,   /* class_finalize */
+			NULL,   /* class_data */
+			sizeof (TnyGioInputStream),
+			0,      /* n_preallocs */
+			tny_gio_input_stream_instance_init,/* instance_init */
+			NULL
+		};
+
+	static const GInterfaceInfo tny_stream_info =
+		{
+			(GInterfaceInitFunc) tny_stream_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+	static const GInterfaceInfo tny_seekable_info =
+		{
+			(GInterfaceInitFunc) tny_seekable_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+	type = g_type_register_static (G_TYPE_OBJECT,
+				       "TnyVfsStream",
+				       &info, 0);
+
+	g_type_add_interface_static (type, TNY_TYPE_STREAM,
+				     &tny_stream_info);
+
+	g_type_add_interface_static (type, TNY_TYPE_SEEKABLE,
+				     &tny_seekable_info);
+
+	return GUINT_TO_POINTER (type);
+}
+
+GType
+tny_gio_input_stream_get_type (void)
+{
+	static GOnce once = G_ONCE_INIT;
+	g_once (&once, tny_gio_input_stream_register_type, NULL);
+	return GPOINTER_TO_UINT (once.retval);
+}
diff --git a/libtinymail-gio/tny-gio-input-stream.h b/libtinymail-gio/tny-gio-input-stream.h
new file mode 100644
index 0000000..58fa50e
--- /dev/null
+++ b/libtinymail-gio/tny-gio-input-stream.h
@@ -0,0 +1,58 @@
+#ifndef TNY_GIO_INPUT_STREAM_H
+#define TNY_GIO_INPUT_STREAM_H
+
+/* libtinymail-gio - The Tiny Mail base library for Gio
+ * Copyright (C) 2009 Javier Jardón <javierjc1982 gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include <tny-stream.h>
+#include <tny-seekable.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_GIO_INPUT_STREAM		(tny_gio_input_stream_get_type ())	
+#define TNY_GIO_INPUT_STREAM(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_GIO_INPUT_STREAM, TnyGioInputStream))
+#define TNY_GIO_INPUT_STREAM_CLASS(vtable)	(G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_GIO_INPUT_STREAM, TnyGioInputStreamClass))
+#define TNY_IS_GIO_INPUT_STREAM(obj)		(G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_GIO_INPUT_STREAM))
+#define TNY_IS_GIO_INPUT_STREAM_CLASS(vtable)	(G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_GIO_INPUT_STREAM))
+#define TNY_GIO_INPUT_STREAM_GET_CLASS(inst)	(G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_GIO_INPUT_STREAM, TnyGioInputStreamClass))
+
+typedef struct _TnyGioInputStream TnyGioInputStream;
+typedef struct _TnyGioInputStreamClass TnyGioInputStreamClass;
+
+struct _TnyGioInputStream
+{
+	GObject parent;
+};
+
+struct _TnyGioInputStreamClass
+{
+	GObjectClass parent;
+};
+
+GType tny_gio_input_stream_get_type (void);
+TnyStream* tny_gio_input_stream_new (GInputStream *input_stream);
+void tny_gio_input_stream_set_stream (TnyGioInputStream *self, GInputStream *input_stream);
+
+G_END_DECLS
+
+#endif
diff --git a/libtinymail-gio/tny-gio-output-stream.c b/libtinymail-gio/tny-gio-output-stream.c
new file mode 100644
index 0000000..d240a7a
--- /dev/null
+++ b/libtinymail-gio/tny-gio-output-stream.c
@@ -0,0 +1,407 @@
+/* libtinymail-gio - The Tiny Mail base library for Gio
+ * Copyright (C) 2009 Javier Jardón <javierjc1982 gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * A Gio to CamelStream mapper.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <tny-gio-output-stream.h>
+
+static GObjectClass *parent_class = NULL;
+
+typedef struct _TnyGioOutputStreamPriv TnyGioOutputStreamPriv;
+
+struct _TnyGioOutputStreamPriv
+{
+        GOutputStream *output_stream;
+	gboolean eos;
+	off_t position;		/* current postion in the input stream */
+	off_t bound_start;	/* first valid position */
+	off_t bound_end;	/* first invalid position */
+};
+
+#define TNY_GIO_OUTPUT_STREAM_GET_PRIVATE(o) \
+	(G_TYPE_INSTANCE_GET_PRIVATE ((o), TNY_TYPE_GIO_OUTPUT_STREAM, TnyGioOutputStreamPriv))
+
+
+static gssize
+tny_gio_output_stream_write_to_stream (TnyStream *self, TnyStream *output)
+{
+	char tmp_buf[4096];
+	gssize total = 0;
+	gssize nb_read;
+	gssize nb_written;
+
+	g_assert (TNY_IS_STREAM (output));
+
+	while (G_UNLIKELY (!tny_stream_is_eos (self))) {
+		nb_read = tny_stream_read (self, tmp_buf, sizeof (tmp_buf));
+		if (G_UNLIKELY (nb_read < 0))
+			return -1;
+		else if (G_LIKELY (nb_read > 0)) {
+			nb_written = 0;
+
+			while (G_LIKELY (nb_written < nb_read))
+			{
+				gssize len = tny_stream_write (output, tmp_buf + nb_written,
+								  nb_read - nb_written);
+				if (G_UNLIKELY (len < 0))
+					return -1;
+				nb_written += len;
+			}
+			total += nb_written;
+		}
+	}
+	return total;
+}
+
+static gssize
+tny_gio_output_stream_read  (TnyStream *self, char *buffer, gsize n)
+{
+        g_warning (  "You can't use the tny_stream_read API on output "
+		     "streams. This problem indicates a bug in the software");
+
+	return -1;
+}
+
+static gssize
+tny_gio_output_stream_write (TnyStream *self, const char *buffer, gsize n)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+        gssize nwritten = 0;
+        GError *error = NULL;
+
+	if (priv->bound_end != (~0))
+		n = MIN (priv->bound_end - priv->position, n);
+
+        nwritten = g_output_stream_write (priv->output_stream, buffer, n, NULL, &error);
+
+	if (nwritten > 0)
+		priv->position += nwritten;
+	else if (nwritten == 0)
+                priv->eos = TRUE;
+
+	return nwritten;
+}
+
+static gint
+tny_gio_output_stream_close (TnyStream *self)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+	GError *error;
+
+        if (!g_output_stream_close (priv->output_stream, NULL, &error))
+                return -1;
+
+        priv->output_stream = NULL;
+        priv->eos = TRUE;
+
+	return 0;
+}
+
+
+/**
+ * tny_gio_output_stream_set_stream:
+ * @self: A #TnyGioStream instance
+ * @output_stream: the stream to write to
+ *
+ * Set the output stream to play adaptor for
+ *
+ **/
+void
+tny_gio_output_stream_set_stream (TnyGioOutputStream *self, GOutputStream *output_stream)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+        GError *error;
+
+        if (!output_stream)
+                return;
+
+	if (priv->output_stream) {
+                g_output_stream_close (priv->output_stream, NULL, &error);
+		priv->output_stream = NULL;
+	}
+
+	priv->output_stream = output_stream;
+	priv->eos = FALSE;
+	priv->position = 0;
+
+        g_seekable_seek (GSEEKABLE (output_stream), priv->position,
+                         G_SEEK_CUR, NULL, &error);
+
+	return;
+}
+
+/**
+ * tny_gio_output_stream_new:
+ * @output_stream: The stream to read from
+ *
+ * Create an adaptor instance between #TnyStream and #Gio input stream
+ *
+ * Return value: a new #TnyStream instance
+ **/
+TnyStream*
+tny_gio_output_stream_new (GOutputStream *output_stream)
+{
+	TnyGioOutputStream *self = g_object_new (TNY_TYPE_GIO_OUTPUT_STREAM, NULL);
+
+	tny_gio_output_stream_set_streams (self, output_stream);
+
+	return TNY_STREAM (self);
+}
+
+static void
+tny_gio_output_stream_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+	TnyGioOutputStream *self = (TnyGioOutputStream *)instance;
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+        priv->output_stream = NULL;
+	priv->eos = FALSE;
+	priv->bound_start = 0;
+	priv->bound_end = (~0);
+	priv->position = 0;
+
+	return;
+}
+
+static void
+tny_gio_output_stream_finalize (GObject *object)
+{
+	TnyGioOutputStream *self = (TnyGioOutputStream *)object;
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+        GError *error = NULL;
+
+        if (G_LIKELY (priv->output_stream))
+                g_output_stream_close (priv->output_stream, NULL, &error);
+
+	(*parent_class->finalize) (object);
+
+	return;
+}
+
+static gint
+tny_gio_output_flush (TnyStream *self)
+{
+        TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+        GError *error;
+
+        if (!g_output_stream_flush (priv->output_stream, NULL, &error))
+                return -1;
+
+	return 0;
+}
+
+static gboolean
+tny_gio_output_is_eos (TnyStream *self)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+	return priv->eos;
+}
+
+static gint
+tny_gio_output_reset (TnyStream *self)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+	gint retval = 0;
+	GError *error;
+
+	if (priv->output_stream == NULL)
+	{
+		errno = EINVAL;
+		return -1;
+	}
+
+        if (!g_seekable_seek (GSEEKABLE (priv->output_stream), 0, G_SEEK_SET, NULL, &error))
+                return -1;
+
+        priv->position = 0;
+	priv->eos = FALSE;
+
+	return 0;
+}
+
+
+
+static off_t
+tny_gio_output_seek (TnySeekable *self, off_t offset, int policy)//TODO
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+        goffset real = 0;
+        GError *error;
+
+	switch (policy) {
+	case SEEK_SET:
+		real = offset;
+		break;
+	case SEEK_CUR:
+		real = priv->position + offset;
+		break;
+	case SEEK_END:
+		if (priv->bound_end == (~0)) {
+                        if (!g_seekable_seek (G_SEEKABLE (priv->output_stream), GOFFSET (offset), G_SEEK_SET, NULL, &error))
+                                return -1;
+                        real = g_seekable_tell (G_SEEKABLE (priv->output_stream));
+			if (real != -1) {
+				if (real<priv->bound_start)
+					real = priv->bound_start;
+				priv->position = real;
+			}
+			return real;
+		}
+		real = priv->bound_end + offset;
+		break;
+	}
+
+	if (priv->bound_end != (~0))
+		real = MIN (real, priv->bound_end);
+	real = MAX (real, priv->bound_start);
+
+        if (!g_seekable_seek (G_SEEKABLE (priv->output_stream), real, G_SEEK_SET, NULL, &error))
+                return -1;
+
+	if (real != priv->position && priv->eos)
+		priv->eos = FALSE;
+
+	priv->position = real;
+
+	return real;
+}
+
+static off_t
+tny_gio_output_tell (TnySeekable *self)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+	return priv->position;
+}
+
+static gint
+tny_gio_output_set_bounds (TnySeekable *self, off_t start, off_t end)
+{
+	TnyGioOutputStreamPriv *priv = TNY_GIO_OUTPUT_STREAM_GET_PRIVATE (self);
+
+	priv->bound_end = end;
+	priv->bound_start = start;
+
+	return 0;
+}
+
+static void
+tny_stream_init (gpointer g, gpointer iface_data)
+{
+	TnyStreamIface *klass = (TnyStreamIface *)g;
+
+	klass->reset= tny_gio_output_reset;
+	klass->flush= tny_gio_output_flush;
+	klass->is_eos= tny_gio_output_is_eos;
+	klass->read= tny_gio_output_stream_read;
+	klass->write= tny_gio_output_stream_write;
+	klass->close= tny_gio_output_stream_close;
+	klass->write_to_stream= tny_gio_output_stream_write_to_stream;
+
+	return;
+}
+
+
+static void
+tny_seekable_init (gpointer g, gpointer iface_data)
+{
+	TnySeekableIface *klass = (TnySeekableIface *)g;
+
+	klass->seek= tny_gio_output_seek;
+	klass->tell= tny_gio_output_tell;
+	klass->set_bounds= tny_gio_output_set_bounds;
+
+	return;
+}
+
+static void
+tny_gio_output_stream_class_init (TnyGioOutputStreamClass *class)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (class);
+	object_class = (GObjectClass*) class;
+
+	object_class->finalize = tny_gio_output_stream_finalize;
+
+	g_type_class_add_private (object_class, sizeof (TnyGioOutputStreamPriv));
+
+	return;
+}
+
+static gpointer
+tny_gio_output_stream_register_type (gpointer notused)
+{
+	GType type = 0;
+
+	static const GTypeInfo info =
+		{
+			sizeof (TnyGioOutputStreamClass),
+			NULL,   /* base_init */
+			NULL,   /* base_finalize */
+			(GClassInitFunc) tny_gio_output_stream_class_init,   /* class_init */
+			NULL,   /* class_finalize */
+			NULL,   /* class_data */
+			sizeof (TnyGioOutputStream),
+			0,      /* n_preallocs */
+			tny_gio_output_stream_instance_init,/* instance_init */
+			NULL
+		};
+
+	static const GInterfaceInfo tny_stream_info =
+		{
+			(GInterfaceInitFunc) tny_stream_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+	static const GInterfaceInfo tny_seekable_info =
+		{
+			(GInterfaceInitFunc) tny_seekable_init, /* interface_init */
+			NULL,         /* interface_finalize */
+			NULL          /* interface_data */
+		};
+
+	type = g_type_register_static (G_TYPE_OBJECT,
+				       "TnyVfsStream",
+				       &info, 0);
+
+	g_type_add_interface_static (type, TNY_TYPE_STREAM,
+				     &tny_stream_info);
+
+	g_type_add_interface_static (type, TNY_TYPE_SEEKABLE,
+				     &tny_seekable_info);
+
+	return GUINT_TO_POINTER (type);
+}
+
+GType
+tny_gio_output_stream_get_type (void)
+{
+	static GOnce once = G_ONCE_INIT;
+	g_once (&once, tny_gio_output_stream_register_type, NULL);
+	return GPOINTER_TO_UINT (once.retval);
+}
diff --git a/libtinymail-gio/tny-gio-output-stream.h b/libtinymail-gio/tny-gio-output-stream.h
new file mode 100644
index 0000000..0dda0bb
--- /dev/null
+++ b/libtinymail-gio/tny-gio-output-stream.h
@@ -0,0 +1,58 @@
+#ifndef TNY_GIO_OUTPUT_STREAM_H
+#define TNY_GIO_OUTPUT_STREAM_H
+
+/* libtinymail-gio - The Tiny Mail base library for Gio
+ * Copyright (C) 2009 Javier Jardón <javierjc1982 gmail com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with self library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <glib.h>
+#include <gio/gio.h>
+#include <glib-object.h>
+
+#include <tny-stream.h>
+#include <tny-seekable.h>
+
+G_BEGIN_DECLS
+
+#define TNY_TYPE_GIO_OUTPUT_STREAM             (tny_gio_output_stream_get_type ())
+#define TNY_GIO_OUTPUT_STREAM(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), TNY_TYPE_GIO_OUTPUT_STREAM, TnyGioOutputStream))
+#define TNY_GIO_OUTPUT_STREAM_CLASS(vtable)    (G_TYPE_CHECK_CLASS_CAST ((vtable), TNY_TYPE_GIO_OUTPUT_STREAM, TnyGioOutputStreamClass))
+#define TNY_IS_GIO_OUTPUT_STREAM(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TNY_TYPE_GIO_OUTPUT_STREAM))
+#define TNY_IS_GIO_OUTPUT_STREAM_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), TNY_TYPE_GIO_OUTPUT_STREAM))
+#define TNY_GIO_OUTPUT_STREAM_GET_CLASS(inst)  (G_TYPE_INSTANCE_GET_CLASS ((inst), TNY_TYPE_GIO_OUTPUT_STREAM, TnyGioOutputStreamClass))
+
+typedef struct _TnyGioOutputStream TnyGioOutputStream;
+typedef struct _TnyGioOutputStreamClass TnyGioOutputStreamClass;
+
+struct _TnyGioOutputStream
+{
+	GObject parent;
+};
+
+struct _TnyGioOutputStreamClass
+{
+	GObjectClass parent;
+};
+
+GType tny_gio_output_stream_get_type (void);
+TnyStream* tny_gio_output_stream_new (GOutputStream *output_stream);
+void tny_gio_output_stream_set_stream (TnyGioOutputStream *self, GOutputStream *output_stream);
+
+G_END_DECLS
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]