Eclipse SUMO - Simulation of Urban MObility
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
zstr.hpp
Go to the documentation of this file.
1//---------------------------------------------------------
2// Copyright 2015 Ontario Institute for Cancer Research
3// Written by Matei David (matei@cs.toronto.edu)
4//---------------------------------------------------------
5
6// Reference:
7// http://stackoverflow.com/questions/14086417/how-to-write-custom-input-stream-in-c
8
9#pragma once
10
11#include <cassert>
12#include <cstdint>
13#include <fstream>
14#include <sstream>
15#include <zlib.h>
16#include <memory>
17#include <iostream>
18#include "strict_fstream.hpp"
19
20#if defined(__GNUC__) && !defined(__clang__)
21#if (__GNUC__ > 5) || (__GNUC__ == 5 && __GNUC_MINOR__>0)
22#define CAN_MOVE_IOSTREAM
23#endif
24#else
25#define CAN_MOVE_IOSTREAM
26#endif
27
28namespace zstr
29{
30
31static const std::size_t default_buff_size = static_cast<std::size_t>(1 << 20);
32
35 : public std::ios_base::failure
36{
37public:
38 static std::string error_to_message(z_stream * zstrm_p, int ret)
39 {
40 std::string msg = "zlib: ";
41 switch (ret)
42 {
43 case Z_STREAM_ERROR:
44 msg += "Z_STREAM_ERROR: ";
45 break;
46 case Z_DATA_ERROR:
47 msg += "Z_DATA_ERROR: ";
48 break;
49 case Z_MEM_ERROR:
50 msg += "Z_MEM_ERROR: ";
51 break;
52 case Z_VERSION_ERROR:
53 msg += "Z_VERSION_ERROR: ";
54 break;
55 case Z_BUF_ERROR:
56 msg += "Z_BUF_ERROR: ";
57 break;
58 default:
59 std::ostringstream oss;
60 oss << ret;
61 msg += "[" + oss.str() + "]: ";
62 break;
63 }
64 if (zstrm_p->msg) {
65 msg += zstrm_p->msg;
66 }
67 msg += " ("
68 "next_in: " +
69 std::to_string(uintptr_t(zstrm_p->next_in)) +
70 ", avail_in: " +
71 std::to_string(uintptr_t(zstrm_p->avail_in)) +
72 ", next_out: " +
73 std::to_string(uintptr_t(zstrm_p->next_out)) +
74 ", avail_out: " +
75 std::to_string(uintptr_t(zstrm_p->avail_out)) +
76 ")";
77 return msg;
78 }
79
80 Exception(z_stream * zstrm_p, int ret)
81 : std::ios_base::failure(error_to_message(zstrm_p, ret))
82 {
83 }
84}; // class Exception
85
86namespace detail
87{
88
90 : public z_stream
91{
92public:
93 z_stream_wrapper(bool _is_input, int _level, int _window_bits)
94 : is_input(_is_input)
95 {
96 this->zalloc = nullptr;//Z_NULL
97 this->zfree = nullptr;//Z_NULL
98 this->opaque = nullptr;//Z_NULL
99 int ret;
100 if (is_input)
101 {
102 this->avail_in = 0;
103 this->next_in = nullptr;//Z_NULL
104 ret = inflateInit2(this, _window_bits ? _window_bits : 15+32);
105 }
106 else
107 {
108 ret = deflateInit2(this, _level, Z_DEFLATED, _window_bits ? _window_bits : 15+16, 8, Z_DEFAULT_STRATEGY);
109 }
110 if (ret != Z_OK) throw Exception(this, ret);
111 }
113 {
114 if (is_input)
115 {
116 inflateEnd(this);
117 }
118 else
119 {
120 deflateEnd(this);
121 }
122 }
123private:
125}; // class z_stream_wrapper
126
127} // namespace detail
128
130 : public std::streambuf
131{
132public:
133 istreambuf(std::streambuf * _sbuf_p,
134 std::size_t _buff_size = default_buff_size, bool _auto_detect = true, int _window_bits = 0)
135 : sbuf_p(_sbuf_p),
136 in_buff(),
137 in_buff_start(nullptr),
138 in_buff_end(nullptr),
139 out_buff(),
140 zstrm_p(nullptr),
141 buff_size(_buff_size),
142 auto_detect(_auto_detect),
143 auto_detect_run(false),
144 is_text(false),
145 window_bits(_window_bits)
146 {
147 assert(sbuf_p);
148 in_buff = std::unique_ptr<char[]>(new char[buff_size]);
149 in_buff_start = in_buff.get();
150 in_buff_end = in_buff.get();
151 out_buff = std::unique_ptr<char[]>(new char[buff_size]);
152 setg(out_buff.get(), out_buff.get(), out_buff.get());
153 }
154
155 istreambuf(const istreambuf &) = delete;
156 istreambuf & operator = (const istreambuf &) = delete;
157
158 pos_type seekoff(off_type off, std::ios_base::seekdir dir,
159 std::ios_base::openmode which) override
160 {
161 if (off != 0 || dir != std::ios_base::cur) {
162 return std::streambuf::seekoff(off, dir, which);
163 }
164
165 if (!zstrm_p) {
166 return 0;
167 }
168
169 return static_cast<long int>(zstrm_p->total_out - static_cast<uLong>(in_avail()));
170 }
171
172 std::streambuf::int_type underflow() override
173 {
174 if (this->gptr() == this->egptr())
175 {
176 // pointers for free region in output buffer
177 char * out_buff_free_start = out_buff.get();
178 int tries = 0;
179 do
180 {
181 if (++tries > 1000) {
182 throw std::ios_base::failure("Failed to fill buffer after 1000 tries");
183 }
184
185 // read more input if none available
187 {
188 // empty input buffer: refill from the start
189 in_buff_start = in_buff.get();
190 std::streamsize sz = sbuf_p->sgetn(in_buff.get(), static_cast<std::streamsize>(buff_size));
192 if (in_buff_end == in_buff_start) break; // end of input
193 }
194 // auto detect if the stream contains text or deflate data
196 {
197 auto_detect_run = true;
198 unsigned char b0 = *reinterpret_cast< unsigned char * >(in_buff_start);
199 unsigned char b1 = *reinterpret_cast< unsigned char * >(in_buff_start + 1);
200 // Ref:
201 // http://en.wikipedia.org/wiki/Gzip
202 // http://stackoverflow.com/questions/9050260/what-does-a-zlib-header-look-like
204 && ((b0 == 0x1F && b1 == 0x8B) // gzip header
205 || (b0 == 0x78 && (b1 == 0x01 // zlib header
206 || b1 == 0x9C
207 || b1 == 0xDA))));
208 }
209 if (is_text)
210 {
211 // simply swap in_buff and out_buff, and adjust pointers
212 assert(in_buff_start == in_buff.get());
214 out_buff_free_start = in_buff_end;
215 in_buff_start = in_buff.get();
216 in_buff_end = in_buff.get();
217 }
218 else
219 {
220 // run inflate() on input
221 if (! zstrm_p) zstrm_p = std::unique_ptr<detail::z_stream_wrapper>(new detail::z_stream_wrapper(true, Z_DEFAULT_COMPRESSION, window_bits));
222 zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(in_buff_start);
223 zstrm_p->avail_in = uint32_t(in_buff_end - in_buff_start);
224 zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff_free_start);
225 zstrm_p->avail_out = uint32_t((out_buff.get() + buff_size) - out_buff_free_start);
226 int ret = inflate(zstrm_p.get(), Z_NO_FLUSH);
227 // process return code
228 if (ret != Z_OK && ret != Z_STREAM_END) throw Exception(zstrm_p.get(), ret);
229 // update in&out pointers following inflate()
230 in_buff_start = reinterpret_cast< decltype(in_buff_start) >(zstrm_p->next_in);
231 in_buff_end = in_buff_start + zstrm_p->avail_in;
232 out_buff_free_start = reinterpret_cast< decltype(out_buff_free_start) >(zstrm_p->next_out);
233 assert(out_buff_free_start + zstrm_p->avail_out == out_buff.get() + buff_size);
234
235 if (ret == Z_STREAM_END) {
236 // if stream ended, deallocate inflator
237 zstrm_p.reset();
238 }
239 }
240 } while (out_buff_free_start == out_buff.get());
241 // 2 exit conditions:
242 // - end of input: there might or might not be output available
243 // - out_buff_free_start != out_buff: output available
244 this->setg(out_buff.get(), out_buff.get(), out_buff_free_start);
245 }
246 return this->gptr() == this->egptr()
247 ? traits_type::eof()
248 : traits_type::to_int_type(*this->gptr());
249 }
250private:
251 std::streambuf * sbuf_p;
252 std::unique_ptr<char[]> in_buff;
255 std::unique_ptr<char[]> out_buff;
256 std::unique_ptr<detail::z_stream_wrapper> zstrm_p;
257 std::size_t buff_size;
262
263}; // class istreambuf
264
266 : public std::streambuf
267{
268public:
269 ostreambuf(std::streambuf * _sbuf_p,
270 std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION, int _window_bits = 0)
271 : sbuf_p(_sbuf_p),
272 in_buff(),
273 out_buff(),
274 zstrm_p(new detail::z_stream_wrapper(false, _level, _window_bits)),
275 buff_size(_buff_size)
276 {
277 assert(sbuf_p);
278 in_buff = std::unique_ptr<char[]>(new char[buff_size]);
279 out_buff = std::unique_ptr<char[]>(new char[buff_size]);
280 setp(in_buff.get(), in_buff.get() + buff_size);
281 }
282
283 ostreambuf(const ostreambuf &) = delete;
284 ostreambuf & operator = (const ostreambuf &) = delete;
285
286 int deflate_loop(int flush)
287 {
288 while (true)
289 {
290 zstrm_p->next_out = reinterpret_cast< decltype(zstrm_p->next_out) >(out_buff.get());
291 zstrm_p->avail_out = uint32_t(buff_size);
292 int ret = deflate(zstrm_p.get(), flush);
293 if (ret != Z_OK && ret != Z_STREAM_END && ret != Z_BUF_ERROR) {
294 failed = true;
295 throw Exception(zstrm_p.get(), ret);
296 }
297 std::streamsize sz = sbuf_p->sputn(out_buff.get(), reinterpret_cast< decltype(out_buff.get()) >(zstrm_p->next_out) - out_buff.get());
298 if (sz != reinterpret_cast< decltype(out_buff.get()) >(zstrm_p->next_out) - out_buff.get())
299 {
300 // there was an error in the sink stream
301 return -1;
302 }
303 if (ret == Z_STREAM_END || ret == Z_BUF_ERROR || sz == 0)
304 {
305 break;
306 }
307 }
308 return 0;
309 }
310
311 virtual ~ostreambuf()
312 {
313 // flush the zlib stream
314 //
315 // NOTE: Errors here (sync() return value not 0) are ignored, because we
316 // cannot throw in a destructor. This mirrors the behaviour of
317 // std::basic_filebuf::~basic_filebuf(). To see an exception on error,
318 // close the ofstream with an explicit call to close(), and do not rely
319 // on the implicit call in the destructor.
320 //
321 if (!failed) try {
322 sync();
323 } catch (...) {}
324 }
325 std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof()) override
326 {
327 zstrm_p->next_in = reinterpret_cast< decltype(zstrm_p->next_in) >(pbase());
328 zstrm_p->avail_in = uint32_t(pptr() - pbase());
329 while (zstrm_p->avail_in > 0)
330 {
331 int r = deflate_loop(Z_NO_FLUSH);
332 if (r != 0)
333 {
334 setp(nullptr, nullptr);
335 return traits_type::eof();
336 }
337 }
338 setp(in_buff.get(), in_buff.get() + buff_size);
339 return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(char_type(c));
340 }
341 int sync() override
342 {
343 // first, call overflow to clear in_buff
344 overflow();
345 if (! pptr()) return -1;
346 // then, call deflate asking to finish the zlib stream
347 zstrm_p->next_in = nullptr;
348 zstrm_p->avail_in = 0;
349 if (deflate_loop(Z_FINISH) != 0) return -1;
350 deflateReset(zstrm_p.get());
351 return 0;
352 }
353private:
354 std::streambuf * sbuf_p = nullptr;
355 std::unique_ptr<char[]> in_buff;
356 std::unique_ptr<char[]> out_buff;
357 std::unique_ptr<detail::z_stream_wrapper> zstrm_p;
358 std::size_t buff_size;
359 bool failed = false;
360
361}; // class ostreambuf
362
364 : public std::istream
365{
366public:
367 istream(std::istream & is,
368 std::size_t _buff_size = default_buff_size, bool _auto_detect = true, int _window_bits = 0)
369 : std::istream(new istreambuf(is.rdbuf(), _buff_size, _auto_detect, _window_bits))
370 {
371 exceptions(std::ios_base::badbit);
372 }
373 explicit istream(std::streambuf * sbuf_p)
374 : std::istream(new istreambuf(sbuf_p))
375 {
376 exceptions(std::ios_base::badbit);
377 }
378 virtual ~istream()
379 {
380 delete rdbuf();
381 }
382}; // class istream
383
385 : public std::ostream
386{
387public:
388 ostream(std::ostream & os,
389 std::size_t _buff_size = default_buff_size, int _level = Z_DEFAULT_COMPRESSION, int _window_bits = 0)
390 : std::ostream(new ostreambuf(os.rdbuf(), _buff_size, _level, _window_bits))
391 {
392 exceptions(std::ios_base::badbit);
393 }
394 explicit ostream(std::streambuf * sbuf_p)
395 : std::ostream(new ostreambuf(sbuf_p))
396 {
397 exceptions(std::ios_base::badbit);
398 }
399 virtual ~ostream()
400 {
401 delete rdbuf();
402 }
403}; // class ostream
404
405namespace detail
406{
407
408template < typename FStream_Type >
410{
411 strict_fstream_holder(const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
412 : _fs(filename, mode)
413 {}
415 FStream_Type _fs {};
416}; // class strict_fstream_holder
417
418} // namespace detail
419
421 : private detail::strict_fstream_holder< strict_fstream::ifstream >,
422 public std::istream
423{
424public:
425 explicit ifstream(const std::string filename, std::ios_base::openmode mode = std::ios_base::in, size_t buff_size = default_buff_size)
426 : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode),
427 std::istream(new istreambuf(_fs.rdbuf(), buff_size))
428 {
429 exceptions(std::ios_base::badbit);
430 }
431 explicit ifstream(): detail::strict_fstream_holder< strict_fstream::ifstream >(), std::istream(new istreambuf(_fs.rdbuf())){}
432 void close() {
433 _fs.close();
434 }
435 #ifdef CAN_MOVE_IOSTREAM
436 void open(const std::string filename, std::ios_base::openmode mode = std::ios_base::in) {
437 _fs.open(filename, mode);
438 std::istream::operator=(std::istream(new istreambuf(_fs.rdbuf())));
439 }
440 #endif
441 bool is_open() const {
442 return _fs.is_open();
443 }
444 virtual ~ifstream()
445 {
446 if (_fs.is_open()) close();
447 if (rdbuf()) delete rdbuf();
448 }
449
451 std::streampos compressed_tellg()
452 {
453 return _fs.tellg();
454 }
455}; // class ifstream
456
458 : private detail::strict_fstream_holder< strict_fstream::ofstream >,
459 public std::ostream
460{
461public:
462 explicit ofstream(const std::string filename, std::ios_base::openmode mode = std::ios_base::out,
463 int level = Z_DEFAULT_COMPRESSION, size_t buff_size = default_buff_size)
464 : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode | std::ios_base::binary),
465 std::ostream(new ostreambuf(_fs.rdbuf(), buff_size, level))
466 {
467 exceptions(std::ios_base::badbit);
468 }
469 explicit ofstream(): detail::strict_fstream_holder< strict_fstream::ofstream >(), std::ostream(new ostreambuf(_fs.rdbuf())){}
470 void close() {
471 std::ostream::flush();
472 _fs.close();
473 }
474 #ifdef CAN_MOVE_IOSTREAM
475 void open(const std::string filename, std::ios_base::openmode mode = std::ios_base::out, int level = Z_DEFAULT_COMPRESSION) {
476 flush();
477 _fs.open(filename, mode | std::ios_base::binary);
478 std::ostream::operator=(std::ostream(new ostreambuf(_fs.rdbuf(), default_buff_size, level)));
479 }
480 #endif
481 bool is_open() const {
482 return _fs.is_open();
483 }
485 std::ostream::flush();
486 _fs.flush();
487 return *this;
488 }
489 virtual ~ofstream()
490 {
491 if (_fs.is_open()) close();
492 if (rdbuf()) delete rdbuf();
493 }
494
495 // Return the position within the compressed file (wrapped filestream)
496 std::streampos compressed_tellp()
497 {
498 return _fs.tellp();
499 }
500}; // class ofstream
501
502} // namespace zstr
void open(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
void open(const std::string &filename, std::ios_base::openmode mode=std::ios_base::out)
Exception class thrown by failed zlib operations.
Definition zstr.hpp:36
static std::string error_to_message(z_stream *zstrm_p, int ret)
Definition zstr.hpp:38
Exception(z_stream *zstrm_p, int ret)
Definition zstr.hpp:80
z_stream_wrapper(bool _is_input, int _level, int _window_bits)
Definition zstr.hpp:93
void open(const std::string filename, std::ios_base::openmode mode=std::ios_base::in)
Definition zstr.hpp:436
std::streampos compressed_tellg()
Return the position within the compressed file (wrapped filestream)
Definition zstr.hpp:451
void close()
Definition zstr.hpp:432
ifstream(const std::string filename, std::ios_base::openmode mode=std::ios_base::in, size_t buff_size=default_buff_size)
Definition zstr.hpp:425
bool is_open() const
Definition zstr.hpp:441
virtual ~ifstream()
Definition zstr.hpp:444
virtual ~istream()
Definition zstr.hpp:378
istream(std::streambuf *sbuf_p)
Definition zstr.hpp:373
istream(std::istream &is, std::size_t _buff_size=default_buff_size, bool _auto_detect=true, int _window_bits=0)
Definition zstr.hpp:367
istreambuf(std::streambuf *_sbuf_p, std::size_t _buff_size=default_buff_size, bool _auto_detect=true, int _window_bits=0)
Definition zstr.hpp:133
char * in_buff_end
Definition zstr.hpp:254
std::unique_ptr< detail::z_stream_wrapper > zstrm_p
Definition zstr.hpp:256
std::unique_ptr< char[]> out_buff
Definition zstr.hpp:255
istreambuf(const istreambuf &)=delete
std::unique_ptr< char[]> in_buff
Definition zstr.hpp:252
char * in_buff_start
Definition zstr.hpp:253
std::size_t buff_size
Definition zstr.hpp:257
pos_type seekoff(off_type off, std::ios_base::seekdir dir, std::ios_base::openmode which) override
Definition zstr.hpp:158
bool auto_detect_run
Definition zstr.hpp:259
std::streambuf::int_type underflow() override
Definition zstr.hpp:172
std::streambuf * sbuf_p
Definition zstr.hpp:251
istreambuf & operator=(const istreambuf &)=delete
std::streampos compressed_tellp()
Definition zstr.hpp:496
ofstream & flush()
Definition zstr.hpp:484
void open(const std::string filename, std::ios_base::openmode mode=std::ios_base::out, int level=Z_DEFAULT_COMPRESSION)
Definition zstr.hpp:475
ofstream(const std::string filename, std::ios_base::openmode mode=std::ios_base::out, int level=Z_DEFAULT_COMPRESSION, size_t buff_size=default_buff_size)
Definition zstr.hpp:462
void close()
Definition zstr.hpp:470
bool is_open() const
Definition zstr.hpp:481
virtual ~ofstream()
Definition zstr.hpp:489
ostream(std::ostream &os, std::size_t _buff_size=default_buff_size, int _level=Z_DEFAULT_COMPRESSION, int _window_bits=0)
Definition zstr.hpp:388
ostream(std::streambuf *sbuf_p)
Definition zstr.hpp:394
virtual ~ostream()
Definition zstr.hpp:399
ostreambuf & operator=(const ostreambuf &)=delete
int deflate_loop(int flush)
Definition zstr.hpp:286
std::streambuf * sbuf_p
Definition zstr.hpp:354
std::size_t buff_size
Definition zstr.hpp:358
std::unique_ptr< char[]> in_buff
Definition zstr.hpp:355
std::unique_ptr< char[]> out_buff
Definition zstr.hpp:356
ostreambuf(const ostreambuf &)=delete
ostreambuf(std::streambuf *_sbuf_p, std::size_t _buff_size=default_buff_size, int _level=Z_DEFAULT_COMPRESSION, int _window_bits=0)
Definition zstr.hpp:269
std::streambuf::int_type overflow(std::streambuf::int_type c=traits_type::eof()) override
Definition zstr.hpp:325
int sync() override
Definition zstr.hpp:341
virtual ~ostreambuf()
Definition zstr.hpp:311
std::unique_ptr< detail::z_stream_wrapper > zstrm_p
Definition zstr.hpp:357
Definition json.hpp:4471
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition json.hpp:21884
Definition zstr.hpp:29
static const std::size_t default_buff_size
Definition zstr.hpp:31
strict_fstream_holder(const std::string &filename, std::ios_base::openmode mode=std::ios_base::in)
Definition zstr.hpp:411