diff options
| author | Mark Adler <git@madler.net> | 2025-05-25 21:46:47 -0700 |
|---|---|---|
| committer | Mark Adler <git@madler.net> | 2025-12-06 19:56:13 -0800 |
| commit | 370ef1b41fd35fbfcf2af317ef3d8065a132f27a (patch) | |
| tree | 3a7707b876f2934b04d1ecfff33708d6350a7ad4 /gzread.c | |
| parent | 562b823635fdcd26e44961f6bd213ae0c10be098 (diff) | |
| download | zlib-370ef1b41fd35fbfcf2af317ef3d8065a132f27a.tar.gz zlib-370ef1b41fd35fbfcf2af317ef3d8065a132f27a.tar.bz2 zlib-370ef1b41fd35fbfcf2af317ef3d8065a132f27a.zip | |
Return all available uncompressed data on error in gzread.c.
The error is recorded, and will be detected by the application
after all of the uncompressed data has been consumed and then one
more call is made to read data. The error is available immediately
from gzerror() if the application would like to know earlier.
Diffstat (limited to 'gzread.c')
| -rw-r--r-- | gzread.c | 59 |
1 files changed, 35 insertions, 24 deletions
| @@ -166,8 +166,10 @@ local int gz_decomp(gz_statep state) { | |||
| 166 | had = strm->avail_out; | 166 | had = strm->avail_out; |
| 167 | do { | 167 | do { |
| 168 | /* get more input for inflate() */ | 168 | /* get more input for inflate() */ |
| 169 | if (strm->avail_in == 0 && gz_avail(state) == -1) | 169 | if (strm->avail_in == 0 && gz_avail(state) == -1) { |
| 170 | return -1; | 170 | ret = state->err; |
| 171 | break; | ||
| 172 | } | ||
| 171 | if (strm->avail_in == 0) { | 173 | if (strm->avail_in == 0) { |
| 172 | gz_error(state, Z_BUF_ERROR, "unexpected end of file"); | 174 | gz_error(state, Z_BUF_ERROR, "unexpected end of file"); |
| 173 | break; | 175 | break; |
| @@ -181,22 +183,23 @@ local int gz_decomp(gz_statep state) { | |||
| 181 | if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { | 183 | if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) { |
| 182 | gz_error(state, Z_STREAM_ERROR, | 184 | gz_error(state, Z_STREAM_ERROR, |
| 183 | "internal error: inflate stream corrupt"); | 185 | "internal error: inflate stream corrupt"); |
| 184 | return -1; | 186 | break; |
| 185 | } | 187 | } |
| 186 | if (ret == Z_MEM_ERROR) { | 188 | if (ret == Z_MEM_ERROR) { |
| 187 | gz_error(state, Z_MEM_ERROR, "out of memory"); | 189 | gz_error(state, Z_MEM_ERROR, "out of memory"); |
| 188 | return -1; | 190 | break; |
| 189 | } | 191 | } |
| 190 | if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ | 192 | if (ret == Z_DATA_ERROR) { /* deflate stream invalid */ |
| 191 | if (state->junk == 1) { /* trailing garbage is ok */ | 193 | if (state->junk == 1) { /* trailing garbage is ok */ |
| 192 | strm->avail_in = 0; | 194 | strm->avail_in = 0; |
| 193 | state->eof = 1; | 195 | state->eof = 1; |
| 194 | state->how = LOOK; | 196 | state->how = LOOK; |
| 197 | ret = Z_OK; | ||
| 195 | break; | 198 | break; |
| 196 | } | 199 | } |
| 197 | gz_error(state, Z_DATA_ERROR, | 200 | gz_error(state, Z_DATA_ERROR, |
| 198 | strm->msg == NULL ? "compressed data error" : strm->msg); | 201 | strm->msg == NULL ? "compressed data error" : strm->msg); |
| 199 | return -1; | 202 | break; |
| 200 | } | 203 | } |
| 201 | } while (strm->avail_out && ret != Z_STREAM_END); | 204 | } while (strm->avail_out && ret != Z_STREAM_END); |
| 202 | 205 | ||
| @@ -208,10 +211,11 @@ local int gz_decomp(gz_statep state) { | |||
| 208 | if (ret == Z_STREAM_END) { | 211 | if (ret == Z_STREAM_END) { |
| 209 | state->junk = 0; | 212 | state->junk = 0; |
| 210 | state->how = LOOK; | 213 | state->how = LOOK; |
| 214 | return 0; | ||
| 211 | } | 215 | } |
| 212 | 216 | ||
| 213 | /* good decompression */ | 217 | /* return decompression status */ |
| 214 | return 0; | 218 | return ret != Z_OK ? -1 : 0; |
| 215 | } | 219 | } |
| 216 | 220 | ||
| 217 | /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. | 221 | /* Fetch data and put it in the output buffer. Assumes state->x.have is 0. |
| @@ -280,12 +284,15 @@ local int gz_skip(gz_statep state) { | |||
| 280 | } | 284 | } |
| 281 | 285 | ||
| 282 | /* Read len bytes into buf from file, or less than len up to the end of the | 286 | /* Read len bytes into buf from file, or less than len up to the end of the |
| 283 | input. Return the number of bytes read. If zero is returned, either the | 287 | input. Return the number of bytes read. If zero is returned, either the end |
| 284 | end of file was reached, or there was an error. state->err must be | 288 | of file was reached, or there was an error. state->err must be consulted in |
| 285 | consulted in that case to determine which. */ | 289 | that case to determine which. If there was an error, but some uncompressed |
| 290 | bytes were read before the error, then that count is returned. The error is | ||
| 291 | still recorded, and so is deferred until the next call. */ | ||
| 286 | local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { | 292 | local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { |
| 287 | z_size_t got; | 293 | z_size_t got; |
| 288 | unsigned n; | 294 | unsigned n; |
| 295 | int err; | ||
| 289 | 296 | ||
| 290 | /* if len is zero, avoid unnecessary operations */ | 297 | /* if len is zero, avoid unnecessary operations */ |
| 291 | if (len == 0) | 298 | if (len == 0) |
| @@ -297,6 +304,7 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { | |||
| 297 | 304 | ||
| 298 | /* get len bytes to buf, or less than len if at the end */ | 305 | /* get len bytes to buf, or less than len if at the end */ |
| 299 | got = 0; | 306 | got = 0; |
| 307 | err = 0; | ||
| 300 | do { | 308 | do { |
| 301 | /* set n to the maximum amount of len that fits in an unsigned int */ | 309 | /* set n to the maximum amount of len that fits in an unsigned int */ |
| 302 | n = (unsigned)-1; | 310 | n = (unsigned)-1; |
| @@ -310,37 +318,36 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { | |||
| 310 | memcpy(buf, state->x.next, n); | 318 | memcpy(buf, state->x.next, n); |
| 311 | state->x.next += n; | 319 | state->x.next += n; |
| 312 | state->x.have -= n; | 320 | state->x.have -= n; |
| 321 | if (state->err != Z_OK) | ||
| 322 | /* caught deferred error from gz_fetch() */ | ||
| 323 | err = -1; | ||
| 313 | } | 324 | } |
| 314 | 325 | ||
| 315 | /* output buffer empty -- return if we're at the end of the input */ | 326 | /* output buffer empty -- return if we're at the end of the input */ |
| 316 | else if (state->eof && state->strm.avail_in == 0) { | 327 | else if (state->eof && state->strm.avail_in == 0) |
| 317 | state->past = 1; /* tried to read past end */ | ||
| 318 | break; | 328 | break; |
| 319 | } | ||
| 320 | 329 | ||
| 321 | /* need output data -- for small len or new stream load up our output | 330 | /* need output data -- for small len or new stream load up our output |
| 322 | buffer */ | 331 | buffer, so that gzgetc() can be fast */ |
| 323 | else if (state->how == LOOK || n < (state->size << 1)) { | 332 | else if (state->how == LOOK || n < (state->size << 1)) { |
| 324 | /* get more output, looking for header if required */ | 333 | /* get more output, looking for header if required */ |
| 325 | if (gz_fetch(state) == -1) | 334 | if (gz_fetch(state) == -1 && state->x.have == 0) |
| 326 | return 0; | 335 | /* if state->x.have != 0, error will be caught after copy */ |
| 336 | err = -1; | ||
| 327 | continue; /* no progress yet -- go back to copy above */ | 337 | continue; /* no progress yet -- go back to copy above */ |
| 328 | /* the copy above assures that we will leave with space in the | 338 | /* the copy above assures that we will leave with space in the |
| 329 | output buffer, allowing at least one gzungetc() to succeed */ | 339 | output buffer, allowing at least one gzungetc() to succeed */ |
| 330 | } | 340 | } |
| 331 | 341 | ||
| 332 | /* large len -- read directly into user buffer */ | 342 | /* large len -- read directly into user buffer */ |
| 333 | else if (state->how == COPY) { /* read directly */ | 343 | else if (state->how == COPY) /* read directly */ |
| 334 | if (gz_load(state, (unsigned char *)buf, n, &n) == -1) | 344 | err = gz_load(state, (unsigned char *)buf, n, &n); |
| 335 | return 0; | ||
| 336 | } | ||
| 337 | 345 | ||
| 338 | /* large len -- decompress directly into user buffer */ | 346 | /* large len -- decompress directly into user buffer */ |
| 339 | else { /* state->how == GZIP */ | 347 | else { /* state->how == GZIP */ |
| 340 | state->strm.avail_out = n; | 348 | state->strm.avail_out = n; |
| 341 | state->strm.next_out = (unsigned char *)buf; | 349 | state->strm.next_out = (unsigned char *)buf; |
| 342 | if (gz_decomp(state) == -1) | 350 | err = gz_decomp(state); |
| 343 | return 0; | ||
| 344 | n = state->x.have; | 351 | n = state->x.have; |
| 345 | state->x.have = 0; | 352 | state->x.have = 0; |
| 346 | } | 353 | } |
| @@ -350,7 +357,11 @@ local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { | |||
| 350 | buf = (char *)buf + n; | 357 | buf = (char *)buf + n; |
| 351 | got += n; | 358 | got += n; |
| 352 | state->x.pos += n; | 359 | state->x.pos += n; |
| 353 | } while (len); | 360 | } while (len && !err); |
| 361 | |||
| 362 | /* note read past eof */ | ||
| 363 | if (len && state->eof) | ||
| 364 | state->past = 1; | ||
| 354 | 365 | ||
| 355 | /* return number of bytes read into user buffer */ | 366 | /* return number of bytes read into user buffer */ |
| 356 | return got; | 367 | return got; |
| @@ -537,7 +548,7 @@ char * ZEXPORT gzgets(gzFile file, char *buf, int len) { | |||
| 537 | if (left) do { | 548 | if (left) do { |
| 538 | /* assure that something is in the output buffer */ | 549 | /* assure that something is in the output buffer */ |
| 539 | if (state->x.have == 0 && gz_fetch(state) == -1) | 550 | if (state->x.have == 0 && gz_fetch(state) == -1) |
| 540 | return NULL; /* error */ | 551 | break; /* error */ |
| 541 | if (state->x.have == 0) { /* end of file */ | 552 | if (state->x.have == 0) { /* end of file */ |
| 542 | state->past = 1; /* read past end */ | 553 | state->past = 1; /* read past end */ |
| 543 | break; /* return what we have */ | 554 | break; /* return what we have */ |
