Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / crypto / external / bsd / netpgp / dist / src / lib / compress.c
blobcffd44f192aa0464c9917a1264aa0b901306db4b
1 /*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
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 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31 * All rights reserved.
32 * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33 * their moral rights under the UK Copyright Design and Patents Act 1988 to
34 * be recorded as the authors of this copyright work.
36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37 * use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 * http://www.apache.org/licenses/LICENSE-2.0
42 * Unless required by applicable law or agreed to in writing, software
43 * distributed under the License is distributed on an "AS IS" BASIS,
44 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
50 /** \file
52 #include "config.h"
54 #ifdef HAVE_SYS_CDEFS_H
55 #include <sys/cdefs.h>
56 #endif
58 #if defined(__NetBSD__)
59 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60 __RCSID("$NetBSD: compress.c,v 1.13 2009/10/04 21:58:25 agc Exp $");
61 #endif
63 #ifdef HAVE_ZLIB_H
64 #include <zlib.h>
65 #endif
67 #ifdef HAVE_BZLIB_H
68 #include <bzlib.h>
69 #endif
71 #include <string.h>
73 #include "packet-parse.h"
74 #include "errors.h"
75 #include "netpgpdefs.h"
76 #include "crypto.h"
77 #include "memory.h"
78 #include "writer.h"
80 #define DECOMPRESS_BUFFER 1024
82 typedef struct {
83 __ops_compression_type_t type;
84 __ops_region_t *region;
85 unsigned char in[DECOMPRESS_BUFFER];
86 unsigned char out[DECOMPRESS_BUFFER];
87 z_stream zstream;/* ZIP and ZLIB */
88 size_t offset;
89 int inflate_ret;
90 } z_decompress_t;
92 typedef struct {
93 __ops_compression_type_t type;
94 __ops_region_t *region;
95 char in[DECOMPRESS_BUFFER];
96 char out[DECOMPRESS_BUFFER];
97 bz_stream bzstream; /* BZIP2 */
98 size_t offset;
99 int inflate_ret;
100 } bz_decompress_t;
102 typedef struct {
103 z_stream stream;
104 unsigned char *src;
105 unsigned char *dst;
106 } compress_t;
109 * \todo remove code duplication between this and
110 * bzip2_compressed_data_reader
112 static int
113 zlib_compressed_data_reader(void *dest, size_t length,
114 __ops_error_t **errors,
115 __ops_reader_t *readinfo,
116 __ops_cbdata_t *cbinfo)
118 z_decompress_t *z = __ops_reader_get_arg(readinfo);
119 size_t len;
120 size_t cc;
121 char *cdest = dest;
123 if (z->type != OPS_C_ZIP && z->type != OPS_C_ZLIB) {
124 (void) fprintf(stderr,
125 "zlib_compressed_data_reader: weird type %d\n",
126 z->type);
127 return 0;
130 if (z->inflate_ret == Z_STREAM_END &&
131 z->zstream.next_out == &z->out[z->offset]) {
132 return 0;
135 if (__ops_get_debug_level(__FILE__)) {
136 (void) fprintf(stderr,
137 "zlib_compressed_data_reader: length %" PRIsize "d\n",
138 length);
141 if (z->region->readc == z->region->length) {
142 if (z->inflate_ret != Z_STREAM_END) {
143 OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,
144 "Compressed data didn't end when region ended.");
147 for (cc = 0 ; cc < length ; cc += len) {
148 if (&z->out[z->offset] == z->zstream.next_out) {
149 int ret;
151 z->zstream.next_out = z->out;
152 z->zstream.avail_out = sizeof(z->out);
153 z->offset = 0;
154 if (z->zstream.avail_in == 0) {
155 unsigned n = z->region->length;
157 if (!z->region->indeterminate) {
158 n -= z->region->readc;
159 if (n > sizeof(z->in)) {
160 n = sizeof(z->in);
162 } else {
163 n = sizeof(z->in);
165 if (!__ops_stacked_limited_read(z->in, n,
166 z->region,
167 errors, readinfo, cbinfo)) {
168 return -1;
171 z->zstream.next_in = z->in;
172 z->zstream.avail_in = (z->region->indeterminate) ?
173 z->region->last_read : n;
175 ret = inflate(&z->zstream, Z_SYNC_FLUSH);
176 if (ret == Z_STREAM_END) {
177 if (!z->region->indeterminate &&
178 z->region->readc != z->region->length) {
179 OPS_ERROR(cbinfo->errors,
180 OPS_E_P_DECOMPRESSION_ERROR,
181 "Compressed stream ended before packet end.");
183 } else if (ret != Z_OK) {
184 (void) fprintf(stderr, "ret=%d\n", ret);
185 OPS_ERROR(cbinfo->errors,
186 OPS_E_P_DECOMPRESSION_ERROR, z->zstream.msg);
188 z->inflate_ret = ret;
190 if (z->zstream.next_out <= &z->out[z->offset]) {
191 (void) fprintf(stderr, "Out of memory in buffer\n");
192 return 0;
194 len = (size_t)(z->zstream.next_out - &z->out[z->offset]);
195 if (len > length) {
196 len = length;
198 (void) memcpy(&cdest[cc], &z->out[z->offset], len);
199 z->offset += len;
202 return length;
205 /* \todo remove code duplication between this and zlib_compressed_data_reader */
206 static int
207 bzip2_compressed_data_reader(void *dest, size_t length,
208 __ops_error_t **errors,
209 __ops_reader_t *readinfo,
210 __ops_cbdata_t *cbinfo)
212 bz_decompress_t *bz = __ops_reader_get_arg(readinfo);
213 size_t len;
214 size_t cc;
215 char *cdest = dest;
217 if (bz->type != OPS_C_BZIP2) {
218 (void) fprintf(stderr, "Weird type %d\n", bz->type);
219 return 0;
222 if (bz->inflate_ret == BZ_STREAM_END &&
223 bz->bzstream.next_out == &bz->out[bz->offset]) {
224 return 0;
226 if (bz->region->readc == bz->region->length) {
227 if (bz->inflate_ret != BZ_STREAM_END) {
228 OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,
229 "Compressed data didn't end when region ended.");
232 for (cc = 0 ; cc < length ; cc += len) {
233 if (&bz->out[bz->offset] == bz->bzstream.next_out) {
234 int ret;
236 bz->bzstream.next_out = (char *) bz->out;
237 bz->bzstream.avail_out = sizeof(bz->out);
238 bz->offset = 0;
239 if (bz->bzstream.avail_in == 0) {
240 unsigned n = bz->region->length;
242 if (!bz->region->indeterminate) {
243 n -= bz->region->readc;
244 if (n > sizeof(bz->in))
245 n = sizeof(bz->in);
246 } else
247 n = sizeof(bz->in);
249 if (!__ops_stacked_limited_read(
250 (unsigned char *) bz->in,
251 n, bz->region,
252 errors, readinfo, cbinfo))
253 return -1;
255 bz->bzstream.next_in = bz->in;
256 bz->bzstream.avail_in =
257 (bz->region->indeterminate) ?
258 bz->region->last_read : n;
260 ret = BZ2_bzDecompress(&bz->bzstream);
261 if (ret == BZ_STREAM_END) {
262 if (!bz->region->indeterminate &&
263 bz->region->readc != bz->region->length)
264 OPS_ERROR(cbinfo->errors,
265 OPS_E_P_DECOMPRESSION_ERROR,
266 "Compressed stream ended before packet end.");
267 } else if (ret != BZ_OK) {
268 OPS_ERROR_1(cbinfo->errors,
269 OPS_E_P_DECOMPRESSION_ERROR,
270 "Invalid return %d from BZ2_bzDecompress", ret);
272 bz->inflate_ret = ret;
274 if (bz->bzstream.next_out <= &bz->out[bz->offset]) {
275 (void) fprintf(stderr, "Out of bz memroy\n");
276 return 0;
278 len = (size_t)(bz->bzstream.next_out - &bz->out[bz->offset]);
279 if (len > length) {
280 len = length;
282 (void) memcpy(&cdest[cc], &bz->out[bz->offset], len);
283 bz->offset += len;
286 return length;
290 * \ingroup Core_Compress
292 * \param *region Pointer to a region
293 * \param *stream How to parse
294 * \param type Which compression type to expect
297 int
298 __ops_decompress(__ops_region_t *region, __ops_stream_t *stream,
299 __ops_compression_type_t type)
301 z_decompress_t z;
302 bz_decompress_t bz;
303 const int printerrors = 1;
304 int ret;
306 switch (type) {
307 case OPS_C_ZIP:
308 case OPS_C_ZLIB:
309 (void) memset(&z, 0x0, sizeof(z));
311 z.region = region;
312 z.offset = 0;
313 z.type = type;
315 z.zstream.next_in = Z_NULL;
316 z.zstream.avail_in = 0;
317 z.zstream.next_out = z.out;
318 z.zstream.zalloc = Z_NULL;
319 z.zstream.zfree = Z_NULL;
320 z.zstream.opaque = Z_NULL;
322 break;
324 case OPS_C_BZIP2:
325 (void) memset(&bz, 0x0, sizeof(bz));
327 bz.region = region;
328 bz.offset = 0;
329 bz.type = type;
331 bz.bzstream.next_in = NULL;
332 bz.bzstream.avail_in = 0;
333 bz.bzstream.next_out = bz.out;
334 bz.bzstream.bzalloc = NULL;
335 bz.bzstream.bzfree = NULL;
336 bz.bzstream.opaque = NULL;
338 break;
340 default:
341 OPS_ERROR_1(&stream->errors,
342 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
343 "Compression algorithm %d is not yet supported", type);
344 return 0;
347 switch (type) {
348 case OPS_C_ZIP:
349 ret = inflateInit2(&z.zstream, -15);
350 break;
352 case OPS_C_ZLIB:
353 ret = inflateInit(&z.zstream);
354 break;
356 case OPS_C_BZIP2:
357 ret = BZ2_bzDecompressInit(&bz.bzstream, 1, 0);
358 break;
360 default:
361 OPS_ERROR_1(&stream->errors,
362 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
363 "Compression algorithm %d is not yet supported", type);
364 return 0;
367 switch (type) {
368 case OPS_C_ZIP:
369 case OPS_C_ZLIB:
370 if (ret != Z_OK) {
371 OPS_ERROR_1(&stream->errors,
372 OPS_E_P_DECOMPRESSION_ERROR,
373 "Cannot initialise ZIP or ZLIB stream for decompression: error=%d", ret);
374 return 0;
376 __ops_reader_push(stream, zlib_compressed_data_reader,
377 NULL, &z);
378 break;
380 case OPS_C_BZIP2:
381 if (ret != BZ_OK) {
382 OPS_ERROR_1(&stream->errors,
383 OPS_E_P_DECOMPRESSION_ERROR,
384 "Cannot initialise BZIP2 stream for decompression: error=%d", ret);
385 return 0;
387 __ops_reader_push(stream, bzip2_compressed_data_reader,
388 NULL, &bz);
389 break;
391 default:
392 OPS_ERROR_1(&stream->errors,
393 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
394 "Compression algorithm %d is not yet supported", type);
395 return 0;
398 ret = __ops_parse(stream, !printerrors);
400 __ops_reader_pop(stream);
402 return ret;
406 \ingroup Core_WritePackets
407 \brief Writes Compressed packet
408 \param data Data to write out
409 \param len Length of data
410 \param output Write settings
411 \return 1 if OK; else 0
414 unsigned
415 __ops_writez(const unsigned char *data,
416 const unsigned int len,
417 __ops_output_t *out)
419 compress_t *zip;
420 size_t sz_in;
421 size_t sz_out;
422 int ret;
423 int r = 0;
425 /* compress the data */
426 const int level = Z_DEFAULT_COMPRESSION; /* \todo allow varying
427 * levels */
429 if ((zip = calloc(1, sizeof(*zip))) == NULL) {
430 (void) fprintf(stderr, "__ops_writez: bad alloc\n");
431 return 0;
433 zip->stream.zalloc = Z_NULL;
434 zip->stream.zfree = Z_NULL;
435 zip->stream.opaque = NULL;
437 /* all other fields set to zero by use of calloc */
439 if (deflateInit(&zip->stream, level) != Z_OK) {
440 (void) fprintf(stderr, "__ops_writez: can't initialise\n");
441 return 0;
443 /* do necessary transformation */
444 /* copy input to maintain const'ness of src */
445 if (zip->src != NULL || zip->dst != NULL) {
446 (void) fprintf(stderr, "__ops_writez: non-null streams\n");
447 return 0;
450 sz_in = len * sizeof(unsigned char);
451 sz_out = ((101 * sz_in) / 100) + 12; /* from zlib webpage */
452 if ((zip->src = calloc(1, sz_in)) == NULL) {
453 free(zip);
454 (void) fprintf(stderr, "__ops_writez: bad alloc2\n");
455 return 0;
457 if ((zip->dst = calloc(1, sz_out)) == NULL) {
458 free(zip->src);
459 free(zip);
460 (void) fprintf(stderr, "__ops_writez: bad alloc3\n");
461 return 0;
463 (void) memcpy(zip->src, data, len);
465 /* setup stream */
466 zip->stream.next_in = zip->src;
467 zip->stream.avail_in = sz_in;
468 zip->stream.total_in = 0;
470 zip->stream.next_out = zip->dst;
471 zip->stream.avail_out = sz_out;
472 zip->stream.total_out = 0;
474 do {
475 r = deflate(&zip->stream, Z_FINISH);
476 } while (r != Z_STREAM_END);
478 /* write it out */
479 ret = __ops_write_ptag(out, OPS_PTAG_CT_COMPRESSED) &&
480 __ops_write_length(out, (unsigned)(zip->stream.total_out + 1))&&
481 __ops_write_scalar(out, OPS_C_ZLIB, 1) &&
482 __ops_write(out, zip->dst, (unsigned)zip->stream.total_out);
484 free(zip->src);
485 free(zip->dst);
486 free(zip);
487 return ret;