kusano 7d535a
/* gzwrite.c -- zlib functions for writing 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_init OF((gz_statep));
kusano 7d535a
local int gz_comp OF((gz_statep, int));
kusano 7d535a
local int gz_zero OF((gz_statep, z_off64_t));
kusano 7d535a
kusano 7d535a
/* Initialize state for writing a gzip file.  Mark initialization by setting
kusano 7d535a
   state->size to non-zero.  Return -1 on failure or 0 on success. */
kusano 7d535a
local int gz_init(state)
kusano 7d535a
    gz_statep state;
kusano 7d535a
{
kusano 7d535a
    int ret;
kusano 7d535a
    z_streamp strm = &(state->strm);
kusano 7d535a
kusano 7d535a
    /* allocate input buffer */
kusano 7d535a
    state->in = malloc(state->want);
kusano 7d535a
    if (state->in == NULL) {
kusano 7d535a
        gz_error(state, Z_MEM_ERROR, "out of memory");
kusano 7d535a
        return -1;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* only need output buffer and deflate state if compressing */
kusano 7d535a
    if (!state->direct) {
kusano 7d535a
        /* allocate output buffer */
kusano 7d535a
        state->out = malloc(state->want);
kusano 7d535a
        if (state->out == 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
kusano 7d535a
        /* allocate deflate memory, set up for gzip compression */
kusano 7d535a
        strm->zalloc = Z_NULL;
kusano 7d535a
        strm->zfree = Z_NULL;
kusano 7d535a
        strm->opaque = Z_NULL;
kusano 7d535a
        ret = deflateInit2(strm, state->level, Z_DEFLATED,
kusano 7d535a
                           MAX_WBITS + 16, DEF_MEM_LEVEL, state->strategy);
kusano 7d535a
        if (ret != Z_OK) {
kusano 7d535a
            free(state->out);
kusano 7d535a
            free(state->in);
kusano 7d535a
            gz_error(state, Z_MEM_ERROR, "out of memory");
kusano 7d535a
            return -1;
kusano 7d535a
        }
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* mark state as initialized */
kusano 7d535a
    state->size = state->want;
kusano 7d535a
kusano 7d535a
    /* initialize write buffer if compressing */
kusano 7d535a
    if (!state->direct) {
kusano 7d535a
        strm->avail_out = state->size;
kusano 7d535a
        strm->next_out = state->out;
kusano 7d535a
        state->x.next = strm->next_out;
kusano 7d535a
    }
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* Compress whatever is at avail_in and next_in and write to the output file.
kusano 7d535a
   Return -1 if there is an error writing to the output file, otherwise 0.
kusano 7d535a
   flush is assumed to be a valid deflate() flush value.  If flush is Z_FINISH,
kusano 7d535a
   then the deflate() state is reset to start a new gzip stream.  If gz->direct
kusano 7d535a
   is true, then simply write to the output file without compressing, and
kusano 7d535a
   ignore flush. */
kusano 7d535a
local int gz_comp(state, flush)
kusano 7d535a
    gz_statep state;
kusano 7d535a
    int flush;
kusano 7d535a
{
kusano 7d535a
    int ret, got;
kusano 7d535a
    unsigned have;
kusano 7d535a
    z_streamp strm = &(state->strm);
kusano 7d535a
kusano 7d535a
    /* allocate memory if this is the first time through */
kusano 7d535a
    if (state->size == 0 && gz_init(state) == -1)
kusano 7d535a
        return -1;
kusano 7d535a
kusano 7d535a
    /* write directly if requested */
kusano 7d535a
    if (state->direct) {
kusano 7d535a
        got = write(state->fd, strm->next_in, strm->avail_in);
kusano 7d535a
        if (got < 0 || (unsigned)got != strm->avail_in) {
kusano 7d535a
            gz_error(state, Z_ERRNO, zstrerror());
kusano 7d535a
            return -1;
kusano 7d535a
        }
kusano 7d535a
        strm->avail_in = 0;
kusano 7d535a
        return 0;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* run deflate() on provided input until it produces no more output */
kusano 7d535a
    ret = Z_OK;
kusano 7d535a
    do {
kusano 7d535a
        /* write out current buffer contents if full, or if flushing, but if
kusano 7d535a
           doing Z_FINISH then don't write until we get to Z_STREAM_END */
kusano 7d535a
        if (strm->avail_out == 0 || (flush != Z_NO_FLUSH &&
kusano 7d535a
            (flush != Z_FINISH || ret == Z_STREAM_END))) {
kusano 7d535a
            have = (unsigned)(strm->next_out - state->x.next);
kusano 7d535a
            if (have && ((got = write(state->fd, state->x.next, have)) < 0 ||
kusano 7d535a
                         (unsigned)got != have)) {
kusano 7d535a
                gz_error(state, Z_ERRNO, zstrerror());
kusano 7d535a
                return -1;
kusano 7d535a
            }
kusano 7d535a
            if (strm->avail_out == 0) {
kusano 7d535a
                strm->avail_out = state->size;
kusano 7d535a
                strm->next_out = state->out;
kusano 7d535a
            }
kusano 7d535a
            state->x.next = strm->next_out;
kusano 7d535a
        }
kusano 7d535a
kusano 7d535a
        /* compress */
kusano 7d535a
        have = strm->avail_out;
kusano 7d535a
        ret = deflate(strm, flush);
kusano 7d535a
        if (ret == Z_STREAM_ERROR) {
kusano 7d535a
            gz_error(state, Z_STREAM_ERROR,
kusano 7d535a
                      "internal error: deflate stream corrupt");
kusano 7d535a
            return -1;
kusano 7d535a
        }
kusano 7d535a
        have -= strm->avail_out;
kusano 7d535a
    } while (have);
kusano 7d535a
kusano 7d535a
    /* if that completed a deflate stream, allow another to start */
kusano 7d535a
    if (flush == Z_FINISH)
kusano 7d535a
        deflateReset(strm);
kusano 7d535a
kusano 7d535a
    /* all done, no errors */
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* Compress len zeros to output.  Return -1 on error, 0 on success. */
kusano 7d535a
local int gz_zero(state, len)
kusano 7d535a
    gz_statep state;
kusano 7d535a
    z_off64_t len;
kusano 7d535a
{
kusano 7d535a
    int first;
kusano 7d535a
    unsigned n;
kusano 7d535a
    z_streamp strm = &(state->strm);
kusano 7d535a
kusano 7d535a
    /* consume whatever's left in the input buffer */
kusano 7d535a
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
        return -1;
kusano 7d535a
kusano 7d535a
    /* compress len zeros (len guaranteed > 0) */
kusano 7d535a
    first = 1;
kusano 7d535a
    while (len) {
kusano 7d535a
        n = GT_OFF(state->size) || (z_off64_t)state->size > len ?
kusano 7d535a
            (unsigned)len : state->size;
kusano 7d535a
        if (first) {
kusano 7d535a
            memset(state->in, 0, n);
kusano 7d535a
            first = 0;
kusano 7d535a
        }
kusano 7d535a
        strm->avail_in = n;
kusano 7d535a
        strm->next_in = state->in;
kusano 7d535a
        state->x.pos += n;
kusano 7d535a
        if (gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
            return -1;
kusano 7d535a
        len -= n;
kusano 7d535a
    }
kusano 7d535a
    return 0;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzwrite(file, buf, len)
kusano 7d535a
    gzFile file;
kusano 7d535a
    voidpc buf;
kusano 7d535a
    unsigned len;
kusano 7d535a
{
kusano 7d535a
    unsigned put = len;
kusano 7d535a
    unsigned 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 0;
kusano 7d535a
    state = (gz_statep)file;
kusano 7d535a
    strm = &(state->strm);
kusano 7d535a
kusano 7d535a
    /* check that we're writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return 0;
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 0;
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
    /* allocate memory if this is the first time through */
kusano 7d535a
    if (state->size == 0 && gz_init(state) == -1)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return 0;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* for small len, copy to input buffer, otherwise compress directly */
kusano 7d535a
    if (len < state->size) {
kusano 7d535a
        /* copy to input buffer, compress when full */
kusano 7d535a
        do {
kusano 7d535a
            if (strm->avail_in == 0)
kusano 7d535a
                strm->next_in = state->in;
kusano 7d535a
            n = state->size - strm->avail_in;
kusano 7d535a
            if (n > len)
kusano 7d535a
                n = len;
kusano 7d535a
            memcpy(strm->next_in + strm->avail_in, buf, n);
kusano 7d535a
            strm->avail_in += n;
kusano 7d535a
            state->x.pos += n;
kusano 7d535a
            buf = (char *)buf + n;
kusano 7d535a
            len -= n;
kusano 7d535a
            if (len && gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
                return 0;
kusano 7d535a
        } while (len);
kusano 7d535a
    }
kusano 7d535a
    else {
kusano 7d535a
        /* consume whatever's left in the input buffer */
kusano 7d535a
        if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
            return 0;
kusano 7d535a
kusano 7d535a
        /* directly compress user buffer to file */
kusano 7d535a
        strm->avail_in = len;
kusano 7d535a
        strm->next_in = (voidp)buf;
kusano 7d535a
        state->x.pos += len;
kusano 7d535a
        if (gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
            return 0;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* input was all buffered or compressed (put will fit in int) */
kusano 7d535a
    return (int)put;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzputc(file, c)
kusano 7d535a
    gzFile file;
kusano 7d535a
    int c;
kusano 7d535a
{
kusano 7d535a
    unsigned char buf[1];
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 writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return -1;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return -1;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* try writing to input buffer for speed (state->size == 0 if buffer not
kusano 7d535a
       initialized) */
kusano 7d535a
    if (strm->avail_in < state->size) {
kusano 7d535a
        if (strm->avail_in == 0)
kusano 7d535a
            strm->next_in = state->in;
kusano 7d535a
        strm->next_in[strm->avail_in++] = c;
kusano 7d535a
        state->x.pos++;
kusano 7d535a
        return c & 0xff;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* no room in buffer or not initialized, use gz_write() */
kusano 7d535a
    buf[0] = c;
kusano 7d535a
    if (gzwrite(file, buf, 1) != 1)
kusano 7d535a
        return -1;
kusano 7d535a
    return c & 0xff;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzputs(file, str)
kusano 7d535a
    gzFile file;
kusano 7d535a
    const char *str;
kusano 7d535a
{
kusano 7d535a
    int ret;
kusano 7d535a
    unsigned len;
kusano 7d535a
kusano 7d535a
    /* write string */
kusano 7d535a
    len = (unsigned)strlen(str);
kusano 7d535a
    ret = gzwrite(file, str, len);
kusano 7d535a
    return ret == 0 && len != 0 ? -1 : ret;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
kusano 7d535a
#include <stdarg.h></stdarg.h>
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORTVA gzprintf (gzFile file, const char *format, ...)
kusano 7d535a
{
kusano 7d535a
    int size, len;
kusano 7d535a
    gz_statep state;
kusano 7d535a
    z_streamp strm;
kusano 7d535a
    va_list va;
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 writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* make sure we have some buffer space */
kusano 7d535a
    if (state->size == 0 && gz_init(state) == -1)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return 0;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* consume whatever's left in the input buffer */
kusano 7d535a
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* do the printf() into the input buffer, put length in len */
kusano 7d535a
    size = (int)(state->size);
kusano 7d535a
    state->in[size - 1] = 0;
kusano 7d535a
    va_start(va, format);
kusano 7d535a
#ifdef NO_vsnprintf
kusano 7d535a
#  ifdef HAS_vsprintf_void
kusano 7d535a
    (void)vsprintf((char *)(state->in), format, va);
kusano 7d535a
    va_end(va);
kusano 7d535a
    for (len = 0; len < size; len++)
kusano 7d535a
        if (state->in[len] == 0) break;
kusano 7d535a
#  else
kusano 7d535a
    len = vsprintf((char *)(state->in), format, va);
kusano 7d535a
    va_end(va);
kusano 7d535a
#  endif
kusano 7d535a
#else
kusano 7d535a
#  ifdef HAS_vsnprintf_void
kusano 7d535a
    (void)vsnprintf((char *)(state->in), size, format, va);
kusano 7d535a
    va_end(va);
kusano 7d535a
    len = strlen((char *)(state->in));
kusano 7d535a
#  else
kusano 7d535a
    len = vsnprintf((char *)(state->in), size, format, va);
kusano 7d535a
    va_end(va);
kusano 7d535a
#  endif
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
    /* check that printf() results fit in buffer */
kusano 7d535a
    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* update buffer and position, defer compression until needed */
kusano 7d535a
    strm->avail_in = (unsigned)len;
kusano 7d535a
    strm->next_in = state->in;
kusano 7d535a
    state->x.pos += len;
kusano 7d535a
    return len;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#else /* !STDC && !Z_HAVE_STDARG_H */
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
kusano 7d535a
                       a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
kusano 7d535a
    gzFile file;
kusano 7d535a
    const char *format;
kusano 7d535a
    int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
kusano 7d535a
        a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
kusano 7d535a
{
kusano 7d535a
    int size, len;
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 can really pass pointer in ints */
kusano 7d535a
    if (sizeof(int) != sizeof(void *))
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* check that we're writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* make sure we have some buffer space */
kusano 7d535a
    if (state->size == 0 && gz_init(state) == -1)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return 0;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* consume whatever's left in the input buffer */
kusano 7d535a
    if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* do the printf() into the input buffer, put length in len */
kusano 7d535a
    size = (int)(state->size);
kusano 7d535a
    state->in[size - 1] = 0;
kusano 7d535a
#ifdef NO_snprintf
kusano 7d535a
#  ifdef HAS_sprintf_void
kusano 7d535a
    sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
kusano 7d535a
            a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
kusano 7d535a
    for (len = 0; len < size; len++)
kusano 7d535a
        if (state->in[len] == 0) break;
kusano 7d535a
#  else
kusano 7d535a
    len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8,
kusano 7d535a
                  a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
kusano 7d535a
#  endif
kusano 7d535a
#else
kusano 7d535a
#  ifdef HAS_snprintf_void
kusano 7d535a
    snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8,
kusano 7d535a
             a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
kusano 7d535a
    len = strlen((char *)(state->in));
kusano 7d535a
#  else
kusano 7d535a
    len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6,
kusano 7d535a
                   a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18,
kusano 7d535a
                   a19, a20);
kusano 7d535a
#  endif
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
    /* check that printf() results fit in buffer */
kusano 7d535a
    if (len <= 0 || len >= (int)size || state->in[size - 1] != 0)
kusano 7d535a
        return 0;
kusano 7d535a
kusano 7d535a
    /* update buffer and position, defer compression until needed */
kusano 7d535a
    strm->avail_in = (unsigned)len;
kusano 7d535a
    strm->next_in = state->in;
kusano 7d535a
    state->x.pos += len;
kusano 7d535a
    return len;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
#endif
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzflush(file, flush)
kusano 7d535a
    gzFile file;
kusano 7d535a
    int flush;
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 writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return Z_STREAM_ERROR;
kusano 7d535a
kusano 7d535a
    /* check flush parameter */
kusano 7d535a
    if (flush < 0 || flush > Z_FINISH)
kusano 7d535a
        return Z_STREAM_ERROR;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return -1;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* compress remaining data with requested flush */
kusano 7d535a
    gz_comp(state, flush);
kusano 7d535a
    return state->err;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzsetparams(file, level, strategy)
kusano 7d535a
    gzFile file;
kusano 7d535a
    int level;
kusano 7d535a
    int strategy;
kusano 7d535a
{
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 Z_STREAM_ERROR;
kusano 7d535a
    state = (gz_statep)file;
kusano 7d535a
    strm = &(state->strm);
kusano 7d535a
kusano 7d535a
    /* check that we're writing and that there's no error */
kusano 7d535a
    if (state->mode != GZ_WRITE || state->err != Z_OK)
kusano 7d535a
        return Z_STREAM_ERROR;
kusano 7d535a
kusano 7d535a
    /* if no change is requested, then do nothing */
kusano 7d535a
    if (level == state->level && strategy == state->strategy)
kusano 7d535a
        return Z_OK;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            return -1;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* change compression parameters for subsequent input */
kusano 7d535a
    if (state->size) {
kusano 7d535a
        /* flush previous input with previous parameters before changing */
kusano 7d535a
        if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1)
kusano 7d535a
            return state->err;
kusano 7d535a
        deflateParams(strm, level, strategy);
kusano 7d535a
    }
kusano 7d535a
    state->level = level;
kusano 7d535a
    state->strategy = strategy;
kusano 7d535a
    return Z_OK;
kusano 7d535a
}
kusano 7d535a
kusano 7d535a
/* -- see zlib.h -- */
kusano 7d535a
int ZEXPORT gzclose_w(file)
kusano 7d535a
    gzFile file;
kusano 7d535a
{
kusano 7d535a
    int ret = Z_OK;
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 writing */
kusano 7d535a
    if (state->mode != GZ_WRITE)
kusano 7d535a
        return Z_STREAM_ERROR;
kusano 7d535a
kusano 7d535a
    /* check for seek request */
kusano 7d535a
    if (state->seek) {
kusano 7d535a
        state->seek = 0;
kusano 7d535a
        if (gz_zero(state, state->skip) == -1)
kusano 7d535a
            ret = state->err;
kusano 7d535a
    }
kusano 7d535a
kusano 7d535a
    /* flush, free memory, and close file */
kusano 7d535a
    if (state->size) {
kusano 7d535a
        if (gz_comp(state, Z_FINISH) == -1)
kusano 7d535a
            ret = state->err;
kusano 7d535a
        if (!state->direct) {
kusano 7d535a
            (void)deflateEnd(&(state->strm));
kusano 7d535a
            free(state->out);
kusano 7d535a
        }
kusano 7d535a
        free(state->in);
kusano 7d535a
    }
kusano 7d535a
    gz_error(state, Z_OK, NULL);
kusano 7d535a
    free(state->path);
kusano 7d535a
    if (close(state->fd) == -1)
kusano 7d535a
        ret = Z_ERRNO;
kusano 7d535a
    free(state);
kusano 7d535a
    return ret;
kusano 7d535a
}