gzip_stream.cc
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
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
14 // distribution.
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.
18 //
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.
30 
31 // Author: brianolson@google.com (Brian Olson)
32 //
33 // This file contains the implementation of classes GzipInputStream and
34 // GzipOutputStream.
35 
36 
37 #if HAVE_ZLIB
39 
42 
43 namespace google {
44 namespace protobuf {
45 namespace io {
46 
47 static const int kDefaultBufferSize = 65536;
48 
49 GzipInputStream::GzipInputStream(ZeroCopyInputStream* sub_stream, Format format,
50  int buffer_size)
51  : format_(format), sub_stream_(sub_stream), zerror_(Z_OK), byte_count_(0) {
52  zcontext_.state = Z_NULL;
53  zcontext_.zalloc = Z_NULL;
54  zcontext_.zfree = Z_NULL;
55  zcontext_.opaque = Z_NULL;
56  zcontext_.total_out = 0;
57  zcontext_.next_in = NULL;
58  zcontext_.avail_in = 0;
59  zcontext_.total_in = 0;
60  zcontext_.msg = NULL;
61  if (buffer_size == -1) {
62  output_buffer_length_ = kDefaultBufferSize;
63  } else {
64  output_buffer_length_ = buffer_size;
65  }
66  output_buffer_ = operator new(output_buffer_length_);
67  GOOGLE_CHECK(output_buffer_ != NULL);
68  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
69  zcontext_.avail_out = output_buffer_length_;
70  output_position_ = output_buffer_;
71 }
72 GzipInputStream::~GzipInputStream() {
73  operator delete(output_buffer_);
74  zerror_ = inflateEnd(&zcontext_);
75 }
76 
77 static inline int internalInflateInit2(z_stream* zcontext,
78  GzipInputStream::Format format) {
79  int windowBitsFormat = 0;
80  switch (format) {
81  case GzipInputStream::GZIP:
82  windowBitsFormat = 16;
83  break;
84  case GzipInputStream::AUTO:
85  windowBitsFormat = 32;
86  break;
87  case GzipInputStream::ZLIB:
88  windowBitsFormat = 0;
89  break;
90  }
91  return inflateInit2(zcontext, /* windowBits */ 15 | windowBitsFormat);
92 }
93 
94 int GzipInputStream::Inflate(int flush) {
95  if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) {
96  // previous inflate filled output buffer. don't change input params yet.
97  } else if (zcontext_.avail_in == 0) {
98  const void* in;
99  int in_size;
100  bool first = zcontext_.next_in == NULL;
101  bool ok = sub_stream_->Next(&in, &in_size);
102  if (!ok) {
103  zcontext_.next_out = NULL;
104  zcontext_.avail_out = 0;
105  return Z_STREAM_END;
106  }
107  zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in));
108  zcontext_.avail_in = in_size;
109  if (first) {
110  int error = internalInflateInit2(&zcontext_, format_);
111  if (error != Z_OK) {
112  return error;
113  }
114  }
115  }
116  zcontext_.next_out = static_cast<Bytef*>(output_buffer_);
117  zcontext_.avail_out = output_buffer_length_;
118  output_position_ = output_buffer_;
119  int error = inflate(&zcontext_, flush);
120  return error;
121 }
122 
123 void GzipInputStream::DoNextOutput(const void** data, int* size) {
124  *data = output_position_;
125  *size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_);
126  output_position_ = zcontext_.next_out;
127 }
128 
129 // implements ZeroCopyInputStream ----------------------------------
130 bool GzipInputStream::Next(const void** data, int* size) {
131  bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
132  (zerror_ == Z_BUF_ERROR);
133  if ((!ok) || (zcontext_.next_out == NULL)) {
134  return false;
135  }
136  if (zcontext_.next_out != output_position_) {
137  DoNextOutput(data, size);
138  return true;
139  }
140  if (zerror_ == Z_STREAM_END) {
141  if (zcontext_.next_out != NULL) {
142  // sub_stream_ may have concatenated streams to follow
143  zerror_ = inflateEnd(&zcontext_);
144  byte_count_ += zcontext_.total_out;
145  if (zerror_ != Z_OK) {
146  return false;
147  }
148  zerror_ = internalInflateInit2(&zcontext_, format_);
149  if (zerror_ != Z_OK) {
150  return false;
151  }
152  } else {
153  *data = NULL;
154  *size = 0;
155  return false;
156  }
157  }
158  zerror_ = Inflate(Z_NO_FLUSH);
159  if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) {
160  // The underlying stream's Next returned false inside Inflate.
161  return false;
162  }
163  ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) ||
164  (zerror_ == Z_BUF_ERROR);
165  if (!ok) {
166  return false;
167  }
168  DoNextOutput(data, size);
169  return true;
170 }
171 void GzipInputStream::BackUp(int count) {
172  output_position_ = reinterpret_cast<void*>(
173  reinterpret_cast<uintptr_t>(output_position_) - count);
174 }
175 bool GzipInputStream::Skip(int count) {
176  const void* data;
177  int size = 0;
178  bool ok = Next(&data, &size);
179  while (ok && (size < count)) {
180  count -= size;
181  ok = Next(&data, &size);
182  }
183  if (size > count) {
184  BackUp(size - count);
185  }
186  return ok;
187 }
188 int64 GzipInputStream::ByteCount() const {
189  int64 ret = byte_count_ + zcontext_.total_out;
190  if (zcontext_.next_out != NULL && output_position_ != NULL) {
191  ret += reinterpret_cast<uintptr_t>(zcontext_.next_out) -
192  reinterpret_cast<uintptr_t>(output_position_);
193  }
194  return ret;
195 }
196 
197 // =========================================================================
198 
199 GzipOutputStream::Options::Options()
200  : format(GZIP),
201  buffer_size(kDefaultBufferSize),
202  compression_level(Z_DEFAULT_COMPRESSION),
203  compression_strategy(Z_DEFAULT_STRATEGY) {}
204 
205 GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) {
206  Init(sub_stream, Options());
207 }
208 
209 GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream,
210  const Options& options) {
211  Init(sub_stream, options);
212 }
213 
214 void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream,
215  const Options& options) {
216  sub_stream_ = sub_stream;
217  sub_data_ = NULL;
218  sub_data_size_ = 0;
219 
220  input_buffer_length_ = options.buffer_size;
221  input_buffer_ = operator new(input_buffer_length_);
222  GOOGLE_CHECK(input_buffer_ != NULL);
223 
224  zcontext_.zalloc = Z_NULL;
225  zcontext_.zfree = Z_NULL;
226  zcontext_.opaque = Z_NULL;
227  zcontext_.next_out = NULL;
228  zcontext_.avail_out = 0;
229  zcontext_.total_out = 0;
230  zcontext_.next_in = NULL;
231  zcontext_.avail_in = 0;
232  zcontext_.total_in = 0;
233  zcontext_.msg = NULL;
234  // default to GZIP format
235  int windowBitsFormat = 16;
236  if (options.format == ZLIB) {
237  windowBitsFormat = 0;
238  }
239  zerror_ =
240  deflateInit2(&zcontext_, options.compression_level, Z_DEFLATED,
241  /* windowBits */ 15 | windowBitsFormat,
242  /* memLevel (default) */ 8, options.compression_strategy);
243 }
244 
245 GzipOutputStream::~GzipOutputStream() {
246  Close();
247  operator delete(input_buffer_);
248 }
249 
250 // private
251 int GzipOutputStream::Deflate(int flush) {
252  int error = Z_OK;
253  do {
254  if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) {
255  bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_);
256  if (!ok) {
257  sub_data_ = NULL;
258  sub_data_size_ = 0;
259  return Z_BUF_ERROR;
260  }
261  GOOGLE_CHECK_GT(sub_data_size_, 0);
262  zcontext_.next_out = static_cast<Bytef*>(sub_data_);
263  zcontext_.avail_out = sub_data_size_;
264  }
265  error = deflate(&zcontext_, flush);
266  } while (error == Z_OK && zcontext_.avail_out == 0);
267  if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) {
268  // Notify lower layer of data.
269  sub_stream_->BackUp(zcontext_.avail_out);
270  // We don't own the buffer anymore.
271  sub_data_ = NULL;
272  sub_data_size_ = 0;
273  }
274  return error;
275 }
276 
277 // implements ZeroCopyOutputStream ---------------------------------
278 bool GzipOutputStream::Next(void** data, int* size) {
279  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
280  return false;
281  }
282  if (zcontext_.avail_in != 0) {
283  zerror_ = Deflate(Z_NO_FLUSH);
284  if (zerror_ != Z_OK) {
285  return false;
286  }
287  }
288  if (zcontext_.avail_in == 0) {
289  // all input was consumed. reset the buffer.
290  zcontext_.next_in = static_cast<Bytef*>(input_buffer_);
291  zcontext_.avail_in = input_buffer_length_;
292  *data = input_buffer_;
293  *size = input_buffer_length_;
294  } else {
295  // The loop in Deflate should consume all avail_in
296  GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed";
297  }
298  return true;
299 }
300 void GzipOutputStream::BackUp(int count) {
301  GOOGLE_CHECK_GE(zcontext_.avail_in, count);
302  zcontext_.avail_in -= count;
303 }
304 int64 GzipOutputStream::ByteCount() const {
305  return zcontext_.total_in + zcontext_.avail_in;
306 }
307 
308 bool GzipOutputStream::Flush() {
309  zerror_ = Deflate(Z_FULL_FLUSH);
310  // Return true if the flush succeeded or if it was a no-op.
311  return (zerror_ == Z_OK) ||
312  (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 &&
313  zcontext_.avail_out != 0);
314 }
315 
317  if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) {
318  return false;
319  }
320  do {
321  zerror_ = Deflate(Z_FINISH);
322  } while (zerror_ == Z_OK);
323  zerror_ = deflateEnd(&zcontext_);
324  bool ok = zerror_ == Z_OK;
325  zerror_ = Z_STREAM_END;
326  return ok;
327 }
328 
329 } // namespace io
330 } // namespace protobuf
331 } // namespace google
332 
333 #endif // HAVE_ZLIB
NULL
NULL
Definition: test_security_zap.cpp:405
google::protobuf::int64
int64_t int64
Definition: protobuf/src/google/protobuf/stubs/port.h:151
options
Message * options
Definition: src/google/protobuf/descriptor.cc:3119
google::protobuf::python::cmessage::Init
static int Init(CMessage *self, PyObject *args, PyObject *kwargs)
Definition: python/google/protobuf/pyext/message.cc:1286
error
Definition: cJSON.c:88
GOOGLE_CHECK_GT
#define GOOGLE_CHECK_GT(A, B)
Definition: logging.h:160
ok
ROSCPP_DECL bool ok()
byte_count_
int64 byte_count_
Definition: json_util_test.cc:527
format
GLint GLint GLsizei GLint GLenum format
Definition: glcorearb.h:2773
GOOGLE_LOG
#define GOOGLE_LOG(LEVEL)
Definition: logging.h:146
size
#define size
Definition: glcorearb.h:2944
GOOGLE_CHECK
#define GOOGLE_CHECK(EXPRESSION)
Definition: logging.h:153
versiongenerate.buffer_size
int buffer_size
Definition: versiongenerate.py:65
testing::internal::posix::Close
int Close(int fd)
Definition: gtest-port.h:2132
common.h
pump.Skip
def Skip(lines, pos, regex)
Definition: pump.py:261
size
GLsizeiptr size
Definition: glcorearb.h:2943
logging.h
gzip_stream.h
GOOGLE_CHECK_GE
#define GOOGLE_CHECK_GE(A, B)
Definition: logging.h:161
google::protobuf::io::GzipInputStream::GzipInputStream
GzipInputStream(ZeroCopyInputStream *sub_stream, Format format=AUTO, int buffer_size=-1)
first
GLint first
Definition: glcorearb.h:2830
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: glcorearb.h:2879
count
GLint GLsizei count
Definition: glcorearb.h:2830
google
Definition: data_proto2_to_proto3_util.h:11


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:54