2 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4 * Authors: Michael Zucchi <notzed@ximian.com>
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.
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.
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.
23 #include "camel-mime-filter.h"
25 /*#define MALLOC_CHECK */ /* for some malloc checking, requires mcheck enabled */
27 /* only suitable for glibc */
32 #define CAMEL_MIME_FILTER_GET_PRIVATE(obj) \
33 (G_TYPE_INSTANCE_GET_PRIVATE \
34 ((obj), CAMEL_TYPE_MIME_FILTER, CamelMimeFilterPrivate))
36 struct _CamelMimeFilterPrivate {
42 #define BACK_HEAD (64)
44 G_DEFINE_ABSTRACT_TYPE (CamelMimeFilter, camel_mime_filter, CAMEL_TYPE_OBJECT)
47 mime_filter_finalize (GObject *object)
49 CamelMimeFilter *mime_filter;
51 mime_filter = CAMEL_MIME_FILTER (object);
53 g_free (mime_filter->outreal);
54 g_free (mime_filter->backbuf);
55 g_free (mime_filter->priv->inbuf);
57 /* Chain up to parent's finalize() method. */
58 G_OBJECT_CLASS (camel_mime_filter_parent_class)->finalize (object);
62 mime_filter_complete (CamelMimeFilter *mime_filter,
70 /* default - do nothing */
74 camel_mime_filter_class_init (CamelMimeFilterClass *class)
76 GObjectClass *object_class;
78 g_type_class_add_private (class, sizeof (CamelMimeFilterPrivate));
80 object_class = G_OBJECT_CLASS (class);
81 object_class->finalize = mime_filter_finalize;
83 class->complete = mime_filter_complete;
87 camel_mime_filter_init (CamelMimeFilter *mime_filter)
89 mime_filter->priv = CAMEL_MIME_FILTER_GET_PRIVATE (mime_filter);
91 mime_filter->outreal = NULL;
92 mime_filter->outbuf = NULL;
93 mime_filter->outsize = 0;
95 mime_filter->backbuf = NULL;
96 mime_filter->backsize = 0;
97 mime_filter->backlen = 0;
101 * camel_mime_filter_new:
103 * Create a new #CamelMimeFilter object.
105 * Returns: a new #CamelMimeFilter
108 camel_mime_filter_new (void)
110 return g_object_new (CAMEL_TYPE_MIME_FILTER, NULL);
115 checkmem (gpointer p)
118 gint status = mprobe (p);
122 printf("Memory underrun at %p\n", p);
125 printf("Memory overrun at %p\n", p);
128 printf("Double free %p\n", p);
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))
143 checkmem (f->outreal);
144 checkmem (f->backbuf);
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 ...
150 if (f->backlen > 0) {
151 struct _CamelMimeFilterPrivate *p;
154 p = CAMEL_MIME_FILTER_GET_PRIVATE (f);
156 newlen = len + prespace + f->backlen;
157 if (p->inlen < newlen) {
158 /* NOTE: g_realloc copies data, we dont need that (slower) */
160 p->inbuf = g_malloc (newlen + PRE_HEAD);
161 p->inlen = newlen + PRE_HEAD;
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;
169 /* preload any backed up data */
170 memcpy ((gchar *) in - f->backlen, f->backbuf, f->backlen);
173 prespace -= f->backlen;
178 checkmem (f->outreal);
179 checkmem (f->backbuf);
182 filterfunc (f, in, len, prespace, out, outlen, outprespace);
185 checkmem (f->outreal);
186 checkmem (f->backbuf);
192 * camel_mime_filter_filter:
193 * @filter: a #CamelMimeFilter object
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)
201 * Passes the input buffer, @in, through @filter and generates an
202 * output buffer, @out.
205 camel_mime_filter_filter (CamelMimeFilter *filter,
213 CamelMimeFilterClass *class;
215 g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
216 g_return_if_fail (in != NULL);
218 class = CAMEL_MIME_FILTER_GET_CLASS (filter);
219 g_return_if_fail (class->filter != NULL);
222 filter, in, len, prespace, out,
223 outlen, outprespace, class->filter);
227 * camel_mime_filter_complete:
228 * @filter: a #CamelMimeFilter object
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)
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().
243 camel_mime_filter_complete (CamelMimeFilter *filter,
251 CamelMimeFilterClass *class;
253 g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
254 g_return_if_fail (in != NULL);
256 class = CAMEL_MIME_FILTER_GET_CLASS (filter);
257 g_return_if_fail (class->complete != NULL);
260 filter, in, len, prespace, out,
261 outlen, outprespace, class->complete);
265 * camel_mime_filter_reset:
266 * @filter: a #CamelMimeFilter object
268 * Resets the state on @filter so that it may be used again.
271 camel_mime_filter_reset (CamelMimeFilter *filter)
273 CamelMimeFilterClass *class;
275 g_return_if_fail (CAMEL_IS_MIME_FILTER (filter));
277 class = CAMEL_MIME_FILTER_GET_CLASS (filter);
279 if (class->reset != NULL)
280 class->reset (filter);
282 /* could free some buffers, if they are really big? */
287 * camel_mime_filter_backup:
288 * @filter: a #CamelMimeFilter object
289 * @data: data buffer to backup
290 * @length: length of @data
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().
295 * Note: New calls replace old data.
298 camel_mime_filter_backup (CamelMimeFilter *filter,
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;
308 filter->backlen = length;
309 memcpy (filter->backbuf, data, length);
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
318 * Ensure that @filter has enough storage space to store @size bytes
322 camel_mime_filter_set_size (CamelMimeFilter *filter,
326 if (filter->outsize < size) {
327 gint offset = filter->outptr - filter->outreal;
329 filter->outreal = g_realloc (filter->outreal, size + PRE_HEAD * 4);
331 g_free (filter->outreal);
332 filter->outreal = g_malloc (size + PRE_HEAD * 4);
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;