summaryrefslogtreecommitdiffstats
path: root/compat/zlib/gzread.c
diff options
context:
space:
mode:
Diffstat (limited to 'compat/zlib/gzread.c')
-rw-r--r--compat/zlib/gzread.c156
1 files changed, 108 insertions, 48 deletions
diff --git a/compat/zlib/gzread.c b/compat/zlib/gzread.c
index bf4538e..956b91e 100644
--- a/compat/zlib/gzread.c
+++ b/compat/zlib/gzread.c
@@ -1,5 +1,5 @@
/* 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 copyright notice in zlib.h
*/
@@ -12,6 +12,7 @@ local int gz_look OF((gz_statep));
local int gz_decomp OF((gz_statep));
local int gz_fetch OF((gz_statep));
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
state->fd, and update state->eof, state->err, and state->msg as appropriate.
@@ -24,13 +25,17 @@ local int gz_load(state, buf, len, have)
unsigned *have;
{
int ret;
+ unsigned get, max = ((unsigned)-1 >> 2) + 1;
*have = 0;
do {
- ret = read(state->fd, buf + *have, len - *have);
+ get = len - *have;
+ if (get > max)
+ get = max;
+ ret = read(state->fd, buf + *have, get);
if (ret <= 0)
break;
- *have += ret;
+ *have += (unsigned)ret;
} while (*have < len);
if (ret < 0) {
gz_error(state, Z_ERRNO, zstrerror());
@@ -94,10 +99,8 @@ local int gz_look(state)
state->in = (unsigned char *)malloc(state->want);
state->out = (unsigned char *)malloc(state->want << 1);
if (state->in == NULL || state->out == NULL) {
- if (state->out != NULL)
- free(state->out);
- if (state->in != NULL)
- free(state->in);
+ free(state->out);
+ free(state->in);
gz_error(state, Z_MEM_ERROR, "out of memory");
return -1;
}
@@ -284,33 +287,17 @@ local int gz_skip(state, len)
return 0;
}
-/* -- see zlib.h -- */
-int ZEXPORT gzread(file, buf, len)
- gzFile file;
+/* Read len bytes into buf from file, or less than len up to the end of the
+ input. Return the number of bytes read. If zero is returned, either the
+ end of file was reached, or there was an error. state->err must be
+ consulted in that case to determine which. */
+local z_size_t gz_read(state, buf, len)
+ gz_statep state;
voidp buf;
- unsigned len;
+ z_size_t len;
{
- unsigned got, n;
- gz_statep state;
- z_streamp strm;
-
- /* get internal structure */
- if (file == NULL)
- return -1;
- state = (gz_statep)file;
- strm = &(state->strm);
-
- /* check that we're reading and that there's no (serious) error */
- if (state->mode != GZ_READ ||
- (state->err != Z_OK && 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;
- }
+ z_size_t got;
+ unsigned n;
/* if len is zero, avoid unnecessary operations */
if (len == 0)
@@ -320,32 +307,38 @@ int ZEXPORT gzread(file, buf, len)
if (state->seek) {
state->seek = 0;
if (gz_skip(state, state->skip) == -1)
- return -1;
+ return 0;
}
/* get len bytes to buf, or less than len if at the end */
got = 0;
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 */
if (state->x.have) {
- n = state->x.have > len ? len : state->x.have;
+ if (state->x.have < n)
+ n = state->x.have;
memcpy(buf, state->x.next, n);
state->x.next += n;
state->x.have -= n;
}
/* output buffer empty -- return if we're at the end of the input */
- else if (state->eof && strm->avail_in == 0) {
+ else if (state->eof && state->strm.avail_in == 0) {
state->past = 1; /* tried to read past end */
break;
}
/* need output data -- for small len or new stream load up our output
buffer */
- else if (state->how == LOOK || len < (state->size << 1)) {
+ else if (state->how == LOOK || n < (state->size << 1)) {
/* get more output, looking for header if required */
if (gz_fetch(state) == -1)
- return -1;
+ return 0;
continue; /* no progress yet -- go back to copy above */
/* the copy above assures that we will leave with space in the
output buffer, allowing at least one gzungetc() to succeed */
@@ -353,16 +346,16 @@ int ZEXPORT gzread(file, buf, len)
/* large len -- read directly into user buffer */
else if (state->how == COPY) { /* read directly */
- if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
- return -1;
+ if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
+ return 0;
}
/* large len -- decompress directly into user buffer */
else { /* state->how == GZIP */
- strm->avail_out = len;
- strm->next_out = (unsigned char *)buf;
+ state->strm.avail_out = n;
+ state->strm.next_out = (unsigned char *)buf;
if (gz_decomp(state) == -1)
- return -1;
+ return 0;
n = state->x.have;
state->x.have = 0;
}
@@ -374,8 +367,75 @@ int ZEXPORT gzread(file, buf, len)
state->x.pos += n;
} while (len);
- /* return number of bytes read into user buffer (will fit in int) */
- return (int)got;
+ /* return number of bytes read into user buffer */
+ 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->mode != GZ_READ ||
+ (state->err != Z_OK && 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->err != Z_OK && 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->mode != GZ_READ ||
+ (state->err != Z_OK && 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 -- */
@@ -408,8 +468,8 @@ int ZEXPORT gzgetc(file)
return *(state->x.next)++;
}
- /* nothing there -- try gzread() */
- ret = gzread(file, buf, 1);
+ /* nothing there -- try gz_read() */
+ ret = gz_read(state, buf, 1);
return ret < 1 ? -1 : buf[0];
}
@@ -451,7 +511,7 @@ int ZEXPORT gzungetc(c, file)
if (state->x.have == 0) {
state->x.have = 1;
state->x.next = state->out + (state->size << 1) - 1;
- state->x.next[0] = c;
+ state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;
@@ -473,7 +533,7 @@ int ZEXPORT gzungetc(c, file)
}
state->x.have++;
state->x.next--;
- state->x.next[0] = c;
+ state->x.next[0] = (unsigned char)c;
state->x.pos--;
state->past = 0;
return c;