[gmime] added new gio stream
- From: Jeffrey Stedfast <fejj src gnome org>
- To: svn-commits-list gnome org
- Subject: [gmime] added new gio stream
- Date: Sun, 26 Apr 2009 17:14:50 -0400 (EDT)
commit 4339443289f29935399630122c53a6619c1a546f
Author: Jeffrey Stedfast <fejj gnome org>
Date: Sun Apr 26 17:14:14 2009 -0400
added new gio stream
2009-04-26 Jeffrey Stedfast <fejj novell com>
* tests/test-streams.c: Updated to test GIO streams.
* gmime/gmime-stream-gio.c: New GMimeStream wrapper around GIO
streams.
---
ChangeLog | 7 +
configure.in | 4 +-
docs/reference/gmime-docs.sgml | 1 +
docs/reference/gmime-sections.txt | 21 ++
gmime/Makefile.am | 2 +
gmime/gmime-gpg-context.c | 2 +-
gmime/gmime-stream-gio.c | 717 +++++++++++++++++++++++++++++++++++++
gmime/gmime-stream-gio.h | 79 ++++
gmime/gmime.h | 1 +
tests/test-streams.c | 32 ++
10 files changed, 863 insertions(+), 3 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index cbf0c4b..666e2dc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
2009-04-26 Jeffrey Stedfast <fejj novell com>
+ * tests/test-streams.c: Updated to test GIO streams.
+
+ * gmime/gmime-stream-gio.c: New GMimeStream wrapper around GIO
+ streams.
+
+2009-04-26 Jeffrey Stedfast <fejj novell com>
+
* gmime/gmime-session*.[c,h]: Removed.
* gmime/gmime-stream-pipe.[c,h]: New stream for pipes (where
diff --git a/configure.in b/configure.in
index 0b9701e..0689724 100644
--- a/configure.in
+++ b/configure.in
@@ -236,10 +236,10 @@ if test "x$enable_warnings" = "xyes"; then
AC_DEFINE(ENABLE_WARNINGS, 1, [Define if GMime should enable warning output.])
fi
-dnl We need at *least* glib 2.12.0 for g_hash_table_remove_all()
+dnl We need at *least* glib 2.16.0 for GIO
AM_PATH_GLIB_2_0(2.12.0, ,
AC_MSG_ERROR(Cannot find GLIB: Is pkg-config in your path?),
- gobject gmodule gthread)
+ gobject gmodule gthread gio)
dnl *****************************
dnl *** Checks for zlib ***
diff --git a/docs/reference/gmime-docs.sgml b/docs/reference/gmime-docs.sgml
index 2877754..a5f6079 100644
--- a/docs/reference/gmime-docs.sgml
+++ b/docs/reference/gmime-docs.sgml
@@ -30,6 +30,7 @@
<!ENTITY GMimeStreamCat SYSTEM "xml/gmime-stream-cat.xml">
<!ENTITY GMimeStreamFile SYSTEM "xml/gmime-stream-file.xml">
<!ENTITY GMimeStreamFs SYSTEM "xml/gmime-stream-fs.xml">
+<!ENTITY GMimeStreamGIO SYSTEM "xml/gmime-stream-gio.xml">
<!ENTITY GMimeStreamMem SYSTEM "xml/gmime-stream-mem.xml">
<!ENTITY GMimeStreamMmap SYSTEM "xml/gmime-stream-mmap.xml">
<!ENTITY GMimeStreamNull SYSTEM "xml/gmime-stream-null.xml">
diff --git a/docs/reference/gmime-sections.txt b/docs/reference/gmime-sections.txt
index 8074808..0d64659 100644
--- a/docs/reference/gmime-sections.txt
+++ b/docs/reference/gmime-sections.txt
@@ -136,6 +136,27 @@ GMIME_STREAM_FS_GET_CLASS
</SECTION>
<SECTION>
+<FILE>gmime-stream-gio</FILE>
+GMimeStreamGIO
+g_mime_stream_gio_new
+g_mime_stream_gio_new_with_bounds
+g_mime_stream_gio_get_owner
+g_mime_stream_gio_set_owner
+
+<SUBSECTION Private>
+g_mime_stream_gio_get_type
+
+<SUBSECTION Standard>
+GMimeStreamGIOClass
+GMIME_TYPE_STREAM_GIO
+GMIME_STREAM_GIO
+GMIME_IS_STREAM_GIO
+GMIME_STREAM_GIO_CLASS
+GMIME_IS_STREAM_GIO_CLASS
+GMIME_STREAM_GIO_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>gmime-stream-mem</FILE>
GMimeStreamMem
g_mime_stream_mem_new
diff --git a/gmime/Makefile.am b/gmime/Makefile.am
index 2939637..fc80826 100644
--- a/gmime/Makefile.am
+++ b/gmime/Makefile.am
@@ -60,6 +60,7 @@ libgmime_2_6_la_SOURCES = \
gmime-stream-file.c \
gmime-stream-filter.c \
gmime-stream-fs.c \
+ gmime-stream-gio.c \
gmime-stream-mem.c \
gmime-stream-mmap.c \
gmime-stream-null.c \
@@ -109,6 +110,7 @@ gmimeinclude_HEADERS = \
gmime-stream-file.h \
gmime-stream-filter.h \
gmime-stream-fs.h \
+ gmime-stream-gio.h \
gmime-stream-mem.h \
gmime-stream-mmap.h \
gmime-stream-null.h \
diff --git a/gmime/gmime-gpg-context.c b/gmime/gmime-gpg-context.c
index 8220761..a61b0b9 100644
--- a/gmime/gmime-gpg-context.c
+++ b/gmime/gmime-gpg-context.c
@@ -2002,7 +2002,7 @@ gpg_export_keys (GMimeCipherContext *context, GPtrArray *keys, GMimeStream *ostr
/**
* g_mime_gpg_context_new:
- * @equest_passwd: a #GMimePasswordRequestFunc
+ * @request_passwd: a #GMimePasswordRequestFunc
* @path: path to gpg binary
*
* Creates a new gpg cipher context object.
diff --git a/gmime/gmime-stream-gio.c b/gmime/gmime-stream-gio.c
new file mode 100644
index 0000000..79e9c82
--- /dev/null
+++ b/gmime/gmime-stream-gio.c
@@ -0,0 +1,717 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GMime
+ * Copyright (C) 2000-2009 Jeffrey Stedfast
+ *
+ * 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 2.1
+ * 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 this library; if not, write to the Free
+ * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "gmime-stream-gio.h"
+
+
+/**
+ * SECTION: gmime-stream-gio
+ * @title: GMimeStreamGIO
+ * @short_description: A wrapper for GLib's GIO streams
+ * @see_also: #GMimeStream
+ *
+ * A simple #GMimeStream implementation that sits on top of GLib's GIO
+ * input and output streams.
+ **/
+
+
+static void g_mime_stream_gio_class_init (GMimeStreamGIOClass *klass);
+static void g_mime_stream_gio_init (GMimeStreamGIO *stream, GMimeStreamGIOClass *klass);
+static void g_mime_stream_gio_finalize (GObject *object);
+
+static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len);
+static ssize_t stream_write (GMimeStream *stream, const char *buf, size_t len);
+static int stream_flush (GMimeStream *stream);
+static int stream_close (GMimeStream *stream);
+static gboolean stream_eos (GMimeStream *stream);
+static int stream_reset (GMimeStream *stream);
+static gint64 stream_seek (GMimeStream *stream, gint64 ofgioet, GMimeSeekWhence whence);
+static gint64 stream_tell (GMimeStream *stream);
+static gint64 stream_length (GMimeStream *stream);
+static GMimeStream *stream_substream (GMimeStream *stream, gint64 start, gint64 end);
+
+
+static GMimeStreamClass *parent_class = NULL;
+
+
+GType
+g_mime_stream_gio_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (GMimeStreamGIOClass),
+ NULL, /* base_class_init */
+ NULL, /* base_class_finalize */
+ (GClassInitFunc) g_mime_stream_gio_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GMimeStreamGIO),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) g_mime_stream_gio_init,
+ };
+
+ type = g_type_register_static (GMIME_TYPE_STREAM, "GMimeStreamGIO", &info, 0);
+ }
+
+ return type;
+}
+
+
+static void
+g_mime_stream_gio_class_init (GMimeStreamGIOClass *klass)
+{
+ GMimeStreamClass *stream_class = GMIME_STREAM_CLASS (klass);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ parent_class = g_type_class_ref (GMIME_TYPE_STREAM);
+
+ object_class->finalize = g_mime_stream_gio_finalize;
+
+ stream_class->read = stream_read;
+ stream_class->write = stream_write;
+ stream_class->flush = stream_flush;
+ stream_class->close = stream_close;
+ stream_class->eos = stream_eos;
+ stream_class->reset = stream_reset;
+ stream_class->seek = stream_seek;
+ stream_class->tell = stream_tell;
+ stream_class->length = stream_length;
+ stream_class->substream = stream_substream;
+}
+
+static void
+g_mime_stream_gio_init (GMimeStreamGIO *stream, GMimeStreamGIOClass *klass)
+{
+ stream->ostream = NULL;
+ stream->istream = NULL;
+ stream->file = NULL;
+
+ stream->owner = TRUE;
+ stream->eos = FALSE;
+}
+
+static void
+g_mime_stream_gio_finalize (GObject *object)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) object;
+
+ if (gio->istream) {
+ g_input_stream_close (gio->istream, NULL, NULL);
+ g_object_unref (gio->istream);
+ }
+
+ if (gio->ostream) {
+ g_output_stream_close (gio->ostream, NULL, NULL);
+ g_object_unref (gio->ostream);
+ }
+
+ if (gio->owner && gio->file)
+ g_object_unref (gio->file);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+set_errno (GError *err)
+{
+ if (!err) {
+ errno = 0;
+ return;
+ }
+
+ switch (err->code) {
+ case G_IO_ERROR_NOT_FOUND: errno = ENOENT; break;
+ case G_IO_ERROR_EXISTS: errno = EEXIST; break;
+ case G_IO_ERROR_IS_DIRECTORY: errno = EISDIR; break;
+ case G_IO_ERROR_NOT_DIRECTORY: errno = ENOTDIR; break;
+ case G_IO_ERROR_NOT_EMPTY: errno = ENOTEMPTY; break;
+ case G_IO_ERROR_FILENAME_TOO_LONG: errno = ENAMETOOLONG; break;
+ case G_IO_ERROR_TOO_MANY_LINKS: errno = ELOOP; break;
+ case G_IO_ERROR_NO_SPACE: errno = ENOSPC; break; // or ENOMEM
+ case G_IO_ERROR_INVALID_ARGUMENT: errno = EINVAL; break;
+ case G_IO_ERROR_PERMISSION_DENIED: errno = EACCES; break; // or EPERM
+ case G_IO_ERROR_NOT_SUPPORTED: errno = ENOTSUP; break;
+ case G_IO_ERROR_CANCELLED: errno = ECANCELED; break;
+ case G_IO_ERROR_READ_ONLY: errno = EROFS; break;
+ case G_IO_ERROR_TIMED_OUT: errno = ETIMEDOUT; break;
+ case G_IO_ERROR_BUSY: errno = EBUSY; break;
+ case G_IO_ERROR_WOULD_BLOCK: errno = EAGAIN; break;
+ case G_IO_ERROR_FAILED:
+ default:
+ errno = EIO;
+ break;
+ }
+
+ g_error_free (err);
+}
+
+static ssize_t
+stream_read (GMimeStream *stream, char *buf, size_t len)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ GError *err = NULL;
+ ssize_t nread;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (gio->istream == NULL) {
+ /* try opening an input stream */
+ if (!(gio->istream = (GInputStream *) g_file_read (gio->file, NULL, &err))) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ if (stream->bound_end != -1 && stream->position >= stream->bound_end) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (stream->bound_end != -1)
+ len = MIN (stream->bound_end - stream->position, (gint64) len);
+
+ /* make sure we are at the right position */
+ if (G_IS_SEEKABLE (gio->istream)) {
+ GSeekable *seekable = (GSeekable *) gio->istream;
+
+ if (!g_seekable_seek (seekable, stream->position, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ if ((nread = g_input_stream_read (gio->istream, buf, len, NULL, &err)) < 0) {
+ set_errno (err);
+ return -1;
+ }
+
+ if (nread > 0)
+ stream->position += nread;
+ else if (nread == 0)
+ gio->eos = TRUE;
+
+ return nread;
+}
+
+static ssize_t
+stream_write (GMimeStream *stream, const char *buf, size_t len)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ size_t nwritten = 0;
+ GError *err = NULL;
+ ssize_t n;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (gio->ostream == NULL) {
+ /* try opening an output stream */
+ if (!(gio->ostream = (GOutputStream *) g_file_append_to (gio->file, G_FILE_CREATE_NONE, NULL, &err))) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ if (stream->bound_end != -1 && stream->position >= stream->bound_end) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (stream->bound_end != -1)
+ len = MIN (stream->bound_end - stream->position, (gint64) len);
+
+ /* make sure we are at the right position */
+ if (G_IS_SEEKABLE (gio->ostream)) {
+ GSeekable *seekable = (GSeekable *) gio->ostream;
+
+ if (!g_seekable_seek (seekable, stream->position, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ if (!g_output_stream_write_all (gio->ostream, buf, len, &nwritten, NULL, &err)) {
+ set_errno (err);
+ gio->eos = TRUE;
+
+ if (nwritten == 0) {
+ /* nothing was written, return error */
+ return -1;
+ }
+
+ errno = 0;
+ }
+
+ if (nwritten > 0)
+ stream->position += nwritten;
+
+ return nwritten;
+}
+
+static int
+stream_flush (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ GError *err = NULL;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (gio->ostream && !g_output_stream_flush (gio->ostream, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+stream_close (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+
+ if (gio->istream) {
+ g_input_stream_close (gio->istream, NULL, NULL);
+ g_object_unref (gio->istream);
+ gio->istream = NULL;
+ }
+
+ if (gio->ostream) {
+ g_output_stream_close (gio->ostream, NULL, NULL);
+ g_object_unref (gio->ostream);
+ gio->ostream = NULL;
+ }
+
+ if (gio->owner && gio->file)
+ g_object_unref (gio->file);
+
+ gio->file = NULL;
+
+ return 0;
+}
+
+static gboolean
+stream_eos (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+
+ if (gio->file == NULL)
+ return TRUE;
+
+ return gio->eos;
+}
+
+static int
+stream_reset (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ GError *err = NULL;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (stream->position == stream->bound_start) {
+ gio->eos = FALSE;
+ return 0;
+ }
+
+ if (gio->istream != NULL) {
+ /* reset the input stream */
+ if (!G_IS_SEEKABLE (gio->istream)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!g_seekable_seek ((GSeekable *) gio->istream, stream->bound_start, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ if (gio->ostream != NULL) {
+ /* reset the output stream */
+ if (!G_IS_SEEKABLE (gio->ostream)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!g_seekable_seek ((GSeekable *) gio->ostream, stream->bound_start, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+ }
+
+ gio->eos = FALSE;
+
+ return 0;
+}
+
+static gint64
+gio_seekable_seek (GMimeStream *stream, GSeekable *seekable, gint64 offset, GMimeSeekWhence whence)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ gboolean need_seek = TRUE;
+ GError *err = NULL;
+ gint64 real;
+
+ switch (whence) {
+ case GMIME_STREAM_SEEK_SET:
+ real = offset;
+ break;
+ case GMIME_STREAM_SEEK_CUR:
+ real = stream->position + offset;
+ break;
+ case GMIME_STREAM_SEEK_END:
+ if (offset > 0 || (stream->bound_end == -1 && !gio->eos)) {
+ /* need to do an actual lseek() here because
+ * we either don't know the offset of the end
+ * of the stream and/or don't know if we can
+ * seek past the end */
+ if (!g_seekable_seek (seekable, offset, G_SEEK_END, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+
+ need_seek = FALSE;
+ real = offset;
+ } else if (gio->eos && stream->bound_end == -1) {
+ /* seeking backwards from eos (which happens
+ * to be our current position) */
+ real = stream->position + offset;
+ } else {
+ /* seeking backwards from a known position */
+ real = stream->bound_end + offset;
+ }
+
+ break;
+ default:
+ g_assert_not_reached ();
+ return -1;
+ }
+
+ /* sanity check the resultant offset */
+ if (real < stream->bound_start) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* short-cut if we are seeking to our current position */
+ if (real == stream->position)
+ return real;
+
+ if (stream->bound_end != -1 && real > stream->bound_end) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (need_seek && !g_seekable_seek (seekable, real, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+
+ return real;
+}
+
+static gint64
+stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ GSeekable *seekable;
+ GError *err = NULL;
+ gint64 real;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* if either of our streams are unseekable, fail */
+ if ((gio->istream != NULL && !G_IS_SEEKABLE (gio->istream)) ||
+ (gio->ostream != NULL && !G_IS_SEEKABLE (gio->ostream))) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (gio->istream || gio->ostream) {
+ gint64 outreal = -1;
+ gint64 inreal = -1;
+
+ if (gio->istream) {
+ /* seek on our input stream */
+ if ((inreal = gio_seekable_seek (stream, (GSeekable *) gio->istream, offset, whence)) == -1)
+ return -1;
+
+ if (gio->ostream == NULL)
+ outreal = inreal;
+ }
+
+ if (gio->ostream) {
+ /* seek on our output stream */
+ if ((outreal = gio_seekable_seek (stream, (GSeekable *) gio->istream, offset, whence)) == -1)
+ return -1;
+
+ if (gio->istream == NULL)
+ inreal = outreal;
+ }
+
+ if (outreal != inreal) {
+ }
+
+ real = outreal;
+ } else {
+ /* no streams yet opened... */
+ switch (whence) {
+ case GMIME_STREAM_SEEK_SET:
+ real = offset;
+ break;
+ case GMIME_STREAM_SEEK_CUR:
+ real = stream->position + offset;
+ break;
+ case GMIME_STREAM_SEEK_END:
+ real = stream->bound_end + offset;
+ break;
+ default:
+ g_assert_not_reached ();
+ return -1;
+ }
+
+ /* check that we haven't seekend beyond bound_end */
+ if (stream->bound_end != -1 && real > stream->bound_end) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* check that we are within the starting bounds */
+ if (real < stream->bound_start) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ /* reset eos if appropriate */
+ if ((stream->bound_end != -1 && real < stream->bound_end) ||
+ (gio->eos && real < stream->position))
+ gio->eos = FALSE;
+
+ stream->position = real;
+
+ return real;
+}
+
+static gint64
+stream_tell (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return stream->position;
+}
+
+static ssize_t
+gio_seekable_bound_end (GMimeStream *stream, GSeekable *seekable)
+{
+ GError *err = NULL;
+ gint64 bound_end;
+
+ if (!g_seekable_seek (seekable, 0, G_SEEK_END, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+
+ bound_end = g_seekable_tell (seekable);
+ if (bound_end < stream->bound_start) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (!g_seekable_seek (seekable, stream->position, G_SEEK_SET, NULL, &err)) {
+ set_errno (err);
+ return -1;
+ }
+
+ return bound_end;
+}
+
+static gint64
+stream_length (GMimeStream *stream)
+{
+ GMimeStreamGIO *gio = (GMimeStreamGIO *) stream;
+ gint64 bound_end;
+
+ if (gio->file == NULL) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (stream->bound_end != -1)
+ return stream->bound_end - stream->bound_start;
+
+ if (gio->istream && G_IS_SEEKABLE (gio->istream)) {
+ if ((bound_end = gio_seekable_bound_end (stream, (GSeekable *) gio->istream)) == -1)
+ return -1;
+ } else if (gio->ostream && G_IS_SEEKABLE (gio->ostream)) {
+ if ((bound_end = gio_seekable_bound_end (stream, (GSeekable *) gio->ostream)) == -1)
+ return -1;
+ } else if (!gio->istream && !gio->ostream) {
+ /* try opening an input stream to get the length */
+ if (!(gio->istream = (GInputStream *) g_file_read (gio->file, NULL, NULL))) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((bound_end = gio_seekable_bound_end (stream, (GSeekable *) gio->istream)) == -1)
+ return -1;
+ } else {
+ /* neither of our streams is seekable, can't get the length */
+ errno = EINVAL;
+ return -1;
+ }
+
+ return bound_end - stream->bound_start;
+}
+
+static GMimeStream *
+stream_substream (GMimeStream *stream, gint64 start, gint64 end)
+{
+ GMimeStreamGIO *gio;
+
+ gio = g_object_newv (GMIME_TYPE_STREAM_GIO, 0, NULL);
+ g_mime_stream_construct (GMIME_STREAM (gio), start, end);
+ gio->file = GMIME_STREAM_GIO (stream)->file;
+ gio->owner = FALSE;
+ gio->eos = FALSE;
+
+ return (GMimeStream *) gio;
+}
+
+
+/**
+ * g_mime_stream_gio_new:
+ * @file: a #GFile
+ *
+ * Creates a new #GMimeStreamGIO wrapper around a #GFile object.
+ *
+ * Returns: a stream using @file.
+ **/
+GMimeStream *
+g_mime_stream_gio_new (GFile *file)
+{
+ GMimeStreamGIO *gio;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ gio = g_object_newv (GMIME_TYPE_STREAM_GIO, 0, NULL);
+ g_mime_stream_construct (GMIME_STREAM (gio), 0, -1);
+ gio->file = file;
+ gio->owner = TRUE;
+ gio->eos = FALSE;
+
+ return (GMimeStream *) gio;
+}
+
+
+/**
+ * g_mime_stream_gio_new_with_bounds:
+ * @file: a #GFile
+ * @start: start boundary
+ * @end: end boundary
+ *
+ * Creates a new #GMimeStreamGIO stream around a #GFile with bounds
+ * @start and @end.
+ *
+ * Returns: a stream using @file with bounds @start and @end.
+ **/
+GMimeStream *
+g_mime_stream_gio_new_with_bounds (GFile *file, gint64 start, gint64 end)
+{
+ GMimeStreamGIO *gio;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+ gio = g_object_newv (GMIME_TYPE_STREAM_GIO, 0, NULL);
+ g_mime_stream_construct (GMIME_STREAM (gio), start, end);
+ gio->file = file;
+ gio->owner = TRUE;
+ gio->eos = FALSE;
+
+ return (GMimeStream *) gio;
+}
+
+
+/**
+ * g_mime_stream_gio_get_owner:
+ * @stream: a #GMimeStreamGIO stream
+ *
+ * Gets whether or not @stream owns the backend file descriptor.
+ *
+ * Returns: %TRUE if @stream owns the backend file descriptor or %FALSE
+ * otherwise.
+ **/
+gboolean
+g_mime_stream_gio_get_owner (GMimeStreamGIO *stream)
+{
+ g_return_val_if_fail (GMIME_IS_STREAM_GIO (stream), FALSE);
+
+ return stream->owner;
+}
+
+
+/**
+ * g_mime_stream_gio_set_owner:
+ * @stream: a #GMimeStreamGIO stream
+ * @owner: owner
+ *
+ * Sets whether or not @stream owns the backend GIO pointer.
+ *
+ * Note: @owner should be %TRUE if the stream should close() the
+ * backend file descriptor when destroyed or %FALSE otherwise.
+ **/
+void
+g_mime_stream_gio_set_owner (GMimeStreamGIO *stream, gboolean owner)
+{
+ g_return_if_fail (GMIME_IS_STREAM_GIO (stream));
+
+ stream->owner = owner;
+}
diff --git a/gmime/gmime-stream-gio.h b/gmime/gmime-stream-gio.h
new file mode 100644
index 0000000..7e62f45
--- /dev/null
+++ b/gmime/gmime-stream-gio.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GMime
+ * Copyright (C) 2000-2009 Jeffrey Stedfast
+ *
+ * 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 2.1
+ * 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 this library; if not, write to the Free
+ * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#ifndef __GMIME_STREAM_GIO_H__
+#define __GMIME_STREAM_GIO_H__
+
+#include <gio/gio.h>
+
+#include <gmime/gmime-stream.h>
+
+G_BEGIN_DECLS
+
+#define GMIME_TYPE_STREAM_GIO (g_mime_stream_gio_get_type ())
+#define GMIME_STREAM_GIO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GMIME_TYPE_STREAM_GIO, GMimeStreamGIO))
+#define GMIME_STREAM_GIO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GMIME_TYPE_STREAM_GIO, GMimeStreamGIOClass))
+#define GMIME_IS_STREAM_GIO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GMIME_TYPE_STREAM_GIO))
+#define GMIME_IS_STREAM_GIO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GMIME_TYPE_STREAM_GIO))
+#define GMIME_STREAM_GIO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GMIME_TYPE_STREAM_GIO, GMimeStreamGIOClass))
+
+typedef struct _GMimeStreamGIO GMimeStreamGIO;
+typedef struct _GMimeStreamGIOClass GMimeStreamGIOClass;
+
+/**
+ * GMimeStreamGIO:
+ * @parent_object: parent #GMimeStream
+ * @ostream: a #GOutputStream
+ * @istream: a #GInputStream
+ * @file: a #GFile
+ * @owner: %TRUE if this stream owns the #GFile or %FALSE otherwise
+ * @eos: %TRUE if the end of the stream has been reached or %FALSE otherwise
+ *
+ * A #GMimeStream wrapper around GLib's GIO streams.
+ **/
+struct _GMimeStreamGIO {
+ GMimeStream parent_object;
+
+ GOutputStream *ostream;
+ GInputStream *istream;
+ GFile *file;
+
+ gboolean owner;
+ gboolean eos;
+};
+
+struct _GMimeStreamGIOClass {
+ GMimeStreamClass parent_class;
+
+};
+
+
+GType g_mime_stream_gio_get_type (void);
+
+GMimeStream *g_mime_stream_gio_new (GFile *file);
+GMimeStream *g_mime_stream_gio_new_with_bounds (GFile *file, gint64 start, gint64 end);
+
+gboolean g_mime_stream_gio_get_owner (GMimeStreamGIO *stream);
+void g_mime_stream_gio_set_owner (GMimeStreamGIO *stream, gboolean owner);
+
+G_END_DECLS
+
+#endif /* __GMIME_STREAM_GIO_H__ */
diff --git a/gmime/gmime.h b/gmime/gmime.h
index 93a8b79..422d3a4 100644
--- a/gmime/gmime.h
+++ b/gmime/gmime.h
@@ -49,6 +49,7 @@
#include <gmime/gmime-stream-file.h>
#include <gmime/gmime-stream-filter.h>
#include <gmime/gmime-stream-fs.h>
+#include <gmime/gmime-stream-gio.h>
#include <gmime/gmime-stream-mem.h>
#include <gmime/gmime-stream-mmap.h>
#include <gmime/gmime-stream-null.h>
diff --git a/tests/test-streams.c b/tests/test-streams.c
index dcf6d4d..8874771 100644
--- a/tests/test-streams.c
+++ b/tests/test-streams.c
@@ -408,6 +408,37 @@ check_stream_buffer_cache (const char *input, const char *output, const char *fi
return TRUE;
}
+static gboolean
+check_stream_gio (const char *input, const char *output, const char *filename, gint64 start, gint64 end)
+{
+ GMimeStream *streams[2];
+ Exception *ex = NULL;
+ GFile *file;
+ int fd;
+
+ if (!(file = g_file_new_for_path (input)))
+ return FALSE;
+
+ if ((fd = open (output, O_RDONLY)) == -1) {
+ g_object_unref (file);
+ return FALSE;
+ }
+
+ streams[0] = g_mime_stream_gio_new_with_bounds (file, start, end);
+ streams[1] = g_mime_stream_fs_new (fd);
+
+ if (!streams_match (streams, filename))
+ ex = exception_new ("GMimeStreamBuffer (Cache Mode) streams did not match for `%s'", filename);
+
+ g_object_unref (streams[0]);
+ g_object_unref (streams[1]);
+
+ if (ex != NULL)
+ throw (ex);
+
+ return TRUE;
+}
+
typedef gboolean (* checkFunc) (const char *, const char *, const char *, gint64, gint64);
@@ -420,6 +451,7 @@ static struct {
{ "GMimeStreamMmap", check_stream_mmap },
{ "GMimeStreamBuffer (block mode)", check_stream_buffer_block },
{ "GMimeStreamBuffer (cache mode)", check_stream_buffer_cache },
+ { "GMimeStreamGIO", check_stream_gio },
};
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]