1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-fs.c : file system based stream
4 * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
5 * Michael Zucchi <notzed@ximian.com>
7 * Copyright 1999-2003 Ximian, Inc. (www.ximian.com)
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
28 #include "camel-seekable-substream.h"
30 static CamelSeekableStreamClass *parent_class = NULL;
32 /* Returns the class for a CamelSeekableSubStream */
33 #define CSS_CLASS(so) CAMEL_SEEKABLE_SUBSTREAM_CLASS (CAMEL_OBJECT(so)->klass)
35 static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
36 static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
37 static int stream_flush (CamelStream *stream);
38 static int stream_close (CamelStream *stream);
39 static gboolean eos (CamelStream *stream);
40 static off_t stream_seek (CamelSeekableStream *stream, off_t offset,
41 CamelStreamSeekPolicy policy);
44 camel_seekable_substream_class_init (CamelSeekableSubstreamClass *camel_seekable_substream_class)
46 CamelSeekableStreamClass *camel_seekable_stream_class =
47 CAMEL_SEEKABLE_STREAM_CLASS (camel_seekable_substream_class);
48 CamelStreamClass *camel_stream_class =
49 CAMEL_STREAM_CLASS (camel_seekable_substream_class);
51 parent_class = CAMEL_SEEKABLE_STREAM_CLASS (camel_type_get_global_classfuncs (camel_seekable_stream_get_type ()));
53 /* virtual method definition */
55 /* virtual method overload */
56 camel_stream_class->read = stream_read;
57 camel_stream_class->write = stream_write;
58 camel_stream_class->flush = stream_flush;
59 camel_stream_class->close = stream_close;
60 camel_stream_class->eos = eos;
62 camel_seekable_stream_class->seek = stream_seek;
67 camel_seekable_substream_finalize (CamelObject *object)
69 CamelSeekableSubstream *seekable_substream =
70 CAMEL_SEEKABLE_SUBSTREAM (object);
72 if (seekable_substream->parent_stream)
73 camel_object_unref (seekable_substream->parent_stream);
78 camel_seekable_substream_get_type (void)
80 static CamelType camel_seekable_substream_type = CAMEL_INVALID_TYPE;
82 if (camel_seekable_substream_type == CAMEL_INVALID_TYPE) {
83 camel_seekable_substream_type = camel_type_register (camel_seekable_stream_get_type (), "CamelSeekableSubstream",
84 sizeof (CamelSeekableSubstream),
85 sizeof (CamelSeekableSubstreamClass),
86 (CamelObjectClassInitFunc) camel_seekable_substream_class_init,
89 (CamelObjectFinalizeFunc) camel_seekable_substream_finalize);
92 return camel_seekable_substream_type;
96 * camel_seekable_substream_new:
97 * @parent_stream: a seekable parent stream
98 * @inf_bound: a lower bound
99 * @sup_bound: an upper bound
101 * Creates a new CamelSeekableSubstream that references the portion
102 * of @parent_stream from @inf_bound to @sup_bound. (If @sup_bound is
103 * #CAMEL_STREAM_UNBOUND, it references to the end of stream, even if
106 * While the substream is open, the caller cannot assume anything about
107 * the current position of @parent_stream. After the substream has been
108 * closed, @parent_stream will stabilize again.
110 * Return value: the substream
113 camel_seekable_substream_new(CamelSeekableStream *parent_stream, off_t start, off_t end)
115 CamelSeekableSubstream *seekable_substream;
117 g_return_val_if_fail (CAMEL_IS_SEEKABLE_STREAM (parent_stream), NULL);
119 /* Create the seekable substream. */
120 seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (camel_object_new (camel_seekable_substream_get_type ()));
123 seekable_substream->parent_stream = parent_stream;
124 camel_object_ref (parent_stream);
126 /* Set the bound of the substream. We can ignore any possible error
127 * here, because if we fail to seek now, it will try again later.
129 camel_seekable_stream_set_bounds ((CamelSeekableStream *)seekable_substream, start, end);
131 return CAMEL_STREAM (seekable_substream);
135 parent_reset (CamelSeekableSubstream *seekable_substream, CamelSeekableStream *parent)
137 CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (seekable_substream);
139 if (camel_seekable_stream_tell (parent) == seekable_stream->position)
142 return camel_seekable_stream_seek (parent, seekable_stream->position, CAMEL_STREAM_SET) == seekable_stream->position;
146 stream_read (CamelStream *stream, char *buffer, size_t n)
148 CamelSeekableStream *parent;
149 CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream);
150 CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream);
156 parent = seekable_substream->parent_stream;
158 /* Go to our position in the parent stream. */
159 if (!parent_reset (seekable_substream, parent)) {
164 /* Compute how many bytes should be read. */
165 if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
166 n = MIN (seekable_stream->bound_end - seekable_stream->position, n);
173 v = camel_stream_read (CAMEL_STREAM (parent), buffer, n);
175 /* ignore <0 - it's an error, let the caller deal */
177 seekable_stream->position += v;
183 stream_write (CamelStream *stream, const char *buffer, size_t n)
185 CamelSeekableStream *parent;
186 CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM(stream);
187 CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(stream);
193 parent = seekable_substream->parent_stream;
195 /* Go to our position in the parent stream. */
196 if (!parent_reset (seekable_substream, parent)) {
201 /* Compute how many bytes should be written. */
202 if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
203 n = MIN (seekable_stream->bound_end - seekable_stream->position, n);
210 v = camel_stream_write((CamelStream *)parent, buffer, n);
212 /* ignore <0 - it's an error, let the caller deal */
214 seekable_stream->position += v;
221 stream_flush (CamelStream *stream)
223 CamelSeekableSubstream *sus = (CamelSeekableSubstream *)stream;
225 return camel_stream_flush(CAMEL_STREAM(sus->parent_stream));
229 stream_close (CamelStream *stream)
231 /* we dont really want to close the substream ... */
236 eos (CamelStream *stream)
238 CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(stream);
239 CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM(stream);
240 CamelSeekableStream *parent;
246 parent = seekable_substream->parent_stream;
247 if (!parent_reset (seekable_substream, parent))
250 eos = camel_stream_eos (CAMEL_STREAM (parent));
251 if (!eos && (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)) {
252 eos = seekable_stream->position >= seekable_stream->bound_end;
260 stream_seek (CamelSeekableStream *seekable_stream, off_t offset,
261 CamelStreamSeekPolicy policy)
263 CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM(seekable_stream);
264 CamelStream *stream = CAMEL_STREAM(seekable_stream);
265 off_t real_offset = 0;
270 case CAMEL_STREAM_SET:
271 real_offset = offset;
274 case CAMEL_STREAM_CUR:
275 real_offset = seekable_stream->position + offset;
278 case CAMEL_STREAM_END:
279 if (seekable_stream->bound_end == CAMEL_STREAM_UNBOUND) {
280 real_offset = camel_seekable_stream_seek(seekable_substream->parent_stream,
283 if (real_offset != -1) {
284 if (real_offset<seekable_stream->bound_start)
285 real_offset = seekable_stream->bound_start;
286 seekable_stream->position = real_offset;
290 real_offset = seekable_stream->bound_end + offset;
294 if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND)
295 real_offset = MIN (real_offset, seekable_stream->bound_end);
297 if (real_offset<seekable_stream->bound_start)
298 real_offset = seekable_stream->bound_start;
300 seekable_stream->position = real_offset;