From 83776c115c013f78496ccc0d82f10e24c53e9430 Mon Sep 17 00:00:00 2001 From: chris mikkelson Date: Wed, 28 Jan 2009 21:53:02 -0600 Subject: [PATCH] Added code to split multipart media into parts. At a boundary, data is flushed downstream, the downstream processors are terminated, and if more parts are expected, a new downstream processor is started. Downstream processor is the "part" type, which looks for headers to decide content type / encoding. --- multipart.c | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 multipart.c diff --git a/multipart.c b/multipart.c new file mode 100644 index 0000000..ac5a984 --- /dev/null +++ b/multipart.c @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2009 Christopher L. Mikkelson + * All Rights Reserved, for now. + */ + +#include +#include "msgproc.h" + +/* needs to be published for other callers */ +#define MULTIPART_BOUNDARY 1 + +struct multipart_state { + char *boundary; + int blen; + char *line; + int l; + int state; +}; + +static void +multipart_start(msgproc *m) +{ + struct multipart_state *mps = malloc(sizeof(struct multipart_state)); + if (mps) { + bzero(mps, sizeof(*mps)); + } + msgproc_setpriv(m, (void*)mps); +} + +static void +setboundary(msgproc *m, int type, void *data, size_t size) +{ + struct multipart_state *mps = msgproc_getpriv(m); + if (type != MULTIPART_BOUNDARY) return; + if (mps) { + mps->boundary = malloc(size + 2); + if (!mps->boundary) return; + mps->boundary[0] = mps->boundary[1] = '-'; + memcpy(mps->boundary + 2, data, size); + mps->blen = size + 2; + } +} + +#define STATE_INMATCH 0 +#define STATE_MATCH 1 +#define STATE_MATCHEOL 2 +#define STATE_NOMATCH 3 +#define STATE_NOMATCHEOL 4 +#define STATE_MATCHEND 5 +#define STATE_DONE 6 + +static void +multipart_process(msgproc *m, char *buf, size_t len) +{ + struct multipart_state *mps = msgproc_getpriv(m); + msgproc *next; + char *s, *t; + int r, n; + + /* r = number of characters in current line which match + boundary and resided in previous buffer. + + n = number of characters in current line which match + boundary and reside in current buffer. + + mps->l = number of characters in boundary matched by + current line (regardless of which buffer(s)). + + s = current character in buffer. + + t = beginning of current part in current buffer. + */ + + if (!mps) return; + if (mps->state == STATE_DONE) return; + if (!mps->boundary) return; + r = mps->l; + next = msgproc_next(m); + + for (s = t = buf; s < buf + len; s++) { + + switch (mps->state) { + case STATE_INMATCH: + if (mps->boundary[mps->l++] != *s) { + mps->state = STATE_NOMATCH; + n = mps->l = 0; + continue; + } + n++; + if (mps->l < mps->blen) continue; + mps->state = STATE_MATCH; + if (*s == '\r') mps->state = STATE_MATCHEOL; + if (*s == '-') mps->state = STATE_MATCHEND; + continue; + case STATE_MATCH: + if (*s == '\r') mps->state = STATE_MATCHEOL; + continue; + case STATE_NOMATCH: + if (*s == '\r') mps->state = STATE_NOMATCHEOL; + continue; + case STATE_MATCHEOL: + if (*s == '\n') { + mps->state = STATE_INMATCH; + n = mps->l; + mps->l = 0; + break; + } + mps->state = STATE_MATCH; + continue; + case STATE_NOMATCHEOL: + if (*s == '\n') mps->state = STATE_INMATCH; + mps->state = STATE_NOMATCH; + continue;; + case STATE_MATCHEND: + if (*s != '-') { + mps->state = STATE_MATCH; + continue; + } + mps->state = STATE_DONE; + n = mps->l; + mps->l = 0; + break; + case STATE_DONE: + t=s; + continue; + } + + /* "break" above lands down here, continue skips to next char */ + /* send stuff downstream. (including a chunk of + boundary if partial match happened at end + of previous segment) */ + if (r) { + msgproc_process(next, mps->boundary, r); + r = 0; + } + msgproc_process(next, t, s - t - n); + n = 0; + + if (mps->state == STATE_DONE) return; + } + + /* reached end of buffer. Process what we have. */ + msgproc_process(next, t, s - t - n); +} + +void +multipart_finish(msgproc *m) +{ + struct multipart_state *mps = msgproc_getpriv(m); + if (mps) { + free(mps->boundary); + } + free(mps); + msgproc_free(m); +} + +msgproc_module msgproc_multipart = { + MSGPROC_MULTIPART, /* type */ + NULL, /* module init */ + setboundary, /* set module parameter */ + multipart_start, /* start module instance */ + NULL, /* set module instance parameter */ + multipart_process, /* process data */ + multipart_finish, /* shut down, free module instance */ + NULL /* shut down, free module */ +}; -- 2.50.1