File: | external/xstream/src/z.cpp |
Location: | line 494, column 13 |
Description: | Value stored to 'cret' is never read |
1 | #include <xstream/config.h> |
2 | |
3 | #if HAVE_LIBZ1 |
4 | |
5 | #include <algorithm> |
6 | #include <string.h> |
7 | #include <string> |
8 | |
9 | #include <xstream/z.h> |
10 | #include <xstream/except/z.h> |
11 | #include <stdexcept> |
12 | |
13 | #include <stdio.h> |
14 | #include <zlib.h> |
15 | #include <arpa/inet.h> |
16 | |
17 | #include <cassert> |
18 | |
19 | #include "debug.h" |
20 | |
21 | #define COMPRESSION_BLOCK_SIZE32000 32000 |
22 | |
23 | namespace xstream { |
24 | namespace z { |
25 | |
26 | // define the standard header for a zlib stream that can be used |
27 | // to prime the inflate engine to start at an arbitrary block in |
28 | // an input stream |
29 | |
30 | static int z_header_length = 2; |
31 | static unsigned char z_header[2] = {0x78, 0x9c}; |
32 | |
33 | struct pimpl: public z_stream {}; |
34 | |
35 | static const int eof = std::streambuf::traits_type::eof(); |
36 | |
37 | static inline int flush_macro(const flush_kind f) { |
38 | switch (f) { |
39 | case no_sync: |
40 | return Z_NO_FLUSH0; |
41 | case normal_sync: |
42 | return Z_SYNC_FLUSH2; |
43 | case full_sync: |
44 | return Z_FULL_FLUSH3; |
45 | case finish_sync: |
46 | return Z_FINISH4; |
47 | case block_sync: |
48 | #ifndef Z_BLOCK5 |
49 | # define Z_BLOCK5 5 |
50 | #endif |
51 | return Z_BLOCK5; |
52 | default: |
53 | //should probably throw |
54 | return Z_NO_FLUSH0; |
55 | } |
56 | } |
57 | |
58 | const char* error_str(int err) { |
59 | switch(err) { |
60 | case Z_MEM_ERROR(-4): |
61 | return "out of memory"; |
62 | case Z_VERSION_ERROR(-6): |
63 | return "zlib version mismatch"; |
64 | case Z_DATA_ERROR(-3): |
65 | return "invalid or incomplete data"; |
66 | case Z_STREAM_ERROR(-2): |
67 | return "stream error"; |
68 | case Z_NEED_DICT2: |
69 | return "need dictionary"; |
70 | case Z_STREAM_END1: |
71 | return "stream end"; |
72 | case Z_BUF_ERROR(-5): |
73 | return "buffer error"; |
74 | } |
75 | |
76 | return "unknown error"; |
77 | } |
78 | |
79 | |
80 | common::common(std::streambuf * sb) |
81 | : xstream::common_buffer(sb), z_strm(0), block_offset(0) |
82 | { |
83 | LOG("z::common"); |
84 | |
85 | z_strm = new pimpl; |
86 | |
87 | //initialize zlib structure |
88 | z_strm->zalloc = Z_NULL0; |
89 | z_strm->zfree = Z_NULL0; |
90 | z_strm->opaque = Z_NULL0; |
91 | //buffers |
92 | z_strm->avail_out = out.size; |
93 | z_strm->next_out = reinterpret_cast < Bytef* >(out.buf); |
94 | |
95 | z_strm->avail_in = 0; |
96 | z_strm->next_in = reinterpret_cast < Bytef* >(in.buf); |
97 | |
98 | } |
99 | |
100 | void common::grow_out (unsigned int factor) { |
101 | |
102 | const size_t taken = out.size - z_strm->avail_out; |
103 | |
104 | out.grow(factor); |
105 | |
106 | z_strm->next_out = reinterpret_cast < Bytef* >(out.buf + taken); |
107 | z_strm->avail_out = out.size - taken; |
108 | } |
109 | |
110 | unsigned long int common::input_count() const { |
111 | return z_strm->total_in; |
112 | } |
113 | |
114 | unsigned long int common::output_count() const { |
115 | return z_strm->total_out; |
116 | } |
117 | |
118 | unsigned long int common::checksum() const { |
119 | return z_strm->adler; |
120 | } |
121 | |
122 | common::~common() { |
123 | LOG("z::~common"); |
124 | delete z_strm; |
125 | } |
126 | |
127 | ostreambuf::ostreambuf (std::streambuf * sb) |
128 | : common(sb), level(Z_DEFAULT_COMPRESSION(-1)) { |
129 | LOG("z::ostreambuf without compression level"); |
130 | init(); |
131 | } |
132 | |
133 | ostreambuf::ostreambuf(std::streambuf *sb, int l) |
134 | : common(sb), level (l) { |
135 | LOG ("z::ostreambuf with compression level " << l); |
136 | init(); |
137 | } |
138 | |
139 | void ostreambuf::raise_error(int err) { |
140 | std::string what = error_str(err); |
141 | |
142 | LOG("z::ostreambuf::raise_error (" << err << ") = " << what); |
143 | |
144 | if (what.size() > 0) { |
145 | throw compress_error(this, what); |
146 | } else { |
147 | throw compress_error(this); |
148 | } |
149 | } |
150 | |
151 | void ostreambuf::init() { |
152 | LOG ("z::ostreambuf::init"); |
153 | |
154 | if (Z_DEFAULT_COMPRESSION(-1) == level || (level <= 9 && level >= 1)) { |
155 | int cret =::deflateInit(z_strm, level)deflateInit_((z_strm), (level), "1.2.3", sizeof(z_stream)); |
156 | |
157 | if (Z_OK0 != cret) { |
158 | LOG ("z::ostreambuf::init: error creating zstream " << cret); |
159 | //XXX exception ins constructor |
160 | raise_error(cret); |
161 | } |
162 | //initialize streambuf interface functions |
163 | setp(in.buf, in.buf + in.size); |
164 | } else { |
165 | char str[256]; |
166 | sprintf(str, "invalid compression level %d", level); |
167 | throw std::domain_error(str); |
168 | } |
169 | } |
170 | |
171 | ostreambuf::~ostreambuf() { |
172 | LOG ("z::ostreambuf::~ostreambuf"); |
173 | //sync (write remaining data) |
174 | flush(finish_sync); |
175 | |
176 | //sync underlying streambuf |
177 | _sb->pubsync(); |
178 | |
179 | if (0 != z_strm) { |
180 | //XXX should I throw an exception in case of error? |
181 | //remember this is a destructor |
182 | //I should definitly LOG something |
183 | int cret = ::deflateEnd(z_strm); |
184 | if (Z_OK0 != cret){ |
185 | LOG("z::~ostreambuf error dealocating zstream"); |
186 | } |
187 | } |
188 | } |
189 | |
190 | int ostreambuf::sync () { |
191 | LOG ("z::ostreambuf::sync"); |
192 | int ret = flush(normal_sync); |
193 | _sb->pubsync(); |
194 | return ret; |
195 | } |
196 | |
197 | |
198 | int ostreambuf::overflow(int c) { |
199 | LOG ("z::ostreambuf::overflow(" << c << ")\t available=" << (available ()) << "\tEOF=" << eof); |
200 | if (eof == c) { |
201 | LOG ("\tEOF"); |
202 | flush(no_sync); |
203 | return eof; |
204 | } else { |
205 | if (0 == available ()) { |
206 | LOG ("\t have to flush :[]"); |
207 | flush(no_sync); |
208 | } |
209 | *pptr () = static_cast < char >(c); |
210 | pbump (1); |
211 | } |
212 | return c; |
213 | } |
214 | |
215 | std::streamsize ostreambuf::xsputn (const char *buffer, std::streamsize n) { |
216 | LOG ("z::ostreambuf::xsputn(" << buffer << "," << n << ")"); |
217 | |
218 | return flush(no_sync, buffer, n); |
219 | } |
220 | |
221 | int ostreambuf::flush(flush_kind f, const char *appendbuf, int appendsize) { |
222 | LOG ("z::ostreambuf::flush(" << f << ")"); |
223 | std::streamsize in_s = taken (); |
224 | LOG ("\tinput_size=" << in_s); |
225 | |
226 | //set up compression engine input feed |
227 | int written; |
228 | if (in_s > 0) { |
229 | z_strm->next_in = reinterpret_cast < Bytef* >(pbase()); |
230 | z_strm->avail_in = in_s; |
231 | written = in_s; |
232 | } else if (appendsize > 0) { |
233 | z_strm->next_in = (Bytef*)appendbuf; |
234 | z_strm->avail_in = appendsize; |
235 | written = appendsize; |
236 | appendsize = 0; |
237 | } else { |
238 | z_strm->next_in = reinterpret_cast < Bytef* >(pbase()); |
239 | z_strm->avail_in = 0; |
240 | written = 0; |
241 | } |
242 | block_offset += written; |
243 | if (block_offset > (std::streamoff)COMPRESSION_BLOCK_SIZE32000) { |
244 | f = (f == no_sync)? full_sync : f; |
245 | } |
246 | |
247 | bool redo = false; |
248 | |
249 | do { |
250 | int cret; |
251 | redo = false; |
252 | |
253 | do { |
254 | cret = ::deflate(z_strm, flush_macro(f)); |
255 | |
256 | if (finish_sync == f && Z_OK0 == cret) { |
257 | grow_out(); |
258 | continue; |
259 | } else { |
260 | break; |
261 | } |
262 | } while (1); |
263 | |
264 | //error handling |
265 | if (f == finish_sync) { |
266 | if (Z_STREAM_END1 != cret) { |
267 | //serious error, throw exception |
268 | LOG ("\terror :" << cret); |
269 | } |
270 | } else if (Z_OK0 != cret) { |
271 | LOG ("\terror deflating " << cret); |
272 | //XXX throw exception here |
273 | raise_error(cret); |
274 | } |
275 | |
276 | if (f != no_sync) { |
277 | std::streamsize count = out.size - z_strm->avail_out; |
278 | LOG ("\twriting " << count << " bytes"); |
279 | int size = htonl(count)(__extension__ ({ register unsigned int __v, __x = (count); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000 ) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x ) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v ; })); |
280 | const std::streamsize wrote = _sb->sputn((char*)&size, 4) + |
281 | _sb->sputn(out.buf, count); |
282 | if (wrote != count + 4) { |
283 | LOG("\terror writting, only wrote " << wrote |
284 | << " but asked for " << count); |
285 | raise_error(Z_STREAM_ERROR(-2)); |
286 | } |
287 | |
288 | // reset output |
289 | z_strm->next_out = reinterpret_cast < Bytef* >(out.buf); |
290 | z_strm->avail_out = out.size; |
291 | block_offset = 0; |
292 | } |
293 | |
294 | if (0 == z_strm->avail_out) { // && 0 != z_strm->avail_in) |
295 | LOG("\tavail_out=0 => redo"); |
296 | redo = true; |
297 | } |
298 | |
299 | if (!redo && appendbuf && appendsize > 0) { |
300 | z_strm->next_in = (Bytef*)appendbuf; |
301 | z_strm->avail_in = appendsize; |
302 | written += appendsize; |
303 | appendsize = 0; |
304 | redo = true; |
305 | } |
306 | } |
307 | while (redo); |
308 | assert (0 == z_strm->avail_in)((0 == z_strm->avail_in) ? static_cast<void> (0) : __assert_fail ("0 == z_strm->avail_in", "external/xstream/src/z.cpp", 308 , __PRETTY_FUNCTION__)); |
309 | //reset buffer |
310 | setp(in.buf, in.buf + in.size); |
311 | return written; |
312 | } |
313 | |
314 | ///////////////////// |
315 | // istream follows // |
316 | ///////////////////// |
317 | |
318 | istreambuf::istreambuf (std::streambuf * sb) |
319 | : common(sb), end(false), block_size(0) { |
320 | LOG ("z::istreambuf"); |
321 | |
322 | int cret = ::inflateInit(z_strm)inflateInit_((z_strm), "1.2.3", sizeof(z_stream)); |
323 | |
324 | if (Z_OK0 != cret) { |
325 | LOG ("\terror creating zstream " << cret); |
326 | //XXX throw exception here |
327 | raise_error(cret); |
328 | } |
329 | //initialize streambuf interface functions |
330 | //first call will call uflow and this will set the buffer accordingly |
331 | //no buffering |
332 | setg(out.buf, out.buf, out.buf); |
333 | } |
334 | |
335 | void istreambuf::raise_error(int err) { |
336 | std::string what = error_str(err); |
337 | |
338 | LOG("z::istreambuf::raise_error (" << err << ") = " << what); |
339 | |
340 | if (what.size() > 0) { |
341 | throw decompress_error(this, what); |
342 | } else { |
343 | throw decompress_error(this); |
344 | } |
345 | } |
346 | |
347 | int istreambuf::underflow() { |
348 | LOG("z:istreambuf::underflow"); |
349 | |
350 | if (end) { |
351 | LOG("\tend of stream (EOF)"); |
352 | //signal the stream has reached it's end |
353 | return eof; |
354 | } |
355 | |
356 | z_strm->avail_out = out.size; |
357 | z_strm->next_out = reinterpret_cast < Bytef* >(out.buf); |
358 | |
359 | if (0 < z_strm->avail_in) { |
360 | LOG("\tdata in queue, inflating"); |
361 | inflate(); |
362 | } |
363 | while (!end && z_strm->avail_out > 0) { |
364 | read_inflate(); |
365 | } |
366 | if (end && z_strm->avail_out > 0) { |
367 | LOG("\tend of stream (EOF)"); |
368 | //signal the stream has reached it's end |
369 | return eof; |
370 | } |
371 | |
372 | //set streambuf pointers |
373 | setg(out.buf, out.buf, reinterpret_cast <char*> (z_strm->next_out) ); |
374 | |
375 | return int(out.buf[0]); |
376 | } |
377 | |
378 | //read to buffer in place (apart from data already buffered) |
379 | std::streamsize istreambuf::xsgetn(char *buffer, std::streamsize n) { |
380 | LOG("z::istreambuf::xsgetn (" << n << ")"); |
381 | |
382 | //try to satisfy request from buffered input |
383 | std::streamsize available = egptr() - gptr(); |
384 | int read = (available >= n)? n : available; |
385 | if (read) { |
386 | std::copy(gptr(), gptr() + read, buffer); |
387 | gbump(read); |
388 | block_offset += read; |
389 | } |
390 | |
391 | //inflate the rest directly into the user's buffer |
392 | if (read < n) { |
393 | if (end) { |
394 | LOG("\tend of stream (EOF)"); |
395 | //signal the stream has reached it's end |
396 | return eof; |
397 | } |
398 | |
399 | z_strm->next_out = reinterpret_cast < Bytef* >(buffer) + read; |
400 | z_strm->avail_out = n - read; |
401 | |
402 | if (0 < z_strm->avail_in) { |
403 | inflate(); |
404 | } |
405 | while (!end && z_strm->avail_out > 0) { |
406 | read_inflate(); |
407 | } |
408 | if (end && z_strm->avail_out > 0) { |
409 | LOG("\tend of stream (EOF)"); |
410 | //signal the stream has reached it's end |
411 | return eof; |
412 | } |
413 | block_offset += n - read; |
414 | } |
415 | return n; |
416 | } |
417 | |
418 | void istreambuf::read_inflate( const flush_kind f) { |
419 | LOG("z::istreambuf::read_inflate " << f); |
420 | int read; |
421 | int block_pending = 0; |
422 | if (block_size < 0) { // stream has no blocksize markers |
423 | read = _sb->sgetn(in.buf, in.size); |
424 | } |
425 | else { // look for prefixed blocksize: leading byte = 0 |
426 | read = _sb->sgetn(in.buf, 4); |
427 | if (read < 4) { |
428 | end = true; |
429 | return; |
430 | } |
431 | if (in.buf[0] == 0) { // z blocks have prefixed blocksize |
432 | int *size = (int*)in.buf; |
433 | block_pending = ntohl(*size)(__extension__ ({ register unsigned int __v, __x = (*size); if (__builtin_constant_p (__x)) __v = ((((__x) & 0xff000000 ) >> 24) | (((__x) & 0x00ff0000) >> 8) | (((__x ) & 0x0000ff00) << 8) | (((__x) & 0x000000ff) << 24)); else __asm__ ("bswap %0" : "=r" (__v) : "0" (__x)); __v ; })); |
434 | read = _sb->sgetn(in.buf, block_pending); |
435 | } |
436 | else { // z blocks are jammed together, no blocksize available |
437 | read += _sb->sgetn(in.buf + 4, in.size - 4); |
438 | block_size = -1; |
439 | } |
440 | } |
441 | LOG("\tread " << read << " bytes"); |
442 | block_offset = 0; |
443 | |
444 | if (0 == read) { |
445 | end = true; |
446 | return; |
447 | } |
448 | |
449 | // We want to be able to start decompression at an arbitrary position |
450 | // in the input stream. This is possible with bzip2 streams, but there |
451 | // is a problem that the compressed blocks are arbitrary numbers of |
452 | // bits long and they are catenated one after another in a bit stream |
453 | // without any reference to byte boundaries. This makes it difficult |
454 | // to jump into the middle of a stream and start the decompressor |
455 | // since it expects a stream header followed by the first block that |
456 | // happens to start on a byte boundary. To make this work, I splice |
457 | // an artificial stream header followed by a dummy compressed block |
458 | // onto the beginning of the input stream, where the length of the |
459 | // dummy block in bits is chosen so that it abutts without padding |
460 | // the next block in the input stream. I have prepared 8 dummy blocks |
461 | // so there should be one to match the alignment of any input block. |
462 | // To match them, I look for the first place in the input stream |
463 | // with a byte string that matches the last 5 bytes in one of my |
464 | // dummy headers, and then I inject the dummy header into the |
465 | // decompressor ahead of the actual data. The dummy blocks are all |
466 | // contrived to decompress to an 8-byte string, so throwing away the |
467 | // first 8 bytes out of the decompressor, it is primed to decompress |
468 | // the remaining stream without any need for bit-shifting the input. |
469 | |
470 | const char* head = (const char*)z_header; |
471 | if (block_size == 0 && strncmp(head, in.buf, z_header_length) != 0) { |
472 | z_strm->avail_in = z_header_length; |
473 | z_strm->next_in = reinterpret_cast < Bytef* >(z_header); |
474 | inflate(f); // inject the z stream header |
475 | } |
476 | block_size = read; |
477 | z_strm->next_in = reinterpret_cast < Bytef* >(in.buf); |
478 | z_strm->avail_in = read; |
479 | inflate(f); |
480 | } |
481 | |
482 | void istreambuf::inflate(const flush_kind f) { |
483 | LOG("z::istreambuf::inflate " << f); |
484 | |
485 | int cret = ::inflate(z_strm, flush_macro(f)); |
486 | |
487 | if (Z_STREAM_END1 == cret) { |
488 | end = true; |
489 | } |
490 | else if (cret == Z_DATA_ERROR(-3) && z_strm->avail_in == 0) { |
491 | // Ignore CRC errors at the end of stream because we may not have |
492 | // started decompressing at the beginning. We can rely on the CRC |
493 | // checks that are present within each compressed block anyway. |
494 | cret = Z_OK0; |
Value stored to 'cret' is never read | |
495 | end = true; |
496 | } |
497 | else if (Z_OK0 != cret) { |
498 | LOG("\terror inflating: " << cret); |
499 | //XXX throw exception |
500 | raise_error(cret); |
501 | //can try to salvage some more data with inflateSync (on some cases) |
502 | } |
503 | } |
504 | |
505 | istreambuf::~istreambuf() { |
506 | LOG("z::~istreambuf"); |
507 | if (0 != z_strm) { |
508 | //XXX should I throw an exception in case of error? |
509 | //remember this is a destructor |
510 | ::inflateEnd(z_strm); |
511 | } |
512 | } |
513 | |
514 | }//namespace z |
515 | }//namespace xstream |
516 | |
517 | #endif //zlib |