#include #include #include #include "zlib.h" #include "geners/BZ2Handle.hh" #include "geners/CStringStream.hh" #include "geners/IOException.hh" #include "geners/platform.hh" #ifdef USING_MS_WINDOWS_CPP #define strcasecmp _stricmp #endif static void doZlibCompression(const char* data, const unsigned long long len, const bool defl, z_stream_s& strm, char* buffer, const unsigned long long bufLen, std::ostream& sink) { assert(buffer); assert(bufLen); int status = Z_OK; strm.next_in = reinterpret_cast(const_cast(data)); strm.avail_in = len; do { strm.next_out = reinterpret_cast(buffer); strm.avail_out = bufLen; status = defl ? deflate(&strm, Z_FINISH) : inflate(&strm, Z_NO_FLUSH); if (!(status == Z_OK || status == Z_STREAM_END)) { if (defl) throw std::runtime_error("In gs::doZlibCompression: " "decompression failure"); else throw std::runtime_error("In gs::doZlibCompression: " "compression failure"); } const unsigned have = bufLen - strm.avail_out; sink.write(buffer, have); if (sink.fail()) throw gs::IOWriteFailure( "In gs::doZlibCompression: sink stream failure"); } while (strm.avail_out == 0); if (defl) { assert(strm.avail_in == 0); assert(status == Z_STREAM_END); status = deflateReset(&strm); } else status = inflateReset(&strm); if (status != Z_OK) throw std::runtime_error("In gs::doZlibCompression: " "failed to reset zlib stream"); } static void doBZ2Compression(const char* data, const unsigned long long len, const bool defl, bz_stream& strm, char* buffer, const unsigned long long bufLen, std::ostream& sink) { assert(buffer); assert(bufLen); int status = BZ_OK; strm.next_in = const_cast(data); strm.avail_in = len; do { strm.next_out = buffer; strm.avail_out = bufLen; status = defl ? BZ2_bzCompress(&strm, BZ_FINISH) : BZ2_bzDecompress(&strm); if (!(status == BZ_OK || status == BZ_STREAM_END)) { if (defl) throw std::runtime_error("In gs::doBZ2Compression: " "decompression failure"); else throw std::runtime_error("In gs::doBZ2Compression: " "compression failure"); } const unsigned have = bufLen - strm.avail_out; sink.write(buffer, have); if (sink.fail()) throw gs::IOWriteFailure( "In gs::doBZ2Compression: sink stream failure"); } while (status != BZ_STREAM_END); } namespace gs { CStringStream::CStringStream(const CompressionMode m, const int compressionLevel, const unsigned minSizeToCompress, const unsigned bufSize) : CStringBuf(), std::basic_iostream(static_cast(this)), mode_(m), compressionLevel_(compressionLevel), minSizeToCompress_(minSizeToCompress), // Have a reasonable minimum buffer size to maintain // performance even if the user wants to shoot himself // in a foot comprBuf_(bufSize > 1024U ? bufSize : 1024U), sink_(0) { } void CStringStream::setCompressionMode(const CompressionMode newmode) { reset(); mode_ = newmode; } void CStringStream::reset() { clear(); seekp(0); seekg(0); } void CStringStream::readCompressed(std::istream& in, const unsigned compressionCode, const unsigned long long len) { reset(); if (!len) return; // Decompress and dump to this string stream if (len > readBuf_.size()) readBuf_.resize(len); in.read(&readBuf_[0], len); switch (static_cast(compressionCode)) { case NOT_COMPRESSED: this->write(&readBuf_[0], len); return; case ZLIB: { if (!inflator_.get()) inflator_ = CPP11_auto_ptr( new ZlibInflateHandle()); doZlibCompression(&readBuf_[0], len, false, inflator_->strm(), &comprBuf_[0], comprBuf_.size(), *this); } break; case BZIP2: { // bzlib2 can not be reset, so we have to make // a new inflator every time bz_stream strm; BZ2InflateHandle h(strm); doBZ2Compression(&readBuf_[0], len, false, strm, &comprBuf_[0], comprBuf_.size(), *this); } break; default: assert(!"Unhandled switch case in " "CStringStream::readCompressed. " "This is a bug. Please report."); } } CStringStream::CompressionMode CStringStream::writeCompressed() { // Compress and dump to sink assert(sink_); unsigned long long len = 0; const char* data = this->getPutBuffer(&len); if (len == 0) return NOT_COMPRESSED; if (mode_ == NOT_COMPRESSED || len < minSizeToCompress_) { sink_->write(data, len); return NOT_COMPRESSED; } switch (mode_) { case ZLIB: { if (!deflator_.get()) deflator_ = CPP11_auto_ptr( new ZlibDeflateHandle(compressionLevel_)); doZlibCompression(data, len, true, deflator_->strm(), &comprBuf_[0], comprBuf_.size(), *sink_); } break; case BZIP2: { // bzlib2 can not be reset, so we have to make // a new deflator every time bz_stream strm; BZ2DeflateHandle h(strm); doBZ2Compression(data, len, true, strm, &comprBuf_[0], comprBuf_.size(), *sink_); } break; default: assert(!"Unhandled switch case in " "CStringStream::writeCompressed. " "This is a bug. Please report."); } seekp(0); return mode_; } bool CStringStream::getCompressionModeByName(const char* name, CompressionMode* m) { static const char* names[] = { "n", "z", "b" }; if (!name || !m) return false; for (unsigned i=0; i(i); return true; } return false; } std::string CStringStream::compressionModeName(const CompressionMode m, const bool useShortName) { std::string mode; switch (m) { case NOT_COMPRESSED: mode = useShortName ? "n" : "not compressed"; break; case ZLIB: mode = useShortName ? "z" : "zlib"; break; case BZIP2: mode = useShortName ? "b" : "bzip2"; break; default: assert(!"Unhandled switch case in " "CStringStream::compressionModeName. " "This is a bug. Please report."); } return mode; } }