add deflate_istream
This commit is contained in:
parent
7f4b074d70
commit
9389d63a5f
101
src/io/deflate_istream.hpp
Normal file
101
src/io/deflate_istream.hpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define ZLIB_CONST
|
||||||
|
#include <zlib.h>
|
||||||
|
#include <istream>
|
||||||
|
#include <memory>
|
||||||
|
#include <array>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
class deflate_istream : public std::istream {
|
||||||
|
public:
|
||||||
|
explicit deflate_istream(std::unique_ptr<std::istream> src)
|
||||||
|
: std::istream(&buf), source(std::move(src)), buf(*source) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class deflate_streambuf : public std::streambuf {
|
||||||
|
public:
|
||||||
|
explicit deflate_streambuf(std::istream& src) : src(src) {
|
||||||
|
zstream.zalloc = Z_NULL;
|
||||||
|
zstream.zfree = Z_NULL;
|
||||||
|
zstream.opaque = Z_NULL;
|
||||||
|
zstream.avail_in = 0;
|
||||||
|
zstream.next_in = Z_NULL;
|
||||||
|
|
||||||
|
int ret = inflateInit2(&zstream, -15);
|
||||||
|
if (ret != Z_OK) {
|
||||||
|
throw std::runtime_error("zlib init failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~deflate_streambuf() {
|
||||||
|
inflateEnd(&zstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
deflate_streambuf(const deflate_streambuf&) = delete;
|
||||||
|
deflate_streambuf& operator=(const deflate_streambuf&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int_type underflow() override {
|
||||||
|
if (gptr() < egptr()) {
|
||||||
|
return traits_type::to_int_type(*gptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eof) {
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
zstream.next_out = reinterpret_cast<Bytef*>(outBuf.data());
|
||||||
|
zstream.avail_out = outBuf.size();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (zstream.avail_in == 0) {
|
||||||
|
src.read(inBuf.data(), inBuf.size());
|
||||||
|
zstream.avail_in = static_cast<uInt>(src.gcount());
|
||||||
|
zstream.next_in = reinterpret_cast<Bytef*>(inBuf.data());
|
||||||
|
|
||||||
|
if (src.bad()) {
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = inflate(&zstream, Z_NO_FLUSH);
|
||||||
|
if (ret == Z_STREAM_END) {
|
||||||
|
eof = true;
|
||||||
|
} else if (ret != Z_OK) {
|
||||||
|
if (ret == Z_BUF_ERROR && zstream.avail_out == outBuf.size()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto decompressed = outBuf.size() - zstream.avail_out;
|
||||||
|
if (decompressed > 0) {
|
||||||
|
setg(outBuf.data(),
|
||||||
|
outBuf.data(),
|
||||||
|
outBuf.data() + decompressed);
|
||||||
|
return traits_type::to_int_type(*gptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eof) {
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (zstream.avail_in > 0 || !src.eof());
|
||||||
|
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t BUFFER_SIZE = 16384;
|
||||||
|
|
||||||
|
std::istream& src;
|
||||||
|
z_stream zstream {};
|
||||||
|
std::array<char, BUFFER_SIZE> inBuf {};
|
||||||
|
std::array<char, BUFFER_SIZE> outBuf {};
|
||||||
|
bool eof = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<std::istream> source;
|
||||||
|
deflate_streambuf buf;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user