1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-stream-mem.c: memory buffer based stream */
5 * Authors: Bertrand Guiheneuf <bertrand@helixcode.com>
6 * Michael Zucchi <notzed@ximian.com>
8 * Copyright 1999, 2000 Ximian, Inc. (www.ximian.com)
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of version 2 of the GNU Lesser General Public
12 * License as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
33 #include <sys/types.h>
35 #include "camel-stream-mem.h"
37 static CamelSeekableStreamClass *parent_class = NULL;
39 /* Returns the class for a CamelStreamMem */
40 #define CSM_CLASS(so) CAMEL_STREAM_MEM_CLASS(CAMEL_OBJECT_GET_CLASS(so))
42 static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
43 static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
44 static gboolean stream_eos (CamelStream *stream);
45 static off_t stream_seek (CamelSeekableStream *stream, off_t offset,
46 CamelStreamSeekPolicy policy);
48 static void camel_stream_mem_finalize (CamelObject *object);
51 camel_stream_mem_class_init (CamelStreamMemClass *camel_stream_mem_class)
53 CamelSeekableStreamClass *camel_seekable_stream_class =
54 CAMEL_SEEKABLE_STREAM_CLASS (camel_stream_mem_class);
55 CamelStreamClass *camel_stream_class =
56 CAMEL_STREAM_CLASS (camel_stream_mem_class);
58 parent_class = CAMEL_SEEKABLE_STREAM_CLASS( camel_type_get_global_classfuncs( CAMEL_SEEKABLE_STREAM_TYPE ) );
60 /* virtual method overload */
61 camel_stream_class->read = stream_read;
62 camel_stream_class->write = stream_write;
63 camel_stream_class->eos = stream_eos;
65 camel_seekable_stream_class->seek = stream_seek;
69 camel_stream_mem_init (CamelObject *object)
71 CamelStreamMem *stream_mem = CAMEL_STREAM_MEM (object);
73 stream_mem->owner = FALSE;
74 stream_mem->buffer = 0;
77 /* could probably be a util method */
78 static void clear_mem(void *p, size_t len)
82 /* This also helps debug bad access memory errors */
95 camel_stream_mem_get_type (void)
97 static CamelType camel_stream_mem_type = CAMEL_INVALID_TYPE;
99 if (camel_stream_mem_type == CAMEL_INVALID_TYPE) {
100 camel_stream_mem_type = camel_type_register( CAMEL_SEEKABLE_STREAM_TYPE,
102 sizeof( CamelStreamMem ),
103 sizeof( CamelStreamMemClass ),
104 (CamelObjectClassInitFunc) camel_stream_mem_class_init,
106 (CamelObjectInitFunc) camel_stream_mem_init,
107 (CamelObjectFinalizeFunc) camel_stream_mem_finalize );
110 return camel_stream_mem_type;
115 * camel_stream_mem_new:
117 * Create a new #CamelStreamMem object.
119 * Returns a new #CamelStreamMem
122 camel_stream_mem_new (void)
124 return camel_stream_mem_new_with_byte_array (g_byte_array_new ());
129 * camel_stream_mem_new_with_buffer:
130 * @buffer: a memory buffer to use as the stream data
131 * @len: length of @buffer
133 * Create a new memory stream using @buffer as the stream data.
135 * Note: @buffer will be copied into an internal #GByteArray structure
136 * for use as the stream backing. This may have resource implications
137 * you may wish to consider.
139 * Returns a new #CamelStreamMem
142 camel_stream_mem_new_with_buffer (const char *buffer, size_t len)
146 ba = g_byte_array_new ();
147 g_byte_array_append (ba, (const guint8 *)buffer, len);
148 return camel_stream_mem_new_with_byte_array (ba);
153 * camel_stream_mem_new_with_byte_array:
154 * @buffer: a #GByteArray to use as the stream data
156 * Create a new #CamelStreamMem using @buffer as the stream data.
158 * Note: The newly created #CamelStreamMem will destroy @buffer
161 * Returns a new #CamelStreamMem
164 camel_stream_mem_new_with_byte_array (GByteArray *buffer)
166 CamelStreamMem *stream_mem;
168 stream_mem = CAMEL_STREAM_MEM (camel_object_new (CAMEL_STREAM_MEM_TYPE));
169 stream_mem->buffer = buffer;
170 stream_mem->owner = TRUE;
172 return CAMEL_STREAM (stream_mem);
177 * camel_stream_mem_set_secure:
178 * @mem: a #CamelStreamMem object
180 * Mark the memory stream as secure. At the very least this means the
181 * data in the buffer will be cleared when the buffer is finalised.
182 * This only applies to buffers owned by the stream.
185 camel_stream_mem_set_secure(CamelStreamMem *mem)
188 /* setup a mem-locked buffer etc? blah blah, well not yet anyway */
192 /* note: with these functions the caller is the 'owner' of the buffer */
195 * camel_stream_mem_set_byte_array:
196 * @mem: a #CamelStreamMem object
197 * @buffer: a #GByteArray
199 * Set @buffer to be the backing data to the existing #CamelStreamMem, @mem.
201 * Note: @mem will not take ownership of @buffer and so will need to
202 * be freed separately from @mem.
205 camel_stream_mem_set_byte_array (CamelStreamMem *mem, GByteArray *buffer)
207 if (mem->buffer && mem->owner) {
208 if (mem->secure && mem->buffer->len)
209 clear_mem (mem->buffer->data, mem->buffer->len);
210 g_byte_array_free (mem->buffer, TRUE);
213 mem->buffer = buffer;
218 * camel_stream_mem_set_buffer:
219 * @mem: a #CamelStreamMem object
220 * @buffer: a memory buffer
221 * @len: length of @buffer
223 * Set @buffer to be the backing data to the existing #CamelStreamMem, @mem.
225 * Note: @buffer will be copied into an internal #GByteArray structure
226 * and so may have resource implications to consider.
229 camel_stream_mem_set_buffer (CamelStreamMem *mem, const char *buffer, size_t len)
233 ba = g_byte_array_new ();
234 g_byte_array_append(ba, (const guint8 *)buffer, len);
235 camel_stream_mem_set_byte_array(mem, ba);
241 camel_stream_mem_finalize (CamelObject *object)
243 CamelStreamMem *s = CAMEL_STREAM_MEM (object);
245 if (s->buffer && s->owner) {
246 /* TODO: we need our own bytearray type since we don't know
247 the real size of the underlying buffer :-/ */
248 if (s->secure && s->buffer->len)
249 clear_mem(s->buffer->data, s->buffer->len);
250 g_byte_array_free(s->buffer, TRUE);
255 stream_read (CamelStream *stream, char *buffer, size_t n)
257 CamelStreamMem *camel_stream_mem = CAMEL_STREAM_MEM (stream);
258 CamelSeekableStream *seekable = CAMEL_SEEKABLE_STREAM (stream);
261 if (seekable->bound_end != CAMEL_STREAM_UNBOUND)
262 n = MIN(seekable->bound_end - seekable->position, n);
264 nread = MIN (n, camel_stream_mem->buffer->len - seekable->position);
266 memcpy (buffer, camel_stream_mem->buffer->data + seekable->position, nread);
267 seekable->position += nread;
275 stream_write (CamelStream *stream, const char *buffer, size_t n)
277 CamelStreamMem *stream_mem = CAMEL_STREAM_MEM (stream);
278 CamelSeekableStream *seekable = CAMEL_SEEKABLE_STREAM (stream);
281 if (seekable->bound_end != CAMEL_STREAM_UNBOUND)
282 nwrite = MIN(seekable->bound_end - seekable->position, n);
284 /* FIXME: we shouldn't use g_byte_arrays or g_malloc perhaps? */
285 if (seekable->position == stream_mem->buffer->len) {
286 g_byte_array_append(stream_mem->buffer, (const guint8 *)buffer, nwrite);
288 g_byte_array_set_size(stream_mem->buffer, nwrite + stream_mem->buffer->len);
289 memcpy(stream_mem->buffer->data + seekable->position, buffer, nwrite);
291 seekable->position += nwrite;
297 stream_eos (CamelStream *stream)
299 CamelStreamMem *stream_mem = CAMEL_STREAM_MEM (stream);
300 CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream);
302 return stream_mem->buffer->len <= seekable_stream->position;
306 stream_seek (CamelSeekableStream *stream, off_t offset,
307 CamelStreamSeekPolicy policy)
310 CamelStreamMem *stream_mem = CAMEL_STREAM_MEM (stream);
313 case CAMEL_STREAM_SET:
316 case CAMEL_STREAM_CUR:
317 position = stream->position + offset;
319 case CAMEL_STREAM_END:
320 position = (stream_mem->buffer)->len + offset;
327 if (stream->bound_end != CAMEL_STREAM_UNBOUND)
328 position = MIN (position, stream->bound_end);
329 if (stream->bound_start != CAMEL_STREAM_UNBOUND)
330 position = MAX (position, 0);
332 position = MAX (position, stream->bound_start);
334 if (position > stream_mem->buffer->len) {
335 int oldlen = stream_mem->buffer->len;
336 g_byte_array_set_size (stream_mem->buffer, position);
337 memset (stream_mem->buffer->data + oldlen, 0,
341 stream->position = position;