Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-stream.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*  GMime
3  *  Copyright (C) 2000-2012 Jeffrey Stedfast
4  *
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.
9  *
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.
14  *
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
18  *  02110-1301, USA.
19  */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "gmime-stream.h"
29
30 #define d(x)
31
32
33 /**
34  * SECTION: gmime-stream
35  * @title: GMimeStream
36  * @short_description: Abstract stream class
37  * @see_also:
38  *
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.
43  **/
44
45
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);
49
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);
60
61
62 static GObjectClass *parent_class = NULL;
63
64
65 GType
66 g_mime_stream_get_type (void)
67 {
68         static GType type = 0;
69         
70         if (!type) {
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 */
78                         sizeof (GMimeStream),
79                         0,    /* n_preallocs */
80                         (GInstanceInitFunc) g_mime_stream_init,
81                 };
82                 
83                 type = g_type_register_static (G_TYPE_OBJECT, "GMimeStream",
84                                                &info, G_TYPE_FLAG_ABSTRACT);
85         }
86         
87         return type;
88 }
89
90
91 static void
92 g_mime_stream_class_init (GMimeStreamClass *klass)
93 {
94         GObjectClass *object_class = G_OBJECT_CLASS (klass);
95         
96         parent_class = g_type_class_ref (G_TYPE_OBJECT);
97         
98         object_class->finalize = g_mime_stream_finalize;
99         
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;
110 }
111
112 static void
113 g_mime_stream_init (GMimeStream *stream, GMimeStreamClass *klass)
114 {
115         stream->super_stream = NULL;
116         
117         stream->position = 0;
118         stream->bound_start = 0;
119         stream->bound_end = 0;
120 }
121
122 static void
123 g_mime_stream_finalize (GObject *object)
124 {
125         GMimeStream *stream = (GMimeStream *) object;
126         
127         if (stream->super_stream)
128                 g_object_unref (stream->super_stream);
129         
130         G_OBJECT_CLASS (parent_class)->finalize (object);
131 }
132
133
134 /**
135  * g_mime_stream_construct:
136  * @stream: a #GMimeStream
137  * @start: start boundary
138  * @end: end boundary
139  *
140  * Initializes a new stream with bounds @start and @end.
141  **/
142 void
143 g_mime_stream_construct (GMimeStream *stream, gint64 start, gint64 end)
144 {
145         stream->position = start;
146         stream->bound_start = start;
147         stream->bound_end = end;
148 }
149
150
151 static ssize_t
152 stream_read (GMimeStream *stream, char *buf, size_t len)
153 {
154         d(g_warning ("Invoked default stream_read implementation."));
155         return 0;
156 }
157
158
159 /**
160  * g_mime_stream_read:
161  * @stream: a #GMimeStream
162  * @buf: buffer
163  * @len: buffer length
164  *
165  * Attempts to read up to @len bytes from @stream into @buf.
166  *
167  * Returns: the number of bytes read or %-1 on fail.
168  **/
169 ssize_t
170 g_mime_stream_read (GMimeStream *stream, char *buf, size_t len)
171 {
172         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
173         g_return_val_if_fail (buf != NULL, -1);
174         
175         if (len == 0)
176                 return 0;
177         
178         return GMIME_STREAM_GET_CLASS (stream)->read (stream, buf, len);
179 }
180
181
182 static ssize_t
183 stream_write (GMimeStream *stream, const char *buf, size_t len)
184 {
185         d(g_warning ("Invoked default stream_write implementation."));
186         return 0;
187 }
188
189
190 /**
191  * g_mime_stream_write:
192  * @stream: a #GMimeStream
193  * @buf: buffer
194  * @len: buffer length
195  *
196  * Attempts to write up to @len bytes of @buf to @stream.
197  *
198  * Returns: the number of bytes written or %-1 on fail.
199  **/
200 ssize_t
201 g_mime_stream_write (GMimeStream *stream, const char *buf, size_t len)
202 {
203         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
204         g_return_val_if_fail (buf != NULL, -1);
205         
206         if (len == 0)
207                 return 0;
208         
209         return GMIME_STREAM_GET_CLASS (stream)->write (stream, buf, len);
210 }
211
212
213 static int
214 stream_flush (GMimeStream *stream)
215 {
216         d(g_warning ("Invoked default stream_flush implementation."));
217         return 0;
218 }
219
220
221 /**
222  * g_mime_stream_flush:
223  * @stream: a #GMimeStream
224  *
225  * Sync's the stream to disk.
226  *
227  * Returns: %0 on success or %-1 on fail.
228  **/
229 int
230 g_mime_stream_flush (GMimeStream *stream)
231 {
232         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
233         
234         return GMIME_STREAM_GET_CLASS (stream)->flush (stream);
235 }
236
237
238 static int
239 stream_close (GMimeStream *stream)
240 {
241         d(g_warning ("Invoked default stream_close implementation."));
242         return 0;
243 }
244
245
246 /**
247  * g_mime_stream_close:
248  * @stream: a #GMimeStream
249  *
250  * Closes the stream.
251  *
252  * Returns: %0 on success or %-1 on fail.
253  **/
254 int
255 g_mime_stream_close (GMimeStream *stream)
256 {
257         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
258         
259         return GMIME_STREAM_GET_CLASS (stream)->close (stream);
260 }
261
262
263 static gboolean
264 stream_eos (GMimeStream *stream)
265 {
266         d(g_warning ("Invoked default stream_eos implementation."));
267         return stream->position >= stream->bound_end;
268 }
269
270
271 /**
272  * g_mime_stream_eos:
273  * @stream: a #GMimeStream
274  *
275  * Tests the end-of-stream indicator for @stream.
276  *
277  * Returns: %TRUE on EOS or %FALSE otherwise.
278  **/
279 gboolean
280 g_mime_stream_eos (GMimeStream *stream)
281 {
282         g_return_val_if_fail (GMIME_IS_STREAM (stream), TRUE);
283         
284         if (stream->bound_end != -1 && stream->position >= stream->bound_end)
285                 return TRUE;
286         
287         return GMIME_STREAM_GET_CLASS (stream)->eos (stream);
288 }
289
290
291 static int
292 stream_reset (GMimeStream *stream)
293 {
294         d(g_warning ("Invoked default stream_reset implementation."));
295         return 0;
296 }
297
298
299 /**
300  * g_mime_stream_reset:
301  * @stream: a #GMimeStream
302  *
303  * Resets the stream.
304  *
305  * Returns: %0 on success or %-1 on fail.
306  **/
307 int
308 g_mime_stream_reset (GMimeStream *stream)
309 {
310         int rv;
311         
312         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
313         
314         if ((rv = GMIME_STREAM_GET_CLASS (stream)->reset (stream)) == 0)
315                 stream->position = stream->bound_start;
316         
317         return rv;
318 }
319
320
321 static gint64
322 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
323 {
324         d(g_warning ("Invoked default stream_seek implementation."));
325         return -1;
326 }
327
328
329 /**
330  * g_mime_stream_seek:
331  * @stream: a #GMimeStream
332  * @offset: positional offset
333  * @whence: seek directive
334  *
335  * Repositions the offset of the stream @stream to
336  * the argument @offset according to the
337  * directive @whence as follows:
338  *
339  *     #GMIME_STREAM_SEEK_SET: Seek @offset bytes relative to
340  *     the beginning (bound_start) of the stream.
341  *
342  *     #GMIME_STREAM_SEEK_CUR: Seek @offset bytes relative to the
343  *     current offset of the stream.
344  *
345  *     #GMIME_STREAM_SEEK_END: Seek @offset bytes relative to the
346  *     end of the stream (bound_end if non-negative).
347  *
348  * Returns: the resultant position on success or %-1 on fail.
349  **/
350 gint64
351 g_mime_stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
352 {
353         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
354         
355         return GMIME_STREAM_GET_CLASS (stream)->seek (stream, offset, whence);
356 }
357
358
359 static gint64
360 stream_tell (GMimeStream *stream)
361 {
362         d(g_warning ("Invoked default stream_tell implementation."));
363         return stream->position;
364 }
365
366
367 /**
368  * g_mime_stream_tell:
369  * @stream: a #GMimeStream
370  *
371  * Gets the current offset within the stream.
372  *
373  * Returns: the current position within the stream or %-1 on fail.
374  **/
375 gint64
376 g_mime_stream_tell (GMimeStream *stream)
377 {
378         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
379         
380         return GMIME_STREAM_GET_CLASS (stream)->tell (stream);
381 }
382
383
384 static gint64
385 stream_length (GMimeStream *stream)
386 {
387         gint64 position = stream->position;
388         gint64 bound_end;
389         
390         if (stream->bound_end != -1)
391                 return stream->bound_end - stream->bound_start;
392         
393         bound_end = g_mime_stream_seek (stream, 0, GMIME_STREAM_SEEK_END);
394         g_mime_stream_seek (stream, position, GMIME_STREAM_SEEK_SET);
395         
396         if (bound_end < stream->bound_start)
397                 return -1;
398         
399         return bound_end - stream->bound_start;
400 }
401
402
403 /**
404  * g_mime_stream_length:
405  * @stream: a #GMimeStream
406  *
407  * Gets the length of the stream.
408  *
409  * Returns: the length of the stream or %-1 if unknown.
410  **/
411 gint64
412 g_mime_stream_length (GMimeStream *stream)
413 {
414         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
415         
416         return GMIME_STREAM_GET_CLASS (stream)->length (stream);
417 }
418
419
420 static GMimeStream *
421 stream_substream (GMimeStream *stream, gint64 start, gint64 end)
422 {
423         d(g_warning ("Invoked default stream_tell implementation."));
424         return NULL;
425 }
426
427
428 /**
429  * g_mime_stream_substream:
430  * @stream: a #GMimeStream
431  * @start: start boundary
432  * @end: end boundary
433  *
434  * Creates a new substream of @stream with bounds @start and @end.
435  *
436  * Returns: a substream of @stream with bounds @start and @end.
437  **/
438 GMimeStream *
439 g_mime_stream_substream (GMimeStream *stream, gint64 start, gint64 end)
440 {
441         GMimeStream *sub;
442         
443         g_return_val_if_fail (GMIME_IS_STREAM (stream), NULL);
444         
445         if ((sub = GMIME_STREAM_GET_CLASS (stream)->substream (stream, start, end))) {
446                 sub->super_stream = stream;
447                 g_object_ref (stream);
448         }
449         
450         return sub;
451 }
452
453
454 /**
455  * g_mime_stream_set_bounds:
456  * @stream: a #GMimeStream
457  * @start: start boundary
458  * @end: end boundary
459  *
460  * Set the bounds on a stream.
461  **/
462 void
463 g_mime_stream_set_bounds (GMimeStream *stream, gint64 start, gint64 end)
464 {
465         g_return_if_fail (GMIME_IS_STREAM (stream));
466         
467         stream->bound_start = start;
468         stream->bound_end = end;
469         
470         if (stream->position < start)
471                 stream->position = start;
472         else if (stream->position > end && end != -1)
473                 stream->position = end;
474 }
475
476
477 /**
478  * g_mime_stream_write_string:
479  * @stream: a #GMimeStream
480  * @str: string to write
481  *
482  * Writes @string to @stream.
483  *
484  * Returns: the number of bytes written or %-1 on fail.
485  **/
486 ssize_t
487 g_mime_stream_write_string (GMimeStream *stream, const char *str)
488 {
489         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
490         g_return_val_if_fail (str != NULL, -1);
491         
492         return g_mime_stream_write (stream, str, strlen (str));
493 }
494
495
496 /**
497  * g_mime_stream_printf:
498  * @stream: a #GMimeStream
499  * @fmt: format
500  * @Varargs: arguments
501  *
502  * Write formatted output to a stream.
503  *
504  * Returns: the number of bytes written or %-1 on fail.
505  **/
506 ssize_t
507 g_mime_stream_printf (GMimeStream *stream, const char *fmt, ...)
508 {
509         va_list args;
510         char *string;
511         ssize_t ret;
512         
513         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
514         g_return_val_if_fail (fmt != NULL, -1);
515         
516         va_start (args, fmt);
517         string = g_strdup_vprintf (fmt, args);
518         va_end (args);
519         
520         if (!string)
521                 return -1;
522         
523         ret = g_mime_stream_write (stream, string, strlen (string));
524         g_free (string);
525         
526         return ret;
527 }
528
529
530 /**
531  * g_mime_stream_write_to_stream:
532  * @src: source stream
533  * @dest: destination stream
534  *
535  * Attempts to write the source stream to the destination stream.
536  *
537  * Returns: the number of bytes written or %-1 on fail.
538  **/
539 ssize_t
540 g_mime_stream_write_to_stream (GMimeStream *src, GMimeStream *dest)
541 {
542         ssize_t nread, nwritten, total = 0;
543         char buf[4096];
544         
545         g_return_val_if_fail (GMIME_IS_STREAM (src), -1);
546         g_return_val_if_fail (GMIME_IS_STREAM (dest), -1);
547         
548         while (!g_mime_stream_eos (src)) {
549                 if ((nread = g_mime_stream_read (src, buf, sizeof (buf))) < 0)
550                         return -1;
551                 
552                 if (nread > 0) {
553                         nwritten = 0;
554                         while (nwritten < nread) {
555                                 ssize_t len;
556                                 
557                                 if ((len = g_mime_stream_write (dest, buf + nwritten, nread - nwritten)) < 0)
558                                         return -1;
559                                 
560                                 nwritten += len;
561                         }
562                         
563                         total += nwritten;
564                 }
565         }
566         
567         return total;
568 }
569
570
571 /**
572  * g_mime_stream_writev:
573  * @stream: a #GMimeStream
574  * @vector: a #GMimeStreamIOVector
575  * @count: number of vector elements
576  *
577  * Writes at most @count blocks described by @vector to @stream.
578  *
579  * Returns: the number of bytes written or %-1 on fail.
580  **/
581 ssize_t
582 g_mime_stream_writev (GMimeStream *stream, GMimeStreamIOVector *vector, size_t count)
583 {
584         ssize_t total = 0;
585         size_t i;
586         
587         g_return_val_if_fail (GMIME_IS_STREAM (stream), -1);
588         
589         for (i = 0; i < count; i++) {
590                 char *buffer = vector[i].data;
591                 size_t nwritten = 0;
592                 ssize_t n;
593                 
594                 while (nwritten < vector[i].len) {
595                         if ((n = g_mime_stream_write (stream, buffer + nwritten,
596                                                       vector[i].len - nwritten)) < 0)
597                                 return -1;
598                         
599                         nwritten += n;
600                 }
601                 
602                 total += nwritten;
603         }
604         
605         return total;
606 }