]> git.mikk.net Git - liburl/commitdiff
Added code to split multipart media into parts. At a boundary, data
authorchris mikkelson <chris@mikk.net>
Thu, 29 Jan 2009 03:53:02 +0000 (21:53 -0600)
committerchris mikkelson <chris@mikk.net>
Thu, 5 Feb 2009 19:14:30 +0000 (13:14 -0600)
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 [new file with mode: 0644]

diff --git a/multipart.c b/multipart.c
new file mode 100644 (file)
index 0000000..ac5a984
--- /dev/null
@@ -0,0 +1,166 @@
+/* 
+ * Copyright (c) 2009  Christopher L. Mikkelson <chris@mikk.net>
+ * All Rights Reserved, for now.
+ */
+
+#include <string.h>
+#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 */
+};