Files
create/src/zipios++/deflateoutputstreambuf.cpp
2011-10-10 13:44:52 +00:00

225 lines
5.9 KiB
C++

#include "zipios-config.h"
#include "meta-iostreams.h"
#include <zlib.h>
#include "fcollexceptions.h"
#include "deflateoutputstreambuf.h"
#include "outputstringstream.h"
namespace zipios {
using std::cerr ;
using std::endl ;
DeflateOutputStreambuf::DeflateOutputStreambuf( streambuf *outbuf, bool user_init,
bool del_outbuf )
: FilterOutputStreambuf( outbuf, del_outbuf ),
_zs_initialized ( false ),
_invecsize ( 1000 ),
_invec ( _invecsize ),
_outvecsize ( 1000 ),
_outvec ( _outvecsize )
{
// NOTICE: It is important that this constructor and the methods it
// calls doesn't do anything with the output streambuf _outbuf The
// reason is that this class can be subclassed, and the subclass
// should get a chance to write to the buffer first
// zlib init:
_zs.zalloc = Z_NULL ;
_zs.zfree = Z_NULL ;
_zs.opaque = Z_NULL ;
if ( user_init && ! init() )
cerr << "DeflateOutputStreambuf::reset() failed!\n" ; // FIXME: throw something
}
DeflateOutputStreambuf::~DeflateOutputStreambuf() {
closeStream() ;
}
// This method is called in the constructor, so it must not write
// anything to the output streambuf _outbuf (see notice in
// constructor)
bool DeflateOutputStreambuf::init( int comp_level ) {
static const int default_mem_level = 8 ;
// _zs.next_in and avail_in must be set according to
// zlib.h (inline doc).
_zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[ 0 ] ) ) ;
_zs.avail_in = 0 ;
_zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
_zs.avail_out = _outvecsize ;
int err ;
if( _zs_initialized ) { // just reset it
endDeflation() ;
err = deflateReset( &_zs ) ;
// FIXME: bug, for deflateReset we do not update the compression level
} else { // init it
err = deflateInit2( &_zs, comp_level, Z_DEFLATED, -MAX_WBITS,
default_mem_level, Z_DEFAULT_STRATEGY ) ;
/* windowBits is passed < 0 to tell that no zlib header should be
written. */
_zs_initialized = true ;
}
// streambuf init:
setp( &( _invec[ 0 ] ), &( _invec[ 0 ] ) + _invecsize ) ;
_crc32 = crc32( 0, Z_NULL, 0 ) ;
_overflown_bytes = 0 ;
if ( err == Z_OK )
return true ;
else
return false ;
}
bool DeflateOutputStreambuf::closeStream() {
int err = Z_OK ;
if( _zs_initialized ) {
endDeflation() ;
err = deflateEnd( &_zs ) ;
_zs_initialized = false ;
}
if ( err == Z_OK )
return true ;
else {
cerr << "DeflateOutputStreambuf::closeStream(): deflateEnd failed" ;
#ifdef HAVE_ZERROR
cerr << ": " << zError( err ) ;
#endif
cerr << endl ;
return false ;
}
}
int DeflateOutputStreambuf::overflow( int c ) {
_zs.avail_in = pptr() - pbase() ;
_zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[ 0 ] ) ) ;
_crc32 = crc32( _crc32, _zs.next_in, _zs.avail_in ) ; // update crc32
_overflown_bytes += _zs.avail_in ;
_zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
_zs.avail_out = _outvecsize ;
// Deflate until _invec is empty.
int err = Z_OK ;
while ( ( _zs.avail_in > 0 || _zs.avail_out == 0 ) && err == Z_OK ) {
if ( _zs.avail_out == 0 )
flushOutvec() ;
err = deflate( &_zs, Z_NO_FLUSH ) ;
}
flushOutvec() ;
// Update 'put' pointers
setp( &( _invec[ 0 ] ), &( _invec[ 0 ] ) + _invecsize ) ;
if( err != Z_OK && err != Z_STREAM_END ) {
#if defined (HAVE_STD_IOSTREAM) && defined (USE_STD_IOSTREAM)
// Throw an exception to make istream set badbit
OutputStringStream msgs ;
msgs << "Deflation failed" ;
#ifdef HAVE_ZERROR
msgs << ": " << zError( err ) ;
#endif
throw IOException( msgs.str() ) ;
#endif
cerr << "Deflation failed\n" ;
return EOF ;
}
if ( c != EOF ) {
*pptr() = c ;
pbump( 1 ) ;
}
return 0 ;
}
int DeflateOutputStreambuf::sync() {
// FIXME: Do something
// return overflow() ;
return 0 ;
}
bool DeflateOutputStreambuf::flushOutvec() {
int deflated_bytes = _outvecsize - _zs.avail_out ;
int bc = _outbuf->sputn( &( _outvec[ 0 ] ), deflated_bytes ) ;
_zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
_zs.avail_out = _outvecsize ;
return deflated_bytes == bc ;
}
void DeflateOutputStreambuf::endDeflation() {
overflow() ;
_zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
_zs.avail_out = _outvecsize ;
// Deflate until _invec is empty.
int err = Z_OK ;
while ( err == Z_OK ) {
if ( _zs.avail_out == 0 )
flushOutvec() ;
err = deflate( &_zs, Z_FINISH ) ;
}
flushOutvec() ;
if ( err != Z_STREAM_END ) {
cerr << "DeflateOutputStreambuf::endDeflation(): deflation failed:\n" ;
#ifdef HAVE_ZERROR
cerr << ": " << zError( err ) ;
#endif
cerr << endl ;
}
}
} // namespace
/** \file
Implementation of DeflateOutputStreambuf.
*/
/*
Zipios++ - a small C++ library that provides easy access to .zip files.
Copyright (C) 2000 Thomas Søndergaard
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/