#include #include #include #include "al.h" #include "sio.h" #include "sio_module.h" typedef struct { size_t outputsize; al_tx_t *outputtx; size_t inputsize; al_t *input, *output; } private_t; /* * create stage * * allocate private instance data */ static sio_rc_t buffer_init(sio_t *sio, void **u) { private_t *mydata; mydata = (private_t *)malloc(sizeof(private_t)); if (mydata == NULL) return SIO_ERR_MEM; mydata->inputsize = 0; mydata->outputsize = 0; *u = mydata; return SIO_OK; } /* * configure stage * * pass two void pointers */ static sio_rc_t buffer_configure(sio_t *sio, void *u, void *obj, void *val) { private_t *mydata = (private_t *)u; const char *name = (const char *)obj; if (!strcmp(name, "inputsize")) { mydata->inputsize = *(size_t *)val; } else if (!strcmp(name, "outputsize")) { mydata->outputsize = *(size_t *)val; } else { return SIO_ERR_ARG; } return SIO_OK; } /* * destroy stage */ static sio_rc_t buffer_cleanup(sio_t *sio, void *u) { private_t *mydata = (private_t *)u; free(mydata); return SIO_OK; } static sio_rc_t buffer_openr(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; al_rc_t arc; arc = al_create(&mydata->input); if (arc != AL_OK) return SIO_ERR_INT; return SIO_OK; } static sio_rc_t buffer_closer(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; al_destroy(mydata->input); mydata->input = NULL; return SIO_OK; } static sio_rc_t buffer_openw(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; al_rc_t arc; arc = al_txalloc(al, &mydata->outputtx); if (arc != AL_OK) return SIO_ERR_INT; arc = al_create(&mydata->output); if (arc != AL_OK) { al_txfree(al, mydata->outputtx); return SIO_ERR_INT; } return SIO_OK; } static sio_rc_t buffer_closew(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; al_destroy(mydata->output); mydata->output = NULL; al_txfree(al, mydata->outputtx); mydata->outputtx = NULL; return SIO_OK; } static sio_rc_t buffer_inout(sio_t *sio, al_t *al, al_t *buf, size_t size, sio_rc_t up, sio_rc_t down) { size_t avail, data, needed; al_rc_t arc; al_label_t label; arc = al_splice(buf, al_bytes(buf), 0, al, NULL); if (arc != AL_OK) return SIO_ERR_INT; avail = al_bytes(buf); if (avail <= 0) return down; arc = al_firstlabel(buf, 0, 1, AL_FORWARD, NULL, &label); if (arc != AL_OK) return SIO_ERR_INT; al_flatten(buf, 0, avail, AL_FORWARD_SPAN, label, NULL, &data); needed = size; if (data < avail) needed = 1; if (data >= needed) { if (data >= size) data = size; al_splice(buf, 0, data, NULL, al); return up; } return down; } static sio_rc_t buffer_input(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; return buffer_inout(sio, al, mydata->input, mydata->inputsize, SIO_DOWNSTREAM, SIO_UPSTREAM); } static sio_rc_t buffer_output(sio_t *sio, al_t *al, void *u) { private_t *mydata = (private_t *)u; return buffer_inout(sio, al, mydata->output, mydata->outputsize, SIO_UPSTREAM, SIO_DOWNSTREAM); } sio_module_t sio_module_buffer = { "buffer", buffer_init, buffer_configure, buffer_cleanup, buffer_openr, buffer_closer, buffer_openw, buffer_closew, buffer_input, buffer_output };