1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc. All rights reserved.
3
// http://code.google.com/p/protobuf/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
9
// * Redistributions of source code must retain the above copyright
10
// notice, this list of conditions and the following disclaimer.
11
// * Redistributions in binary form must reproduce the above
12
// copyright notice, this list of conditions and the following disclaimer
13
// in the documentation and/or other materials provided with the
15
// * Neither the name of Google Inc. nor the names of its
16
// contributors may be used to endorse or promote products derived from
17
// this software without specific prior written permission.
19
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
// Author: brianolson@google.com (Brian Olson)
33
// This file contains the implementation of classes GzipInputStream and
39
#include <google/protobuf/io/gzip_stream.h>
41
#include <google/protobuf/stubs/common.h>
47
static const int kDefaultBufferSize = 65536;
49
GzipInputStream::GzipInputStream(
50
ZeroCopyInputStream* sub_stream, Format format, int buffer_size)
51
: format_(format), sub_stream_(sub_stream), zerror_(Z_OK) {
52
zcontext_.zalloc = Z_NULL;
53
zcontext_.zfree = Z_NULL;
54
zcontext_.opaque = Z_NULL;
55
zcontext_.total_out = 0;
56
zcontext_.next_in = NULL;
57
zcontext_.avail_in = 0;
58
zcontext_.total_in = 0;
60
if (buffer_size == -1) {
61
output_buffer_length_ = kDefaultBufferSize;
63
output_buffer_length_ = buffer_size;
65
output_buffer_ = operator new(output_buffer_length_);
66
GOOGLE_CHECK(output_buffer_ != NULL);
67
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
68
zcontext_.avail_out = output_buffer_length_;
69
output_position_ = output_buffer_;
71
GzipInputStream::~GzipInputStream() {
72
operator delete(output_buffer_);
73
zerror_ = inflateEnd(&zcontext_);
76
int GzipInputStream::Inflate(int flush) {
77
if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
78
// previous inflate filled output buffer. don't change input params yet.
79
} else if (zcontext_.avail_in == 0) {
82
bool first = zcontext_.next_in == NULL;
83
bool ok = sub_stream_->Next(&in, &in_size);
85
zcontext_.next_out = NULL;
86
zcontext_.avail_out = 0;
89
zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
90
zcontext_.avail_in = in_size;
92
int windowBitsFormat = 0;
94
case GZIP: windowBitsFormat = 16; break;
95
case AUTO: windowBitsFormat = 32; break;
96
case ZLIB: windowBitsFormat = 0; break;
98
int error = inflateInit2(&zcontext_,
99
/* windowBits */15 | windowBitsFormat);
105
zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
106
zcontext_.avail_out = output_buffer_length_;
107
output_position_ = output_buffer_;
108
int error = inflate(&zcontext_, flush);
112
void GzipInputStream::DoNextOutput(const void** data, int* size) {
113
*data = output_position_;
114
*size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
115
output_position_ = zcontext_.next_out;
118
// implements ZeroCopyInputStream ----------------------------------
119
bool GzipInputStream::Next(const void** data, int* size) {
120
bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
121
|| (zerror_ == Z_BUF_ERROR);
122
if ((!ok) || (zcontext_.next_out == NULL)) {
125
if (zcontext_.next_out != output_position_) {
126
DoNextOutput(data, size);
129
if (zerror_ == Z_STREAM_END) {
134
zerror_ = Inflate(Z_NO_FLUSH);
135
if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
136
// The underlying stream's Next returned false inside Inflate.
139
ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END)
140
|| (zerror_ == Z_BUF_ERROR);
144
DoNextOutput(data, size);
147
void GzipInputStream::BackUp(int count) {
148
output_position_ = reinterpret_cast<void*>(
149
reinterpret_cast<uintptr_t>(output_position_) - count);
151
bool GzipInputStream::Skip(int count) {
154
bool ok = Next(&data, &size);
155
while (ok && (size < count)) {
157
ok = Next(&data, &size);
160
BackUp(size - count);
164
int64 GzipInputStream::ByteCount() const {
165
return zcontext_.total_out +
166
(((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_));
169
// =========================================================================
171
GzipOutputStream::Options::Options()
173
buffer_size(kDefaultBufferSize),
174
compression_level(Z_DEFAULT_COMPRESSION),
175
compression_strategy(Z_DEFAULT_STRATEGY) {}
177
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
178
Init(sub_stream, Options());
181
GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
182
const Options& options) {
183
Init(sub_stream, options);
186
GzipOutputStream::GzipOutputStream(
187
ZeroCopyOutputStream* sub_stream, Format format, int buffer_size) {
189
options.format = format;
190
if (buffer_size != -1) {
191
options.buffer_size = buffer_size;
193
Init(sub_stream, options);
196
void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
197
const Options& options) {
198
sub_stream_ = sub_stream;
202
input_buffer_length_ = options.buffer_size;
203
input_buffer_ = operator new(input_buffer_length_);
204
GOOGLE_CHECK(input_buffer_ != NULL);
206
zcontext_.zalloc = Z_NULL;
207
zcontext_.zfree = Z_NULL;
208
zcontext_.opaque = Z_NULL;
209
zcontext_.next_out = NULL;
210
zcontext_.avail_out = 0;
211
zcontext_.total_out = 0;
212
zcontext_.next_in = NULL;
213
zcontext_.avail_in = 0;
214
zcontext_.total_in = 0;
215
zcontext_.msg = NULL;
216
// default to GZIP format
217
int windowBitsFormat = 16;
218
if (options.format == ZLIB) {
219
windowBitsFormat = 0;
221
zerror_ = deflateInit2(
223
options.compression_level,
225
/* windowBits */15 | windowBitsFormat,
226
/* memLevel (default) */8,
227
options.compression_strategy);
230
GzipOutputStream::~GzipOutputStream() {
232
if (input_buffer_ != NULL) {
233
operator delete(input_buffer_);
238
int GzipOutputStream::Deflate(int flush) {
241
if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
242
bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
248
GOOGLE_CHECK_GT(sub_data_size_, 0);
249
zcontext_.next_out = static_cast<Bytef*>(sub_data_);
250
zcontext_.avail_out = sub_data_size_;
252
error = deflate(&zcontext_, flush);
253
} while (error == Z_OK && zcontext_.avail_out == 0);
254
if (((flush == Z_FULL_FLUSH) || (flush == Z_FINISH))
255
&& (zcontext_.avail_out != sub_data_size_)) {
256
// Notify lower layer of data.
257
sub_stream_->BackUp(zcontext_.avail_out);
258
// We don't own the buffer anymore.
265
// implements ZeroCopyOutputStream ---------------------------------
266
bool GzipOutputStream::Next(void** data, int* size) {
267
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
270
if (zcontext_.avail_in != 0) {
271
zerror_ = Deflate(Z_NO_FLUSH);
272
if (zerror_ != Z_OK) {
276
if (zcontext_.avail_in == 0) {
277
// all input was consumed. reset the buffer.
278
zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
279
zcontext_.avail_in = input_buffer_length_;
280
*data = input_buffer_;
281
*size = input_buffer_length_;
283
// The loop in Deflate should consume all avail_in
284
GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
288
void GzipOutputStream::BackUp(int count) {
289
GOOGLE_CHECK_GE(zcontext_.avail_in, count);
290
zcontext_.avail_in -= count;
292
int64 GzipOutputStream::ByteCount() const {
293
return zcontext_.total_in + zcontext_.avail_in;
296
bool GzipOutputStream::Flush() {
298
zerror_ = Deflate(Z_FULL_FLUSH);
299
} while (zerror_ == Z_OK);
300
return zerror_ == Z_OK;
303
bool GzipOutputStream::Close() {
304
if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
308
zerror_ = Deflate(Z_FINISH);
309
} while (zerror_ == Z_OK);
310
zerror_ = deflateEnd(&zcontext_);
311
bool ok = zerror_ == Z_OK;
312
zerror_ = Z_STREAM_END;
317
} // namespace protobuf
318
} // namespace google