2 * Copyright (c) 2003-2007 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 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "archive_platform.h"
28 __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_bzip2.c,v 1.18 2008/05/26 17:00:22 kientzle Exp $");
48 #include "archive_private.h"
49 #include "archive_read_private.h"
54 char *uncompressed_buffer;
55 size_t uncompressed_buffer_size;
58 char eof; /* True = found end of compressed data. */
61 static int finish(struct archive_read *);
62 static ssize_t read_ahead(struct archive_read *, const void **, size_t);
63 static ssize_t read_consume(struct archive_read *, size_t);
64 static int drive_decompressor(struct archive_read *a, struct private_data *);
67 /* These two functions are defined even if we lack the library. See below. */
68 static int bid(const void *, size_t);
69 static int init(struct archive_read *, const void *, size_t);
72 archive_read_support_compression_bzip2(struct archive *_a)
74 struct archive_read *a = (struct archive_read *)_a;
75 if (__archive_read_register_compression(a, bid, init) != NULL)
77 return (ARCHIVE_FATAL);
81 * Test whether we can handle this data.
83 * This logic returns zero if any part of the signature fails. It
84 * also tries to Do The Right Thing if a very short buffer prevents us
85 * from verifying as much as we would like.
88 bid(const void *buff, size_t len)
90 const unsigned char *buffer;
96 buffer = (const unsigned char *)buff;
98 if (buffer[0] != 'B') /* Verify first ID byte. */
102 return (bits_checked);
104 if (buffer[1] != 'Z') /* Verify second ID byte. */
108 return (bits_checked);
110 if (buffer[2] != 'h') /* Verify third ID byte. */
114 return (bits_checked);
116 if (buffer[3] < '1' || buffer[3] > '9')
120 return (bits_checked);
122 /* After BZh[1-9], there must be either a data block
123 * which begins with 0x314159265359 or an end-of-data
124 * marker of 0x177245385090. */
126 if (buffer[4] == 0x31) {
127 /* Verify the data block signature. */
130 if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", s - 4) != 0)
132 bits_checked += 8 * (s - 4);
133 } else if (buffer[4] == 0x17) {
134 /* Verify the end-of-data marker. */
137 if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", s - 4) != 0)
139 bits_checked += 8 * (s - 4);
143 return (bits_checked);
149 * If we don't have the library on this system, we can't actually do the
150 * decompression. We can, however, still detect compressed archives
151 * and emit a useful message.
154 init(struct archive_read *a, const void *buff, size_t n)
156 (void)a; /* UNUSED */
157 (void)buff; /* UNUSED */
158 (void)n; /* UNUSED */
160 archive_set_error(&a->archive, -1,
161 "This version of libarchive was compiled without bzip2 support");
162 return (ARCHIVE_FATAL);
169 * Setup the callbacks.
172 init(struct archive_read *a, const void *buff, size_t n)
174 struct private_data *state;
177 a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
178 a->archive.compression_name = "bzip2";
180 state = (struct private_data *)malloc(sizeof(*state));
182 archive_set_error(&a->archive, ENOMEM,
183 "Can't allocate data for %s decompression",
184 a->archive.compression_name);
185 return (ARCHIVE_FATAL);
187 memset(state, 0, sizeof(*state));
189 state->uncompressed_buffer_size = 64 * 1024;
190 state->uncompressed_buffer = (char *)malloc(state->uncompressed_buffer_size);
191 state->stream.next_out = state->uncompressed_buffer;
192 state->read_next = state->uncompressed_buffer;
193 state->stream.avail_out = state->uncompressed_buffer_size;
195 if (state->uncompressed_buffer == NULL) {
196 archive_set_error(&a->archive, ENOMEM,
197 "Can't allocate %s decompression buffers",
198 a->archive.compression_name);
200 return (ARCHIVE_FATAL);
204 * A bug in bzlib.h: stream.next_in should be marked 'const'
205 * but isn't (the library never alters data through the
206 * next_in pointer, only reads it). The result: this ugly
207 * cast to remove 'const'.
209 state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
210 state->stream.avail_in = n;
212 a->decompressor->read_ahead = read_ahead;
213 a->decompressor->consume = read_consume;
214 a->decompressor->skip = NULL; /* not supported */
215 a->decompressor->finish = finish;
217 /* Initialize compression library. */
218 ret = BZ2_bzDecompressInit(&(state->stream),
219 0 /* library verbosity */,
220 0 /* don't use slow low-mem algorithm */);
222 /* If init fails, try using low-memory algorithm instead. */
223 if (ret == BZ_MEM_ERROR) {
224 ret = BZ2_bzDecompressInit(&(state->stream),
225 0 /* library verbosity */,
226 1 /* do use slow low-mem algorithm */);
230 a->decompressor->data = state;
234 /* Library setup failed: Clean up. */
235 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
236 "Internal error initializing %s library",
237 a->archive.compression_name);
238 free(state->uncompressed_buffer);
241 /* Override the error message if we know what really went wrong. */
244 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
245 "Internal error initializing compression library: "
246 "invalid setup parameter");
249 archive_set_error(&a->archive, ENOMEM,
250 "Internal error initializing compression library: "
253 case BZ_CONFIG_ERROR:
254 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
255 "Internal error initializing compression library: "
256 "mis-compiled library");
260 return (ARCHIVE_FATAL);
264 * Return a block of data from the decompression buffer. Decompress more
268 read_ahead(struct archive_read *a, const void **p, size_t min)
270 struct private_data *state;
271 size_t read_avail, was_avail;
274 state = (struct private_data *)a->decompressor->data;
275 if (!a->client_reader) {
276 archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
277 "No read callback is registered? "
278 "This is probably an internal programming error.");
279 return (ARCHIVE_FATAL);
282 read_avail = state->stream.next_out - state->read_next;
284 if (read_avail + state->stream.avail_out < min) {
285 memmove(state->uncompressed_buffer, state->read_next,
287 state->read_next = state->uncompressed_buffer;
288 state->stream.next_out = state->read_next + read_avail;
289 state->stream.avail_out
290 = state->uncompressed_buffer_size - read_avail;
293 while (read_avail < min && /* Haven't satisfied min. */
294 read_avail < state->uncompressed_buffer_size) { /* !full */
295 was_avail = read_avail;
296 if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
298 if (ret == ARCHIVE_EOF)
299 break; /* Break on EOF even if we haven't met min. */
300 read_avail = state->stream.next_out - state->read_next;
301 if (was_avail == read_avail) /* No progress? */
305 *p = state->read_next;
310 * Mark a previously-returned block of data as read.
313 read_consume(struct archive_read *a, size_t n)
315 struct private_data *state;
317 state = (struct private_data *)a->decompressor->data;
318 a->archive.file_position += n;
319 state->read_next += n;
320 if (state->read_next > state->stream.next_out)
321 __archive_errx(1, "Request to consume too many "
322 "bytes from bzip2 decompressor");
327 * Clean up the decompressor.
330 finish(struct archive_read *a)
332 struct private_data *state;
335 state = (struct private_data *)a->decompressor->data;
337 switch (BZ2_bzDecompressEnd(&(state->stream))) {
341 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
342 "Failed to clean up %s compressor",
343 a->archive.compression_name);
347 free(state->uncompressed_buffer);
350 a->decompressor->data = NULL;
355 * Utility function to pull data through decompressor, reading input
356 * blocks as necessary.
359 drive_decompressor(struct archive_read *a, struct private_data *state)
362 int decompressed, total_decompressed;
364 const void *read_buf;
367 return (ARCHIVE_EOF);
368 total_decompressed = 0;
370 if (state->stream.avail_in == 0) {
371 read_buf = state->stream.next_in;
372 ret = (a->client_reader)(&a->archive, a->client_data,
374 state->stream.next_in = (void *)(uintptr_t)read_buf;
377 * TODO: Find a better way to handle
382 if (ret == 0 && total_decompressed == 0) {
383 archive_set_error(&a->archive, EIO,
384 "Premature end of %s compressed data",
385 a->archive.compression_name);
386 return (ARCHIVE_FATAL);
388 a->archive.raw_position += ret;
389 state->stream.avail_in = ret;
393 output = state->stream.next_out;
395 /* Decompress some data. */
396 ret = BZ2_bzDecompress(&(state->stream));
397 decompressed = state->stream.next_out - output;
399 /* Accumulate the total bytes of output. */
400 state->total_out += decompressed;
401 total_decompressed += decompressed;
404 case BZ_OK: /* Decompressor made some progress. */
405 if (decompressed > 0)
408 case BZ_STREAM_END: /* Found end of stream. */
412 /* Any other return value is an error. */
419 /* Return a fatal error. */
421 archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
422 "%s decompression failed", a->archive.compression_name);
423 return (ARCHIVE_FATAL);
426 #endif /* HAVE_BZLIB_H */