gzread.c updated to zlib 1.2.11

This commit is contained in:
Przemyslaw Skibinski 2017-01-18 12:14:01 +01:00
parent 7f82aad187
commit 5735fd74ee

View File

@ -1,9 +1,9 @@
/* gzread.c contains minimal changes required to be compiled with zlibWrapper: /* gzread.c contains minimal changes required to be compiled with zlibWrapper:
* - gz_statep was converted to union to work with -Wstrict-aliasing=1 */ * - gz_statep was converted to union to work with -Wstrict-aliasing=1 */
/* gzread.c -- zlib functions for reading gzip files /* gzread.c -- zlib functions for reading gzip files
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
* For conditions of distribution and use, see http://www.zlib.net/zlib_license.html * For conditions of distribution and use, see copyright notice in zlib.h
*/ */
#include "gzguts.h" #include "gzguts.h"
@ -15,9 +15,10 @@ local int gz_look OF((gz_statep));
local int gz_decomp OF((gz_statep)); local int gz_decomp OF((gz_statep));
local int gz_fetch OF((gz_statep)); local int gz_fetch OF((gz_statep));
local int gz_skip OF((gz_statep, z_off64_t)); local int gz_skip OF((gz_statep, z_off64_t));
local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
state->fd, and update state->eof, state->err, and state->msg as appropriate. state.state->fd, and update state.state->eof, state.state->err, and state.state->msg as appropriate.
This function needs to loop on read(), since read() is not guaranteed to This function needs to loop on read(), since read() is not guaranteed to
read the number of bytes requested, depending on the type of descriptor. */ read the number of bytes requested, depending on the type of descriptor. */
local int gz_load(state, buf, len, have) local int gz_load(state, buf, len, have)
@ -27,13 +28,17 @@ local int gz_load(state, buf, len, have)
unsigned *have; unsigned *have;
{ {
int ret; int ret;
unsigned get, max = ((unsigned)-1 >> 2) + 1;
*have = 0; *have = 0;
do { do {
ret = (int)read(state.state->fd, buf + *have, len - *have); get = len - *have;
if (get > max)
get = max;
ret = read(state.state->fd, buf + *have, get);
if (ret <= 0) if (ret <= 0)
break; break;
*have += ret; *have += (unsigned)ret;
} while (*have < len); } while (*have < len);
if (ret < 0) { if (ret < 0) {
gz_error(state, Z_ERRNO, zstrerror()); gz_error(state, Z_ERRNO, zstrerror());
@ -77,8 +82,8 @@ local int gz_avail(state)
return 0; return 0;
} }
/* Look for gzip header, set up for inflate or copy. state->x.have must be 0. /* Look for gzip header, set up for inflate or copy. state.state->x.have must be 0.
If this is the first time in, allocate required memory. state->how will be If this is the first time in, allocate required memory. state.state->how will be
left unchanged if there is no more input data available, will be set to COPY left unchanged if there is no more input data available, will be set to COPY
if there is no gzip header and direct copying will be performed, or it will if there is no gzip header and direct copying will be performed, or it will
be set to GZIP for decompression. If direct copying, then leftover input be set to GZIP for decompression. If direct copying, then leftover input
@ -97,10 +102,8 @@ local int gz_look(state)
state.state->in = (unsigned char *)malloc(state.state->want); state.state->in = (unsigned char *)malloc(state.state->want);
state.state->out = (unsigned char *)malloc(state.state->want << 1); state.state->out = (unsigned char *)malloc(state.state->want << 1);
if (state.state->in == NULL || state.state->out == NULL) { if (state.state->in == NULL || state.state->out == NULL) {
if (state.state->out != NULL) free(state.state->out);
free(state.state->out); free(state.state->in);
if (state.state->in != NULL)
free(state.state->in);
gz_error(state, Z_MEM_ERROR, "out of memory"); gz_error(state, Z_MEM_ERROR, "out of memory");
return -1; return -1;
} }
@ -136,7 +139,6 @@ local int gz_look(state)
file -- for here we assume that if a gzip file is being written, then file -- for here we assume that if a gzip file is being written, then
the header will be written in a single operation, so that reading a the header will be written in a single operation, so that reading a
single byte is sufficient indication that it is not a gzip file) */ single byte is sufficient indication that it is not a gzip file) */
//printf("strm->next_in[0]=%d strm->next_in[1]=%d\n", strm->next_in[0], strm->next_in[1]);
if (strm->avail_in > 1 && if (strm->avail_in > 1 &&
((strm->next_in[0] == 31 && strm->next_in[1] == 139) /* gz header */ ((strm->next_in[0] == 31 && strm->next_in[1] == 139) /* gz header */
|| (strm->next_in[0] == 40 && strm->next_in[1] == 181))) { /* zstd header */ || (strm->next_in[0] == 40 && strm->next_in[1] == 181))) { /* zstd header */
@ -170,9 +172,9 @@ local int gz_look(state)
} }
/* Decompress from input to the provided next_out and avail_out in the state. /* Decompress from input to the provided next_out and avail_out in the state.
On return, state->x.have and state->x.next point to the just decompressed On return, state.state->x.have and state.state->x.next point to the just decompressed
data. If the gzip stream completes, state->how is reset to LOOK to look for data. If the gzip stream completes, state.state->how is reset to LOOK to look for
the next gzip stream or raw data, once state->x.have is depleted. Returns 0 the next gzip stream or raw data, once state.state->x.have is depleted. Returns 0
on success, -1 on failure. */ on success, -1 on failure. */
local int gz_decomp(state) local int gz_decomp(state)
gz_statep state; gz_statep state;
@ -222,11 +224,11 @@ local int gz_decomp(state)
return 0; return 0;
} }
/* Fetch data and put it in the output buffer. Assumes state->x.have is 0. /* Fetch data and put it in the output buffer. Assumes state.state->x.have is 0.
Data is either copied from the input file or decompressed from the input Data is either copied from the input file or decompressed from the input
file depending on state->how. If state->how is LOOK, then a gzip header is file depending on state.state->how. If state.state->how is LOOK, then a gzip header is
looked for to determine whether to copy or decompress. Returns -1 on error, looked for to determine whether to copy or decompress. Returns -1 on error,
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the otherwise 0. gz_fetch() will leave state.state->how as COPY or GZIP unless the
end of the input file has been reached and all data has been processed. */ end of the input file has been reached and all data has been processed. */
local int gz_fetch(state) local int gz_fetch(state)
gz_statep state; gz_statep state;
@ -289,33 +291,17 @@ local int gz_skip(state, len)
return 0; return 0;
} }
/* -- see zlib.h -- */ /* Read len bytes into buf from file, or less than len up to the end of the
int ZEXPORT gzread(file, buf, len) input. Return the number of bytes read. If zero is returned, either the
gzFile file; end of file was reached, or there was an error. state.state->err must be
voidp buf; consulted in that case to determine which. */
unsigned len; local z_size_t gz_read(state, buf, len)
{
unsigned got, n;
gz_statep state; gz_statep state;
z_streamp strm; voidp buf;
z_size_t len;
/* get internal structure */ {
if (file == NULL) z_size_t got;
return -1; unsigned n;
state = (gz_statep)file;
strm = &(state.state->strm);
/* check that we're reading and that there's no (serious) error */
if (state.state->mode != GZ_READ ||
(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
return -1;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids the flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
return -1;
}
/* if len is zero, avoid unnecessary operations */ /* if len is zero, avoid unnecessary operations */
if (len == 0) if (len == 0)
@ -325,32 +311,38 @@ int ZEXPORT gzread(file, buf, len)
if (state.state->seek) { if (state.state->seek) {
state.state->seek = 0; state.state->seek = 0;
if (gz_skip(state, state.state->skip) == -1) if (gz_skip(state, state.state->skip) == -1)
return -1; return 0;
} }
/* get len bytes to buf, or less than len if at the end */ /* get len bytes to buf, or less than len if at the end */
got = 0; got = 0;
do { do {
/* set n to the maximum amount of len that fits in an unsigned int */
n = -1;
if (n > len)
n = len;
/* first just try copying data from the output buffer */ /* first just try copying data from the output buffer */
if (state.state->x.have) { if (state.state->x.have) {
n = state.state->x.have > len ? len : state.state->x.have; if (state.state->x.have < n)
n = state.state->x.have;
memcpy(buf, state.state->x.next, n); memcpy(buf, state.state->x.next, n);
state.state->x.next += n; state.state->x.next += n;
state.state->x.have -= n; state.state->x.have -= n;
} }
/* output buffer empty -- return if we're at the end of the input */ /* output buffer empty -- return if we're at the end of the input */
else if (state.state->eof && strm->avail_in == 0) { else if (state.state->eof && state.state->strm.avail_in == 0) {
state.state->past = 1; /* tried to read past end */ state.state->past = 1; /* tried to read past end */
break; break;
} }
/* need output data -- for small len or new stream load up our output /* need output data -- for small len or new stream load up our output
buffer */ buffer */
else if (state.state->how == LOOK || len < (state.state->size << 1)) { else if (state.state->how == LOOK || n < (state.state->size << 1)) {
/* get more output, looking for header if required */ /* get more output, looking for header if required */
if (gz_fetch(state) == -1) if (gz_fetch(state) == -1)
return -1; return 0;
continue; /* no progress yet -- go back to copy above */ continue; /* no progress yet -- go back to copy above */
/* the copy above assures that we will leave with space in the /* the copy above assures that we will leave with space in the
output buffer, allowing at least one gzungetc() to succeed */ output buffer, allowing at least one gzungetc() to succeed */
@ -358,16 +350,16 @@ int ZEXPORT gzread(file, buf, len)
/* large len -- read directly into user buffer */ /* large len -- read directly into user buffer */
else if (state.state->how == COPY) { /* read directly */ else if (state.state->how == COPY) { /* read directly */
if (gz_load(state, (unsigned char *)buf, len, &n) == -1) if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
return -1; return 0;
} }
/* large len -- decompress directly into user buffer */ /* large len -- decompress directly into user buffer */
else { /* state->how == GZIP */ else { /* state.state->how == GZIP */
strm->avail_out = len; state.state->strm.avail_out = n;
strm->next_out = (unsigned char *)buf; state.state->strm.next_out = (unsigned char *)buf;
if (gz_decomp(state) == -1) if (gz_decomp(state) == -1)
return -1; return 0;
n = state.state->x.have; n = state.state->x.have;
state.state->x.have = 0; state.state->x.have = 0;
} }
@ -379,8 +371,75 @@ int ZEXPORT gzread(file, buf, len)
state.state->x.pos += n; state.state->x.pos += n;
} while (len); } while (len);
/* return number of bytes read into user buffer (will fit in int) */ /* return number of bytes read into user buffer */
return (int)got; return got;
}
/* -- see zlib.h -- */
int ZEXPORT gzread(file, buf, len)
gzFile file;
voidp buf;
unsigned len;
{
gz_statep state;
/* get internal structure */
if (file == NULL)
return -1;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state.state->mode != GZ_READ ||
(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
return -1;
/* since an int is returned, make sure len fits in one, otherwise return
with an error (this avoids a flaw in the interface) */
if ((int)len < 0) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
return -1;
}
/* read len or fewer bytes to buf */
len = gz_read(state, buf, len);
/* check for an error */
if (len == 0 && state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)
return -1;
/* return the number of bytes read (this is assured to fit in an int) */
return (int)len;
}
/* -- see zlib.h -- */
z_size_t ZEXPORT gzfread(buf, size, nitems, file)
voidp buf;
z_size_t size;
z_size_t nitems;
gzFile file;
{
z_size_t len;
gz_statep state;
/* get internal structure */
if (file == NULL)
return 0;
state = (gz_statep)file;
/* check that we're reading and that there's no (serious) error */
if (state.state->mode != GZ_READ ||
(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
return 0;
/* compute bytes to read -- error on overflow */
len = nitems * size;
if (size && len / size != nitems) {
gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
return 0;
}
/* read len or fewer bytes to buf, return the number of full items read */
return len ? gz_read(state, buf, len) / size : 0;
} }
/* -- see zlib.h -- */ /* -- see zlib.h -- */
@ -401,7 +460,6 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));
#endif #endif
int ZEXPORT gzgetc(file) int ZEXPORT gzgetc(file)
gzFile file; gzFile file;
{ {
@ -426,8 +484,8 @@ int ZEXPORT gzgetc(file)
return *(state.state->x.next)++; return *(state.state->x.next)++;
} }
/* nothing there -- try gzread() */ /* nothing there -- try gz_read() */
ret = gzread(file, buf, 1); ret = gz_read(state, buf, 1);
return ret < 1 ? -1 : buf[0]; return ret < 1 ? -1 : buf[0];
} }