15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Protocol Buffers - Google's data interchange format 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2008 Google Inc. All rights reserved. 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// http://code.google.com/p/protobuf/ 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met: 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions of source code must retain the above copyright 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Redistributions in binary form must reproduce the above 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// * Neither the name of Google Inc. nor the names of its 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: brianolson@google.com (Brian Olson) 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This file contains the implementation of classes GzipInputStream and 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GzipOutputStream. 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h" 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if HAVE_ZLIB 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <google/protobuf/io/gzip_stream.h> 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <google/protobuf/stubs/common.h> 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace google { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace protobuf { 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace io { 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const int kDefaultBufferSize = 65536; 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipInputStream::GzipInputStream( 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ZeroCopyInputStream* sub_stream, Format format, int buffer_size) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : format_(format), sub_stream_(sub_stream), zerror_(Z_OK) { 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.zalloc = Z_NULL; 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.zfree = Z_NULL; 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.opaque = Z_NULL; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.total_out = 0; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_in = NULL; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_in = 0; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.total_in = 0; 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.msg = NULL; 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (buffer_size == -1) { 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_buffer_length_ = kDefaultBufferSize; 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_buffer_length_ = buffer_size; 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_buffer_ = operator new(output_buffer_length_); 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GOOGLE_CHECK(output_buffer_ != NULL); 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_out = static_cast<Bytef*>(output_buffer_); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_out = output_buffer_length_; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_position_ = output_buffer_; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipInputStream::~GzipInputStream() { 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operator delete(output_buffer_); 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = inflateEnd(&zcontext_); 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static inline int internalInflateInit2( 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) z_stream* zcontext, GzipInputStream::Format format) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int windowBitsFormat = 0; 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (format) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GzipInputStream::GZIP: windowBitsFormat = 16; break; 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GzipInputStream::AUTO: windowBitsFormat = 32; break; 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case GzipInputStream::ZLIB: windowBitsFormat = 0; break; 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return inflateInit2(zcontext, /* windowBits */15 | windowBitsFormat); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GzipInputStream::Inflate(int flush) { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((zerror_ == Z_OK) && (zcontext_.avail_out == 0)) { 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previous inflate filled output buffer. don't change input params yet. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (zcontext_.avail_in == 0) { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* in; 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int in_size; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool first = zcontext_.next_in == NULL; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ok = sub_stream_->Next(&in, &in_size); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) { 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_out = NULL; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_out = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Z_STREAM_END; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_in = static_cast<Bytef*>(const_cast<void*>(in)); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_in = in_size; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (first) { 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = internalInflateInit2(&zcontext_, format_); 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (error != Z_OK) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_out = static_cast<Bytef*>(output_buffer_); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_out = output_buffer_length_; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_position_ = output_buffer_; 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = inflate(&zcontext_, flush); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GzipInputStream::DoNextOutput(const void** data, int* size) { 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *data = output_position_; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = ((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_position_ = zcontext_.next_out; 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implements ZeroCopyInputStream ---------------------------------- 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GzipInputStream::Next(const void** data, int* size) { 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) || (zerror_ == Z_BUF_ERROR); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((!ok) || (zcontext_.next_out == NULL)) { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zcontext_.next_out != output_position_) { 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoNextOutput(data, size); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zerror_ == Z_STREAM_END) { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zcontext_.next_out != NULL) { 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sub_stream_ may have concatenated streams to follow 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = inflateEnd(&zcontext_); 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zerror_ != Z_OK) { 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = internalInflateInit2(&zcontext_, format_); 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zerror_ != Z_OK) { 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *data = NULL; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = 0; 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = Inflate(Z_NO_FLUSH); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((zerror_ == Z_STREAM_END) && (zcontext_.next_out == NULL)) { 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The underlying stream's Next returned false inside Inflate. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = (zerror_ == Z_OK) || (zerror_ == Z_STREAM_END) 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) || (zerror_ == Z_BUF_ERROR); 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) { 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DoNextOutput(data, size); 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GzipInputStream::BackUp(int count) { 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_position_ = reinterpret_cast<void*>( 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<uintptr_t>(output_position_) - count); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GzipInputStream::Skip(int count) { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const void* data; 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int size; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ok = Next(&data, &size); 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (ok && (size < count)) { 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) count -= size; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ok = Next(&data, &size); 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (size > count) { 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BackUp(size - count); 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 GzipInputStream::ByteCount() const { 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return zcontext_.total_out + 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (((uintptr_t)zcontext_.next_out) - ((uintptr_t)output_position_)); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ========================================================================= 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipOutputStream::Options::Options() 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : format(GZIP), 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) buffer_size(kDefaultBufferSize), 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compression_level(Z_DEFAULT_COMPRESSION), 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) compression_strategy(Z_DEFAULT_STRATEGY) {} 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream) { 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(sub_stream, Options()); 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipOutputStream::GzipOutputStream(ZeroCopyOutputStream* sub_stream, 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Options& options) { 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Init(sub_stream, options); 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GzipOutputStream::Init(ZeroCopyOutputStream* sub_stream, 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Options& options) { 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_stream_ = sub_stream; 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_ = NULL; 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_size_ = 0; 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_buffer_length_ = options.buffer_size; 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) input_buffer_ = operator new(input_buffer_length_); 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GOOGLE_CHECK(input_buffer_ != NULL); 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.zalloc = Z_NULL; 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.zfree = Z_NULL; 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.opaque = Z_NULL; 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_out = NULL; 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_out = 0; 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.total_out = 0; 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_in = NULL; 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_in = 0; 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.total_in = 0; 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.msg = NULL; 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // default to GZIP format 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int windowBitsFormat = 16; 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (options.format == ZLIB) { 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) windowBitsFormat = 0; 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = deflateInit2( 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &zcontext_, 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options.compression_level, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Z_DEFLATED, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* windowBits */15 | windowBitsFormat, 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /* memLevel (default) */8, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) options.compression_strategy); 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)GzipOutputStream::~GzipOutputStream() { 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Close(); 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (input_buffer_ != NULL) { 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) operator delete(input_buffer_); 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// private 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GzipOutputStream::Deflate(int flush) { 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int error = Z_OK; 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((sub_data_ == NULL) || (zcontext_.avail_out == 0)) { 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ok = sub_stream_->Next(&sub_data_, &sub_data_size_); 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ok) { 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_ = NULL; 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_size_ = 0; 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return Z_BUF_ERROR; 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GOOGLE_CHECK_GT(sub_data_size_, 0); 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_out = static_cast<Bytef*>(sub_data_); 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_out = sub_data_size_; 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error = deflate(&zcontext_, flush); 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (error == Z_OK && zcontext_.avail_out == 0); 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((flush == Z_FULL_FLUSH) || (flush == Z_FINISH)) { 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Notify lower layer of data. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_stream_->BackUp(zcontext_.avail_out); 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We don't own the buffer anymore. 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_ = NULL; 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) sub_data_size_ = 0; 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return error; 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// implements ZeroCopyOutputStream --------------------------------- 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GzipOutputStream::Next(void** data, int* size) { 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zcontext_.avail_in != 0) { 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = Deflate(Z_NO_FLUSH); 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zerror_ != Z_OK) { 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (zcontext_.avail_in == 0) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // all input was consumed. reset the buffer. 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.next_in = static_cast<Bytef*>(input_buffer_); 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_in = input_buffer_length_; 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *data = input_buffer_; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *size = input_buffer_length_; 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The loop in Deflate should consume all avail_in 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GOOGLE_LOG(DFATAL) << "Deflate left bytes unconsumed"; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GzipOutputStream::BackUp(int count) { 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) GOOGLE_CHECK_GE(zcontext_.avail_in, count); 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zcontext_.avail_in -= count; 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int64 GzipOutputStream::ByteCount() const { 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return zcontext_.total_in + zcontext_.avail_in; 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GzipOutputStream::Flush() { 302ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch zerror_ = Deflate(Z_FULL_FLUSH); 303ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // Return true if the flush succeeded or if it was a no-op. 304ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return (zerror_ == Z_OK) || 305ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch (zerror_ == Z_BUF_ERROR && zcontext_.avail_in == 0 && 306ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch zcontext_.avail_out != 0); 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool GzipOutputStream::Close() { 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((zerror_ != Z_OK) && (zerror_ != Z_BUF_ERROR)) { 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = Deflate(Z_FINISH); 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (zerror_ == Z_OK); 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = deflateEnd(&zcontext_); 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool ok = zerror_ == Z_OK; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) zerror_ = Z_STREAM_END; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ok; 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace io 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace protobuf 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace google 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // HAVE_ZLIB 327