gzread.c (muscle7.61) | : | gzread.c (muscle7.62) | ||
---|---|---|---|---|
/* 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 copyright notice in zlib.h | * For conditions of distribution and use, see copyright notice in zlib.h | |||
*/ | */ | |||
#if defined(__APPLE__) || defined(__linux__) || defined(__EMSCRIPTEN__) | ||||
# include <unistd.h> // just to avoid implicit-declaration warnings --jaf | ||||
#endif | ||||
#include "gzguts.h" | #include "gzguts.h" | |||
#ifndef _WIN32 | ||||
# include <unistd.h> | ||||
#endif | ||||
/* Local functions */ | /* Local functions */ | |||
local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); | local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *)); | |||
local int gz_avail OF((gz_statep)); | local int gz_avail OF((gz_statep)); | |||
local int gz_look OF((gz_statep)); | 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. | |||
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) | |||
gz_statep state; | gz_statep state; | |||
unsigned char *buf; | unsigned char *buf; | |||
unsigned len; | unsigned len; | |||
unsigned *have; | unsigned *have; | |||
{ | { | |||
int ret; | int ret; | |||
unsigned get, max = ((unsigned)-1 >> 2) + 1; | ||||
*have = 0; | *have = 0; | |||
do { | 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) | if (ret <= 0) | |||
break; | break; | |||
*have += ret; | *have += (unsigned)ret; | |||
} while (*have < len); | } while (*have < len); | |||
if (ret < 0) { | if (ret < 0) { | |||
#if __STDC_WANT_SECURE_LIB__ | ||||
char errbuf[255]; | ||||
(void) zstrerror(errbuf, 255); | ||||
gz_error(state, Z_ERRNO, errbuf); | ||||
#else | ||||
gz_error(state, Z_ERRNO, zstrerror()); | gz_error(state, Z_ERRNO, zstrerror()); | |||
#endif | ||||
return -1; | return -1; | |||
} | } | |||
if (ret == 0) | if (ret == 0) | |||
state->eof = 1; | state->eof = 1; | |||
return 0; | return 0; | |||
} | } | |||
/* Load up input buffer and set eof flag if last data loaded -- return -1 on | /* Load up input buffer and set eof flag if last data loaded -- return -1 on | |||
error, 0 otherwise. Note that the eof flag is set when the end of the input | error, 0 otherwise. Note that the eof flag is set when the end of the input | |||
file is reached, even though there may be unused data in the buffer. Once | file is reached, even though there may be unused data in the buffer. Once | |||
skipping to change at line 105 | skipping to change at line 104 | |||
gz_look() will return 0 on success or -1 on failure. */ | gz_look() will return 0 on success or -1 on failure. */ | |||
local int gz_look(state) | local int gz_look(state) | |||
gz_statep state; | gz_statep state; | |||
{ | { | |||
z_streamp strm = &(state->strm); | z_streamp strm = &(state->strm); | |||
/* allocate read buffers and inflate memory */ | /* allocate read buffers and inflate memory */ | |||
if (state->size == 0) { | if (state->size == 0) { | |||
/* allocate buffers */ | /* allocate buffers */ | |||
state->in = (unsigned char *)malloc(state->want); | state->in = (unsigned char *)malloc(state->want); | |||
state->out = (unsigned char *)malloc(state->want * 2); | state->out = (unsigned char *)malloc(state->want << 1); | |||
if (state->in == NULL || state->out == NULL) { | if (state->in == NULL || state->out == NULL) { | |||
if (state->out != NULL) | free(state->out); | |||
free(state->out); | free(state->in); | |||
if (state->in != NULL) | ||||
free(state->in); | ||||
gz_error(state, Z_MEM_ERROR, "out of memory"); | gz_error(state, Z_MEM_ERROR, "out of memory"); | |||
return -1; | return -1; | |||
} | } | |||
state->size = state->want; | state->size = state->want; | |||
/* allocate inflate memory */ | /* allocate inflate memory */ | |||
state->strm.zalloc = Z_NULL; | state->strm.zalloc = Z_NULL; | |||
state->strm.zfree = Z_NULL; | state->strm.zfree = Z_NULL; | |||
state->strm.opaque = Z_NULL; | state->strm.opaque = Z_NULL; | |||
state->strm.avail_in = 0; | state->strm.avail_in = 0; | |||
skipping to change at line 297 | skipping to change at line 294 | |||
/* need more data to skip -- load up output buffer */ | /* need more data to skip -- load up output buffer */ | |||
else { | else { | |||
/* 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 -1; | |||
} | } | |||
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 | |||
consulted in that case to determine which. */ | ||||
local z_size_t gz_read(state, buf, len) | ||||
gz_statep state; | ||||
voidp buf; | voidp buf; | |||
unsigned len; | z_size_t len; | |||
{ | { | |||
unsigned got, n; | z_size_t got; | |||
gz_statep state; | unsigned n; | |||
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; | ||||
} | ||||
/* if len is zero, avoid unnecessary operations */ | /* if len is zero, avoid unnecessary operations */ | |||
if (len == 0) | if (len == 0) | |||
return 0; | return 0; | |||
/* process a skip request */ | /* process a skip request */ | |||
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 */ | |||
} | } | |||
/* 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; | |||
} | } | |||
/* update progress */ | /* update progress */ | |||
len -= n; | len -= n; | |||
buf = (char *)buf + n; | buf = (char *)buf + n; | |||
got += n; | got += n; | |||
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 -- */ | |||
#ifdef Z_PREFIX_SET | #ifdef Z_PREFIX_SET | |||
# undef z_gzgetc | # undef z_gzgetc | |||
#else | #else | |||
# undef gzgetc | # undef gzgetc | |||
#endif | #endif | |||
int ZEXPORT gzgetc(file) | int ZEXPORT gzgetc(file) | |||
gzFile file; | gzFile file; | |||
skipping to change at line 421 | skipping to change at line 475 | |||
(state->err != Z_OK && state->err != Z_BUF_ERROR)) | (state->err != Z_OK && state->err != Z_BUF_ERROR)) | |||
return -1; | return -1; | |||
/* try output buffer (no need to check for skip request) */ | /* try output buffer (no need to check for skip request) */ | |||
if (state->x.have) { | if (state->x.have) { | |||
state->x.have--; | state->x.have--; | |||
state->x.pos++; | state->x.pos++; | |||
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]; | |||
} | } | |||
int ZEXPORT gzgetc_(file) | int ZEXPORT gzgetc_(file) | |||
gzFile file; | gzFile file; | |||
{ | { | |||
return gzgetc(file); | return gzgetc(file); | |||
} | } | |||
/* -- see zlib.h -- */ | /* -- see zlib.h -- */ | |||
skipping to change at line 464 | skipping to change at line 518 | |||
} | } | |||
/* can't push EOF */ | /* can't push EOF */ | |||
if (c < 0) | if (c < 0) | |||
return -1; | return -1; | |||
/* if output buffer empty, put byte at end (allows more pushing) */ | /* if output buffer empty, put byte at end (allows more pushing) */ | |||
if (state->x.have == 0) { | if (state->x.have == 0) { | |||
state->x.have = 1; | state->x.have = 1; | |||
state->x.next = state->out + (state->size << 1) - 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->x.pos--; | |||
state->past = 0; | state->past = 0; | |||
return c; | return c; | |||
} | } | |||
/* if no room, give up (must have already done a gzungetc()) */ | /* if no room, give up (must have already done a gzungetc()) */ | |||
if (state->x.have == (state->size << 1)) { | if (state->x.have == (state->size << 1)) { | |||
gz_error(state, Z_DATA_ERROR, "out of room to push characters"); | gz_error(state, Z_DATA_ERROR, "out of room to push characters"); | |||
return -1; | return -1; | |||
} | } | |||
skipping to change at line 486 | skipping to change at line 540 | |||
/* slide output data if needed and insert byte before existing data */ | /* slide output data if needed and insert byte before existing data */ | |||
if (state->x.next == state->out) { | if (state->x.next == state->out) { | |||
unsigned char *src = state->out + state->x.have; | unsigned char *src = state->out + state->x.have; | |||
unsigned char *dest = state->out + (state->size << 1); | unsigned char *dest = state->out + (state->size << 1); | |||
while (src > state->out) | while (src > state->out) | |||
*--dest = *--src; | *--dest = *--src; | |||
state->x.next = dest; | state->x.next = dest; | |||
} | } | |||
state->x.have++; | state->x.have++; | |||
state->x.next--; | state->x.next--; | |||
state->x.next[0] = c; | state->x.next[0] = (unsigned char)c; | |||
state->x.pos--; | state->x.pos--; | |||
state->past = 0; | state->past = 0; | |||
return c; | return c; | |||
} | } | |||
/* -- see zlib.h -- */ | /* -- see zlib.h -- */ | |||
char * ZEXPORT gzgets(file, buf, len) | char * ZEXPORT gzgets(file, buf, len) | |||
gzFile file; | gzFile file; | |||
char *buf; | char *buf; | |||
int len; | int len; | |||
End of changes. 27 change blocks. | ||||
59 lines changed or deleted | 113 lines changed or added |