Zipios++
|
00001 00002 #include "zipios++/zipios-config.h" 00003 00004 #include "zipios++/meta-iostreams.h" 00005 00006 #include <zlib.h> 00007 00008 #include "zipios++/fcollexceptions.h" 00009 #include "zipios++/inflateinputstreambuf.h" 00010 00011 #include "outputstringstream.h" 00012 00013 namespace zipios { 00014 00015 using std::cerr ; 00016 using std::endl ; 00017 00018 InflateInputStreambuf::InflateInputStreambuf( streambuf *inbuf, int s_pos, bool del_inbuf ) 00019 : FilterInputStreambuf( inbuf, del_inbuf ), 00020 _zs_initialized ( false ), 00021 _invecsize ( 1000 ), 00022 _invec ( _invecsize ), 00023 _outvecsize ( 1000 ), 00024 _outvec ( _outvecsize ) 00025 { 00026 // NOTICE: It is important that this constructor and the methods it 00027 // calls doesn't do anything with the input streambuf _inbuf, other 00028 // than repositioning it to the specified position. The reason is 00029 // that this class can be subclassed, and the subclass should get a 00030 // chance to read from the buffer first) 00031 00032 // zlib init: 00033 _zs.zalloc = Z_NULL ; 00034 _zs.zfree = Z_NULL ; 00035 _zs.opaque = Z_NULL ; 00036 00037 reset( s_pos ) ; 00038 // We're not checking the return value of reset() and throwing 00039 // an exception in case of an error, because we cannot catch the exception 00040 // in the constructors of subclasses with all compilers. 00041 } 00042 00043 InflateInputStreambuf::~InflateInputStreambuf() { 00044 // Dealloc z_stream stuff 00045 int err = inflateEnd( &_zs ) ; 00046 if( err != Z_OK ) { 00047 cerr << "~inflatebuf: inflateEnd failed" ; 00048 #ifdef HAVE_ZERROR 00049 cerr << ": " << zError( err ) ; 00050 #endif 00051 cerr << endl ; 00052 } 00053 } 00054 00055 00056 int InflateInputStreambuf::underflow() { 00057 // If not underflow don't fill buffer 00058 if ( gptr() < egptr() ) 00059 return static_cast< unsigned char >( *gptr() ) ; 00060 00061 // Prepare _outvec and get array pointers 00062 _zs.avail_out = _outvecsize ; 00063 _zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ; 00064 00065 // Inflate until _outvec is full 00066 // eof (or I/O prob) on _inbuf will break out of loop too. 00067 int err = Z_OK ; 00068 while ( _zs.avail_out > 0 && err == Z_OK ) { 00069 if ( _zs.avail_in == 0 ) { // fill _invec 00070 int bc = _inbuf->sgetn( &(_invec[ 0 ] ) , 00071 _invecsize ) ; 00072 // FIXME: handle i/o problems. 00073 _zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ; 00074 _zs.avail_in = bc ; 00075 // If we could not read any new data (bc == 0) and inflate isn't 00076 // done it will return Z_BUF_ERROR and thus breaks out of the 00077 // loop. This means we don't have to respond to the situation 00078 // where we can't read more bytes here. 00079 } 00080 00081 err = inflate( &_zs, Z_NO_FLUSH ) ; 00082 } 00083 // Normally the number of inflated bytes will be the 00084 // full length of the output buffer, but if we can't read 00085 // more input from the _inbuf streambuf, we end up with 00086 // less. 00087 int inflated_bytes = _outvecsize - _zs.avail_out ; 00088 setg( &( _outvec[ 0 ] ), 00089 &( _outvec[ 0 ] ), 00090 &( _outvec[ 0 ] ) + inflated_bytes ) ; 00091 // FIXME: look at the error returned from inflate here, if there is 00092 // some way to report it to the InflateInputStreambuf user. 00093 // Until I find out I'll just print a warning to stdout. 00094 if( err != Z_OK && err != Z_STREAM_END ) { 00095 #if defined (HAVE_STD_IOSTREAM) && defined (USE_STD_IOSTREAM) 00096 // Throw an exception to make istream set badbit 00097 OutputStringStream msgs ; 00098 msgs << "InflateInputStreambuf: inflate failed" ; 00099 #ifdef HAVE_ZERROR 00100 msgs << ": " << zError( err ) ; 00101 #endif 00102 throw IOException( msgs.str() ) ; 00103 #endif 00104 // If HAVE_STD_IOSTREAM not defined we just return eof 00105 // if no output is produced, and that happens anyway 00106 } 00107 if (inflated_bytes > 0 ) 00108 return static_cast< unsigned char >( *gptr() ) ; 00109 else 00110 return EOF ; // traits_type::eof() ; 00111 } 00112 00113 00114 00115 // This method is called in the constructor, so it must not 00116 // read anything from the input streambuf _inbuf (see notice in constructor) 00117 bool InflateInputStreambuf::reset( int stream_position ) { 00118 if ( stream_position >= 0 ) { // reposition _inbuf 00119 _inbuf->pubseekpos( stream_position ) ; 00120 } 00121 00122 // _zs.next_in and avail_in must be set according to 00123 // zlib.h (inline doc). 00124 _zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ; 00125 _zs.avail_in = 0 ; 00126 00127 int err ; 00128 if( _zs_initialized ) { // just reset it 00129 err = inflateReset( &_zs ) ; 00130 } else { // init it 00131 err = inflateInit2( &_zs, -MAX_WBITS ) ; 00132 /* windowBits is passed < 0 to tell that there is no zlib header. 00133 Note that in this case inflate *requires* an extra "dummy" byte 00134 after the compressed stream in order to complete decompression 00135 and return Z_STREAM_END. We always have an extra "dummy" byte, 00136 because there is always some trailing data after the compressed 00137 data (either the next entry or the central directory. */ 00138 _zs_initialized = true ; 00139 } 00140 00141 // streambuf init: 00142 // The important thing here, is that 00143 // - the pointers are not NULL (which would mean unbuffered) 00144 // - and that gptr() is not less than egptr() (so we trigger underflow 00145 // the first time data is read). 00146 setg( &( _outvec[ 0 ] ), 00147 &( _outvec[ 0 ] ) + _outvecsize, 00148 &( _outvec[ 0 ] ) + _outvecsize ) ; 00149 00150 if ( err == Z_OK ) 00151 return true ; 00152 else 00153 return false ; 00154 } 00155 00156 } // namespace 00157 00162 /* 00163 Zipios++ - a small C++ library that provides easy access to .zip files. 00164 Copyright (C) 2000 Thomas Søndergaard 00165 00166 This library is free software; you can redistribute it and/or 00167 modify it under the terms of the GNU Lesser General Public 00168 License as published by the Free Software Foundation; either 00169 version 2 of the License, or (at your option) any later version. 00170 00171 This library is distributed in the hope that it will be useful, 00172 but WITHOUT ANY WARRANTY; without even the implied warranty of 00173 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00174 Lesser General Public License for more details. 00175 00176 You should have received a copy of the GNU Lesser General Public 00177 License along with this library; if not, write to the Free Software 00178 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00179 */