/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* GMime
* Copyright (C) 2000-2007 Jeffrey Stedfast
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; 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 <string.h>
#include "gmime-stream.h"
#define d(x)
static void g_mime_stream_class_init (GMimeStreamClass *klass);
static void g_mime_stream_init (GMimeStream *stream, GMimeStreamClass *klass);
static void g_mime_stream_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 off_t stream_seek (GMimeStream *stream, off_t offset, GMimeSeekWhence whence);
static off_t stream_tell (GMimeStream *stream);
static ssize_t stream_length (GMimeStream *stream);
static GMimeStream *stream_substream (GMimeStream *stream, off_t start, off_t end);
static GObjectClass *parent_class = NULL;
GType
g_mime_stream_get_type (void)
{
static GType type = 0;
if (!type) {
static const GTypeInfo info = {
sizeof (GMimeStreamClass),
NULL, /* base_class_init */
NULL, /* base_class_finalize */
(GClassInitFunc) g_mime_stream_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GMimeStream),
0, /* n_preallocs */
(GInstanceInitFunc) g_mime_stream_init,
};
type = g_type_register_static (G_TYPE_OBJECT, "GMimeStream", &info, 0);
}
return type;
}
static void
g_mime_stream_class_init (GMimeStreamClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
parent_class = g_type_class_ref (G_TYPE_OBJECT);
object_class->finalize = g_mime_stream_finalize;
klass->read = stream_read;
klass->write = stream_write;
klass->flush = stream_flush;
klass->close = stream_close;
klass->eos = stream_eos;
klass->reset = stream_reset;
klass->seek = stream_seek;
klass->tell = stream_tell;
klass->length = stream_length;
klass->substream = stream_substream;
}
static void
g_mime_stream_init (GMimeStream *stream, GMimeStreamClass *klass)
{
stream->super_stream = NULL;
stream->position = 0;
stream->bound_start = 0;
stream->bound_end = 0;
}
static void
g_mime_stream_finalize (GObject *object)
{
GMimeStream *stream = (GMimeStream *) object;
if (stream->super_stream)
g_object_unref (stream->super_stream);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
/**
* g_mime_stream_construct:
* @stream: stream
* @start: start boundary
* @end: end boundary
*
* Initializes a new stream with bounds @start and @end.
**/
void
g_mime_stream_construct (GMimeStream *stream, off_t start, off_t end)
{
stream->position = start;
stream->bound_start = start;
stream->bound_end = end;
}
static ssize_t
stream_read (GMimeStream *stream, char *buf, size_t len)
{
d(g_warning ("Invoked default stream_read implementation."));
return 0;
}
/**
* g_mime_stream_read:
* @stream: stream
* @buf: buffer
* @len: buffer length
*
* Attempts to read up to @len bytes from @stream into @buf.
*
* Returns the number of bytes read or %-1 on fail.
**/
ssize_t
g_mime_stream_read (GMimeStream *stream, char *buf, size_t len)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
g_return_val_if_fail (buf != NULL, -1);
if (len == 0)
return 0;
return GMIME_STREAM_GET_CLASS (stream)->read (stream, buf, len);
}
static ssize_t
stream_write (GMimeStream *stream, const char *buf, size_t len)
{
d(g_warning ("Invoked default stream_write implementation."));
return 0;
}
/**
* g_mime_stream_write:
* @stream: stream
* @buf: buffer
* @len: buffer length
*
* Attempts to write up to @len bytes of @buf to @stream.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_stream_write (GMimeStream *stream, const char *buf, size_t len)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
g_return_val_if_fail (buf != NULL, -1);
if (len == 0)
return 0;
return GMIME_STREAM_GET_CLASS (stream)->write (stream, buf, len);
}
static int
stream_flush (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_flush implementation."));
return 0;
}
/**
* g_mime_stream_flush:
* @stream: stream
*
* Sync's the stream to disk.
*
* Returns %0 on success or %-1 on fail.
**/
int
g_mime_stream_flush (GMimeStream *stream)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
return GMIME_STREAM_GET_CLASS (stream)->flush (stream);
}
static int
stream_close (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_close implementation."));
return 0;
}
/**
* g_mime_stream_close:
* @stream: stream
*
* Closes the stream.
*
* Returns %0 on success or %-1 on fail.
**/
int
g_mime_stream_close (GMimeStream *stream)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
return GMIME_STREAM_GET_CLASS (stream)->close (stream);
}
static gboolean
stream_eos (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_eos implementation."));
return stream->position < stream->bound_end;
}
/**
* g_mime_stream_eos:
* @stream: stream
*
* Tests the end-of-stream indicator for @stream.
*
* Returns %TRUE on EOS or %FALSE otherwise.
**/
gboolean
g_mime_stream_eos (GMimeStream *stream)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), TRUE);
if (stream->bound_end != -1 && stream->position >= stream->bound_end)
return TRUE;
return GMIME_STREAM_GET_CLASS (stream)->eos (stream);
}
static int
stream_reset (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_reset implementation."));
return 0;
}
/**
* g_mime_stream_reset:
* @stream: stream
*
* Resets the stream.
*
* Returns %0 on success or %-1 on fail.
**/
int
g_mime_stream_reset (GMimeStream *stream)
{
int rv;
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
if ((rv = GMIME_STREAM_GET_CLASS (stream)->reset (stream)) == 0)
stream->position = stream->bound_start;
return rv;
}
static off_t
stream_seek (GMimeStream *stream, off_t offset, GMimeSeekWhence whence)
{
d(g_warning ("Invoked default stream_seek implementation."));
return -1;
}
/**
* g_mime_stream_seek:
* @stream: stream
* @offset: positional offset
* @whence: seek directive
*
* Repositions the offset of the stream @stream to
* the argument @offset according to the
* directive @whence as follows:
*
* #GMIME_STREAM_SEEK_SET: Seek @offset bytes relative to
* the beginning (bound_start) of the stream.
*
* #GMIME_STREAM_SEEK_CUR: Seek @offset bytes relative to the
* current offset of the stream.
*
* #GMIME_STREAM_SEEK_END: Seek @offset bytes relative to the
* end of the stream (bound_end if non-negative).
*
* Returns the resultant position on success or %-1 on fail.
**/
off_t
g_mime_stream_seek (GMimeStream *stream, off_t offset, GMimeSeekWhence whence)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
return GMIME_STREAM_GET_CLASS (stream)->seek (stream, offset, whence);
}
static off_t
stream_tell (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_tell implementation."));
return stream->position;
}
/**
* g_mime_stream_tell:
* @stream: stream
*
* Gets the current offset within the stream.
*
* Returns the current position within the stream or %-1 on fail.
**/
off_t
g_mime_stream_tell (GMimeStream *stream)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
return GMIME_STREAM_GET_CLASS (stream)->tell (stream);
}
static ssize_t
stream_length (GMimeStream *stream)
{
d(g_warning ("Invoked default stream_length implementation."));
return -1;
}
/**
* g_mime_stream_length:
* @stream: stream
*
* Gets the length of the stream.
*
* Returns the length of the stream or %-1 if unknown.
**/
ssize_t
g_mime_stream_length (GMimeStream *stream)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
return GMIME_STREAM_GET_CLASS (stream)->length (stream);
}
static GMimeStream *
stream_substream (GMimeStream *stream, off_t start, off_t end)
{
d(g_warning ("Invoked default stream_tell implementation."));
return NULL;
}
/**
* g_mime_stream_substream:
* @stream: stream
* @start: start boundary
* @end: end boundary
*
* Creates a new substream of @stream with bounds @start and @end.
*
* Returns a substream of @stream with bounds @start and @end.
**/
GMimeStream *
g_mime_stream_substream (GMimeStream *stream, off_t start, off_t end)
{
GMimeStream *sub;
g_return_val_if_fail (GMIME_IS_STREAM (stream), NULL);
if ((sub = GMIME_STREAM_GET_CLASS (stream)->substream (stream, start, end))) {
sub->super_stream = stream;
g_object_ref (stream);
}
return sub;
}
/**
* g_mime_stream_ref:
* @stream: stream
*
* Ref's a stream.
*
* WARNING: This method is deprecated. Use g_object_ref() instead.
**/
void
g_mime_stream_ref (GMimeStream *stream)
{
g_return_if_fail (GMIME_IS_STREAM (stream));
g_object_ref (stream);
}
/**
* g_mime_stream_unref:
* @stream: stream
*
* Unref's a stream.
*
* WARNING: This method is deprecated. Use g_object_unref() instead.
**/
void
g_mime_stream_unref (GMimeStream *stream)
{
g_return_if_fail (GMIME_IS_STREAM (stream));
g_object_unref (stream);
}
/**
* g_mime_stream_set_bounds:
* @stream: stream
* @start: start boundary
* @end: end boundary
*
* Set the bounds on a stream.
**/
void
g_mime_stream_set_bounds (GMimeStream *stream, off_t start, off_t end)
{
g_return_if_fail (GMIME_IS_STREAM (stream));
stream->bound_start = start;
stream->bound_end = end;
if (stream->position < start)
stream->position = start;
else if (stream->position > end && end != -1)
stream->position = end;
}
/**
* g_mime_stream_write_string:
* @stream: stream
* @string: string to write
*
* Writes @string to @stream.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_stream_write_string (GMimeStream *stream, const char *string)
{
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
g_return_val_if_fail (string != NULL, -1);
return g_mime_stream_write (stream, (char *) string, strlen (string));
}
/**
* g_mime_stream_printf:
* @stream: stream
* @fmt: format
* @Varargs: arguments
*
* Write formatted output to a stream.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_stream_printf (GMimeStream *stream, const char *fmt, ...)
{
va_list args;
char *string;
ssize_t ret;
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
g_return_val_if_fail (fmt != NULL, -1);
va_start (args, fmt);
string = g_strdup_vprintf (fmt, args);
va_end (args);
if (!string)
return -1;
ret = g_mime_stream_write (stream, string, strlen (string));
g_free (string);
return ret;
}
/**
* g_mime_stream_write_to_stream:
* @src: source stream
* @dest: destination stream
*
* Attempts to write stream @src to stream @dest.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_stream_write_to_stream (GMimeStream *src, GMimeStream *dest)
{
ssize_t nread, nwritten, total = 0;
char buf[4096];
g_return_val_if_fail (GMIME_IS_STREAM (src), -1);
g_return_val_if_fail (GMIME_IS_STREAM (dest), -1);
while (!g_mime_stream_eos (src)) {
if ((nread = g_mime_stream_read (src, buf, sizeof (buf))) < 0)
return -1;
if (nread > 0) {
nwritten = 0;
while (nwritten < nread) {
ssize_t len;
if ((len = g_mime_stream_write (dest, buf + nwritten, nread - nwritten)) < 0)
return -1;
nwritten += len;
}
total += nwritten;
}
}
return total;
}
/**
* g_mime_stream_writev:
* @stream: stream
* @vector: i/o vector
* @count: number of vector elements
*
* Writes at most @count blocks described by @vector to @stream.
*
* Returns the number of bytes written or %-1 on fail.
**/
ssize_t
g_mime_stream_writev (GMimeStream *stream, GMimeStreamIOVector *vector, size_t count)
{
ssize_t total = 0;
size_t i;
g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
for (i = 0; i < count; i++) {
char *buffer = vector[i].data;
size_t nwritten = 0;
ssize_t n;
while (nwritten < vector[i].len) {
if ((n = g_mime_stream_write (stream, buffer + nwritten,
vector[i].len - nwritten)) < 0)
return -1;
nwritten += n;
}
total += nwritten;
}
return total;
}
syntax highlighted by Code2HTML, v. 0.9.1