diff options
-rw-r--r-- | camel/ChangeLog | 6 | ||||
-rw-r--r-- | camel/camel-seekable-substream.c | 479 | ||||
-rw-r--r-- | camel/camel-seekable-substream.h | 23 |
3 files changed, 204 insertions, 304 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index fff7a3f951..f31fac1b2c 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,11 @@ 2000-04-19 Dan Winship <danw@helixcode.com> + * camel-seekable-substream.c: clean up a lot. + (eos): When testing for end-of-stream, reset the parent position + before testing if it is at end-of-stream, since either (a) it may + have been seek'ed to eos by someone else, or (b) we may have been + seek'ed away from eos and it hasn't been synced yet. + * camel-medium.[ch] (camel_medium_add_header): const poison. (Belatedly goes with my change of 2000-02-23.) (camel_medium_init): Use g_strcase_{hash,equal} on the header diff --git a/camel/camel-seekable-substream.c b/camel/camel-seekable-substream.c index 3c9534e326..59f53c3090 100644 --- a/camel/camel-seekable-substream.c +++ b/camel/camel-seekable-substream.c @@ -1,16 +1,15 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* camel-stream-fs.c : file system based stream */ -/* inspired by gnome-stream-fs.c in bonobo by Miguel de Icaza */ -/* +/* * - * Author : + * Author : * Bertrand Guiheneuf <bertrand@helixcode.com> * * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as + * 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. * @@ -27,120 +26,91 @@ #include <config.h> #include "camel-seekable-substream.h" -static CamelSeekableStreamClass *parent_class=NULL; - +static CamelSeekableStreamClass *parent_class = NULL; /* Returns the class for a CamelSeekableSubStream */ #define CSS_CLASS(so) CAMEL_SEEKABLE_SUBSTREAM_CLASS (GTK_OBJECT(so)->klass) - - - -static gint _read (CamelStream *stream, - gchar *buffer, gint n); -static gint _write (CamelStream *stream, - const gchar *buffer, - gint n); -static void _flush (CamelStream *stream); -static gint _available (CamelStream *stream); -static gboolean _eos (CamelStream *stream); -static void _close (CamelStream *stream); -static gint _seek (CamelSeekableStream *stream, - gint offset, - CamelStreamSeekPolicy policy); - -static void _finalize (GtkObject *object); -static void _destroy (GtkObject *object); - -static void _init_with_seekable_stream_and_bounds (CamelSeekableSubstream *seekable_substream, +static gint stream_read (CamelStream *stream, + gchar *buffer, gint n); +static gint stream_write (CamelStream *stream, + const gchar *buffer, + gint n); +static void stream_flush (CamelStream *stream); +static gint available (CamelStream *stream); +static gboolean eos (CamelStream *stream); +static gint stream_seek (CamelSeekableStream *stream, + gint offset, + CamelStreamSeekPolicy policy); + +static void finalize (GtkObject *object); + +static void init_with_seekable_stream_and_bounds (CamelSeekableSubstream *seekable_substream, CamelSeekableStream *parent_stream, - guint32 inf_bound, + guint32 inf_bound, gint64 sup_bound); - static void camel_seekable_substream_class_init (CamelSeekableSubstreamClass *camel_seekable_substream_class) { - CamelSeekableStreamClass *camel_seekable_stream_class = CAMEL_SEEKABLE_STREAM_CLASS (camel_seekable_substream_class); - CamelStreamClass *camel_stream_class = CAMEL_STREAM_CLASS (camel_seekable_substream_class); - GtkObjectClass *gtk_object_class = GTK_OBJECT_CLASS (camel_seekable_substream_class); + CamelSeekableStreamClass *camel_seekable_stream_class = + CAMEL_SEEKABLE_STREAM_CLASS (camel_seekable_substream_class); + CamelStreamClass *camel_stream_class = + CAMEL_STREAM_CLASS (camel_seekable_substream_class); + GtkObjectClass *gtk_object_class = + GTK_OBJECT_CLASS (camel_seekable_substream_class); parent_class = gtk_type_class (camel_seekable_stream_get_type ()); - + /* virtual method definition */ - camel_seekable_substream_class->init_with_seekable_stream_and_bounds = _init_with_seekable_stream_and_bounds; - - /* virtual method overload */ - camel_stream_class->read = _read; - camel_stream_class->write = _write; - camel_stream_class->flush = _flush; - camel_stream_class->available = _available; - camel_stream_class->eos = _eos; - camel_stream_class->close = _close; + camel_seekable_substream_class->init_with_seekable_stream_and_bounds = + init_with_seekable_stream_and_bounds; - camel_seekable_stream_class->seek = _seek; + /* virtual method overload */ + camel_stream_class->read = stream_read; + camel_stream_class->write = stream_write; + camel_stream_class->flush = stream_flush; + camel_stream_class->available = available; + camel_stream_class->eos = eos; - gtk_object_class->finalize = _finalize; - gtk_object_class->destroy = _destroy; + camel_seekable_stream_class->seek = stream_seek; + gtk_object_class->finalize = finalize; } -static void -camel_seekable_substream_init (gpointer object, gpointer klass) -{ - /* does nothing */ -} - - - GtkType camel_seekable_substream_get_type (void) { static GtkType camel_seekable_substream_type = 0; - - if (!camel_seekable_substream_type) { - GtkTypeInfo camel_seekable_substream_info = + + if (!camel_seekable_substream_type) { + GtkTypeInfo camel_seekable_substream_info = { "CamelSeekableSubstream", sizeof (CamelSeekableSubstream), sizeof (CamelSeekableSubstreamClass), (GtkClassInitFunc) camel_seekable_substream_class_init, - (GtkObjectInitFunc) camel_seekable_substream_init, + (GtkObjectInitFunc) NULL, /* reserved_1 */ NULL, /* reserved_2 */ NULL, (GtkClassInitFunc) NULL, }; - + camel_seekable_substream_type = gtk_type_unique (camel_seekable_stream_get_type (), &camel_seekable_substream_info); } - - return camel_seekable_substream_type; -} - - - - - -static void -_destroy (GtkObject *object) -{ - /* does nothing for the moment */ - GTK_OBJECT_CLASS (parent_class)->destroy (object); + return camel_seekable_substream_type; } -static void -_finalize (GtkObject *object) +static void +finalize (GtkObject *object) { - CamelSeekableStream *seekable_stream; - CamelSeekableSubstream *seekable_substream; - - seekable_stream = CAMEL_SEEKABLE_STREAM (object); - seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (object); + CamelSeekableSubstream *seekable_substream = + CAMEL_SEEKABLE_SUBSTREAM (object); if (seekable_substream->parent_stream) gtk_object_unref (GTK_OBJECT (seekable_substream->parent_stream)); @@ -149,334 +119,261 @@ _finalize (GtkObject *object) } - -static void -_set_bounds (CamelSeekableSubstream *seekable_substream, guint32 inf_bound, gint64 sup_bound) +static void +set_bounds (CamelSeekableSubstream *seekable_substream, + guint32 inf_bound, gint64 sup_bound) { - g_assert (seekable_substream); - g_assert (seekable_substream->parent_stream); - /* store the bounds */ seekable_substream->inf_bound = inf_bound; seekable_substream->sup_bound = sup_bound; - - seekable_substream->cur_pos = 0; seekable_substream->eos = FALSE; } + static void -_reemit_parent_signal (CamelStream *parent_stream, gpointer user_data) +reemit_parent_signal (CamelStream *parent_stream, gpointer user_data) { - CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (user_data); + CamelSeekableSubstream *seekable_substream = + CAMEL_SEEKABLE_SUBSTREAM (user_data); - gtk_signal_emit_by_name (GTK_OBJECT (seekable_substream), "data_available"); - + gtk_signal_emit_by_name (GTK_OBJECT (seekable_substream), + "data_available"); } -static void -_init_with_seekable_stream_and_bounds (CamelSeekableSubstream *seekable_substream, - CamelSeekableStream *parent_stream, - guint32 inf_bound, - gint64 sup_bound) +static void +init_with_seekable_stream_and_bounds (CamelSeekableSubstream *seekable_substream, + CamelSeekableStream *parent_stream, + guint32 inf_bound, gint64 sup_bound) { - /* sanity checks */ - g_assert (seekable_substream); - g_assert (!seekable_substream->parent_stream); - g_assert (parent_stream); - - /* store the parent stream */ + /* Store the parent stream. */ seekable_substream->parent_stream = parent_stream; gtk_object_ref (GTK_OBJECT (parent_stream)); + gtk_object_sink (GTK_OBJECT (parent_stream)); - /* set the bound of the substream */ - _set_bounds (seekable_substream, inf_bound, sup_bound); + /* Set the bound of the substream. */ + set_bounds (seekable_substream, inf_bound, sup_bound); - /* - * connect to the parent stream "data_available" - * stream so that we can reemit the signal on the - * seekable substream in case some data would - * be available for us + /* Connect to the parent stream "data_available" signal so + * that we can reemit the signal on the seekable substream in + * case some data would be available for us */ - gtk_signal_connect (GTK_OBJECT (parent_stream), - "data_available", - _reemit_parent_signal, - seekable_substream); - - gtk_signal_emit_by_name (GTK_OBJECT (seekable_substream), "data_available"); + gtk_signal_connect (GTK_OBJECT (parent_stream), "data_available", + reemit_parent_signal, seekable_substream); + gtk_signal_emit_by_name (GTK_OBJECT (seekable_substream), + "data_available"); } - - +/** + * camel_seekable_substream_new_with_seekable_stream_and_bounds: + * @parent_stream: a seekable parent stream + * @inf_bound: a lower bound + * @sup_bound: an upper bound + * + * Creates a new CamelSeekableSubstream that references the portion + * of @parent_stream from @inf_bound to @sup_bound. (If @sup_bound is -1, + * it references to the end of stream, even if the stream grows.) + * + * While the substream is open, the caller cannot assume anything about + * the current position of @parent_stream. After the substream has been + * closed, @parent_stream will stabilize again. + * + * Return value: the substream + **/ CamelStream * -camel_seekable_substream_new_with_seekable_stream_and_bounds (CamelSeekableStream *parent_stream, - guint32 inf_bound, - gint64 sup_bound) +camel_seekable_substream_new_with_seekable_stream_and_bounds (CamelSeekableStream *parent_stream, + guint32 inf_bound, + gint64 sup_bound) { CamelSeekableSubstream *seekable_substream; - /* create the seekable substream */ - seekable_substream = gtk_type_new (camel_seekable_substream_get_type ()); + g_return_val_if_fail (CAMEL_IS_SEEKABLE_STREAM (parent_stream), NULL); + + /* Create the seekable substream. */ + seekable_substream = + gtk_type_new (camel_seekable_substream_get_type ()); - /* initialize it */ - CSS_CLASS (seekable_substream)->init_with_seekable_stream_and_bounds (seekable_substream, - parent_stream, - inf_bound, - sup_bound); + /* Initialize it. */ + init_with_seekable_stream_and_bounds (seekable_substream, + parent_stream, + inf_bound, sup_bound); return CAMEL_STREAM (seekable_substream); } - - - -/** - * _read: read bytes from a stream - * @stream: stream - * @buffer: buffer where bytes are stored - * @n: max number of bytes to read - * - * - * - * Return value: number of bytes actually read. - **/ -static gint -_read (CamelStream *stream, gchar *buffer, gint n) +static gboolean +parent_reset (CamelSeekableSubstream *seekable_substream) { - CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream); - CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream); - gint v; - gint nb_to_read; + CamelSeekableStream *parent, *seekable_stream = + CAMEL_SEEKABLE_STREAM (seekable_substream); guint32 parent_stream_current_position; guint32 position_in_parent; - - g_assert (stream); - g_assert (seekable_substream->parent_stream); - g_assert (n); + parent = seekable_substream->parent_stream; + g_return_val_if_fail (parent != NULL, FALSE); + parent_stream_current_position = + camel_seekable_stream_get_current_position (parent); - /* - we are doing something quite infefficient : - - each time we want to read a block, we store - the parent stream position so that we can - change it, and restore it before returning + /* Compute our position in the parent stream. */ + position_in_parent = + seekable_stream->cur_pos + seekable_substream->inf_bound; - This may change. I don't know yet. - It may be useless to reseek every time - and is incompatible with buffering. - */ + /* Go to our position in the parent stream. */ + if (parent_stream_current_position != position_in_parent) { + camel_seekable_stream_seek (parent, position_in_parent, + CAMEL_STREAM_SET); + } + /* Check if we were able to set the position in the parent. */ + parent_stream_current_position = + camel_seekable_stream_get_current_position (parent); - parent_stream_current_position = - camel_seekable_stream_get_current_position (seekable_substream->parent_stream); + return parent_stream_current_position == position_in_parent; +} - /* compute the position in the parent stream */ - position_in_parent = - seekable_stream->cur_pos + seekable_substream->inf_bound; - - /* compute how much byte should be read */ - if (seekable_substream->sup_bound != -1) - nb_to_read = - MIN (seekable_substream->sup_bound - position_in_parent, n); - else - nb_to_read = n; - //printf ("Nb to read = %d\n", n); - if (!nb_to_read) { - +static gint +stream_read (CamelStream *stream, gchar *buffer, gint n) +{ + CamelSeekableStream *seekable_stream = + CAMEL_SEEKABLE_STREAM (stream); + CamelSeekableSubstream *seekable_substream = + CAMEL_SEEKABLE_SUBSTREAM (stream); + gint v, nb_to_read, position_in_parent; + + /* Go to our position in the parent stream. */ + if (!parent_reset (seekable_substream)) { seekable_substream->eos = TRUE; return 0; } - /*printf ("In SeekableSubstream(%p)::read, the position has to be changed\n", stream); - printf ("--- parent_stream_current_position=%d, position_in_parent=%d\n", - parent_stream_current_position, position_in_parent); - printf ("--- seekable_substream->inf_bound=%d\n", seekable_substream->inf_bound); - printf ("--- seekable_substream->sup_bound=%d\n", seekable_substream->sup_bound); - printf ("--- seekable_substream->parent_stream=%p\n", seekable_substream->parent_stream); - */ - /* go to our position in the parent stream */ - if (parent_stream_current_position != position_in_parent) { - - - camel_seekable_stream_seek (seekable_substream->parent_stream, - position_in_parent, - CAMEL_STREAM_SET); - } - - /* check if we were able to set the position in the parent */ - parent_stream_current_position = - camel_seekable_stream_get_current_position (seekable_substream->parent_stream); + /* Compute how much byte should be read. */ + position_in_parent = + seekable_stream->cur_pos + seekable_substream->inf_bound; + if (seekable_substream->sup_bound != -1) { + nb_to_read = MIN (seekable_substream->sup_bound - + position_in_parent, n); + } else + nb_to_read = n; - if (parent_stream_current_position != position_in_parent) { - seekable_substream->eos = TRUE; + if (!nb_to_read) { + if (n) + seekable_substream->eos = TRUE; return 0; } - - /* Read the data */ - if (nb_to_read >0 ) - v = camel_stream_read ( CAMEL_STREAM (seekable_substream->parent_stream), - buffer, - nb_to_read); - else + /* Read the data. */ + if (nb_to_read > 0) { + v = camel_stream_read (CAMEL_STREAM (seekable_substream->parent_stream), + buffer, nb_to_read); + } else v = 0; - /* if the return value is negative, an error occured, - we must do something FIXME : handle exception */ - if (v>0) + /* If the return value is negative, an error occured, + * we must do something FIXME : handle exception + */ + if (v > 0) seekable_stream->cur_pos += v; - - /* printf ("Nb Bytes Read : %d\n",v); */ - /* return the number of bytes read */ return v; } -/** - * _write: write bytes to a stream - * @stream: the stream - * @buffer: byte buffer - * @n: number of bytes to write - * - * - * - * Return value: the number of bytes actually written - * in the stream. - **/ static gint -_write (CamelStream *stream, const gchar *buffer, gint n) +stream_write (CamelStream *stream, const gchar *buffer, gint n) { /* NOT VALID ON SEEKABLE SUBSTREAM */ - g_warning ("CamelSeekableSubstream:: seekable substream don't have a write method\n"); + g_warning ("CamelSeekableSubstream:: seekable substream doesn't " + "have a write method\n"); return -1; } - -/** - * _flush: flush pending changes - * @stream: the stream - * - * - **/ static void -_flush (CamelStream *stream) +stream_flush (CamelStream *stream) { /* NOT VALID ON SEEKABLE SUBSTREAM */ - g_warning ("CamelSeekableSubstream:: seekable substream don't have a flush method\n"); + g_warning ("CamelSeekableSubstream:: seekable substream doesn't " + "have a flush method\n"); } - -/** - * _available: return the number of bytes available for reading - * @stream: the stream - * - * Return the number of bytes available without blocking. - * - * Return value: the number of bytes available - **/ -static gint -_available (CamelStream *stream) +static gint +available (CamelStream *stream) { - g_warning ("not implemented\n"); + g_warning ("CamelSeekableSubstream::available not implemented\n"); return -1; } -/** - * _eos: test if there are bytes left to read - * @stream: the stream - * - * - * - * Return value: true if all stream has been read - **/ static gboolean -_eos (CamelStream *stream) +eos (CamelStream *stream) { - CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream); - CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream); + CamelSeekableSubstream *seekable_substream = + CAMEL_SEEKABLE_SUBSTREAM (stream); + CamelSeekableStream *seekable_stream = + CAMEL_SEEKABLE_STREAM (stream); guint32 substream_len; gboolean eos; - + g_assert (stream); if (seekable_substream->eos) eos = TRUE; else { + parent_reset (seekable_substream); - /* first check that the parent stream is ok */ eos = camel_stream_eos (CAMEL_STREAM (seekable_substream->parent_stream)); if ((!eos) && (seekable_substream->sup_bound != -1)) { - substream_len = seekable_substream->sup_bound - seekable_substream->inf_bound; + substream_len = seekable_substream->sup_bound - seekable_substream->inf_bound; eos = ( seekable_stream->cur_pos >= substream_len); - } + } } - return eos; } -/** - * _close: close a stream - * @stream: the stream - * - * - **/ -static void -_close (CamelStream *stream) -{ - CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream); - - g_assert (stream); - seekable_substream->open = FALSE; -} - - static gint -_seek (CamelSeekableStream *stream, gint offset, CamelStreamSeekPolicy policy) +stream_seek (CamelSeekableStream *stream, gint offset, + CamelStreamSeekPolicy policy) { - CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream); - CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream); - gint64 real_offset = 0; + CamelSeekableSubstream *seekable_substream = + CAMEL_SEEKABLE_SUBSTREAM (stream); + CamelSeekableStream *seekable_stream = + CAMEL_SEEKABLE_STREAM (stream); + gint64 real_offset = 0; guint32 substream_len; guint32 parent_pos; gboolean seek_done = FALSE; - substream_len = seekable_substream->sup_bound - seekable_substream->inf_bound; - - seekable_substream->eos = FALSE; + substream_len = seekable_substream->sup_bound - + seekable_substream->inf_bound; - switch (policy) { + seekable_substream->eos = FALSE; + switch (policy) { case CAMEL_STREAM_SET: real_offset = offset; - break; case CAMEL_STREAM_CUR: real_offset = seekable_stream->cur_pos + offset; - break; case CAMEL_STREAM_END: if (seekable_substream->sup_bound != -1) real_offset = substream_len - offset; else { - parent_pos = camel_seekable_stream_seek (seekable_substream->parent_stream, - offset, + parent_pos = camel_seekable_stream_seek (seekable_substream->parent_stream, + offset, CAMEL_STREAM_END); - seekable_stream->cur_pos = parent_pos - seekable_substream->inf_bound; + seekable_stream->cur_pos = parent_pos - + seekable_substream->inf_bound; seek_done = TRUE; } - break; default: @@ -485,11 +382,11 @@ _seek (CamelSeekableStream *stream, gint offset, CamelStreamSeekPolicy policy) if (!seek_done) { if (real_offset > 0) { - seekable_stream->cur_pos = MIN (real_offset, substream_len); - } else + seekable_stream->cur_pos = MIN (real_offset, + substream_len); + } else seekable_stream->cur_pos = 0; } - return seekable_stream->cur_pos; } diff --git a/camel/camel-seekable-substream.h b/camel/camel-seekable-substream.h index 72f04601c8..4710f5fd5a 100644 --- a/camel/camel-seekable-substream.h +++ b/camel/camel-seekable-substream.h @@ -1,15 +1,15 @@ /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* camel-seekable-substream.h : stream */ -/* +/* * - * Author : + * Author : * Bertrand Guiheneuf <bertrand@helixcode.com> * * Copyright 1999, 2000 Helix Code, Inc. (http://www.helixcode.com) * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as + * 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. * @@ -52,24 +52,21 @@ struct _CamelSeekableSubstream CamelSeekableStream parent_object; /* --**-- Private fields --**-- */ - CamelSeekableStream *parent_stream; /* the stream this substream uses */ - guint32 cur_pos; /* current postion in the stream */ + CamelSeekableStream *parent_stream; guint32 inf_bound; /* first valid position */ gint64 sup_bound; /* first invalid position */ - gboolean open; gboolean eos; - }; typedef struct { CamelSeekableStreamClass parent_class; - - /* Virtual methods */ - void (*init_with_seekable_stream_and_bounds) (CamelSeekableSubstream *seekable_substream, + + /* Virtual methods */ + void (*init_with_seekable_stream_and_bounds) (CamelSeekableSubstream *seekable_substream, CamelSeekableStream *parent_stream, - guint32 inf_bound, + guint32 inf_bound, gint64 sup_bound); } CamelSeekableSubstreamClass; @@ -85,7 +82,7 @@ GtkType camel_seekable_substream_get_type (void); /* obtain a new seekable substream */ CamelStream * camel_seekable_substream_new_with_seekable_stream_and_bounds (CamelSeekableStream *parent_stream, - guint32 inf_bound, + guint32 inf_bound, gint64 sup_bound); #ifdef __cplusplus |