zipios++  2.0.2
Zipios++ – a small C++ library that provides easy access to .zip files.
inflateinputstreambuf.cpp
Go to the documentation of this file.
1 /*
2  Zipios++ - a small C++ library that provides easy access to .zip files.
3 
4  Copyright (C) 2000-2007 Thomas Sondergaard
5  Copyright (C) 2015 Made to Order Software Corporation
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Lesser General Public
9  License as published by the Free Software Foundation; either
10  version 2 of the License, or (at your option) any later version.
11 
12  This library is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  Lesser General Public License for more details.
16 
17  You should have received a copy of the GNU Lesser General Public
18  License along with this library; if not, write to the Free Software
19  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
31 
33 
34 #include "zipios_common.hpp"
35 
36 
37 namespace zipios
38 {
39 
70 InflateInputStreambuf::InflateInputStreambuf(std::streambuf *inbuf, offset_t start_pos)
71  : FilterInputStreambuf(inbuf)
72  , m_outvec(getBufferSize())
73  , m_invec(getBufferSize())
74  //, m_zs() -- auto-init
75  //, m_zs_initialized(false) -- auto-init
76 {
77  // NOTICE: It is important that this constructor and the methods it
78  // calls doesn't do anything with the input streambuf inbuf, other
79  // than repositioning it to the specified position. The reason is
80  // that this class can be subclassed, and the subclass should get a
81  // chance to read from the buffer first)
82 
83  // zlib init:
84  m_zs.zalloc = Z_NULL;
85  m_zs.zfree = Z_NULL;
86  m_zs.opaque = Z_NULL;
87 
88  reset(start_pos);
89  // We are not checking the return value of reset() and throwing
90  // an exception in case of an error, because we cannot catch the exception
91  // in the constructors of subclasses with all compilers.
92 }
93 
94 
100 {
101  // Dealloc z_stream stuff
102  int const err(inflateEnd(&m_zs));
103  if(err != Z_OK)
104  {
105  // in a destructor we cannot throw...
106  OutputStringStream msgs; // LCOV_EXCL_LINE
107  msgs << "InflateInputStreambuf::~InflateInputStreambuf(): inflateEnd() failed" // LCOV_EXCL_LINE
108  << ": " << zError(err); // LCOV_EXCL_LINE
113  std::cerr << msgs.str() << std::endl; // LCOV_EXCL_LINE
114  }
115 }
116 
117 
130 std::streambuf::int_type InflateInputStreambuf::underflow()
131 {
132  // If not really underflow do not fill buffer
133  // (is that really possible?!)
134  if(gptr() < egptr())
135  {
136  return traits_type::to_int_type(*gptr()); // LCOV_EXCL_LINE
137  }
138 
139  // Prepare _outvec and get array pointers
140  m_zs.avail_out = getBufferSize();
141  m_zs.next_out = reinterpret_cast<unsigned char *>(&m_outvec[0]);
142 
143  // Inflate until _outvec is full
144  // eof (or I/O prob) on _inbuf will break out of loop too.
145  int err(Z_OK);
146  while(m_zs.avail_out > 0 && err == Z_OK)
147  {
148  if(m_zs.avail_in == 0)
149  {
150  // fill m_invec
151  std::streamsize const bc(m_inbuf->sgetn(&m_invec[0], getBufferSize()));
155  m_zs.next_in = reinterpret_cast<unsigned char *>(&m_invec[0]);
156  m_zs.avail_in = bc;
157  // If we could not read any new data (bc == 0) and inflate is not
158  // done it will return Z_BUF_ERROR and thus breaks out of the
159  // loop. This means we do not have to respond to the situation
160  // where we cannot read more bytes here.
161  }
162 
163  err = inflate(&m_zs, Z_NO_FLUSH);
164  }
165 
166  // Normally the number of inflated bytes will be the
167  // full length of the output buffer, but if we can't read
168  // more input from the _inbuf streambuf, we end up with
169  // less.
170  offset_t const inflated_bytes = getBufferSize() - m_zs.avail_out;
171  setg(&m_outvec[0], &m_outvec[0], &m_outvec[0] + inflated_bytes);
172 
180  if(err != Z_OK && err != Z_STREAM_END)
181  {
182  OutputStringStream msgs;
183  msgs << "InflateInputStreambuf::underflow(): inflate failed"
184  << ": " << zError(err);
185  // Throw an exception to immediately exit to the read() or similar
186  // function and make istream set badbit
187  throw IOException(msgs.str());
188  }
189 
190  if(inflated_bytes > 0)
191  {
192  return traits_type::to_int_type(*gptr());
193  }
194 
195  return traits_type::eof();
196 }
197 
198 
199 
216 {
217  if(stream_position >= 0)
218  {
219  // reposition m_inbuf
220  m_inbuf->pubseekpos(stream_position);
221  }
222 
223  // m_zs.next_in and avail_in must be set according to
224  // zlib.h (inline doc).
225  m_zs.next_in = reinterpret_cast<Bytef *>(&m_invec[0]);
226  m_zs.avail_in = 0;
227 
228  int err(Z_OK);
229  if(m_zs_initialized)
230  {
231  // just reset it
232  err = inflateReset(&m_zs);
233  }
234  else
235  {
236  // initialize it
237  err = inflateInit2(&m_zs, -MAX_WBITS);
238  /* windowBits is passed < 0 to tell that there is no zlib header.
239  Note that in this case inflate *requires* an extra "dummy" byte
240  after the compressed stream in order to complete decompression
241  and return Z_STREAM_END. We always have an extra "dummy" byte,
242  because there is always some trailing data after the compressed
243  data (either the next entry or the central directory. */
244  m_zs_initialized = true;
245  }
246 
247  // streambuf init:
248  // The important thing here, is that
249  // - the pointers are not NULL (which would mean unbuffered)
250  // - and that gptr() is not less than egptr() (so we trigger underflow
251  // the first time data is read).
252  setg(&m_outvec[0], &m_outvec[0] + getBufferSize(), &m_outvec[0] + getBufferSize());
253 
254  return err == Z_OK;
255 }
256 
257 
258 } // zipios namespace
259 
260 // Local Variables:
261 // mode: cpp
262 // indent-tabs-mode: nil
263 // c-basic-offset: 4
264 // tab-width: 4
265 // End:
266 
267 // vim: ts=4 sw=4 et
Various exceptions used throughout the Zipios++ library, all based on zipios::Exception.
Define zipios::InflateInputStreambuf to decompress files.
bool reset(offset_t stream_position=-1)
Initializes the stream buffer.
InflateInputStreambuf(std::streambuf *inbuf, offset_t s_pos=-1)
Initialize a InflateInputStreambuf.
An IOException is used to signal an I/O error.
virtual ~InflateInputStreambuf()
Clean up the InflateInputStreambuf object.
size_t getBufferSize()
std::streamoff offset_t
Various functions used throughout the library.
std::ostringstream OutputStringStream
An output stream using strings.
virtual std::streambuf::int_type underflow() override
Called when more data is required.
A base class to develop input stream filters.