From 183cf393a453cddb689666ce7fb35a97e7f523bf Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Tue, 15 Sep 2020 21:13:56 +0200 Subject: Add bzip2 stream compression support Signed-off-by: David Oberhollenzer --- lib/fstream/Makemodule.am | 6 ++ lib/fstream/compress/bzip2.c | 87 +++++++++++++++++++++++++++++ lib/fstream/compress/ostream_compressor.c | 5 ++ lib/fstream/compressor.c | 10 ++++ lib/fstream/internal.h | 4 ++ lib/fstream/uncompress/autodetect.c | 1 + lib/fstream/uncompress/bzip2.c | 87 +++++++++++++++++++++++++++++ lib/fstream/uncompress/istream_compressor.c | 5 ++ 8 files changed, 205 insertions(+) create mode 100644 lib/fstream/compress/bzip2.c create mode 100644 lib/fstream/uncompress/bzip2.c (limited to 'lib/fstream') diff --git a/lib/fstream/Makemodule.am b/lib/fstream/Makemodule.am index 8a1254c..1834cb8 100644 --- a/lib/fstream/Makemodule.am +++ b/lib/fstream/Makemodule.am @@ -35,4 +35,10 @@ libfstream_a_SOURCES += lib/fstream/uncompress/zstd.c libfstream_a_CPPFLAGS += -DWITH_ZSTD endif +if WITH_BZIP2 +libfstream_a_SOURCES += lib/fstream/compress/bzip2.c +libfstream_a_SOURCES += lib/fstream/uncompress/bzip2.c +libfstream_a_CPPFLAGS += -DWITH_BZIP2 +endif + noinst_LIBRARIES += libfstream.a diff --git a/lib/fstream/compress/bzip2.c b/lib/fstream/compress/bzip2.c new file mode 100644 index 0000000..3ca425a --- /dev/null +++ b/lib/fstream/compress/bzip2.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bzip2.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "../internal.h" + +#include + +typedef struct { + ostream_comp_t base; + + bz_stream strm; +} ostream_bzip2_t; + +static int flush_inbuf(ostream_comp_t *base, bool finish) +{ + ostream_bzip2_t *bzip2 = (ostream_bzip2_t *)base; + size_t have; + int ret; + + bzip2->strm.next_in = (char *)base->inbuf; + bzip2->strm.avail_in = base->inbuf_used; + + for (;;) { + bzip2->strm.next_out = (char *)base->outbuf; + bzip2->strm.avail_out = sizeof(base->outbuf); + + ret = BZ2_bzCompress(&bzip2->strm, finish ? BZ_FINISH : BZ_RUN); + + if (ret < 0 && ret != BZ_OUTBUFF_FULL) { + fprintf(stderr, "%s: internal error in bzip2 " + "compressor.\n", + base->wrapped->get_filename(base->wrapped)); + return -1; + } + + have = sizeof(base->outbuf) - bzip2->strm.avail_out; + + if (base->wrapped->append(base->wrapped, base->outbuf, have)) + return -1; + + if (ret == BZ_STREAM_END || ret == BZ_OUTBUFF_FULL || + bzip2->strm.avail_in == 0) { + break; + } + } + + if (bzip2->strm.avail_in > 0) { + memmove(base->inbuf, bzip2->strm.next_in, + bzip2->strm.avail_in); + } + + base->inbuf_used = bzip2->strm.avail_in; + return 0; +} + +static void cleanup(ostream_comp_t *base) +{ + ostream_bzip2_t *bzip2 = (ostream_bzip2_t *)base; + + BZ2_bzCompressEnd(&bzip2->strm); +} + +ostream_comp_t *ostream_bzip2_create(const char *filename) +{ + ostream_bzip2_t *bzip2 = calloc(1, sizeof(*bzip2)); + ostream_comp_t *base = (ostream_comp_t *)bzip2; + + if (bzip2 == NULL) { + fprintf(stderr, "%s: creating bzip2 compressor: %s.\n", + filename, strerror(errno)); + return NULL; + } + + if (BZ2_bzCompressInit(&bzip2->strm, 9, 0, 30) != BZ_OK) { + fprintf(stderr, "%s: error initializing bzip2 compressor.\n", + filename); + free(bzip2); + 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 index d1d55e1..7ea7919 100644 --- a/lib/fstream/compress/ostream_compressor.c +++ b/lib/fstream/compress/ostream_compressor.c @@ -80,6 +80,11 @@ ostream_t *ostream_compressor_create(ostream_t *strm, int comp_id) case FSTREAM_COMPRESSOR_ZSTD: #ifdef WITH_ZSTD comp = ostream_zstd_create(strm->get_filename(strm)); +#endif + break; + case FSTREAM_COMPRESSOR_BZIP2: +#ifdef WITH_BZIP2 + comp = ostream_bzip2_create(strm->get_filename(strm)); #endif break; default: diff --git a/lib/fstream/compressor.c b/lib/fstream/compressor.c index 84a859c..903a5f7 100644 --- a/lib/fstream/compressor.c +++ b/lib/fstream/compressor.c @@ -17,6 +17,9 @@ int fstream_compressor_id_from_name(const char *name) if (strcmp(name, "zstd") == 0) return FSTREAM_COMPRESSOR_ZSTD; + if (strcmp(name, "bzip2") == 0) + return FSTREAM_COMPRESSOR_BZIP2; + return -1; } @@ -31,6 +34,9 @@ const char *fstream_compressor_name_from_id(int id) if (id == FSTREAM_COMPRESSOR_ZSTD) return "zstd"; + if (id == FSTREAM_COMPRESSOR_BZIP2) + return "bzip2"; + return NULL; } @@ -48,6 +54,10 @@ bool fstream_compressor_exists(int id) #ifdef WITH_ZSTD case FSTREAM_COMPRESSOR_ZSTD: return true; +#endif +#ifdef WITH_BZIP2 + case FSTREAM_COMPRESSOR_BZIP2: + return true; #endif default: break; diff --git a/lib/fstream/internal.h b/lib/fstream/internal.h index 83ecc64..2dc81e4 100644 --- a/lib/fstream/internal.h +++ b/lib/fstream/internal.h @@ -59,12 +59,16 @@ SQFS_INTERNAL ostream_comp_t *ostream_xz_create(const char *filename); SQFS_INTERNAL ostream_comp_t *ostream_zstd_create(const char *filename); +SQFS_INTERNAL ostream_comp_t *ostream_bzip2_create(const char *filename); + SQFS_INTERNAL istream_comp_t *istream_gzip_create(const char *filename); SQFS_INTERNAL istream_comp_t *istream_xz_create(const char *filename); SQFS_INTERNAL istream_comp_t *istream_zstd_create(const char *filename); +SQFS_INTERNAL istream_comp_t *istream_bzip2_create(const char *filename); + #ifdef __cplusplus } #endif diff --git a/lib/fstream/uncompress/autodetect.c b/lib/fstream/uncompress/autodetect.c index b788518..61628f8 100644 --- a/lib/fstream/uncompress/autodetect.c +++ b/lib/fstream/uncompress/autodetect.c @@ -14,6 +14,7 @@ static const struct { { FSTREAM_COMPRESSOR_GZIP, (const sqfs_u8 *)"\x1F\x8B\x08", 3 }, { FSTREAM_COMPRESSOR_XZ, (const sqfs_u8 *)("\xFD" "7zXZ"), 6 }, { FSTREAM_COMPRESSOR_ZSTD, (const sqfs_u8 *)"\x28\xB5\x2F\xFD", 4 }, + { FSTREAM_COMPRESSOR_BZIP2, (const sqfs_u8 *)"BZh", 3 }, }; int istream_detect_compressor(istream_t *strm, diff --git a/lib/fstream/uncompress/bzip2.c b/lib/fstream/uncompress/bzip2.c new file mode 100644 index 0000000..b5fae5c --- /dev/null +++ b/lib/fstream/uncompress/bzip2.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * bzip2.c + * + * Copyright (C) 2019 David Oberhollenzer + */ +#include "../internal.h" + +#include + +typedef struct { + istream_comp_t base; + + bz_stream strm; +} istream_bzip2_t; + +static int precache(istream_t *base) +{ + istream_bzip2_t *bzip2 = (istream_bzip2_t *)base; + istream_t *wrapped = ((istream_comp_t *)base)->wrapped; + int ret; + + for (;;) { + ret = istream_precache(wrapped); + if (ret != 0) + return ret; + + bzip2->strm.next_in = (char *)wrapped->buffer; + bzip2->strm.avail_in = wrapped->buffer_used; + + bzip2->strm.next_out = (char *)base->buffer + base->buffer_used; + bzip2->strm.avail_out = BUFSZ - base->buffer_used; + + if (bzip2->strm.avail_out < 1) + break; + + ret = BZ2_bzDecompress(&bzip2->strm); + + if (ret < 0) { + fprintf(stderr, "%s: internal error in bzip2 " + "decompressor.\n", + wrapped->get_filename(wrapped)); + return -1; + } + + base->buffer_used = BUFSZ - bzip2->strm.avail_out; + wrapped->buffer_offset = wrapped->buffer_used - + bzip2->strm.avail_in; + + if (ret == BZ_STREAM_END) { + base->eof = true; + break; + } + } + + return 0; +} + +static void cleanup(istream_comp_t *base) +{ + istream_bzip2_t *bzip2 = (istream_bzip2_t *)base; + + BZ2_bzDecompressEnd(&bzip2->strm); +} + +istream_comp_t *istream_bzip2_create(const char *filename) +{ + istream_bzip2_t *bzip2 = calloc(1, sizeof(*bzip2)); + istream_comp_t *base = (istream_comp_t *)bzip2; + + if (bzip2 == NULL) { + fprintf(stderr, "%s: creating bzip2 compressor: %s.\n", + filename, strerror(errno)); + return NULL; + } + + if (BZ2_bzDecompressInit(&bzip2->strm, 0, 0) != BZ_OK) { + fprintf(stderr, "%s: error initializing bzip2 decompressor.\n", + filename); + free(bzip2); + return NULL; + } + + ((istream_t *)base)->precache = precache; + base->cleanup = cleanup; + return base; +} diff --git a/lib/fstream/uncompress/istream_compressor.c b/lib/fstream/uncompress/istream_compressor.c index 2262c9b..bc8ef39 100644 --- a/lib/fstream/uncompress/istream_compressor.c +++ b/lib/fstream/uncompress/istream_compressor.c @@ -42,6 +42,11 @@ istream_t *istream_compressor_create(istream_t *strm, int comp_id) case FSTREAM_COMPRESSOR_ZSTD: #ifdef WITH_ZSTD comp = istream_zstd_create(strm->get_filename(strm)); +#endif + break; + case FSTREAM_COMPRESSOR_BZIP2: +#ifdef WITH_BZIP2 + comp = istream_bzip2_create(strm->get_filename(strm)); #endif break; default: -- cgit v1.2.3