~ubuntu-branches/ubuntu/jaunty/gnupg2/jaunty

« back to all changes in this revision

Viewing changes to g10/compress.c

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Mueller
  • Date: 2005-03-29 10:30:32 UTC
  • Revision ID: james.westby@ubuntu.com-20050329103032-sj42n2ain3ipx310
Tags: upstream-1.9.15
ImportĀ upstreamĀ versionĀ 1.9.15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* compress.c - compress filter
 
2
 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
 
3
 *               2003 Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of GnuPG.
 
6
 *
 
7
 * GnuPG is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * GnuPG is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
20
 */
 
21
 
 
22
#include <config.h>
 
23
#include <stdio.h>
 
24
#include <stdlib.h>
 
25
#include <string.h>
 
26
#include <unistd.h>
 
27
#include <assert.h>
 
28
#include <errno.h>
 
29
#include <zlib.h>
 
30
#ifdef __riscos__
 
31
# include "zlib-riscos.h"
 
32
#endif
 
33
 
 
34
#include "gpg.h"
 
35
#include "util.h"
 
36
#include "memory.h"
 
37
#include "packet.h"
 
38
#include "filter.h"
 
39
#include "main.h"
 
40
#include "options.h"
 
41
 
 
42
static void
 
43
init_compress( compress_filter_context_t *zfx, z_stream *zs )
 
44
{
 
45
    int rc;
 
46
    int level;
 
47
 
 
48
#ifdef __riscos__
 
49
    static int zlib_initialized = 0;
 
50
 
 
51
    if (!zlib_initialized)
 
52
        zlib_initialized = riscos_load_module("ZLib", zlib_path, 1);
 
53
#endif
 
54
 
 
55
    if( opt.compress >= 0 && opt.compress <= 9 )
 
56
        level = opt.compress;
 
57
    else if( opt.compress == -1 )
 
58
        level = Z_DEFAULT_COMPRESSION;
 
59
    else if( opt.compress == 10 ) /* remove this ! */
 
60
        level = 0;
 
61
    else {
 
62
        log_error("invalid compression level; using default level\n");
 
63
        level = Z_DEFAULT_COMPRESSION;
 
64
    }
 
65
 
 
66
 
 
67
    if( (rc = zfx->algo == 1? deflateInit2( zs, level, Z_DEFLATED,
 
68
                                            -13, 8, Z_DEFAULT_STRATEGY)
 
69
                            : deflateInit( zs, level )
 
70
                            ) != Z_OK ) {
 
71
        log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
 
72
                               rc == Z_MEM_ERROR ? "out of core" :
 
73
                               rc == Z_VERSION_ERROR ? "invalid lib version" :
 
74
                                                       "unknown error" );
 
75
    }
 
76
 
 
77
    zfx->outbufsize = 8192;
 
78
    zfx->outbuf = xmalloc ( zfx->outbufsize );
 
79
}
 
80
 
 
81
static int
 
82
do_compress( compress_filter_context_t *zfx, z_stream *zs, int flush, iobuf_t a )
 
83
{
 
84
    gpg_error_t rc;
 
85
    int zrc;
 
86
    unsigned n;
 
87
 
 
88
    do {
 
89
#ifndef __riscos__
 
90
        zs->next_out = zfx->outbuf;
 
91
#else /* __riscos__ */
 
92
        zs->next_out = (Bytef *) zfx->outbuf;
 
93
#endif /* __riscos__ */
 
94
        zs->avail_out = zfx->outbufsize;
 
95
        if( DBG_FILTER )
 
96
            log_debug("enter deflate: avail_in=%u, avail_out=%u, flush=%d\n",
 
97
                    (unsigned)zs->avail_in, (unsigned)zs->avail_out, flush );
 
98
        zrc = deflate( zs, flush );
 
99
        if( zrc == Z_STREAM_END && flush == Z_FINISH )
 
100
            ;
 
101
        else if( zrc != Z_OK ) {
 
102
            if( zs->msg )
 
103
                log_fatal("zlib deflate problem: %s\n", zs->msg );
 
104
            else
 
105
                log_fatal("zlib deflate problem: rc=%d\n", zrc );
 
106
        }
 
107
        n = zfx->outbufsize - zs->avail_out;
 
108
        if( DBG_FILTER )
 
109
            log_debug("leave deflate: "
 
110
                      "avail_in=%u, avail_out=%u, n=%u, zrc=%d\n",
 
111
                (unsigned)zs->avail_in, (unsigned)zs->avail_out,
 
112
                                               (unsigned)n, zrc );
 
113
 
 
114
        rc = iobuf_write (a, zfx->outbuf, n);
 
115
        if (rc)
 
116
          {
 
117
            log_debug("deflate: iobuf_write failed\n");
 
118
            return rc;
 
119
          }
 
120
    } while( zs->avail_in || (flush == Z_FINISH && zrc != Z_STREAM_END) );
 
121
    return 0;
 
122
}
 
