xref: /freebsd/sys/contrib/zstd/zlibWrapper/gzread.c (revision 9cbefe25d46756f342c7dd3d174d2d1103808f21)
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