2 * Copyright (c) 2003-2004 Tim Kientzle
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "archive_platform.h"
29 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.6 2004/08/14 03:45:45 kientzle Exp $");
40 #include "archive_private.h"
45 unsigned char *uncompressed_buffer;
46 size_t uncompressed_buffer_size;
51 static int finish(struct archive *);
52 static ssize_t read_ahead(struct archive *, const void **, size_t);
53 static ssize_t read_consume(struct archive *, size_t);
54 static int drive_decompressor(struct archive *a, struct private_data *);
57 /* These two functions are defined even if we lack bzlib. See below. */
58 static int bid(const void *, size_t);
59 static int init(struct archive *, const void *, size_t);
62 archive_read_support_compression_bzip2(struct archive *a)
64 return (__archive_read_register_compression(a, bid, init));
68 * Test whether we can handle this data.
70 * This logic returns zero if any part of the signature fails. It
71 * also tries to Do The Right Thing if a very short buffer prevents us
72 * from verifying as much as we would like.
75 bid(const void *buff, size_t len)
77 const unsigned char *buffer;
85 if (buffer[0] != 'B') /* Verify first ID byte. */
89 return (bits_checked);
91 if (buffer[1] != 'Z') /* Verify second ID byte. */
95 return (bits_checked);
97 if (buffer[2] != 'h') /* Verify third ID byte. */
101 return (bits_checked);
103 if (buffer[3] < '1' || buffer[3] > '9')
108 * Research Question: Can we do any more to verify that this
109 * really is BZip2 format?? For 99.9% of the time, the above
110 * test is sufficient, but it would be nice to do a more
111 * thorough check. It's especially troubling that the BZip2
112 * signature begins with all ASCII characters; a tar archive
113 * whose first filename begins with 'BZh3' would potentially
114 * fool this logic. (It may also be possible to gaurd against
115 * such anomalies in archive_read_support_compression_none.)
118 return (bits_checked);
124 * If we don't have bzlib on this system, we can't actually do the
125 * decompression. We can, however, still detect bzip2-compressed
126 * archives and emit a useful message.
129 init(struct archive *a, const void *buff, size_t n)
131 (void)a; /* UNUSED */
132 (void)buff; /* UNUSED */
133 (void)n; /* UNUSED */
135 archive_set_error(a, -1,
136 "This version of libarchive was compiled without bzip2 support");
137 return (ARCHIVE_FATAL);
144 * Setup the callbacks.
147 init(struct archive *a, const void *buff, size_t n)
149 struct private_data *state;
152 a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
153 a->compression_name = "bzip2";
155 state = malloc(sizeof(*state));
157 archive_set_error(a, ENOMEM,
158 "Can't allocate data for %s decompression",
159 a->compression_name);
160 return (ARCHIVE_FATAL);
162 memset(state, 0, sizeof(*state));
164 state->uncompressed_buffer_size = 64 * 1024;
165 state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
166 state->stream.next_out = state->uncompressed_buffer;
167 state->read_next = state->uncompressed_buffer;
168 state->stream.avail_out = state->uncompressed_buffer_size;
170 if (state->uncompressed_buffer == NULL) {
171 archive_set_error(a, ENOMEM,
172 "Can't allocate %s decompression buffers",
173 a->compression_name);
175 return (ARCHIVE_FATAL);
179 * A bug in bzlib.h: stream.next_in should be marked 'const'
180 * but isn't (the library never alters data through the
181 * next_in pointer, only reads it). The result: this ugly
182 * cast to remove 'const'.
184 state->stream.next_in = (void *)(uintptr_t)(const void *)buff;
185 state->stream.avail_in = n;
187 a->compression_read_ahead = read_ahead;
188 a->compression_read_consume = read_consume;
189 a->compression_finish = finish;
191 /* Initialize compression library. */
192 ret = BZ2_bzDecompressInit(&(state->stream),
193 0 /* library verbosity */,
194 0 /* don't use slow low-mem algorithm */);
196 /* If init fails, try using low-memory algorithm instead. */
197 if (ret == BZ_MEM_ERROR) {
198 ret = BZ2_bzDecompressInit(&(state->stream),
199 0 /* library verbosity */,
200 1 /* do use slow low-mem algorithm */);
204 a->compression_data = state;
208 /* Library setup failed: Clean up. */
209 archive_set_error(a, ARCHIVE_ERRNO_MISC,
210 "Internal error initializing %s library", a->compression_name);
211 free(state->uncompressed_buffer);
214 /* Override the error message if we know what really went wrong. */
217 archive_set_error(a, ARCHIVE_ERRNO_MISC,
218 "Internal error initializing compression library: "
219 "invalid setup parameter");
222 archive_set_error(a, ARCHIVE_ERRNO_MISC,
223 "Internal error initializing compression library: "
226 case BZ_CONFIG_ERROR:
227 archive_set_error(a, ARCHIVE_ERRNO_MISC,
228 "Internal error initializing compression library: "
229 "mis-compiled library");
233 return (ARCHIVE_FATAL);
237 * Return a block of data from the decompression buffer. Decompress more
241 read_ahead(struct archive *a, const void **p, size_t min)
243 struct private_data *state;
244 int read_avail, was_avail, ret;
246 state = a->compression_data;
248 if (!a->client_reader) {
249 archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
250 "No read callback is registered? "
251 "This is probably an internal programming error.");
252 return (ARCHIVE_FATAL);
255 read_avail = state->stream.next_out - state->read_next;
257 if (read_avail + state->stream.avail_out < min) {
258 memmove(state->uncompressed_buffer, state->read_next,
260 state->read_next = state->uncompressed_buffer;
261 state->stream.next_out = state->read_next + read_avail;
262 state->stream.avail_out
263 = state->uncompressed_buffer_size - read_avail;
266 while (was_avail < read_avail && /* Made some progress. */
267 read_avail < (int)min && /* Haven't satisfied min. */
268 read_avail < (int)state->uncompressed_buffer_size) { /* !full */
269 if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
271 was_avail = read_avail;
272 read_avail = state->stream.next_out - state->read_next;
275 *p = state->read_next;
280 * Mark a previously-returned block of data as read.
283 read_consume(struct archive *a, size_t n)
285 struct private_data *state;
287 state = a->compression_data;
288 a->file_position += n;
289 state->read_next += n;
290 if (state->read_next > state->stream.next_out)
291 __archive_errx(1, "Request to consume too many "
292 "bytes from bzip2 decompressor");
297 * Clean up the decompressor.
300 finish(struct archive *a)
302 struct private_data *state;
305 state = a->compression_data;
307 switch (BZ2_bzDecompressEnd(&(state->stream))) {
311 archive_set_error(a, ARCHIVE_ERRNO_MISC,
312 "Failed to clean up %s compressor", a->compression_name);
316 free(state->uncompressed_buffer);
319 a->compression_data = NULL;
320 if (a->client_closer != NULL)
321 (a->client_closer)(a, a->client_data);
327 * Utility function to pull data through decompressor, reading input
328 * blocks as necessary.
331 drive_decompressor(struct archive *a, struct private_data *state)
334 int decompressed, total_decompressed;
337 total_decompressed = 0;
339 if (state->stream.avail_in == 0) {
340 ret = (a->client_reader)(a, a->client_data,
341 (const void **)&state->stream.next_in);
344 * TODO: Find a better way to handle
349 if (ret == 0 && total_decompressed == 0) {
350 archive_set_error(a, EIO,
351 "Premature end of %s compressed data",
352 a->compression_name);
353 return (ARCHIVE_FATAL);
355 a->raw_position += ret;
356 state->stream.avail_in = ret;
360 output = state->stream.next_out;
362 /* Decompress some data. */
363 ret = BZ2_bzDecompress(&(state->stream));
364 decompressed = state->stream.next_out - output;
366 /* Accumulate the total bytes of output. */
367 state->total_out += decompressed;
368 total_decompressed += decompressed;
371 case BZ_OK: /* Decompressor made some progress. */
372 if (decompressed > 0)
375 case BZ_STREAM_END: /* Found end of stream. */
378 /* Any other return value is an error. */
385 /* Return a fatal error. */
387 archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
388 a->compression_name);
389 return (ARCHIVE_FATAL);
392 #endif /* HAVE_BZLIB_H */