0 | |
/// @author Matei David, Ontario Institute for Cancer Research
|
1 | |
/// @version 1.0
|
2 | |
/// @date 2015
|
3 | |
/// @copyright MIT Public License
|
4 | |
///
|
5 | |
/// C++ libz wrapper.
|
6 | |
///
|
7 | |
/// Reference:
|
8 | |
/// http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c
|
|
0 |
//---------------------------------------------------------
|
|
1 |
// Copyright 2015 Ontario Institute for Cancer Research
|
|
2 |
// Written by Matei David (matei@cs.toronto.edu)
|
|
3 |
//---------------------------------------------------------
|
|
4 |
|
|
5 |
// Reference:
|
|
6 |
// http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c
|
9 | 7 |
|
10 | 8 |
#ifndef __ZSTR_HPP
|
11 | 9 |
#define __ZSTR_HPP
|
|
106 | 104 |
{
|
107 | 105 |
public:
|
108 | 106 |
istreambuf(std::streambuf * _sbuf_p,
|
109 | |
std::streamsize _buff_size = default_buff_size, bool _auto_detect = true)
|
|
107 |
std::size_t _buff_size = default_buff_size, bool _auto_detect = true)
|
110 | 108 |
: sbuf_p(_sbuf_p),
|
111 | 109 |
zstrm_p(nullptr),
|
112 | 110 |
buff_size(_buff_size),
|
|
152 | 150 |
if (in_buff_end == in_buff_start) break; // end of input
|
153 | 151 |
}
|
154 | 152 |
// auto detect if the stream contains text or deflate data
|
155 | |
if (auto_detect and not auto_detect_run)
|
|
153 |
if (auto_detect && ! auto_detect_run)
|
156 | 154 |
{
|
157 | 155 |
auto_detect_run = true;
|
158 | 156 |
unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
|
|
160 | 158 |
// Ref:
|
161 | 159 |
// http://en.wikipedia.org/wiki/Gzip
|
162 | 160 |
// http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
|
163 | |
is_text = not (in_buff_start + 2 <= in_buff_end
|
164 | |
and ((b0 == 0x1F and b1 == 0x8B) // gzip header
|
165 | |
or (b0 == 0x78 and (b1 == 0x01 // zlib header
|
166 | |
or b1 == 0x9C
|
167 | |
or b1 == 0xDA))));
|
|
161 |
is_text = ! (in_buff_start + 2 <= in_buff_end
|
|
162 |
&& ((b0 == 0x1F && b1 == 0x8B) // gzip header
|
|
163 |
|| (b0 == 0x78 && (b1 == 0x01 // zlib header
|
|
164 |
|| b1 == 0x9C
|
|
165 |
|| b1 == 0xDA))));
|
168 | 166 |
}
|
169 | 167 |
if (is_text)
|
170 | 168 |
{
|
|
178 | 176 |
else
|
179 | 177 |
{
|
180 | 178 |
// run inflate() on input
|
181 | |
if (not zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
|
|
179 |
if (! zstrm_p) zstrm_p = new detail::z_stream_wrapper(true);
|
182 | 180 |
zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
|
183 | 181 |
zstrm_p->avail_in = in_buff_end - in_buff_start;
|
184 | 182 |
zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
|
185 | 183 |
zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
|
186 | 184 |
int ret = inflate(zstrm_p, Z_NO_FLUSH);
|
187 | 185 |
// process return code
|
188 | |
if (ret != Z_OK and ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
|
|
186 |
if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p, ret);
|
189 | 187 |
// update in&out pointers following inflate()
|
190 | 188 |
in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
|
191 | 189 |
in_buff_end = in_buff_start + zstrm_p->avail_in;
|
|
215 | 213 |
char * in_buff_end;
|
216 | 214 |
char * out_buff;
|
217 | 215 |
detail::z_stream_wrapper * zstrm_p;
|
218 | |
std::streamsize buff_size;
|
|
216 |
std::size_t buff_size;
|
219 | 217 |
bool auto_detect;
|
220 | 218 |
bool auto_detect_run;
|
221 | 219 |
bool is_text;
|
222 | 220 |
|
223 | |
static const std::streamsize default_buff_size = 1 << 20;
|
|
221 |
static const std::size_t default_buff_size = (std::size_t)1 << 20;
|
224 | 222 |
}; // class istreambuf
|
225 | 223 |
|
226 | 224 |
class ostreambuf
|
|
228 | 226 |
{
|
229 | 227 |
public:
|
230 | 228 |
ostreambuf(std::streambuf * _sbuf_p,
|
231 | |
std::streamsize _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION)
|
|
229 |
std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION)
|
232 | 230 |
: sbuf_p(_sbuf_p),
|
233 | 231 |
zstrm_p(new detail::z_stream_wrapper(false, _level)),
|
234 | 232 |
buff_size(_buff_size)
|
|
251 | 249 |
zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff);
|
252 | 250 |
zstrm_p->avail_out = buff_size;
|
253 | 251 |
int ret = deflate(zstrm_p, flush);
|
254 | |
if (ret != Z_OK and ret != Z_STREAM_END and ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret);
|
|
252 |
if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) throw Exception(zstrm_p, ret);
|
255 | 253 |
std::streamsize sz = sbuf_p->sputn(out_buff, reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff);
|
256 | 254 |
if (sz != reinterpret_cast< decltype(out_buff) >(zstrm_p->next_out) - out_buff)
|
257 | 255 |
{
|
258 | 256 |
// there was an error in the sink stream
|
259 | 257 |
return -1;
|
260 | 258 |
}
|
261 | |
if (ret == Z_STREAM_END or ret == Z_BUF_ERROR or sz == 0)
|
|
259 |
if (ret == Z_STREAM_END || ret == Z_BUF_ERROR || sz == 0)
|
262 | 260 |
{
|
263 | 261 |
break;
|
264 | 262 |
}
|
|
301 | 299 |
{
|
302 | 300 |
// first, call overflow to clear in_buff
|
303 | 301 |
overflow();
|
304 | |
if (not pptr()) return -1;
|
|
302 |
if (! pptr()) return -1;
|
305 | 303 |
// then, call deflate asking to finish the zlib stream
|
306 | 304 |
zstrm_p->next_in = nullptr;
|
307 | 305 |
zstrm_p->avail_in = 0;
|
|
314 | 312 |
char * in_buff;
|
315 | 313 |
char * out_buff;
|
316 | 314 |
detail::z_stream_wrapper * zstrm_p;
|
317 | |
std::streamsize buff_size;
|
318 | |
|
319 | |
static const std::streamsize default_buff_size = 1 << 20;
|
|
315 |
std::size_t buff_size;
|
|
316 |
|
|
317 |
static const std::size_t default_buff_size = (std::size_t)1 << 20;
|
320 | 318 |
}; // class ostreambuf
|
321 | 319 |
|
322 | 320 |
class istream
|