diff options
Diffstat (limited to 'lib/fstream/uncompress')
-rw-r--r-- | lib/fstream/uncompress/autodetect.c | 1 | ||||
-rw-r--r-- | lib/fstream/uncompress/istream_compressor.c | 5 | ||||
-rw-r--r-- | lib/fstream/uncompress/zstd.c | 79 |
3 files changed, 85 insertions, 0 deletions
diff --git a/lib/fstream/uncompress/autodetect.c b/lib/fstream/uncompress/autodetect.c index 4ffe078..b788518 100644 --- a/lib/fstream/uncompress/autodetect.c +++ b/lib/fstream/uncompress/autodetect.c @@ -13,6 +13,7 @@ static const struct { } magic[] = { { 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 }, }; int istream_detect_compressor(istream_t *strm, diff --git a/lib/fstream/uncompress/istream_compressor.c b/lib/fstream/uncompress/istream_compressor.c index 924f309..2262c9b 100644 --- a/lib/fstream/uncompress/istream_compressor.c +++ b/lib/fstream/uncompress/istream_compressor.c @@ -39,6 +39,11 @@ istream_t *istream_compressor_create(istream_t *strm, int comp_id) comp = istream_xz_create(strm->get_filename(strm)); #endif break; + case FSTREAM_COMPRESSOR_ZSTD: +#ifdef WITH_ZSTD + comp = istream_zstd_create(strm->get_filename(strm)); +#endif + break; default: break; } diff --git a/lib/fstream/uncompress/zstd.c b/lib/fstream/uncompress/zstd.c new file mode 100644 index 0000000..1838af5 --- /dev/null +++ b/lib/fstream/uncompress/zstd.c @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * zstd.c + * + * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at> + */ +#include "../internal.h" + +#include <zstd.h> + +typedef struct { + istream_comp_t base; + + ZSTD_DStream* strm; +} istream_zstd_t; + +static int precache(istream_t *base) +{ + istream_zstd_t *zstd = (istream_zstd_t *)base; + istream_t *wrapped = ((istream_comp_t *)base)->wrapped; + ZSTD_outBuffer out; + ZSTD_inBuffer in; + size_t ret; + + if (istream_precache(wrapped)) + return -1; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + + in.src = wrapped->buffer; + in.size = wrapped->buffer_used; + + out.dst = ((istream_comp_t *)base)->uncompressed + base->buffer_used; + out.size = BUFSZ - base->buffer_used; + + ret = ZSTD_decompressStream(zstd->strm, &out, &in); + + if (ZSTD_isError(ret)) { + fprintf(stderr, "%s: error in zstd decoder.\n", + wrapped->get_filename(wrapped)); + return -1; + } + + wrapped->buffer_offset = in.pos; + base->buffer_used += out.pos; + return 0; +} + +static void cleanup(istream_comp_t *base) +{ + istream_zstd_t *zstd = (istream_zstd_t *)base; + + ZSTD_freeDStream(zstd->strm); +} + +istream_comp_t *istream_zstd_create(const char *filename) +{ + istream_zstd_t *zstd = calloc(1, sizeof(*zstd)); + istream_comp_t *base = (istream_comp_t *)zstd; + + if (zstd == NULL) { + fprintf(stderr, "%s: creating zstd decoder: %s.\n", + filename, strerror(errno)); + return NULL; + } + + zstd->strm = ZSTD_createDStream(); + if (zstd->strm == NULL) { + fprintf(stderr, "%s: error creating zstd decoder.\n", + filename); + free(zstd); + return NULL; + } + + ((istream_t *)base)->precache = precache; + base->cleanup = cleanup; + return base; +} |