/* * Copyright (c) 2013-2016, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * * See full license text in LICENSE file at top of project tree */ #include <inttypes.h> #include <string.h> /* memset */ #include <iostream> #include "Gzip.h" namespace i2p { namespace data { const size_t GZIP_CHUNK_SIZE = 16384; GzipInflator::GzipInflator (): m_IsDirty (false) { memset (&m_Inflator, 0, sizeof (m_Inflator)); inflateInit2 (&m_Inflator, MAX_WBITS + 16); // gzip } GzipInflator::~GzipInflator () { inflateEnd (&m_Inflator); } size_t GzipInflator::Inflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) { if (m_IsDirty) inflateReset (&m_Inflator); m_IsDirty = true; m_Inflator.next_in = const_cast<uint8_t *>(in); m_Inflator.avail_in = inLen; m_Inflator.next_out = out; m_Inflator.avail_out = outLen; int err; if ((err = inflate (&m_Inflator, Z_NO_FLUSH)) == Z_STREAM_END) { return outLen - m_Inflator.avail_out; } return 0; } void GzipInflator::Inflate (const uint8_t * in, size_t inLen, std::ostream& os) { m_IsDirty = true; uint8_t * out = new uint8_t[GZIP_CHUNK_SIZE]; m_Inflator.next_in = const_cast<uint8_t *>(in); m_Inflator.avail_in = inLen; int ret; do { m_Inflator.next_out = out; m_Inflator.avail_out = GZIP_CHUNK_SIZE; ret = inflate (&m_Inflator, Z_NO_FLUSH); if (ret < 0) { inflateEnd (&m_Inflator); os.setstate(std::ios_base::failbit); break; } os.write ((char *)out, GZIP_CHUNK_SIZE - m_Inflator.avail_out); } while (!m_Inflator.avail_out); // more data to read delete[] out; } void GzipInflator::Inflate (std::istream& in, std::ostream& out) { uint8_t * buf = new uint8_t[GZIP_CHUNK_SIZE]; while (!in.eof ()) { in.read ((char *) buf, GZIP_CHUNK_SIZE); Inflate (buf, in.gcount (), out); } delete[] buf; } GzipDeflator::GzipDeflator (): m_IsDirty (false) { memset (&m_Deflator, 0, sizeof (m_Deflator)); deflateInit2 (&m_Deflator, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); // 15 + 16 sets gzip } GzipDeflator::~GzipDeflator () { deflateEnd (&m_Deflator); } void GzipDeflator::SetCompressionLevel (int level) { deflateParams (&m_Deflator, level, Z_DEFAULT_STRATEGY); } size_t GzipDeflator::Deflate (const uint8_t * in, size_t inLen, uint8_t * out, size_t outLen) { if (m_IsDirty) deflateReset (&m_Deflator); m_IsDirty = true; m_Deflator.next_in = const_cast<uint8_t *>(in); m_Deflator.avail_in = inLen; m_Deflator.next_out = out; m_Deflator.avail_out = outLen; int err; if ((err = deflate (&m_Deflator, Z_FINISH)) == Z_STREAM_END) { return outLen - m_Deflator.avail_out; } /* else */ return 0; } } // data } // i2p