From: Tim Kientzle Date: Sun, 8 Mar 2009 08:42:26 +0000 (-0400) Subject: Since the most popular XZ decompression library also supports LZMA, X-Git-Tag: v2.7.0~181 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=75bd264fb7aebef34f309ac951da230f33bb9600;p=thirdparty%2Flibarchive.git Since the most popular XZ decompression library also supports LZMA, just fold the LZMA handling into the XZ reader. This also eliminates some duplication of bid code. Also, clean up the style a bit to exploit the peek/consume I/O style. SVN-Revision: 747 --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 15de2aede..c973e58b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -538,7 +538,6 @@ SET(libarchive_SOURCES libarchive/archive_read_support_compression_gzip.c libarchive/archive_read_support_compression_none.c libarchive/archive_read_support_compression_program.c - libarchive/archive_read_support_compression_lzma.c libarchive/archive_read_support_compression_xz.c libarchive/archive_read_support_format_all.c libarchive/archive_read_support_format_ar.c diff --git a/Makefile.am b/Makefile.am index b17e6bab8..760dae5b6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -109,7 +109,6 @@ libarchive_la_SOURCES= \ libarchive/archive_read_support_compression_gzip.c \ libarchive/archive_read_support_compression_none.c \ libarchive/archive_read_support_compression_program.c \ - libarchive/archive_read_support_compression_lzma.c \ libarchive/archive_read_support_compression_xz.c \ libarchive/archive_read_support_format_all.c \ libarchive/archive_read_support_format_ar.c \ diff --git a/libarchive/Makefile b/libarchive/Makefile index 5eb171ceb..5897710f0 100644 --- a/libarchive/Makefile +++ b/libarchive/Makefile @@ -37,10 +37,9 @@ SRCS= archive_check_magic.c \ archive_read_support_compression_bzip2.c \ archive_read_support_compression_compress.c \ archive_read_support_compression_gzip.c \ - archive_read_support_compression_lzma.c \ archive_read_support_compression_none.c \ archive_read_support_compression_program.c \ - archive_read_support_compression_xz.c \ + archive_read_support_compression_xz.c \ archive_read_support_format_all.c \ archive_read_support_format_ar.c \ archive_read_support_format_cpio.c \ diff --git a/libarchive/archive_read_support_compression_lzma.c b/libarchive/archive_read_support_compression_lzma.c deleted file mode 100644 index 9a939020f..000000000 --- a/libarchive/archive_read_support_compression_lzma.c +++ /dev/null @@ -1,356 +0,0 @@ -/*- - * Copyright (c) 2003-2008 Tim Kientzle and Miklos Vajna - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "archive_platform.h" - -__FBSDID("$FreeBSD$"); - -#ifdef HAVE_ERRNO_H -#include -#endif -#include -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_LZMADEC_H -#include -#endif - -#include "archive.h" -#include "archive_private.h" -#include "archive_read_private.h" - -#ifndef HAVE_LZMA_H -#if HAVE_LZMADEC_H -struct private_data { - lzmadec_stream stream; - unsigned char *out_block; - size_t out_block_size; - int64_t total_out; - char eof; /* True = found end of compressed data. */ -}; - -/* Lzma filter */ -static ssize_t lzma_filter_read(struct archive_read_filter *, const void **); -static int lzma_filter_close(struct archive_read_filter *); -#endif - -/* - * Note that we can detect lzma archives even if we can't decompress - * them. (In fact, we like detecting them because we can give better - * error messages.) So the bid framework here gets compiled even - * if lzmadec is unavailable. - */ -static int lzma_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); -static int lzma_bidder_init(struct archive_read_filter *); -static int lzma_bidder_free(struct archive_read_filter_bidder *); - -int -archive_read_support_compression_lzma(struct archive *_a) -{ - struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter_bidder *bidder = __archive_read_get_bidder(a); - - if (bidder == NULL) - return (ARCHIVE_FATAL); - - bidder->data = NULL; - bidder->bid = lzma_bidder_bid; - bidder->init = lzma_bidder_init; - bidder->options = NULL; - bidder->free = lzma_bidder_free; - return (ARCHIVE_OK); -} - -static int -lzma_bidder_free(struct archive_read_filter_bidder *self){ - (void)self; /* UNUSED */ - return (ARCHIVE_OK); -} - -/* - * Test whether we can handle this data. - * - * This logic returns zero if any part of the signature fails. It - * also tries to Do The Right Thing if a very short buffer prevents us - * from verifying as much as we would like. - * - * LZMA has a rather poor file signature. Zeros do not - * make good signature bytes as a rule, and the only non-zero byte - * here is an ASCII character. For example, an uncompressed tar - * archive whose first file is ']' would satisfy this check. It may - * be necessary to exclude LZMA from compression_all() because of - * this. Clients of libarchive would then have to explicitly enable - * LZMA checking instead of (or in addition to) compression_all() when - * they have other evidence (file name, command-line option) to go on. - */ -static int -lzma_bidder_bid(struct archive_read_filter_bidder *self, - struct archive_read_filter *filter) -{ - const unsigned char *buffer; - ssize_t avail; - int bits_checked; - - (void)self; /* UNUSED */ - - buffer = __archive_read_filter_ahead(filter, 6, &avail); - if (buffer == NULL) - return (0); - - /* First byte of raw LZMA stream is always 0x5d. */ - bits_checked = 0; - if (buffer[0] != 0x5d) - return (0); - bits_checked += 8; - - /* Second through fifth bytes are dictionary code, stored in - * little-endian order. The two least-significant bytes are - * always zero. */ - if (buffer[1] != 0 || buffer[2] != 0) - return (0); - bits_checked += 16; - - /* ??? TODO: Fix this. ??? */ - /* NSIS format check uses this, but I've seen tar.lzma - * archives where this byte is 0xff, not 0. Can it - * ever be anything other than 0 or 0xff? - */ -#if 0 - if (buffer[5] != 0) - return (0); - bits_checked += 8; -#endif - - /* TODO: The above test is still very weak. It would be - * good to do better. */ - - return (bits_checked); -} - -#ifndef HAVE_LZMADEC_H - -/* - * If we don't have the library on this system, we can't actually do the - * decompression. We can, however, still detect compressed archives - * and emit a useful message. - */ -static int -lzma_bidder_init(struct archive_read_filter *filter) -{ - (void)filter; /* UNUSED */ - - archive_set_error(&filter->archive->archive, -1, - "This version of libarchive was compiled without lzma support"); - return (ARCHIVE_FATAL); -} - - -#else - -/* - * Setup the callbacks. - */ -static int -lzma_bidder_init(struct archive_read_filter *self) -{ - static const size_t out_block_size = 64 * 1024; - void *out_block; - const char *buff; - struct private_data *state; - ssize_t ret; - - self->code = ARCHIVE_COMPRESSION_LZMA; - self->name = "lzma"; - - state = (struct private_data *)calloc(sizeof(*state), 1); - out_block = (unsigned char *)malloc(out_block_size); - if (state == NULL || out_block == NULL) { - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate data for lzma decompression"); - free(out_block); - free(state); - return (ARCHIVE_FATAL); - } - - self->data = state; - state->out_block_size = out_block_size; - state->out_block = out_block; - self->read = lzma_filter_read; - self->skip = NULL; /* not supported */ - self->close = lzma_filter_close; - - /* - * Prime the lzma library with at least 18 bytes - * of input. (But give it as much as is available.) - */ - buff = __archive_read_filter_ahead(self->upstream, 18, &ret); - if (buff == NULL) - return (ARCHIVE_FATAL); - __archive_read_filter_consume(self->upstream, ret); - /* - * zlib.h made this mistake and people keep copying it. - * stream.next_in should be const but isn't, hence this very - * ugly cast. - */ - state->stream.next_in = (unsigned char *)(uintptr_t)buff; - state->stream.avail_in = ret; - - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Initialize compression library. */ - ret = lzmadec_init(&(state->stream)); - - if (ret == LZMADEC_OK) - return (ARCHIVE_OK); - - /* Library setup failed: Clean up. */ - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing lzma library"); - - /* Override the error message if we know what really went wrong. */ - switch (ret) { - case LZMADEC_HEADER_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "invalid header"); - break; - case LZMADEC_MEM_ERROR: - archive_set_error(&self->archive->archive, ENOMEM, - "Internal error initializing compression library: " - "out of memory"); - break; - } - - free(state->out_block); - free(state); - self->data = NULL; - return (ARCHIVE_FATAL); -} - -/* - * Return the next block of decompressed data. - */ -static ssize_t -lzma_filter_read(struct archive_read_filter *self, const void **p) -{ - struct private_data *state; - size_t read_avail, decompressed; - const void *read_buf; - ssize_t ret; - - state = (struct private_data *)self->data; - read_avail = 0; - - /* Empty our output buffer. */ - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Try to fill the output buffer. */ - while (state->stream.avail_out > 0 && !state->eof) { - /* If the last upstream block is done, get another one. */ - if (state->stream.avail_in == 0) { - read_buf = __archive_read_filter_ahead(self->upstream, - 1, &ret); - if (ret == 0) { - state->eof = 1; - break; - } - if (read_buf == NULL || ret < 0) - return (ARCHIVE_FATAL); - /* stream.next_in is really const, but lzmadec - * doesn't declare it so. */ - state->stream.next_in - = (unsigned char *)(uintptr_t)read_buf; - state->stream.avail_in = ret; - __archive_read_filter_consume(self->upstream, ret); - } - - /* Decompress as much as we can in one pass. */ - ret = lzmadec_decode(&(state->stream), - state->stream.avail_in == 0); - switch (ret) { - case LZMADEC_STREAM_END: /* Found end of stream. */ - state->eof = 1; - case LZMADEC_OK: /* Decompressor made some progress. */ - break; - case LZMADEC_BUF_ERROR: /* Insufficient input data? */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Insufficient compressed data"); - return (ARCHIVE_FATAL); - default: - /* Return an error. */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "%s decompression failed", - self->archive->archive.compression_name); - return (ARCHIVE_FATAL); - } - } - - *p = state->out_block; - decompressed = state->stream.next_out - state->out_block; - state->total_out += decompressed; - return (decompressed); -} - -/* - * Clean up the decompressor. - */ -static int -lzma_filter_close(struct archive_read_filter *self) -{ - struct private_data *state; - int ret; - - state = (struct private_data *)self->data; - ret = ARCHIVE_OK; - switch (lzmadec_end(&(state->stream))) { - case LZMADEC_OK: - break; - default: - archive_set_error(&(self->archive->archive), - ARCHIVE_ERRNO_MISC, - "Failed to clean up %s compressor", - self->archive->archive.compression_name); - ret = ARCHIVE_FATAL; - } - - free(state->out_block); - free(state); - return (ret); -} - -#endif /* HAVE_LZMADEC_H */ -#endif /* HAVE_LZMA_H */ diff --git a/libarchive/archive_read_support_compression_xz.c b/libarchive/archive_read_support_compression_xz.c index be238ac55..2cdac6e51 100644 --- a/libarchive/archive_read_support_compression_xz.c +++ b/libarchive/archive_read_support_compression_xz.c @@ -41,15 +41,18 @@ __FBSDID("$FreeBSD$"); #ifdef HAVE_UNISTD_H #include #endif -#ifdef HAVE_LZMA_H +#if HAVE_LZMA_H #include +#elif HAVE_LZMADEC_H +#include #endif #include "archive.h" #include "archive_private.h" #include "archive_read_private.h" -#if HAVE_LZMA_H +#if HAVE_LZMA_H && HAVE_LIBLZMA + struct private_data { lzma_stream stream; unsigned char *out_block; @@ -58,24 +61,40 @@ struct private_data { char eof; /* True = found end of compressed data. */ }; -/* Lzma filter */ +/* Combined lzma/xz filter */ static ssize_t xz_filter_read(struct archive_read_filter *, const void **); static int xz_filter_close(struct archive_read_filter *); -static int xz_lzma_bidder_init(struct archive_read_filter *, int code); -static int lzma_bidder_bid(struct archive_read_filter_bidder *, - struct archive_read_filter *); +static int xz_lzma_bidder_init(struct archive_read_filter *); + +#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC + +struct private_data { + lzmadec_stream stream; + unsigned char *out_block; + size_t out_block_size; + int64_t total_out; + char eof; /* True = found end of compressed data. */ +}; + +/* Lzma-only filter */ +static ssize_t lzma_filter_read(struct archive_read_filter *, const void **); +static int lzma_filter_close(struct archive_read_filter *); static int lzma_bidder_init(struct archive_read_filter *); + #endif /* - * Note that we can detect xz archives even if we can't decompress - * them. (In fact, we like detecting them because we can give better - * error messages.) So the bid framework here gets compiled even - * if lzma is unavailable. + * Note that we can detect xz and lzma compressed files even if we + * can't decompress them. (In fact, we like detecting them because we + * can give better error messages.) So the bid framework here gets + * compiled even if no lzma library is available. */ static int xz_bidder_bid(struct archive_read_filter_bidder *, struct archive_read_filter *); static int xz_bidder_init(struct archive_read_filter *); +static int lzma_bidder_bid(struct archive_read_filter_bidder *, + struct archive_read_filter *); +static int lzma_bidder_init(struct archive_read_filter *); int archive_read_support_compression_xz(struct archive *_a) @@ -94,7 +113,6 @@ archive_read_support_compression_xz(struct archive *_a) return (ARCHIVE_OK); } -#ifdef HAVE_LZMA_H int archive_read_support_compression_lzma(struct archive *_a) { @@ -111,15 +129,9 @@ archive_read_support_compression_lzma(struct archive *_a) bidder->free = NULL; return (ARCHIVE_OK); } -#endif /* * Test whether we can handle this data. - * - * This logic returns zero if any part of the signature fails. It - * also tries to Do The Right Thing if a very short buffer prevents us - * from verifying as much as we would like. - * */ static int xz_bidder_bid(struct archive_read_filter_bidder *self, @@ -161,14 +173,9 @@ xz_bidder_bid(struct archive_read_filter_bidder *self, return (bits_checked); } -#ifdef HAVE_LZMA_H /* * Test whether we can handle this data. * - * This logic returns zero if any part of the signature fails. It - * also tries to Do The Right Thing if a very short buffer prevents us - * from verifying as much as we would like. - * * LZMA has a rather poor file signature. Zeros do not * make good signature bytes as a rule, and the only non-zero byte * here is an ASCII character. For example, an uncompressed tar @@ -221,54 +228,39 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self, return (bits_checked); } -#endif -#ifndef HAVE_LZMA_H +#if HAVE_LZMA_H && HAVE_LIBLZMA /* - * If we don't have the library on this system, we can't actually do the - * decompression. We can, however, still detect compressed archives - * and emit a useful message. + * liblzma 4.999.7 and later support both lzma and xz streams. */ -static int -xz_bidder_init(struct archive_read_filter *filter) -{ - (void)filter; /* UNUSED */ - - archive_set_error(&filter->archive->archive, -1, - "This version of libarchive was compiled without xz support"); - return (ARCHIVE_FATAL); -} - - -#else /* HAVE_LZMA_H */ - static int xz_bidder_init(struct archive_read_filter *self) { - return (xz_lzma_bidder_init(self, ARCHIVE_COMPRESSION_XZ)); + self->code = ARCHIVE_COMPRESSION_XZ; + self->name = "xz"; + return (xz_lzma_bidder_init(self)); } static int lzma_bidder_init(struct archive_read_filter *self) { - return (xz_lzma_bidder_init(self, ARCHIVE_COMPRESSION_LZMA)); + self->code = ARCHIVE_COMPRESSION_LZMA; + self->name = "lzma"; + return (xz_lzma_bidder_init(self)); } /* * Setup the callbacks. */ static int -xz_lzma_bidder_init(struct archive_read_filter *self, int code) +xz_lzma_bidder_init(struct archive_read_filter *self) { static const size_t out_block_size = 64 * 1024; void *out_block; struct private_data *state; int ret; - self->code = code; - self->name = (code == ARCHIVE_COMPRESSION_XZ)?"xz": "lzma"; - state = (struct private_data *)calloc(sizeof(*state), 1); out_block = (unsigned char *)malloc(out_block_size); if (state == NULL || out_block == NULL) { @@ -296,7 +288,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self, int code) * maybe, it needs to check memory size which * running system has. */ - if (code == ARCHIVE_COMPRESSION_XZ) + if (self->code == ARCHIVE_COMPRESSION_XZ) ret = lzma_stream_decoder(&(state->stream), (1U << 23) + (1U << 21),/* memlimit */ LZMA_CONCATENATED); @@ -307,11 +299,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self, int code) if (ret == LZMA_OK) return (ARCHIVE_OK); - /* Library setup failed: Clean up. */ - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing lzma library"); - - /* Override the error message if we know what really went wrong. */ + /* Library setup failed: Choose an error message and clean up. */ switch (ret) { case LZMA_MEM_ERROR: archive_set_error(&self->archive->archive, ENOMEM, @@ -324,6 +312,10 @@ xz_lzma_bidder_init(struct archive_read_filter *self, int code) "Internal error initializing compression library: " "Invalid or unsupported options"); break; + default: + archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing lzma library"); + break; } free(state->out_block); @@ -339,12 +331,11 @@ static ssize_t xz_filter_read(struct archive_read_filter *self, const void **p) { struct private_data *state; - size_t read_avail, decompressed; - const void *read_buf; + size_t decompressed; + ssize_t avail_in; int ret; state = (struct private_data *)self->data; - read_avail = 0; /* Empty our output buffer. */ state->stream.next_out = state->out_block; @@ -352,79 +343,68 @@ xz_filter_read(struct archive_read_filter *self, const void **p) /* Try to fill the output buffer. */ while (state->stream.avail_out > 0 && !state->eof) { - /* If the last upstream block is done, get another one. */ - if (state->stream.avail_in == 0) { - read_buf = __archive_read_filter_ahead(self->upstream, - 1, &ret); - if (ret == 0) { - state->eof = 1; - break; - } - if (read_buf == NULL || ret < 0) - return (ARCHIVE_FATAL); - /* stream.next_in is really const, but lzma - * doesn't declare it so. */ - state->stream.next_in - = (unsigned char *)(uintptr_t)read_buf; - state->stream.avail_in = ret; - __archive_read_filter_consume(self->upstream, ret); - } + state->stream.next_in = + __archive_read_filter_ahead(self->upstream, 1, &avail_in); + if (state->stream.next_in == NULL && avail_in < 0) + return (ARCHIVE_FATAL); + state->stream.avail_in = avail_in; /* Decompress as much as we can in one pass. */ ret = lzma_code(&(state->stream), (state->stream.avail_in == 0)? LZMA_FINISH: LZMA_RUN); switch (ret) { case LZMA_STREAM_END: /* Found end of stream. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); state->eof = 1; + break; case LZMA_OK: /* Decompressor made some progress. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); break; case LZMA_MEM_ERROR: archive_set_error(&self->archive->archive, ENOMEM, - "Internal error decompressing compression library: " - "Cannot allocate memory"); + "Lzma library error: Cannot allocate memory"); return (ARCHIVE_FATAL); case LZMA_MEMLIMIT_ERROR: archive_set_error(&self->archive->archive, ENOMEM, - "Internal error decompressing compression library: " - "Memory usage limit was reached"); + "Lzma library error: Out of memory"); return (ARCHIVE_FATAL); case LZMA_FORMAT_ERROR: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error decompressing compression library: " - "File format not recognized"); + "Lzma library error: format not recognized"); return (ARCHIVE_FATAL); case LZMA_OPTIONS_ERROR: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error decompressing compression library: " - "Invalid or unsupported options"); + "Lzma library error: Invalid options"); return (ARCHIVE_FATAL); case LZMA_DATA_ERROR: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error decompressing compression library: " - "Data is corrupt"); + "Lzma library error: Corrupted input data"); return (ARCHIVE_FATAL); case LZMA_BUF_ERROR: archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error decompressing compression library: " - "No progress is possible"); + "Lzma library error: No progress is possible"); return (ARCHIVE_FATAL); default: /* Return an error. */ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "%s decompression failed", - self->archive->archive.compression_name); + "Lzma decompression failed: Unknown error"); return (ARCHIVE_FATAL); } } - *p = state->out_block; decompressed = state->stream.next_out - state->out_block; state->total_out += decompressed; + if (decompressed == 0) + *p = NULL; + else + *p = state->out_block; return (decompressed); } @@ -443,4 +423,204 @@ xz_filter_close(struct archive_read_filter *self) return (ARCHIVE_OK); } +#else + +#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC + +/* + * If we have the older liblzmadec library, then we can handle + * LZMA streams but not XZ streams. + */ + +/* + * Setup the callbacks. + */ +static int +lzma_bidder_init(struct archive_read_filter *self) +{ + static const size_t out_block_size = 64 * 1024; + void *out_block; + struct private_data *state; + ssize_t ret, avail_in; + + self->code = ARCHIVE_COMPRESSION_LZMA; + self->name = "lzma"; + + state = (struct private_data *)calloc(sizeof(*state), 1); + out_block = (unsigned char *)malloc(out_block_size); + if (state == NULL || out_block == NULL) { + archive_set_error(&self->archive->archive, ENOMEM, + "Can't allocate data for lzma decompression"); + free(out_block); + free(state); + return (ARCHIVE_FATAL); + } + + self->data = state; + state->out_block_size = out_block_size; + state->out_block = out_block; + self->read = lzma_filter_read; + self->skip = NULL; /* not supported */ + self->close = lzma_filter_close; + + /* Prime the lzma library with 18 bytes of input. */ + state->stream.next_in = (unsigned char *)(uintptr_t) + __archive_read_filter_ahead(self->upstream, 18, &avail_in); + if (state->stream.next_in == NULL) + return (ARCHIVE_FATAL); + state->stream.avail_in = avail_in; + state->stream.next_out = state->out_block; + state->stream.avail_out = state->out_block_size; + + /* Initialize compression library. */ + ret = lzmadec_init(&(state->stream)); + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); + if (ret == LZMADEC_OK) + return (ARCHIVE_OK); + + /* Library setup failed: Clean up. */ + archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, + "Internal error initializing lzma library"); + + /* Override the error message if we know what really went wrong. */ + switch (ret) { + case LZMADEC_HEADER_ERROR: + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Internal error initializing compression library: " + "invalid header"); + break; + case LZMADEC_MEM_ERROR: + archive_set_error(&self->archive->archive, ENOMEM, + "Internal error initializing compression library: " + "out of memory"); + break; + } + + free(state->out_block); + free(state); + self->data = NULL; + return (ARCHIVE_FATAL); +} + +/* + * Return the next block of decompressed data. + */ +static ssize_t +lzma_filter_read(struct archive_read_filter *self, const void **p) +{ + struct private_data *state; + size_t decompressed; + ssize_t avail_in, ret; + + state = (struct private_data *)self->data; + + /* Empty our output buffer. */ + state->stream.next_out = state->out_block; + state->stream.avail_out = state->out_block_size; + + /* Try to fill the output buffer. */ + while (state->stream.avail_out > 0 && !state->eof) { + state->stream.next_in = (unsigned char *)(uintptr_t) + __archive_read_filter_ahead(self->upstream, 1, &avail_in); + if (state->stream.next_in == NULL) { + if (avail_in < 0) + return (ARCHIVE_FATAL); + state->eof = 1; +// break; + } + state->stream.avail_in = avail_in; + + /* Decompress as much as we can in one pass. */ + ret = lzmadec_decode(&(state->stream), avail_in == 0); + switch (ret) { + case LZMADEC_STREAM_END: /* Found end of stream. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); + state->eof = 1; + break; + case LZMADEC_OK: /* Decompressor made some progress. */ + __archive_read_filter_consume(self->upstream, + avail_in - state->stream.avail_in); + break; + case LZMADEC_BUF_ERROR: /* Insufficient input data? */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Insufficient compressed data"); + return (ARCHIVE_FATAL); + default: + /* Return an error. */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_MISC, + "Lzma decompression failed"); + return (ARCHIVE_FATAL); + } + } + + decompressed = state->stream.next_out - state->out_block; + state->total_out += decompressed; + if (decompressed == 0) + *p = NULL; + else + *p = state->out_block; + return (decompressed); +} + +/* + * Clean up the decompressor. + */ +static int +lzma_filter_close(struct archive_read_filter *self) +{ + struct private_data *state; + int ret; + + state = (struct private_data *)self->data; + ret = ARCHIVE_OK; + switch (lzmadec_end(&(state->stream))) { + case LZMADEC_OK: + break; + default: + archive_set_error(&(self->archive->archive), + ARCHIVE_ERRNO_MISC, + "Failed to clean up %s compressor", + self->archive->archive.compression_name); + ret = ARCHIVE_FATAL; + } + + free(state->out_block); + free(state); + return (ret); +} + +#else + +/* + * + * If we have no suitable library on this system, we can't actually do + * the decompression. We can, however, still detect compressed + * archives and emit a useful message. + * + */ +static int +lzma_bidder_init(struct archive_read_filter *filter) +{ + archive_set_error(&filter->archive->archive, -1, + "This version of libarchive was compiled without lzma support"); + return (ARCHIVE_FATAL); +} + +#endif /* HAVE_LZMADEC_H */ + + +static int +xz_bidder_init(struct archive_read_filter *filter) +{ + archive_set_error(&filter->archive->archive, -1, + "This version of libarchive was compiled without xz support"); + return (ARCHIVE_FATAL); +} + + #endif /* HAVE_LZMA_H */