53 namespace strict_fstream
58 :
public std::exception
61 Exception(
const std::string& msg) : _msg(msg) {}
62 const char * what() const noexcept {
return _msg.c_str(); }
70 struct static_method_holder
72 static std::string mode_to_string(std::ios_base::openmode mode)
74 static const int n_modes = 6;
75 static const std::ios_base::openmode mode_val_v[n_modes] =
85 static const char * mode_name_v[n_modes] =
95 for (
size_t i = 0; i < n_modes; ++i)
97 if (mode & mode_val_v[i])
99 res += (not res.empty()?
"|" :
"");
100 res += mode_name_v[i];
103 if (res.empty()) res =
"none";
106 static void check_mode(
const std::string& filename, std::ios_base::openmode mode)
108 if ((mode & std::ios_base::trunc) and not (mode & std::ios_base::out))
110 throw Exception(std::string(
"strict_fstream: open('") + filename +
"'): mode error: trunc and not out");
112 else if ((mode & std::ios_base::app) and not (mode & std::ios_base::out))
114 throw Exception(std::string(
"strict_fstream: open('") + filename +
"'): mode error: app and not out");
116 else if ((mode & std::ios_base::trunc) and (mode & std::ios_base::app))
118 throw Exception(std::string(
"strict_fstream: open('") + filename +
"'): mode error: trunc and app");
121 static void check_open(std::ios * s_p,
const std::string& filename, std::ios_base::openmode mode)
125 throw Exception(std::string(
"strict_fstream: open('")
126 + filename +
"'," + mode_to_string(mode) +
"): open failed: " 127 + std::strerror(errno));
130 static void check_peek(std::istream * is_p,
const std::string& filename, std::ios_base::openmode mode)
132 bool peek_failed =
true;
136 peek_failed = is_p->fail();
138 catch (std::ios_base::failure e) {}
141 throw Exception(std::string(
"strict_fstream: open('")
142 + filename +
"'," + mode_to_string(mode) +
"): peek failed: " 143 + std::strerror(errno));
152 :
public std::ifstream
155 ifstream() =
default;
156 ifstream(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
158 open(filename, mode);
160 void open(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
162 mode |= std::ios_base::in;
163 exceptions(std::ios_base::badbit);
164 detail::static_method_holder::check_mode(filename, mode);
165 std::ifstream::open(filename, mode);
166 detail::static_method_holder::check_open(
this, filename, mode);
167 detail::static_method_holder::check_peek(
this, filename, mode);
172 :
public std::ofstream
175 ofstream() =
default;
176 ofstream(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
178 open(filename, mode);
180 void open(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
182 mode |= std::ios_base::out;
183 exceptions(std::ios_base::badbit);
184 detail::static_method_holder::check_mode(filename, mode);
185 std::ofstream::open(filename, mode);
186 detail::static_method_holder::check_open(
this, filename, mode);
191 :
public std::fstream
195 fstream(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
197 open(filename, mode);
199 void open(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
201 if (not (mode & std::ios_base::out)) mode |= std::ios_base::in;
202 exceptions(std::ios_base::badbit);
203 detail::static_method_holder::check_mode(filename, mode);
204 std::fstream::open(filename, mode);
205 detail::static_method_holder::check_open(
this, filename, mode);
206 detail::static_method_holder::check_peek(
this, filename, mode);
220 :
public std::exception
223 Exception(z_stream * zstrm_p,
int ret)
229 _msg +=
"Z_STREAM_ERROR: ";
232 _msg +=
"Z_DATA_ERROR: ";
235 _msg +=
"Z_MEM_ERROR: ";
237 case Z_VERSION_ERROR:
238 _msg +=
"Z_VERSION_ERROR: ";
241 _msg +=
"Z_BUF_ERROR: ";
244 std::ostringstream oss;
246 _msg +=
"[" + oss.str() +
"]: ";
249 _msg += zstrm_p->msg;
251 Exception(
const std::string msg) : _msg(msg) {}
252 const char * what() const noexcept {
return _msg.c_str(); }
260 class z_stream_wrapper
264 z_stream_wrapper(
bool _is_input =
true,
int _level = Z_DEFAULT_COMPRESSION)
265 : is_input(_is_input)
267 this->zalloc = Z_NULL;
268 this->zfree = Z_NULL;
269 this->opaque = Z_NULL;
274 this->next_in = Z_NULL;
275 ret = inflateInit2(
this, 15+32);
279 ret = deflateInit2(
this, _level, Z_DEFLATED, 15+16, 8, Z_DEFAULT_STRATEGY);
281 if (ret != Z_OK)
throw Exception(
this, ret);
301 :
public std::streambuf
304 istreambuf(std::streambuf * _sbuf_p,
305 std::streamsize _buff_size = default_buff_size,
bool _auto_detect =
true)
308 buff_size(_buff_size),
309 auto_detect(_auto_detect),
310 auto_detect_run(false),
314 in_buff =
new char [buff_size];
315 in_buff_start = in_buff;
316 in_buff_end = in_buff;
317 out_buff =
new char [buff_size];
318 setg(out_buff, out_buff, out_buff);
321 istreambuf(
const istreambuf &) =
delete;
322 istreambuf(istreambuf &&) =
default;
323 istreambuf & operator = (
const istreambuf &) =
delete;
324 istreambuf & operator = (istreambuf &&) =
default;
326 virtual ~istreambuf()
330 if (zstrm_p)
delete zstrm_p;
333 virtual std::streambuf::int_type underflow()
335 if (this->gptr() == this->egptr())
338 char * out_buff_free_start = out_buff;
342 if (in_buff_start == in_buff_end)
345 in_buff_start = in_buff;
346 std::streamsize sz = sbuf_p->sgetn(in_buff, buff_size);
347 in_buff_end = in_buff + sz;
348 if (in_buff_end == in_buff_start)
break;
351 if (auto_detect and not auto_detect_run)
353 auto_detect_run =
true;
354 unsigned char b0 = *
reinterpret_cast< unsigned char *
>(in_buff_start);
355 unsigned char b1 = *
reinterpret_cast< unsigned char *
>(in_buff_start + 1);
359 is_text = not (in_buff_start + 2 <= in_buff_end
360 and ((b0 == 0x1F and b1 == 0x8B)
361 or (b0 == 0x78 and (b1 == 0x01
368 assert(in_buff_start == in_buff);
369 std::swap(in_buff, out_buff);
370 out_buff_free_start = in_buff_end;
371 in_buff_start = in_buff;
372 in_buff_end = in_buff;
377 if (not zstrm_p) zstrm_p =
new detail::z_stream_wrapper(
true);
378 zstrm_p->next_in =
reinterpret_cast< decltype(zstrm_p-
>next_in) >(in_buff_start);
379 zstrm_p->avail_in = in_buff_end - in_buff_start;
380 zstrm_p->next_out =
reinterpret_cast< decltype(zstrm_p-
>next_out) >(out_buff_free_start);
381 zstrm_p->avail_out = (out_buff + buff_size) - out_buff_free_start;
382 int ret = inflate(zstrm_p, Z_NO_FLUSH);
384 if (ret != Z_OK and ret != Z_STREAM_END)
throw Exception(zstrm_p, ret);
386 in_buff_start =
reinterpret_cast< decltype(in_buff_start)
>(zstrm_p->next_in);
387 in_buff_end = in_buff_start + zstrm_p->avail_in;
388 out_buff_free_start =
reinterpret_cast< decltype(out_buff_free_start)
>(zstrm_p->next_out);
389 assert(out_buff_free_start + zstrm_p->avail_out == out_buff + buff_size);
391 if (ret == Z_STREAM_END)
397 }
while (out_buff_free_start == out_buff);
401 this->setg(out_buff, out_buff, out_buff_free_start);
403 return this->gptr() == this->egptr()
405 : traits_type::to_int_type(*this->gptr());
408 std::streambuf * sbuf_p;
410 char * in_buff_start;
413 detail::z_stream_wrapper * zstrm_p;
414 std::streamsize buff_size;
416 bool auto_detect_run;
419 static const std::streamsize default_buff_size = 1 << 20;
423 :
public std::streambuf
426 ostreambuf(std::streambuf * _sbuf_p,
427 std::streamsize _buff_size = default_buff_size,
int _level = Z_DEFAULT_COMPRESSION)
429 zstrm_p(new detail::z_stream_wrapper(false, _level)),
430 buff_size(_buff_size)
433 in_buff =
new char [buff_size];
434 out_buff =
new char [buff_size];
435 setp(in_buff, in_buff + buff_size);
438 ostreambuf(
const ostreambuf &) =
delete;
439 ostreambuf(ostreambuf &&) =
default;
440 ostreambuf & operator = (
const ostreambuf &) =
delete;
441 ostreambuf & operator = (ostreambuf &&) =
default;
443 int deflate_loop(
int flush)
447 zstrm_p->next_out =
reinterpret_cast< decltype(zstrm_p-
>next_out) >(out_buff);
448 zstrm_p->avail_out = buff_size;
449 int ret = deflate(zstrm_p, flush);
450 if (ret != Z_OK and ret != Z_STREAM_END and ret != Z_BUF_ERROR)
throw Exception(zstrm_p, ret);
451 std::streamsize sz = sbuf_p->sputn(out_buff,
reinterpret_cast< decltype(out_buff)
>(zstrm_p->next_out) - out_buff);
452 if (sz !=
reinterpret_cast< decltype(out_buff)
>(zstrm_p->next_out) - out_buff)
457 if (ret == Z_STREAM_END or ret == Z_BUF_ERROR or sz == 0)
465 virtual ~ostreambuf()
473 virtual std::streambuf::int_type overflow(std::streambuf::int_type c = traits_type::eof())
475 zstrm_p->next_in =
reinterpret_cast< decltype(zstrm_p-
>next_in) >(pbase());
476 zstrm_p->avail_in = pptr() - pbase();
477 while (zstrm_p->avail_in > 0)
479 int r = deflate_loop(Z_NO_FLUSH);
482 setp(
nullptr,
nullptr);
483 return traits_type::eof();
486 setp(in_buff, in_buff + buff_size);
487 return traits_type::eq_int_type(c, traits_type::eof()) ? traits_type::eof() : sputc(c);
493 if (not pptr())
return -1;
495 zstrm_p->next_in =
nullptr;
496 zstrm_p->avail_in = 0;
497 if (deflate_loop(Z_FINISH) != 0)
return -1;
498 deflateReset(zstrm_p);
502 std::streambuf * sbuf_p;
505 detail::z_stream_wrapper * zstrm_p;
506 std::streamsize buff_size;
508 static const std::streamsize default_buff_size = 1 << 20;
512 :
public std::istream
515 istream(std::istream & is)
516 :
std::istream(new istreambuf(is.rdbuf()))
518 exceptions(std::ios_base::badbit);
520 explicit istream(std::streambuf * sbuf_p)
521 :
std::istream(new istreambuf(sbuf_p))
523 exceptions(std::ios_base::badbit);
532 :
public std::ostream
535 ostream(std::ostream & os)
536 :
std::ostream(new ostreambuf(os.rdbuf()))
538 exceptions(std::ios_base::badbit);
540 explicit ostream(std::streambuf * sbuf_p)
541 :
std::ostream(new ostreambuf(sbuf_p))
543 exceptions(std::ios_base::badbit);
554 template <
typename FStream_Type >
555 struct strict_fstream_holder
557 strict_fstream_holder(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
558 : _fs(filename, mode)
566 :
private detail::strict_fstream_holder< strict_fstream::ifstream >,
570 explicit ifstream(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::in)
571 : detail::strict_fstream_holder< strict_fstream::ifstream >(filename, mode),
572 std::istream(new istreambuf(_fs.rdbuf()))
574 exceptions(std::ios_base::badbit);
578 if (rdbuf())
delete rdbuf();
583 :
private detail::strict_fstream_holder< strict_fstream::ofstream >,
587 explicit ofstream(
const std::string& filename, std::ios_base::openmode mode = std::ios_base::out)
588 : detail::strict_fstream_holder< strict_fstream::ofstream >(filename, mode |
std::ios_base::binary),
589 std::ostream(new ostreambuf(_fs.rdbuf()))
591 exceptions(std::ios_base::badbit);
595 if (rdbuf())
delete rdbuf();
603 typedef std::ifstream ifstream;
604 typedef std::ofstream ofstream;