diff options
Diffstat (limited to 'gzread.c')
-rw-r--r-- | gzread.c | 48 |
1 files changed, 32 insertions, 16 deletions
@@ -69,8 +69,8 @@ local int gz_avail(state) | |||
69 | (strm->avail_in == 0 ? -1 : \ | 69 | (strm->avail_in == 0 ? -1 : \ |
70 | (strm->avail_in--, *(strm->next_in)++))) | 70 | (strm->avail_in--, *(strm->next_in)++))) |
71 | 71 | ||
72 | /* Get a four-byte little-endian integer and return 0 on success and the | 72 | /* Get a four-byte little-endian integer and return 0 on success and the value |
73 | value in *ret. Otherwise -1 is returned and *ret is not modified. */ | 73 | in *ret. Otherwise -1 is returned and *ret is not modified. */ |
74 | local int gz_next4(state, ret) | 74 | local int gz_next4(state, ret) |
75 | gz_statep state; | 75 | gz_statep state; |
76 | unsigned long *ret; | 76 | unsigned long *ret; |
@@ -93,7 +93,7 @@ local int gz_next4(state, ret) | |||
93 | /* Look for gzip header, set up for inflate or copy. state->have must be zero. | 93 | /* Look for gzip header, set up for inflate or copy. state->have must be zero. |
94 | If this is the first time in, allocate required memory. state->how will be | 94 | If this is the first time in, allocate required memory. state->how will be |
95 | left unchanged if there is no more input data available, will be set to 1 if | 95 | left unchanged if there is no more input data available, will be set to 1 if |
96 | there is no gzip header and direct copying will be performned, or it will be | 96 | there is no gzip header and direct copying will be performed, or it will be |
97 | set to 2 for decompression, and the gzip header will be skipped so that the | 97 | set to 2 for decompression, and the gzip header will be skipped so that the |
98 | next available input data is the raw deflate stream. If direct copying, | 98 | next available input data is the raw deflate stream. If direct copying, |
99 | then leftover input data from the input buffer will be copied to the output | 99 | then leftover input data from the input buffer will be copied to the output |
@@ -190,6 +190,8 @@ local int gz_head(state) | |||
190 | NEXT(); | 190 | NEXT(); |
191 | NEXT(); | 191 | NEXT(); |
192 | } | 192 | } |
193 | /* an unexpected end of file is not checked for here -- it will be | ||
194 | noticed on the first request for uncompressed data */ | ||
193 | 195 | ||
194 | /* set up for decompression */ | 196 | /* set up for decompression */ |
195 | inflateReset(strm); | 197 | inflateReset(strm); |
@@ -206,7 +208,7 @@ local int gz_head(state) | |||
206 | 208 | ||
207 | /* doing raw i/o, save start of raw data for seeking, copy any leftover | 209 | /* doing raw i/o, save start of raw data for seeking, copy any leftover |
208 | input to output -- this assumes that the output buffer is larger than | 210 | input to output -- this assumes that the output buffer is larger than |
209 | the input buffer */ | 211 | the input buffer, which also assures space for gzungetc() */ |
210 | state->raw = state->pos; | 212 | state->raw = state->pos; |
211 | state->next = state->out; | 213 | state->next = state->out; |
212 | if (strm->avail_in) { | 214 | if (strm->avail_in) { |
@@ -220,10 +222,10 @@ local int gz_head(state) | |||
220 | 222 | ||
221 | /* Decompress from input to the provided next_out and avail_out in the state. | 223 | /* Decompress from input to the provided next_out and avail_out in the state. |
222 | If the end of the compressed data is reached, then verify the gzip trailer | 224 | If the end of the compressed data is reached, then verify the gzip trailer |
223 | check value and length (modulo 2^32). state->have and state->next are | 225 | check value and length (modulo 2^32). state->have and state->next are set |
224 | set to point to the just decompressed data, and the crc is updated. If the | 226 | to point to the just decompressed data, and the crc is updated. If the |
225 | trailer is verified, state->how is reset to zero to look for the next gzip | 227 | trailer is verified, state->how is reset to zero to look for the next gzip |
226 | stream or raw data, once state->have is depleted. Returns 0 on success, -1 | 228 | stream or raw data, once state->have is depleted. Returns 0 on success, -1 |
227 | on failure. Failures may include invalid compressed data or a failed gzip | 229 | on failure. Failures may include invalid compressed data or a failed gzip |
228 | trailer verification. */ | 230 | trailer verification. */ |
229 | local int gz_decomp(state) | 231 | local int gz_decomp(state) |
@@ -372,6 +374,17 @@ int ZEXPORT gzread(file, buf, len) | |||
372 | if (state->mode != GZ_READ || state->err != Z_OK) | 374 | if (state->mode != GZ_READ || state->err != Z_OK) |
373 | return -1; | 375 | return -1; |
374 | 376 | ||
377 | /* since an int is returned, make sure len fits in one, otherwise return | ||
378 | with an error (this avoids the flaw in the interface) */ | ||
379 | if ((int)len < 0) { | ||
380 | gz_error(state, Z_BUF_ERROR, "requested length does not fit in int"); | ||
381 | return -1; | ||
382 | } | ||
383 | |||
384 | /* if len is zero, avoid unnecessary operations */ | ||
385 | if (len == 0) | ||
386 | return 0; | ||
387 | |||
375 | /* process a skip request */ | 388 | /* process a skip request */ |
376 | if (state->seek) { | 389 | if (state->seek) { |
377 | state->seek = 0; | 390 | state->seek = 0; |
@@ -381,8 +394,7 @@ int ZEXPORT gzread(file, buf, len) | |||
381 | 394 | ||
382 | /* get len bytes to buf, or less than len if at the end */ | 395 | /* get len bytes to buf, or less than len if at the end */ |
383 | got = 0; | 396 | got = 0; |
384 | while (len) { | 397 | do { |
385 | |||
386 | /* first just try copying data from the output buffer */ | 398 | /* first just try copying data from the output buffer */ |
387 | if (state->have) { | 399 | if (state->have) { |
388 | n = state->have > len ? len : state->have; | 400 | n = state->have > len ? len : state->have; |
@@ -402,6 +414,8 @@ int ZEXPORT gzread(file, buf, len) | |||
402 | if (gz_make(state) == -1) | 414 | if (gz_make(state) == -1) |
403 | return -1; | 415 | return -1; |
404 | continue; /* no progress yet -- go back to memcpy() above */ | 416 | continue; /* no progress yet -- go back to memcpy() above */ |
417 | /* the copy above assures that we will leave with space in the | ||
418 | output buffer, allowing at least one gzungetc() to succeed */ | ||
405 | } | 419 | } |
406 | 420 | ||
407 | /* large len -- read directly into user buffer */ | 421 | /* large len -- read directly into user buffer */ |
@@ -422,13 +436,13 @@ int ZEXPORT gzread(file, buf, len) | |||
422 | 436 | ||
423 | /* update progress */ | 437 | /* update progress */ |
424 | len -= n; | 438 | len -= n; |
425 | buf += n; | 439 | buf = (char *)buf + n; |
426 | got += n; | 440 | got += n; |
427 | state->pos += n; | 441 | state->pos += n; |
428 | } | 442 | } while (len); |
429 | 443 | ||
430 | /* return number of bytes read into user buffer */ | 444 | /* return number of bytes read into user buffer (will fit in int) */ |
431 | return (int)got; /* len had better fit in int -- interface flaw */ | 445 | return (int)got; |
432 | } | 446 | } |
433 | 447 | ||
434 | /* -- see zlib.h -- */ | 448 | /* -- see zlib.h -- */ |
@@ -448,7 +462,7 @@ int ZEXPORT gzgetc(file) | |||
448 | if (state->mode != GZ_READ || state->err != Z_OK) | 462 | if (state->mode != GZ_READ || state->err != Z_OK) |
449 | return -1; | 463 | return -1; |
450 | 464 | ||
451 | /* try output buffer */ | 465 | /* try output buffer (no need to check for skip request) */ |
452 | if (state->have) { | 466 | if (state->have) { |
453 | state->have--; | 467 | state->have--; |
454 | state->pos++; | 468 | state->pos++; |
@@ -496,9 +510,11 @@ int ZEXPORT gzungetc(c, file) | |||
496 | return c; | 510 | return c; |
497 | } | 511 | } |
498 | 512 | ||
499 | /* if no room, give up (must have already done a gz_ungetc()) */ | 513 | /* if no room, give up (must have already done a gzungetc()) */ |
500 | if (state->have == (state->size << 1)) | 514 | if (state->have == (state->size << 1)) { |
515 | gz_error(state, Z_BUF_ERROR, "out of room to push characters"); | ||
501 | return -1; | 516 | return -1; |
517 | } | ||
502 | 518 | ||
503 | /* slide output data if needed and insert byte before existing data */ | 519 | /* slide output data if needed and insert byte before existing data */ |
504 | if (state->next == state->out) { | 520 | if (state->next == state->out) { |