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