deflate.c revision 1.19 1 /* $NetBSD: deflate.c,v 1.19 2011/02/24 20:03:41 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.19 2011/02/24 20:03:41 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 int size_hint)
76 {
77 /* decomp indicates whether we compress (0) or decompress (1) */
78
79 z_stream zbuf;
80 u_int8_t *output;
81 u_int32_t count, result, tocopy;
82 int error, i, j;
83 struct deflate_buf buf[ZBUF];
84
85 DPRINTF(("deflate_global: size %d\n", size));
86
87 memset(&zbuf, 0, sizeof(z_stream));
88 zbuf.next_in = data; /* data that is going to be processed */
89 zbuf.zalloc = ocf_zalloc;
90 zbuf.zfree = ocf_zfree;
91 zbuf.opaque = Z_NULL;
92 zbuf.avail_in = size; /* Total length of data to be processed */
93
94 if (!decomp) {
95 buf[0].size = size;
96 } else {
97 /*
98 * Choose a buffer with 4x the size of the input buffer
99 * for the size of the output buffer in the case of
100 * decompression. If it's not sufficient, it will need to be
101 * updated while the decompression is going on
102 */
103
104 buf[0].size = MAX(size * 4, size_hint);
105 }
106 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT);
107 if (buf[0].out == NULL)
108 return 0;
109 i = 1;
110
111 zbuf.next_out = buf[0].out;
112 zbuf.avail_out = buf[0].size;
113
114 error = decomp ? inflateInit2(&zbuf, window_inflate) :
115 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
116 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
117
118 if (error != Z_OK)
119 goto bad2;
120 for (;;) {
121 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
122 deflate(&zbuf, Z_FINISH);
123 if (error == Z_STREAM_END) /* success */
124 break;
125 /*
126 * XXX compensate for two problems:
127 * -Former versions of this code didn't set Z_FINISH
128 * on compression, so the compressed data are not correctly
129 * terminated and the decompressor doesn't get Z_STREAM_END.
130 * Accept such packets for interoperability.
131 * -sys/net/zlib.c has a bug which makes that Z_BUF_ERROR is
132 * set after successful decompression under rare conditions.
133 */
134 else if (decomp && (error == Z_OK || error == Z_BUF_ERROR)
135 && zbuf.avail_in == 0 && zbuf.avail_out != 0)
136 break;
137 else if (error != Z_OK)
138 goto bad;
139 else if (zbuf.avail_out == 0) {
140 /* we need more output space, allocate size */
141 int nextsize = buf[i-1].size * 2;
142 if (i == ZBUF || nextsize > 1000000)
143 goto bad;
144 buf[i].out = malloc(nextsize, M_CRYPTO_DATA, M_NOWAIT);
145 if (buf[i].out == NULL)
146 goto bad;
147 zbuf.next_out = buf[i].out;
148 zbuf.avail_out = buf[i].size = nextsize;
149 i++;
150 }
151 }
152
153 result = count = zbuf.total_out;
154
155 if (i != 1) { /* copy everything into one buffer */
156 output = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
157 if (output == NULL)
158 goto bad;
159 *out = output;
160 for (j = 0; j < i; j++) {
161 tocopy = MIN(count, buf[j].size);
162 /* XXX the last buf can be empty */
163 KASSERT(tocopy || j == (i - 1));
164 memcpy(output, buf[j].out, tocopy);
165 output += tocopy;
166 free(buf[j].out, M_CRYPTO_DATA);
167 count -= tocopy;
168 }
169 KASSERT(count == 0);
170 } else {
171 *out = buf[0].out;
172 }
173 if (decomp)
174 inflateEnd(&zbuf);
175 else
176 deflateEnd(&zbuf);
177 return result;
178
179 bad:
180 if (decomp)
181 inflateEnd(&zbuf);
182 else
183 deflateEnd(&zbuf);
184 bad2:
185 for (j = 0; j < i; j++)
186 free(buf[j].out, M_CRYPTO_DATA);
187 return 0;
188 }
189
190 /*
191 * Initial version will perform a single gzip encapsulation,
192 * filling in the header,
193 * and appending the crc and uncompressed length.
194 *
195 * Later version will support multiple buffers with
196 * a flag indication final buffer. The crc is maintained
197 * over all buffers and appended to the output along with
198 * the uncompressed length after the final data buffer
199 * has been compressed and output.
200 *
201 * Ditto for uncompress - CRC is extracted from the final packed
202 * and compared against CRC of uncompressed data.
203 *
204 */
205
206 /* constant header for the gzip */
207 static const char gzip_header[10] = {
208 0x1f, 0x8b, /* ID1 ID2 */
209 Z_DEFLATED, /* CM */
210 0, /* FLG */
211 0, 0, 0, 0, /* MTIME */
212 0, /* XFL */
213 0x03 /* OS (Unix) */
214 };
215
216 /* Followed by compressed payload */
217 /* Followed by uint32_t CRC32 and uint32_t ISIZE */
218 #define GZIP_TAIL_SIZE 8
219
220 u_int32_t
221 gzip_global(u_int8_t *data, u_int32_t size,
222 int decomp, u_int8_t **out, int size_hint)
223 {
224 /* decomp indicates whether we compress (0) or decompress (1) */
225 z_stream zbuf;
226 u_int8_t *output;
227 u_int32_t count, result;
228 int error, i = 0, j;
229 struct deflate_buf *buf, *tmp;
230 size_t nbufs;
231 u_int32_t crc;
232 u_int32_t isize, icrc;
233
234 DPRINTF(("gzip_global: decomp %d, size %d\n", decomp, size));
235
236 nbufs = ZBUF;
237 buf = malloc(nbufs*sizeof(struct deflate_buf), M_CRYPTO_DATA, M_NOWAIT);
238 if (buf == NULL) {
239 DPRINTF(("gzip_global.%d: failed to malloc %d\n",
240 __LINE__, nbufs*sizeof(struct deflate_buf)));
241 return 0;
242 }
243
244 memset(&zbuf, 0, sizeof(z_stream));
245 zbuf.zalloc = ocf_zalloc;
246 zbuf.zfree = ocf_zfree;
247 zbuf.opaque = Z_NULL;
248
249 crc = crc32(0, NULL, 0); /* get initial crc value */
250
251 zbuf.avail_in = size; /* Total length of data to be processed */
252 zbuf.next_in = data; /* data that is going to be processed */
253
254 if (!decomp) {
255 /* compress */
256 DPRINTF(("gzip_global: compress[%d] malloc %d + %d + %d = %d\n",
257 i, size, sizeof(gzip_header), GZIP_TAIL_SIZE,
258 size + sizeof(gzip_header) + GZIP_TAIL_SIZE));
259
260 buf[0].size = size;
261
262 crc = crc32(crc, data, size);
263 DPRINTF(("gzip_compress: size %d, crc 0x%x\n", size, crc));
264 } else {
265 /* decompress */
266 /* check the gzip header */
267 if (zbuf.avail_in <= 0) {
268 /* Not enough data for the header & tail */
269 DPRINTF(("gzip_global: not enough data (%d)\n",
270 size));
271 goto bad2;
272 }
273
274 /* XXX this is pretty basic,
275 * needs to be expanded to ignore MTIME, OS,
276 * but still ensure flags are 0.
277 * Q. Do we need to support the flags and
278 * optional header fields? Likely.
279 * XXX add flag and field support too.
280 */
281 if (memcmp(data, gzip_header, sizeof(gzip_header)) != 0) {
282 DPRINTF(("gzip_global: unsupported gzip header (%02x%02x)\n",
283 data[0], data[1]));
284 goto bad2;
285 } else {
286 DPRINTF(("gzip_global.%d: gzip header ok\n",__LINE__));
287 }
288
289 memcpy(&isize, &data[size-sizeof(uint32_t)], sizeof(uint32_t));
290 LE32TOH(isize);
291 memcpy(&icrc, &data[size-2*sizeof(uint32_t)], sizeof(uint32_t));
292 LE32TOH(icrc);
293
294 DPRINTF(("gzip_global: isize = %d (%02x %02x %02x %02x)\n",
295 isize,
296 data[size-4],
297 data[size-3],
298 data[size-2],
299 data[size-1]));
300
301 buf[0].size = isize;
302
303 /* skip over the gzip header */
304 zbuf.next_in = data + sizeof(gzip_header);
305
306 /* actual payload size stripped of gzip header and tail */
307 zbuf.avail_in = size - sizeof(gzip_header) - GZIP_TAIL_SIZE;
308 }
309
310 buf[0].out = malloc(buf[0].size, M_CRYPTO_DATA, M_NOWAIT);
311 if (buf[0].out == NULL)
312 goto bad2;
313 zbuf.next_out = buf[0].out;
314 zbuf.avail_out = buf[0].size;
315 DPRINTF(("zbuf avail_in %d, avail_out %d\n",
316 zbuf.avail_in, zbuf.avail_out));
317 i = 1;
318
319 error = decomp ? inflateInit2(&zbuf, window_inflate) :
320 deflateInit2(&zbuf, Z_DEFAULT_COMPRESSION, Z_METHOD,
321 window_deflate, Z_MEMLEVEL, Z_DEFAULT_STRATEGY);
322
323 if (error != Z_OK) {
324 printf("deflateInit2() failed\n");
325 goto bad;
326 }
327 for (;;) {
328 DPRINTF(("pre: %s in:%d out:%d\n", decomp ? "deflate()" : "inflate()",
329 zbuf.avail_in, zbuf.avail_out));
330 error = decomp ? inflate(&zbuf, Z_SYNC_FLUSH) :
331 deflate(&zbuf, Z_FINISH);
332 DPRINTF(("post: %s in:%d out:%d\n", decomp ? "deflate()" : "inflate()",
333 zbuf.avail_in, zbuf.avail_out));
334 if (error != Z_OK && error != Z_STREAM_END) {
335 printf("deflate() or inflate() failed, error=%d\n", error);
336 goto bad;
337 } else if (zbuf.avail_in == 0 && zbuf.avail_out != 0) {
338 DPRINTF(("gzip_global: avail_in == 0, ending\n"));
339 goto end;
340 } else if (zbuf.avail_in == 0 && zbuf.avail_out == 0) {
341 DPRINTF(("gzip_global: avail_in == 0, avail_out == 0, ending\n"));
342 goto end;
343 } else if (zbuf.avail_out == 0) {
344 if (i == nbufs) {
345 nbufs += ZBUF;
346 tmp = realloc(buf,nbufs*sizeof(struct deflate_buf),
347 M_CRYPTO_DATA, M_NOWAIT);
348 if (tmp == NULL)
349 goto bad;
350 buf = tmp;
351 }
352 /* we need more output space, allocate size */
353 buf[i].out = malloc(size, M_CRYPTO_DATA, M_NOWAIT);
354 if (buf[i].out == NULL)
355 goto bad;
356 zbuf.next_out = buf[i].out;
357 buf[i].size = size;
358 zbuf.avail_out = buf[i].size;
359 i++;
360 } else
361 goto bad;
362 }
363
364 end:
365 if (decomp) {
366 count = result = zbuf.total_out;
367 } else {
368 /* need room for header, CRC, and ISIZE */
369 result = zbuf.total_out + sizeof(gzip_header) + GZIP_TAIL_SIZE;
370 count = zbuf.total_out;
371 }
372
373 DPRINTF(("gzip_global: in %d -> out %d\n", size, result));
374
375 *out = malloc(result, M_CRYPTO_DATA, M_NOWAIT);
376 if (*out == NULL)
377 goto bad;
378 output = *out;
379 if (decomp)
380 inflateEnd(&zbuf);
381 else {
382 deflateEnd(&zbuf);
383
384 /* fill in gzip header */
385 memcpy(output, gzip_header, sizeof(gzip_header));
386 output += sizeof(gzip_header);
387 }
388 for (j = 0; j < i; j++) {
389 if (decomp) {
390 /* update crc for decompressed data */
391 crc = crc32(crc, buf[j].out, MIN(count, buf[j].size));
392 }
393 if (count > buf[j].size) {
394 memcpy(output, buf[j].out, buf[j].size);
395 output += buf[j].size;
396 free(buf[j].out, M_CRYPTO_DATA);
397 count -= buf[j].size;
398 } else {
399 /* it should be the last buffer */
400 memcpy(output, buf[j].out, count);
401 output += count;
402 free(buf[j].out, M_CRYPTO_DATA);
403 count = 0;
404 }
405 }
406 free(buf, M_CRYPTO_DATA);
407
408 if (!decomp) {
409 /* fill in CRC and ISIZE */
410 HTOLE32(crc);
411 memcpy(output, &crc, sizeof(uint32_t));
412 HTOLE32(size);
413 memcpy(output + sizeof(uint32_t), &size, sizeof(uint32_t));
414
415 DPRINTF(("gzip_global: size = 0x%x (%02x %02x %02x %02x)\n",
416 size,
417 output[7],
418 output[3],
419 output[5],
420 output[4]));
421 } else {
422 if (crc != icrc || result != isize) {
423 free(*out, M_CRYPTO_DATA);
424 *out = NULL;
425 return 0;
426 }
427 }
428
429 return result;
430
431 bad:
432 if (decomp)
433 inflateEnd(&zbuf);
434 else
435 deflateEnd(&zbuf);
436 bad2:
437 *out = NULL;
438 for (j = 0; j < i; j++)
439 free(buf[j].out, M_CRYPTO_DATA);
440 free(buf, M_CRYPTO_DATA);
441 return 0;
442 }
443