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