Header And Logo

PostgreSQL
| The world's most advanced open source database.

pgp-compress.c

Go to the documentation of this file.
00001 /*
00002  * pgp-compress.c
00003  *    ZIP and ZLIB compression via zlib.
00004  *
00005  * Copyright (c) 2005 Marko Kreen
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * contrib/pgcrypto/pgp-compress.c
00030  */
00031 
00032 #include "postgres.h"
00033 
00034 #include "mbuf.h"
00035 #include "px.h"
00036 #include "pgp.h"
00037 
00038 
00039 /*
00040  * Compressed pkt writer
00041  */
00042 
00043 #ifdef HAVE_LIBZ
00044 
00045 #include <zlib.h>
00046 
00047 #define ZIP_OUT_BUF 8192
00048 #define ZIP_IN_BLOCK 8192
00049 
00050 struct ZipStat
00051 {
00052     uint8       type;
00053     int         buf_len;
00054     int         hdr_done;
00055     z_stream    stream;
00056     uint8       buf[ZIP_OUT_BUF];
00057 };
00058 
00059 static void *
00060 z_alloc(void *priv, unsigned n_items, unsigned item_len)
00061 {
00062     return px_alloc(n_items * item_len);
00063 }
00064 
00065 static void
00066 z_free(void *priv, void *addr)
00067 {
00068     px_free(addr);
00069 }
00070 
00071 static int
00072 compress_init(PushFilter *next, void *init_arg, void **priv_p)
00073 {
00074     int         res;
00075     struct ZipStat *st;
00076     PGP_Context *ctx = init_arg;
00077     uint8       type = ctx->compress_algo;
00078 
00079     if (type != PGP_COMPR_ZLIB && type != PGP_COMPR_ZIP)
00080         return PXE_PGP_UNSUPPORTED_COMPR;
00081 
00082     /*
00083      * init
00084      */
00085     st = px_alloc(sizeof(*st));
00086     memset(st, 0, sizeof(*st));
00087     st->buf_len = ZIP_OUT_BUF;
00088     st->stream.zalloc = z_alloc;
00089     st->stream.zfree = z_free;
00090 
00091     if (type == PGP_COMPR_ZIP)
00092         res = deflateInit2(&st->stream, ctx->compress_level,
00093                            Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
00094     else
00095         res = deflateInit(&st->stream, ctx->compress_level);
00096     if (res != Z_OK)
00097     {
00098         px_free(st);
00099         return PXE_PGP_COMPRESSION_ERROR;
00100     }
00101     *priv_p = st;
00102 
00103     return ZIP_IN_BLOCK;
00104 }
00105 
00106 /* writes compressed data packet */
00107 
00108 /* can handle zero-len incoming data, but shouldn't */
00109 static int
00110 compress_process(PushFilter *next, void *priv, const uint8 *data, int len)
00111 {
00112     int         res,
00113                 n_out;
00114     struct ZipStat *st = priv;
00115 
00116     /*
00117      * process data
00118      */
00119     while (len > 0)
00120     {
00121         st->stream.next_in = (void *) data;
00122         st->stream.avail_in = len;
00123         st->stream.next_out = st->buf;
00124         st->stream.avail_out = st->buf_len;
00125         res = deflate(&st->stream, 0);
00126         if (res != Z_OK)
00127             return PXE_PGP_COMPRESSION_ERROR;
00128 
00129         n_out = st->buf_len - st->stream.avail_out;
00130         if (n_out > 0)
00131         {
00132             res = pushf_write(next, st->buf, n_out);
00133             if (res < 0)
00134                 return res;
00135         }
00136         len = st->stream.avail_in;
00137     }
00138 
00139     return 0;
00140 }
00141 
00142 static int
00143 compress_flush(PushFilter *next, void *priv)
00144 {
00145     int         res,
00146                 zres,
00147                 n_out;
00148     struct ZipStat *st = priv;
00149 
00150     st->stream.next_in = NULL;
00151     st->stream.avail_in = 0;
00152     while (1)
00153     {
00154         st->stream.next_out = st->buf;
00155         st->stream.avail_out = st->buf_len;
00156         zres = deflate(&st->stream, Z_FINISH);
00157         if (zres != Z_STREAM_END && zres != Z_OK)
00158             return PXE_PGP_COMPRESSION_ERROR;
00159         n_out = st->buf_len - st->stream.avail_out;
00160         if (n_out > 0)
00161         {
00162             res = pushf_write(next, st->buf, n_out);
00163             if (res < 0)
00164                 return res;
00165         }
00166         if (zres == Z_STREAM_END)
00167             break;
00168     }
00169     return 0;
00170 }
00171 
00172 static void
00173 compress_free(void *priv)
00174 {
00175     struct ZipStat *st = priv;
00176 
00177     deflateEnd(&st->stream);
00178     memset(st, 0, sizeof(*st));
00179     px_free(st);
00180 }
00181 
00182 static const PushFilterOps
00183             compress_filter = {
00184     compress_init, compress_process, compress_flush, compress_free
00185 };
00186 
00187 int
00188 pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
00189 {
00190     return pushf_create(res, &compress_filter, ctx, dst);
00191 }
00192 
00193 /*
00194  * Decompress
00195  */
00196 struct DecomprData
00197 {
00198     int         buf_len;        /* = ZIP_OUT_BUF */
00199     int         buf_data;       /* available data */
00200     uint8      *pos;
00201     z_stream    stream;
00202     int         eof;
00203     uint8       buf[ZIP_OUT_BUF];
00204 };
00205 
00206 static int
00207 decompress_init(void **priv_p, void *arg, PullFilter *src)
00208 {
00209     PGP_Context *ctx = arg;
00210     struct DecomprData *dec;
00211     int         res;
00212 
00213     if (ctx->compress_algo != PGP_COMPR_ZLIB
00214         && ctx->compress_algo != PGP_COMPR_ZIP)
00215         return PXE_PGP_UNSUPPORTED_COMPR;
00216 
00217     dec = px_alloc(sizeof(*dec));
00218     memset(dec, 0, sizeof(*dec));
00219     dec->buf_len = ZIP_OUT_BUF;
00220     *priv_p = dec;
00221 
00222     dec->stream.zalloc = z_alloc;
00223     dec->stream.zfree = z_free;
00224 
00225     if (ctx->compress_algo == PGP_COMPR_ZIP)
00226         res = inflateInit2(&dec->stream, -15);
00227     else
00228         res = inflateInit(&dec->stream);
00229     if (res != Z_OK)
00230     {
00231         px_free(dec);
00232         px_debug("decompress_init: inflateInit error");
00233         return PXE_PGP_COMPRESSION_ERROR;
00234     }
00235 
00236     return 0;
00237 }
00238 
00239 static int
00240 decompress_read(void *priv, PullFilter *src, int len,
00241                 uint8 **data_p, uint8 *buf, int buflen)
00242 {
00243     int         res;
00244     int         flush;
00245     struct DecomprData *dec = priv;
00246 
00247 restart:
00248     if (dec->buf_data > 0)
00249     {
00250         if (len > dec->buf_data)
00251             len = dec->buf_data;
00252         *data_p = dec->pos;
00253         dec->pos += len;
00254         dec->buf_data -= len;
00255         return len;
00256     }
00257 
00258     if (dec->eof)
00259         return 0;
00260 
00261     if (dec->stream.avail_in == 0)
00262     {
00263         uint8      *tmp;
00264 
00265         res = pullf_read(src, 8192, &tmp);
00266         if (res < 0)
00267             return res;
00268         dec->stream.next_in = tmp;
00269         dec->stream.avail_in = res;
00270     }
00271 
00272     dec->stream.next_out = dec->buf;
00273     dec->stream.avail_out = dec->buf_len;
00274     dec->pos = dec->buf;
00275 
00276     /*
00277      * Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
00278      * it anyway (Z_NO_FLUSH), but seems to reserve the right not to.  So lets
00279      * follow the API.
00280      */
00281     flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
00282     res = inflate(&dec->stream, flush);
00283     if (res != Z_OK && res != Z_STREAM_END)
00284     {
00285         px_debug("decompress_read: inflate error: %d", res);
00286         return PXE_PGP_CORRUPT_DATA;
00287     }
00288 
00289     dec->buf_data = dec->buf_len - dec->stream.avail_out;
00290     if (res == Z_STREAM_END)
00291         dec->eof = 1;
00292     goto restart;
00293 }
00294 
00295 static void
00296 decompress_free(void *priv)
00297 {
00298     struct DecomprData *dec = priv;
00299 
00300     inflateEnd(&dec->stream);
00301     memset(dec, 0, sizeof(*dec));
00302     px_free(dec);
00303 }
00304 
00305 static const PullFilterOps
00306             decompress_filter = {
00307     decompress_init, decompress_read, decompress_free
00308 };
00309 
00310 int
00311 pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
00312 {
00313     return pullf_create(res, &decompress_filter, ctx, src);
00314 }
00315 #else                           /* !HAVE_ZLIB */
00316 
00317 int
00318 pgp_compress_filter(PushFilter **res, PGP_Context *ctx, PushFilter *dst)
00319 {
00320     return PXE_PGP_UNSUPPORTED_COMPR;
00321 }
00322 
00323 int
00324 pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
00325 {
00326     return PXE_PGP_UNSUPPORTED_COMPR;
00327 }
00328 
00329 #endif