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