2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
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
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.
54 #ifdef HAVE_SYS_CDEFS_H
55 #include <sys/cdefs.h>
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 $");
73 #include "packet-parse.h"
75 #include "netpgpdefs.h"
80 #define DECOMPRESS_BUFFER 1024
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 */
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 */
109 * \todo remove code duplication between this and
110 * bzip2_compressed_data_reader
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
);
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",
130 if (z
->inflate_ret
== Z_STREAM_END
&&
131 z
->zstream
.next_out
== &z
->out
[z
->offset
]) {
135 if (__ops_get_debug_level(__FILE__
)) {
136 (void) fprintf(stderr
,
137 "zlib_compressed_data_reader: length %" PRIsize
"d\n",
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
) {
151 z
->zstream
.next_out
= z
->out
;
152 z
->zstream
.avail_out
= sizeof(z
->out
);
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
)) {
165 if (!__ops_stacked_limited_read(z
->in
, n
,
167 errors
, readinfo
, cbinfo
)) {
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");
194 len
= (size_t)(z
->zstream
.next_out
- &z
->out
[z
->offset
]);
198 (void) memcpy(&cdest
[cc
], &z
->out
[z
->offset
], len
);
205 /* \todo remove code duplication between this and zlib_compressed_data_reader */
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
);
217 if (bz
->type
!= OPS_C_BZIP2
) {
218 (void) fprintf(stderr
, "Weird type %d\n", bz
->type
);
222 if (bz
->inflate_ret
== BZ_STREAM_END
&&
223 bz
->bzstream
.next_out
== &bz
->out
[bz
->offset
]) {
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
) {
236 bz
->bzstream
.next_out
= (char *) bz
->out
;
237 bz
->bzstream
.avail_out
= sizeof(bz
->out
);
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
))
249 if (!__ops_stacked_limited_read(
250 (unsigned char *) bz
->in
,
252 errors
, readinfo
, cbinfo
))
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");
278 len
= (size_t)(bz
->bzstream
.next_out
- &bz
->out
[bz
->offset
]);
282 (void) memcpy(&cdest
[cc
], &bz
->out
[bz
->offset
], len
);
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
298 __ops_decompress(__ops_region_t
*region
, __ops_stream_t
*stream
,
299 __ops_compression_type_t type
)
303 const int printerrors
= 1;
309 (void) memset(&z
, 0x0, sizeof(z
));
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
;
325 (void) memset(&bz
, 0x0, sizeof(bz
));
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
;
341 OPS_ERROR_1(&stream
->errors
,
342 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG
,
343 "Compression algorithm %d is not yet supported", type
);
349 ret
= inflateInit2(&z
.zstream
, -15);
353 ret
= inflateInit(&z
.zstream
);
357 ret
= BZ2_bzDecompressInit(&bz
.bzstream
, 1, 0);
361 OPS_ERROR_1(&stream
->errors
,
362 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG
,
363 "Compression algorithm %d is not yet supported", type
);
371 OPS_ERROR_1(&stream
->errors
,
372 OPS_E_P_DECOMPRESSION_ERROR
,
373 "Cannot initialise ZIP or ZLIB stream for decompression: error=%d", ret
);
376 __ops_reader_push(stream
, zlib_compressed_data_reader
,
382 OPS_ERROR_1(&stream
->errors
,
383 OPS_E_P_DECOMPRESSION_ERROR
,
384 "Cannot initialise BZIP2 stream for decompression: error=%d", ret
);
387 __ops_reader_push(stream
, bzip2_compressed_data_reader
,
392 OPS_ERROR_1(&stream
->errors
,
393 OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG
,
394 "Compression algorithm %d is not yet supported", type
);
398 ret
= __ops_parse(stream
, !printerrors
);
400 __ops_reader_pop(stream
);
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
415 __ops_writez(const unsigned char *data
,
416 const unsigned int len
,
425 /* compress the data */
426 const int level
= Z_DEFAULT_COMPRESSION
; /* \todo allow varying
429 if ((zip
= calloc(1, sizeof(*zip
))) == NULL
) {
430 (void) fprintf(stderr
, "__ops_writez: bad alloc\n");
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");
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");
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
) {
454 (void) fprintf(stderr
, "__ops_writez: bad alloc2\n");
457 if ((zip
->dst
= calloc(1, sz_out
)) == NULL
) {
460 (void) fprintf(stderr
, "__ops_writez: bad alloc3\n");
463 (void) memcpy(zip
->src
, data
, len
);
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;
475 r
= deflate(&zip
->stream
, Z_FINISH
);
476 } while (r
!= Z_STREAM_END
);
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
);