Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-stream-mem.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 #include <errno.h>
28
29 #include "gmime-stream-mem.h"
30
31
32 /**
33  * SECTION: gmime-stream-mem
34  * @title: GMimeStreamMem
35  * @short_description: A memory-backed stream
36  * @see_also: #GMimeStream
37  *
38  * A simple #GMimeStream implementation that uses a memory buffer for
39  * storage.
40  **/
41
42
43 static void g_mime_stream_mem_class_init (GMimeStreamMemClass *klass);
44 static void g_mime_stream_mem_init (GMimeStreamMem *stream, GMimeStreamMemClass *klass);
45 static void g_mime_stream_mem_finalize (GObject *object);
46
47 static ssize_t stream_read (GMimeStream *stream, char *buf, size_t len);
48 static ssize_t stream_write (GMimeStream *stream, const char *buf, size_t len);
49 static int stream_flush (GMimeStream *stream);
50 static int stream_close (GMimeStream *stream);
51 static gboolean stream_eos (GMimeStream *stream);
52 static int stream_reset (GMimeStream *stream);
53 static gint64 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence);
54 static gint64 stream_tell (GMimeStream *stream);
55 static gint64 stream_length (GMimeStream *stream);
56 static GMimeStream *stream_substream (GMimeStream *stream, gint64 start, gint64 end);
57
58
59 static GMimeStreamClass *parent_class = NULL;
60
61
62 GType
63 g_mime_stream_mem_get_type (void)
64 {
65         static GType type = 0;
66         
67         if (!type) {
68                 static const GTypeInfo info = {
69                         sizeof (GMimeStreamMemClass),
70                         NULL, /* base_class_init */
71                         NULL, /* base_class_finalize */
72                         (GClassInitFunc) g_mime_stream_mem_class_init,
73                         NULL, /* class_finalize */
74                         NULL, /* class_data */
75                         sizeof (GMimeStreamMem),
76                         0,    /* n_preallocs */
77                         (GInstanceInitFunc) g_mime_stream_mem_init,
78                 };
79                 
80                 type = g_type_register_static (GMIME_TYPE_STREAM, "GMimeStreamMem", &info, 0);
81         }
82         
83         return type;
84 }
85
86
87 static void
88 g_mime_stream_mem_class_init (GMimeStreamMemClass *klass)
89 {
90         GMimeStreamClass *stream_class = GMIME_STREAM_CLASS (klass);
91         GObjectClass *object_class = G_OBJECT_CLASS (klass);
92         
93         parent_class = g_type_class_ref (GMIME_TYPE_STREAM);
94         
95         object_class->finalize = g_mime_stream_mem_finalize;
96         
97         stream_class->read = stream_read;
98         stream_class->write = stream_write;
99         stream_class->flush = stream_flush;
100         stream_class->close = stream_close;
101         stream_class->eos = stream_eos;
102         stream_class->reset = stream_reset;
103         stream_class->seek = stream_seek;
104         stream_class->tell = stream_tell;
105         stream_class->length = stream_length;
106         stream_class->substream = stream_substream;
107 }
108
109 static void
110 g_mime_stream_mem_init (GMimeStreamMem *stream, GMimeStreamMemClass *klass)
111 {
112         stream->owner = TRUE;
113         stream->buffer = NULL;
114 }
115
116 static void
117 g_mime_stream_mem_finalize (GObject *object)
118 {
119         GMimeStreamMem *stream = (GMimeStreamMem *) object;
120         
121         if (stream->owner && stream->buffer)
122                 g_byte_array_free (stream->buffer, TRUE);
123         
124         G_OBJECT_CLASS (parent_class)->finalize (object);
125 }
126
127
128 static ssize_t
129 stream_read (GMimeStream *stream, char *buf, size_t len)
130 {
131         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
132         gint64 bound_end;
133         ssize_t n;
134         
135         if (mem->buffer == NULL) {
136                 errno = EBADF;
137                 return -1;
138         }
139         
140         bound_end = stream->bound_end != -1 ? stream->bound_end : (gint64) mem->buffer->len;
141         
142         n = (size_t) MIN (bound_end - stream->position, (gint64) len);
143         if (n > 0) {
144                 memcpy (buf, mem->buffer->data + stream->position, n);
145                 stream->position += n;
146         } else if (n < 0) {
147                 errno = EINVAL;
148                 n = -1;
149         }
150         
151         return n;
152 }
153
154 static ssize_t
155 stream_write (GMimeStream *stream, const char *buf, size_t len)
156 {
157         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
158         gint64 bound_end;
159         ssize_t n;
160         
161         if (mem->buffer == NULL) {
162                 errno = EBADF;
163                 return -1;
164         }
165         
166         if (stream->bound_end == -1) {
167                 if (stream->position + len > mem->buffer->len)
168                         g_byte_array_set_size (mem->buffer, (guint) stream->position + len);
169                 
170                 bound_end = mem->buffer->len;
171         } else
172                 bound_end = stream->bound_end;
173         
174         n = (size_t) MIN (bound_end - stream->position, (gint64) len);
175         if (n > 0) {
176                 memcpy (mem->buffer->data + stream->position, buf, n);
177                 stream->position += n;
178         } else if (n < 0) {
179                 errno = EINVAL;
180                 n = -1;
181         }
182         
183         return n;
184 }
185
186 static int
187 stream_flush (GMimeStream *stream)
188 {
189         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
190         
191         if (mem->buffer == NULL) {
192                 errno = EBADF;
193                 return -1;
194         }
195         
196         return 0;
197 }
198
199 static int
200 stream_close (GMimeStream *stream)
201 {
202         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
203         
204         if (mem->owner && mem->buffer)
205                 g_byte_array_free (mem->buffer, TRUE);
206         
207         mem->buffer = NULL;
208         
209         return 0;
210 }
211
212 static gboolean
213 stream_eos (GMimeStream *stream)
214 {
215         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
216         gint64 bound_end;
217         
218         if (mem->buffer == NULL)
219                 return TRUE;
220         
221         bound_end = stream->bound_end != -1 ? stream->bound_end : (gint64) mem->buffer->len;
222         
223         return stream->position >= bound_end;
224 }
225
226 static int
227 stream_reset (GMimeStream *stream)
228 {
229         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
230         
231         if (mem->buffer == NULL) {
232                 errno = EBADF;
233                 return -1;
234         }
235         
236         return 0;
237 }
238
239 static gint64
240 stream_seek (GMimeStream *stream, gint64 offset, GMimeSeekWhence whence)
241 {
242         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
243         gint64 bound_end, real = stream->position;
244         
245         if (mem->buffer == NULL) {
246                 errno = EBADF;
247                 return -1;
248         }
249         
250         bound_end = stream->bound_end != -1 ? stream->bound_end : (gint64) mem->buffer->len;
251         
252         switch (whence) {
253         case GMIME_STREAM_SEEK_SET:
254                 real = offset;
255                 break;
256         case GMIME_STREAM_SEEK_END:
257                 real = offset + bound_end;
258                 break;
259         case GMIME_STREAM_SEEK_CUR:
260                 real = stream->position + offset;
261                 break;
262         }
263         
264         if (real < stream->bound_start) {
265                 errno = EINVAL;
266                 return -1;
267         }
268         
269         if (stream->bound_end != -1 && real > bound_end) {
270                 errno = EINVAL;
271                 return -1;
272         }
273         
274         if (real > bound_end) {
275                 if (real > G_MAXUINT) {
276                         errno = ENOSPC;
277                         return -1;
278                 }
279                 
280                 g_byte_array_set_size (mem->buffer, (guint) real);
281         }
282         
283         stream->position = real;
284         
285         return stream->position;
286 }
287
288 static gint64
289 stream_tell (GMimeStream *stream)
290 {
291         GMimeStreamMem *mem = (GMimeStreamMem *) stream;
292         
293         if (mem->buffer == NULL) {
294                 errno = EBADF;
295                 return -1;
296         }
297         
298         return stream->position;
299 }
300
301 static gint64
302 stream_length (GMimeStream *stream)
303 {
304         GMimeStreamMem *mem = GMIME_STREAM_MEM (stream);
305         gint64 bound_end;
306         
307         if (mem->buffer == NULL) {
308                 errno = EBADF;
309                 return -1;
310         }
311         
312         bound_end = stream->bound_end != -1 ? stream->bound_end : (gint64) mem->buffer->len;
313         
314         return bound_end - stream->bound_start;
315 }
316
317 static GMimeStream *
318 stream_substream (GMimeStream *stream, gint64 start, gint64 end)
319 {
320         GMimeStreamMem *mem;
321         
322         mem = g_object_newv (GMIME_TYPE_STREAM_MEM, 0, NULL);
323         g_mime_stream_construct ((GMimeStream *) mem, start, end);
324         mem->buffer = GMIME_STREAM_MEM (stream)->buffer;
325         mem->owner = FALSE;
326         
327         return (GMimeStream *) mem;
328 }
329
330
331 /**
332  * g_mime_stream_mem_new:
333  *
334  * Creates a new #GMimeStreamMem object.
335  *
336  * Returns: a new memory stream.
337  **/
338 GMimeStream *
339 g_mime_stream_mem_new (void)
340 {
341         GMimeStreamMem *mem;
342         
343         mem = g_object_newv (GMIME_TYPE_STREAM_MEM, 0, NULL);
344         g_mime_stream_construct ((GMimeStream *) mem, 0, -1);
345         mem->buffer = g_byte_array_new ();
346         mem->owner = TRUE;
347         
348         return (GMimeStream *) mem;
349 }
350
351
352 /**
353  * g_mime_stream_mem_new_with_byte_array:
354  * @array: source data
355  *
356  * Creates a new #GMimeStreamMem with data @array.
357  *
358  * Returns: a new memory stream using @array.
359  **/
360 GMimeStream *
361 g_mime_stream_mem_new_with_byte_array (GByteArray *array)
362 {
363         GMimeStreamMem *mem;
364         
365         mem = g_object_newv (GMIME_TYPE_STREAM_MEM, 0, NULL);
366         g_mime_stream_construct ((GMimeStream *) mem, 0, -1);
367         mem->buffer = array;
368         mem->owner = TRUE;
369         
370         return (GMimeStream *) mem;
371 }
372
373
374 /**
375  * g_mime_stream_mem_new_with_buffer:
376  * @buffer: stream data
377  * @len: buffer length
378  *
379  * Creates a new #GMimeStreamMem object and initializes the stream
380  * contents with the first @len bytes of @buffer.
381  *
382  * Returns: a new memory stream initialized with @buffer.
383  **/
384 GMimeStream *
385 g_mime_stream_mem_new_with_buffer (const char *buffer, size_t len)
386 {
387         GMimeStreamMem *mem;
388         
389         mem = g_object_newv (GMIME_TYPE_STREAM_MEM, 0, NULL);
390         g_mime_stream_construct ((GMimeStream *) mem, 0, -1);
391         mem->buffer = g_byte_array_new ();
392         mem->owner = TRUE;
393         
394         g_byte_array_append (mem->buffer, (unsigned char *) buffer, len);
395         
396         return (GMimeStream *) mem;
397 }
398
399
400 /**
401  * g_mime_stream_mem_get_byte_array:
402  * @mem: a #GMimeStreamMem
403  *
404  * Gets the byte array from the memory stream.
405  *
406  * Returns: the byte array from the memory stream.
407  **/
408 GByteArray *
409 g_mime_stream_mem_get_byte_array (GMimeStreamMem *mem)
410 {
411         g_return_val_if_fail (GMIME_IS_STREAM_MEM (mem), NULL);
412         
413         return mem->buffer;
414 }
415
416
417 /**
418  * g_mime_stream_mem_set_byte_array:
419  * @mem: a #GMimeStreamMem
420  * @array: stream data
421  *
422  * Sets the byte array on the memory stream.
423  *
424  * Note: The memory stream is not responsible for freeing the byte
425  * array. Use g_mime_stream_mem_set_owner() to change this behavior.
426  **/
427 void
428 g_mime_stream_mem_set_byte_array (GMimeStreamMem *mem, GByteArray *array)
429 {
430         GMimeStream *stream;
431         
432         g_return_if_fail (GMIME_IS_STREAM_MEM (mem));
433         g_return_if_fail (array != NULL);
434         
435         if (mem->owner && mem->buffer)
436                 g_byte_array_free (mem->buffer, TRUE);
437         
438         mem->buffer = array;
439         mem->owner = FALSE;
440         
441         stream = GMIME_STREAM (mem);
442         
443         stream->position = 0;
444         stream->bound_start = 0;
445         stream->bound_end = -1;
446 }
447
448
449 /**
450  * g_mime_stream_mem_get_owner:
451  * @mem: a #GMimeStreamMem
452  *
453  * Gets whether or not @mem owns the backend memory buffer.
454  *
455  * Returns: %TRUE if @mem owns the backend memory buffer or %FALSE
456  * otherwise.
457  **/
458 gboolean
459 g_mime_stream_mem_get_owner (GMimeStreamMem *mem)
460 {
461         g_return_val_if_fail (GMIME_IS_STREAM_MEM (mem), FALSE);
462         
463         return mem->owner;
464 }
465
466
467 /**
468  * g_mime_stream_mem_set_owner:
469  * @mem: a #GMimeStreamMem
470  * @owner: %TRUE if this stream should own the #GByteArray or %FALSE otherwise
471  *
472  * Sets whether or not @mem owns the backend memory buffer.
473  *
474  * Note: @owner should be %TRUE if the stream should free the backend
475  * memory buffer when destroyed or %FALSE otherwise.
476  **/
477 void
478 g_mime_stream_mem_set_owner (GMimeStreamMem *mem, gboolean owner)
479 {
480         g_return_if_fail (GMIME_IS_STREAM_MEM (mem));
481         
482         mem->owner = owner;
483 }