Update from 0.9.8-stable.
[openssl.git] / crypto / comp / c_zlib.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <openssl/objects.h>
5 #include <openssl/comp.h>
6 #include <openssl/err.h>
7
8 COMP_METHOD *COMP_zlib(void );
9
10 static COMP_METHOD zlib_method_nozlib={
11         NID_undef,
12         "(undef)",
13         NULL,
14         NULL,
15         NULL,
16         NULL,
17         NULL,
18         NULL,
19         };
20
21 #ifndef ZLIB
22 #undef ZLIB_SHARED
23 #else
24
25 #include <zlib.h>
26
27 static int zlib_stateful_init(COMP_CTX *ctx);
28 static void zlib_stateful_finish(COMP_CTX *ctx);
29 static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
30         unsigned int olen, unsigned char *in, unsigned int ilen);
31 static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
32         unsigned int olen, unsigned char *in, unsigned int ilen);
33
34 #if 0
35 static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
36         unsigned int olen, unsigned char *in, unsigned int ilen);
37 static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
38         unsigned int olen, unsigned char *in, unsigned int ilen);
39
40 static int zz_uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
41         uLong sourceLen);
42
43 static COMP_METHOD zlib_stateless_method={
44         NID_zlib_compression,
45         LN_zlib_compression,
46         NULL,
47         NULL,
48         zlib_compress_block,
49         zlib_expand_block,
50         NULL,
51         NULL,
52         };
53 #endif
54
55 static COMP_METHOD zlib_stateful_method={
56         NID_zlib_compression,
57         LN_zlib_compression,
58         zlib_stateful_init,
59         zlib_stateful_finish,
60         zlib_stateful_compress_block,
61         zlib_stateful_expand_block,
62         NULL,
63         NULL,
64         };
65
66 /* 
67  * When OpenSSL is built on Windows, we do not want to require that
68  * the ZLIB.DLL be available in order for the OpenSSL DLLs to
69  * work.  Therefore, all ZLIB routines are loaded at run time
70  * and we do not link to a .LIB file when ZLIB_SHARED is set.
71  */
72 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
73 # include <windows.h>
74 #endif /* !(OPENSSL_SYS_WINDOWS || OPENSSL_SYS_WIN32) */
75
76 #ifdef ZLIB_SHARED
77 #include <openssl/dso.h>
78
79 /* Function pointers */
80 typedef int (*compress_ft)(Bytef *dest,uLongf *destLen,
81         const Bytef *source, uLong sourceLen);
82 typedef int (*inflateEnd_ft)(z_streamp strm);
83 typedef int (*inflate_ft)(z_streamp strm, int flush);
84 typedef int (*inflateInit__ft)(z_streamp strm,
85         const char * version, int stream_size);
86 typedef int (*deflateEnd_ft)(z_streamp strm);
87 typedef int (*deflate_ft)(z_streamp strm, int flush);
88 typedef int (*deflateInit__ft)(z_streamp strm, int level,
89         const char * version, int stream_size);
90 static compress_ft      p_compress=NULL;
91 static inflateEnd_ft    p_inflateEnd=NULL;
92 static inflate_ft       p_inflate=NULL;
93 static inflateInit__ft  p_inflateInit_=NULL;
94 static deflateEnd_ft    p_deflateEnd=NULL;
95 static deflate_ft       p_deflate=NULL;
96 static deflateInit__ft  p_deflateInit_=NULL;
97
98 static int zlib_loaded = 0;     /* only attempt to init func pts once */
99 static DSO *zlib_dso = NULL;
100
101 #define compress                p_compress
102 #define inflateEnd              p_inflateEnd
103 #define inflate                 p_inflate
104 #define inflateInit_            p_inflateInit_
105 #define deflateEnd              p_deflateEnd
106 #define deflate                 p_deflate
107 #define deflateInit_            p_deflateInit_
108 #endif /* ZLIB_SHARED */
109
110 struct zlib_state
111         {
112         z_stream istream;
113         z_stream ostream;
114         };
115
116 static int zlib_stateful_ex_idx = -1;
117
118 static void zlib_stateful_free_ex_data(void *obj, void *item,
119         CRYPTO_EX_DATA *ad, int ind,long argl, void *argp)
120         {
121         struct zlib_state *state = (struct zlib_state *)item;
122         inflateEnd(&state->istream);
123         deflateEnd(&state->ostream);
124         OPENSSL_free(state);
125         }
126
127 static int zlib_stateful_init(COMP_CTX *ctx)
128         {
129         int err;
130         struct zlib_state *state =
131                 (struct zlib_state *)OPENSSL_malloc(sizeof(struct zlib_state));
132
133         if (state == NULL)
134                 goto err;
135
136         state->istream.zalloc = Z_NULL;
137         state->istream.zfree = Z_NULL;
138         state->istream.opaque = Z_NULL;
139         state->istream.next_in = Z_NULL;
140         state->istream.next_out = Z_NULL;
141         state->istream.avail_in = 0;
142         state->istream.avail_out = 0;
143         err = inflateInit_(&state->istream,
144                 ZLIB_VERSION, sizeof(z_stream));
145         if (err != Z_OK)
146                 goto err;
147
148         state->ostream.zalloc = Z_NULL;
149         state->ostream.zfree = Z_NULL;
150         state->ostream.opaque = Z_NULL;
151         state->ostream.next_in = Z_NULL;
152         state->ostream.next_out = Z_NULL;
153         state->ostream.avail_in = 0;
154         state->ostream.avail_out = 0;
155         err = deflateInit_(&state->ostream,Z_DEFAULT_COMPRESSION,
156                 ZLIB_VERSION, sizeof(z_stream));
157         if (err != Z_OK)
158                 goto err;
159
160         CRYPTO_new_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
161         if (zlib_stateful_ex_idx == -1)
162                 {
163                 CRYPTO_w_lock(CRYPTO_LOCK_COMP);
164                 if (zlib_stateful_ex_idx == -1)
165                         zlib_stateful_ex_idx =
166                                 CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_COMP,
167                                         0,NULL,NULL,NULL,zlib_stateful_free_ex_data);
168                 CRYPTO_w_unlock(CRYPTO_LOCK_COMP);
169                 if (zlib_stateful_ex_idx == -1)
170                         goto err;
171                 }
172         CRYPTO_set_ex_data(&ctx->ex_data,zlib_stateful_ex_idx,state);
173         return 1;
174  err:
175         if (state) OPENSSL_free(state);
176         return 0;
177         }
178
179 static void zlib_stateful_finish(COMP_CTX *ctx)
180         {
181         CRYPTO_free_ex_data(CRYPTO_EX_INDEX_COMP,ctx,&ctx->ex_data);
182         }
183
184 static int zlib_stateful_compress_block(COMP_CTX *ctx, unsigned char *out,
185         unsigned int olen, unsigned char *in, unsigned int ilen)
186         {
187         int err = Z_OK;
188         struct zlib_state *state =
189                 (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
190                         zlib_stateful_ex_idx);
191
192         if (state == NULL)
193                 return -1;
194
195         state->ostream.next_in = in;
196         state->ostream.avail_in = ilen;
197         state->ostream.next_out = out;
198         state->ostream.avail_out = olen;
199         if (ilen > 0)
200                 err = deflate(&state->ostream, Z_SYNC_FLUSH);
201         if (err != Z_OK)
202                 return -1;
203 #ifdef DEBUG_ZLIB
204         fprintf(stderr,"compress(%4d)->%4d %s\n",
205                 ilen,olen - state->ostream.avail_out,
206                 (ilen != olen - state->ostream.avail_out)?"zlib":"clear");
207 #endif
208         return olen - state->ostream.avail_out;
209         }
210
211 static int zlib_stateful_expand_block(COMP_CTX *ctx, unsigned char *out,
212         unsigned int olen, unsigned char *in, unsigned int ilen)
213         {
214         int err = Z_OK;
215
216         struct zlib_state *state =
217                 (struct zlib_state *)CRYPTO_get_ex_data(&ctx->ex_data,
218                         zlib_stateful_ex_idx);
219
220         if (state == NULL)
221                 return 0;
222
223         state->istream.next_in = in;
224         state->istream.avail_in = ilen;
225         state->istream.next_out = out;
226         state->istream.avail_out = olen;
227         if (ilen > 0)
228                 err = inflate(&state->istream, Z_SYNC_FLUSH);
229         if (err != Z_OK)
230                 return -1;
231 #ifdef DEBUG_ZLIB
232         fprintf(stderr,"expand(%4d)->%4d %s\n",
233                 ilen,olen - state->istream.avail_out,
234                 (ilen != olen - state->istream.avail_out)?"zlib":"clear");
235 #endif
236         return olen - state->istream.avail_out;
237         }
238
239 #if 0
240 static int zlib_compress_block(COMP_CTX *ctx, unsigned char *out,
241         unsigned int olen, unsigned char *in, unsigned int ilen)
242         {
243         unsigned long l;
244         int i;
245         int clear=1;
246
247         if (ilen > 128)
248                 {
249                 out[0]=1;
250                 l=olen-1;
251                 i=compress(&(out[1]),&l,in,(unsigned long)ilen);
252                 if (i != Z_OK)
253                         return(-1);
254                 if (ilen > l)
255                         {
256                         clear=0;
257                         l++;
258                         }
259                 }
260         if (clear)
261                 {
262                 out[0]=0;
263                 memcpy(&(out[1]),in,ilen);
264                 l=ilen+1;
265                 }
266 #ifdef DEBUG_ZLIB
267         fprintf(stderr,"compress(%4d)->%4d %s\n",
268                 ilen,(int)l,(clear)?"clear":"zlib");
269 #endif
270         return((int)l);
271         }
272
273 static int zlib_expand_block(COMP_CTX *ctx, unsigned char *out,
274         unsigned int olen, unsigned char *in, unsigned int ilen)
275         {
276         unsigned long l;
277         int i;
278
279         if (in[0])
280                 {
281                 l=olen;
282                 i=zz_uncompress(out,&l,&(in[1]),(unsigned long)ilen-1);
283                 if (i != Z_OK)
284                         return(-1);
285                 }
286         else
287                 {
288                 memcpy(out,&(in[1]),ilen-1);
289                 l=ilen-1;
290                 }
291 #ifdef DEBUG_ZLIB
292         fprintf(stderr,"expand  (%4d)->%4d %s\n",
293                 ilen,(int)l,in[0]?"zlib":"clear");
294 #endif
295         return((int)l);
296         }
297
298 static int zz_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source,
299              uLong sourceLen)
300 {
301     z_stream stream;
302     int err;
303
304     stream.next_in = (Bytef*)source;
305     stream.avail_in = (uInt)sourceLen;
306     /* Check for source > 64K on 16-bit machine: */
307     if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
308
309     stream.next_out = dest;
310     stream.avail_out = (uInt)*destLen;
311     if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
312
313     stream.zalloc = (alloc_func)0;
314     stream.zfree = (free_func)0;
315
316     err = inflateInit_(&stream,
317             ZLIB_VERSION, sizeof(z_stream));
318     if (err != Z_OK) return err;
319
320     err = inflate(&stream, Z_FINISH);
321     if (err != Z_STREAM_END) {
322         inflateEnd(&stream);
323         return err;
324     }
325     *destLen = stream.total_out;
326
327     err = inflateEnd(&stream);
328     return err;
329 }
330 #endif
331
332 #endif
333
334 COMP_METHOD *COMP_zlib(void)
335         {
336         COMP_METHOD *meth = &zlib_method_nozlib;
337
338 #ifdef ZLIB_SHARED
339         if (!zlib_loaded)
340                 {
341 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
342                 zlib_dso = DSO_load(NULL, "ZLIB1", NULL, 0);
343 #else
344                 zlib_dso = DSO_load(NULL, "z", NULL, 0);
345 #endif
346                 if (zlib_dso != NULL)
347                         {
348                         p_compress
349                                 = (compress_ft) DSO_bind_func(zlib_dso,
350                                         "compress");
351                         p_inflateEnd
352                                 = (inflateEnd_ft) DSO_bind_func(zlib_dso,
353                                         "inflateEnd");
354                         p_inflate
355                                 = (inflate_ft) DSO_bind_func(zlib_dso,
356                                         "inflate");
357                         p_inflateInit_
358                                 = (inflateInit__ft) DSO_bind_func(zlib_dso,
359                                         "inflateInit_");
360                         p_deflateEnd
361                                 = (deflateEnd_ft) DSO_bind_func(zlib_dso,
362                                         "deflateEnd");
363                         p_deflate
364                                 = (deflate_ft) DSO_bind_func(zlib_dso,
365                                         "deflate");
366                         p_deflateInit_
367                                 = (deflateInit__ft) DSO_bind_func(zlib_dso,
368                                         "deflateInit_");
369
370                         if (p_compress && p_inflateEnd && p_inflate
371                                 && p_inflateInit_ && p_deflateEnd
372                                 && p_deflate && p_deflateInit_)
373                                 zlib_loaded++;
374                         }
375                 }
376
377 #endif
378 #ifdef ZLIB_SHARED
379         if (zlib_loaded)
380 #endif
381 #if defined(ZLIB) || defined(ZLIB_SHARED)
382                 meth = &zlib_stateful_method;
383 #endif
384
385         return(meth);
386         }
387