Initialize the gmime for upstream
[platform/upstream/gmime.git] / gmime / gmime-filter.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> /* for memcpy */
27
28 #include "gmime-filter.h"
29
30
31 /**
32  * SECTION: gmime-filter
33  * @title: GMimeFilter
34  * @short_description: Abstract filter class
35  * @see_also: #GMimeStreamFilter
36  *
37  * Stream filters are an efficient way of converting data from one
38  * format to another.
39  **/
40
41
42 struct _GMimeFilterPrivate {
43         char *inbuf;
44         size_t inlen;
45 };
46
47 #define PRE_HEAD (64)
48 #define BACK_HEAD (64)
49 #define _PRIVATE(o) (((GMimeFilter *)(o))->priv)
50
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);
54
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);
61
62
63 static GObjectClass *parent_class = NULL;
64
65
66 GType
67 g_mime_filter_get_type (void)
68 {
69         static GType type = 0;
70         
71         if (!type) {
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 */
79                         sizeof (GMimeFilter),
80                         0,    /* n_preallocs */
81                         (GInstanceInitFunc) g_mime_filter_init,
82                 };
83                 
84                 type = g_type_register_static (G_TYPE_OBJECT, "GMimeFilter",
85                                                &info, G_TYPE_FLAG_ABSTRACT);
86         }
87         
88         return type;
89 }
90
91
92 static void
93 g_mime_filter_class_init (GMimeFilterClass *klass)
94 {
95         GObjectClass *object_class = G_OBJECT_CLASS (klass);
96         
97         parent_class = g_type_class_ref (G_TYPE_OBJECT);
98         
99         object_class->finalize = g_mime_filter_finalize;
100         
101         klass->copy = filter_copy;
102         klass->filter = filter_filter;
103         klass->complete = filter_complete;
104         klass->reset = filter_reset;
105 }
106
107 static void
108 g_mime_filter_init (GMimeFilter *filter, GMimeFilterClass *klass)
109 {
110         filter->priv = g_new0 (struct _GMimeFilterPrivate, 1);
111         filter->outptr = NULL;
112         filter->outreal = NULL;
113         filter->outbuf = NULL;
114         filter->outsize = 0;
115         
116         filter->backbuf = NULL;
117         filter->backsize = 0;
118         filter->backlen = 0;
119 }
120
121 static void
122 g_mime_filter_finalize (GObject *object)
123 {
124         GMimeFilter *filter = (GMimeFilter *) object;
125         
126         g_free (filter->priv->inbuf);
127         g_free (filter->priv);
128         g_free (filter->outreal);
129         g_free (filter->backbuf);
130         
131         G_OBJECT_CLASS (parent_class)->finalize (object);
132 }
133
134
135 static GMimeFilter *
136 filter_copy (GMimeFilter *filter)
137 {
138         return NULL;
139 }
140
141
142 /**
143  * g_mime_filter_copy:
144  * @filter: filter
145  *
146  * Copies @filter into a new GMimeFilter object.
147  *
148  * Returns: a duplicate of @filter.
149  **/
150 GMimeFilter *
151 g_mime_filter_copy (GMimeFilter *filter)
152 {
153         g_return_val_if_fail (GMIME_IS_FILTER (filter), NULL);
154         
155         return GMIME_FILTER_GET_CLASS (filter)->copy (filter);
156 }
157
158
159 static void
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))
165 {
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;
171                 
172                 if (p->inlen < newlen) {
173                         /* NOTE: g_realloc copies data, we dont need that (slower) */
174                         g_free (p->inbuf);
175                         p->inbuf = g_malloc (newlen + PRE_HEAD);
176                         p->inlen = newlen + PRE_HEAD;
177                 }
178                 
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;
183         }
184         
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;
191                 filter->backlen = 0;
192         }
193         
194         filterfunc (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace);
195 }
196
197
198 static void
199 filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
200                char **outbuf, size_t *outlen, size_t *outprespace)
201 {
202         /* no-op */
203 }
204
205
206 /**
207  * g_mime_filter_filter:
208  * @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
215  *
216  * Filters the input data and writes it to @out.
217  **/
218 void
219 g_mime_filter_filter (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
220                       char **outbuf, size_t *outlen, size_t *outprespace)
221 {
222         g_return_if_fail (GMIME_IS_FILTER (filter));
223         
224         filter_run (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace,
225                     GMIME_FILTER_GET_CLASS (filter)->filter);
226 }
227
228
229 static void
230 filter_complete (GMimeFilter *filter, char *inbuf, size_t inlen, size_t prespace,
231                  char **outbuf, size_t *outlen, size_t *outprespace)
232 {
233         /* no-op */
234 }
235
236
237 /**
238  * g_mime_filter_complete:
239  * @filter: filter
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
246  *
247  * Completes the filtering.
248  **/
249 void
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)
253 {
254         g_return_if_fail (GMIME_IS_FILTER (filter));
255         
256         filter_run (filter, inbuf, inlen, prespace, outbuf, outlen, outprespace,
257                     GMIME_FILTER_GET_CLASS (filter)->complete);
258 }
259
260
261 static void
262 filter_reset (GMimeFilter *filter)
263 {
264         /* no-op */
265 }
266
267
268 /**
269  * g_mime_filter_reset:
270  * @filter: a #GMimeFilter object
271  *
272  * Resets the filter.
273  **/
274 void
275 g_mime_filter_reset (GMimeFilter *filter)
276 {
277         g_return_if_fail (GMIME_IS_FILTER (filter));
278         
279         GMIME_FILTER_GET_CLASS (filter)->reset (filter);
280         
281         /* could free some buffers, if they are really big? */
282         filter->backlen = 0;
283 }
284
285
286 /**
287  * g_mime_filter_backup:
288  * @filter: filter
289  * @data: data to backup
290  * @length: length of @data
291  *
292  * Sets number of bytes backed up on the input, new calls replace
293  * previous ones
294  **/
295 void
296 g_mime_filter_backup (GMimeFilter *filter, const char *data, size_t length)
297 {
298         g_return_if_fail (GMIME_IS_FILTER (filter));
299         
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;
305         }
306         
307         filter->backlen = length;
308         memcpy (filter->backbuf, data, length);
309 }
310
311
312 /**
313  * g_mime_filter_set_size:
314  * @filter: filter
315  * @size: requested size for the output buffer
316  * @keep: %TRUE if existing data in the output buffer should be kept
317  *
318  * Ensure this much size is available for filter output (if required)
319  **/
320 void
321 g_mime_filter_set_size (GMimeFilter *filter, size_t size, gboolean keep)
322 {
323         g_return_if_fail (GMIME_IS_FILTER (filter));
324         
325         if (filter->outsize < size) {
326                 size_t offset = filter->outptr - filter->outreal;
327                 
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                 
335                 filter->outptr = filter->outreal + offset;
336                 filter->outbuf = filter->outreal + PRE_HEAD * 4;
337                 filter->outsize = size;
338                 
339                 /* this could be offset from the end of the structure, but 
340                    this should be good enough */
341                 
342                 filter->outpre = PRE_HEAD * 4;
343         }
344 }