kusano fc6ab3
/* gzread.c -- zlib functions for reading gzip files
kusano fc6ab3
 * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler
kusano fc6ab3
 * For conditions of distribution and use, see copyright notice in zlib.h
kusano fc6ab3
 */
kusano fc6ab3
kusano fc6ab3
#include "gzguts.h"
kusano fc6ab3
kusano fc6ab3
/* Local functions */
kusano fc6ab3
local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
kusano fc6ab3
local int gz_avail OF((gz_statep));
kusano fc6ab3
local int gz_look OF((gz_statep));
kusano fc6ab3
local int gz_decomp OF((gz_statep));
kusano fc6ab3
local int gz_fetch OF((gz_statep));
kusano fc6ab3
local int gz_skip OF((gz_statep, z_off64_t));
kusano fc6ab3
kusano fc6ab3
/* Use read() to load a buffer -- return -1 on error, otherwise 0.  Read from
kusano fc6ab3
   state->fd, and update state->eof, state->err, and state->msg as appropriate.
kusano fc6ab3
   This function needs to loop on read(), since read() is not guaranteed to
kusano fc6ab3
   read the number of bytes requested, depending on the type of descriptor. */
kusano fc6ab3
local int gz_load(state, buf, len, have)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
    unsigned char *buf;
kusano fc6ab3
    unsigned len;
kusano fc6ab3
    unsigned *have;
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
kusano fc6ab3
    *have = 0;
kusano fc6ab3
    do {
kusano fc6ab3
        ret = read(state->fd, buf + *have, len - *have);
kusano fc6ab3
        if (ret <= 0)
kusano fc6ab3
            break;
kusano fc6ab3
        *have += ret;
kusano fc6ab3
    } while (*have < len);
kusano fc6ab3
    if (ret < 0) {
kusano fc6ab3
        gz_error(state, Z_ERRNO, zstrerror());
kusano fc6ab3
        return -1;
kusano fc6ab3
    }
kusano fc6ab3
    if (ret == 0)
kusano fc6ab3
        state->eof = 1;
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Load up input buffer and set eof flag if last data loaded -- return -1 on
kusano fc6ab3
   error, 0 otherwise.  Note that the eof flag is set when the end of the input
kusano fc6ab3
   file is reached, even though there may be unused data in the buffer.  Once
kusano fc6ab3
   that data has been used, no more attempts will be made to read the file.
kusano fc6ab3
   If strm->avail_in != 0, then the current data is moved to the beginning of
kusano fc6ab3
   the input buffer, and then the remainder of the buffer is loaded with the
kusano fc6ab3
   available data from the input file. */
