zipios  2.3.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-2022 Made to Order Software Corp. All Rights Reserved
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 {
75  // NOTICE: It is important that this constructor and the methods it
76  // calls doesn't do anything with the input streambuf inbuf, other
77  // than repositioning it to the specified \p start_pos. The reason is
78  // that this class can be sub-classed, and the sub-class should get a
79  // chance to read from the buffer first
80 
81  reset(start_pos);
82  // We are not checking the return value of reset() and throwing
83  // an exception in case of an error, because we cannot catch the
84  // exception in the constructors of sub-classes with all compilers.
85 }
86 
87 
93 {
94  // Dealloc z_stream stuff
95  int const err(inflateEnd(&m_zs));
96  if(err != Z_OK)
97  {
98  // in a destructor we cannot throw...
99  OutputStringStream msgs; // LCOV_EXCL_LINE
100  msgs << "InflateInputStreambuf::~InflateInputStreambuf(): inflateEnd() failed" // LCOV_EXCL_LINE
101  << ": " << zError(err); // LCOV_EXCL_LINE
106  std::cerr << msgs.str() << std::endl; // LCOV_EXCL_LINE
107  }
108 }
109 
110 
123 std::streambuf::int_type InflateInputStreambuf::underflow()
124 {
125  // If not really underflow do not fill buffer
126  // (is that really possible?!)
127  if(gptr() < egptr())
128  {
129  return traits_type::to_int_type(*gptr()); // LCOV_EXCL_LINE
130  }
131 
132  // Prepare _outvec and get array pointers
133  m_zs.avail_out = getBufferSize();
134  m_zs.next_out = reinterpret_cast<unsigned char *>(&m_outvec[0]);
135 
136  // Inflate until _outvec is full
137  // eof (or I/O prob) on _inbuf will break out of loop too.
138  int err(Z_OK);
139  while(m_zs.avail_out > 0 && err == Z_OK)
140  {
141  if(m_zs.avail_in == 0)
142  {
143  // fill m_invec
144  std::streamsize const bc(m_inbuf->sgetn(&m_invec[0], getBufferSize()));
148  m_zs.next_in = reinterpret_cast<unsigned char *>(&m_invec[0]);
149  m_zs.avail_in = bc;
150  // If we could not read any new data (bc == 0) and inflate is not
151  // done it will return Z_BUF_ERROR and thus breaks out of the
152  // loop. This means we do not have to respond to the situation
153  // where we cannot read more bytes here.
154  }
155 
156  err = inflate(&m_zs, Z_NO_FLUSH);
157  }
158 
159  // Normally the number of inflated bytes will be the
160  // full length of the output buffer, but if we can't read
161  // more input from the _inbuf streambuf, we end up with
162  // less.
163  offset_t const inflated_bytes = getBufferSize() - m_zs.avail_out;
164  setg(&m_outvec[0], &m_outvec[0], &m_outvec[0] + inflated_bytes);
165 
173  if(err != Z_OK && err != Z_STREAM_END)
174  {
175  OutputStringStream msgs;
176  msgs << "InflateInputStreambuf::underflow(): inflate failed"
177  << ": " << zError(err);
178  // Throw an exception to immediately exit to the read() or similar
179  // function and make istream set badbit
180  throw IOException(msgs.str());
181  }
182 
183  if(inflated_bytes > 0)
184  {
185  return traits_type::to_int_type(*gptr());
186  }
187 
188  return traits_type::eof();
189 }
190 
191 
192 
209 {
210  if(stream_position >= 0)
211  {
212  // reposition m_inbuf
213  m_inbuf->pubseekpos(stream_position);
214  }
215 
216  // m_zs.next_in and avail_in must be set according to
217  // zlib.h (inline doc).
218  m_zs.next_in = reinterpret_cast<Bytef *>(&m_invec[0]);
219  m_zs.avail_in = 0;
220 
221  int err(Z_OK);
222  if(m_zs_initialized)
223  {
224  // just reset it
225  err = inflateReset(&m_zs);
226  }
227  else
228  {
229  // initialize it
230  err = inflateInit2(&m_zs, -MAX_WBITS);
231  /* windowBits is passed < 0 to tell that there is no zlib header.
232  Note that in this case inflate *requires* an extra "dummy" byte
233  after the compressed stream in order to complete decompression
234  and return Z_STREAM_END. We always have an extra "dummy" byte,
235  because there is always some trailing data after the compressed
236  data (either the next entry or the central directory. */
237  m_zs_initialized = true;
238  }
239 
240  // streambuf init:
241  // The important thing here, is that
242  // - the pointers are not NULL (which would mean unbuffered)
243  // - and that gptr() is not less than egptr() (so we trigger underflow
244  // the first time data is read).
245  setg(&m_outvec[0], &m_outvec[0] + getBufferSize(), &m_outvec[0] + getBufferSize());
246 
247  return err == Z_OK;
248 }
249 
250 
251 } // zipios namespace
252 
253 // Local Variables:
254 // mode: cpp
255 // indent-tabs-mode: nil
256 // c-basic-offset: 4
257 // tab-width: 4
258 // End:
259 
260 // 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.