Zipios++
inflateinputstreambuf.cpp
Go to the documentation of this file.
1 
2 #include "zipios++/zipios-config.h"
3 
4 #include "zipios++/meta-iostreams.h"
5 
6 #include <zlib.h>
7 
10 
11 #include "outputstringstream.h"
12 
13 namespace zipios {
14 
15 using std::cerr ;
16 using std::endl ;
17 
18 InflateInputStreambuf::InflateInputStreambuf( streambuf *inbuf, int s_pos, bool del_inbuf )
19  : FilterInputStreambuf( inbuf, del_inbuf ),
20  _zs_initialized ( false ),
21  _invecsize ( 1000 ),
22  _invec ( _invecsize ),
23  _outvecsize ( 1000 ),
24  _outvec ( _outvecsize )
25 {
26  // NOTICE: It is important that this constructor and the methods it
27  // calls doesn't do anything with the input streambuf _inbuf, other
28  // than repositioning it to the specified position. The reason is
29  // that this class can be subclassed, and the subclass should get a
30  // chance to read from the buffer first)
31 
32  // zlib init:
33  _zs.zalloc = Z_NULL ;
34  _zs.zfree = Z_NULL ;
35  _zs.opaque = Z_NULL ;
36 
37  reset( s_pos ) ;
38  // We're not checking the return value of reset() and throwing
39  // an exception in case of an error, because we cannot catch the exception
40  // in the constructors of subclasses with all compilers.
41 }
42 
43 InflateInputStreambuf::~InflateInputStreambuf() {
44  // Dealloc z_stream stuff
45  int err = inflateEnd( &_zs ) ;
46  if( err != Z_OK ) {
47  cerr << "~inflatebuf: inflateEnd failed" ;
48 #ifdef HAVE_ZERROR
49  cerr << ": " << zError( err ) ;
50 #endif
51  cerr << endl ;
52  }
53 }
54 
55 
56 int InflateInputStreambuf::underflow() {
57  // If not underflow don't fill buffer
58  if ( gptr() < egptr() )
59  return static_cast< unsigned char >( *gptr() ) ;
60 
61  // Prepare _outvec and get array pointers
62  _zs.avail_out = _outvecsize ;
63  _zs.next_out = reinterpret_cast< unsigned char * >( &( _outvec[ 0 ] ) ) ;
64 
65  // Inflate until _outvec is full
66  // eof (or I/O prob) on _inbuf will break out of loop too.
67  int err = Z_OK ;
68  while ( _zs.avail_out > 0 && err == Z_OK ) {
69  if ( _zs.avail_in == 0 ) { // fill _invec
70  int bc = _inbuf->sgetn( &(_invec[ 0 ] ) ,
71  _invecsize ) ;
72  // FIXME: handle i/o problems.
73  _zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ;
74  _zs.avail_in = bc ;
75  // If we could not read any new data (bc == 0) and inflate isn't
76  // done it will return Z_BUF_ERROR and thus breaks out of the
77  // loop. This means we don't have to respond to the situation
78  // where we can't read more bytes here.
79  }
80 
81  err = inflate( &_zs, Z_NO_FLUSH ) ;
82  }
83  // Normally the number of inflated bytes will be the
84  // full length of the output buffer, but if we can't read
85  // more input from the _inbuf streambuf, we end up with
86  // less.
87  int inflated_bytes = _outvecsize - _zs.avail_out ;
88  setg( &( _outvec[ 0 ] ),
89  &( _outvec[ 0 ] ),
90  &( _outvec[ 0 ] ) + inflated_bytes ) ;
91  // FIXME: look at the error returned from inflate here, if there is
92  // some way to report it to the InflateInputStreambuf user.
93  // Until I find out I'll just print a warning to stdout.
94  if( err != Z_OK && err != Z_STREAM_END ) {
95 #if defined (HAVE_STD_IOSTREAM) && defined (USE_STD_IOSTREAM)
96  // Throw an exception to make istream set badbit
97  OutputStringStream msgs ;
98  msgs << "InflateInputStreambuf: inflate failed" ;
99 #ifdef HAVE_ZERROR
100  msgs << ": " << zError( err ) ;
101 #endif
102  throw IOException( msgs.str() ) ;
103 #endif
104  // If HAVE_STD_IOSTREAM not defined we just return eof
105  // if no output is produced, and that happens anyway
106  }
107  if (inflated_bytes > 0 )
108  return static_cast< unsigned char >( *gptr() ) ;
109  else
110  return EOF ; // traits_type::eof() ;
111 }
112 
113 
114 
115 // This method is called in the constructor, so it must not
116 // read anything from the input streambuf _inbuf (see notice in constructor)
117 bool InflateInputStreambuf::reset( int stream_position ) {
118  if ( stream_position >= 0 ) { // reposition _inbuf
119  _inbuf->pubseekpos( stream_position ) ;
120  }
121 
122  // _zs.next_in and avail_in must be set according to
123  // zlib.h (inline doc).
124  _zs.next_in = reinterpret_cast< unsigned char * >( &( _invec[0] ) ) ;
125  _zs.avail_in = 0 ;
126 
127  int err ;
128  if( _zs_initialized ) { // just reset it
129  err = inflateReset( &_zs ) ;
130  } else { // init it
131  err = inflateInit2( &_zs, -MAX_WBITS ) ;
132  /* windowBits is passed < 0 to tell that there is no zlib header.
133  Note that in this case inflate *requires* an extra "dummy" byte
134  after the compressed stream in order to complete decompression
135  and return Z_STREAM_END. We always have an extra "dummy" byte,
136  because there is always some trailing data after the compressed
137  data (either the next entry or the central directory. */
138  _zs_initialized = true ;
139  }
140 
141  // streambuf init:
142  // The important thing here, is that
143  // - the pointers are not NULL (which would mean unbuffered)
144  // - and that gptr() is not less than egptr() (so we trigger underflow
145  // the first time data is read).
146  setg( &( _outvec[ 0 ] ),
147  &( _outvec[ 0 ] ) + _outvecsize,
148  &( _outvec[ 0 ] ) + _outvecsize ) ;
149 
150  if ( err == Z_OK )
151  return true ;
152  else
153  return false ;
154 }
155 
156 } // namespace
157 
162 /*
163  Zipios++ - a small C++ library that provides easy access to .zip files.
164  Copyright (C) 2000 Thomas Søndergaard
165 
166  This library is free software; you can redistribute it and/or
167  modify it under the terms of the GNU Lesser General Public
168  License as published by the Free Software Foundation; either
169  version 2 of the License, or (at your option) any later version.
170 
171  This library is distributed in the hope that it will be useful,
172  but WITHOUT ANY WARRANTY; without even the implied warranty of
173  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
174  Lesser General Public License for more details.
175 
176  You should have received a copy of the GNU Lesser General Public
177  License along with this library; if not, write to the Free Software
178  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
179 */
Header file that defines InflateInputStreambuf.
bool reset(int stream_position=-1)
Resets the zlib stream and purges input and output buffers.
OutputStringStream is typedefed to ostringstream if sstream is part of the standard library (unless Z...
Header file that defines OutputStringStream.
An input streambuf filter is a streambuf that filters the input it gets from the streambuf it is atta...
An IOException is used to signal an I/O error.
string str()
Specialization of ostrstream::str() that takes care of null-terminating the string and unfreezing the...
Header file that defines a number of exceptions used by FileCollection and its subclasses.
InflateInputStreambuf(streambuf *inbuf, int s_pos=-1, bool del_inbuf=false)
InflateInputStreambuf constructor.