Whitespace cleanups.
[platform/upstream/evolution-data-server.git] / camel / camel-mime-filter.c
1 /*
2  *  Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
3  *
4  *  Authors: Michael Zucchi <notzed@ximian.com>
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of version 2 of the GNU Lesser General Public
8  * License as published by the Free Software Foundation.
9  *
10  * This program 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  * 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 program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include <string.h>
22
23 #include "camel-mime-filter.h"
24
25 /*#define MALLOC_CHECK */ /* for some malloc checking, requires mcheck enabled */
26
27 /* only suitable for glibc */
28 #ifdef MALLOC_CHECK
29 #include <mcheck.h>
30 #endif
31
32 #define CAMEL_MIME_FILTER_GET_PRIVATE(obj) \
33         (G_TYPE_INSTANCE_GET_PRIVATE \
34         ((obj), CAMEL_TYPE_MIME_FILTER, CamelMimeFilterPrivate))
35
36 struct _CamelMimeFilterPrivate {
37         gchar *inbuf;
38         gsize inlen;
39 };
40
41 #define PRE_HEAD (64)
42 #define BACK_HEAD (64)
43
44 G_DEFINE_ABSTRACT_TYPE (CamelMimeFilter, camel_mime_filter, CAMEL_TYPE_OBJECT)
45
46 static void
47 mime_filter_finalize (GObject *object)
48 {
49         CamelMimeFilter *mime_filter;
50
51         mime_filter = CAMEL_MIME_FILTER (object);
52
53         g_free (mime_filter->outreal);
54         g_free (mime_filter->backbuf);
55         g_free (mime_filter->priv->inbuf);
56
57         /* Chain up to parent's finalize() method. */
58         G_OBJECT_CLASS (camel_mime_filter_parent_class)->finalize (object);
59 }
60
61 static void
62 mime_filter_complete (CamelMimeFilter *mime_filter,
63                       const gchar *in,
64                       gsize len,
65                       gsize prespace,
66                       gchar **out,
67                       gsize *outlen,
68                       gsize *outprespace)
69 {
70         /* default - do nothing */
71 }
72
73 static void
74 camel_mime_filter_class_init (CamelMimeFilterClass *class)
75 {
76         GObjectClass *object_class;
77
78         g_type_class_add_private (class, sizeof (CamelMimeFilterPrivate));
79
80         object_class = G_OBJECT_CLASS (class);
81         object_class->finalize = mime_filter_finalize;
82
83         class->complete = mime_filter_complete;
84 }
85
86 static void
87 camel_mime_filter_init (CamelMimeFilter *mime_filter)
88 {
89         mime_filter->priv = CAMEL_MIME_FILTER_GET_PRIVATE (mime_filter);
90
91         mime_filter->outreal = NULL;
92         mime_filter->outbuf = NULL;
93         mime_filter->outsize = 0;
94
95         mime_filter->backbuf = NULL;
96         mime_filter->backsize = 0;
97         mime_filter->backlen = 0;
98 }
99
100 /**
101  * camel_mime_filter_new:
102  *
103  * Create a new #CamelMimeFilter object.
104  *
105  * Returns: a new #CamelMimeFilter
106  **/
107 CamelMimeFilter *
108 camel_mime_filter_new (void)
109 {
110         return g_object_new (CAMEL_TYPE_MIME_FILTER, NULL);
111 }
112
113 #ifdef MALLOC_CHECK
114 static void
115 checkmem (gpointer p)
116 {
117         if (p) {
118                 gint status = mprobe (p);
119
120                 switch (status) {
121                 case MCHECK_HEAD:
122                         printf("Memory underrun at %p\n", p);
123                         abort ();
124                 case MCHECK_TAIL:
125                         printf("Memory overrun at %p\n", p);
126                         abort ();
127                 case MCHECK_FREE:
128                         printf("Double free %p\n", p);
129                         abort ();
130                 }
131         }
132 }
133 #endif
134
135 static void filter_run (CamelMimeFilter *f,
136                        const gchar *in, gsize len, gsize prespace,
137                        gchar **out, gsize *outlen, gsize *outprespace,
138                        void (*filterfunc)(CamelMimeFilter *f,
139                                           const gchar *in, gsize len, gsize prespace,
140                                           gchar **out, gsize *outlen, gsize *outprespace))
141 {
142 #ifdef MALLOC_CHECK
143         checkmem (f->outreal);
144         checkmem (f->backbuf);
145 #endif
146         /*
147          * here we take a performance hit, if the input buffer doesn't
148          * have the pre-space required.  We make a buffer that does ...
149         */
150         if (f->backlen > 0) {
151                 struct _CamelMimeFilterPrivate *p;
152                 gint newlen;
153
154                 p = CAMEL_MIME_FILTER_GET_PRIVATE (f);
155
156                 newlen = len + prespace + f->backlen;
157                 if (p->inlen < newlen) {
158                         /* NOTE: g_realloc copies data, we dont need that (slower) */
159                         g_free (p->inbuf);
160                         p->inbuf = g_malloc (newlen + PRE_HEAD);
161                         p->inlen = newlen + PRE_HEAD;
162                 }
163
164                 /* copy to end of structure */
165                 memcpy (p->inbuf + p->inlen - len, in, len);
166                 in = p->inbuf + p->inlen - len;
167                 prespace = p->inlen - len;
168
169                 /* preload any backed up data */
170                 memcpy ((gchar *) in - f->backlen, f->backbuf, f->backlen);
171                 in -= f->backlen;
172                 len += f->backlen;
173                 prespace -= f->backlen;
174                 f->backlen = 0;
175         }
176
177 #ifdef MALLOC_CHECK
178         checkmem (f->outreal);
179         checkmem (f->backbuf);
180 #endif
181
182         filterfunc (f, in, len, prespace, out, outlen, outprespace);
183
184 #ifdef MALLOC_CHECK
185         checkmem (f->outreal);
186         checkmem (f->backbuf);
187 #endif
188
189 }
190
191 /**
192  * camel_mime_filter_filter:
193  * @filter: a #CamelMimeFilter object
194  * @in: input buffer
195  * @len: length of @in
196  * @prespace: amount of prespace
197  * @out: pointer to the output buffer (to be set)
198  * @outlen: pointer to the length of the output buffer (to be set)
199  * @outprespace: pointer to the output prespace length (to be set)
200  *
201  * Passes the input buffer, @in, through @filter and generates an
202  * output buffer, @out.
203  **/
204 void
205 camel_mime_filter_filter (CamelMimeFilter *filter,
206                           const gchar *in,
207                           gsize len,
208                           gsize prespace,
209                           gchar **out,
210                           gsize *outlen,
211                           gsize *outprespace)
212 {
213         CamelMimeFilterClass *class;
214
215         g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
216         g_return_if_fail (in != NULL);
217
218         class = CAMEL_MIME_FILTER_GET_CLASS (filter);
219         g_return_if_fail (class->filter != NULL);
220
221         filter_run (
222                 filter, in, len, prespace, out,
223                 outlen, outprespace, class->filter);
224 }
225
226 /**
227  * camel_mime_filter_complete:
228  * @filter: a #CamelMimeFilter object
229  * @in: input buffer
230  * @len: length of @in
231  * @prespace: amount of prespace
232  * @out: pointer to the output buffer (to be set)
233  * @outlen: pointer to the length of the output buffer (to be set)
234  * @outprespace: pointer to the output prespace length (to be set)
235  *
236  * Passes the input buffer, @in, through @filter and generates an
237  * output buffer, @out and makes sure that all data is flushed to the
238  * output buffer. This must be the last filtering call made, no
239  * further calls to camel_mime_filter_filter() may be called on @filter
240  * until @filter has been reset using camel_mime_filter_reset().
241  **/
242 void
243 camel_mime_filter_complete (CamelMimeFilter *filter,
244                             const gchar *in,
245                             gsize len,
246                             gsize prespace,
247                             gchar **out,
248                             gsize *outlen,
249                             gsize *outprespace)
250 {
251         CamelMimeFilterClass *class;
252
253         g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
254         g_return_if_fail (in != NULL);
255
256         class = CAMEL_MIME_FILTER_GET_CLASS (filter);
257         g_return_if_fail (class->complete != NULL);
258
259         filter_run (
260                 filter, in, len, prespace, out,
261                 outlen, outprespace, class->complete);
262 }
263
264 /**
265  * camel_mime_filter_reset:
266  * @filter: a #CamelMimeFilter object
267  *
268  * Resets the state on @filter so that it may be used again.
269  **/
270 void
271 camel_mime_filter_reset (CamelMimeFilter *filter)
272 {
273         CamelMimeFilterClass *class;
274
275         g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
276
277         class = CAMEL_MIME_FILTER_GET_CLASS (filter);
278
279         if (class->reset != NULL)
280                 class->reset (filter);
281
282         /* could free some buffers, if they are really big? */
283         filter->backlen = 0;
284 }
285
286 /**
287  * camel_mime_filter_backup:
288  * @filter: a #CamelMimeFilter object
289  * @data: data buffer to backup
290  * @length: length of @data
291  *
292  * Saves @data to be used as prespace input data to the next call to
293  * camel_mime_filter_filter() or camel_mime_filter_complete().
294  *
295  * Note: New calls replace old data.
296  **/
297 void
298 camel_mime_filter_backup (CamelMimeFilter *filter,
299                           const gchar *data,
300                           gsize length)
301 {
302         if (filter->backsize < length) {
303                 /* g_realloc copies data, unnecessary overhead */
304                 g_free (filter->backbuf);
305                 filter->backbuf = g_malloc (length + BACK_HEAD);
306                 filter->backsize = length + BACK_HEAD;
307         }
308         filter->backlen = length;
309         memcpy (filter->backbuf, data, length);
310 }
311
312 /**
313  * camel_mime_filter_set_size:
314  * @filter: a #CamelMimeFilter object
315  * @size: requested amount of storage space
316  * @keep: %TRUE to keep existing buffered data or %FALSE otherwise
317  *
318  * Ensure that @filter has enough storage space to store @size bytes
319  * for filter output.
320  **/
321 void
322 camel_mime_filter_set_size (CamelMimeFilter *filter,
323                             gsize size,
324                             gint keep)
325 {
326         if (filter->outsize < size) {
327                 gint offset = filter->outptr - filter->outreal;
328                 if (keep) {
329                         filter->outreal = g_realloc (filter->outreal, size + PRE_HEAD * 4);
330                 } else {
331                         g_free (filter->outreal);
332                         filter->outreal = g_malloc (size + PRE_HEAD * 4);
333                 }
334                 filter->outptr = filter->outreal + offset;
335                 filter->outbuf = filter->outreal + PRE_HEAD * 4;
336                 filter->outsize = size;
337                 /* this could be offset from the end of the structure, but
338                  * this should be good enough */
339                 filter->outpre = PRE_HEAD * 4;
340         }
341 }