// Description: // A compressed (file) input/output stream. // // Copyright (C) 2001 Frank Becker // // This program is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License as published by the Free Software // Foundation; either version 2 of the License, or (at your option) any later // version. // // This program is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details // #include #include #include #include ofstream &operator<<( ofstream &outfile, Uint32 i) { char *pi = (char*)&i; if( ! ::isLittleEndian()) swap( pi, 4); outfile.write( pi, 4); return outfile; } ifstream &operator>>( ifstream &infile, Uint32 &i) { char *pi = (char*)&i; infile.read( pi, 4); if( ! ::isLittleEndian()) swap( pi, 4); return infile; } //----------------------------------------------------------------------------- ziStreamBuffer::ziStreamBuffer( ifstream &fd): _fstream( fd), _eof(false), _compressed(true), _isOK(false) { XTRACE(); _init(); } ziStreamBuffer::~ziStreamBuffer() { XTRACE(); } streamsize ziStreamBuffer::xsgetn(char* s, streamsize n) { XTRACE(); if( !_compressed) { if( _fstream.eof()) return EOF; _fstream.read( s, n); return _fstream.gcount(); } if( _eof) return EOF; _stream.next_out = (Byte*)s; _stream.avail_out = n; do { if( _stream.avail_in == 0) { _fstream.read( (char*)_inBuf, ZSTREAM_BUFFSIZE); _stream.next_in = _inBuf; _stream.avail_in = _fstream.gcount(); } int err = inflate(&_stream, Z_NO_FLUSH); if( err == Z_STREAM_END) _eof = true; else if( err != Z_OK) { LOG_ERROR << "ziStreamBuffer::xsgetn error during inflate: " << err << endl; exit(-1); } } while( (_stream.avail_out > 0) && !_eof); return n-_stream.avail_out; } void ziStreamBuffer::_init( void) { XTRACE(); if( !_fstream.is_open()) { LOG_ERROR << "Input stream not open!" << endl; } // xsetflags( ios::binary); Uint32 magic; _fstream >> magic; if( magic != ZSTREAM_MAGIC) { // LOG_WARNING << "Treating as uncompressed file..." << endl; _compressed = false; _fstream.seekg( -4, ios::cur); } _stream.zalloc = (alloc_func)0; _stream.zfree = (free_func)0; _stream.opaque = (voidpf)0; _stream.next_in = _inBuf; _stream.avail_in = 0; if( inflateInit( &_stream) != Z_OK) { LOG_ERROR << "Unable to initialize ziStreamBuffer" << endl; } _isOK = true; } //----------------------------------------------------------------------------- zoStreamBuffer::zoStreamBuffer( ofstream &fd): _fstream( fd), _isOK(false) { XTRACE(); _init(); } zoStreamBuffer::~zoStreamBuffer() { XTRACE(); int zerr; do { zerr = deflate(&_stream, Z_FINISH); _flush(); } while( zerr == Z_OK); // LOG_DEBUG << _stream.total_in << " IN bytes." << endl; // LOG_DEBUG << _stream.total_out << " OUT bytes." << endl; if( deflateEnd( &_stream) != Z_OK) { LOG_ERROR << "Problem destroying zoStreamBuffer." << endl; } } streamsize zoStreamBuffer::xsputn(const char* s, streamsize n) { // XTRACE(); _stream.next_in = (Byte*)s; _stream.avail_in = n; while( _stream.avail_in != 0) { if( deflate(&_stream, Z_NO_FLUSH) != Z_OK) { LOG_ERROR << "Compression error!" << endl; break; } if( _stream.avail_out == 0) { _flush(); } } return n-_stream.avail_in; } void zoStreamBuffer::_flush( void) { XTRACE(); int len = ZSTREAM_BUFFSIZE - _stream.avail_out; if( len) { _fstream.write( (char*)_outBuf, len); _stream.next_out = _outBuf; _stream.avail_out = ZSTREAM_BUFFSIZE; } } void zoStreamBuffer::_init( void) { XTRACE(); if( !_fstream.is_open()) { LOG_ERROR << "Output stream not open!" << endl; } // xsetflags( ios::binary); _fstream << (Uint32) ZSTREAM_MAGIC; _stream.zalloc = (alloc_func)0; _stream.zfree = (free_func)0; _stream.opaque = (voidpf)0; _stream.next_out = _outBuf; _stream.avail_out = ZSTREAM_BUFFSIZE; if( deflateInit( &_stream, Z_BEST_COMPRESSION) != Z_OK) { LOG_ERROR << "Unable to initialize zoStreamBuffer" << endl; } _isOK = true; } //----------------------------------------------------------------------------- //Note: This rather stupid looking *new + ref for _streambuf is to avoid //gcc asking for -fhuge-objects when cross compiling to windows. ziStream::ziStream( ifstream &inf): super(0), _streambuf( *new ziStreamBuffer( inf)) { XTRACE(); init( &_streambuf); } ziStream::~ziStream() { XTRACE(); delete &_streambuf; } //----------------------------------------------------------------------------- zoStream::zoStream( ofstream &outf): super(0), _streambuf( *new zoStreamBuffer( outf)) { XTRACE(); init( &_streambuf); } zoStream::~zoStream() { XTRACE(); delete &_streambuf; } //-----------------------------------------------------------------------------