/* * Copyright (C) 2000 Helix Code Inc. * * Authors: Michael Zucchi * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include "camel-mime-filter.h" /*#define MALLOC_CHECK */ /* for some malloc checking, requires mcheck enabled */ /* only suitable for glibc */ #ifdef MALLOC_CHECK #include #endif struct _CamelMimeFilterPrivate { char *inbuf; size_t inlen; }; #define PRE_HEAD (64) #define BACK_HEAD (64) #define _PRIVATE(o) (((CamelMimeFilter *)(o))->priv) #define FCLASS(o) ((CamelMimeFilterClass *)(CAMEL_OBJECT_GET_CLASS(o))) static CamelObjectClass *camel_mime_filter_parent; static void complete (CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace); static void camel_mime_filter_class_init (CamelMimeFilterClass *klass) { camel_mime_filter_parent = camel_type_get_global_classfuncs (camel_object_get_type ()); klass->complete = complete; } static void camel_mime_filter_init (CamelMimeFilter *obj) { obj->outreal = NULL; obj->outbuf = NULL; obj->outsize = 0; obj->backbuf = NULL; obj->backsize = 0; obj->backlen = 0; _PRIVATE(obj) = g_malloc0(sizeof(*obj->priv)); } static void camel_mime_filter_finalize(CamelObject *o) { CamelMimeFilter *f = (CamelMimeFilter *)o; struct _CamelMimeFilterPrivate *p = _PRIVATE(f); g_free(f->outreal); g_free(f->backbuf); g_free(p->inbuf); g_free(p); } CamelType camel_mime_filter_get_type (void) { static CamelType camel_mime_filter_type = CAMEL_INVALID_TYPE; if (camel_mime_filter_type == CAMEL_INVALID_TYPE) { camel_mime_filter_type = camel_type_register (CAMEL_OBJECT_TYPE, "CamelMimeFilter", sizeof (CamelMimeFilter), sizeof (CamelMimeFilterClass), (CamelObjectClassInitFunc) camel_mime_filter_class_init, NULL, (CamelObjectInitFunc) camel_mime_filter_init, (CamelObjectFinalizeFunc) camel_mime_filter_finalize); } return camel_mime_filter_type; } static void complete(CamelMimeFilter *mf, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace) { /* default - do nothing */ } /** * camel_mime_filter_new: * * Create a new CamelMimeFilter object. * * Return value: A new CamelMimeFilter widget. **/ CamelMimeFilter * camel_mime_filter_new (void) { CamelMimeFilter *new = CAMEL_MIME_FILTER ( camel_object_new (camel_mime_filter_get_type ())); return new; } #ifdef MALLOC_CHECK static void checkmem(void *p) { if (p) { int status = mprobe(p); switch (status) { case MCHECK_HEAD: printf("Memory underrun at %p\n", p); abort(); case MCHECK_TAIL: printf("Memory overrun at %p\n", p); abort(); case MCHECK_FREE: printf("Double free %p\n", p); abort(); } } } #endif static void filter_run(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace, void (*filterfunc)(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace)) { struct _CamelMimeFilterPrivate *p; #ifdef MALLOC_CHECK checkmem(f->outreal); checkmem(f->backbuf); #endif /* here we take a performance hit, if the input buffer doesn't have the pre-space required. We make a buffer that does ... */ if (prespace < f->backlen) { int newlen = len+prespace+f->backlen; p = _PRIVATE(f); if (p->inlen < newlen) { /* NOTE: g_realloc copies data, we dont need that (slower) */ g_free(p->inbuf); p->inbuf = g_malloc(newlen+PRE_HEAD); p->inlen = newlen+PRE_HEAD; } /* copy to end of structure */ memcpy(p->inbuf+p->inlen - len, in, len); in = p->inbuf+p->inlen - len; prespace = p->inlen - len; } #ifdef MALLOC_CHECK checkmem(f->outreal); checkmem(f->backbuf); #endif /* preload any backed up data */ if (f->backlen > 0) { memcpy(in-f->backlen, f->backbuf, f->backlen); in -= f->backlen; len += f->backlen; prespace -= f->backlen; f->backlen = 0; } filterfunc(f, in, len, prespace, out, outlen, outprespace); #ifdef MALLOC_CHECK checkmem(f->outreal); checkmem(f->backbuf); #endif } void camel_mime_filter_filter(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace) { if (FCLASS(f)->filter) filter_run(f, in, len, prespace, out, outlen, outprespace, FCLASS(f)->filter); else g_error("Filter function unplmenented in class"); } void camel_mime_filter_complete(CamelMimeFilter *f, char *in, size_t len, size_t prespace, char **out, size_t *outlen, size_t *outprespace) { if (FCLASS(f)->complete) filter_run(f, in, len, prespace, out, outlen, outprespace, FCLASS(f)->complete); } void camel_mime_filter_reset(CamelMimeFilter *f) { if (FCLASS(f)->reset) { FCLASS(f)->reset(f); } /* could free some buffers, if they are really big? */ f->backlen = 0; } /* sets number of bytes backed up on the input, new calls replace previous ones */ void camel_mime_filter_backup(CamelMimeFilter *f, const char *data, size_t length) { if (f->backsize < length) { /* g_realloc copies data, unnecessary overhead */ g_free(f->backbuf); f->backbuf = g_malloc(length+BACK_HEAD); f->backsize = length+BACK_HEAD; } f->backlen = length; memcpy(f->backbuf, data, length); } /* ensure this much size available for filter output (if required) */ void camel_mime_filter_set_size(CamelMimeFilter *f, size_t size, int keep) { if (f->outsize < size) { int offset = f->outptr - f->outreal; if (keep) { f->outreal = g_realloc(f->outreal, size + PRE_HEAD*4); } else { g_free(f->outreal); f->outreal = g_malloc(size + PRE_HEAD*4); } f->outptr = f->outreal + offset; f->outbuf = f->outreal + PRE_HEAD*4; f->outsize = size; /* this could be offset from the end of the structure, but this should be good enough */ f->outpre = PRE_HEAD*4; } }