Index: ossp-pkg/sio/sio_zlib.c RCS File: /v/ossp/cvs/ossp-pkg/sio/sio_zlib.c,v co -q -kk -p'1.1' '/v/ossp/cvs/ossp-pkg/sio/sio_zlib.c,v' | diff -u /dev/null - -L'ossp-pkg/sio/sio_zlib.c' 2>/dev/null --- ossp-pkg/sio/sio_zlib.c +++ - 2024-05-17 05:36:09.038206650 +0200 @@ -0,0 +1,324 @@ +#include +#include +#include + +#include "al.h" +#include "sio.h" + +#include + +typedef struct { + z_stream zs; + int lvl; + al_t *ibuf; + char *obuf; + size_t olen; + al_t *al; + void *u; +} data_t; + +typedef struct { + data_t input; + data_t output; + int inputlevel; + int outputlevel; + size_t inputsize; + size_t outputsize; + al_label_t data_label; +} private_t; + +/* + * create stage + * + * allocate private instance data + */ +static +sio_rc_t zlib_init(sio_t *sio, void **up) +{ + private_t *my; + + my = (private_t *)malloc(sizeof(private_t)); + if (my == NULL) + return SIO_ERR_MEM; + + my->inputsize = 0; + my->outputsize = 0; + my->inputlevel = 0; + my->outputlevel = 0; + + sio_label(sio, SIO_LN_DATA, &my->data_label); + + *up = my; + + return SIO_OK; +} + +/* + * configure stage + * + * pass two void pointers + */ +static +sio_rc_t zlib_configure(sio_t *sio, void *u, void *obj, void *val) +{ + private_t *my = (private_t *)u; + const char *name = (const char *)obj; + + if (!strcmp(name, "inputlevel")) { + my->inputlevel = *(int *)val; + } else if (!strcmp(name, "outputlevel")) { + my->outputlevel = *(int *)val; + } else if (!strcmp(name, "inputsize")) { + my->inputsize = *(size_t *)val; + } else if (!strcmp(name, "outputsize")) { + my->outputsize = *(size_t *)val; + } else { + return SIO_ERR_ARG; + } + + return SIO_OK; +} + +/* + * destroy stage + */ +static +sio_rc_t zlib_cleanup(sio_t *sio, void *u) +{ + private_t *my = (private_t *)u; + + free(my); + + return SIO_OK; +} + +static +int zlib_alloc_data(private_t *my, data_t *dt) +{ + al_rc_t arc; + int zrc; + + dt->u = (void *)my; + + if (dt->lvl >= 0) + zrc = deflateInit(&dt->zs, dt->lvl); + else + zrc = inflateInit(&dt->zs); + if (zrc != Z_OK) + return -1; + + arc = al_create(&dt->ibuf); + if (arc != AL_OK) + return -1; + + dt->obuf = malloc(dt->olen); + if (dt->obuf == NULL) { + al_destroy(dt->ibuf); + dt->ibuf = NULL; + return -1; + } + + return 0; +} + +static +void zlib_free_data(data_t *dt) +{ + al_destroy(dt->ibuf); + dt->ibuf = NULL; + + free(dt->obuf); + dt->obuf = NULL; + + if (dt->lvl >= 0) + deflateEnd(&dt->zs); + else + inflateEnd(&dt->zs); +} + +static +sio_rc_t zlib_openr(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + if (my->inputsize <= 0) + return SIO_ERR_ARG; + + my->input.lvl = my->inputlevel; + my->input.olen = my->inputsize; + my->input.al = al; + + if (zlib_alloc_data(my, &my->input)) + return SIO_ERR_INT; + + return SIO_OK; +} + +static +sio_rc_t zlib_closer(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + zlib_free_data(&my->input); + + return SIO_OK; +} + +static +sio_rc_t zlib_openw(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + if (my->outputsize <= 0) + return SIO_ERR_ARG; + + my->output.lvl = my->outputlevel; + my->output.olen = my->outputsize; + my->output.al = al; + + if (zlib_alloc_data(my, &my->output)) + return SIO_ERR_INT; + + return SIO_OK; +} + +static +sio_rc_t zlib_closew(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + if (my->output.lvl >= 0) + deflateEnd(&my->output.zs); + else + inflateEnd(&my->output.zs); + + free(my->output.obuf); + my->output.obuf = NULL; + + al_destroy(my->output.ibuf); + my->output.ibuf = NULL; + + return SIO_OK; +} + +/* + * buffer logic + * + * gather data from producer + * if buffer size reached or label changes then push data to consumer + * (read -> downstream, write -> upstream) + * + * buffer size depends on label type + * + */ +static +al_rc_t zlib_inout_cb(al_chunk_t *alcp, void *u) +{ + data_t *dt = (data_t *)u; + private_t *my = (private_t *)dt->u; + z_stream *zs = &dt->zs; + int level = dt->lvl; + int zrc, flush; + al_rc_t arc; + char *p; + size_t n; + + arc = AL_OK; + + p = al_chunk_ptr(alcp, 0); + n = al_chunk_len(alcp); + + if (al_same_label(alcp, my->data_label)) { + zs->next_in = p; + zs->avail_in = n; + flush = 0; + } else { + zs->next_in = ""; + zs->avail_in = 0; + flush = Z_FINISH; + } + + do { + if (zs->avail_out == 0) { + zs->next_out = dt->obuf; + zs->avail_out = dt->olen; + zs->total_out = 0; + } + if (level >= 0) + zrc = deflate(zs, flush); + else + zrc = inflate(zs, flush); + if (zrc != Z_OK && zrc != Z_STREAM_END) { + arc = AL_ERR_INT; + break; + } + if (zs->avail_out == 0 || zrc == Z_STREAM_END || flush) { + arc = al_append_bytes(dt->al, dt->obuf, zs->total_out, + my->data_label); + zs->avail_out = 0; + if (arc != AL_OK) + break; + } + } while (zs->avail_in > 0 || (zrc == Z_OK && zs->avail_out == 0)); + + if (arc != AL_OK) + return arc; + + if (flush) + arc = al_append_bytes(dt->al, p, n, al_chunk_label(alcp)); + + return arc; +} + +static +sio_rc_t zlib_inout(sio_t *sio, al_t *al, private_t *my, data_t *dt) +{ + al_rc_t arc; + + arc = al_splice(al, 0, al_bytes(al), NULL, dt->ibuf); + if (arc != AL_OK) + return SIO_ERR_INT; + + arc = al_traverse_cb(dt->ibuf, 0, al_bytes(dt->ibuf), + AL_FORWARD, NULL, + zlib_inout_cb, (void *)dt); + if (arc != AL_OK) + return SIO_ERR_INT; + + arc = al_splice(dt->ibuf, 0, al_bytes(dt->ibuf), NULL, NULL); + if (arc != AL_OK) + return SIO_ERR_INT; + + return SIO_OK; +} + +static +sio_rc_t zlib_input(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + return zlib_inout(sio, al, my, &my->input); +} + +static +sio_rc_t zlib_output(sio_t *sio, al_t *al, void *u) +{ + private_t *my = (private_t *)u; + + return zlib_inout(sio, al, my, &my->output); +} + +sio_module_t sio_module_zlib = { + "zlib", + zlib_init, + zlib_configure, + zlib_cleanup, + zlib_openr, + zlib_closer, + zlib_openw, + zlib_closew, + zlib_input, + zlib_output, + NULL +}; +