kusano fc6ab3
local int gz_avail(state)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
{
kusano fc6ab3
    unsigned got;
kusano fc6ab3
    z_streamp strm = &(state->strm);
kusano fc6ab3
kusano fc6ab3
    if (state->err != Z_OK && state->err != Z_BUF_ERROR)
kusano fc6ab3
        return -1;
kusano fc6ab3
    if (state->eof == 0) {
kusano fc6ab3
        if (strm->avail_in) {       /* copy what's there to the start */
kusano fc6ab3
            unsigned char *p = state->in;
kusano fc6ab3
            unsigned const char *q = strm->next_in;
kusano fc6ab3
            unsigned n = strm->avail_in;
kusano fc6ab3
            do {
kusano fc6ab3
                *p++ = *q++;
kusano fc6ab3
            } while (--n);
kusano fc6ab3
        }
kusano fc6ab3
        if (gz_load(state, state->in + strm->avail_in,
kusano fc6ab3
                    state->size - strm->avail_in, &got) == -1)
kusano fc6ab3
            return -1;
kusano fc6ab3
        strm->avail_in += got;
kusano fc6ab3
        strm->next_in = state->in;
kusano fc6ab3
    }
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Look for gzip header, set up for inflate or copy.  state->x.have must be 0.
kusano fc6ab3
   If this is the first time in, allocate required memory.  state->how will be
kusano fc6ab3
   left unchanged if there is no more input data available, will be set to COPY
kusano fc6ab3
   if there is no gzip header and direct copying will be performed, or it will
kusano fc6ab3
   be set to GZIP for decompression.  If direct copying, then leftover input
kusano fc6ab3
   data from the input buffer will be copied to the output buffer.  In that
kusano fc6ab3
   case, all further file reads will be directly to either the output buffer or
kusano fc6ab3
   a user buffer.  If decompressing, the inflate state will be initialized.
kusano fc6ab3
   gz_look() will return 0 on success or -1 on failure. */
kusano fc6ab3
local int gz_look(state)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
{
kusano fc6ab3
    z_streamp strm = &(state->strm);
kusano fc6ab3
kusano fc6ab3
    /* allocate read buffers and inflate memory */
kusano fc6ab3
    if (state->size == 0) {
kusano fc6ab3
        /* allocate buffers */
kusano fc6ab3
        state->in = (unsigned char *)malloc(state->want);
kusano fc6ab3
        state->out = (unsigned char *)malloc(state->want << 1);
kusano fc6ab3
        if (state->in == NULL || state->out == NULL) {
kusano fc6ab3
            if (state->out != NULL)
kusano fc6ab3
                free(state->out);
kusano fc6ab3
            if (state->in != NULL)
kusano fc6ab3
                free(state->in);
kusano fc6ab3
            gz_error(state, Z_MEM_ERROR, "out of memory");
kusano fc6ab3
            return -1;
kusano fc6ab3
        }
kusano fc6ab3
        state->size = state->want;
kusano fc6ab3
kusano fc6ab3
        /* allocate inflate memory */
kusano fc6ab3
        state->strm.zalloc = Z_NULL;
kusano fc6ab3
        state->strm.zfree = Z_NULL;
kusano fc6ab3
        state->strm.opaque = Z_NULL;
kusano fc6ab3
        state->strm.avail_in = 0;
kusano fc6ab3
        state->strm.next_in = Z_NULL;
kusano fc6ab3
        if (inflateInit2(&(state->strm), 15 + 16) != Z_OK) {    /* gunzip */
kusano fc6ab3
            free(state->out);
kusano fc6ab3
            free(state->in);
kusano fc6ab3
            state->size = 0;
kusano fc6ab3
            gz_error(state, Z_MEM_ERROR, "out of memory");
kusano fc6ab3
            return -1;
kusano fc6ab3
        }
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* get at least the magic bytes in the input buffer */
kusano fc6ab3
    if (strm->avail_in < 2) {
kusano fc6ab3
        if (gz_avail(state) == -1)
kusano fc6ab3
            return -1;
kusano fc6ab3
        if (strm->avail_in == 0)
kusano fc6ab3
            return 0;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* look for gzip magic bytes -- if there, do gzip decoding (note: there is
kusano fc6ab3
       a logical dilemma here when considering the case of a partially written
kusano fc6ab3
       gzip file, to wit, if a single 31 byte is written, then we cannot tell
kusano fc6ab3
       whether this is a single-byte file, or just a partially written gzip
kusano fc6ab3
       file -- for here we assume that if a gzip file is being written, then
kusano fc6ab3
       the header will be written in a single operation, so that reading a
kusano fc6ab3
       single byte is sufficient indication that it is not a gzip file) */
kusano fc6ab3
    if (strm->avail_in > 1 &&
kusano fc6ab3
            strm->next_in[0] == 31 && strm->next_in[1] == 139) {
kusano fc6ab3
        inflateReset(strm);
kusano fc6ab3
        state->how = GZIP;
kusano fc6ab3
        state->direct = 0;
kusano fc6ab3
        return 0;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* no gzip header -- if we were decoding gzip before, then this is trailing
kusano fc6ab3
       garbage.  Ignore the trailing garbage and finish. */
kusano fc6ab3
    if (state->direct == 0) {
kusano fc6ab3
        strm->avail_in = 0;
kusano fc6ab3
        state->eof = 1;
kusano fc6ab3
        state->x.have = 0;
kusano fc6ab3
        return 0;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* doing raw i/o, copy any leftover input to output -- this assumes that
kusano fc6ab3
       the output buffer is larger than the input buffer, which also assures
kusano fc6ab3
       space for gzungetc() */
kusano fc6ab3
    state->x.next = state->out;
kusano fc6ab3
    if (strm->avail_in) {
kusano fc6ab3
        memcpy(state->x.next, strm->next_in, strm->avail_in);
kusano fc6ab3
        state->x.have = strm->avail_in;
kusano fc6ab3
        strm->avail_in = 0;
kusano fc6ab3
    }
kusano fc6ab3
    state->how = COPY;
kusano fc6ab3
    state->direct = 1;
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Decompress from input to the provided next_out and avail_out in the state.
kusano fc6ab3
   On return, state->x.have and state->x.next point to the just decompressed
kusano fc6ab3
   data.  If the gzip stream completes, state->how is reset to LOOK to look for
kusano fc6ab3
   the next gzip stream or raw data, once state->x.have is depleted.  Returns 0
kusano fc6ab3
   on success, -1 on failure. */
kusano fc6ab3
local int gz_decomp(state)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
{
kusano fc6ab3
    int ret = Z_OK;
kusano fc6ab3
    unsigned had;
kusano fc6ab3
    z_streamp strm = &(state->strm);
kusano fc6ab3
kusano fc6ab3
    /* fill output buffer up to end of deflate stream */
kusano fc6ab3
    had = strm->avail_out;
kusano fc6ab3
    do {
kusano fc6ab3
        /* get more input for inflate() */
kusano fc6ab3
        if (strm->avail_in == 0 && gz_avail(state) == -1)
kusano fc6ab3
            return -1;
kusano fc6ab3
        if (strm->avail_in == 0) {
kusano fc6ab3
            gz_error(state, Z_BUF_ERROR, "unexpected end of file");
kusano fc6ab3
            break;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* decompress and handle errors */
kusano fc6ab3
        ret = inflate(strm, Z_NO_FLUSH);
kusano fc6ab3
        if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT) {
kusano fc6ab3
            gz_error(state, Z_STREAM_ERROR,
kusano fc6ab3
                     "internal error: inflate stream corrupt");
kusano fc6ab3
            return -1;
kusano fc6ab3
        }
kusano fc6ab3
        if (ret == Z_MEM_ERROR) {
kusano fc6ab3
            gz_error(state, Z_MEM_ERROR, "out of memory");
kusano fc6ab3
            return -1;
kusano fc6ab3
        }
kusano fc6ab3
        if (ret == Z_DATA_ERROR) {              /* deflate stream invalid */
kusano fc6ab3
            gz_error(state, Z_DATA_ERROR,
kusano fc6ab3
                     strm->msg == NULL ? "compressed data error" : strm->msg);
kusano fc6ab3
            return -1;
kusano fc6ab3
        }
kusano fc6ab3
    } while (strm->avail_out && ret != Z_STREAM_END);
kusano fc6ab3
kusano fc6ab3
    /* update available output */
kusano fc6ab3
    state->x.have = had - strm->avail_out;
kusano fc6ab3
    state->x.next = strm->next_out - state->x.have;
kusano fc6ab3
kusano fc6ab3
    /* if the gzip stream completed successfully, look for another */
kusano fc6ab3
    if (ret == Z_STREAM_END)
kusano fc6ab3
        state->how = LOOK;
kusano fc6ab3
kusano fc6ab3
    /* good decompression */
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Fetch data and put it in the output buffer.  Assumes state->x.have is 0.
kusano fc6ab3
   Data is either copied from the input file or decompressed from the input
kusano fc6ab3
   file depending on state->how.  If state->how is LOOK, then a gzip header is
kusano fc6ab3
   looked for to determine whether to copy or decompress.  Returns -1 on error,
kusano fc6ab3
   otherwise 0.  gz_fetch() will leave state->how as COPY or GZIP unless the
kusano fc6ab3
   end of the input file has been reached and all data has been processed.  */
kusano fc6ab3
local int gz_fetch(state)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
{
kusano fc6ab3
    z_streamp strm = &(state->strm);
kusano fc6ab3
kusano fc6ab3
    do {
kusano fc6ab3
        switch(state->how) {
kusano fc6ab3
        case LOOK:      /* -> LOOK, COPY (only if never GZIP), or GZIP */
kusano fc6ab3
            if (gz_look(state) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
            if (state->how == LOOK)
kusano fc6ab3
                return 0;
kusano fc6ab3
            break;
kusano fc6ab3
        case COPY:      /* -> COPY */
kusano fc6ab3
            if (gz_load(state, state->out, state->size << 1, &(state->x.have))
kusano fc6ab3
                    == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
            state->x.next = state->out;
kusano fc6ab3
            return 0;
kusano fc6ab3
        case GZIP:      /* -> GZIP or LOOK (if end of gzip stream) */
kusano fc6ab3
            strm->avail_out = state->size << 1;
kusano fc6ab3
            strm->next_out = state->out;
kusano fc6ab3
            if (gz_decomp(state) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
        }
kusano fc6ab3
    } while (state->x.have == 0 && (!state->eof || strm->avail_in));
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* Skip len uncompressed bytes of output.  Return -1 on error, 0 on success. */
kusano fc6ab3
local int gz_skip(state, len)
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
    z_off64_t len;
kusano fc6ab3
{
kusano fc6ab3
    unsigned n;
kusano fc6ab3
kusano fc6ab3
    /* skip over len bytes or reach end-of-file, whichever comes first */
kusano fc6ab3
    while (len)
kusano fc6ab3
        /* skip over whatever is in output buffer */
kusano fc6ab3
        if (state->x.have) {
kusano fc6ab3
            n = GT_OFF(state->x.have) || (z_off64_t)state->x.have > len ?
kusano fc6ab3
                (unsigned)len : state->x.have;
kusano fc6ab3
            state->x.have -= n;
kusano fc6ab3
            state->x.next += n;
kusano fc6ab3
            state->x.pos += n;
kusano fc6ab3
            len -= n;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* output buffer empty -- return if we're at the end of the input */
kusano fc6ab3
        else if (state->eof && state->strm.avail_in == 0)
kusano fc6ab3
            break;
kusano fc6ab3
kusano fc6ab3
        /* need more data to skip -- load up output buffer */
kusano fc6ab3
        else {
kusano fc6ab3
            /* get more output, looking for header if required */
kusano fc6ab3
            if (gz_fetch(state) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
        }
kusano fc6ab3
    return 0;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
int ZEXPORT gzread(file, buf, len)
kusano fc6ab3
    gzFile file;
kusano fc6ab3
    voidp buf;
kusano fc6ab3
    unsigned len;
kusano fc6ab3
{
kusano fc6ab3
    unsigned got, n;
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
    z_streamp strm;
kusano fc6ab3
kusano fc6ab3
    /* get internal structure */
kusano fc6ab3
    if (file == NULL)
kusano fc6ab3
        return -1;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
    strm = &(state->strm);
kusano fc6ab3
kusano fc6ab3
    /* check that we're reading and that there's no (serious) error */
kusano fc6ab3
    if (state->mode != GZ_READ ||
kusano fc6ab3
            (state->err != Z_OK && state->err != Z_BUF_ERROR))
kusano fc6ab3
        return -1;
kusano fc6ab3
kusano fc6ab3
    /* since an int is returned, make sure len fits in one, otherwise return
kusano fc6ab3
       with an error (this avoids the flaw in the interface) */
kusano fc6ab3
    if ((int)len < 0) {
kusano fc6ab3
        gz_error(state, Z_DATA_ERROR, "requested length does not fit in int");
kusano fc6ab3
        return -1;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* if len is zero, avoid unnecessary operations */
kusano fc6ab3
    if (len == 0)
kusano fc6ab3
        return 0;
kusano fc6ab3
kusano fc6ab3
    /* process a skip request */
kusano fc6ab3
    if (state->seek) {
kusano fc6ab3
        state->seek = 0;
kusano fc6ab3
        if (gz_skip(state, state->skip) == -1)
kusano fc6ab3
            return -1;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* get len bytes to buf, or less than len if at the end */
kusano fc6ab3
    got = 0;
kusano fc6ab3
    do {
kusano fc6ab3
        /* first just try copying data from the output buffer */
kusano fc6ab3
        if (state->x.have) {
kusano fc6ab3
            n = state->x.have > len ? len : state->x.have;
kusano fc6ab3
            memcpy(buf, state->x.next, n);
kusano fc6ab3
            state->x.next += n;
kusano fc6ab3
            state->x.have -= n;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* output buffer empty -- return if we're at the end of the input */
kusano fc6ab3
        else if (state->eof && strm->avail_in == 0) {
kusano fc6ab3
            state->past = 1;        /* tried to read past end */
kusano fc6ab3
            break;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* need output data -- for small len or new stream load up our output
kusano fc6ab3
           buffer */
kusano fc6ab3
        else if (state->how == LOOK || len < (state->size << 1)) {
kusano fc6ab3
            /* get more output, looking for header if required */
kusano fc6ab3
            if (gz_fetch(state) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
            continue;       /* no progress yet -- go back to copy above */
kusano fc6ab3
            /* the copy above assures that we will leave with space in the
kusano fc6ab3
               output buffer, allowing at least one gzungetc() to succeed */
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* large len -- read directly into user buffer */
kusano fc6ab3
        else if (state->how == COPY) {      /* read directly */
kusano fc6ab3
            if (gz_load(state, (unsigned char *)buf, len, &n) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* large len -- decompress directly into user buffer */
kusano fc6ab3
        else {  /* state->how == GZIP */
kusano fc6ab3
            strm->avail_out = len;
kusano fc6ab3
            strm->next_out = (unsigned char *)buf;
kusano fc6ab3
            if (gz_decomp(state) == -1)
kusano fc6ab3
                return -1;
kusano fc6ab3
            n = state->x.have;
kusano fc6ab3
            state->x.have = 0;
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* update progress */
kusano fc6ab3
        len -= n;
kusano fc6ab3
        buf = (char *)buf + n;
kusano fc6ab3
        got += n;
kusano fc6ab3
        state->x.pos += n;
kusano fc6ab3
    } while (len);
kusano fc6ab3
kusano fc6ab3
    /* return number of bytes read into user buffer (will fit in int) */
kusano fc6ab3
    return (int)got;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
#ifdef Z_PREFIX_SET
kusano fc6ab3
#  undef z_gzgetc
kusano fc6ab3
#else
kusano fc6ab3
#  undef gzgetc
kusano fc6ab3
#endif
kusano fc6ab3
int ZEXPORT gzgetc(file)
kusano fc6ab3
    gzFile file;
kusano fc6ab3
{
kusano fc6ab3
    int ret;
kusano fc6ab3
    unsigned char buf[1];
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
kusano fc6ab3
    /* get internal structure */
kusano fc6ab3
    if (file == NULL)
kusano fc6ab3
        return -1;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
kusano fc6ab3
    /* check that we're reading and that there's no (serious) error */
kusano fc6ab3
    if (state->mode != GZ_READ ||
kusano fc6ab3
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
kusano fc6ab3
        return -1;
kusano fc6ab3
kusano fc6ab3
    /* try output buffer (no need to check for skip request) */
kusano fc6ab3
    if (state->x.have) {
kusano fc6ab3
        state->x.have--;
kusano fc6ab3
        state->x.pos++;
kusano fc6ab3
        return *(state->x.next)++;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* nothing there -- try gzread() */
kusano fc6ab3
    ret = gzread(file, buf, 1);
kusano fc6ab3
    return ret < 1 ? -1 : buf[0];
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
int ZEXPORT gzgetc_(file)
kusano fc6ab3
gzFile file;
kusano fc6ab3
{
kusano fc6ab3
    return gzgetc(file);
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
int ZEXPORT gzungetc(c, file)
kusano fc6ab3
    int c;
kusano fc6ab3
    gzFile file;
kusano fc6ab3
{
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
kusano fc6ab3
    /* get internal structure */
kusano fc6ab3
    if (file == NULL)
kusano fc6ab3
        return -1;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
kusano fc6ab3
    /* check that we're reading and that there's no (serious) error */
kusano fc6ab3
    if (state->mode != GZ_READ ||
kusano fc6ab3
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
kusano fc6ab3
        return -1;
kusano fc6ab3
kusano fc6ab3
    /* process a skip request */
kusano fc6ab3
    if (state->seek) {
kusano fc6ab3
        state->seek = 0;
kusano fc6ab3
        if (gz_skip(state, state->skip) == -1)
kusano fc6ab3
            return -1;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* can't push EOF */
kusano fc6ab3
    if (c < 0)
kusano fc6ab3
        return -1;
kusano fc6ab3
kusano fc6ab3
    /* if output buffer empty, put byte at end (allows more pushing) */
kusano fc6ab3
    if (state->x.have == 0) {
kusano fc6ab3
        state->x.have = 1;
kusano fc6ab3
        state->x.next = state->out + (state->size << 1) - 1;
kusano fc6ab3
        state->x.next[0] = c;
kusano fc6ab3
        state->x.pos--;
kusano fc6ab3
        state->past = 0;
kusano fc6ab3
        return c;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* if no room, give up (must have already done a gzungetc()) */
kusano fc6ab3
    if (state->x.have == (state->size << 1)) {
kusano fc6ab3
        gz_error(state, Z_DATA_ERROR, "out of room to push characters");
kusano fc6ab3
        return -1;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* slide output data if needed and insert byte before existing data */
kusano fc6ab3
    if (state->x.next == state->out) {
kusano fc6ab3
        unsigned char *src = state->out + state->x.have;
kusano fc6ab3
        unsigned char *dest = state->out + (state->size << 1);
kusano fc6ab3
        while (src > state->out)
kusano fc6ab3
            *--dest = *--src;
kusano fc6ab3
        state->x.next = dest;
kusano fc6ab3
    }
kusano fc6ab3
    state->x.have++;
kusano fc6ab3
    state->x.next--;
kusano fc6ab3
    state->x.next[0] = c;
kusano fc6ab3
    state->x.pos--;
kusano fc6ab3
    state->past = 0;
kusano fc6ab3
    return c;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
char * ZEXPORT gzgets(file, buf, len)
kusano fc6ab3
    gzFile file;
kusano fc6ab3
    char *buf;
kusano fc6ab3
    int len;
kusano fc6ab3
{
kusano fc6ab3
    unsigned left, n;
kusano fc6ab3
    char *str;
kusano fc6ab3
    unsigned char *eol;
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
kusano fc6ab3
    /* check parameters and get internal structure */
kusano fc6ab3
    if (file == NULL || buf == NULL || len < 1)
kusano fc6ab3
        return NULL;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
kusano fc6ab3
    /* check that we're reading and that there's no (serious) error */
kusano fc6ab3
    if (state->mode != GZ_READ ||
kusano fc6ab3
        (state->err != Z_OK && state->err != Z_BUF_ERROR))
kusano fc6ab3
        return NULL;
kusano fc6ab3
kusano fc6ab3
    /* process a skip request */
kusano fc6ab3
    if (state->seek) {
kusano fc6ab3
        state->seek = 0;
kusano fc6ab3
        if (gz_skip(state, state->skip) == -1)
kusano fc6ab3
            return NULL;
kusano fc6ab3
    }
kusano fc6ab3
kusano fc6ab3
    /* copy output bytes up to new line or len - 1, whichever comes first --
kusano fc6ab3
       append a terminating zero to the string (we don't check for a zero in
kusano fc6ab3
       the contents, let the user worry about that) */
kusano fc6ab3
    str = buf;
kusano fc6ab3
    left = (unsigned)len - 1;
kusano fc6ab3
    if (left) do {
kusano fc6ab3
        /* assure that something is in the output buffer */
kusano fc6ab3
        if (state->x.have == 0 && gz_fetch(state) == -1)
kusano fc6ab3
            return NULL;                /* error */
kusano fc6ab3
        if (state->x.have == 0) {       /* end of file */
kusano fc6ab3
            state->past = 1;            /* read past end */
kusano fc6ab3
            break;                      /* return what we have */
kusano fc6ab3
        }
kusano fc6ab3
kusano fc6ab3
        /* look for end-of-line in current output buffer */
kusano fc6ab3
        n = state->x.have > left ? left : state->x.have;
kusano fc6ab3
        eol = (unsigned char *)memchr(state->x.next, '\n', n);
kusano fc6ab3
        if (eol != NULL)
kusano fc6ab3
            n = (unsigned)(eol - state->x.next) + 1;
kusano fc6ab3
kusano fc6ab3
        /* copy through end-of-line, or remainder if not found */
kusano fc6ab3
        memcpy(buf, state->x.next, n);
kusano fc6ab3
        state->x.have -= n;
kusano fc6ab3
        state->x.next += n;
kusano fc6ab3
        state->x.pos += n;
kusano fc6ab3
        left -= n;
kusano fc6ab3
        buf += n;
kusano fc6ab3
    } while (left && eol == NULL);
kusano fc6ab3
kusano fc6ab3
    /* return terminated string, or if nothing, end of file */
kusano fc6ab3
    if (buf == str)
kusano fc6ab3
        return NULL;
kusano fc6ab3
    buf[0] = 0;
kusano fc6ab3
    return str;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
int ZEXPORT gzdirect(file)
kusano fc6ab3
    gzFile file;
kusano fc6ab3
{
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
kusano fc6ab3
    /* get internal structure */
kusano fc6ab3
    if (file == NULL)
kusano fc6ab3
        return 0;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
kusano fc6ab3
    /* if the state is not known, but we can find out, then do so (this is
kusano fc6ab3
       mainly for right after a gzopen() or gzdopen()) */
kusano fc6ab3
    if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
kusano fc6ab3
        (void)gz_look(state);
kusano fc6ab3
kusano fc6ab3
    /* return 1 if transparent, 0 if processing a gzip stream */
kusano fc6ab3
    return state->direct;
kusano fc6ab3
}
kusano fc6ab3
kusano fc6ab3
/* -- see zlib.h -- */
kusano fc6ab3
int ZEXPORT gzclose_r(file)
kusano fc6ab3
    gzFile file;
kusano fc6ab3
{
kusano fc6ab3
    int ret, err;
kusano fc6ab3
    gz_statep state;
kusano fc6ab3
kusano fc6ab3
    /* get internal structure */
kusano fc6ab3
    if (file == NULL)
kusano fc6ab3
        return Z_STREAM_ERROR;
kusano fc6ab3
    state = (gz_statep)file;
kusano fc6ab3
kusano fc6ab3
    /* check that we're reading */
kusano fc6ab3
    if (state->mode != GZ_READ)
kusano fc6ab3
        return Z_STREAM_ERROR;
kusano fc6ab3
kusano fc6ab3
    /* free memory and close file */
kusano fc6ab3
    if (state->size) {
kusano fc6ab3
        inflateEnd(&(state->strm));
kusano fc6ab3
        free(state->out);
kusano fc6ab3
        free(state->in);
kusano fc6ab3
    }
kusano fc6ab3
    err = state->err == Z_BUF_ERROR ? Z_BUF_ERROR : Z_OK;
kusano fc6ab3
    gz_error(state, Z_OK, NULL);
kusano fc6ab3
    free(state->path);
kusano fc6ab3
    ret = close(state->fd);
kusano fc6ab3
    free(state);
kusano fc6ab3
    return ret ? Z_ERRNO : err;
kusano fc6ab3
}