aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Adler <git@madler.net>2025-05-25 21:46:47 -0700
committerMark Adler <git@madler.net>2025-12-06 19:56:13 -0800
commit370ef1b41fd35fbfcf2af317ef3d8065a132f27a (patch)
tree3a7707b876f2934b04d1ecfff33708d6350a7ad4
parent562b823635fdcd26e44961f6bd213ae0c10be098 (diff)
downloadzlib-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.
-rw-r--r--gzlib.c1
-rw-r--r--gzread.c59
-rw-r--r--zlib.h21
3 files changed, 49 insertions, 32 deletions
diff --git a/gzlib.c b/gzlib.c
index 79a7e97..1c5c7be 100644
--- a/gzlib.c
+++ b/gzlib.c
@@ -104,6 +104,7 @@ local gzFile gz_open(const void *path, int fd, const char *mode) {
104 return NULL; 104 return NULL;
105 state->size = 0; /* no buffers allocated yet */ 105 state->size = 0; /* no buffers allocated yet */
106 state->want = GZBUFSIZE; /* requested buffer size */ 106 state->want = GZBUFSIZE; /* requested buffer size */
107 state->err = Z_OK; /* no error yet */
107 state->msg = NULL; /* no error message yet */ 108 state->msg = NULL; /* no error message yet */
108 109
109 /* interpret mode */ 110 /* interpret mode */
diff --git a/gzread.c b/gzread.c
index b9075da..2c70054 100644
--- a/gzread.c
+++ b/gzread.c
@@ -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. */
286local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) { 292local 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 */
diff --git a/zlib.h b/zlib.h
index 9ec7bc1..fa8b3d4 100644
--- a/zlib.h
+++ b/zlib.h
@@ -1454,7 +1454,8 @@ ZEXTERN int ZEXPORT gzread(gzFile file, voidp buf, unsigned len);
1454 gzread returns the number of uncompressed bytes actually read, less than 1454 gzread returns the number of uncompressed bytes actually read, less than
1455 len for end of file, or -1 for error. If len is too large to fit in an int, 1455 len for end of file, or -1 for error. If len is too large to fit in an int,
1456 then nothing is read, -1 is returned, and the error state is set to 1456 then nothing is read, -1 is returned, and the error state is set to
1457 Z_STREAM_ERROR. 1457 Z_STREAM_ERROR. If some data was read before an error, then that data is
1458 returned until exhausted, after which the next call will signal the error.
1458*/ 1459*/
1459 1460
1460ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, 1461ZEXTERN z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems,
@@ -1536,8 +1537,9 @@ ZEXTERN char * ZEXPORT gzgets(gzFile file, char *buf, int len);
1536 left untouched. 1537 left untouched.
1537 1538
1538 gzgets returns buf which is a null-terminated string, or it returns NULL 1539 gzgets returns buf which is a null-terminated string, or it returns NULL
1539 for end-of-file or in case of error. If there was an error, the contents at 1540 for end-of-file or in case of error. If some data was read before an error,
1540 buf are indeterminate. 1541 then that data is returned until exhausted, after which the next call will
1542 return NULL to signal the error.
1541*/ 1543*/
1542 1544
1543ZEXTERN int ZEXPORT gzputc(gzFile file, int c); 1545ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
@@ -1548,11 +1550,14 @@ ZEXTERN int ZEXPORT gzputc(gzFile file, int c);
1548 1550
1549ZEXTERN int ZEXPORT gzgetc(gzFile file); 1551ZEXTERN int ZEXPORT gzgetc(gzFile file);
1550/* 1552/*
1551 Read and decompress one byte from file. gzgetc returns this byte or -1 1553 Read and decompress one byte from file. gzgetc returns this byte or -1 in
1552 in case of end of file or error. This is implemented as a macro for speed. 1554 case of end of file or error. If some data was read before an error, then
1553 As such, it does not do all of the checking the other functions do. I.e. 1555 that data is returned until exhausted, after which the next call will return
1554 it does not check to see if file is NULL, nor whether the structure file 1556 -1 to signal the error.
1555 points to has been clobbered or not. 1557
1558 This is implemented as a macro for speed. As such, it does not do all of
1559 the checking the other functions do. I.e. it does not check to see if file
1560 is NULL, nor whether the structure file points to has been clobbered or not.
1556*/ 1561*/
1557 1562
1558ZEXTERN int ZEXPORT gzungetc(int c, gzFile file); 1563ZEXTERN int ZEXPORT gzungetc(int c, gzFile file);