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