From 551dd3879c288a2b6b6fbaca5c09c04fbe994ff4 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Tue, 13 Dec 2022 09:15:19 +0100 Subject: Split stream compression out of libio Move it to a separate libxfrm library, where it can be independently tested as well. The bulk of the new code is also mainly test cases for the compressors. Signed-off-by: David Oberhollenzer --- lib/xfrm/bzip2.c | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 lib/xfrm/bzip2.c (limited to 'lib/xfrm/bzip2.c') diff --git a/lib/xfrm/bzip2.c b/lib/xfrm/bzip2.c new file mode 100644 index 0000000..7e5807d --- /dev/null +++ b/lib/xfrm/bzip2.c @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bzip2.c + * + * Copyright (C) 2021 David Oberhollenzer + */ +#include +#include +#include + +#include "xfrm/stream.h" +#include "xfrm/compress.h" + +typedef struct { + xfrm_stream_t base; + + bz_stream strm; + bool compress; + bool initialized; + + int level; + int work_factor; +} xfrm_stream_bzip2_t; + +static const int bzlib_action[] = { + [XFRM_STREAM_FLUSH_NONE] = BZ_RUN, + [XFRM_STREAM_FLUSH_SYNC] = BZ_FLUSH, + [XFRM_STREAM_FLUSH_FULL] = BZ_FINISH, +}; + +static int process_data(xfrm_stream_t *stream, const void *in, sqfs_u32 in_size, + void *out, sqfs_u32 out_size, + sqfs_u32 *in_read, sqfs_u32 *out_written, + int flush_mode) +{ + xfrm_stream_bzip2_t *bzip2 = (xfrm_stream_bzip2_t *)stream; + sqfs_u32 diff; + int ret; + + if (!bzip2->initialized) { + if (bzip2->compress) { + ret = BZ2_bzCompressInit(&bzip2->strm, bzip2->level, 0, + bzip2->work_factor); + } else { + ret = BZ2_bzDecompressInit(&bzip2->strm, 0, 0); + } + + if (ret != BZ_OK) + return XFRM_STREAM_ERROR; + + bzip2->initialized = true; + } + + if (flush_mode < 0 || flush_mode >= XFRM_STREAM_FLUSH_COUNT) + flush_mode = XFRM_STREAM_FLUSH_NONE; + + while (in_size > 0 && out_size > 0) { + bzip2->strm.next_in = (char *)in; + bzip2->strm.avail_in = in_size; + + bzip2->strm.next_out = (char *)out; + bzip2->strm.avail_out = out_size; + + if (bzip2->compress) { + ret = BZ2_bzCompress(&bzip2->strm, + bzlib_action[flush_mode]); + } else { + ret = BZ2_bzDecompress(&bzip2->strm); + } + + if (ret == BZ_OUTBUFF_FULL) + return XFRM_STREAM_BUFFER_FULL; + + if (ret < 0) + return XFRM_STREAM_ERROR; + + diff = (in_size - bzip2->strm.avail_in); + in = (const char *)in + diff; + in_size -= diff; + *in_read += diff; + + diff = (out_size - bzip2->strm.avail_out); + out = (char *)out + diff; + out_size -= diff; + *out_written += diff; + + if (ret == BZ_STREAM_END) { + if (bzip2->compress) { + BZ2_bzCompressEnd(&bzip2->strm); + } else { + BZ2_bzDecompressEnd(&bzip2->strm); + } + + bzip2->initialized = false; + return XFRM_STREAM_END; + } + } + + return XFRM_STREAM_OK; +} + +static void destroy(sqfs_object_t *obj) +{ + xfrm_stream_bzip2_t *bzip2 = (xfrm_stream_bzip2_t *)obj; + + if (bzip2->initialized) { + if (bzip2->compress) { + BZ2_bzCompressEnd(&bzip2->strm); + } else { + BZ2_bzDecompressEnd(&bzip2->strm); + } + } + + free(bzip2); +} + +static xfrm_stream_t *stream_create(const compressor_config_t *cfg, + bool compress) +{ + xfrm_stream_bzip2_t *bzip2 = calloc(1, sizeof(*bzip2)); + xfrm_stream_t *xfrm = (xfrm_stream_t *)bzip2; + + if (bzip2 == NULL) { + perror("creating bzip2 stream compressor"); + return NULL; + } + + if (cfg == NULL) { + bzip2->level = COMP_BZIP2_DEFAULT_LEVEL; + bzip2->work_factor = COMP_BZIP2_DEFAULT_WORK_FACTOR; + } else { + bzip2->level = cfg->level; + bzip2->work_factor = cfg->opt.bzip2.work_factor; + } + + bzip2->initialized = false; + bzip2->compress = compress; + xfrm->process_data = process_data; + sqfs_object_init(bzip2, destroy, NULL); + return xfrm; +} + +xfrm_stream_t *compressor_stream_bzip2_create(const compressor_config_t *cfg) +{ + return stream_create(cfg, true); +} + +xfrm_stream_t *decompressor_stream_bzip2_create(void) +{ + return stream_create(NULL, false); +} -- cgit v1.2.3