aboutsummaryrefslogtreecommitdiff
path: root/src/xz/coder.c
diff options
context:
space:
mode:
authorLasse Collin <lasse.collin@tukaani.org>2022-10-08 21:28:15 +0300
committerLasse Collin <lasse.collin@tukaani.org>2022-11-09 14:28:41 +0200
commit3176f992c55b8d788c4633809aaf9447376a5a12 (patch)
treea08fb57cecafafb4d41bd1b2df3007d61aff513d /src/xz/coder.c
parentliblzma: Add .lz support to lzma_auto_decoder(). (diff)
downloadxz-3176f992c55b8d788c4633809aaf9447376a5a12.tar.xz
xz: Add .lz (lzip) decompression support.
If configured with --disable-lzip-decoder then --long-help will still list `lzip' in --format but I left it like that since due to translations it would be messy to have two help strings. Features are disabled only in special situations so wrong help in such a situation shouldn't matter much. Thanks to Michał Górny for the original patch.
Diffstat (limited to '')
-rw-r--r--src/xz/coder.c68
1 files changed, 65 insertions, 3 deletions
diff --git a/src/xz/coder.c b/src/xz/coder.c
index 5bca958f..05f22888 100644
--- a/src/xz/coder.c
+++ b/src/xz/coder.c
@@ -51,6 +51,11 @@ static lzma_check check;
/// This becomes false if the --check=CHECK option is used.
static bool check_default = true;
+/// Indicates if unconsumed input is allowed to remain after
+/// decoding has successfully finished. This is set for each file
+/// in coder_init().
+static bool allow_trailing_input;
+
#ifdef MYTHREAD_ENABLED
static lzma_mt mt_options = {
.flags = 0,
@@ -136,6 +141,11 @@ memlimit_too_small(uint64_t memory_usage)
extern void
coder_set_compression_settings(void)
{
+#ifdef HAVE_LZIP_DECODER
+ // .lz compression isn't supported.
+ assert(opt_format != FORMAT_LZIP);
+#endif
+
// The default check type is CRC64, but fallback to CRC32
// if CRC64 isn't supported by the copy of liblzma we are
// using. CRC32 is always supported.
@@ -470,6 +480,18 @@ is_format_lzma(void)
return true;
}
+
+
+#ifdef HAVE_LZIP_DECODER
+/// Return true if the data in in_buf seems to be in the .lz format.
+static bool
+is_format_lzip(void)
+{
+ static const uint8_t magic[4] = { 0x4C, 0x5A, 0x49, 0x50 };
+ return strm.avail_in >= sizeof(magic)
+ && memcmp(in_buf.u8, magic, sizeof(magic)) == 0;
+}
+#endif
#endif
@@ -483,6 +505,12 @@ coder_init(file_pair *pair)
{
lzma_ret ret = LZMA_PROG_ERROR;
+ // In most cases if there is input left when coding finishes,
+ // something has gone wrong. Exceptions are --single-stream
+ // and decoding .lz files which can contain trailing non-.lz data.
+ // These will be handled later in this function.
+ allow_trailing_input = false;
+
if (opt_mode == MODE_COMPRESS) {
#ifdef HAVE_ENCODERS
switch (opt_format) {
@@ -506,6 +534,14 @@ coder_init(file_pair *pair)
ret = lzma_alone_encoder(&strm, filters[0].options);
break;
+# ifdef HAVE_LZIP_DECODER
+ case FORMAT_LZIP:
+ // args.c should disallow this.
+ assert(0);
+ ret = LZMA_PROG_ERROR;
+ break;
+# endif
+
case FORMAT_RAW:
ret = lzma_raw_encoder(&strm, filters);
break;
@@ -522,7 +558,9 @@ coder_init(file_pair *pair)
else
flags |= LZMA_TELL_UNSUPPORTED_CHECK;
- if (!opt_single_stream)
+ if (opt_single_stream)
+ allow_trailing_input = true;
+ else
flags |= LZMA_CONCATENATED;
// We abuse FORMAT_AUTO to indicate unknown file format,
@@ -531,8 +569,14 @@ coder_init(file_pair *pair)
switch (opt_format) {
case FORMAT_AUTO:
+ // .lz is checked before .lzma since .lzma detection
+ // is more complicated (no magic bytes).
if (is_format_xz())
init_format = FORMAT_XZ;
+# ifdef HAVE_LZIP_DECODER
+ else if (is_format_lzip())
+ init_format = FORMAT_LZIP;
+# endif
else if (is_format_lzma())
init_format = FORMAT_LZMA;
break;
@@ -547,6 +591,13 @@ coder_init(file_pair *pair)
init_format = FORMAT_LZMA;
break;
+# ifdef HAVE_LZIP_DECODER
+ case FORMAT_LZIP:
+ if (is_format_lzip())
+ init_format = FORMAT_LZIP;
+ break;
+# endif
+
case FORMAT_RAW:
init_format = FORMAT_RAW;
break;
@@ -604,6 +655,15 @@ coder_init(file_pair *pair)
MODE_DECOMPRESS));
break;
+# ifdef HAVE_LZIP_DECODER
+ case FORMAT_LZIP:
+ allow_trailing_input = true;
+ ret = lzma_lzip_decoder(&strm,
+ hardware_memlimit_get(
+ MODE_DECOMPRESS), flags);
+ break;
+# endif
+
case FORMAT_RAW:
// Memory usage has already been checked in
// coder_set_compression_settings().
@@ -864,7 +924,7 @@ coder_normal(file_pair *pair)
}
if (ret == LZMA_STREAM_END) {
- if (opt_single_stream) {
+ if (allow_trailing_input) {
io_fix_src_pos(pair, strm.avail_in);
success = true;
break;
@@ -872,7 +932,9 @@ coder_normal(file_pair *pair)
// Check that there is no trailing garbage.
// This is needed for LZMA_Alone and raw
- // streams.
+ // streams. This is *not* done with .lz files
+ // as that format specifically requires
+ // allowing trailing garbage.
if (strm.avail_in == 0 && !pair->src_eof) {
// Try reading one more byte.
// Hopefully we don't get any more