Add gzfread(), duplicating the interface of fread().
This commit is contained in:
138
gzread.c
138
gzread.c
@@ -12,6 +12,7 @@ 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->fd, and update state->eof, state->err, and state->msg as appropriate.
|
||||||
@@ -284,33 +285,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->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->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if len is zero, avoid unnecessary operations */
|
/* if len is zero, avoid unnecessary operations */
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
@@ -320,32 +305,38 @@ int ZEXPORT gzread(file, buf, len)
|
|||||||
if (state->seek) {
|
if (state->seek) {
|
||||||
state->seek = 0;
|
state->seek = 0;
|
||||||
if (gz_skip(state, state->skip) == -1)
|
if (gz_skip(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->x.have) {
|
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);
|
memcpy(buf, state->x.next, n);
|
||||||
state->x.next += n;
|
state->x.next += n;
|
||||||
state->x.have -= n;
|
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->eof && strm->avail_in == 0) {
|
else if (state->eof && state->strm.avail_in == 0) {
|
||||||
state->past = 1; /* tried to read past end */
|
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->how == LOOK || len < (state->size << 1)) {
|
else if (state->how == LOOK || n < (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 */
|
||||||
@@ -353,16 +344,16 @@ int ZEXPORT gzread(file, buf, len)
|
|||||||
|
|
||||||
/* large len -- read directly into user buffer */
|
/* large len -- read directly into user buffer */
|
||||||
else if (state->how == COPY) { /* read directly */
|
else if (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->how == GZIP */
|
||||||
strm->avail_out = len;
|
state->strm.avail_out = n;
|
||||||
strm->next_out = (unsigned char *)buf;
|
state->strm.next_out = (unsigned char *)buf;
|
||||||
if (gz_decomp(state) == -1)
|
if (gz_decomp(state) == -1)
|
||||||
return -1;
|
return 0;
|
||||||
n = state->x.have;
|
n = state->x.have;
|
||||||
state->x.have = 0;
|
state->x.have = 0;
|
||||||
}
|
}
|
||||||
@@ -374,8 +365,75 @@ int ZEXPORT gzread(file, buf, len)
|
|||||||
state->x.pos += n;
|
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->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 -- */
|
/* -- see zlib.h -- */
|
||||||
@@ -408,8 +466,8 @@ int ZEXPORT gzgetc(file)
|
|||||||
return *(state->x.next)++;
|
return *(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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
zlib.h
30
zlib.h
@@ -1388,7 +1388,35 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
|
|||||||
case.
|
case.
|
||||||
|
|
||||||
gzread returns the number of uncompressed bytes actually read, less than
|
gzread returns the number of uncompressed bytes actually read, less than
|
||||||
len for end of file, or -1 for error.
|
len for end of file, or -1 for error. If len is too large to fit in an int,
|
||||||
|
then nothing is read, -1 is returned, and the error state is set to
|
||||||
|
Z_STREAM_ERROR.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems,
|
||||||
|
gzFile file));
|
||||||
|
/*
|
||||||
|
Read up to nitems items of size size from file to buf, otherwise operating
|
||||||
|
as gzread() does. This duplicates the interface of stdio's fread(), with
|
||||||
|
size_t request and return types. If the library defines size_t, then
|
||||||
|
z_size_t is identical to size_t. If not, then z_size_t is an unsigned
|
||||||
|
integer type that can contain a pointer.
|
||||||
|
|
||||||
|
gzfread() returns the number of full items read of size size, or zero if
|
||||||
|
the end of the file was reached and a full item could not be read, or if
|
||||||
|
there was an error. gzerror() must be consulted if zero is returned in
|
||||||
|
order to determine if there was an error. If the multiplication of size and
|
||||||
|
nitems overflows, i.e. the product does not fit in a z_size_t, then nothing
|
||||||
|
is read, zero is returned, and the error state is set to Z_STREAM_ERROR.
|
||||||
|
|
||||||
|
In the event that the end of file is reached and only a partial item is
|
||||||
|
available at the end, i.e. the remaining uncompressed data length is not a
|
||||||
|
multiple of size, then the final partial item is nevetheless read into buf
|
||||||
|
and the end-of-file flag is set. The length of the partial item read is not
|
||||||
|
provided, but could be inferred from the result of gztell(). This behavior
|
||||||
|
is the same as the behavior of fread() implementations in common libraries,
|
||||||
|
but it prevents the direct use of gzfread() to read a concurrently written
|
||||||
|
file, reseting and retrying on end-of-file, when size is not 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
|
ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
|
||||||
|
|||||||
Reference in New Issue
Block a user