From 869c6bb7e455c91680bad8c2649bcfcdacfc4e7d Mon Sep 17 00:00:00 2001 From: David Shaw Date: Fri, 31 Oct 2003 05:39:02 +0000 Subject: [PATCH] * misc.c (compress_algo_to_string, string_to_compress_algo, check_compress_algo): Add bzip2. * compress.c (compress_filter): Make static to help force the use of push_compress_filter. Remove default algorithm setting since that is done in push_compress_filter now. * main.h: Use named algorithm. * filter.h, compress.c (push_compress_filter, push_compress_filter2): New. Figure out which is the appropriate compression filter to use, and push it into place. * compress.c (handle_compressed), encode.c (encode_simple, encode_crypt), sign.c (sign_file, sign_symencrypt_file), import.c (read_block), export.c (do_export): Use push_compress_filter instead of pushing the compression filter ourselves. * compress-bz2.c: New. Bzlib versions of the compression filter routines. * Makefile.am: Include compress-bz2.c if bz2lib is available. --- g10/ChangeLog | 25 +++++ g10/Makefile.am | 10 +- g10/compress-bz2.c | 242 +++++++++++++++++++++++++++++++++++++++++++++ g10/compress.c | 60 +++++++++-- g10/encode.c | 6 +- g10/export.c | 4 +- g10/filter.h | 5 +- g10/g10.c | 3 +- g10/import.c | 14 +-- g10/main.h | 2 +- g10/misc.c | 25 ++++- g10/sign.c | 10 +- 12 files changed, 366 insertions(+), 40 deletions(-) create mode 100644 g10/compress-bz2.c diff --git a/g10/ChangeLog b/g10/ChangeLog index 62b728a75..b7ffc151f 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,28 @@ +2003-10-30 David Shaw + + * misc.c (compress_algo_to_string, string_to_compress_algo, + check_compress_algo): Add bzip2. + + * compress.c (compress_filter): Make static to help force the use + of push_compress_filter. Remove default algorithm setting since + that is done in push_compress_filter now. + + * main.h: Use named algorithm. + + * filter.h, compress.c (push_compress_filter, + push_compress_filter2): New. Figure out which is the appropriate + compression filter to use, and push it into place. + + * compress.c (handle_compressed), encode.c (encode_simple, + encode_crypt), sign.c (sign_file, sign_symencrypt_file), import.c + (read_block), export.c (do_export): Use push_compress_filter + instead of pushing the compression filter ourselves. + + * compress-bz2.c: New. Bzlib versions of the compression filter + routines. + + * Makefile.am: Include compress-bz2.c if bz2lib is available. + 2003-10-30 Werner Koch * apdu.c (close_ct_reader, close_pcsc_reader): Implemented. diff --git a/g10/Makefile.am b/g10/Makefile.am index 37fbe0079..7ec5a8c10 100644 --- a/g10/Makefile.am +++ b/g10/Makefile.am @@ -1,5 +1,5 @@ # Copyright (C) 1998, 1999, 2000, 2001, 2002, -# 2003 Free Software Foundation, Inc. +# 2003 Free Software Foundation, Inc. # # This file is part of GnuPG. # @@ -32,10 +32,17 @@ needed_libs = ../cipher/libcipher.a ../mpi/libmpi.a ../util/libutil.a #noinst_PROGRAMS = gpgd bin_PROGRAMS = gpg gpgv +if ENABLE_BZIP2_SUPPORT +bzip2_source = compress-bz2.c +else +bzip2_source = +endif + common_source = \ global.h \ build-packet.c \ compress.c \ + $(bzip2_source) \ filter.h \ free-packet.c \ getkey.c \ @@ -154,4 +161,3 @@ update-source-from-gnupg-2: cp $$dir/g10/$$i $$i; echo $$i; \ done ; \ echo "Please remember to update the ChangeLog accordingly!" - diff --git a/g10/compress-bz2.c b/g10/compress-bz2.c new file mode 100644 index 000000000..a8497c154 --- /dev/null +++ b/g10/compress-bz2.c @@ -0,0 +1,242 @@ +/* compress.c - bzip2 compress filter + * Copyright (C) 2003 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include + +#include "util.h" +#include "memory.h" +#include "packet.h" +#include "filter.h" +#include "main.h" +#include "options.h" + +/* Note that the code in compress.c is nearly identical to the code + here, so if you fix a bug here, look there to see if the matching + bug needs to be fixed. I tried to have one set of functions that + could do ZIP, ZLIB, and BZIP2, but it became dangerously unreadable + with #ifdefs and if(algo) -dshaw */ + +static void +init_compress( compress_filter_context_t *zfx, bz_stream *bzs ) +{ + int rc; + int level; + + if( opt.compress >= 0 && opt.compress <= 9 ) + level = opt.compress; + else if( opt.compress == -1 ) + level = 6; /* no particular reason, but it seems reasonable */ + else if( opt.compress == 10 ) /* remove this ! */ + level = 0; + else + { + log_error("invalid compression level; using default level\n"); + level = 6; + } + + if((rc=BZ2_bzCompressInit(bzs,level,0,0))!=BZ_OK) + log_fatal("bz2lib problem: %d\n",rc); + + zfx->outbufsize = 8192; + zfx->outbuf = m_alloc( zfx->outbufsize ); +} + +static int +do_compress(compress_filter_context_t *zfx, bz_stream *bzs, int flush, IOBUF a) +{ + int zrc; + unsigned n; + + do + { + bzs->next_out = zfx->outbuf; + bzs->avail_out = zfx->outbufsize; + if( DBG_FILTER ) + log_debug("enter bzCompress: avail_in=%u, avail_out=%u, flush=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, flush ); + zrc = BZ2_bzCompress( bzs, flush ); + if( zrc == BZ_STREAM_END && flush == BZ_FINISH ) + ; + else if( zrc != BZ_RUN_OK && zrc != BZ_FINISH_OK ) + log_fatal("bz2lib deflate problem: rc=%d\n", zrc ); + + n = zfx->outbufsize - bzs->avail_out; + if( DBG_FILTER ) + log_debug("leave bzCompress:" + " avail_in=%u, avail_out=%u, n=%u, zrc=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, + (unsigned)n, zrc ); + + if( iobuf_write( a, zfx->outbuf, n ) ) + { + log_debug("bzCompress: iobuf_write failed\n"); + return G10ERR_WRITE_FILE; + } + } + while( bzs->avail_in || (flush == BZ_FINISH && zrc != BZ_STREAM_END) ); + + return 0; +} + +static void +init_uncompress( compress_filter_context_t *zfx, bz_stream *bzs ) +{ + int rc; + + if((rc=BZ2_bzDecompressInit(bzs,0,0))!=BZ_OK) + log_fatal("bz2lib problem: %d\n",rc); + + zfx->inbufsize = 2048; + zfx->inbuf = m_alloc( zfx->inbufsize ); + bzs->avail_in = 0; +} + +static int +do_uncompress( compress_filter_context_t *zfx, bz_stream *bzs, + IOBUF a, size_t *ret_len ) +{ + int zrc; + int rc=0; + size_t n; + int nread, count; + int refill = !bzs->avail_in; + + if( DBG_FILTER ) + log_debug("begin bzDecompress: avail_in=%u, avail_out=%u, inbuf=%u\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, + (unsigned)zfx->inbufsize ); + do + { + if( bzs->avail_in < zfx->inbufsize && refill ) + { + n = bzs->avail_in; + if( !n ) + bzs->next_in = zfx->inbuf; + count = zfx->inbufsize - n; + nread = iobuf_read( a, zfx->inbuf + n, count ); + if( nread == -1 ) nread = 0; + n += nread; + bzs->avail_in = n; + } + + refill = 1; + + if( DBG_FILTER ) + log_debug("enter bzDecompress: avail_in=%u, avail_out=%u\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out); + + zrc=BZ2_bzDecompress(bzs); + if( DBG_FILTER ) + log_debug("leave bzDecompress: avail_in=%u, avail_out=%u, zrc=%d\n", + (unsigned)bzs->avail_in, (unsigned)bzs->avail_out, zrc); + if( zrc == BZ_STREAM_END ) + rc = -1; /* eof */ + else if( zrc != BZ_OK && zrc != BZ_PARAM_ERROR ) + log_fatal("bz2lib inflate problem: rc=%d\n", zrc ); + } + while( bzs->avail_out && zrc != BZ_STREAM_END && zrc != BZ_PARAM_ERROR ); + + /* I'm not completely happy with the two uses of BZ_PARAM_ERROR + here. The corresponding zlib function is Z_BUF_ERROR, which + covers a narrower scope than BZ_PARAM_ERROR. -dshaw */ + + *ret_len = zfx->outbufsize - bzs->avail_out; + if( DBG_FILTER ) + log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len ); + return rc; +} + +int +compress_filter_bz2( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len) +{ + size_t size = *ret_len; + compress_filter_context_t *zfx = opaque; + bz_stream *bzs = zfx->opaque; + int rc=0; + + if( control == IOBUFCTRL_UNDERFLOW ) + { + if( !zfx->status ) + { + bzs = zfx->opaque = m_alloc_clear( sizeof *bzs ); + init_uncompress( zfx, bzs ); + zfx->status = 1; + } + + bzs->next_out = buf; + bzs->avail_out = size; + zfx->outbufsize = size; /* needed only for calculation */ + rc = do_uncompress( zfx, bzs, a, ret_len ); + } + else if( control == IOBUFCTRL_FLUSH ) + { + if( !zfx->status ) + { + PACKET pkt; + PKT_compressed cd; + + if( zfx->algo != COMPRESS_ALGO_BZIP2 ) + BUG(); + memset( &cd, 0, sizeof cd ); + cd.len = 0; + cd.algorithm = zfx->algo; + init_packet( &pkt ); + pkt.pkttype = PKT_COMPRESSED; + pkt.pkt.compressed = &cd; + if( build_packet( a, &pkt )) + log_bug("build_packet(PKT_COMPRESSED) failed\n"); + bzs = zfx->opaque = m_alloc_clear( sizeof *bzs ); + init_compress( zfx, bzs ); + zfx->status = 2; + } + + bzs->next_in = buf; + bzs->avail_in = size; + rc = do_compress( zfx, bzs, BZ_RUN, a ); + } + else if( control == IOBUFCTRL_FREE ) + { + if( zfx->status == 1 ) + { + BZ2_bzDecompressEnd(bzs); + m_free(bzs); + zfx->opaque = NULL; + m_free(zfx->outbuf); zfx->outbuf = NULL; + } + else if( zfx->status == 2 ) + { + bzs->next_in = buf; + bzs->avail_in = 0; + do_compress( zfx, bzs, BZ_FINISH, a ); + BZ2_bzCompressEnd(bzs); + m_free(bzs); + zfx->opaque = NULL; + m_free(zfx->outbuf); zfx->outbuf = NULL; + } + if (zfx->release) + zfx->release (zfx); + } + else if( control == IOBUFCTRL_DESC ) + *(char**)buf = "compress_filter"; + return rc; +} diff --git a/g10/compress.c b/g10/compress.c index 8d9327cc3..80878835a 100644 --- a/g10/compress.c +++ b/g10/compress.c @@ -1,5 +1,6 @@ /* compress.c - compress filter - * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + * Copyright (C) 1998, 1999, 2000, 2001, 2002, + * 2003 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -18,6 +19,12 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +/* Note that the code in compress-bz2.c is nearly identical to the + code here, so if you fix a bug here, look there to see if the + matching bug needs to be fixed. I tried to have one set of + functions that could do ZIP, ZLIB, and BZIP2, but it became + dangerously unreadable with #ifdefs and if(algo) -dshaw */ + #include #include #include @@ -37,6 +44,9 @@ #include "main.h" #include "options.h" +int compress_filter_bz2( void *opaque, int control, + IOBUF a, byte *buf, size_t *ret_len); + static void init_compress( compress_filter_context_t *zfx, z_stream *zs ) { @@ -208,7 +218,7 @@ do_uncompress( compress_filter_context_t *zfx, z_stream *zs, return rc; } -int +static int compress_filter( void *opaque, int control, IOBUF a, byte *buf, size_t *ret_len) { @@ -237,10 +247,8 @@ compress_filter( void *opaque, int control, if( !zfx->status ) { PACKET pkt; PKT_compressed cd; - - if( !zfx->algo ) - zfx->algo = DEFAULT_COMPRESS_ALGO; - if( zfx->algo != 1 && zfx->algo != 2 ) + if(zfx->algo != COMPRESS_ALGO_ZIP + && zfx->algo != COMPRESS_ALGO_ZLIB) BUG(); memset( &cd, 0, sizeof cd ); cd.len = 0; @@ -308,12 +316,12 @@ handle_compressed( void *procctx, PKT_compressed *cd, compress_filter_context_t *cfx; int rc; - if( cd->algorithm < 1 || cd->algorithm > 2 ) - return G10ERR_COMPR_ALGO; + if(check_compress_algo(cd->algorithm)) + return G10ERR_COMPR_ALGO; cfx = m_alloc_clear (sizeof *cfx); - cfx->algo = cd->algorithm; cfx->release = release_context; - iobuf_push_filter( cd->buf, compress_filter, cfx ); + cfx->algo = cd->algorithm; + push_compress_filter(cd->buf,cfx,cd->algorithm); if( callback ) rc = callback(cd->buf, passthru ); else @@ -322,3 +330,35 @@ handle_compressed( void *procctx, PKT_compressed *cd, return rc; } +void +push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo) +{ + push_compress_filter2(out,zfx,algo,0); +} + +void +push_compress_filter2(IOBUF out,compress_filter_context_t *zfx, + int algo,int rel) +{ + if(algo>0) + zfx->algo=algo; + else + zfx->algo=DEFAULT_COMPRESS_ALGO; + + switch(zfx->algo) + { + case COMPRESS_ALGO_ZIP: + case COMPRESS_ALGO_ZLIB: + iobuf_push_filter2(out,compress_filter,zfx,rel); + break; + +#ifdef HAVE_BZIP2 + case COMPRESS_ALGO_BZIP2: + iobuf_push_filter2(out,compress_filter_bz2,zfx,rel); + break; +#endif + + default: + BUG(); + } +} diff --git a/g10/encode.c b/g10/encode.c index 05fdb6ac3..dfde96234 100644 --- a/g10/encode.c +++ b/g10/encode.c @@ -332,8 +332,7 @@ encode_simple( const char *filename, int mode, int use_seskey ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; - zfx.algo=default_compress_algo(); - iobuf_push_filter( out, compress_filter, &zfx ); + push_compress_filter(out,&zfx,opt.def_compress_algo); } /* do the work */ @@ -627,8 +626,7 @@ encode_crypt( const char *filename, STRLIST remusr, int use_symkey ) { if (cfx.dek && cfx.dek->use_mdc) zfx.new_ctb = 1; - zfx.algo = compr_algo; - iobuf_push_filter( out, compress_filter, &zfx ); + push_compress_filter(out,&zfx,compr_algo); } } diff --git a/g10/export.c b/g10/export.c index 5783f6ac1..1545fafcd 100644 --- a/g10/export.c +++ b/g10/export.c @@ -114,9 +114,9 @@ do_export( STRLIST users, int secret, unsigned int options ) iobuf_push_filter( out, armor_filter, &afx ); } if( opt.compress_keys && opt.compress ) - iobuf_push_filter( out, compress_filter, &zfx ); - rc = do_export_stream( out, users, secret, NULL, options, &any ); + push_compress_filter(out,&zfx,opt.def_compress_algo); + rc = do_export_stream( out, users, secret, NULL, options, &any ); if( rc || !any ) iobuf_cancel(out); else diff --git a/g10/filter.h b/g10/filter.h index 9f235fd6b..fed70c25c 100644 --- a/g10/filter.h +++ b/g10/filter.h @@ -132,8 +132,9 @@ void unarmor_pump_release (UnarmorPump x); int unarmor_pump (UnarmorPump x, int c); /*-- compress.c --*/ -int compress_filter( void *opaque, int control, - IOBUF chain, byte *buf, size_t *ret_len); +void push_compress_filter(IOBUF out,compress_filter_context_t *zfx,int algo); +void push_compress_filter2(IOBUF out,compress_filter_context_t *zfx, + int algo,int rel); /*-- cipher.c --*/ int cipher_filter( void *opaque, int control, diff --git a/g10/g10.c b/g10/g10.c index 9123bc4d3..28ebc8ddb 100644 --- a/g10/g10.c +++ b/g10/g10.c @@ -2485,7 +2485,8 @@ main( int argc, char **argv ) break; case aEncrSym: - /* This works with PGP 8. It doesn't work with 2 or 6. It + /* This works with PGP 8 in the sense that it acts just like a + symmetric message. It doesn't work at all with 2 or 6. It might work with 7, but alas, I don't have a copy to test with right now. */ if( argc > 1 ) diff --git a/g10/import.c b/g10/import.c index 80b4f6749..c5bcb595c 100644 --- a/g10/import.c +++ b/g10/import.c @@ -364,17 +364,17 @@ read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root ) /* make a linked list of all packets */ switch( pkt->pkttype ) { case PKT_COMPRESSED: - if( pkt->pkt.compressed->algorithm < 1 - || pkt->pkt.compressed->algorithm > 2 ) { + if(check_compress_algo(pkt->pkt.compressed->algorithm)) + { rc = G10ERR_COMPR_ALGO; goto ready; - } - { + } + else + { compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx ); - cfx->algo = pkt->pkt.compressed->algorithm; pkt->pkt.compressed->buf = NULL; - iobuf_push_filter2( a, compress_filter, cfx, 1 ); - } + push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1); + } free_packet( pkt ); init_packet(pkt); break; diff --git a/g10/main.h b/g10/main.h index 5ea89b18d..1288790db 100644 --- a/g10/main.h +++ b/g10/main.h @@ -30,7 +30,7 @@ (i.e. uncompressed) rather than 1 (zip). */ #define DEFAULT_CIPHER_ALGO CIPHER_ALGO_CAST5 #define DEFAULT_DIGEST_ALGO DIGEST_ALGO_SHA1 -#define DEFAULT_COMPRESS_ALGO 1 +#define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP typedef struct { int header_okay; diff --git a/g10/misc.c b/g10/misc.c index 727c49920..49a84d905 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -548,17 +548,23 @@ compress_algo_to_string(int algo) switch(algo) { - case 0: + case COMPRESS_ALGO_NONE: s="Uncompressed"; break; - case 1: + case COMPRESS_ALGO_ZIP: s="ZIP"; break; - case 2: + case COMPRESS_ALGO_ZLIB: s="ZLIB"; break; + +#ifdef HAVE_BZIP2 + case COMPRESS_ALGO_BZIP2: + s="BZIP2"; + break; +#endif } return s; @@ -573,12 +579,20 @@ string_to_compress_algo(const char *string) return 1; else if(ascii_strcasecmp(string,"zlib")==0) return 2; +#ifdef HAVE_BZIP2 + else if(ascii_strcasecmp(string,"bzip2")==0) + return 3; +#endif else if(ascii_strcasecmp(string,"z0")==0) return 0; else if(ascii_strcasecmp(string,"z1")==0) return 1; else if(ascii_strcasecmp(string,"z2")==0) return 2; +#ifdef HAVE_BZIP2 + else if(ascii_strcasecmp(string,"z3")==0) + return 3; +#endif else return -1; } @@ -586,8 +600,13 @@ string_to_compress_algo(const char *string) int check_compress_algo(int algo) { +#ifdef HAVE_BZIP2 + if(algo>=0 && algo<=3) + return 0; +#else if(algo>=0 && algo<=2) return 0; +#endif return G10ERR_COMPR_ALGO; } diff --git a/g10/sign.c b/g10/sign.c index 3bfe602b2..b24e68f89 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -859,10 +859,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr, /* algo 0 means no compression */ if( compr_algo ) - { - zfx.algo = compr_algo; - iobuf_push_filter( out, compress_filter, &zfx ); - } + push_compress_filter(out,&zfx,compr_algo); } /* Write the one-pass signature packets if needed */ @@ -1181,10 +1178,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr) /* Push the Zip filter */ if (opt.compress && default_compress_algo()) - { - zfx.algo = default_compress_algo(); - iobuf_push_filter( out, compress_filter, &zfx ); - } + push_compress_filter(out,&zfx,opt.def_compress_algo); /* Write the one-pass signature packets */ /*(current filters: zip - encrypt - armor)*/