inflateinputstreambuf.cpp

Go to the documentation of this file.
00001 
00002 #include "zipios-config.h"
00003 
00004 #include "meta-iostreams.h"
00005 
00006 #include <zlib.h>
00007 
00008 #include "fcollexceptions.h"
00009 #include "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 */

Generated on Wed Nov 23 19:00:18 2011 for FreeCAD by  doxygen 1.6.1