1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1
8 * of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
28 #include "gmime-stream.h"
34 * SECTION: gmime-stream
36 * @short_description: Abstract stream class
39 * Streams are the fundamental method for reading and writing data
40 * used by GMime. You'll probably notice that the basic API is similar
41 * to that of the low-level Unix I/O layer (read(), write(), lseek(),
42 * etc) with some additional nicities such as a printf-like function.
46 static void g_mime_stream_class_init (GMimeStreamClass *klass);
47 static void g_mime_stream_init (GMimeStream *stream, GMimeStreamClass *klass);
48 static void g_mime_stream_finalize (GObject *object);
50 static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len);
51 static ssize_t stream_write (GMimeStream *stream, const char *buf, size_t len);
52 static int stream_flush (GMimeStream *stream);
53 static int stream_close (GMimeStream *stream);
54 static gboolean stream_eos (GMimeStream *stream);
55 static int stream_reset (GMimeStream *stream);
56 static gint64 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence);
57 static gint64 stream_tell (GMimeStream *stream);
58 static gint64 stream_length (GMimeStream *stream);
59 static GMimeStream *stream_substream (GMimeStream *stream, gint64 start, gint64 end);
62 static GObjectClass *parent_class = NULL;
66 g_mime_stream_get_type (void)
68 static GType type = 0;
71 static const GTypeInfo info = {
72 sizeof (GMimeStreamClass),
73 NULL, /* base_class_init */
74 NULL, /* base_class_finalize */
75 (GClassInitFunc) g_mime_stream_class_init,
76 NULL, /* class_finalize */
77 NULL, /* class_data */
80 (GInstanceInitFunc) g_mime_stream_init,
83 type = g_type_register_static (G_TYPE_OBJECT, "GMimeStream",
84 &info, G_TYPE_FLAG_ABSTRACT);
92 g_mime_stream_class_init (GMimeStreamClass *klass)
94 GObjectClass *object_class = G_OBJECT_CLASS (klass);
96 parent_class = g_type_class_ref (G_TYPE_OBJECT);
98 object_class->finalize = g_mime_stream_finalize;
100 klass->read = stream_read;
101 klass->write = stream_write;
102 klass->flush = stream_flush;
103 klass->close = stream_close;
104 klass->eos = stream_eos;
105 klass->reset = stream_reset;
106 klass->seek = stream_seek;
107 klass->tell = stream_tell;
108 klass->length = stream_length;
109 klass->substream = stream_substream;
113 g_mime_stream_init (GMimeStream *stream, GMimeStreamClass *klass)
115 stream->super_stream = NULL;
117 stream->position = 0;
118 stream->bound_start = 0;
119 stream->bound_end = 0;
123 g_mime_stream_finalize (GObject *object)
125 GMimeStream *stream = (GMimeStream *) object;
127 if (stream->super_stream)
128 g_object_unref (stream->super_stream);
130 G_OBJECT_CLASS (parent_class)->finalize (object);
135 * g_mime_stream_construct:
136 * @stream: a #GMimeStream
137 * @start: start boundary
140 * Initializes a new stream with bounds @start and @end.
143 g_mime_stream_construct (GMimeStream *stream, gint64 start, gint64 end)
145 stream->position = start;
146 stream->bound_start = start;
147 stream->bound_end = end;
152 stream_read (GMimeStream *stream, char *buf, size_t len)
154 d(g_warning ("Invoked default stream_read implementation."));
160 * g_mime_stream_read:
161 * @stream: a #GMimeStream
163 * @len: buffer length
165 * Attempts to read up to @len bytes from @stream into @buf.
167 * Returns: the number of bytes read or %-1 on fail.
170 g_mime_stream_read (GMimeStream *stream, char *buf, size_t len)
172 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
173 g_return_val_if_fail (buf != NULL, -1);
178 return GMIME_STREAM_GET_CLASS (stream)->read (stream, buf, len);
183 stream_write (GMimeStream *stream, const char *buf, size_t len)
185 d(g_warning ("Invoked default stream_write implementation."));
191 * g_mime_stream_write:
192 * @stream: a #GMimeStream
194 * @len: buffer length
196 * Attempts to write up to @len bytes of @buf to @stream.
198 * Returns: the number of bytes written or %-1 on fail.
201 g_mime_stream_write (GMimeStream *stream, const char *buf, size_t len)
203 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
204 g_return_val_if_fail (buf != NULL, -1);
209 return GMIME_STREAM_GET_CLASS (stream)->write (stream, buf, len);
214 stream_flush (GMimeStream *stream)
216 d(g_warning ("Invoked default stream_flush implementation."));
222 * g_mime_stream_flush:
223 * @stream: a #GMimeStream
225 * Sync's the stream to disk.
227 * Returns: %0 on success or %-1 on fail.
230 g_mime_stream_flush (GMimeStream *stream)
232 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
234 return GMIME_STREAM_GET_CLASS (stream)->flush (stream);
239 stream_close (GMimeStream *stream)
241 d(g_warning ("Invoked default stream_close implementation."));
247 * g_mime_stream_close:
248 * @stream: a #GMimeStream
252 * Returns: %0 on success or %-1 on fail.
255 g_mime_stream_close (GMimeStream *stream)
257 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
259 return GMIME_STREAM_GET_CLASS (stream)->close (stream);
264 stream_eos (GMimeStream *stream)
266 d(g_warning ("Invoked default stream_eos implementation."));
267 return stream->position >= stream->bound_end;
273 * @stream: a #GMimeStream
275 * Tests the end-of-stream indicator for @stream.
277 * Returns: %TRUE on EOS or %FALSE otherwise.
280 g_mime_stream_eos (GMimeStream *stream)
282 g_return_val_if_fail (GMIME_IS_STREAM (stream), TRUE);
284 if (stream->bound_end != -1 && stream->position >= stream->bound_end)
287 return GMIME_STREAM_GET_CLASS (stream)->eos (stream);
292 stream_reset (GMimeStream *stream)
294 d(g_warning ("Invoked default stream_reset implementation."));
300 * g_mime_stream_reset:
301 * @stream: a #GMimeStream
305 * Returns: %0 on success or %-1 on fail.
308 g_mime_stream_reset (GMimeStream *stream)
312 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
314 if ((rv = GMIME_STREAM_GET_CLASS (stream)->reset (stream)) == 0)
315 stream->position = stream->bound_start;
322 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
324 d(g_warning ("Invoked default stream_seek implementation."));
330 * g_mime_stream_seek:
331 * @stream: a #GMimeStream
332 * @offset: positional offset
333 * @whence: seek directive
335 * Repositions the offset of the stream @stream to
336 * the argument @offset according to the
337 * directive @whence as follows:
339 * #GMIME_STREAM_SEEK_SET: Seek @offset bytes relative to
340 * the beginning (bound_start) of the stream.
342 * #GMIME_STREAM_SEEK_CUR: Seek @offset bytes relative to the
343 * current offset of the stream.
345 * #GMIME_STREAM_SEEK_END: Seek @offset bytes relative to the
346 * end of the stream (bound_end if non-negative).
348 * Returns: the resultant position on success or %-1 on fail.
351 g_mime_stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
353 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
355 return GMIME_STREAM_GET_CLASS (stream)->seek (stream, offset, whence);
360 stream_tell (GMimeStream *stream)
362 d(g_warning ("Invoked default stream_tell implementation."));
363 return stream->position;
368 * g_mime_stream_tell:
369 * @stream: a #GMimeStream
371 * Gets the current offset within the stream.
373 * Returns: the current position within the stream or %-1 on fail.
376 g_mime_stream_tell (GMimeStream *stream)
378 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
380 return GMIME_STREAM_GET_CLASS (stream)->tell (stream);
385 stream_length (GMimeStream *stream)
387 gint64 position = stream->position;
390 if (stream->bound_end != -1)
391 return stream->bound_end - stream->bound_start;
393 bound_end = g_mime_stream_seek (stream, 0, GMIME_STREAM_SEEK_END);
394 g_mime_stream_seek (stream, position, GMIME_STREAM_SEEK_SET);
396 if (bound_end < stream->bound_start)
399 return bound_end - stream->bound_start;
404 * g_mime_stream_length:
405 * @stream: a #GMimeStream
407 * Gets the length of the stream.
409 * Returns: the length of the stream or %-1 if unknown.
412 g_mime_stream_length (GMimeStream *stream)
414 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
416 return GMIME_STREAM_GET_CLASS (stream)->length (stream);
421 stream_substream (GMimeStream *stream, gint64 start, gint64 end)
423 d(g_warning ("Invoked default stream_tell implementation."));
429 * g_mime_stream_substream:
430 * @stream: a #GMimeStream
431 * @start: start boundary
434 * Creates a new substream of @stream with bounds @start and @end.
436 * Returns: a substream of @stream with bounds @start and @end.
439 g_mime_stream_substream (GMimeStream *stream, gint64 start, gint64 end)
443 g_return_val_if_fail (GMIME_IS_STREAM (stream), NULL);
445 if ((sub = GMIME_STREAM_GET_CLASS (stream)->substream (stream, start, end))) {
446 sub->super_stream = stream;
447 g_object_ref (stream);
455 * g_mime_stream_set_bounds:
456 * @stream: a #GMimeStream
457 * @start: start boundary
460 * Set the bounds on a stream.
463 g_mime_stream_set_bounds (GMimeStream *stream, gint64 start, gint64 end)
465 g_return_if_fail (GMIME_IS_STREAM (stream));
467 stream->bound_start = start;
468 stream->bound_end = end;
470 if (stream->position < start)
471 stream->position = start;
472 else if (stream->position > end && end != -1)
473 stream->position = end;
478 * g_mime_stream_write_string:
479 * @stream: a #GMimeStream
480 * @str: string to write
482 * Writes @string to @stream.
484 * Returns: the number of bytes written or %-1 on fail.
487 g_mime_stream_write_string (GMimeStream *stream, const char *str)
489 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
490 g_return_val_if_fail (str != NULL, -1);
492 return g_mime_stream_write (stream, str, strlen (str));
497 * g_mime_stream_printf:
498 * @stream: a #GMimeStream
500 * @Varargs: arguments
502 * Write formatted output to a stream.
504 * Returns: the number of bytes written or %-1 on fail.
507 g_mime_stream_printf (GMimeStream *stream, const char *fmt, ...)
513 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
514 g_return_val_if_fail (fmt != NULL, -1);
516 va_start (args, fmt);
517 string = g_strdup_vprintf (fmt, args);
523 ret = g_mime_stream_write (stream, string, strlen (string));
531 * g_mime_stream_write_to_stream:
532 * @src: source stream
533 * @dest: destination stream
535 * Attempts to write the source stream to the destination stream.
537 * Returns: the number of bytes written or %-1 on fail.
540 g_mime_stream_write_to_stream (GMimeStream *src, GMimeStream *dest)
542 ssize_t nread, nwritten, total = 0;
545 g_return_val_if_fail (GMIME_IS_STREAM (src), -1);
546 g_return_val_if_fail (GMIME_IS_STREAM (dest), -1);
548 while (!g_mime_stream_eos (src)) {
549 if ((nread = g_mime_stream_read (src, buf, sizeof (buf))) < 0)
554 while (nwritten < nread) {
557 if ((len = g_mime_stream_write (dest, buf + nwritten, nread - nwritten)) < 0)
572 * g_mime_stream_writev:
573 * @stream: a #GMimeStream
574 * @vector: a #GMimeStreamIOVector
575 * @count: number of vector elements
577 * Writes at most @count blocks described by @vector to @stream.
579 * Returns: the number of bytes written or %-1 on fail.
582 g_mime_stream_writev (GMimeStream *stream, GMimeStreamIOVector *vector, size_t count)
587 g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
589 for (i = 0; i < count; i++) {
590 char *buffer = vector[i].data;
594 while (nwritten < vector[i].len) {
595 if ((n = g_mime_stream_write (stream, buffer + nwritten,
596 vector[i].len - nwritten)) < 0)