Path: blob/main/sys/contrib/zstd/zlibWrapper/gzread.c
48255 views
/* gzread.c contains minimal changes required to be compiled with zlibWrapper:1* - gz_statep was converted to union to work with -Wstrict-aliasing=1 */23/* gzread.c -- zlib functions for reading gzip files4* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler5* For conditions of distribution and use, see http://www.zlib.net/zlib_license.html6*/78#include "gzguts.h"910/* fix for Visual Studio, which doesn't support ssize_t type.11* see https://github.com/facebook/zstd/issues/1800#issuecomment-545945050 */12#if defined(_MSC_VER) && !defined(ssize_t)13# include <BaseTsd.h>14typedef SSIZE_T ssize_t;15#endif161718/* Local functions */19local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));20local int gz_avail OF((gz_statep));21local int gz_look OF((gz_statep));22local int gz_decomp OF((gz_statep));23local int gz_fetch OF((gz_statep));24local int gz_skip OF((gz_statep, z_off64_t));25local z_size_t gz_read OF((gz_statep, voidp, z_size_t));2627/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from28state.state->fd, and update state.state->eof, state.state->err, and state.state->msg as appropriate.29This function needs to loop on read(), since read() is not guaranteed to30read the number of bytes requested, depending on the type of descriptor. */31local int gz_load(state, buf, len, have)32gz_statep state;33unsigned char *buf;34unsigned len;35unsigned *have;36{37ssize_t ret;38unsigned get, max = ((unsigned)-1 >> 2) + 1;3940*have = 0;41do {42get = len - *have;43if (get > max)44get = max;45ret = read(state.state->fd, buf + *have, get);46if (ret <= 0)47break;48*have += (unsigned)ret;49} while (*have < len);50if (ret < 0) {51gz_error(state, Z_ERRNO, zstrerror());52return -1;53}54if (ret == 0)55state.state->eof = 1;56return 0;57}5859/* Load up input buffer and set eof flag if last data loaded -- return -1 on60error, 0 otherwise. Note that the eof flag is set when the end of the input61file is reached, even though there may be unused data in the buffer. Once62that data has been used, no more attempts will be made to read the file.63If strm->avail_in != 0, then the current data is moved to the beginning of64the input buffer, and then the remainder of the buffer is loaded with the65available data from the input file. */66local int gz_avail(state)67gz_statep state;68{69unsigned got;70z_streamp strm = &(state.state->strm);7172if (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)73return -1;74if (state.state->eof == 0) {75if (strm->avail_in) { /* copy what's there to the start */76unsigned char *p = state.state->in;77unsigned const char *q = strm->next_in;78unsigned n = strm->avail_in;79do {80*p++ = *q++;81} while (--n);82}83if (gz_load(state, state.state->in + strm->avail_in,84state.state->size - strm->avail_in, &got) == -1)85return -1;86strm->avail_in += got;87strm->next_in = state.state->in;88}89return 0;90}9192/* Look for gzip header, set up for inflate or copy. state.state->x.have must be 0.93If this is the first time in, allocate required memory. state.state->how will be94left unchanged if there is no more input data available, will be set to COPY95if there is no gzip header and direct copying will be performed, or it will96be set to GZIP for decompression. If direct copying, then leftover input97data from the input buffer will be copied to the output buffer. In that98case, all further file reads will be directly to either the output buffer or99a user buffer. If decompressing, the inflate state will be initialized.100gz_look() will return 0 on success or -1 on failure. */101local int gz_look(state)102gz_statep state;103{104z_streamp strm = &(state.state->strm);105106/* allocate read buffers and inflate memory */107if (state.state->size == 0) {108/* allocate buffers */109state.state->in = (unsigned char *)malloc(state.state->want);110state.state->out = (unsigned char *)malloc(state.state->want << 1);111if (state.state->in == NULL || state.state->out == NULL) {112free(state.state->out);113free(state.state->in);114gz_error(state, Z_MEM_ERROR, "out of memory");115return -1;116}117state.state->size = state.state->want;118119/* allocate inflate memory */120state.state->strm.zalloc = Z_NULL;121state.state->strm.zfree = Z_NULL;122state.state->strm.opaque = Z_NULL;123state.state->strm.avail_in = 0;124state.state->strm.next_in = Z_NULL;125if (inflateInit2(&(state.state->strm), 15 + 16) != Z_OK) { /* gunzip */126free(state.state->out);127free(state.state->in);128state.state->size = 0;129gz_error(state, Z_MEM_ERROR, "out of memory");130return -1;131}132}133134/* get at least the magic bytes in the input buffer */135if (strm->avail_in < 2) {136if (gz_avail(state) == -1)137return -1;138if (strm->avail_in == 0)139return 0;140}141142/* look for gzip magic bytes -- if there, do gzip decoding (note: there is143a logical dilemma here when considering the case of a partially written144gzip file, to wit, if a single 31 byte is written, then we cannot tell145whether this is a single-byte file, or just a partially written gzip146file -- for here we assume that if a gzip file is being written, then147the header will be written in a single operation, so that reading a148single byte is sufficient indication that it is not a gzip file) */149if (strm->avail_in > 1 &&150((strm->next_in[0] == 31 && strm->next_in[1] == 139) /* gz header */151|| (strm->next_in[0] == 40 && strm->next_in[1] == 181))) { /* zstd header */152inflateReset(strm);153state.state->how = GZIP;154state.state->direct = 0;155return 0;156}157158/* no gzip header -- if we were decoding gzip before, then this is trailing159garbage. Ignore the trailing garbage and finish. */160if (state.state->direct == 0) {161strm->avail_in = 0;162state.state->eof = 1;163state.state->x.have = 0;164return 0;165}166167/* doing raw i/o, copy any leftover input to output -- this assumes that168the output buffer is larger than the input buffer, which also assures169space for gzungetc() */170state.state->x.next = state.state->out;171if (strm->avail_in) {172memcpy(state.state->x.next, strm->next_in, strm->avail_in);173state.state->x.have = strm->avail_in;174strm->avail_in = 0;175}176state.state->how = COPY;177state.state->direct = 1;178return 0;179}180181/* Decompress from input to the provided next_out and avail_out in the state.182On return, state.state->x.have and state.state->x.next point to the just decompressed183data. If the gzip stream completes, state.state->how is reset to LOOK to look for184the next gzip stream or raw data, once state.state->x.have is depleted. Returns 0185on success, -1 on failure. */186local int gz_decomp(state)187gz_statep state;188{189int ret = Z_OK;190unsigned had;191z_streamp strm = &(state.state->strm);192193/* fill output buffer up to end of deflate stream */194had = strm->avail_out;195do {196/* get more input for inflate() */197if (strm->avail_in == 0 && gz_avail(state) == -1)198return -1;199if (strm->avail_in == 0) {200gz_error(state, Z_BUF_ERROR, "unexpected end of file");201break;202}203204/* decompress and handle errors */205ret = inflate(strm, Z_NO_FLUSH);206if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {207gz_error(state, Z_STREAM_ERROR,208"internal error: inflate stream corrupt");209return -1;210}211if (ret == Z_MEM_ERROR) {212gz_error(state, Z_MEM_ERROR, "out of memory");213return -1;214}215if (ret == Z_DATA_ERROR) { /* deflate stream invalid */216gz_error(state, Z_DATA_ERROR,217strm->msg == NULL ? "compressed data error" : strm->msg);218return -1;219}220} while (strm->avail_out && ret != Z_STREAM_END);221222/* update available output */223state.state->x.have = had - strm->avail_out;224state.state->x.next = strm->next_out - state.state->x.have;225226/* if the gzip stream completed successfully, look for another */227if (ret == Z_STREAM_END)228state.state->how = LOOK;229230/* good decompression */231return 0;232}233234/* Fetch data and put it in the output buffer. Assumes state.state->x.have is 0.235Data is either copied from the input file or decompressed from the input236file depending on state.state->how. If state.state->how is LOOK, then a gzip header is237looked for to determine whether to copy or decompress. Returns -1 on error,238otherwise 0. gz_fetch() will leave state.state->how as COPY or GZIP unless the239end of the input file has been reached and all data has been processed. */240local int gz_fetch(state)241gz_statep state;242{243z_streamp strm = &(state.state->strm);244245do {246switch(state.state->how) {247case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */248if (gz_look(state) == -1)249return -1;250if (state.state->how == LOOK)251return 0;252break;253case COPY: /* -> COPY */254if (gz_load(state, state.state->out, state.state->size << 1, &(state.state->x.have))255== -1)256return -1;257state.state->x.next = state.state->out;258return 0;259case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */260strm->avail_out = state.state->size << 1;261strm->next_out = state.state->out;262if (gz_decomp(state) == -1)263return -1;264}265} while (state.state->x.have == 0 && (!state.state->eof || strm->avail_in));266return 0;267}268269/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */270local int gz_skip(state, len)271gz_statep state;272z_off64_t len;273{274unsigned n;275276/* skip over len bytes or reach end-of-file, whichever comes first */277while (len)278/* skip over whatever is in output buffer */279if (state.state->x.have) {280n = GT_OFF(state.state->x.have) || (z_off64_t)state.state->x.have > len ?281(unsigned)len : state.state->x.have;282state.state->x.have -= n;283state.state->x.next += n;284state.state->x.pos += n;285len -= n;286}287288/* output buffer empty -- return if we're at the end of the input */289else if (state.state->eof && state.state->strm.avail_in == 0)290break;291292/* need more data to skip -- load up output buffer */293else {294/* get more output, looking for header if required */295if (gz_fetch(state) == -1)296return -1;297}298return 0;299}300301/* Read len bytes into buf from file, or less than len up to the end of the302input. Return the number of bytes read. If zero is returned, either the303end of file was reached, or there was an error. state.state->err must be304consulted in that case to determine which. */305local z_size_t gz_read(state, buf, len)306gz_statep state;307voidp buf;308z_size_t len;309{310z_size_t got;311unsigned n;312313/* if len is zero, avoid unnecessary operations */314if (len == 0)315return 0;316317/* process a skip request */318if (state.state->seek) {319state.state->seek = 0;320if (gz_skip(state, state.state->skip) == -1)321return 0;322}323324/* get len bytes to buf, or less than len if at the end */325got = 0;326do {327/* set n to the maximum amount of len that fits in an unsigned int */328n = -1;329if (n > len)330n = (unsigned)len;331332/* first just try copying data from the output buffer */333if (state.state->x.have) {334if (state.state->x.have < n)335n = state.state->x.have;336memcpy(buf, state.state->x.next, n);337state.state->x.next += n;338state.state->x.have -= n;339}340341/* output buffer empty -- return if we're at the end of the input */342else if (state.state->eof && state.state->strm.avail_in == 0) {343state.state->past = 1; /* tried to read past end */344break;345}346347/* need output data -- for small len or new stream load up our output348buffer */349else if (state.state->how == LOOK || n < (state.state->size << 1)) {350/* get more output, looking for header if required */351if (gz_fetch(state) == -1)352return 0;353continue; /* no progress yet -- go back to copy above */354/* the copy above assures that we will leave with space in the355output buffer, allowing at least one gzungetc() to succeed */356}357358/* large len -- read directly into user buffer */359else if (state.state->how == COPY) { /* read directly */360if (gz_load(state, (unsigned char *)buf, n, &n) == -1)361return 0;362}363364/* large len -- decompress directly into user buffer */365else { /* state.state->how == GZIP */366state.state->strm.avail_out = n;367state.state->strm.next_out = (unsigned char *)buf;368if (gz_decomp(state) == -1)369return 0;370n = state.state->x.have;371state.state->x.have = 0;372}373374/* update progress */375len -= n;376buf = (char *)buf + n;377got += n;378state.state->x.pos += n;379} while (len);380381/* return number of bytes read into user buffer */382return got;383}384385/* -- see zlib.h -- */386int ZEXPORT gzread(file, buf, len)387gzFile file;388voidp buf;389unsigned len;390{391gz_statep state;392393/* get internal structure */394if (file == NULL)395return -1;396state.file = file;397398/* check that we're reading and that there's no (serious) error */399if (state.state->mode != GZ_READ ||400(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))401return -1;402403/* since an int is returned, make sure len fits in one, otherwise return404with an error (this avoids a flaw in the interface) */405if ((int)len < 0) {406gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");407return -1;408}409410/* read len or fewer bytes to buf */411len = (unsigned)gz_read(state, buf, len);412413/* check for an error */414if (len == 0 && state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)415return -1;416417/* return the number of bytes read (this is assured to fit in an int) */418return (int)len;419}420421/* -- see zlib.h -- */422z_size_t ZEXPORT gzfread(buf, size, nitems, file)423voidp buf;424z_size_t size;425z_size_t nitems;426gzFile file;427{428z_size_t len;429gz_statep state;430431/* get internal structure */432if (file == NULL)433return 0;434state.file = file;435436/* check that we're reading and that there's no (serious) error */437if (state.state->mode != GZ_READ ||438(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))439return 0;440441/* compute bytes to read -- error on overflow */442len = nitems * size;443if (size && len / size != nitems) {444gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");445return 0;446}447448/* read len or fewer bytes to buf, return the number of full items read */449return len ? gz_read(state, buf, len) / size : 0;450}451452/* -- see zlib.h -- */453#if ZLIB_VERNUM >= 0x1261454#ifdef Z_PREFIX_SET455# undef z_gzgetc456#else457# undef gzgetc458#endif459#endif460461#if ZLIB_VERNUM == 0x1260462# undef gzgetc463#endif464465#if ZLIB_VERNUM <= 0x1250466ZEXTERN int ZEXPORT gzgetc OF((gzFile file));467ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));468#endif469470int ZEXPORT gzgetc(file)471gzFile file;472{473int ret;474unsigned char buf[1];475gz_statep state;476477/* get internal structure */478if (file == NULL)479return -1;480state.file = file;481482/* check that we're reading and that there's no (serious) error */483if (state.state->mode != GZ_READ ||484(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))485return -1;486487/* try output buffer (no need to check for skip request) */488if (state.state->x.have) {489state.state->x.have--;490state.state->x.pos++;491return *(state.state->x.next)++;492}493494/* nothing there -- try gz_read() */495ret = (int)gz_read(state, buf, 1);496return ret < 1 ? -1 : buf[0];497}498499int ZEXPORT gzgetc_(file)500gzFile file;501{502return gzgetc(file);503}504505/* -- see zlib.h -- */506int ZEXPORT gzungetc(c, file)507int c;508gzFile file;509{510gz_statep state;511512/* get internal structure */513if (file == NULL)514return -1;515state.file = file;516517/* check that we're reading and that there's no (serious) error */518if (state.state->mode != GZ_READ ||519(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))520return -1;521522/* process a skip request */523if (state.state->seek) {524state.state->seek = 0;525if (gz_skip(state, state.state->skip) == -1)526return -1;527}528529/* can't push EOF */530if (c < 0)531return -1;532533/* if output buffer empty, put byte at end (allows more pushing) */534if (state.state->x.have == 0) {535state.state->x.have = 1;536state.state->x.next = state.state->out + (state.state->size << 1) - 1;537state.state->x.next[0] = (unsigned char)c;538state.state->x.pos--;539state.state->past = 0;540return c;541}542543/* if no room, give up (must have already done a gzungetc()) */544if (state.state->x.have == (state.state->size << 1)) {545gz_error(state, Z_DATA_ERROR, "out of room to push characters");546return -1;547}548549/* slide output data if needed and insert byte before existing data */550if (state.state->x.next == state.state->out) {551unsigned char *src = state.state->out + state.state->x.have;552unsigned char *dest = state.state->out + (state.state->size << 1);553while (src > state.state->out)554*--dest = *--src;555state.state->x.next = dest;556}557state.state->x.have++;558state.state->x.next--;559state.state->x.next[0] = (unsigned char)c;560state.state->x.pos--;561state.state->past = 0;562return c;563}564565/* -- see zlib.h -- */566char * ZEXPORT gzgets(file, buf, len)567gzFile file;568char *buf;569int len;570{571unsigned left, n;572char *str;573unsigned char *eol;574gz_statep state;575576/* check parameters and get internal structure */577if (file == NULL || buf == NULL || len < 1)578return NULL;579state.file = file;580581/* check that we're reading and that there's no (serious) error */582if (state.state->mode != GZ_READ ||583(state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))584return NULL;585586/* process a skip request */587if (state.state->seek) {588state.state->seek = 0;589if (gz_skip(state, state.state->skip) == -1)590return NULL;591}592593/* copy output bytes up to new line or len - 1, whichever comes first --594append a terminating zero to the string (we don't check for a zero in595the contents, let the user worry about that) */596str = buf;597left = (unsigned)len - 1;598if (left) do {599/* assure that something is in the output buffer */600if (state.state->x.have == 0 && gz_fetch(state) == -1)601return NULL; /* error */602if (state.state->x.have == 0) { /* end of file */603state.state->past = 1; /* read past end */604break; /* return what we have */605}606607/* look for end-of-line in current output buffer */608n = state.state->x.have > left ? left : state.state->x.have;609eol = (unsigned char *)memchr(state.state->x.next, '\n', n);610if (eol != NULL)611n = (unsigned)(eol - state.state->x.next) + 1;612613/* copy through end-of-line, or remainder if not found */614memcpy(buf, state.state->x.next, n);615state.state->x.have -= n;616state.state->x.next += n;617state.state->x.pos += n;618left -= n;619buf += n;620} while (left && eol == NULL);621622/* return terminated string, or if nothing, end of file */623if (buf == str)624return NULL;625buf[0] = 0;626return str;627}628629/* -- see zlib.h -- */630int ZEXPORT gzdirect(file)631gzFile file;632{633gz_statep state;634635/* get internal structure */636if (file == NULL)637return 0;638state.file = file;639640/* if the state is not known, but we can find out, then do so (this is641mainly for right after a gzopen() or gzdopen()) */642if (state.state->mode == GZ_READ && state.state->how == LOOK && state.state->x.have == 0)643(void)gz_look(state);644645/* return 1 if transparent, 0 if processing a gzip stream */646return state.state->direct;647}648649/* -- see zlib.h -- */650int ZEXPORT gzclose_r(file)651gzFile file;652{653int ret, err;654gz_statep state;655656/* get internal structure */657if (file == NULL)658return Z_STREAM_ERROR;659state.file = file;660661/* check that we're reading */662if (state.state->mode != GZ_READ)663return Z_STREAM_ERROR;664665/* free memory and close file */666if (state.state->size) {667inflateEnd(&(state.state->strm));668free(state.state->out);669free(state.state->in);670}671err = state.state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;672gz_error(state, Z_OK, NULL);673free(state.state->path);674ret = close(state.state->fd);675free(state.state);676return ret ? Z_ERRNO : err;677}678679680