/* $OpenBSD: compress.c,v 1.4 2006/04/14 02:45:35 deraadt Exp $ */ /* * Copyright (c) 2005 Jean-Francois Brousseau * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "includes.h" #include "log.h" #include "cvs.h" #include "compress.h" #define CVS_ZLIB_BUFSIZE 1024 struct cvs_zlib_ctx { int z_level; z_stream z_instrm; z_stream z_destrm; }; /* * cvs_zlib_newctx() * * Allocate a new ZLIB context structure used for both inflation and deflation * of data with compression level , which must be between 0 and 9. A * value of 0 means no compression, and 9 is the highest level of compression. */ CVSZCTX * cvs_zlib_newctx(int level) { CVSZCTX *ctx; if (level < 0 || level > 9) fatal("invalid compression level %d (must be between 0 and 9)", level); ctx = xcalloc(1, sizeof(*ctx)); ctx->z_level = level; ctx->z_instrm.zalloc = Z_NULL; ctx->z_instrm.zfree = Z_NULL; ctx->z_instrm.opaque = Z_NULL; ctx->z_destrm.zalloc = Z_NULL; ctx->z_destrm.zfree = Z_NULL; ctx->z_destrm.opaque = Z_NULL; if (inflateInit(&(ctx->z_instrm)) != Z_OK || deflateInit(&(ctx->z_destrm), level) != Z_OK) fatal("failed to initialize zlib streams"); return (ctx); } /* * cvs_zlib_free() * * Free a ZLIB context previously allocated with cvs_zlib_newctx(). */ void cvs_zlib_free(CVSZCTX *ctx) { if (ctx != NULL) { (void)inflateEnd(&(ctx->z_instrm)); (void)deflateEnd(&(ctx->z_destrm)); xfree(ctx); } } /* * cvs_zlib_inflate() * * Decompress the first bytes of using the zlib context and * store the resulting data in . * Returns the number of bytes inflated on success, or -1 on failure. */ int cvs_zlib_inflate(CVSZCTX *ctx, BUF *dst, u_char *src, size_t slen) { int bytes, ret; u_char buf[CVS_ZLIB_BUFSIZE]; bytes = 0; cvs_buf_empty(dst); if (inflateReset(&(ctx->z_instrm)) == Z_STREAM_ERROR) fatal("inflate error: %s", ctx->z_instrm.msg); ctx->z_instrm.next_in = src; ctx->z_instrm.avail_in = slen; do { ctx->z_instrm.next_out = buf; ctx->z_instrm.avail_out = sizeof(buf); ret = inflate(&(ctx->z_instrm), Z_FINISH); if (ret == Z_MEM_ERROR || ret == Z_BUF_ERROR || ret == Z_STREAM_ERROR || ret == Z_DATA_ERROR) fatal("inflate error: %s", ctx->z_instrm.msg); cvs_buf_append(dst, buf, ctx->z_instrm.avail_out); bytes += sizeof(buf) - ctx->z_instrm.avail_out; } while (ret != Z_STREAM_END); return (bytes); } /* * cvs_zlib_deflate() * * Compress the first bytes of using the zlib context and * store the resulting data in . * Returns the number of bytes deflated on success, or -1 on failure. */ int cvs_zlib_deflate(CVSZCTX *ctx, BUF *dst, u_char *src, size_t slen) { int bytes, ret; u_char buf[CVS_ZLIB_BUFSIZE]; bytes = 0; cvs_buf_empty(dst); if (deflateReset(&(ctx->z_destrm)) == Z_STREAM_ERROR) fatal("deflate error: %s", ctx->z_destrm.msg); ctx->z_destrm.next_in = src; ctx->z_destrm.avail_in = slen; do { ctx->z_destrm.next_out = buf; ctx->z_destrm.avail_out = sizeof(buf); ret = deflate(&(ctx->z_destrm), Z_FINISH); if (ret == Z_STREAM_ERROR || ret == Z_BUF_ERROR) fatal("deflate error: %s", ctx->z_destrm.msg); if (cvs_buf_append(dst, buf, sizeof(buf) - ctx->z_destrm.avail_out) < 0) return (-1); bytes += sizeof(buf) - ctx->z_destrm.avail_out; } while (ret != Z_STREAM_END); return (bytes); }