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