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
26 #include <string.h> /* for memcpy */
28 #include "gmime-filter.h"
32 * SECTION: gmime-filter
34 * @short_description: Abstract filter class
35 * @see_also: #GMimeStreamFilter
37 * Stream filters are an efficient way of converting data from one
42 struct _GMimeFilterPrivate {
48 #define BACK_HEAD (64)
49 #define _PRIVATE(o) (((GMimeFilter *)(o))->priv)
51 static void g_mime_filter_class_init (GMimeFilterClass *klass);
52 static void g_mime_filter_init (GMimeFilter *filter, GMimeFilterClass *klass);
53 static void g_mime_filter_finalize (GObject *object);
55 static GMimeFilter *filter_copy (GMimeFilter *filter);
56 static void filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
57 char **outbuf, size_t *outlen, size_t *outprespace);
58 static void filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
59 char **outbuf, size_t *outlen, size_t *outprespace);
60 static void filter_reset (GMimeFilter *filter);
63 static GObjectClass *parent_class = NULL;
67 g_mime_filter_get_type (void)
69 static GType type = 0;
72 static const GTypeInfo info = {
73 sizeof (GMimeFilterClass),
74 NULL, /* base_class_init */
75 NULL, /* base_class_finalize */
76 (GClassInitFunc) g_mime_filter_class_init,
77 NULL, /* class_finalize */
78 NULL, /* class_data */
81 (GInstanceInitFunc) g_mime_filter_init,
84 type = g_type_register_static (G_TYPE_OBJECT, "GMimeFilter",
85 &info, G_TYPE_FLAG_ABSTRACT);
93 g_mime_filter_class_init (GMimeFilterClass *klass)
95 GObjectClass *object_class = G_OBJECT_CLASS (klass);
97 parent_class = g_type_class_ref (G_TYPE_OBJECT);
99 object_class->finalize = g_mime_filter_finalize;
101 klass->copy = filter_copy;
102 klass->filter = filter_filter;
103 klass->complete = filter_complete;
104 klass->reset = filter_reset;
108 g_mime_filter_init (GMimeFilter *filter, GMimeFilterClass *klass)
110 filter->priv = g_new0 (struct _GMimeFilterPrivate, 1);
111 filter->outptr = NULL;
112 filter->outreal = NULL;
113 filter->outbuf = NULL;
116 filter->backbuf = NULL;
117 filter->backsize = 0;
122 g_mime_filter_finalize (GObject *object)
124 GMimeFilter *filter = (GMimeFilter *) object;
126 g_free (filter->priv->inbuf);
127 g_free (filter->priv);
128 g_free (filter->outreal);
129 g_free (filter->backbuf);
131 G_OBJECT_CLASS (parent_class)->finalize (object);
136 filter_copy (GMimeFilter *filter)
143 * g_mime_filter_copy:
146 * Copies @filter into a new GMimeFilter object.
148 * Returns: a duplicate of @filter.
151 g_mime_filter_copy (GMimeFilter *filter)
153 g_return_val_if_fail (GMIME_IS_FILTER (filter), NULL);
155 return GMIME_FILTER_GET_CLASS (filter)->copy (filter);
160 filter_run (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
161 char **outbuf, size_t *outlen, size_t *outprespace,
162 void (*filterfunc) (GMimeFilter *filter,
163 char *inbuf, size_t inlen, size_t prespace,
164 char **outbuf, size_t *outlen, size_t *outprespace))
166 /* here we take a performance hit, if the input buffer doesn't
167 have the pre-space required. We make a buffer that does... */
168 if (prespace < filter->backlen) {
169 struct _GMimeFilterPrivate *p = _PRIVATE (filter);
170 size_t newlen = inlen + prespace + filter->backlen;
172 if (p->inlen < newlen) {
173 /* NOTE: g_realloc copies data, we dont need that (slower) */
175 p->inbuf = g_malloc (newlen + PRE_HEAD);
176 p->inlen = newlen + PRE_HEAD;
179 /* copy to end of structure */
180 memcpy (p->inbuf + p->inlen - inlen, inbuf, inlen);
181 inbuf = p->inbuf + p->inlen - inlen;
182 prespace = p->inlen - inlen;
185 /* preload any backed up data */
186 if (filter->backlen > 0) {
187 memcpy (inbuf - filter->backlen, filter->backbuf, filter->backlen);
188 inbuf -= filter->backlen;
189 inlen += filter->backlen;
190 prespace -= filter->backlen;
194 filterfunc (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace);
199 filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
200 char **outbuf, size_t *outlen, size_t *outprespace)
207 * g_mime_filter_filter:
209 * @inbuf: input buffer
210 * @inlen: input buffer length
211 * @prespace: prespace buffer length
212 * @outbuf: pointer to output buffer
213 * @outlen: pointer to output length
214 * @outprespace: pointer to output prespace buffer length
216 * Filters the input data and writes it to @out.
219 g_mime_filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
220 char **outbuf, size_t *outlen, size_t *outprespace)
222 g_return_if_fail (GMIME_IS_FILTER (filter));
224 filter_run (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace,
225 GMIME_FILTER_GET_CLASS (filter)->filter);
230 filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
231 char **outbuf, size_t *outlen, size_t *outprespace)
238 * g_mime_filter_complete:
240 * @inbuf: input buffer
241 * @inlen: input buffer length
242 * @prespace: prespace buffer length
243 * @outbuf: pointer to output buffer
244 * @outlen: pointer to output length
245 * @outprespace: pointer to output prespace buffer length
247 * Completes the filtering.
250 g_mime_filter_complete (GMimeFilter *filter,
251 char *inbuf, size_t inlen, size_t prespace,
252 char **outbuf, size_t *outlen, size_t *outprespace)
254 g_return_if_fail (GMIME_IS_FILTER (filter));
256 filter_run (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace,
257 GMIME_FILTER_GET_CLASS (filter)->complete);
262 filter_reset (GMimeFilter *filter)
269 * g_mime_filter_reset:
270 * @filter: a #GMimeFilter object
275 g_mime_filter_reset (GMimeFilter *filter)
277 g_return_if_fail (GMIME_IS_FILTER (filter));
279 GMIME_FILTER_GET_CLASS (filter)->reset (filter);
281 /* could free some buffers, if they are really big? */
287 * g_mime_filter_backup:
289 * @data: data to backup
290 * @length: length of @data
292 * Sets number of bytes backed up on the input, new calls replace
296 g_mime_filter_backup (GMimeFilter *filter, const char *data, size_t length)
298 g_return_if_fail (GMIME_IS_FILTER (filter));
300 if (filter->backsize < length) {
301 /* g_realloc copies data, unnecessary overhead */
302 g_free (filter->backbuf);
303 filter->backbuf = g_malloc (length + BACK_HEAD);
304 filter->backsize = length + BACK_HEAD;
307 filter->backlen = length;
308 memcpy (filter->backbuf, data, length);
313 * g_mime_filter_set_size:
315 * @size: requested size for the output buffer
316 * @keep: %TRUE if existing data in the output buffer should be kept
318 * Ensure this much size is available for filter output (if required)
321 g_mime_filter_set_size (GMimeFilter *filter, size_t size, gboolean keep)
323 g_return_if_fail (GMIME_IS_FILTER (filter));
325 if (filter->outsize < size) {
326 size_t 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);
335 filter->outptr = filter->outreal + offset;
336 filter->outbuf = filter->outreal + PRE_HEAD * 4;
337 filter->outsize = size;
339 /* this could be offset from the end of the structure, but
340 this should be good enough */
342 filter->outpre = PRE_HEAD * 4;