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.
Header file that defines OutputStringStream.
An input streambuf filter is a streambuf that filters the input it gets from the streambuf it is atta...
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.