123
 
 
124
static void
 
125
init_uncompress( compress_filter_context_t *zfx, z_stream *zs )
 
126
{
 
127
    int rc;
 
128
 
 
129
    /****************
 
130
     * PGP uses a windowsize of 13 bits. Using a negative value for
 
131
     * it forces zlib not to expect a zlib header.  This is a
 
132
     * undocumented feature Peter Gutmann told me about.
 
133
     *    
 
134
     * We must use 15 bits for the inflator because CryptoEx uses 15
 
135
     * bits thus the output would get scrambled w/o error indication
 
136
     * if we would use 13 bits.  For the uncompressing this does not
 
137
     * matter at all.
 
138
     */
 
139
    if( (rc = zfx->algo == 1? inflateInit2( zs, -15)
 
140
                            : inflateInit( zs )) != Z_OK ) {
 
141
        log_fatal("zlib problem: %s\n", zs->msg? zs->msg :
 
142
                               rc == Z_MEM_ERROR ? "out of core" :
 
143
                               rc == Z_VERSION_ERROR ? "invalid lib version" :
 
144
                                                       "unknown error" );
 
145
    }
 
146
 
 
147
    zfx->inbufsize = 2048;
 
148
    zfx->inbuf = xmalloc ( zfx->inbufsize );
 
149
    zs->avail_in = 0;
 
150
}
 
151
 
 
152
static int
 
153
do_uncompress( compress_filter_context_t *zfx, z_stream *zs,
 
154
               iobuf_t a, size_t *ret_len )
 
155
{
 
156
    int zrc;
 
157
    int rc=0;
 
158
    size_t n;
 
159
    int nread, count;
 
160
    int refill = !zs->avail_in;
 
161
 
 
162
    if( DBG_FILTER )
 
163
        log_debug("begin inflate: avail_in=%u, avail_out=%u, inbuf=%u\n",
 
164
                (unsigned)zs->avail_in, (unsigned)zs->avail_out,
 
165
                (unsigned)zfx->inbufsize );
 
166
    do {
 
167
        if( zs->avail_in < zfx->inbufsize && refill ) {
 
168
            n = zs->avail_in;
 
169
            if( !n )
 
170
#ifndef __riscos__
 
171
                zs->next_in = zfx->inbuf;
 
172
#else /* __riscos__ */
 
173
                zs->next_in = (Bytef *) zfx->inbuf;
 
174
#endif /* __riscos__ */
 
175
            count = zfx->inbufsize - n;
 
176
            nread = iobuf_read( a, zfx->inbuf + n, count );
 
177
            if( nread == -1 ) nread = 0;
 
178
            n += nread;
 
179
            /* If we use the undocumented feature to suppress
 
180
             * the zlib header, we have to give inflate an
 
181
             * extra dummy byte to read */
 
182
            if( nread < count && zfx->algo == 1 ) {
 
183
                *(zfx->inbuf + n) = 0xFF; /* is it really needed ? */
 
184
                zfx->algo1hack = 1;
 
185
                n++;
 
186
            }
 
187
            zs->avail_in = n;
 
188
        }
 
189
        refill = 1;
 
190
        if( DBG_FILTER )
 
191
            log_debug("enter inflate: avail_in=%u, avail_out=%u\n",
 
192
                    (unsigned)zs->avail_in, (unsigned)zs->avail_out);
 
193
#ifdef Z_SYNC_FLUSH
 
194
        zrc = inflate( zs, Z_SYNC_FLUSH );
 
195
#else
 
196
        zrc = inflate( zs, Z_PARTIAL_FLUSH );
 
197
#endif
 
198
        if( DBG_FILTER )
 
199
            log_debug("leave inflate: avail_in=%u, avail_out=%u, zrc=%d\n",
 
200
                   (unsigned)zs->avail_in, (unsigned)zs->avail_out, zrc);
 
201
        if( zrc == Z_STREAM_END )
 
202
            rc = -1; /* eof */
 
203
        else if( zrc != Z_OK && zrc != Z_BUF_ERROR ) {
 
204
            if( zs->msg )
 
205
                log_fatal("zlib inflate problem: %s\n", zs->msg );
 
206
            else
 
207
                log_fatal("zlib inflate problem: rc=%d\n", zrc );
 
208
        }
 
209
    } while( zs->avail_out && zrc != Z_STREAM_END  && zrc != Z_BUF_ERROR );
 
210
    *ret_len = zfx->outbufsize - zs->avail_out;
 
211
    if( DBG_FILTER )
 
212
        log_debug("do_uncompress: returning %u bytes\n", (unsigned)*ret_len );
 
213
    return rc;
 
214
}
 
215
 
 
216
int
 
