diff options
author | Tom Bereknyei <tom@rebelliondefense.com> | 2019-12-13 03:29:33 -0500 |
---|---|---|
committer | Tom Bereknyei <tom@rebelliondefense.com> | 2019-12-13 03:34:15 -0500 |
commit | c6295a3afd87a605f30f1de8b09d7885eb08fedb (patch) | |
tree | 17b611f1cdf0e6491cdc1c52b1046bdb614758bf /src/libutil/compression.cc | |
parent | f800d450b78091835ab7ca67847d76e75d877a24 (diff) |
Initial gzip support
Closes #3256
Diffstat (limited to 'src/libutil/compression.cc')
-rw-r--r-- | src/libutil/compression.cc | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/src/libutil/compression.cc b/src/libutil/compression.cc index 0dd84e320..17b506d5d 100644 --- a/src/libutil/compression.cc +++ b/src/libutil/compression.cc @@ -11,6 +11,8 @@ #include <brotli/decode.h> #include <brotli/encode.h> +#include <zlib.h> + #include <iostream> namespace nix { @@ -42,6 +44,66 @@ struct NoneSink : CompressionSink void write(const unsigned char * data, size_t len) override { nextSink(data, len); } }; +struct GzipDecompressionSink : CompressionSink +{ + Sink & nextSink; + z_stream strm; + bool finished = false; + uint8_t outbuf[BUFSIZ]; + + GzipDecompressionSink(Sink & nextSink) : nextSink(nextSink) + { + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = 0; + strm.next_in = Z_NULL; + strm.next_out = outbuf; + strm.avail_out = sizeof(outbuf); + + // Enable gzip and zlib decoding (+32) with 15 windowBits + int ret = inflateInit2(&strm,15+32); + if (ret != Z_OK) + throw CompressionError("unable to initialise gzip encoder"); + } + + ~GzipDecompressionSink() + { + inflateEnd(&strm); + } + + void finish() override + { + CompressionSink::flush(); + write(nullptr, 0); + } + + void write(const unsigned char * data, size_t len) override + { + assert(len <= std::numeric_limits<decltype(strm.avail_in)>::max()); + + strm.next_in = (Bytef *) data; + strm.avail_in = len; + + while (!finished && (!data || strm.avail_in)) { + checkInterrupt(); + + int ret = inflate(&strm,Z_SYNC_FLUSH); + if (ret != Z_OK && ret != Z_STREAM_END) + throw CompressionError("error while decompressing gzip file: %d: %d: %d",ret, len, strm.avail_in); + + + finished = ret == Z_STREAM_END; + + if (strm.avail_out < sizeof(outbuf) || strm.avail_in == 0) { + nextSink(outbuf, sizeof(outbuf) - strm.avail_out); + strm.next_out = (Bytef *) outbuf; + strm.avail_out = sizeof(outbuf); + } + } + } +}; + struct XzDecompressionSink : CompressionSink { Sink & nextSink; @@ -215,6 +277,8 @@ ref<CompressionSink> makeDecompressionSink(const std::string & method, Sink & ne return make_ref<XzDecompressionSink>(nextSink); else if (method == "bzip2") return make_ref<BzipDecompressionSink>(nextSink); + else if (method == "gzip") + return make_ref<GzipDecompressionSink>(nextSink); else if (method == "br") return make_ref<BrotliDecompressionSink>(nextSink); else |