zipios  2.2.0
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-2019 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.1 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
The zipios namespace includes the Zipios library definitions.
Definition: backbuffer.cpp:35
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.