]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Since the most popular XZ decompression library also supports LZMA,
authorTim Kientzle <kientzle@gmail.com>
Sun, 8 Mar 2009 08:42:26 +0000 (04:42 -0400)
committerTim Kientzle <kientzle@gmail.com>
Sun, 8 Mar 2009 08:42:26 +0000 (04:42 -0400)
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

CMakeLists.txt
Makefile.am
libarchive/Makefile
libarchive/archive_read_support_compression_lzma.c [deleted file]
libarchive/archive_read_support_compression_xz.c

index 15de2aede5e704cd0d096578396afa8680d12047..c973e58b4fabc4fde32bd592d5fecbde0809bc10 100644 (file)
@@ -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
index b17e6bab8d08d64d84e2459467835fa00fdb7d4b..760dae5b6414e8b25aee73d971a5be31e8f70243 100644 (file)
@@ -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             \
index 5eb171cebc0abf3d6303736c4fb76d7df08f6291..5897710f0b70e57e62d44b98b8854c076d6f2723 100644 (file)
@@ -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 (file)
index 9a93902..0000000
+++ /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 <errno.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_LZMADEC_H
-#include <lzmadec.h>
-#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.
- *
- * <sigh> 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.  <sigh>
-        * 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. <sigh> */
-                       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 */
index be238ac55c9cc3ec3e3715b4d27b67d924bc09a0..2cdac6e51b19aea8beff69294ab09b868daeb72c 100644 (file)
@@ -41,15 +41,18 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-#ifdef HAVE_LZMA_H
+#if HAVE_LZMA_H
 #include <lzma.h>
+#elif HAVE_LZMADEC_H
+#include <lzmadec.h>
 #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.
- *
  * <sigh> 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. <sigh> */
-                       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 */