17 #include <arpa/inet.h>
23 #define COMPRESSION_BLOCK_SIZE 32000
34 if (streambuf_mutex != 0) \
35 pthread_mutex_lock(streambuf_mutex); \
36 pthread_mutex_t *mutex_saved = streambuf_mutex; \
39 #define MUTEX_UNLOCK \
40 streambuf_mutex = mutex_saved; \
41 if (streambuf_mutex != 0) \
42 pthread_mutex_unlock(streambuf_mutex); \
45 #define MUTEX_ESCAPE \
46 streambuf_mutex = mutex_saved; \
47 if (streambuf_mutex != 0) \
48 pthread_mutex_unlock(streambuf_mutex);
57 static int z_header_length = 2;
58 static unsigned char z_header[2] = {0x78, 0x9c};
60 struct pimpl:
public z_stream {};
64 static inline int flush_macro(
const flush_kind
f) {
85 const char* error_str(
int err) {
88 return "out of memory";
90 return "zlib version mismatch";
92 return "invalid or incomplete data";
94 return "stream error";
96 return "need dictionary";
100 return "buffer error";
103 return "unknown error";
107 common::common(std::streambuf * sb)
108 : xstream::common_buffer(sb), z_strm(0), block_start(0), block_offset(0),
116 z_strm->zalloc = Z_NULL;
117 z_strm->zfree = Z_NULL;
118 z_strm->opaque = Z_NULL;
120 z_strm->avail_out = out.size;
121 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
123 z_strm->avail_in = 0;
124 z_strm->next_in = reinterpret_cast < Bytef* >(in.buf);
128 void common::grow_out (
unsigned int factor) {
130 const size_t taken = out.size - z_strm->avail_out;
134 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf + taken);
135 z_strm->avail_out = out.size - taken;
138 unsigned long int common::input_count()
const {
139 return z_strm->total_in;
142 unsigned long int common::output_count()
const {
143 return z_strm->total_out;
146 unsigned long int common::checksum()
const {
147 return z_strm->adler;
155 ostreambuf::ostreambuf (std::streambuf * sb)
156 : common(sb), level(Z_DEFAULT_COMPRESSION) {
157 LOG(
"z::ostreambuf without compression level");
158 block_start = _sb->pubseekoff(0, std::ios_base::cur, std::ios_base::out);
162 ostreambuf::ostreambuf(std::streambuf *sb,
int l)
163 : common(sb), level (l) {
164 LOG (
"z::ostreambuf with compression level " << l);
165 block_start = _sb->pubseekoff(0, std::ios_base::cur, std::ios_base::out);
169 void ostreambuf::raise_error(
int err) {
172 LOG(
"z::ostreambuf::raise_error (" << err <<
") = " << what);
174 if (what.size() > 0) {
175 throw compress_error(
this, what);
177 throw compress_error(
this);
181 void ostreambuf::init() {
182 LOG (
"z::ostreambuf::init");
184 if (Z_DEFAULT_COMPRESSION == level || (level <= 9 && level >= 1)) {
185 int cret =::deflateInit(z_strm, level);
187 LOG (
"z::ostreambuf::init: error creating zstream " << cret);
192 setp(in.buf, in.buf + in.size);
195 sprintf(str,
"invalid compression level %d", level);
196 throw std::domain_error(str);
200 ostreambuf::~ostreambuf() {
201 LOG (
"z::ostreambuf::~ostreambuf");
214 int cret = ::deflateEnd(z_strm);
216 LOG(
"z::~ostreambuf error dealocating zstream");
221 int ostreambuf::sync () {
222 LOG (
"z::ostreambuf::sync");
225 ret = flush(finish_sync);
232 int ostreambuf::overflow(
int c) {
233 LOG (
"z::ostreambuf::overflow(" << c <<
")\t available=" << (available ()) <<
"\tEOF=" <<
eof);
239 if (0 == available ()) {
240 LOG (
"\t have to flush :[]");
243 *pptr () = static_cast <
char >(
c);
249 std::streamsize ostreambuf::xsputn (
const char *buffer, std::streamsize n) {
250 LOG (
"z::ostreambuf::xsputn(" << buffer <<
"," << n <<
")");
252 return flush(no_sync, buffer, n);
255 int ostreambuf::flush(flush_kind f,
const char *appendbuf,
int appendsize) {
256 LOG (
"z::ostreambuf::flush(" << f <<
")");
257 std::streamsize in_s = taken ();
258 LOG (
"\tinput_size=" << in_s);
263 z_strm->next_in = reinterpret_cast < Bytef* >(pbase());
264 z_strm->avail_in = in_s;
266 }
else if (appendsize > 0) {
267 z_strm->next_in = (Bytef*)appendbuf;
268 z_strm->avail_in = appendsize;
269 written = appendsize;
272 z_strm->next_in = reinterpret_cast < Bytef* >(pbase());
273 z_strm->avail_in = 0;
276 block_offset += written;
277 if (block_offset > (std::streamoff)COMPRESSION_BLOCK_SIZE) {
278 f = (f == no_sync)? finish_sync : f;
281 if (z_strm->avail_in + z_strm->total_in == 0)
285 bool reinit_deflator =
false;
292 cret = ::deflate(z_strm, flush_macro(f));
294 if (finish_sync == f && Z_OK == cret) {
303 if (f == finish_sync) {
304 if (Z_STREAM_END == cret) {
306 reinit_deflator =
true;
310 LOG (
"\terror :" << cret);
312 }
else if (Z_OK != cret) {
313 LOG (
"\terror deflating " << cret);
318 if (f == finish_sync) {
319 std::streamsize count = out.size - z_strm->avail_out;
321 LOG (
"\twriting " << count <<
" bytes");
322 int size = htonl(count);
324 const std::streamsize wrote = _sb->sputn((
char*)&size, 4) +
325 _sb->sputn(out.buf, count);
326 if (wrote != count + 4) {
328 LOG(
"\terror writting, only wrote " << wrote
329 <<
" but asked for " << count);
330 raise_error(Z_STREAM_ERROR);
332 block_start = _sb->pubseekoff(0, std::ios_base::cur,
337 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
338 z_strm->avail_out = out.size;
341 if (0 == z_strm->avail_out) {
342 LOG(
"\tavail_out=0 => redo");
346 if (!redo && appendbuf && appendsize > 0) {
347 z_strm->next_in = (Bytef*)appendbuf;
348 z_strm->avail_in = appendsize;
349 written += appendsize;
355 assert (0 == z_strm->avail_in);
357 if (reinit_deflator) {
359 cret = ::deflateEnd(z_strm);
361 LOG(
"\tERROR: deflateEnd returned " << cret);
364 z_strm->zalloc = Z_NULL;
365 z_strm->zfree = Z_NULL;
366 z_strm->opaque = Z_NULL;
367 z_strm->avail_out = out.size;
368 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
369 z_strm->avail_in = 0;
370 z_strm->next_in = reinterpret_cast < Bytef* >(in.buf);
371 cret =::deflateInit(z_strm, level);
373 LOG(
"\tERROR: deflateInit returned " << cret);
379 setp(in.buf, in.buf + in.size);
387 istreambuf::istreambuf (std::streambuf *sb,
int *left,
unsigned int left_size)
388 : common(sb), end(false),
block_size(0), block_next(0),
389 new_block_start(0), new_block_offset(0),
392 LOG (
"z::istreambuf");
394 memset(z_strm, 0,
sizeof(*z_strm));
395 int cret = ::inflateInit(z_strm);
398 LOG (
"\terror creating zstream " << cret);
405 setg(out.buf, out.buf, out.buf);
406 block_start = _sb->pubseekoff(0, std::ios_base::cur, std::ios_base::in);
408 if (left_size >=
sizeof(leftovers_buf)) {
409 leftovers = (leftovers_buf*)left;
412 LOG(
"\terror - insufficient space for leftovers buffer");
417 void istreambuf::raise_error(
int err) {
420 LOG(
"z::istreambuf::raise_error (" << err <<
") = " << what);
422 if (what.size() > 0) {
423 throw decompress_error(
this, what);
425 throw decompress_error(
this);
429 int istreambuf::underflow() {
430 LOG(
"z:istreambuf::underflow");
433 LOG(
"\tend of stream (EOF)");
438 if (new_block_start > 0 || new_block_offset > 0) {
439 if (block_start != new_block_start ||
440 block_offset > new_block_offset ||
443 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
444 z_strm->avail_out = 0;
447 while (block_offset < new_block_offset) {
448 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
449 z_strm->avail_out = new_block_offset - block_offset;
450 if (z_strm->avail_out > out.size) {
451 z_strm->avail_out = out.size;
453 block_offset += z_strm->avail_out;
457 new_block_offset = 0;
460 z_strm->avail_out = out.size;
461 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
463 if (0 < z_strm->avail_in) {
464 LOG(
"\tdata in queue, inflating");
467 while (!end && z_strm->avail_out > 0) {
470 if (end && z_strm->avail_out > 0) {
471 LOG(
"\tend of stream (EOF)");
477 setg(out.buf, out.buf, reinterpret_cast <char*> (z_strm->next_out) );
479 return int(out.buf[0]);
483 std::streamsize istreambuf::xsgetn(
char *buffer, std::streamsize n) {
484 LOG(
"z::istreambuf::xsgetn (" << n <<
")");
486 if (new_block_start > 0 || new_block_offset > 0) {
487 if (block_start != new_block_start ||
488 block_offset > new_block_offset ||
491 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
492 z_strm->avail_out = 0;
494 setg(out.buf, out.buf, out.buf);
498 std::streamsize available = egptr() - gptr();
499 int waste = new_block_offset - block_offset;
500 waste = (available < waste)? available : waste;
503 block_offset += waste;
506 while (block_offset < new_block_offset) {
507 z_strm->next_out = reinterpret_cast < Bytef* >(out.buf);
508 z_strm->avail_out = new_block_offset - block_offset;
509 if (z_strm->avail_out > out.size) {
510 z_strm->avail_out = out.size;
512 block_offset += z_strm->avail_out;
516 new_block_offset = 0;
520 std::streamsize available = egptr() - gptr();
521 int read = (available >= n)? n : available;
523 std::copy(gptr(), gptr() + read, buffer);
525 block_offset += read;
531 LOG(
"\tend of stream (EOF)");
536 z_strm->next_out = reinterpret_cast < Bytef* >(buffer) + read;
537 z_strm->avail_out = n - read;
539 if (0 < z_strm->avail_in) {
542 while (!end && z_strm->avail_out > 0) {
545 if (end && z_strm->avail_out > 0) {
546 LOG(
"\tend of stream (EOF)");
550 block_offset += n - read;
555 void istreambuf::read_inflate(
const flush_kind f) {
556 LOG(
"z::istreambuf::read_inflate " << f);
557 bool reinit_inflator =
false;
561 if (new_block_start > 0) {
562 _sb->pubseekoff(new_block_start, std::ios_base::beg,
569 read = _sb->sgetn(in.buf, in.size);
574 if (new_block_start > 0) {
575 _sb->pubseekoff(new_block_start, std::ios_base::beg,
577 block_start = new_block_start;
584 block_start = _sb->pubseekoff(0, std::ios_base::cur,
586 block_start -= leftovers->len;
588 reinit_inflator = (block_next != block_start);
589 read = leftovers->len;
591 read += _sb->sgetn(leftovers->buf + read, 4 - read);
598 if (leftovers->buf[0] == 0) {
599 int *size = (
int*)leftovers->buf;
602 if (reinit_inflator && read > 0) {
603 std::memcpy(in.buf, leftovers->buf + 4, read);
604 read += _sb->sgetn(in.buf + read,
block_size - read);
609 leftovers->len = _sb->sgetn(leftovers->buf, 8);
610 if (leftovers->len > 4) {
611 std::memcpy(in.buf + read, leftovers->buf + 4,
613 read += leftovers->len - 4;
617 read += _sb->sgetn(in.buf + read, in.size - read);
621 block_next = _sb->pubseekoff(0, std::ios_base::cur,
623 block_next -= leftovers->len;
626 LOG(
"\tread " << read <<
" bytes");
634 const char* head = (
const char*)z_header;
635 if (reinit_inflator) {
636 int cret = ::inflateEnd(z_strm);
638 LOG (
"\terror terminating zstream " << cret);
642 z_strm->zalloc = Z_NULL;
643 z_strm->zfree = Z_NULL;
644 z_strm->opaque = Z_NULL;
645 cret = ::inflateInit(z_strm);
647 LOG (
"\terror initializing zstream " << cret);
651 if (strncmp(head, in.buf, z_header_length) != 0) {
652 z_strm->avail_in = z_header_length;
653 z_strm->next_in = reinterpret_cast < Bytef* >(z_header);
657 z_strm->next_in = reinterpret_cast < Bytef* >(in.buf);
658 z_strm->avail_in = read;
662 void istreambuf::inflate(
const flush_kind f) {
663 LOG(
"z::istreambuf::inflate " << f);
665 int cret = ::inflate(z_strm, flush_macro(f));
667 if (Z_STREAM_END == cret) {
668 z_strm->avail_in = 0;
671 else if (cret == Z_DATA_ERROR && z_strm->avail_in == 0) {
677 else if (Z_OK != cret) {
678 printf(
"z input stream crapping out, cret is %d\n", cret);
679 LOG(
"\terror inflating: " << cret);
686 istreambuf::~istreambuf() {
687 LOG(
"z::~istreambuf");
691 ::inflateEnd(z_strm);
debugging/logging support
sprintf(text,"Post KinFit Cut")
C++ streambuf interface to read and write file formats supported by Zlib.
static const size_t block_size
printf("string=%s", string)
exceptions related to zlib usage xstream::z namespace