5 #include "util/zlib_source.h" 8 #include "base/logging.h" 9 #include "strings/strcat.h" 13 inline Status ToStatus(
int err, StringPiece msg) {
16 return Status(StatusCode::IO_ERROR, StrCat(
"ZLib error ", err,
": ", msg));
19 static inline int internalInflateInit2(ZlibSource::Format format, z_stream* zcontext) {
20 int windowBitsFormat = 0;
22 case ZlibSource::GZIP:
23 windowBitsFormat = 16;
25 case ZlibSource::AUTO:
26 windowBitsFormat = 32;
28 case ZlibSource::ZLIB:
32 return inflateInit2(zcontext, 15 | windowBitsFormat);
35 static inline void InitCtx(z_stream* zcontext) {
36 memset(zcontext, 0,
sizeof(z_stream));
39 bool ZlibSource::IsZlibSource(Source* source) {
40 std::array<unsigned char, 2> buf;
41 auto res = source->Read(strings::MutableByteRange(buf));
45 bool is_zlib = res.obj == 2 && (buf[0] == 0x1f) && (buf[1] == 0x8b);
46 source->Prepend(strings::ByteRange(buf));
51 static constexpr
size_t kBufSize = 8192;
53 ZlibSource::ZlibSource(Source* sub_stream, Format format)
54 : sub_stream_(sub_stream), format_(format) {
56 buf_.reset(
new uint8_t[kBufSize]);
59 ZlibSource::~ZlibSource() {
60 inflateEnd(&zcontext_);
64 StatusObject<size_t> ZlibSource::ReadInternal(
const strings::MutableByteRange& range) {
65 zcontext_.next_out = range.begin();
66 zcontext_.avail_out = range.size();
69 if (zcontext_.avail_in > 0) {
70 int zerror = inflate(&zcontext_, Z_NO_FLUSH);
73 if (zerror == Z_STREAM_END) {
76 CHECK_EQ(0, inflateEnd(&zcontext_));
77 if (zcontext_.avail_in) {
78 int reset = internalInflateInit2(format_, &zcontext_);
79 CHECK_EQ(Z_OK, reset);
84 return ToStatus(zerror, zcontext_.msg);
87 if (zcontext_.next_out == range.end())
90 DCHECK_EQ(0, zcontext_.avail_in);
93 auto res = sub_stream_->Read(strings::MutableByteRange(buf_.get(), kBufSize));
100 DVLOG(1) <<
"Read " << res.obj <<
" bytes";
102 zcontext_.next_in = buf_.get();
103 zcontext_.avail_in = res.obj;
104 if (!zcontext_.state) {
105 int reset = internalInflateInit2(format_, &zcontext_);
106 CHECK_EQ(Z_OK, reset);
110 if (zcontext_.avail_in > 0) {
111 CHECK_EQ(0, zcontext_.avail_out);
114 return zcontext_.next_out - range.begin();
117 ZlibSink::ZlibSink(Sink* sub,
unsigned level,
size_t buf_size)
118 : sub_(sub), buf_(new uint8_t[buf_size]), buf_size_(buf_size) {
121 int lev = level == 0 ? Z_DEFAULT_COMPRESSION : level;
122 int zerror = deflateInit2(&zcontext_, lev, Z_DEFLATED, 15 | 16, 8, Z_DEFAULT_STRATEGY);
123 CHECK_EQ(Z_OK, zerror);
125 zcontext_.next_out = buf_.get();
126 zcontext_.avail_out = buf_size_;
129 ZlibSink::~ZlibSink() { deflateEnd(&zcontext_); }
131 Status ZlibSink::Append(
const strings::ByteRange& slice) {
132 zcontext_.next_in = const_cast<Bytef*>(reinterpret_cast<const Bytef*>(slice.data()));
133 zcontext_.avail_in = slice.size();
135 int zerror = deflate(&zcontext_, Z_NO_FLUSH);
137 return ToStatus(zerror, zcontext_.msg);
139 while (zcontext_.avail_out == 0) {
140 strings::ByteRange br(buf_.get(), buf_size_);
141 RETURN_IF_ERROR(sub_->Append(br));
143 zcontext_.next_out = buf_.get();
144 zcontext_.avail_out = buf_size_;
146 int zerror = deflate(&zcontext_, Z_NO_FLUSH);
148 return ToStatus(zerror, zcontext_.msg);
150 CHECK_EQ(0, zcontext_.avail_in);
155 Status ZlibSink::Flush() {
157 int zerror = deflate(&zcontext_, Z_FINISH);
158 if (zerror == Z_STREAM_END)
160 if (zerror != Z_OK && zerror != Z_BUF_ERROR) {
161 return ToStatus(zerror, zcontext_.msg);
164 RETURN_IF_ERROR(sub_->Append(strings::ByteRange{buf_.get(), zcontext_.next_out}));
165 zcontext_.next_out = buf_.get();
166 zcontext_.avail_out = buf_size_;
168 RETURN_IF_ERROR(sub_->Append(strings::ByteRange{buf_.get(), zcontext_.next_out}));
170 return sub_->Flush();