xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/compress.c (revision 69d4f30f789bba62f419ef0c761a3970b87fb8b1)
12232f800Sagc /*-
22232f800Sagc  * Copyright (c) 2009 The NetBSD Foundation, Inc.
32232f800Sagc  * All rights reserved.
42232f800Sagc  *
52232f800Sagc  * This code is derived from software contributed to The NetBSD Foundation
62232f800Sagc  * by Alistair Crooks (agc@NetBSD.org)
72232f800Sagc  *
82232f800Sagc  * Redistribution and use in source and binary forms, with or without
92232f800Sagc  * modification, are permitted provided that the following conditions
102232f800Sagc  * are met:
112232f800Sagc  * 1. Redistributions of source code must retain the above copyright
122232f800Sagc  *    notice, this list of conditions and the following disclaimer.
132232f800Sagc  * 2. Redistributions in binary form must reproduce the above copyright
142232f800Sagc  *    notice, this list of conditions and the following disclaimer in the
152232f800Sagc  *    documentation and/or other materials provided with the distribution.
162232f800Sagc  *
172232f800Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182232f800Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192232f800Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202232f800Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212232f800Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222232f800Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232232f800Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242232f800Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252232f800Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262232f800Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272232f800Sagc  * POSSIBILITY OF SUCH DAMAGE.
282232f800Sagc  */
2993bf6008Sagc /*
3093bf6008Sagc  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3193bf6008Sagc  * All rights reserved.
3293bf6008Sagc  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
3393bf6008Sagc  * their moral rights under the UK Copyright Design and Patents Act 1988 to
3493bf6008Sagc  * be recorded as the authors of this copyright work.
3593bf6008Sagc  *
3693bf6008Sagc  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3793bf6008Sagc  * use this file except in compliance with the License.
3893bf6008Sagc  *
3993bf6008Sagc  * You may obtain a copy of the License at
4093bf6008Sagc  *     http://www.apache.org/licenses/LICENSE-2.0
4193bf6008Sagc  *
4293bf6008Sagc  * Unless required by applicable law or agreed to in writing, software
4393bf6008Sagc  * distributed under the License is distributed on an "AS IS" BASIS,
4493bf6008Sagc  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4593bf6008Sagc  *
4693bf6008Sagc  * See the License for the specific language governing permissions and
4793bf6008Sagc  * limitations under the License.
4893bf6008Sagc  */
4993bf6008Sagc 
5093bf6008Sagc /** \file
5193bf6008Sagc  */
5293bf6008Sagc #include "config.h"
5393bf6008Sagc 
5457324b9fSagc #ifdef HAVE_SYS_CDEFS_H
5557324b9fSagc #include <sys/cdefs.h>
5657324b9fSagc #endif
5757324b9fSagc 
5857324b9fSagc #if defined(__NetBSD__)
5957324b9fSagc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60*69d4f30fSagc __RCSID("$NetBSD: compress.c,v 1.16 2010/08/15 07:52:26 agc Exp $");
6157324b9fSagc #endif
6257324b9fSagc 
6393bf6008Sagc #ifdef HAVE_ZLIB_H
6493bf6008Sagc #include <zlib.h>
6593bf6008Sagc #endif
6693bf6008Sagc 
6793bf6008Sagc #ifdef HAVE_BZLIB_H
6893bf6008Sagc #include <bzlib.h>
6993bf6008Sagc #endif
7093bf6008Sagc 
7193bf6008Sagc #include <string.h>
7293bf6008Sagc 
7393bf6008Sagc #include "packet-parse.h"
7493bf6008Sagc #include "errors.h"
7593bf6008Sagc #include "netpgpdefs.h"
764b3a3e18Sagc #include "crypto.h"
7793bf6008Sagc #include "memory.h"
78efdd9dbaSagc #include "writer.h"
7993bf6008Sagc 
8093bf6008Sagc #define DECOMPRESS_BUFFER	1024
8193bf6008Sagc 
8293bf6008Sagc typedef struct {
8393bf6008Sagc 	__ops_compression_type_t type;
8493bf6008Sagc 	__ops_region_t   *region;
85b15ec256Sagc 	uint8_t   	in[DECOMPRESS_BUFFER];
86b15ec256Sagc 	uint8_t   	out[DECOMPRESS_BUFFER];
8793bf6008Sagc 	z_stream        zstream;/* ZIP and ZLIB */
8893bf6008Sagc 	size_t          offset;
8993bf6008Sagc 	int             inflate_ret;
9093bf6008Sagc } z_decompress_t;
9193bf6008Sagc 
9293bf6008Sagc typedef struct {
9393bf6008Sagc 	__ops_compression_type_t type;
9493bf6008Sagc 	__ops_region_t   *region;
9593bf6008Sagc 	char            in[DECOMPRESS_BUFFER];
9693bf6008Sagc 	char            out[DECOMPRESS_BUFFER];
9793bf6008Sagc 	bz_stream       bzstream;	/* BZIP2 */
9893bf6008Sagc 	size_t          offset;
9993bf6008Sagc 	int             inflate_ret;
10093bf6008Sagc } bz_decompress_t;
10193bf6008Sagc 
10293bf6008Sagc typedef struct {
10393bf6008Sagc 	z_stream        stream;
104b15ec256Sagc 	uint8_t  	*src;
105b15ec256Sagc 	uint8_t  	*dst;
10693bf6008Sagc } compress_t;
10793bf6008Sagc 
10893bf6008Sagc /*
10993bf6008Sagc  * \todo remove code duplication between this and
11093bf6008Sagc  * bzip2_compressed_data_reader
11193bf6008Sagc  */
11293bf6008Sagc static int
11393bf6008Sagc zlib_compressed_data_reader(void *dest, size_t length,
11493bf6008Sagc 			    __ops_error_t **errors,
1152232f800Sagc 			    __ops_reader_t *readinfo,
116d21b929eSagc 			    __ops_cbdata_t *cbinfo)
11793bf6008Sagc {
1182232f800Sagc 	z_decompress_t *z = __ops_reader_get_arg(readinfo);
11993bf6008Sagc 	size_t           len;
12085073018Sagc 	size_t		 cc;
12193bf6008Sagc 	char		*cdest = dest;
12293bf6008Sagc 
123bcfd8565Sagc 	if (z->type != OPS_C_ZIP && z->type != OPS_C_ZLIB) {
124bcfd8565Sagc 		(void) fprintf(stderr,
125bcfd8565Sagc 			"zlib_compressed_data_reader: weird type %d\n",
126bcfd8565Sagc 			z->type);
127bcfd8565Sagc 		return 0;
128bcfd8565Sagc 	}
12993bf6008Sagc 
13093bf6008Sagc 	if (z->inflate_ret == Z_STREAM_END &&
13193bf6008Sagc 	    z->zstream.next_out == &z->out[z->offset]) {
13293bf6008Sagc 		return 0;
13393bf6008Sagc 	}
13493bf6008Sagc 
13593bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
1364b3a3e18Sagc 		(void) fprintf(stderr,
1374b3a3e18Sagc 			"zlib_compressed_data_reader: length %" PRIsize "d\n",
1384b3a3e18Sagc 			length);
13993bf6008Sagc 	}
14093bf6008Sagc 
14157324b9fSagc 	if (z->region->readc == z->region->length) {
14293bf6008Sagc 		if (z->inflate_ret != Z_STREAM_END) {
14393bf6008Sagc 			OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,
14493bf6008Sagc 			"Compressed data didn't end when region ended.");
14593bf6008Sagc 		}
14693bf6008Sagc 	}
14793bf6008Sagc 	for (cc = 0 ; cc < length ; cc += len) {
14893bf6008Sagc 		if (&z->out[z->offset] == z->zstream.next_out) {
14993bf6008Sagc 			int             ret;
15093bf6008Sagc 
15193bf6008Sagc 			z->zstream.next_out = z->out;
15293bf6008Sagc 			z->zstream.avail_out = sizeof(z->out);
15393bf6008Sagc 			z->offset = 0;
15493bf6008Sagc 			if (z->zstream.avail_in == 0) {
15593bf6008Sagc 				unsigned        n = z->region->length;
15693bf6008Sagc 
15793bf6008Sagc 				if (!z->region->indeterminate) {
15857324b9fSagc 					n -= z->region->readc;
15993bf6008Sagc 					if (n > sizeof(z->in)) {
16093bf6008Sagc 						n = sizeof(z->in);
16193bf6008Sagc 					}
16293bf6008Sagc 				} else {
16393bf6008Sagc 					n = sizeof(z->in);
16493bf6008Sagc 				}
1654b3a3e18Sagc 				if (!__ops_stacked_limited_read(z->in, n,
1664b3a3e18Sagc 						z->region,
1672232f800Sagc 						errors, readinfo, cbinfo)) {
16893bf6008Sagc 					return -1;
16993bf6008Sagc 				}
17093bf6008Sagc 
17193bf6008Sagc 				z->zstream.next_in = z->in;
17293bf6008Sagc 				z->zstream.avail_in = (z->region->indeterminate) ?
17393bf6008Sagc 					z->region->last_read : n;
17493bf6008Sagc 			}
17593bf6008Sagc 			ret = inflate(&z->zstream, Z_SYNC_FLUSH);
17693bf6008Sagc 			if (ret == Z_STREAM_END) {
17793bf6008Sagc 				if (!z->region->indeterminate &&
17857324b9fSagc 				    z->region->readc != z->region->length) {
17993bf6008Sagc 					OPS_ERROR(cbinfo->errors,
18093bf6008Sagc 						OPS_E_P_DECOMPRESSION_ERROR,
18193bf6008Sagc 						"Compressed stream ended before packet end.");
18293bf6008Sagc 				}
18393bf6008Sagc 			} else if (ret != Z_OK) {
18493bf6008Sagc 				(void) fprintf(stderr, "ret=%d\n", ret);
1854b3a3e18Sagc 				OPS_ERROR(cbinfo->errors,
1864b3a3e18Sagc 				OPS_E_P_DECOMPRESSION_ERROR, z->zstream.msg);
18793bf6008Sagc 			}
18893bf6008Sagc 			z->inflate_ret = ret;
18993bf6008Sagc 		}
190bcfd8565Sagc 		if (z->zstream.next_out <= &z->out[z->offset]) {
191bcfd8565Sagc 			(void) fprintf(stderr, "Out of memory in buffer\n");
192bcfd8565Sagc 			return 0;
193bcfd8565Sagc 		}
1943574ef6dSagc 		len = (size_t)(z->zstream.next_out - &z->out[z->offset]);
19593bf6008Sagc 		if (len > length) {
19693bf6008Sagc 			len = length;
19793bf6008Sagc 		}
19893bf6008Sagc 		(void) memcpy(&cdest[cc], &z->out[z->offset], len);
19993bf6008Sagc 		z->offset += len;
20093bf6008Sagc 	}
20193bf6008Sagc 
202*69d4f30fSagc 	return (int)length;
20393bf6008Sagc }
20493bf6008Sagc 
20593bf6008Sagc /* \todo remove code duplication between this and zlib_compressed_data_reader */
20693bf6008Sagc static int
20793bf6008Sagc bzip2_compressed_data_reader(void *dest, size_t length,
20893bf6008Sagc 			     __ops_error_t **errors,
2092232f800Sagc 			     __ops_reader_t *readinfo,
210d21b929eSagc 			     __ops_cbdata_t *cbinfo)
21193bf6008Sagc {
2122232f800Sagc 	bz_decompress_t *bz = __ops_reader_get_arg(readinfo);
21393bf6008Sagc 	size_t		len;
21485073018Sagc 	size_t		 cc;
21593bf6008Sagc 	char		*cdest = dest;
21693bf6008Sagc 
217bcfd8565Sagc 	if (bz->type != OPS_C_BZIP2) {
218bcfd8565Sagc 		(void) fprintf(stderr, "Weird type %d\n", bz->type);
219bcfd8565Sagc 		return 0;
220bcfd8565Sagc 	}
22193bf6008Sagc 
22293bf6008Sagc 	if (bz->inflate_ret == BZ_STREAM_END &&
22393bf6008Sagc 	    bz->bzstream.next_out == &bz->out[bz->offset]) {
22493bf6008Sagc 		return 0;
22593bf6008Sagc 	}
22657324b9fSagc 	if (bz->region->readc == bz->region->length) {
22793bf6008Sagc 		if (bz->inflate_ret != BZ_STREAM_END) {
22893bf6008Sagc 			OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,
22993bf6008Sagc 			"Compressed data didn't end when region ended.");
23093bf6008Sagc 		}
23193bf6008Sagc 	}
23293bf6008Sagc 	for (cc = 0 ; cc < length ; cc += len) {
23393bf6008Sagc 		if (&bz->out[bz->offset] == bz->bzstream.next_out) {
23493bf6008Sagc 			int             ret;
23593bf6008Sagc 
23693bf6008Sagc 			bz->bzstream.next_out = (char *) bz->out;
23793bf6008Sagc 			bz->bzstream.avail_out = sizeof(bz->out);
23893bf6008Sagc 			bz->offset = 0;
23993bf6008Sagc 			if (bz->bzstream.avail_in == 0) {
24093bf6008Sagc 				unsigned        n = bz->region->length;
24193bf6008Sagc 
24293bf6008Sagc 				if (!bz->region->indeterminate) {
24357324b9fSagc 					n -= bz->region->readc;
24493bf6008Sagc 					if (n > sizeof(bz->in))
24593bf6008Sagc 						n = sizeof(bz->in);
24693bf6008Sagc 				} else
24793bf6008Sagc 					n = sizeof(bz->in);
24893bf6008Sagc 
2494b3a3e18Sagc 				if (!__ops_stacked_limited_read(
250b15ec256Sagc 						(uint8_t *) bz->in,
2514b3a3e18Sagc 						n, bz->region,
2522232f800Sagc 						errors, readinfo, cbinfo))
25393bf6008Sagc 					return -1;
25493bf6008Sagc 
25593bf6008Sagc 				bz->bzstream.next_in = bz->in;
2564b3a3e18Sagc 				bz->bzstream.avail_in =
2574b3a3e18Sagc 					(bz->region->indeterminate) ?
2584b3a3e18Sagc 					 bz->region->last_read : n;
25993bf6008Sagc 			}
26093bf6008Sagc 			ret = BZ2_bzDecompress(&bz->bzstream);
26193bf6008Sagc 			if (ret == BZ_STREAM_END) {
26293bf6008Sagc 				if (!bz->region->indeterminate &&
26357324b9fSagc 				    bz->region->readc != bz->region->length)
26493bf6008Sagc 					OPS_ERROR(cbinfo->errors,
26593bf6008Sagc 						OPS_E_P_DECOMPRESSION_ERROR,
26693bf6008Sagc 						"Compressed stream ended before packet end.");
26793bf6008Sagc 			} else if (ret != BZ_OK) {
26893bf6008Sagc 				OPS_ERROR_1(cbinfo->errors,
26993bf6008Sagc 					OPS_E_P_DECOMPRESSION_ERROR,
27093bf6008Sagc 					"Invalid return %d from BZ2_bzDecompress", ret);
27193bf6008Sagc 			}
27293bf6008Sagc 			bz->inflate_ret = ret;
27393bf6008Sagc 		}
274bcfd8565Sagc 		if (bz->bzstream.next_out <= &bz->out[bz->offset]) {
275bcfd8565Sagc 			(void) fprintf(stderr, "Out of bz memroy\n");
276bcfd8565Sagc 			return 0;
277bcfd8565Sagc 		}
2783574ef6dSagc 		len = (size_t)(bz->bzstream.next_out - &bz->out[bz->offset]);
279bcfd8565Sagc 		if (len > length) {
28093bf6008Sagc 			len = length;
281bcfd8565Sagc 		}
28293bf6008Sagc 		(void) memcpy(&cdest[cc], &bz->out[bz->offset], len);
28393bf6008Sagc 		bz->offset += len;
28493bf6008Sagc 	}
28593bf6008Sagc 
286*69d4f30fSagc 	return (int)length;
28793bf6008Sagc }
28893bf6008Sagc 
28993bf6008Sagc /**
29093bf6008Sagc  * \ingroup Core_Compress
29193bf6008Sagc  *
29293bf6008Sagc  * \param *region 	Pointer to a region
29341335e2dSagc  * \param *stream 	How to parse
29493bf6008Sagc  * \param type Which compression type to expect
29593bf6008Sagc */
29693bf6008Sagc 
29793bf6008Sagc int
29841335e2dSagc __ops_decompress(__ops_region_t *region, __ops_stream_t *stream,
29993bf6008Sagc 	       __ops_compression_type_t type)
30093bf6008Sagc {
30193bf6008Sagc 	z_decompress_t z;
30293bf6008Sagc 	bz_decompress_t bz;
303393ecd92Sagc 	const int	printerrors = 1;
30493bf6008Sagc 	int             ret;
30593bf6008Sagc 
30693bf6008Sagc 	switch (type) {
30793bf6008Sagc 	case OPS_C_ZIP:
30893bf6008Sagc 	case OPS_C_ZLIB:
30993bf6008Sagc 		(void) memset(&z, 0x0, sizeof(z));
31093bf6008Sagc 
31193bf6008Sagc 		z.region = region;
31293bf6008Sagc 		z.offset = 0;
31393bf6008Sagc 		z.type = type;
31493bf6008Sagc 
31593bf6008Sagc 		z.zstream.next_in = Z_NULL;
31693bf6008Sagc 		z.zstream.avail_in = 0;
31793bf6008Sagc 		z.zstream.next_out = z.out;
31893bf6008Sagc 		z.zstream.zalloc = Z_NULL;
31993bf6008Sagc 		z.zstream.zfree = Z_NULL;
32093bf6008Sagc 		z.zstream.opaque = Z_NULL;
32193bf6008Sagc 
32293bf6008Sagc 		break;
32393bf6008Sagc 
32493bf6008Sagc 	case OPS_C_BZIP2:
32593bf6008Sagc 		(void) memset(&bz, 0x0, sizeof(bz));
32693bf6008Sagc 
32793bf6008Sagc 		bz.region = region;
32893bf6008Sagc 		bz.offset = 0;
32993bf6008Sagc 		bz.type = type;
33093bf6008Sagc 
33193bf6008Sagc 		bz.bzstream.next_in = NULL;
33293bf6008Sagc 		bz.bzstream.avail_in = 0;
33393bf6008Sagc 		bz.bzstream.next_out = bz.out;
33493bf6008Sagc 		bz.bzstream.bzalloc = NULL;
33593bf6008Sagc 		bz.bzstream.bzfree = NULL;
33693bf6008Sagc 		bz.bzstream.opaque = NULL;
33793bf6008Sagc 
33893bf6008Sagc 		break;
33993bf6008Sagc 
34093bf6008Sagc 	default:
34141335e2dSagc 		OPS_ERROR_1(&stream->errors,
34293bf6008Sagc 			OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
34393bf6008Sagc 			"Compression algorithm %d is not yet supported", type);
34493bf6008Sagc 		return 0;
34593bf6008Sagc 	}
34693bf6008Sagc 
34793bf6008Sagc 	switch (type) {
34893bf6008Sagc 	case OPS_C_ZIP:
349*69d4f30fSagc 		ret = (int)inflateInit2(&z.zstream, -15);
35093bf6008Sagc 		break;
35193bf6008Sagc 
35293bf6008Sagc 	case OPS_C_ZLIB:
353*69d4f30fSagc 		ret = (int)inflateInit(&z.zstream);
35493bf6008Sagc 		break;
35593bf6008Sagc 
35693bf6008Sagc 	case OPS_C_BZIP2:
35793bf6008Sagc 		ret = BZ2_bzDecompressInit(&bz.bzstream, 1, 0);
35893bf6008Sagc 		break;
35993bf6008Sagc 
36093bf6008Sagc 	default:
36141335e2dSagc 		OPS_ERROR_1(&stream->errors,
36293bf6008Sagc 			OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
36393bf6008Sagc 			"Compression algorithm %d is not yet supported", type);
36493bf6008Sagc 		return 0;
36593bf6008Sagc 	}
36693bf6008Sagc 
36793bf6008Sagc 	switch (type) {
36893bf6008Sagc 	case OPS_C_ZIP:
36993bf6008Sagc 	case OPS_C_ZLIB:
37093bf6008Sagc 		if (ret != Z_OK) {
37141335e2dSagc 			OPS_ERROR_1(&stream->errors,
37293bf6008Sagc 				OPS_E_P_DECOMPRESSION_ERROR,
37393bf6008Sagc "Cannot initialise ZIP or ZLIB stream for decompression: error=%d", ret);
37493bf6008Sagc 			return 0;
37593bf6008Sagc 		}
37641335e2dSagc 		__ops_reader_push(stream, zlib_compressed_data_reader,
3774b3a3e18Sagc 					NULL, &z);
37893bf6008Sagc 		break;
37993bf6008Sagc 
38093bf6008Sagc 	case OPS_C_BZIP2:
38193bf6008Sagc 		if (ret != BZ_OK) {
38241335e2dSagc 			OPS_ERROR_1(&stream->errors,
38393bf6008Sagc 				OPS_E_P_DECOMPRESSION_ERROR,
38493bf6008Sagc "Cannot initialise BZIP2 stream for decompression: error=%d", ret);
38593bf6008Sagc 			return 0;
38693bf6008Sagc 		}
38741335e2dSagc 		__ops_reader_push(stream, bzip2_compressed_data_reader,
3884b3a3e18Sagc 					NULL, &bz);
38993bf6008Sagc 		break;
39093bf6008Sagc 
39193bf6008Sagc 	default:
39241335e2dSagc 		OPS_ERROR_1(&stream->errors,
39393bf6008Sagc 			OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG,
39493bf6008Sagc 			"Compression algorithm %d is not yet supported", type);
39593bf6008Sagc 		return 0;
39693bf6008Sagc 	}
39793bf6008Sagc 
39841335e2dSagc 	ret = __ops_parse(stream, !printerrors);
39993bf6008Sagc 
40041335e2dSagc 	__ops_reader_pop(stream);
40193bf6008Sagc 
40293bf6008Sagc 	return ret;
40393bf6008Sagc }
40493bf6008Sagc 
40593bf6008Sagc /**
40693bf6008Sagc \ingroup Core_WritePackets
40793bf6008Sagc \brief Writes Compressed packet
40893bf6008Sagc \param data Data to write out
40993bf6008Sagc \param len Length of data
41057324b9fSagc \param output Write settings
4114b3a3e18Sagc \return 1 if OK; else 0
41293bf6008Sagc */
41393bf6008Sagc 
4144b3a3e18Sagc unsigned
415b15ec256Sagc __ops_writez(__ops_output_t *out, const uint8_t *data, const unsigned len)
41693bf6008Sagc {
417e82f21ebSagc 	compress_t	*zip;
4183574ef6dSagc 	size_t		 sz_in;
4193574ef6dSagc 	size_t		 sz_out;
420e82f21ebSagc 	int              ret;
42193bf6008Sagc 	int              r = 0;
42293bf6008Sagc 
42393bf6008Sagc 	/* compress the data */
42493bf6008Sagc 	const int       level = Z_DEFAULT_COMPRESSION;	/* \todo allow varying
42593bf6008Sagc 							 * levels */
426e82f21ebSagc 
427e82f21ebSagc 	if ((zip = calloc(1, sizeof(*zip))) == NULL) {
428e82f21ebSagc 		(void) fprintf(stderr, "__ops_writez: bad alloc\n");
429e82f21ebSagc 		return 0;
430e82f21ebSagc 	}
431efdd9dbaSagc 	zip->stream.zalloc = Z_NULL;
432efdd9dbaSagc 	zip->stream.zfree = Z_NULL;
433efdd9dbaSagc 	zip->stream.opaque = NULL;
43493bf6008Sagc 
43593bf6008Sagc 	/* all other fields set to zero by use of calloc */
43693bf6008Sagc 
437*69d4f30fSagc 	if ((int)deflateInit(&zip->stream, level) != Z_OK) {
43857324b9fSagc 		(void) fprintf(stderr, "__ops_writez: can't initialise\n");
4394b3a3e18Sagc 		return 0;
44093bf6008Sagc 	}
44193bf6008Sagc 	/* do necessary transformation */
44293bf6008Sagc 	/* copy input to maintain const'ness of src */
443bcfd8565Sagc 	if (zip->src != NULL || zip->dst != NULL) {
44457324b9fSagc 		(void) fprintf(stderr, "__ops_writez: non-null streams\n");
4454b3a3e18Sagc 		return 0;
446bcfd8565Sagc 	}
44793bf6008Sagc 
448b15ec256Sagc 	sz_in = len * sizeof(uint8_t);
4493574ef6dSagc 	sz_out = ((101 * sz_in) / 100) + 12;	/* from zlib webpage */
450e82f21ebSagc 	if ((zip->src = calloc(1, sz_in)) == NULL) {
451e82f21ebSagc 		free(zip);
452e82f21ebSagc 		(void) fprintf(stderr, "__ops_writez: bad alloc2\n");
453e82f21ebSagc 		return 0;
454e82f21ebSagc 	}
455e82f21ebSagc 	if ((zip->dst = calloc(1, sz_out)) == NULL) {
456e82f21ebSagc 		free(zip->src);
457e82f21ebSagc 		free(zip);
458e82f21ebSagc 		(void) fprintf(stderr, "__ops_writez: bad alloc3\n");
459e82f21ebSagc 		return 0;
460e82f21ebSagc 	}
461efdd9dbaSagc 	(void) memcpy(zip->src, data, len);
46293bf6008Sagc 
46393bf6008Sagc 	/* setup stream */
464efdd9dbaSagc 	zip->stream.next_in = zip->src;
465*69d4f30fSagc 	zip->stream.avail_in = (unsigned)sz_in;
466efdd9dbaSagc 	zip->stream.total_in = 0;
46793bf6008Sagc 
468efdd9dbaSagc 	zip->stream.next_out = zip->dst;
469*69d4f30fSagc 	zip->stream.avail_out = (unsigned)sz_out;
470efdd9dbaSagc 	zip->stream.total_out = 0;
47193bf6008Sagc 
472bcfd8565Sagc 	do {
473efdd9dbaSagc 		r = deflate(&zip->stream, Z_FINISH);
474bcfd8565Sagc 	} while (r != Z_STREAM_END);
47593bf6008Sagc 
47693bf6008Sagc 	/* write it out */
477e82f21ebSagc 	ret = __ops_write_ptag(out, OPS_PTAG_CT_COMPRESSED) &&
47857324b9fSagc 		__ops_write_length(out, (unsigned)(zip->stream.total_out + 1))&&
47957324b9fSagc 		__ops_write_scalar(out, OPS_C_ZLIB, 1) &&
480e82f21ebSagc 		__ops_write(out, zip->dst, (unsigned)zip->stream.total_out);
481e82f21ebSagc 
482e82f21ebSagc 	free(zip->src);
483e82f21ebSagc 	free(zip->dst);
484e82f21ebSagc 	free(zip);
485e82f21ebSagc 	return ret;
48693bf6008Sagc }
487