diff options
| author | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-09-14 16:17:15 +0200 | 
|---|---|---|
| committer | David Oberhollenzer <david.oberhollenzer@sigma-star.at> | 2020-09-16 09:34:35 +0200 | 
| commit | 5f637f97c3427dc6e1a68678aefee1f62ca34d62 (patch) | |
| tree | 75254191b93adce81e188069d54de383c0123984 /lib/fstream/compress | |
| parent | 0a0cbefc6ebb6174aad3e6f0b8a6dea87aed49da (diff) | |
Implement ostream compressor wrapper
Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
Diffstat (limited to 'lib/fstream/compress')
| -rw-r--r-- | lib/fstream/compress/gzip.c | 81 | ||||
| -rw-r--r-- | lib/fstream/compress/ostream_compressor.c | 98 | ||||
| -rw-r--r-- | lib/fstream/compress/xz.c | 80 | 
3 files changed, 259 insertions, 0 deletions
diff --git a/lib/fstream/compress/gzip.c b/lib/fstream/compress/gzip.c new file mode 100644 index 0000000..f604b71 --- /dev/null +++ b/lib/fstream/compress/gzip.c @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * gzip.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "../internal.h" + +#include <zlib.h> + +typedef struct { +	ostream_comp_t base; + +	z_stream strm; +} ostream_gzip_t; + +static int flush_inbuf(ostream_comp_t *base, bool finish) +{ +	ostream_gzip_t *gzip = (ostream_gzip_t *)base; +	size_t have; +	int ret; + +	gzip->strm.avail_in = base->inbuf_used; +	gzip->strm.next_in = base->inbuf; + +	do { +		gzip->strm.avail_out = BUFSZ; +		gzip->strm.next_out = base->outbuf; + +		ret = deflate(&gzip->strm, finish ? Z_FINISH : Z_NO_FLUSH); + +		if (ret == Z_STREAM_ERROR) { +			fprintf(stderr, +				"%s: internal error in gzip compressor.\n", +				base->wrapped->get_filename(base->wrapped)); +			return -1; +		} + +		have = BUFSZ - gzip->strm.avail_out; + +		if (base->wrapped->append(base->wrapped, base->outbuf, have)) +			return -1; +	} while (gzip->strm.avail_out == 0); + +	base->inbuf_used = 0; +	return 0; +} + +static void cleanup(ostream_comp_t *base) +{ +	ostream_gzip_t *gzip = (ostream_gzip_t *)base; + +	deflateEnd(&gzip->strm); +} + +ostream_comp_t *ostream_gzip_create(const char *filename) +{ +	ostream_gzip_t *gzip = calloc(1, sizeof(*gzip)); +	ostream_comp_t *base = (ostream_comp_t *)gzip; +	int ret; + +	if (gzip == NULL) { +		fprintf(stderr, "%s: creating gzip wrapper: %s.\n", +			filename, strerror(errno)); +		return NULL; +	} + +	ret = deflateInit2(&gzip->strm, 9, Z_DEFLATED, 16 + 15, 8, +			   Z_DEFAULT_STRATEGY); +	if (ret != Z_OK) { +		fprintf(stderr, +			"%s: internal error creating gzip compressor.\n", +			filename); +		free(gzip); +		return NULL; +	} + +	base->flush_inbuf = flush_inbuf; +	base->cleanup = cleanup; +	return base; +} diff --git a/lib/fstream/compress/ostream_compressor.c b/lib/fstream/compress/ostream_compressor.c new file mode 100644 index 0000000..5137f1d --- /dev/null +++ b/lib/fstream/compress/ostream_compressor.c @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * ostream_compressor.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "../internal.h" + +static int comp_append(ostream_t *strm, const void *data, size_t size) +{ +	ostream_comp_t *comp = (ostream_comp_t *)strm; +	size_t diff; + +	while (size > 0) { +		if (comp->inbuf_used >= BUFSZ) { +			if (comp->flush_inbuf(comp, false)) +				return -1; +		} + +		diff = BUFSZ - comp->inbuf_used; + +		if (diff > size) +			diff = size; + +		memcpy(comp->inbuf + comp->inbuf_used, data, diff); + +		comp->inbuf_used += diff; +		data = (const char *)data + diff; +		size -= diff; +	} + +	return 0; +} + +static int comp_flush(ostream_t *strm) +{ +	ostream_comp_t *comp = (ostream_comp_t *)strm; + +	if (comp->inbuf_used > 0) { +		if (comp->flush_inbuf(comp, true)) +			return -1; +	} + +	return comp->wrapped->flush(comp->wrapped); +} + +static const char *comp_get_filename(ostream_t *strm) +{ +	ostream_comp_t *comp = (ostream_comp_t *)strm; + +	return comp->wrapped->get_filename(comp->wrapped); +} + +static void comp_destroy(sqfs_object_t *obj) +{ +	ostream_comp_t *comp = (ostream_comp_t *)obj; + +	comp->cleanup(comp); +	sqfs_destroy(comp->wrapped); +	free(comp); +} + +ostream_t *ostream_compressor_create(ostream_t *strm, int comp_id) +{ +	ostream_comp_t *comp = NULL; +	sqfs_object_t *obj; +	ostream_t *base; + +	switch (comp_id) { +	case FSTREAM_COMPRESSOR_GZIP: +#ifdef WITH_GZIP +		comp = ostream_gzip_create(strm->get_filename(strm)); +#endif +		break; +	case FSTREAM_COMPRESSOR_XZ: +#ifdef WITH_XZ +		comp = ostream_xz_create(strm->get_filename(strm)); +#endif +		break; +	default: +		break; +	} + +	if (comp == NULL) +		return NULL; + +	comp->wrapped = strm; +	comp->inbuf_used = 0; + +	base = (ostream_t *)comp; +	base->append = comp_append; +	base->flush = comp_flush; +	base->get_filename = comp_get_filename; + +	obj = (sqfs_object_t *)comp; +	obj->destroy = comp_destroy; +	return base; +} diff --git a/lib/fstream/compress/xz.c b/lib/fstream/compress/xz.c new file mode 100644 index 0000000..65bda0b --- /dev/null +++ b/lib/fstream/compress/xz.c @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * xz.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "../internal.h" + +#include <lzma.h> + +typedef struct { +	ostream_comp_t base; + +	lzma_stream strm; +} ostream_xz_t; + +static int flush_inbuf(ostream_comp_t *base, bool finish) +{ +	ostream_xz_t *xz = (ostream_xz_t *)base; +	lzma_ret ret_xz; +	size_t have; + +	xz->strm.next_in = base->inbuf; +	xz->strm.avail_in = base->inbuf_used; + +	do { +		xz->strm.next_out = base->outbuf; +		xz->strm.avail_out = BUFSZ; + +		ret_xz = lzma_code(&xz->strm, finish ? LZMA_FINISH : LZMA_RUN); + +		if ((ret_xz != LZMA_OK) && (ret_xz != LZMA_STREAM_END)) { +			fprintf(stderr, +				"%s: internal error in XZ compressor.\n", +				base->wrapped->get_filename(base->wrapped)); +			return -1; +		} + +		have = BUFSZ - xz->strm.avail_out; + +		if (base->wrapped->append(base->wrapped, base->outbuf, have)) +			return -1; +	} while (xz->strm.avail_out == 0); + +	base->inbuf_used = 0; +	return 0; +} + +static void cleanup(ostream_comp_t *base) +{ +	ostream_xz_t *xz = (ostream_xz_t *)base; + +	lzma_end(&xz->strm); +} + +ostream_comp_t *ostream_xz_create(const char *filename) +{ +	ostream_xz_t *xz = calloc(1, sizeof(*xz)); +	ostream_comp_t *base = (ostream_comp_t *)xz; +	lzma_ret ret_xz; + +	if (xz == NULL) { +		fprintf(stderr, "%s: creating xz wrapper: %s.\n", +			filename, strerror(errno)); +		return NULL; +	} + +	ret_xz = lzma_easy_encoder(&xz->strm, LZMA_PRESET_DEFAULT, +				   LZMA_CHECK_CRC64); +	if (ret_xz != LZMA_OK) { +		fprintf(stderr, "%s: error initializing XZ compressor\n", +			filename); +		free(xz); +		return NULL; +	} + +	base->flush_inbuf = flush_inbuf; +	base->cleanup = cleanup; +	return base; +}  | 
