deflate.c revision 1.16 1 /* $NetBSD: deflate.c,v 1.16 2011/02/17 17:10:18 drochner Exp $ */
2 /* $FreeBSD: src/sys/opencrypto/deflate.c,v 1.1.2.1 2002/11/21 23:34:23 sam Exp $ */
3 /* $OpenBSD: deflate.c,v 1.3 2001/08/20 02:45:22 hugh Exp $ */
4
5 /*
6 * Copyright (c) 2001 Jean-Jacques Bernard-Gundol (jj (at) wabbitt.org)
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 /*
33 * This file contains a wrapper around the deflate algo compression
34 * functions using the zlib library (see net/zlib.{c,h})
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: deflate.c,v 1.16 2011/02/17 17:10:18 drochner Exp $");
39
40 #include <sys/types.h>
41 #include <sys/malloc.h>
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <net/zlib.h>
45
46 #include <opencrypto/cryptodev.h>
47 #include <opencrypto/deflate.h>
48
49
50 int window_inflate = -1 * MAX_WBITS;
51 int window_deflate = -12;
52
53 /*
54 * This function takes a block of data and (de)compress it using the deflate
55 * algorithm
56 */
57
58 static void *
59 ocf_zalloc(void *nil, u_int type, u_int size)
60 {
61 void *ptr;
62
63 ptr = malloc(type *size, M_CRYPTO_DATA, M_NOWAIT);
64 return ptr;
65 }
66
67 static void
68 ocf_zfree(void *nil, void *ptr)
69 {
70 free(ptr, M_CRYPTO_DATA);
71 }
72
73 u_int32_t
74 deflate_global(u_int8_t *data, u_int32_t size, int decomp, u_int8_t **out)
75 {
76 /* decomp indicates whether we compress (0) or decompress (1) */
77
78 z_stream zbuf;
79 u_int8_t *output;
80 u_int32_t count, result, tocopy;
81 int error, i, j;
82 struct deflate_buf *buf, *tmp;
83 size_t len;
84
85 DPRINTF(("deflate_global: size %d\n", size));
86
87 len = ZBUF;
88 buf = malloc(len*sizeof(struct deflate_buf), M_CRYPTO_DATA, M_NOWAIT);
89 if (buf == NULL)
90 return 0;
91
92 memset(&zbuf, 0, sizeof(z_stream));
93 zbuf.next_in = data; /* data that is going to be processed */
94 zbuf.zalloc = ocf_zalloc;
95 zbuf.zfree = ocf_zfree;
96 zbuf.opaque = Z_NULL;
97 zbuf.avail_in = size; /* Total length of data to be processed */
98
99 if (!decomp) {
100 buf[0].size = size;
101 } else {
102 /*
103 * Choose a buffer with 4x the size of the input buffer
104 * for the size of the output buffer in the case of
105 * decompression. If it's not sufficient, it will need to be
106 * updated while the decompression is going on
107 */
108
109 buf[0].size = size * 4;
110 }
111 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT);
112 if (buf[0].out == NULL)
113 goto bad3;
114 i = 1;
115
116 zbuf.next_out = buf[0].out;
117 zbuf.avail_out = buf[0].size;
118
119 error = decomp ? inflateInit2(&zbuf, window_inflate) :
120 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
121 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
122
123 if (error != Z_OK)
124 goto bad2;
125 for (;;) {
126 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
127 deflate(&zbuf, Z_FINISH);
128 if (error == Z_STREAM_END) /* success */
129 break;
130 /*
131 * XXX compensate for two problems:
132 * -Former versions of this code didn't set Z_FINISH
133 * on compression, so the compressed data are not correctly
134 * terminated and the decompressor doesn't get Z_STREAM_END.
135 * Accept such packets for interoperability.
136 * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is
137 * set after successful decompression under rare conditions.
138 */
139 else if (decomp && (error == Z_OK || error == Z_BUF_ERROR)
140 && zbuf.avail_in == 0 && zbuf.avail_out != 0)
141 break;
142 else if (error != Z_OK)
143 goto bad;
144 else if (zbuf.avail_out == 0) {
145 if (i == len) {
146 len += ZBUF;
147 tmp = realloc(buf,len*sizeof(struct deflate_buf),
148 M_CRYPTO_DATA, M_NOWAIT);
149 if (tmp == NULL)
150 goto bad;
151 buf = tmp;
152 }
153 /* we need more output space, allocate size */
154 buf[i].out = malloc(size, M_CRYPTO_DATA, M_NOWAIT);
155 if (buf[i].out == NULL)
156 goto bad;
157 zbuf.next_out = buf[i].out;
158 buf[i].size = size;
159 zbuf.avail_out = buf[i].size;
160 i++;
161 }
162 }
163
164 result = count = zbuf.total_out;
165
166 if (i != 1) { /* copy everything into one buffer */
167 output = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
168 if (output == NULL)
169 goto bad;
170 *out = output;
171 for (j = 0; j < i; j++) {
172 tocopy = MIN(count, buf[j].size);
173 /* XXX the last buf can be empty */
174 KASSERT(tocopy || j == (i - 1));
175 memcpy(output, buf[j].out, tocopy);
176 output += tocopy;
177 free(buf[j].out, M_CRYPTO_DATA);
178 count -= tocopy;
179 }
180 KASSERT(count == 0);
181 } else {
182 *out = buf[0].out;
183 }
184 free(buf, M_CRYPTO_DATA);
185 if (decomp)
186 inflateEnd(&zbuf);
187 else
188 deflateEnd(&zbuf);
189 return result;
190
191 bad:
192 if (decomp)
193 inflateEnd(&zbuf);
194 else
195 deflateEnd(&zbuf);
196 bad2:
197 for (j = 0; j < i; j++)
198 free(buf[j].out, M_CRYPTO_DATA);
199 bad3:
200 free(buf, M_CRYPTO_DATA);
201 return 0;
202 }
203
204 /*
205 * Initial version will perform a single gzip encapsulation,
206 * filling in the header,
207 * and appending the crc and uncompressed length.
208 *
209 * Later version will support multiple buffers with
210 * a flag indication final buffer. The crc is maintained
211 * over all buffers and appended to the output along with
212 * the uncompressed length after the final data buffer
213 * has been compressed and output.
214 *
215 * Ditto for uncompress - CRC is extracted from the final packed
216 * and compared against CRC of uncompressed data.
217 *
218 */
219
220 /* constant header for the gzip */
221 static const char gzip_header[10] = {
222 0x1f, 0x8b, /* ID1 ID2 */
223 Z_DEFLATED, /* CM */
224 0, /* FLG */
225 0, 0, 0, 0, /* MTIME */
226 0, /* XFL */
227 0x03 /* OS (Unix) */
228 };
229
230 /* Followed by compressed payload */
231 /* Followed by uint32_t CRC32 and uint32_t ISIZE */
232 #define GZIP_TAIL_SIZE 8
233
234 u_int32_t
235 gzip_global(u_int8_t *data, u_int32_t size,
236 int decomp, u_int8_t **out)
237 {
238 /* decomp indicates whether we compress (0) or decompress (1) */
239 z_stream zbuf;
240 u_int8_t *output;
241 u_int32_t count, result;
242 int error, i = 0, j;
243 struct deflate_buf *buf, *tmp;
244 size_t nbufs;
245 u_int32_t crc;
246 u_int32_t isize;
247
248 DPRINTF(("gzip_global: decomp %d, size %d\n", decomp, size));
249
250 nbufs = ZBUF;
251 buf = malloc(nbufs*sizeof(struct deflate_buf), M_CRYPTO_DATA, M_NOWAIT);
252 if (buf == NULL) {
253 DPRINTF(("gzip_global.%d: failed to malloc %d\n",
254 __LINE__, nbufs*sizeof(struct deflate_buf)));
255 return 0;
256 }
257
258 memset(&zbuf, 0, sizeof(z_stream));
259 zbuf.zalloc = ocf_zalloc;
260 zbuf.zfree = ocf_zfree;
261 zbuf.opaque = Z_NULL;
262
263 crc = crc32(0, NULL, 0); /* get initial crc value */
264
265 zbuf.avail_in = size; /* Total length of data to be processed */
266 zbuf.next_in = data; /* data that is going to be processed */
267
268 if (!decomp) {
269 /* compress */
270 DPRINTF(("gzip_global: compress[%d] malloc %d + %d + %d = %d\n",
271 i, size, sizeof(gzip_header), GZIP_TAIL_SIZE,
272 size + sizeof(gzip_header) + GZIP_TAIL_SIZE));
273
274 buf[0].size = size;
275
276 crc = crc32(crc, data, size);
277 DPRINTF(("gzip_compress: size %d, crc 0x%x\n", size, crc));
278 } else {
279 /* decompress */
280 /* check the gzip header */
281 if (zbuf.avail_in <= 0) {
282 /* Not enough data for the header & tail */
283 DPRINTF(("gzip_global: not enough data (%d)\n",
284 size));
285 goto bad2;
286 }
287
288 /* XXX this is pretty basic,
289 * needs to be expanded to ignore MTIME, OS,
290 * but still ensure flags are 0.
291 * Q. Do we need to support the flags and
292 * optional header fields? Likely.
293 * XXX add flag and field support too.
294 */
295 if (memcmp(data, gzip_header, sizeof(gzip_header)) != 0) {
296 DPRINTF(("gzip_global: unsupported gzip header (%02x%02x)\n",
297 data[0], data[1]));
298 goto bad2;
299 } else {
300 DPRINTF(("gzip_global.%d: gzip header ok\n",__LINE__));
301 }
302
303 isize = *((uint32_t *)&data[size-sizeof(uint32_t)]);
304
305 DPRINTF(("gzip_global: isize = %d (%02x %02x %02x %02x)\n",
306 isize,
307 data[size-4],
308 data[size-3],
309 data[size-2],
310 data[size-1]));
311
312 buf[0].size = isize;
313
314 /* skip over the gzip header */
315 zbuf.next_in = data + sizeof(gzip_header);
316
317 /* actual payload size stripped of gzip header and tail */
318 zbuf.avail_in = size - sizeof(gzip_header) - GZIP_TAIL_SIZE;
319 }
320
321 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT);
322 if (buf[0].out == NULL)
323 goto bad2;
324 zbuf.next_out = buf[0].out;
325 zbuf.avail_out = buf[0].size;
326 DPRINTF(("zbuf avail_in %d, avail_out %d\n",
327 zbuf.avail_in, zbuf.avail_out));
328 i = 1;
329
330 error = decomp ? inflateInit2(&zbuf, window_inflate) :
331 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
332 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
333
334 if (error != Z_OK) {
335 printf("deflateInit2() failed\n");
336 goto bad;
337 }
338 for (;;) {
339 DPRINTF(("pre: %s in:%d out:%d\n", decomp ? "deflate()" : "inflate()",
340 zbuf.avail_in, zbuf.avail_out));
341 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
342 deflate(&zbuf, Z_FINISH);
343 DPRINTF(("post: %s in:%d out:%d\n", decomp ? "deflate()" : "inflate()",
344 zbuf.avail_in, zbuf.avail_out));
345 if (error != Z_OK && error != Z_STREAM_END) {
346 printf("deflate() or inflate() failed, error=%d\n", error);
347 goto bad;
348 } else if (zbuf.avail_in == 0 && zbuf.avail_out != 0) {
349 DPRINTF(("gzip_global: avail_in == 0, ending\n"));
350 goto end;
351 } else if (zbuf.avail_in == 0 && zbuf.avail_out == 0) {
352 DPRINTF(("gzip_global: avail_in == 0, avail_out == 0, ending\n"));
353 goto end;
354 } else if (zbuf.avail_out == 0) {
355 if (i == nbufs) {
356 nbufs += ZBUF;
357 tmp = realloc(buf,nbufs*sizeof(struct deflate_buf),
358 M_CRYPTO_DATA, M_NOWAIT);
359 if (tmp == NULL)
360 goto bad;
361 buf = tmp;
362 }
363 /* we need more output space, allocate size */
364 buf[i].out = malloc(size, M_CRYPTO_DATA, M_NOWAIT);
365 if (buf[i].out == NULL)
366 goto bad;
367 zbuf.next_out = buf[i].out;
368 buf[i].size = size;
369 zbuf.avail_out = buf[i].size;
370 i++;
371 } else
372 goto bad;
373 }
374
375 end:
376 if (decomp) {
377 count = result = zbuf.total_out;
378 } else {
379 /* need room for header, CRC, and ISIZE */
380 result = zbuf.total_out + sizeof(gzip_header) + GZIP_TAIL_SIZE;
381 count = zbuf.total_out;
382 }
383
384 DPRINTF(("gzip_global: in %d -> out %d\n", size, result));
385
386 *out = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
387 if (*out == NULL)
388 goto bad;
389 output = *out;
390 if (decomp)
391 inflateEnd(&zbuf);
392 else {
393 deflateEnd(&zbuf);
394
395 /* fill in gzip header */
396 memcpy(output, gzip_header, sizeof(gzip_header));
397 output += sizeof(gzip_header);
398 }
399 for (j = 0; j < i; j++) {
400 if (decomp) {
401 /* update crc for decompressed data */
402 crc = crc32(crc, buf[j].out, buf[j].size);
403 }
404 if (count > buf[j].size) {
405 memcpy(output, buf[j].out, buf[j].size);
406 output += buf[j].size;
407 free(buf[j].out, M_CRYPTO_DATA);
408 count -= buf[j].size;
409 } else {
410 /* it should be the last buffer */
411 memcpy(output, buf[j].out, count);
412 output += count;
413 free(buf[j].out, M_CRYPTO_DATA);
414 count = 0;
415 }
416 }
417 free(buf, M_CRYPTO_DATA);
418
419 if (!decomp) {
420 /* fill in CRC and ISIZE */
421 ((uint32_t *)output)[0] = crc;
422 ((uint32_t *)output)[1] = size;
423
424 DPRINTF(("gzip_global: size = 0x%x (%02x %02x %02x %02x)\n",
425 size,
426 output[7],
427 output[3],
428 output[5],
429 output[4]));
430 }
431
432 return result;
433
434 bad:
435 if (decomp)
436 inflateEnd(&zbuf);
437 else
438 deflateEnd(&zbuf);
439 bad2:
440 *out = NULL;
441 for (j = 0; j < i; j++)
442 free(buf[j].out, M_CRYPTO_DATA);
443 free(buf, M_CRYPTO_DATA);
444 return 0;
445 }
446