10c16b537SWarner Losh /* gzread.c contains minimal changes required to be compiled with zlibWrapper:
20c16b537SWarner Losh * - gz_statep was converted to union to work with -Wstrict-aliasing=1 */
30c16b537SWarner Losh
40c16b537SWarner Losh /* gzread.c -- zlib functions for reading gzip files
50c16b537SWarner Losh * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
60c16b537SWarner Losh * For conditions of distribution and use, see http://www.zlib.net/zlib_license.html
70c16b537SWarner Losh */
80c16b537SWarner Losh
90c16b537SWarner Losh #include "gzguts.h"
100c16b537SWarner Losh
11*9cbefe25SConrad Meyer /* fix for Visual Studio, which doesn't support ssize_t type.
12*9cbefe25SConrad Meyer * see https://github.com/facebook/zstd/issues/1800#issuecomment-545945050 */
13*9cbefe25SConrad Meyer #if defined(_MSC_VER) && !defined(ssize_t)
14*9cbefe25SConrad Meyer # include <BaseTsd.h>
15*9cbefe25SConrad Meyer typedef SSIZE_T ssize_t;
16*9cbefe25SConrad Meyer #endif
17*9cbefe25SConrad Meyer
18*9cbefe25SConrad Meyer
190c16b537SWarner Losh /* Local functions */
200c16b537SWarner Losh local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
210c16b537SWarner Losh local int gz_avail OF((gz_statep));
220c16b537SWarner Losh local int gz_look OF((gz_statep));
230c16b537SWarner Losh local int gz_decomp OF((gz_statep));
240c16b537SWarner Losh local int gz_fetch OF((gz_statep));
250c16b537SWarner Losh local int gz_skip OF((gz_statep, z_off64_t));
260c16b537SWarner Losh local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
270c16b537SWarner Losh
280c16b537SWarner Losh /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
290c16b537SWarner Losh state.state->fd, and update state.state->eof, state.state->err, and state.state->msg as appropriate.
300c16b537SWarner Losh This function needs to loop on read(), since read() is not guaranteed to
310c16b537SWarner Losh read the number of bytes requested, depending on the type of descriptor. */
gz_load(state,buf,len,have)320c16b537SWarner Losh local int gz_load(state, buf, len, have)
330c16b537SWarner Losh gz_statep state;
340c16b537SWarner Losh unsigned char *buf;
350c16b537SWarner Losh unsigned len;
360c16b537SWarner Losh unsigned *have;
370c16b537SWarner Losh {
380c16b537SWarner Losh ssize_t ret;
390c16b537SWarner Losh unsigned get, max = ((unsigned)-1 >> 2) + 1;
400c16b537SWarner Losh
410c16b537SWarner Losh *have = 0;
420c16b537SWarner Losh do {
430c16b537SWarner Losh get = len - *have;
440c16b537SWarner Losh if (get > max)
450c16b537SWarner Losh get = max;
460c16b537SWarner Losh ret = read(state.state->fd, buf + *have, get);
470c16b537SWarner Losh if (ret <= 0)
480c16b537SWarner Losh break;
490c16b537SWarner Losh *have += (unsigned)ret;
500c16b537SWarner Losh } while (*have < len);
510c16b537SWarner Losh if (ret < 0) {
520c16b537SWarner Losh gz_error(state, Z_ERRNO, zstrerror());
530c16b537SWarner Losh return -1;
540c16b537SWarner Losh }
550c16b537SWarner Losh if (ret == 0)
560c16b537SWarner Losh state.state->eof = 1;
570c16b537SWarner Losh return 0;
580c16b537SWarner Losh }
590c16b537SWarner Losh
600c16b537SWarner Losh /* Load up input buffer and set eof flag if last data loaded -- return -1 on
610c16b537SWarner Losh error, 0 otherwise. Note that the eof flag is set when the end of the input
620c16b537SWarner Losh file is reached, even though there may be unused data in the buffer. Once
630c16b537SWarner Losh that data has been used, no more attempts will be made to read the file.
640c16b537SWarner Losh If strm->avail_in != 0, then the current data is moved to the beginning of
650c16b537SWarner Losh the input buffer, and then the remainder of the buffer is loaded with the
660c16b537SWarner Losh available data from the input file. */
gz_avail(state)670c16b537SWarner Losh local int gz_avail(state)
680c16b537SWarner Losh gz_statep state;
690c16b537SWarner Losh {
700c16b537SWarner Losh unsigned got;
710c16b537SWarner Losh z_streamp strm = &(state.state->strm);
720c16b537SWarner Losh
730c16b537SWarner Losh if (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)
740c16b537SWarner Losh return -1;
750c16b537SWarner Losh if (state.state->eof == 0) {
760c16b537SWarner Losh if (strm->avail_in) { /* copy what's there to the start */
770c16b537SWarner Losh unsigned char *p = state.state->in;
780c16b537SWarner Losh unsigned const char *q = strm->next_in;
790c16b537SWarner Losh unsigned n = strm->avail_in;
800c16b537SWarner Losh do {
810c16b537SWarner Losh *p++ = *q++;
820c16b537SWarner Losh } while (--n);
830c16b537SWarner Losh }
840c16b537SWarner Losh if (gz_load(state, state.state->in + strm->avail_in,
850c16b537SWarner Losh state.state->size - strm->avail_in, &got) == -1)
860c16b537SWarner Losh return -1;
870c16b537SWarner Losh strm->avail_in += got;
880c16b537SWarner Losh strm->next_in = state.state->in;
890c16b537SWarner Losh }
900c16b537SWarner Losh return 0;
910c16b537SWarner Losh }
920c16b537SWarner Losh
930c16b537SWarner Losh /* Look for gzip header, set up for inflate or copy. state.state->x.have must be 0.
940c16b537SWarner Losh If this is the first time in, allocate required memory. state.state->how will be
950c16b537SWarner Losh left unchanged if there is no more input data available, will be set to COPY
960c16b537SWarner Losh if there is no gzip header and direct copying will be performed, or it will
970c16b537SWarner Losh be set to GZIP for decompression. If direct copying, then leftover input
980c16b537SWarner Losh data from the input buffer will be copied to the output buffer. In that
990c16b537SWarner Losh case, all further file reads will be directly to either the output buffer or
1000c16b537SWarner Losh a user buffer. If decompressing, the inflate state will be initialized.
1010c16b537SWarner Losh gz_look() will return 0 on success or -1 on failure. */
gz_look(state)1020c16b537SWarner Losh local int gz_look(state)
1030c16b537SWarner Losh gz_statep state;
1040c16b537SWarner Losh {
1050c16b537SWarner Losh z_streamp strm = &(state.state->strm);
1060c16b537SWarner Losh
1070c16b537SWarner Losh /* allocate read buffers and inflate memory */
1080c16b537SWarner Losh if (state.state->size == 0) {
1090c16b537SWarner Losh /* allocate buffers */
1100c16b537SWarner Losh state.state->in = (unsigned char *)malloc(state.state->want);
1110c16b537SWarner Losh state.state->out = (unsigned char *)malloc(state.state->want << 1);
1120c16b537SWarner Losh if (state.state->in == NULL || state.state->out == NULL) {
1130c16b537SWarner Losh free(state.state->out);
1140c16b537SWarner Losh free(state.state->in);
1150c16b537SWarner Losh gz_error(state, Z_MEM_ERROR, "out of memory");
1160c16b537SWarner Losh return -1;
1170c16b537SWarner Losh }
1180c16b537SWarner Losh state.state->size = state.state->want;
1190c16b537SWarner Losh
1200c16b537SWarner Losh /* allocate inflate memory */
1210c16b537SWarner Losh state.state->strm.zalloc = Z_NULL;
1220c16b537SWarner Losh state.state->strm.zfree = Z_NULL;
1230c16b537SWarner Losh state.state->strm.opaque = Z_NULL;
1240c16b537SWarner Losh state.state->strm.avail_in = 0;
1250c16b537SWarner Losh state.state->strm.next_in = Z_NULL;
1260c16b537SWarner Losh if (inflateInit2(&(state.state->strm), 15 + 16) != Z_OK) { /* gunzip */
1270c16b537SWarner Losh free(state.state->out);
1280c16b537SWarner Losh free(state.state->in);
1290c16b537SWarner Losh state.state->size = 0;
1300c16b537SWarner Losh gz_error(state, Z_MEM_ERROR, "out of memory");
1310c16b537SWarner Losh return -1;
1320c16b537SWarner Losh }
1330c16b537SWarner Losh }
1340c16b537SWarner Losh
1350c16b537SWarner Losh /* get at least the magic bytes in the input buffer */
1360c16b537SWarner Losh if (strm->avail_in < 2) {
1370c16b537SWarner Losh if (gz_avail(state) == -1)
1380c16b537SWarner Losh return -1;
1390c16b537SWarner Losh if (strm->avail_in == 0)
1400c16b537SWarner Losh return 0;
1410c16b537SWarner Losh }
1420c16b537SWarner Losh
1430c16b537SWarner Losh /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
1440c16b537SWarner Losh a logical dilemma here when considering the case of a partially written
1450c16b537SWarner Losh gzip file, to wit, if a single 31 byte is written, then we cannot tell
1460c16b537SWarner Losh whether this is a single-byte file, or just a partially written gzip
1470c16b537SWarner Losh file -- for here we assume that if a gzip file is being written, then
1480c16b537SWarner Losh the header will be written in a single operation, so that reading a
1490c16b537SWarner Losh single byte is sufficient indication that it is not a gzip file) */
1500c16b537SWarner Losh if (strm->avail_in > 1 &&
1510c16b537SWarner Losh ((strm->next_in[0] == 31 && strm->next_in[1] == 139) /* gz header */
1520c16b537SWarner Losh || (strm->next_in[0] == 40 && strm->next_in[1] == 181))) { /* zstd header */
1530c16b537SWarner Losh inflateReset(strm);
1540c16b537SWarner Losh state.state->how = GZIP;
1550c16b537SWarner Losh state.state->direct = 0;
1560c16b537SWarner Losh return 0;
1570c16b537SWarner Losh }
1580c16b537SWarner Losh
1590c16b537SWarner Losh /* no gzip header -- if we were decoding gzip before, then this is trailing
1600c16b537SWarner Losh garbage. Ignore the trailing garbage and finish. */
1610c16b537SWarner Losh if (state.state->direct == 0) {
1620c16b537SWarner Losh strm->avail_in = 0;
1630c16b537SWarner Losh state.state->eof = 1;
1640c16b537SWarner Losh state.state->x.have = 0;
1650c16b537SWarner Losh return 0;
1660c16b537SWarner Losh }
1670c16b537SWarner Losh
1680c16b537SWarner Losh /* doing raw i/o, copy any leftover input to output -- this assumes that
1690c16b537SWarner Losh the output buffer is larger than the input buffer, which also assures
1700c16b537SWarner Losh space for gzungetc() */
1710c16b537SWarner Losh state.state->x.next = state.state->out;
1720c16b537SWarner Losh if (strm->avail_in) {
1730c16b537SWarner Losh memcpy(state.state->x.next, strm->next_in, strm->avail_in);
1740c16b537SWarner Losh state.state->x.have = strm->avail_in;
1750c16b537SWarner Losh strm->avail_in = 0;
1760c16b537SWarner Losh }
1770c16b537SWarner Losh state.state->how = COPY;
1780c16b537SWarner Losh state.state->direct = 1;
1790c16b537SWarner Losh return 0;
1800c16b537SWarner Losh }
1810c16b537SWarner Losh
1820c16b537SWarner Losh /* Decompress from input to the provided next_out and avail_out in the state.
1830c16b537SWarner Losh On return, state.state->x.have and state.state->x.next point to the just decompressed
1840c16b537SWarner Losh data. If the gzip stream completes, state.state->how is reset to LOOK to look for
1850c16b537SWarner Losh the next gzip stream or raw data, once state.state->x.have is depleted. Returns 0
1860c16b537SWarner Losh on success, -1 on failure. */
gz_decomp(state)1870c16b537SWarner Losh local int gz_decomp(state)
1880c16b537SWarner Losh gz_statep state;
1890c16b537SWarner Losh {
1900c16b537SWarner Losh int ret = Z_OK;
1910c16b537SWarner Losh unsigned had;
1920c16b537SWarner Losh z_streamp strm = &(state.state->strm);
1930c16b537SWarner Losh
1940c16b537SWarner Losh /* fill output buffer up to end of deflate stream */
1950c16b537SWarner Losh had = strm->avail_out;
1960c16b537SWarner Losh do {
1970c16b537SWarner Losh /* get more input for inflate() */
1980c16b537SWarner Losh if (strm->avail_in == 0 && gz_avail(state) == -1)
1990c16b537SWarner Losh return -1;
2000c16b537SWarner Losh if (strm->avail_in == 0) {
2010c16b537SWarner Losh gz_error(state, Z_BUF_ERROR, "unexpected end of file");
2020c16b537SWarner Losh break;
2030c16b537SWarner Losh }
2040c16b537SWarner Losh
2050c16b537SWarner Losh /* decompress and handle errors */
2060c16b537SWarner Losh ret = inflate(strm, Z_NO_FLUSH);
2070c16b537SWarner Losh if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
2080c16b537SWarner Losh gz_error(state, Z_STREAM_ERROR,
2090c16b537SWarner Losh "internal error: inflate stream corrupt");
2100c16b537SWarner Losh return -1;
2110c16b537SWarner Losh }
2120c16b537SWarner Losh if (ret == Z_MEM_ERROR) {
2130c16b537SWarner Losh gz_error(state, Z_MEM_ERROR, "out of memory");
2140c16b537SWarner Losh return -1;
2150c16b537SWarner Losh }
2160c16b537SWarner Losh if (ret == Z_DATA_ERROR) { /* deflate stream invalid */
2170c16b537SWarner Losh gz_error(state, Z_DATA_ERROR,
2180c16b537SWarner Losh strm->msg == NULL ? "compressed data error" : strm->msg);
2190c16b537SWarner Losh return -1;
2200c16b537SWarner Losh }
2210c16b537SWarner Losh } while (strm->avail_out && ret != Z_STREAM_END);
2220c16b537SWarner Losh
2230c16b537SWarner Losh /* update available output */
2240c16b537SWarner Losh state.state->x.have = had - strm->avail_out;
2250c16b537SWarner Losh state.state->x.next = strm->next_out - state.state->x.have;
2260c16b537SWarner Losh
2270c16b537SWarner Losh /* if the gzip stream completed successfully, look for another */
2280c16b537SWarner Losh if (ret == Z_STREAM_END)
2290c16b537SWarner Losh state.state->how = LOOK;
2300c16b537SWarner Losh
2310c16b537SWarner Losh /* good decompression */
2320c16b537SWarner Losh return 0;
2330c16b537SWarner Losh }
2340c16b537SWarner Losh
2350c16b537SWarner Losh /* Fetch data and put it in the output buffer. Assumes state.state->x.have is 0.
2360c16b537SWarner Losh Data is either copied from the input file or decompressed from the input
2370c16b537SWarner Losh file depending on state.state->how. If state.state->how is LOOK, then a gzip header is
2380c16b537SWarner Losh looked for to determine whether to copy or decompress. Returns -1 on error,
2390c16b537SWarner Losh otherwise 0. gz_fetch() will leave state.state->how as COPY or GZIP unless the
2400c16b537SWarner Losh end of the input file has been reached and all data has been processed. */
gz_fetch(state)2410c16b537SWarner Losh local int gz_fetch(state)
2420c16b537SWarner Losh gz_statep state;
2430c16b537SWarner Losh {
2440c16b537SWarner Losh z_streamp strm = &(state.state->strm);
2450c16b537SWarner Losh
2460c16b537SWarner Losh do {
2470c16b537SWarner Losh switch(state.state->how) {
2480c16b537SWarner Losh case LOOK: /* -> LOOK, COPY (only if never GZIP), or GZIP */
2490c16b537SWarner Losh if (gz_look(state) == -1)
2500c16b537SWarner Losh return -1;
2510c16b537SWarner Losh if (state.state->how == LOOK)
2520c16b537SWarner Losh return 0;
2530c16b537SWarner Losh break;
2540c16b537SWarner Losh case COPY: /* -> COPY */
2550c16b537SWarner Losh if (gz_load(state, state.state->out, state.state->size << 1, &(state.state->x.have))
2560c16b537SWarner Losh == -1)
2570c16b537SWarner Losh return -1;
2580c16b537SWarner Losh state.state->x.next = state.state->out;
2590c16b537SWarner Losh return 0;
2600c16b537SWarner Losh case GZIP: /* -> GZIP or LOOK (if end of gzip stream) */
2610c16b537SWarner Losh strm->avail_out = state.state->size << 1;
2620c16b537SWarner Losh strm->next_out = state.state->out;
2630c16b537SWarner Losh if (gz_decomp(state) == -1)
2640c16b537SWarner Losh return -1;
2650c16b537SWarner Losh }
2660c16b537SWarner Losh } while (state.state->x.have == 0 && (!state.state->eof || strm->avail_in));
2670c16b537SWarner Losh return 0;
2680c16b537SWarner Losh }
2690c16b537SWarner Losh
2700c16b537SWarner Losh /* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
gz_skip(state,len)2710c16b537SWarner Losh local int gz_skip(state, len)
2720c16b537SWarner Losh gz_statep state;
2730c16b537SWarner Losh z_off64_t len;
2740c16b537SWarner Losh {
2750c16b537SWarner Losh unsigned n;
2760c16b537SWarner Losh
2770c16b537SWarner Losh /* skip over len bytes or reach end-of-file, whichever comes first */
2780c16b537SWarner Losh while (len)
2790c16b537SWarner Losh /* skip over whatever is in output buffer */
2800c16b537SWarner Losh if (state.state->x.have) {
2810c16b537SWarner Losh n = GT_OFF(state.state->x.have) || (z_off64_t)state.state->x.have > len ?
2820c16b537SWarner Losh (unsigned)len : state.state->x.have;
2830c16b537SWarner Losh state.state->x.have -= n;
2840c16b537SWarner Losh state.state->x.next += n;
2850c16b537SWarner Losh state.state->x.pos += n;
2860c16b537SWarner Losh len -= n;
2870c16b537SWarner Losh }
2880c16b537SWarner Losh
2890c16b537SWarner Losh /* output buffer empty -- return if we're at the end of the input */
2900c16b537SWarner Losh else if (state.state->eof && state.state->strm.avail_in == 0)
2910c16b537SWarner Losh break;
2920c16b537SWarner Losh
2930c16b537SWarner Losh /* need more data to skip -- load up output buffer */
2940c16b537SWarner Losh else {
2950c16b537SWarner Losh /* get more output, looking for header if required */
2960c16b537SWarner Losh if (gz_fetch(state) == -1)
2970c16b537SWarner Losh return -1;
2980c16b537SWarner Losh }
2990c16b537SWarner Losh return 0;
3000c16b537SWarner Losh }
3010c16b537SWarner Losh
3020c16b537SWarner Losh /* Read len bytes into buf from file, or less than len up to the end of the
3030c16b537SWarner Losh input. Return the number of bytes read. If zero is returned, either the
3040c16b537SWarner Losh end of file was reached, or there was an error. state.state->err must be
3050c16b537SWarner Losh consulted in that case to determine which. */
gz_read(state,buf,len)3060c16b537SWarner Losh local z_size_t gz_read(state, buf, len)
3070c16b537SWarner Losh gz_statep state;
3080c16b537SWarner Losh voidp buf;
3090c16b537SWarner Losh z_size_t len;
3100c16b537SWarner Losh {
3110c16b537SWarner Losh z_size_t got;
3120c16b537SWarner Losh unsigned n;
3130c16b537SWarner Losh
3140c16b537SWarner Losh /* if len is zero, avoid unnecessary operations */
3150c16b537SWarner Losh if (len == 0)
3160c16b537SWarner Losh return 0;
3170c16b537SWarner Losh
3180c16b537SWarner Losh /* process a skip request */
3190c16b537SWarner Losh if (state.state->seek) {
3200c16b537SWarner Losh state.state->seek = 0;
3210c16b537SWarner Losh if (gz_skip(state, state.state->skip) == -1)
3220c16b537SWarner Losh return 0;
3230c16b537SWarner Losh }
3240c16b537SWarner Losh
3250c16b537SWarner Losh /* get len bytes to buf, or less than len if at the end */
3260c16b537SWarner Losh got = 0;
3270c16b537SWarner Losh do {
3280c16b537SWarner Losh /* set n to the maximum amount of len that fits in an unsigned int */
3290c16b537SWarner Losh n = -1;
3300c16b537SWarner Losh if (n > len)
3310c16b537SWarner Losh n = (unsigned)len;
3320c16b537SWarner Losh
3330c16b537SWarner Losh /* first just try copying data from the output buffer */
3340c16b537SWarner Losh if (state.state->x.have) {
3350c16b537SWarner Losh if (state.state->x.have < n)
3360c16b537SWarner Losh n = state.state->x.have;
3370c16b537SWarner Losh memcpy(buf, state.state->x.next, n);
3380c16b537SWarner Losh state.state->x.next += n;
3390c16b537SWarner Losh state.state->x.have -= n;
3400c16b537SWarner Losh }
3410c16b537SWarner Losh
3420c16b537SWarner Losh /* output buffer empty -- return if we're at the end of the input */
3430c16b537SWarner Losh else if (state.state->eof && state.state->strm.avail_in == 0) {
3440c16b537SWarner Losh state.state->past = 1; /* tried to read past end */
3450c16b537SWarner Losh break;
3460c16b537SWarner Losh }
3470c16b537SWarner Losh
3480c16b537SWarner Losh /* need output data -- for small len or new stream load up our output
3490c16b537SWarner Losh buffer */
3500c16b537SWarner Losh else if (state.state->how == LOOK || n < (state.state->size << 1)) {
3510c16b537SWarner Losh /* get more output, looking for header if required */
3520c16b537SWarner Losh if (gz_fetch(state) == -1)
3530c16b537SWarner Losh return 0;
3540c16b537SWarner Losh continue; /* no progress yet -- go back to copy above */
3550c16b537SWarner Losh /* the copy above assures that we will leave with space in the
3560c16b537SWarner Losh output buffer, allowing at least one gzungetc() to succeed */
3570c16b537SWarner Losh }
3580c16b537SWarner Losh
3590c16b537SWarner Losh /* large len -- read directly into user buffer */
3600c16b537SWarner Losh else if (state.state->how == COPY) { /* read directly */
3610c16b537SWarner Losh if (gz_load(state, (unsigned char *)buf, n, &n) == -1)
3620c16b537SWarner Losh return 0;
3630c16b537SWarner Losh }
3640c16b537SWarner Losh
3650c16b537SWarner Losh /* large len -- decompress directly into user buffer */
3660c16b537SWarner Losh else { /* state.state->how == GZIP */
3670c16b537SWarner Losh state.state->strm.avail_out = n;
3680c16b537SWarner Losh state.state->strm.next_out = (unsigned char *)buf;
3690c16b537SWarner Losh if (gz_decomp(state) == -1)
3700c16b537SWarner Losh return 0;
3710c16b537SWarner Losh n = state.state->x.have;
3720c16b537SWarner Losh state.state->x.have = 0;
3730c16b537SWarner Losh }
3740c16b537SWarner Losh
3750c16b537SWarner Losh /* update progress */
3760c16b537SWarner Losh len -= n;
3770c16b537SWarner Losh buf = (char *)buf + n;
3780c16b537SWarner Losh got += n;
3790c16b537SWarner Losh state.state->x.pos += n;
3800c16b537SWarner Losh } while (len);
3810c16b537SWarner Losh
3820c16b537SWarner Losh /* return number of bytes read into user buffer */
3830c16b537SWarner Losh return got;
3840c16b537SWarner Losh }
3850c16b537SWarner Losh
3860c16b537SWarner Losh /* -- see zlib.h -- */
gzread(file,buf,len)3870c16b537SWarner Losh int ZEXPORT gzread(file, buf, len)
3880c16b537SWarner Losh gzFile file;
3890c16b537SWarner Losh voidp buf;
3900c16b537SWarner Losh unsigned len;
3910c16b537SWarner Losh {
3920c16b537SWarner Losh gz_statep state;
3930c16b537SWarner Losh
3940c16b537SWarner Losh /* get internal structure */
3950c16b537SWarner Losh if (file == NULL)
3960c16b537SWarner Losh return -1;
397*9cbefe25SConrad Meyer state.file = file;
3980c16b537SWarner Losh
3990c16b537SWarner Losh /* check that we're reading and that there's no (serious) error */
4000c16b537SWarner Losh if (state.state->mode != GZ_READ ||
4010c16b537SWarner Losh (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
4020c16b537SWarner Losh return -1;
4030c16b537SWarner Losh
4040c16b537SWarner Losh /* since an int is returned, make sure len fits in one, otherwise return
4050c16b537SWarner Losh with an error (this avoids a flaw in the interface) */
4060c16b537SWarner Losh if ((int)len < 0) {
4070c16b537SWarner Losh gz_error(state, Z_STREAM_ERROR, "request does not fit in an int");
4080c16b537SWarner Losh return -1;
4090c16b537SWarner Losh }
4100c16b537SWarner Losh
4110c16b537SWarner Losh /* read len or fewer bytes to buf */
4120c16b537SWarner Losh len = (unsigned)gz_read(state, buf, len);
4130c16b537SWarner Losh
4140c16b537SWarner Losh /* check for an error */
4150c16b537SWarner Losh if (len == 0 && state.state->err != Z_OK && state.state->err != Z_BUF_ERROR)
4160c16b537SWarner Losh return -1;
4170c16b537SWarner Losh
4180c16b537SWarner Losh /* return the number of bytes read (this is assured to fit in an int) */
4190c16b537SWarner Losh return (int)len;
4200c16b537SWarner Losh }
4210c16b537SWarner Losh
4220c16b537SWarner Losh /* -- see zlib.h -- */
gzfread(buf,size,nitems,file)4230c16b537SWarner Losh z_size_t ZEXPORT gzfread(buf, size, nitems, file)
4240c16b537SWarner Losh voidp buf;
4250c16b537SWarner Losh z_size_t size;
4260c16b537SWarner Losh z_size_t nitems;
4270c16b537SWarner Losh gzFile file;
4280c16b537SWarner Losh {
4290c16b537SWarner Losh z_size_t len;
4300c16b537SWarner Losh gz_statep state;
4310c16b537SWarner Losh
4320c16b537SWarner Losh /* get internal structure */
4330c16b537SWarner Losh if (file == NULL)
4340c16b537SWarner Losh return 0;
435*9cbefe25SConrad Meyer state.file = file;
4360c16b537SWarner Losh
4370c16b537SWarner Losh /* check that we're reading and that there's no (serious) error */
4380c16b537SWarner Losh if (state.state->mode != GZ_READ ||
4390c16b537SWarner Losh (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
4400c16b537SWarner Losh return 0;
4410c16b537SWarner Losh
4420c16b537SWarner Losh /* compute bytes to read -- error on overflow */
4430c16b537SWarner Losh len = nitems * size;
4440c16b537SWarner Losh if (size && len / size != nitems) {
4450c16b537SWarner Losh gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t");
4460c16b537SWarner Losh return 0;
4470c16b537SWarner Losh }
4480c16b537SWarner Losh
4490c16b537SWarner Losh /* read len or fewer bytes to buf, return the number of full items read */
4500c16b537SWarner Losh return len ? gz_read(state, buf, len) / size : 0;
4510c16b537SWarner Losh }
4520c16b537SWarner Losh
4530c16b537SWarner Losh /* -- see zlib.h -- */
4540c16b537SWarner Losh #if ZLIB_VERNUM >= 0x1261
4550c16b537SWarner Losh #ifdef Z_PREFIX_SET
4560c16b537SWarner Losh # undef z_gzgetc
4570c16b537SWarner Losh #else
4580c16b537SWarner Losh # undef gzgetc
4590c16b537SWarner Losh #endif
4600c16b537SWarner Losh #endif
4610c16b537SWarner Losh
4620c16b537SWarner Losh #if ZLIB_VERNUM == 0x1260
4630c16b537SWarner Losh # undef gzgetc
4640c16b537SWarner Losh #endif
4650c16b537SWarner Losh
4660c16b537SWarner Losh #if ZLIB_VERNUM <= 0x1250
4670c16b537SWarner Losh ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
4680c16b537SWarner Losh ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file));
4690c16b537SWarner Losh #endif
4700c16b537SWarner Losh
gzgetc(file)4710c16b537SWarner Losh int ZEXPORT gzgetc(file)
4720c16b537SWarner Losh gzFile file;
4730c16b537SWarner Losh {
4740c16b537SWarner Losh int ret;
4750c16b537SWarner Losh unsigned char buf[1];
4760c16b537SWarner Losh gz_statep state;
4770c16b537SWarner Losh
4780c16b537SWarner Losh /* get internal structure */
4790c16b537SWarner Losh if (file == NULL)
4800c16b537SWarner Losh return -1;
481*9cbefe25SConrad Meyer state.file = file;
4820c16b537SWarner Losh
4830c16b537SWarner Losh /* check that we're reading and that there's no (serious) error */
4840c16b537SWarner Losh if (state.state->mode != GZ_READ ||
4850c16b537SWarner Losh (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
4860c16b537SWarner Losh return -1;
4870c16b537SWarner Losh
4880c16b537SWarner Losh /* try output buffer (no need to check for skip request) */
4890c16b537SWarner Losh if (state.state->x.have) {
4900c16b537SWarner Losh state.state->x.have--;
4910c16b537SWarner Losh state.state->x.pos++;
4920c16b537SWarner Losh return *(state.state->x.next)++;
4930c16b537SWarner Losh }
4940c16b537SWarner Losh
4950c16b537SWarner Losh /* nothing there -- try gz_read() */
496*9cbefe25SConrad Meyer ret = (int)gz_read(state, buf, 1);
4970c16b537SWarner Losh return ret < 1 ? -1 : buf[0];
4980c16b537SWarner Losh }
4990c16b537SWarner Losh
gzgetc_(file)5000c16b537SWarner Losh int ZEXPORT gzgetc_(file)
5010c16b537SWarner Losh gzFile file;
5020c16b537SWarner Losh {
5030c16b537SWarner Losh return gzgetc(file);
5040c16b537SWarner Losh }
5050c16b537SWarner Losh
5060c16b537SWarner Losh /* -- see zlib.h -- */
gzungetc(c,file)5070c16b537SWarner Losh int ZEXPORT gzungetc(c, file)
5080c16b537SWarner Losh int c;
5090c16b537SWarner Losh gzFile file;
5100c16b537SWarner Losh {
5110c16b537SWarner Losh gz_statep state;
5120c16b537SWarner Losh
5130c16b537SWarner Losh /* get internal structure */
5140c16b537SWarner Losh if (file == NULL)
5150c16b537SWarner Losh return -1;
516*9cbefe25SConrad Meyer state.file = file;
5170c16b537SWarner Losh
5180c16b537SWarner Losh /* check that we're reading and that there's no (serious) error */
5190c16b537SWarner Losh if (state.state->mode != GZ_READ ||
5200c16b537SWarner Losh (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
5210c16b537SWarner Losh return -1;
5220c16b537SWarner Losh
5230c16b537SWarner Losh /* process a skip request */
5240c16b537SWarner Losh if (state.state->seek) {
5250c16b537SWarner Losh state.state->seek = 0;
5260c16b537SWarner Losh if (gz_skip(state, state.state->skip) == -1)
5270c16b537SWarner Losh return -1;
5280c16b537SWarner Losh }
5290c16b537SWarner Losh
5300c16b537SWarner Losh /* can't push EOF */
5310c16b537SWarner Losh if (c < 0)
5320c16b537SWarner Losh return -1;
5330c16b537SWarner Losh
5340c16b537SWarner Losh /* if output buffer empty, put byte at end (allows more pushing) */
5350c16b537SWarner Losh if (state.state->x.have == 0) {
5360c16b537SWarner Losh state.state->x.have = 1;
5370c16b537SWarner Losh state.state->x.next = state.state->out + (state.state->size << 1) - 1;
5380c16b537SWarner Losh state.state->x.next[0] = (unsigned char)c;
5390c16b537SWarner Losh state.state->x.pos--;
5400c16b537SWarner Losh state.state->past = 0;
5410c16b537SWarner Losh return c;
5420c16b537SWarner Losh }
5430c16b537SWarner Losh
5440c16b537SWarner Losh /* if no room, give up (must have already done a gzungetc()) */
5450c16b537SWarner Losh if (state.state->x.have == (state.state->size << 1)) {
5460c16b537SWarner Losh gz_error(state, Z_DATA_ERROR, "out of room to push characters");
5470c16b537SWarner Losh return -1;
5480c16b537SWarner Losh }
5490c16b537SWarner Losh
5500c16b537SWarner Losh /* slide output data if needed and insert byte before existing data */
5510c16b537SWarner Losh if (state.state->x.next == state.state->out) {
5520c16b537SWarner Losh unsigned char *src = state.state->out + state.state->x.have;
5530c16b537SWarner Losh unsigned char *dest = state.state->out + (state.state->size << 1);
5540c16b537SWarner Losh while (src > state.state->out)
5550c16b537SWarner Losh *--dest = *--src;
5560c16b537SWarner Losh state.state->x.next = dest;
5570c16b537SWarner Losh }
5580c16b537SWarner Losh state.state->x.have++;
5590c16b537SWarner Losh state.state->x.next--;
5600c16b537SWarner Losh state.state->x.next[0] = (unsigned char)c;
5610c16b537SWarner Losh state.state->x.pos--;
5620c16b537SWarner Losh state.state->past = 0;
5630c16b537SWarner Losh return c;
5640c16b537SWarner Losh }
5650c16b537SWarner Losh
5660c16b537SWarner Losh /* -- see zlib.h -- */
gzgets(file,buf,len)5670c16b537SWarner Losh char * ZEXPORT gzgets(file, buf, len)
5680c16b537SWarner Losh gzFile file;
5690c16b537SWarner Losh char *buf;
5700c16b537SWarner Losh int len;
5710c16b537SWarner Losh {
5720c16b537SWarner Losh unsigned left, n;
5730c16b537SWarner Losh char *str;
5740c16b537SWarner Losh unsigned char *eol;
5750c16b537SWarner Losh gz_statep state;
5760c16b537SWarner Losh
5770c16b537SWarner Losh /* check parameters and get internal structure */
5780c16b537SWarner Losh if (file == NULL || buf == NULL || len < 1)
5790c16b537SWarner Losh return NULL;
580*9cbefe25SConrad Meyer state.file = file;
5810c16b537SWarner Losh
5820c16b537SWarner Losh /* check that we're reading and that there's no (serious) error */
5830c16b537SWarner Losh if (state.state->mode != GZ_READ ||
5840c16b537SWarner Losh (state.state->err != Z_OK && state.state->err != Z_BUF_ERROR))
5850c16b537SWarner Losh return NULL;
5860c16b537SWarner Losh
5870c16b537SWarner Losh /* process a skip request */
5880c16b537SWarner Losh if (state.state->seek) {
5890c16b537SWarner Losh state.state->seek = 0;
5900c16b537SWarner Losh if (gz_skip(state, state.state->skip) == -1)
5910c16b537SWarner Losh return NULL;
5920c16b537SWarner Losh }
5930c16b537SWarner Losh
5940c16b537SWarner Losh /* copy output bytes up to new line or len - 1, whichever comes first --
5950c16b537SWarner Losh append a terminating zero to the string (we don't check for a zero in
5960c16b537SWarner Losh the contents, let the user worry about that) */
5970c16b537SWarner Losh str = buf;
5980c16b537SWarner Losh left = (unsigned)len - 1;
5990c16b537SWarner Losh if (left) do {
6000c16b537SWarner Losh /* assure that something is in the output buffer */
6010c16b537SWarner Losh if (state.state->x.have == 0 && gz_fetch(state) == -1)
6020c16b537SWarner Losh return NULL; /* error */
6030c16b537SWarner Losh if (state.state->x.have == 0) { /* end of file */
6040c16b537SWarner Losh state.state->past = 1; /* read past end */
6050c16b537SWarner Losh break; /* return what we have */
6060c16b537SWarner Losh }
6070c16b537SWarner Losh
6080c16b537SWarner Losh /* look for end-of-line in current output buffer */
6090c16b537SWarner Losh n = state.state->x.have > left ? left : state.state->x.have;
6100c16b537SWarner Losh eol = (unsigned char *)memchr(state.state->x.next, '\n', n);
6110c16b537SWarner Losh if (eol != NULL)
6120c16b537SWarner Losh n = (unsigned)(eol - state.state->x.next) + 1;
6130c16b537SWarner Losh
6140c16b537SWarner Losh /* copy through end-of-line, or remainder if not found */
6150c16b537SWarner Losh memcpy(buf, state.state->x.next, n);
6160c16b537SWarner Losh state.state->x.have -= n;
6170c16b537SWarner Losh state.state->x.next += n;
6180c16b537SWarner Losh state.state->x.pos += n;
6190c16b537SWarner Losh left -= n;
6200c16b537SWarner Losh buf += n;
6210c16b537SWarner Losh } while (left && eol == NULL);
6220c16b537SWarner Losh
6230c16b537SWarner Losh /* return terminated string, or if nothing, end of file */
6240c16b537SWarner Losh if (buf == str)
6250c16b537SWarner Losh return NULL;
6260c16b537SWarner Losh buf[0] = 0;
6270c16b537SWarner Losh return str;
6280c16b537SWarner Losh }
6290c16b537SWarner Losh
6300c16b537SWarner Losh /* -- see zlib.h -- */
gzdirect(file)6310c16b537SWarner Losh int ZEXPORT gzdirect(file)
6320c16b537SWarner Losh gzFile file;
6330c16b537SWarner Losh {
6340c16b537SWarner Losh gz_statep state;
6350c16b537SWarner Losh
6360c16b537SWarner Losh /* get internal structure */
6370c16b537SWarner Losh if (file == NULL)
6380c16b537SWarner Losh return 0;
639*9cbefe25SConrad Meyer state.file = file;
6400c16b537SWarner Losh
6410c16b537SWarner Losh /* if the state is not known, but we can find out, then do so (this is
6420c16b537SWarner Losh mainly for right after a gzopen() or gzdopen()) */
6430c16b537SWarner Losh if (state.state->mode == GZ_READ && state.state->how == LOOK && state.state->x.have == 0)
6440c16b537SWarner Losh (void)gz_look(state);
6450c16b537SWarner Losh
6460c16b537SWarner Losh /* return 1 if transparent, 0 if processing a gzip stream */
6470c16b537SWarner Losh return state.state->direct;
6480c16b537SWarner Losh }
6490c16b537SWarner Losh
6500c16b537SWarner Losh /* -- see zlib.h -- */
gzclose_r(file)6510c16b537SWarner Losh int ZEXPORT gzclose_r(file)
6520c16b537SWarner Losh gzFile file;
6530c16b537SWarner Losh {
6540c16b537SWarner Losh int ret, err;
6550c16b537SWarner Losh gz_statep state;
6560c16b537SWarner Losh
6570c16b537SWarner Losh /* get internal structure */
6580c16b537SWarner Losh if (file == NULL)
6590c16b537SWarner Losh return Z_STREAM_ERROR;
660*9cbefe25SConrad Meyer state.file = file;
6610c16b537SWarner Losh
6620c16b537SWarner Losh /* check that we're reading */
6630c16b537SWarner Losh if (state.state->mode != GZ_READ)
6640c16b537SWarner Losh return Z_STREAM_ERROR;
6650c16b537SWarner Losh
6660c16b537SWarner Losh /* free memory and close file */
6670c16b537SWarner Losh if (state.state->size) {
6680c16b537SWarner Losh inflateEnd(&(state.state->strm));
6690c16b537SWarner Losh free(state.state->out);
6700c16b537SWarner Losh free(state.state->in);
6710c16b537SWarner Losh }
6720c16b537SWarner Losh err = state.state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
6730c16b537SWarner Losh gz_error(state, Z_OK, NULL);
6740c16b537SWarner Losh free(state.state->path);
6750c16b537SWarner Losh ret = close(state.state->fd);
6760c16b537SWarner Losh free(state.state);
6770c16b537SWarner Losh return ret ? Z_ERRNO : err;
6780c16b537SWarner Losh }
679