diff options
Diffstat (limited to 'contrib/pgcrypto/pgp-compress.c')
-rw-r--r-- | contrib/pgcrypto/pgp-compress.c | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/contrib/pgcrypto/pgp-compress.c b/contrib/pgcrypto/pgp-compress.c new file mode 100644 index 00000000000..4faf0e4e1ae --- /dev/null +++ b/contrib/pgcrypto/pgp-compress.c @@ -0,0 +1,322 @@ +/* + * pgp-compress.c + * ZIP and ZLIB compression via zlib. + * + * Copyright (c) 2005 Marko Kreen + * 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. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + * + * $PostgreSQL: pgsql/contrib/pgcrypto/pgp-compress.c,v 1.1 2005/07/10 13:46:28 momjian Exp $ + */ + +#include <postgres.h> + +#include "mbuf.h" +#include "px.h" +#include "pgp.h" + + +/* + * Compressed pkt writer + */ + +#ifndef DISABLE_ZLIB + +#include <zlib.h> +#define ZIP_OUT_BUF 8192 +#define ZIP_IN_BLOCK 8192 + +struct ZipStat +{ + uint8 type; + int buf_len; + int hdr_done; + z_stream stream; + uint8 buf[ZIP_OUT_BUF]; +}; + +static void * +z_alloc(void *priv, unsigned n_items, unsigned item_len) +{ + return px_alloc(n_items * item_len); +} + +static void +z_free(void *priv, void *addr) +{ + px_free(addr); +} + +static int +compress_init(PushFilter * next, void *init_arg, void **priv_p) +{ + int res; + struct ZipStat *st; + PGP_Context *ctx = init_arg; + uint8 type = ctx->compress_algo; + + if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP) + return PXE_PGP_UNSUPPORTED_COMPR; + + /* + * init + */ + st = px_alloc(sizeof(*st)); + memset(st, 0, sizeof(*st)); + st->buf_len = ZIP_OUT_BUF; + st->stream.zalloc = z_alloc; + st->stream.zfree = z_free; + + if (type == PGP_COMPR_ZIP) + res = deflateInit2(&st->stream, ctx->compress_level, + Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + else + res = deflateInit(&st->stream, ctx->compress_level); + if (res != Z_OK) + { + px_free(st); + return PXE_PGP_COMPRESSION_ERROR; + } + *priv_p = st; + + return ZIP_IN_BLOCK; +} + +/* writes compressed data packet */ + +/* cant handle zero-len incoming data, but shouldnt */ +static int +compress_process(PushFilter * next, void *priv, const uint8 *data, int len) +{ + int res, + n_out; + struct ZipStat *st = priv; + + /* + * process data + */ + while (len > 0) + { + st->stream.next_in = (void *) data; + st->stream.avail_in = len; + st->stream.next_out = st->buf; + st->stream.avail_out = st->buf_len; + res = deflate(&st->stream, 0); + if (res != Z_OK) + return PXE_PGP_COMPRESSION_ERROR; + + n_out = st->buf_len - st->stream.avail_out; + if (n_out > 0) + { + res = pushf_write(next, st->buf, n_out); + if (res < 0) + return res; + } + len = st->stream.avail_in; + } + + return 0; +} + +static int +compress_flush(PushFilter * next, void *priv) +{ + int res, + zres, + n_out; + struct ZipStat *st = priv; + + st->stream.next_in = NULL; + st->stream.avail_in = 0; + while (1) + { + st->stream.next_out = st->buf; + st->stream.avail_out = st->buf_len; + zres = deflate(&st->stream, Z_FINISH); + if (zres != Z_STREAM_END && zres != Z_OK) + return PXE_PGP_COMPRESSION_ERROR; + n_out = st->buf_len - st->stream.avail_out; + if (n_out > 0) + { + res = pushf_write(next, st->buf, n_out); + if (res < 0) + return res; + } + if (zres == Z_STREAM_END) + break; + } + return 0; +} + +static void +compress_free(void *priv) +{ + struct ZipStat *st = priv; + + deflateEnd(&st->stream); + memset(st, 0, sizeof(*st)); + px_free(st); +} + +static const PushFilterOps +compress_filter = { + compress_init, compress_process, compress_flush, compress_free +}; + +int +pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst) +{ + return pushf_create(res, &compress_filter, ctx, dst); +} + +/* + * Decompress + */ +struct DecomprData +{ + int buf_len; /* = ZIP_OUT_BUF */ + int buf_data; /* available data */ + uint8 *pos; + z_stream stream; + int eof; + uint8 buf[ZIP_OUT_BUF]; +}; + +static int +decompress_init(void **priv_p, void *arg, PullFilter *src) +{ + PGP_Context *ctx = arg; + struct DecomprData *dec; + int res; + + if (ctx->compress_algo != PGP_COMPR_ZLIB + && ctx->compress_algo != PGP_COMPR_ZIP) + return PXE_PGP_UNSUPPORTED_COMPR; + + dec = px_alloc(sizeof(*dec)); + memset(dec, 0, sizeof(*dec)); + dec->buf_len = ZIP_OUT_BUF; + *priv_p = dec; + + dec->stream.zalloc = z_alloc; + dec->stream.zfree = z_free; + + if (ctx->compress_algo == PGP_COMPR_ZIP) + res = inflateInit2(&dec->stream, -15); + else + res = inflateInit(&dec->stream); + if (res != Z_OK) + { + px_free(dec); + px_debug("decompress_init: inflateInit error"); + return PXE_PGP_COMPRESSION_ERROR; + } + + return 0; +} + +static int decompress_read(void *priv, PullFilter *src, int len, + uint8 **data_p, uint8 *buf, int buflen) +{ + int res; + int flush; + struct DecomprData *dec = priv; + +restart: + if (dec->buf_data > 0) + { + if (len > dec->buf_data) + len = dec->buf_data; + *data_p = dec->pos; + dec->pos += len; + dec->buf_data -= len; + return len; + } + + if (dec->eof) + return 0; + + if (dec->stream.avail_in == 0) { + uint8 *tmp; + res = pullf_read(src, 8192, &tmp); + if (res < 0) + return res; + dec->stream.next_in = tmp; + dec->stream.avail_in = res; + } + + dec->stream.next_out = dec->buf; + dec->stream.avail_out = dec->buf_len; + dec->pos = dec->buf; + + // Z_NO_FLUSH, Z_SYNC_FLUSH, + flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH; + res = inflate(&dec->stream, flush); + if (res != Z_OK && res != Z_STREAM_END) + { + px_debug("decompress_read: inflate error: %d", res); + return PXE_PGP_CORRUPT_DATA; + } + + dec->buf_data = dec->buf_len - dec->stream.avail_out; + if (res == Z_STREAM_END) + dec->eof = 1; + goto restart; +} + +static void decompress_free(void *priv) +{ + struct DecomprData *dec = priv; + inflateEnd(&dec->stream); + memset(dec, 0, sizeof(*dec)); + px_free(dec); +} + +static const PullFilterOps +decompress_filter = { + decompress_init, decompress_read, decompress_free +}; + +int +pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src) +{ + return pullf_create(res, &decompress_filter, ctx, src); +} + +#else /* DISABLE_ZLIB */ + +int +pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst) +{ + return PXE_PGP_UNSUPPORTED_COMPR; +} + +int +pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src) +{ + return PXE_PGP_UNSUPPORTED_COMPR; +} + +#endif + + |