Mercurial > audlegacy-plugins
diff src/console/Zlib_Inflater.cxx @ 341:986f098da058 trunk
[svn] - merge in blargg's changes
author | nenolod |
---|---|
date | Thu, 07 Dec 2006 15:20:41 -0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/console/Zlib_Inflater.cxx Thu Dec 07 15:20:41 2006 -0800 @@ -0,0 +1,175 @@ +// File_Extractor 0.4.0. http://www.slack.net/~ant/ + +#include "Zlib_Inflater.h" + +#include <assert.h> +#include <string.h> + +/* Copyright (C) 2006 Shay Green. This module 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.1 of the License, or (at your option) any later version. This +module 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 module; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ + +#include "blargg_source.h" + +static const char* get_zlib_err( int code ) +{ + assert( code != Z_OK ); + if ( code == Z_MEM_ERROR ) + return "Out of memory"; + + const char* str = zError( code ); + if ( code == Z_DATA_ERROR ) + str = "Zip data is corrupt"; + if ( !str ) + str = "Zip error"; + return str; +} + +void Zlib_Inflater::end() +{ + if ( deflated_ ) + { + deflated_ = false; + if ( inflateEnd( &zbuf ) ) + check( false ); + } + buf.clear(); + + static z_stream const empty = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + memcpy( &zbuf, &empty, sizeof zbuf ); +} + +Zlib_Inflater::Zlib_Inflater() +{ + deflated_ = false; + end(); // initialize things +} + +Zlib_Inflater::~Zlib_Inflater() +{ + end(); +} + +blargg_err_t Zlib_Inflater::begin( mode_t mode, callback_t callback, void* user_data, + long buf_size ) +{ + end(); + + if ( buf_size && buf.resize( buf_size ) ) + buf_size = 0; // not enough memory for requested size, so use default + + if ( !buf_size ) + RETURN_ERR( buf.resize( 16 * 1024L ) ); + + // Fill buffer with some data, less than normal buffer size since caller might + // just be examining beginning of file. 4K is a common disk block size. + long count = (buf_size ? buf_size : 4096); + RETURN_ERR( callback( user_data, buf.begin(), &count ) ); + zbuf.avail_in = count; + zbuf.next_in = buf.begin(); + + if ( mode == mode_auto ) + { + // examine buffer for gzip header + mode = mode_copy; + int const min_gzip_size = 2 + 8 + 8; + if ( count >= min_gzip_size && buf [0] == 0x1F && buf [1] == 0x8B ) + mode = mode_ungz; + } + + if ( mode != mode_copy ) + { + int wb = MAX_WBITS + 16; // have zlib handle gzip header + if ( mode == mode_raw_deflate ) + wb = -MAX_WBITS; + + int zerr = inflateInit2( &zbuf, wb ); + if ( zerr ) + return get_zlib_err( zerr ); + + deflated_ = true; + } + return 0; +} + + +blargg_err_t Zlib_Inflater::read( void* out, long* count_io, + callback_t callback, void* user_data ) +{ + if ( !*count_io ) + return 0; + + if ( !deflated_ ) + { + // copy buffered data + long first = zbuf.avail_in; + if ( first ) + { + if ( first > *count_io ) + first = *count_io; + memcpy( out, zbuf.next_in, first ); + zbuf.next_in += first; + zbuf.avail_in -= first; + if ( !zbuf.avail_in ) + buf.clear(); // done with buffer + } + + // read remaining directly + long second = *count_io - first; + if ( second ) + { + long actual = second; + RETURN_ERR( callback( user_data, (char*) out + first, &actual ) ); + *count_io -= second - actual; + } + } + else + { + zbuf.next_out = (Bytef*) out; + zbuf.avail_out = *count_io; + + while ( 1 ) + { + uInt old_avail_in = zbuf.avail_in; + int err = inflate( &zbuf, Z_NO_FLUSH ); + if ( err == Z_STREAM_END ) + { + *count_io -= zbuf.avail_out; + end(); + break; // all data deflated + } + + if ( err == Z_BUF_ERROR && !old_avail_in ) + err = 0; // we just need to provide more input + + if ( err ) + return get_zlib_err( err ); + + if ( !zbuf.avail_out ) + break; // requested number of bytes deflated + + if ( zbuf.avail_in ) + { + // inflate() should never leave input if there's still space for output + assert( false ); + return "Corrupt zip data"; + } + + // refill buffer + long count = buf.size(); + RETURN_ERR( callback( user_data, buf.begin(), &count ) ); + zbuf.next_in = buf.begin(); + zbuf.avail_in = count; + if ( !zbuf.avail_in ) + return "Corrupt zip data"; // stream didn't end but there's no more data + } + } + return 0; +}