217
compress_filter( void *opaque, int control,
 
218
                 iobuf_t a, byte *buf, size_t *ret_len)
 
219
{
 
220
    size_t size = *ret_len;
 
221
    compress_filter_context_t *zfx = opaque;
 
222
    z_stream *zs = zfx->opaque;
 
223
    int rc=0;
 
224
 
 
225
    if( control == IOBUFCTRL_UNDERFLOW ) {
 
226
        if( !zfx->status ) {
 
227
            zs = zfx->opaque = xcalloc (1, sizeof *zs );
 
228
            init_uncompress( zfx, zs );
 
229
            zfx->status = 1;
 
230
        }
 
231
 
 
232
#ifndef __riscos__
 
233
        zs->next_out = buf;
 
234
#else /* __riscos__ */
 
235
        zs->next_out = (Bytef *) buf;
 
236
#endif /* __riscos__ */
 
237
        zs->avail_out = size;
 
238
        zfx->outbufsize = size; /* needed only for calculation */
 
239
        rc = do_uncompress( zfx, zs, a, ret_len );
 
240
    }
 
241
    else if( control == IOBUFCTRL_FLUSH ) {
 
242
        if( !zfx->status ) {
 
243
            PACKET pkt;
 
244
            PKT_compressed cd;
 
245
 
 
246
            if( !zfx->algo )
 
247
                zfx->algo = DEFAULT_COMPRESS_ALGO;
 
248
            if( zfx->algo != 1 && zfx->algo != 2 )
 
249
              BUG();
 
250
            memset( &cd, 0, sizeof cd );
 
251
            cd.len = 0;
 
252
            cd.algorithm = zfx->algo;
 
253
            init_packet( &pkt );
 
254
            pkt.pkttype = PKT_COMPRESSED;
 
255
            pkt.pkt.compressed = &cd;
 
256
            if( build_packet( a, &pkt ))
 
257
                log_bug("build_packet(PKT_COMPRESSED) failed\n");
 
258
            zs = zfx->opaque = xcalloc (1, sizeof *zs );
 
259
            init_compress( zfx, zs );
 
260
            zfx->status = 2;
 
261
        }
 
262
 
 
263
#ifndef __riscos__
 
264
        zs->next_in = buf;
 
265
#else /* __riscos__ */
 
266
        zs->next_in = (Bytef *) buf;
 
267
#endif /* __riscos__ */
 
268
        zs->avail_in = size;
 
269
        rc = do_compress( zfx, zs, Z_NO_FLUSH, a );
 
270
    }
 
271
    else if( control == IOBUFCTRL_FREE ) {
 
272
        if( zfx->status == 1 ) {
 
273
            inflateEnd(zs);
 
274
            xfree (zs);
 
275
            zfx->opaque = NULL;
 
276
            xfree (zfx->outbuf); zfx->outbuf = NULL;
 
277
        }
 
278
        else if( zfx->status == 2 ) {
 
279
#ifndef __riscos__
 
280
            zs->next_in = buf;
 
281
#else /* __riscos__ */
 
282
            zs->next_in = (Bytef *) buf;
 
283
#endif /* __riscos__ */
 
284
            zs->avail_in = 0;
 
285
            do_compress( zfx, zs, Z_FINISH, a );
 
286
            deflateEnd(zs);
 
287
            xfree (zs);
 
288
            zfx->opaque = NULL;
 
289
            xfree (zfx->outbuf); zfx->outbuf = NULL;
 
290
        }
 
291
        if (zfx->release)
 
292
          zfx->release (zfx);
 
293
    }
 
294
    else if( control == IOBUFCTRL_DESC )
 
295
        *(char**)buf = "compress_filter";
 
296
    return rc;
 
297
}
 
298
 
 
299
 
 
300
static void
 
301
release_context (compress_filter_context_t *ctx)
 
302
{
 
303
  xfree (ctx);
 
304
}
 
305
 
 
306
/****************
 
307
 * Handle a compressed packet
 
308
 */
 
309
int
 
310
handle_compressed( void *procctx, PKT_compressed *cd,
 
311
                   int (*callback)(iobuf_t, void *), void *passthru )
 
312
{
 
313
    compress_filter_context_t *cfx;
 
314
    int rc;
 
315
 
 
316
    if( cd->algorithm < 1 || cd->algorithm > 2  )
 
317
        return GPG_ERR_COMPR_ALGO;
 
318
    cfx = xcalloc (1,sizeof *cfx);
 
319
    cfx->algo = cd->algorithm;
 
320
    cfx->release = release_context;
 
321
    iobuf_push_filter( cd->buf, compress_filter, cfx );
 
322
    if( callback )
 
323
        rc = callback(cd->buf, passthru );
 
324
    else
 
325
        rc = proc_packets(procctx, cd->buf);
 
326
    cd->buf = NULL;
 
327
    return rc;
 
328
}
 
329