summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS8
-rw-r--r--ChangeLog43
-rw-r--r--INSTALL22
-rw-r--r--Makefile.in9
-rw-r--r--NEWS32
-rw-r--r--README80
-rw-r--r--carg_parser.c26
-rw-r--r--carg_parser.h66
-rwxr-xr-xconfigure25
-rw-r--r--decoder.c38
-rw-r--r--decoder.h47
-rw-r--r--doc/lunzip.129
-rw-r--r--list.c55
-rw-r--r--lzip.h105
-rw-r--r--lzip_index.c113
-rw-r--r--lzip_index.h25
-rw-r--r--main.c295
-rwxr-xr-xtestsuite/check.sh104
-rw-r--r--testsuite/fox.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_bcrc.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_crc0.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_das46.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_de20.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_mes81.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_s11.lzbin0 -> 80 bytes
-rw-r--r--testsuite/fox_v2.lzbin0 -> 80 bytes
-rw-r--r--testsuite/test_em.txt.lzbin0 -> 14024 bytes
27 files changed, 612 insertions, 510 deletions
diff --git a/AUTHORS b/AUTHORS
index d3cc828..e39119d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,7 +1,7 @@
Lunzip was written by Antonio Diaz Diaz.
The ideas embodied in lunzip are due to (at least) the following people:
-Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
-the definition of Markov chains), G.N.N. Martin (for the definition of
-range encoding), Igor Pavlov (for putting all the above together in
-LZMA), and Julian Seward (for bzip2's CLI).
+Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the
+definition of Markov chains), G.N.N. Martin (for the definition of range
+encoding), Igor Pavlov (for putting all the above together in LZMA), and
+Julian Seward (for bzip2's CLI).
diff --git a/ChangeLog b/ChangeLog
index ba6ef85..08e3c0a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,19 @@
+2021-01-01 Antonio Diaz Diaz <antonio@gnu.org>
+
+ * Version 1.12 released.
+ * main.c (main): Report an error if a file name is empty.
+ Make '-o' behave like '-c', but writing to file instead of stdout.
+ Do not open output if input is a terminal.
+ * Replace 'decompressed', 'compressed' with 'out', 'in' in output.
+ * lzip_index.c: Improve messages for corruption in last header.
+ * main.c: Set a valid invocation_name even if argc == 0.
+ * Document extraction from tar.lz in '--help' output and man page.
+ * testsuite: Add 9 new test files.
+
2019-01-01 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.11 released.
- * File_* renamed to Lzip_*.
+ * Rename File_* to Lzip_*.
* lzip.h (Lzip_trailer): New function 'Lt_verify_consistency'.
* lzip_index.c: Detect some kinds of corrupt trailers.
* main.c (main): Check return value of close( infd ).
@@ -12,10 +24,10 @@
2018-02-05 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.10 released.
- * main.c: Added new option '--loose-trailing'.
- * Improved corrupt header detection to HD=3.
+ * main.c: New option '--loose-trailing'.
+ * Improve corrupt header detection to HD=3.
* main.c: Show corrupt or truncated header in multimember file.
- * Replaced 'bits/byte' with inverse compression ratio in output.
+ * Replace 'bits/byte' with inverse compression ratio in output.
* Show progress of decompression at verbosity level 2 (-vv).
* Show progress of decompression only if stderr is a terminal.
* main.c: Show final diagnostic when testing multiple files.
@@ -31,16 +43,16 @@
* main.c: Continue testing if any input file is a terminal.
* main.c: Show trailing data in both hexadecimal and ASCII.
* lzip_index.c: Improve detection of bad dict and trailing data.
- * lzip.h: Unified messages for bad magic, trailing data, etc.
+ * lzip.h: Unify messages for bad magic, trailing data, etc.
2016-05-12 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.8 released.
- * main.c: Added new option '-a, --trailing-error'.
+ * main.c: New option '-a, --trailing-error'.
* main.c (main): With '-u', verify that output file is regular.
* main.c (decompress): Print up to 6 bytes of trailing data
when '-vvvv' is specified.
- * decoder.c (LZd_verify_trailer): Removed test of final code.
+ * decoder.c (LZd_verify_trailer): Remove test of final code.
* main.c (main): Delete '--output' file if infd is a terminal.
* main.c (main): Don't use stdin more than once.
* Error messages synced with lzip-1.18.
@@ -52,17 +64,17 @@
* Version 1.7 released.
* Minor changes.
- * Makefile.in: Added new targets 'install*-compress'.
+ * Makefile.in: New targets 'install*-compress'.
2014-07-01 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.6 released.
- * License changed to GPL version 2 or later.
+ * Change license to GPL version 2 or later.
2014-04-11 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.5 released.
- * main.c: Added new option '-u, --buffer-size' (low memory mode).
+ * main.c: New option '-u, --buffer-size' (low memory mode).
* main.c (close_and_set_permissions): Behave like 'cp -p'.
2013-09-17 Antonio Diaz Diaz <antonio@gnu.org>
@@ -83,8 +95,7 @@
* Version 1.2 released.
* Decompression time has been reduced by 12%.
- * Makefile.in: Added new target 'install-as-lzip'.
- * Makefile.in: Added new target 'install-bin'.
+ * Makefile.in: New targets 'install-as-lzip' and 'install-bin'.
* main.c: Use 'setmode' instead of '_setmode' on Windows and OS/2.
2012-02-26 Antonio Diaz Diaz <ant_diaz@teleline.es>
@@ -94,8 +105,8 @@
multi-member file when only one '-v' is specified.
* main.c (close_and_set_permissions): Inability to change output
file attributes has been downgraded from error to warning.
- * Changed quote characters in messages as advised by GNU Standards.
- * configure: 'datadir' renamed to 'datarootdir'.
+ * Change quote characters in messages as advised by GNU Standards.
+ * configure: Rename 'datadir' to 'datarootdir'.
2011-01-17 Antonio Diaz Diaz <ant_diaz@teleline.es>
@@ -104,8 +115,8 @@
* Created from the decompression code of clzip 1.1.
-Copyright (C) 2010-2019 Antonio Diaz Diaz.
+Copyright (C) 2010-2021 Antonio Diaz Diaz.
This file is a collection of facts, and thus it is not copyrightable,
-but just in case, you have unlimited permission to copy, distribute and
+but just in case, you have unlimited permission to copy, distribute, and
modify it.
diff --git a/INSTALL b/INSTALL
index 2652bad..313b7dc 100644
--- a/INSTALL
+++ b/INSTALL
@@ -1,7 +1,7 @@
Requirements
------------
-You will need a C compiler.
-I use gcc 5.3.0 and 4.1.2, but the code should compile with any standards
+You will need a C99 compiler. (gcc 3.3.6 or newer is recommended).
+I use gcc 6.1.0 and 4.1.2, but the code should compile with any standards
compliant compiler.
Gcc is available at http://gcc.gnu.org.
@@ -41,11 +41,11 @@ the main archive.
documentation.
Or type 'make install-compress', which additionally compresses the
- man page after installation. (Installing compressed docs may become
- the default in the future).
+ man page after installation.
+ (Installing compressed docs may become the default in the future).
- You can install only the program or the man page by typing 'make
- install-bin' or 'make install-man' respectively.
+ You can install only the program or the man page by typing
+ 'make install-bin' or 'make install-man' respectively.
Instead of 'make install', you can type 'make install-as-lzip' to
install the program and any data files and documentation, and link
@@ -55,10 +55,10 @@ the main archive.
Another way
-----------
You can also compile lunzip into a separate directory.
-To do this, you must use a version of 'make' that supports the 'VPATH'
-variable, such as GNU 'make'. 'cd' to the directory where you want the
+To do this, you must use a version of 'make' that supports the variable
+'VPATH', such as GNU 'make'. 'cd' to the directory where you want the
object files and executables to go and run the 'configure' script.
-'configure' automatically checks for the source code in '.', in '..' and
+'configure' automatically checks for the source code in '.', in '..', and
in the directory that 'configure' is in.
'configure' recognizes the option '--srcdir=DIR' to control where to
@@ -69,7 +69,7 @@ After running 'configure', you can run 'make' and 'make install' as
explained above.
-Copyright (C) 2010-2019 Antonio Diaz Diaz.
+Copyright (C) 2010-2021 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy,
-distribute and modify it.
+distribute, and modify it.
diff --git a/Makefile.in b/Makefile.in
index 691bd14..aff94d4 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -71,7 +71,7 @@ install-info :
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
-if $(CAN_RUN_INSTALLINFO) ; then \
- install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
+ install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
fi
install-info-compress : install-info
@@ -96,7 +96,7 @@ uninstall-bin :
uninstall-info :
-if $(CAN_RUN_INSTALLINFO) ; then \
- install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
+ install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
fi
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
@@ -119,7 +119,10 @@ dist : doc
$(DISTNAME)/*.c \
$(DISTNAME)/testsuite/check.sh \
$(DISTNAME)/testsuite/test.txt \
- $(DISTNAME)/testsuite/test.txt.lz
+ $(DISTNAME)/testsuite/fox.lz \
+ $(DISTNAME)/testsuite/fox_*.lz \
+ $(DISTNAME)/testsuite/test.txt.lz \
+ $(DISTNAME)/testsuite/test_em.txt.lz
rm -f $(DISTNAME)
lzip -v -9 $(DISTNAME).tar
diff --git a/NEWS b/NEWS
index d49ddba..98e59f3 100644
--- a/NEWS
+++ b/NEWS
@@ -1,14 +1,28 @@
-Changes in version 1.11:
+Changes in version 1.12:
-Detection of forbidden combinations of characters in trailing data has
-been improved.
+Lunzip now reports an error if a file name is empty (lunzip -t "").
-Errors are now also checked when closing the input file.
+Option '-o, --output' now behaves like '-c, --stdout', but sending the
+output unconditionally to a file instead of to standard output. See the new
+description of '-o' in the manual. This change is backwards compatible only
+when decompressing from standard input alone. Therefore commands like:
+ lunzip -d -o foo - bar.lz < foo.lz
+must now be split into:
+ lunzip -d -o foo - < foo.lz
+ lunzip -d bar.lz
+or rewritten as:
+ lunzip -d - bar.lz < foo.lz > foo
-Lunzip now compiles on DOS with DJGPP. (Patch from Robert Riebisch).
+Lunzip now does not even open the output file if the input file is a terminal.
-The configure script now accepts appending options to CFLAGS using the
-syntax 'CFLAGS+=OPTIONS'.
+The words 'decompressed' and 'compressed' have been replaced with the
+shorter 'out' and 'in' in the verbose output when decompressing or testing.
-It has been documented in INSTALL the use of
-CFLAGS+='-D __USE_MINGW_ANSI_STDIO' when compiling on MinGW.
+Option '--list' now reports corruption or truncation of the last header in a
+multimenber file specifically instead of showing the generic message "Last
+member in input file is truncated or corrupt."
+
+The commands needed to extract files from a tar.lz archive have been
+documented in the output of '--help' and in the man page.
+
+9 new test files have been added to the testsuite.
diff --git a/README b/README
index b86ff58..b09c908 100644
--- a/README
+++ b/README
@@ -1,53 +1,57 @@
Description
-Lunzip is a decompressor for the lzip format. It is written in C and its
-small size makes it well suited for embedded devices or software
-installers that need to decompress files but don't need compression
-capabilities. Lunzip is fully compatible with lzip-1.4 or newer.
+Lunzip is a decompressor for the lzip format written in C. Its small size
+makes it well suited for embedded devices or software installers that need
+to decompress files but don't need compression capabilities. Lunzip is fully
+compatible with lzip 1.4 or newer.
The lzip file format is designed for data sharing and long-term archiving,
taking into account both data integrity and decoder availability:
* The lzip format provides very safe integrity checking and some data
- recovery means. The lziprecover program can repair bit flip errors
- (one of the most common forms of data corruption) in lzip files,
- and provides data recovery capabilities, including error-checked
- merging of damaged copies of a file.
-
- * The lzip format is as simple as possible (but not simpler). The
- lzip manual provides the source code of a simple decompressor
- along with a detailed explanation of how it works, so that with
- the only help of the lzip manual it would be possible for a
- digital archaeologist to extract the data from a lzip file long
- after quantum computers eventually render LZMA obsolete.
+ recovery means. The program lziprecover can repair bit flip errors
+ (one of the most common forms of data corruption) in lzip files, and
+ provides data recovery capabilities, including error-checked merging
+ of damaged copies of a file.
+
+ * The lzip format is as simple as possible (but not simpler). The lzip
+ manual provides the source code of a simple decompressor along with a
+ detailed explanation of how it works, so that with the only help of the
+ lzip manual it would be possible for a digital archaeologist to extract
+ the data from a lzip file long after quantum computers eventually
+ render LZMA obsolete.
* Additionally the lzip reference implementation is copylefted, which
guarantees that it will remain free forever.
-A nice feature of the lzip format is that a corrupt byte is easier to
-repair the nearer it is from the beginning of the file. Therefore, with
-the help of lziprecover, losing an entire archive just because of a
-corrupt byte near the beginning is a thing of the past.
+A nice feature of the lzip format is that a corrupt byte is easier to repair
+the nearer it is from the beginning of the file. Therefore, with the help of
+lziprecover, losing an entire archive just because of a corrupt byte near
+the beginning is a thing of the past.
-Lunzip uses the same well-defined exit status values used by lzip, which
+Lunzip uses the same well-defined exit status values used by bzip2, which
makes it safer than decompressors returning ambiguous warning values (like
gunzip) when it is used as a back end for other programs like tar or zutils.
Lunzip provides a 'low memory' mode able to decompress any file using as
little memory as 50 kB, irrespective of the dictionary size used to
compress the file. To activate it, specify the size of the output buffer
-with the '--buffer-size' option and lunzip will use the decompressed
+with the option '--buffer-size' and lunzip will use the decompressed
file as dictionary for distances beyond the buffer size. Of course, the
-smaller the buffer size used in relation to the dictionary size, the
+larger the difference between the buffer size and the dictionary size, the
more accesses to disk are needed and the slower the decompression is.
This 'low memory' mode only works when decompressing to a regular file
and is intended for systems without enough memory (RAM + swap) to keep
the whole dictionary at once. It has been tested on a laptop with a 486
processor and 4 MiB of RAM.
-The amount of memory required by lunzip to decompress a file is about
-46 kB larger than the dictionary size used to compress that file, unless
-the '--buffer-size' option is specified.
+The option '--buffer-size' may help to decompress a file erroneously created
+with a dictionary size much larger than the uncompressed size. (Lzip adjusts
+the dictionary size to the uncompressed size, but third-party tools may not).
+
+The amount of memory required by lunzip to decompress a file is about 46 kB
+larger than the dictionary size used to compress that file, unless
+'--buffer-size' is specified.
Lunzip attempts to guess the name for the decompressed file from that of
the compressed file as follows:
@@ -62,12 +66,12 @@ possible, ownership of the file just as 'cp -p' does. (If the user ID or
the group ID can't be duplicated, the file permission bits S_ISUID and
S_ISGID are cleared).
-Lunzip is able to read from some types of non regular files if the
-'--stdout' option is specified.
+Lunzip is able to read from some types of non-regular files if either the
+option '-c' or the option '-o' is specified.
-If no file names are specified, lunzip decompresses from standard input
-to standard output. In this case, lunzip will decline to read compressed
-input from a terminal.
+If no file names are specified, lunzip decompresses from standard input to
+standard output. In this case, lunzip will refuse to read compressed input
+from a terminal, as this might leave the terminal in an abnormal state.
Lunzip will correctly decompress a file which is the concatenation of two or
more compressed files. The result is the concatenation of the corresponding
@@ -75,16 +79,20 @@ decompressed files. Integrity testing of concatenated compressed files is
also supported.
The ideas embodied in lunzip are due to (at least) the following people:
-Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
-the definition of Markov chains), G.N.N. Martin (for the definition of
-range encoding), Igor Pavlov (for putting all the above together in
-LZMA), and Julian Seward (for bzip2's CLI).
+Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the
+definition of Markov chains), G.N.N. Martin (for the definition of range
+encoding), Igor Pavlov (for putting all the above together in LZMA), and
+Julian Seward (for bzip2's CLI).
+
+LANGUAGE NOTE: Uncompressed = not compressed = plain data; it may never have
+been compressed. Decompressed is used to refer to data which have undergone
+the process of decompression.
-Copyright (C) 2010-2019 Antonio Diaz Diaz.
+Copyright (C) 2010-2021 Antonio Diaz Diaz.
This file is free documentation: you have unlimited permission to copy,
-distribute and modify it.
+distribute, and modify it.
The file Makefile.in is a data file used by configure to produce the
Makefile. It has the same copyright owner and permissions that configure
diff --git a/carg_parser.c b/carg_parser.c
index ce01d7b..d0c05d5 100644
--- a/carg_parser.c
+++ b/carg_parser.c
@@ -1,20 +1,20 @@
-/* Arg_parser - POSIX/GNU command line argument parser. (C version)
- Copyright (C) 2006-2019 Antonio Diaz Diaz.
+/* Arg_parser - POSIX/GNU command line argument parser. (C version)
+ Copyright (C) 2006-2021 Antonio Diaz Diaz.
- This library is free software. Redistribution and use in source and
- binary forms, with or without modification, are permitted provided
- that the following conditions are met:
+ This library is free software. 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.
+ 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.
+ 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 library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include <stdlib.h>
diff --git a/carg_parser.h b/carg_parser.h
index dcae2de..c5f2352 100644
--- a/carg_parser.h
+++ b/carg_parser.h
@@ -1,44 +1,44 @@
-/* Arg_parser - POSIX/GNU command line argument parser. (C version)
- Copyright (C) 2006-2019 Antonio Diaz Diaz.
+/* Arg_parser - POSIX/GNU command line argument parser. (C version)
+ Copyright (C) 2006-2021 Antonio Diaz Diaz.
- This library is free software. Redistribution and use in source and
- binary forms, with or without modification, are permitted provided
- that the following conditions are met:
+ This library is free software. 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.
+ 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.
+ 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 library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-/* Arg_parser reads the arguments in 'argv' and creates a number of
- option codes, option arguments and non-option arguments.
+/* Arg_parser reads the arguments in 'argv' and creates a number of
+ option codes, option arguments, and non-option arguments.
- In case of error, 'ap_error' returns a non-null pointer to an error
- message.
+ In case of error, 'ap_error' returns a non-null pointer to an error
+ message.
- 'options' is an array of 'struct ap_Option' terminated by an element
- containing a code which is zero. A null name means a short-only
- option. A code value outside the unsigned char range means a
- long-only option.
+ 'options' is an array of 'struct ap_Option' terminated by an element
+ containing a code which is zero. A null name means a short-only
+ option. A code value outside the unsigned char range means a
+ long-only option.
- Arg_parser normally makes it appear as if all the option arguments
- were specified before all the non-option arguments for the purposes
- of parsing, even if the user of your program intermixed option and
- non-option arguments. If you want the arguments in the exact order
- the user typed them, call 'ap_init' with 'in_order' = true.
+ Arg_parser normally makes it appear as if all the option arguments
+ were specified before all the non-option arguments for the purposes
+ of parsing, even if the user of your program intermixed option and
+ non-option arguments. If you want the arguments in the exact order
+ the user typed them, call 'ap_init' with 'in_order' = true.
- The argument '--' terminates all options; any following arguments are
- treated as non-option arguments, even if they begin with a hyphen.
+ The argument '--' terminates all options; any following arguments are
+ treated as non-option arguments, even if they begin with a hyphen.
- The syntax for optional option arguments is '-<short_option><argument>'
- (without whitespace), or '--<long_option>=<argument>'.
+ The syntax for optional option arguments is '-<short_option><argument>'
+ (without whitespace), or '--<long_option>=<argument>'.
*/
#ifdef __cplusplus
@@ -79,11 +79,11 @@ void ap_free( struct Arg_parser * const ap );
const char * ap_error( const struct Arg_parser * const ap );
- /* The number of arguments parsed (may be different from argc) */
+/* The number of arguments parsed. May be different from argc. */
int ap_arguments( const struct Arg_parser * const ap );
- /* If ap_code( i ) is 0, ap_argument( i ) is a non-option.
- Else ap_argument( i ) is the option's argument (or empty). */
+/* If ap_code( i ) is 0, ap_argument( i ) is a non-option.
+ Else ap_argument( i ) is the option's argument (or empty). */
int ap_code( const struct Arg_parser * const ap, const int i );
const char * ap_argument( const struct Arg_parser * const ap, const int i );
diff --git a/configure b/configure
index 1098e99..54fb2fb 100755
--- a/configure
+++ b/configure
@@ -1,12 +1,12 @@
#! /bin/sh
# configure script for Lunzip - Decompressor for the lzip format
-# Copyright (C) 2010-2019 Antonio Diaz Diaz.
+# Copyright (C) 2010-2021 Antonio Diaz Diaz.
#
# This configure script is free software: you have unlimited permission
-# to copy, distribute and modify it.
+# to copy, distribute, and modify it.
pkgname=lunzip
-pkgversion=1.11
+pkgversion=1.12
progname=lunzip
srctrigger=doc/${progname}.1
@@ -26,11 +26,7 @@ CFLAGS='-Wall -W -O2'
LDFLAGS=
# checking whether we are using GNU C.
-/bin/sh -c "${CC} --version" > /dev/null 2>&1 ||
- {
- CC=cc
- CFLAGS=-O2
- }
+/bin/sh -c "${CC} --version" > /dev/null 2>&1 || { CC=cc ; CFLAGS=-O2 ; }
# Loop over all args
args=
@@ -42,11 +38,12 @@ while [ $# != 0 ] ; do
shift
# Add the argument quoted to args
- args="${args} \"${option}\""
+ if [ -z "${args}" ] ; then args="\"${option}\""
+ else args="${args} \"${option}\"" ; fi
# Split out the argument for options that take them
case ${option} in
- *=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
+ *=*) optarg=`echo "${option}" | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
esac
# Process the options
@@ -125,7 +122,7 @@ if [ -z "${srcdir}" ] ; then
if [ ! -r "${srcdir}/${srctrigger}" ] ; then srcdir=.. ; fi
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
## the sed command below emulates the dirname command
- srcdir=`echo $0 | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+ srcdir=`echo "$0" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
fi
fi
@@ -148,7 +145,7 @@ if [ -z "${no_create}" ] ; then
# Run this file to recreate the current configuration.
#
# This script is free software: you have unlimited permission
-# to copy, distribute and modify it.
+# to copy, distribute, and modify it.
exec /bin/sh $0 ${args} --no-create
EOF
@@ -170,11 +167,11 @@ echo "LDFLAGS = ${LDFLAGS}"
rm -f Makefile
cat > Makefile << EOF
# Makefile for Lunzip - Decompressor for the lzip format
-# Copyright (C) 2010-2019 Antonio Diaz Diaz.
+# Copyright (C) 2010-2021 Antonio Diaz Diaz.
# This file was generated automatically by configure. Don't edit.
#
# This Makefile is free software: you have unlimited permission
-# to copy, distribute and modify it.
+# to copy, distribute, and modify it.
pkgname = ${pkgname}
pkgversion = ${pkgversion}
diff --git a/decoder.c b/decoder.c
index 3095015..63d30ea 100644
--- a/decoder.c
+++ b/decoder.c
@@ -1,18 +1,18 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
@@ -104,9 +104,8 @@ void LZd_flush_data( struct LZ_decoder * const d )
writeblock( d->outfd, d->buffer + d->stream_pos, size ) != size )
{ show_error( "Write error", errno, false ); cleanup_and_fail( 1 ); }
if( d->pos >= d->buffer_size )
- { d->partial_data_pos += d->pos; d->pos = 0; d->pos_wrapped = true;
- if( d->partial_data_pos >= d->dictionary_size )
- d->pos_wrapped_dic = true; }
+ { d->partial_data_pos += d->pos; d->pos = 0;
+ if( d->partial_data_pos >= d->dictionary_size ) d->pos_wrapped = true; }
d->stream_pos = d->pos;
}
}
@@ -173,16 +172,15 @@ static bool LZd_verify_trailer( struct LZ_decoder * const d,
{
if( verbosity >= 4 ) show_header( d->dictionary_size );
if( data_size == 0 || member_size == 0 )
- fputs( "no data compressed. ", stderr );
+ fputs( "no data compressed. ", stderr );
else
- fprintf( stderr, "%6.3f:1, %5.2f%% ratio, %5.2f%% saved. ",
+ fprintf( stderr, "%6.3f:1, %5.2f%% ratio, %5.2f%% saved. ",
(double)data_size / member_size,
( 100.0 * member_size ) / data_size,
100.0 - ( ( 100.0 * member_size ) / data_size ) );
if( verbosity >= 4 ) fprintf( stderr, "CRC %08X, ", td_crc );
if( verbosity >= 3 )
- fprintf( stderr, "decompressed %9llu, compressed %8llu. ",
- data_size, member_size );
+ fprintf( stderr, "%9llu out, %8llu in. ", data_size, member_size );
}
return true;
}
@@ -320,7 +318,7 @@ int LZd_decode_member( struct LZ_decoder * const d,
rep3 = rep2; rep2 = rep1; rep1 = rep0; rep0 = distance;
state = St_set_match( state );
if( rep0 >= d->dictionary_size ||
- ( rep0 >= LZd_data_position( d ) && !d->pos_wrapped_dic ) )
+ ( !d->pos_wrapped && rep0 >= LZd_data_position( d ) ) )
{ LZd_flush_data( d ); return 1; }
}
copy_block( d, rep0, len );
diff --git a/decoder.h b/decoder.h
index ba4adb0..0fe0110 100644
--- a/decoder.h
+++ b/decoder.h
@@ -1,18 +1,18 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
enum { rd_buffer_size = 16384 };
@@ -107,7 +107,7 @@ static inline unsigned Rd_decode( struct Range_decoder * const rdec,
/* symbol <<= 1; */
/* if( rdec->code >= rdec->range ) { rdec->code -= rdec->range; symbol |= 1; } */
bit = ( rdec->code >= rdec->range );
- symbol = ( symbol << 1 ) + bit;
+ symbol <<= 1; symbol += bit;
rdec->code -= rdec->range & ( 0U - bit );
}
return symbol;
@@ -137,8 +137,7 @@ static inline unsigned Rd_decode_bit( struct Range_decoder * const rdec,
static inline unsigned Rd_decode_tree3( struct Range_decoder * const rdec,
Bit_model bm[] )
{
- unsigned symbol = 1;
- symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
+ unsigned symbol = 2 | Rd_decode_bit( rdec, &bm[1] );
symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
return symbol & 7;
@@ -147,8 +146,7 @@ static inline unsigned Rd_decode_tree3( struct Range_decoder * const rdec,
static inline unsigned Rd_decode_tree6( struct Range_decoder * const rdec,
Bit_model bm[] )
{
- unsigned symbol = 1;
- symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
+ unsigned symbol = 2 | Rd_decode_bit( rdec, &bm[1] );
symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
symbol = ( symbol << 1 ) | Rd_decode_bit( rdec, &bm[symbol] );
@@ -177,7 +175,7 @@ Rd_decode_tree_reversed( struct Range_decoder * const rdec,
for( i = 0; i < num_bits; ++i )
{
const unsigned bit = Rd_decode_bit( rdec, &bm[model] );
- model = ( model << 1 ) + bit;
+ model <<= 1; model += bit;
symbol |= ( bit << i );
}
return symbol;
@@ -187,12 +185,9 @@ static inline unsigned
Rd_decode_tree_reversed4( struct Range_decoder * const rdec, Bit_model bm[] )
{
unsigned symbol = Rd_decode_bit( rdec, &bm[1] );
- unsigned model = 2 + symbol;
- unsigned bit = Rd_decode_bit( rdec, &bm[model] );
- model = ( model << 1 ) + bit; symbol |= ( bit << 1 );
- bit = Rd_decode_bit( rdec, &bm[model] );
- model = ( model << 1 ) + bit; symbol |= ( bit << 2 );
- symbol |= ( Rd_decode_bit( rdec, &bm[model] ) << 3 );
+ symbol += Rd_decode_bit( rdec, &bm[2+symbol] ) << 1;
+ symbol += Rd_decode_bit( rdec, &bm[4+symbol] ) << 2;
+ symbol += Rd_decode_bit( rdec, &bm[8+symbol] ) << 3;
return symbol;
}
@@ -205,7 +200,7 @@ static inline unsigned Rd_decode_matched( struct Range_decoder * const rdec,
{
const unsigned match_bit = ( match_byte <<= 1 ) & mask;
const unsigned bit = Rd_decode_bit( rdec, &bm[symbol+match_bit+mask] );
- symbol = ( symbol << 1 ) + bit;
+ symbol <<= 1; symbol += bit;
if( symbol > 0xFF ) return symbol & 0xFF;
mask &= ~(match_bit ^ (bit << 8)); /* if( match_bit != bit ) mask = 0; */
}
@@ -235,7 +230,6 @@ struct LZ_decoder
uint32_t crc;
int outfd; /* output file descriptor */
bool pos_wrapped;
- bool pos_wrapped_dic;
};
void LZd_flush_data( struct LZ_decoder * const d );
@@ -333,7 +327,6 @@ static inline bool LZd_init( struct LZ_decoder * const d,
d->crc = 0xFFFFFFFFU;
d->outfd = ofd;
d->pos_wrapped = false;
- d->pos_wrapped_dic = false;
/* prev_byte of first byte; also for LZd_peek( 0 ) on corrupt file */
d->buffer[d->buffer_size-1] = 0;
return true;
diff --git a/doc/lunzip.1 b/doc/lunzip.1
index 1198723..f96b431 100644
--- a/doc/lunzip.1
+++ b/doc/lunzip.1
@@ -1,22 +1,22 @@
-.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.46.1.
-.TH LUNZIP "1" "January 2019" "lunzip 1.11" "User Commands"
+.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.16.
+.TH LUNZIP "1" "January 2021" "lunzip 1.12" "User Commands"
.SH NAME
lunzip \- decompressor for the lzip format
.SH SYNOPSIS
.B lunzip
[\fI\,options\/\fR] [\fI\,files\/\fR]
.SH DESCRIPTION
-Lunzip is a decompressor for the lzip format. It is written in C and its
-small size makes it well suited for embedded devices or software
-installers that need to decompress files but don't need compression
-capabilities. Lunzip is fully compatible with lzip\-1.4 or newer.
+Lunzip is a decompressor for the lzip format written in C. Its small size
+makes it well suited for embedded devices or software installers that need
+to decompress files but don't need compression capabilities. Lunzip is fully
+compatible with lzip 1.4 or newer.
.PP
Lunzip provides a 'low memory' mode able to decompress any file using as
little memory as 50 kB, irrespective of the dictionary size used to
compress the file. To activate it, specify the size of the output buffer
-with the '\-\-buffer\-size' option and lunzip will use the decompressed
+with the option \fB\-\-buffer\-size\fR and lunzip will use the decompressed
file as dictionary for distances beyond the buffer size. Of course, the
-smaller the buffer size used in relation to the dictionary size, the
+larger the difference between the buffer size and the dictionary size, the
more accesses to disk are needed and the slower the decompression is.
This 'low memory' mode only works when decompressing to a regular file
and is intended for systems without enough memory (RAM + swap) to keep
@@ -48,7 +48,7 @@ keep (don't delete) input files
print (un)compressed file sizes
.TP
\fB\-o\fR, \fB\-\-output=\fR<file>
-if reading standard input, write to <file>
+write to <file>, keep input files
.TP
\fB\-q\fR, \fB\-\-quiet\fR
suppress all messages
@@ -72,16 +72,25 @@ Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...
Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12
to 2^29 bytes.
.PP
+To extract all the files from archive 'foo.tar.lz', use the commands
+\&'tar \fB\-xf\fR foo.tar.lz' or 'lunzip \fB\-cd\fR foo.tar.lz | tar \fB\-xf\fR \-'.
+.PP
Exit status: 0 for a normal exit, 1 for environmental problems (file
not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or
invalid input file, 3 for an internal consistency error (eg, bug) which
caused lunzip to panic.
+.PP
+The ideas embodied in lunzip are due to (at least) the following people:
+Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the
+definition of Markov chains), G.N.N. Martin (for the definition of range
+encoding), Igor Pavlov (for putting all the above together in LZMA), and
+Julian Seward (for bzip2's CLI).
.SH "REPORTING BUGS"
Report bugs to lzip\-bug@nongnu.org
.br
Lunzip home page: http://www.nongnu.org/lzip/lunzip.html
.SH COPYRIGHT
-Copyright \(co 2019 Antonio Diaz Diaz.
+Copyright \(co 2021 Antonio Diaz Diaz.
License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>
.br
This is free software: you are free to change and redistribute it.
diff --git a/list.c b/list.c
index 97adb50..8ab8c44 100644
--- a/list.c
+++ b/list.c
@@ -1,26 +1,26 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#include <stdbool.h>
+#include <stdint.h>
#include <stdio.h>
#include <string.h>
-#include <stdint.h>
#include <unistd.h>
#include <sys/stat.h>
@@ -33,11 +33,11 @@ static void list_line( const unsigned long long uncomp_size,
const char * const input_filename )
{
if( uncomp_size > 0 )
- printf( "%15llu %15llu %6.2f%% %s\n", uncomp_size, comp_size,
+ printf( "%14llu %14llu %6.2f%% %s\n", uncomp_size, comp_size,
100.0 - ( ( 100.0 * comp_size ) / uncomp_size ),
input_filename );
else
- printf( "%15llu %15llu -INF%% %s\n", uncomp_size, comp_size,
+ printf( "%14llu %14llu -INF%% %s\n", uncomp_size, comp_size,
input_filename );
}
@@ -60,15 +60,15 @@ int list_files( const char * const filenames[], const int num_filenames,
if( from_stdin ) { if( stdin_used ) continue; else stdin_used = true; }
input_filename = from_stdin ? "(stdin)" : filenames[i];
infd = from_stdin ? STDIN_FILENO :
- open_instream( input_filename, &in_stats, true, true );
- if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
+ open_instream( input_filename, &in_stats, false, true );
+ if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
Li_init( &lzip_index, infd, ignore_trailing, loose_trailing );
close( infd );
if( lzip_index.retval != 0 )
{
show_file_error( input_filename, lzip_index.error, 0 );
- if( retval < lzip_index.retval ) retval = lzip_index.retval;
+ set_retval( &retval, lzip_index.retval );
Li_free( &lzip_index ); continue;
}
if( verbosity >= 0 )
@@ -80,31 +80,22 @@ int list_files( const char * const filenames[], const int num_filenames,
{
first_post = false;
if( verbosity >= 1 ) fputs( " dict memb trail ", stdout );
- fputs( " uncompressed compressed saved name\n", stdout );
+ fputs( " uncompressed compressed saved name\n", stdout );
}
if( verbosity >= 1 )
- {
- long long trailing_size;
- unsigned dictionary_size = 0;
- long i;
- for( i = 0; i < lzip_index.members; ++i )
- dictionary_size =
- max( dictionary_size, Li_dictionary_size( &lzip_index, i ) );
- trailing_size = Li_file_size( &lzip_index ) - cdata_size;
- printf( "%s %5ld %6lld ", format_ds( dictionary_size ),
- lzip_index.members, trailing_size );
- }
+ printf( "%s %5ld %6lld ", format_ds( lzip_index.dictionary_size ),
+ lzip_index.members, Li_file_size( &lzip_index ) - cdata_size );
list_line( udata_size, cdata_size, input_filename );
if( verbosity >= 2 && lzip_index.members > 1 )
{
long i;
- fputs( " member data_pos data_size member_pos member_size\n", stdout );
+ fputs( " member data_pos data_size member_pos member_size\n", stdout );
for( i = 0; i < lzip_index.members; ++i )
{
const struct Block * db = Li_dblock( &lzip_index, i );
const struct Block * mb = Li_mblock( &lzip_index, i );
- printf( "%5ld %15llu %15llu %15llu %15llu\n",
+ printf( "%6ld %14llu %14llu %14llu %14llu\n",
i + 1, db->pos, db->size, mb->pos, mb->size );
}
first_post = true; /* reprint heading after list of members */
diff --git a/lzip.h b/lzip.h
index 23db964..3961c33 100644
--- a/lzip.h
+++ b/lzip.h
@@ -1,18 +1,18 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef max
@@ -22,8 +22,6 @@
#define min(x,y) ((x) <= (y) ? (x) : (y))
#endif
-void * resize_buffer( void * buf, const unsigned min_size );
-
typedef int State;
enum { states = 12 };
@@ -82,7 +80,7 @@ static inline int get_len_state( const int len )
{ return min( len - min_match_len, len_states - 1 ); }
static inline int get_lit_state( const uint8_t prev_byte )
- { return ( prev_byte >> ( 8 - literal_context_bits ) ); }
+ { return prev_byte >> ( 8 - literal_context_bits ); }
enum { bit_model_move_bits = 5,
@@ -116,65 +114,6 @@ static inline void Lm_init( struct Len_model * const lm )
}
-/* defined in main.c */
-extern int verbosity;
-
-struct Pretty_print /* requires global var 'int verbosity' */
- {
- const char * name;
- char * padded_name;
- const char * stdin_name;
- unsigned longest_name;
- bool first_post;
- };
-
-static inline void Pp_init( struct Pretty_print * const pp,
- const char * const filenames[],
- const int num_filenames )
- {
- unsigned stdin_name_len;
- int i;
- pp->name = 0;
- pp->padded_name = 0;
- pp->stdin_name = "(stdin)";
- pp->longest_name = 0;
- pp->first_post = false;
-
- if( verbosity <= 0 ) return;
- stdin_name_len = strlen( pp->stdin_name );
- for( i = 0; i < num_filenames; ++i )
- {
- const char * const s = filenames[i];
- const unsigned len = (strcmp( s, "-" ) == 0) ? stdin_name_len : strlen( s );
- if( pp->longest_name < len ) pp->longest_name = len;
- }
- if( pp->longest_name == 0 ) pp->longest_name = stdin_name_len;
- }
-
-static inline void Pp_set_name( struct Pretty_print * const pp,
- const char * const filename )
- {
- unsigned name_len, padded_name_len, i = 0;
-
- if( filename && filename[0] && strcmp( filename, "-" ) != 0 )
- pp->name = filename;
- else pp->name = pp->stdin_name;
- name_len = strlen( pp->name );
- padded_name_len = max( name_len, pp->longest_name ) + 4;
- pp->padded_name = resize_buffer( pp->padded_name, padded_name_len + 1 );
- while( i < 2 ) pp->padded_name[i++] = ' ';
- while( i < name_len + 2 ) { pp->padded_name[i] = pp->name[i-2]; ++i; }
- pp->padded_name[i++] = ':';
- while( i < padded_name_len ) pp->padded_name[i++] = ' ';
- pp->padded_name[i] = 0;
- pp->first_post = true;
- }
-
-static inline void Pp_reset( struct Pretty_print * const pp )
- { if( pp->name && pp->name[0] ) pp->first_post = true; }
-void Pp_show_msg( struct Pretty_print * const pp, const char * const msg );
-
-
typedef uint32_t CRC32[256]; /* Table of CRCs of all 8-bit messages. */
extern CRC32 crc32;
@@ -213,7 +152,7 @@ static const uint8_t lzip_magic[4] = { 0x4C, 0x5A, 0x49, 0x50 }; /* "LZIP" */
typedef uint8_t Lzip_header[6]; /* 0-3 magic bytes */
/* 4 version */
- /* 5 coded_dict_size */
+ /* 5 coded dictionary size */
enum { Lh_size = 6 };
static inline bool Lh_verify_magic( const Lzip_header data )
@@ -250,6 +189,12 @@ static inline unsigned Lh_get_dictionary_size( const Lzip_header data )
return sz;
}
+static inline bool Lh_verify( const Lzip_header data )
+ {
+ return Lh_verify_magic( data ) && Lh_verify_version( data ) &&
+ isvalid_ds( Lh_get_dictionary_size( data ) );
+ }
+
typedef uint8_t Lzip_trailer[20];
/* 0-3 CRC32 of the uncompressed data */
@@ -294,10 +239,14 @@ static inline bool Lt_verify_consistency( const Lzip_trailer data )
}
+static inline void set_retval( int * retval, const int new_val )
+ { if( *retval < new_val ) *retval = new_val; }
+
static const char * const bad_magic_msg = "Bad magic number (file not in lzip format).";
static const char * const bad_dict_msg = "Invalid dictionary size in member header.";
static const char * const corrupt_mm_msg = "Corrupt header in multimember file.";
static const char * const trailing_msg = "Trailing data not allowed.";
+static const char * const mem_msg = "Not enough memory.";
/* defined in decoder.c */
int readblock( const int fd, uint8_t * const buf, const int size );
@@ -308,11 +257,15 @@ int list_files( const char * const filenames[], const int num_filenames,
/* defined in main.c */
struct stat;
+struct Pretty_print;
+extern int verbosity;
+void * resize_buffer( void * buf, const unsigned min_size );
+void Pp_show_msg( struct Pretty_print * const pp, const char * const msg );
const char * bad_version( const unsigned version );
const char * format_ds( const unsigned dictionary_size );
void show_header( const unsigned dictionary_size );
int open_instream( const char * const name, struct stat * const in_statsp,
- const bool no_ofile, const bool reg_only );
+ const bool one_to_one, const bool reg_only );
void cleanup_and_fail( const int retval );
void show_error( const char * const msg, const int errcode, const bool help );
void show_file_error( const char * const filename, const char * const msg,
diff --git a/lzip_index.c b/lzip_index.c
index 44c7b17..ca4df8d 100644
--- a/lzip_index.c
+++ b/lzip_index.c
@@ -1,28 +1,28 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include "lzip.h"
@@ -58,8 +58,7 @@ static bool push_back_member( struct Lzip_index * const li,
struct Member * p;
void * tmp = resize_buffer( li->member_vector,
( li->members + 1 ) * sizeof li->member_vector[0] );
- if( !tmp )
- { add_error( li, "Not enough memory." ); li->retval = 1; return false; }
+ if( !tmp ) { add_error( li, mem_msg ); li->retval = 1; return false; }
li->member_vector = (struct Member *)tmp;
p = &(li->member_vector[li->members]);
init_member( p, dp, ds, mp, ms, dict_size );
@@ -89,6 +88,19 @@ static void Li_reverse_member_vector( struct Lzip_index * const li )
}
+static bool Li_check_header_error( struct Lzip_index * const li,
+ const Lzip_header header )
+ {
+ if( !Lh_verify_magic( header ) )
+ { add_error( li, bad_magic_msg ); li->retval = 2; return true; }
+ if( !Lh_verify_version( header ) )
+ { add_error( li, bad_version( Lh_version( header ) ) ); li->retval = 2;
+ return true; }
+ if( !isvalid_ds( Lh_get_dictionary_size( header ) ) )
+ { add_error( li, bad_dict_msg ); li->retval = 2; return true; }
+ return false;
+ }
+
static void Li_set_errno_error( struct Lzip_index * const li,
const char * const msg )
{
@@ -106,9 +118,18 @@ static void Li_set_num_error( struct Lzip_index * const li,
}
+static bool Li_read_header( struct Lzip_index * const li, const int fd,
+ Lzip_header header, const long long pos )
+ {
+ if( seek_read( fd, header, Lh_size, pos ) != Lh_size )
+ { Li_set_errno_error( li, "Error reading member header: " ); return false; }
+ return true;
+ }
+
+
/* If successful, push last member and set pos to member header. */
-static bool Li_skip_trailing_data( struct Lzip_index * const li,
- const int fd, long long * const pos,
+static bool Li_skip_trailing_data( struct Lzip_index * const li, const int fd,
+ unsigned long long * const pos,
const bool ignore_trailing,
const bool loose_trailing )
{
@@ -135,36 +156,40 @@ static bool Li_skip_trailing_data( struct Lzip_index * const li,
if( buffer[i-1] <= max_msb ) /* most significant byte of member_size */
{
Lzip_header header;
+ const Lzip_header * header2;
const Lzip_trailer * const trailer =
(const Lzip_trailer *)( buffer + i - Lt_size );
const unsigned long long member_size = Lt_get_member_size( *trailer );
unsigned dictionary_size;
+ bool full_h2;
if( member_size == 0 ) /* skip trailing zeros */
{ while( i > Lt_size && buffer[i-9] == 0 ) --i; continue; }
if( member_size > ipos + i || !Lt_verify_consistency( *trailer ) )
continue;
- if( seek_read( fd, header, Lh_size,
- ipos + i - member_size ) != Lh_size )
- { Li_set_errno_error( li, "Error reading member header: " );
- return false; }
- dictionary_size = Lh_get_dictionary_size( header );
- if( !Lh_verify_magic( header ) || !Lh_verify_version( header ) ||
- !isvalid_ds( dictionary_size ) ) continue;
- if( Lh_verify_prefix( buffer + i, bsize - i ) )
+ if( !Li_read_header( li, fd, header, ipos + i - member_size ) )
+ return false;
+ if( !Lh_verify( header ) ) continue;
+ header2 = (const Lzip_header *)( buffer + i );
+ full_h2 = bsize - i >= Lh_size;
+ if( Lh_verify_prefix( *header2, bsize - i ) ) /* last member */
{
- add_error( li, "Last member in input file is truncated or corrupt." );
+ if( !full_h2 ) add_error( li, "Last member in input file is truncated." );
+ else if( !Li_check_header_error( li, *header2 ) )
+ add_error( li, "Last member in input file is truncated or corrupt." );
li->retval = 2; return false;
}
- if( !loose_trailing && bsize - i >= Lh_size &&
- Lh_verify_corrupt( buffer + i ) )
+ if( !loose_trailing && full_h2 && Lh_verify_corrupt( *header2 ) )
{ add_error( li, corrupt_mm_msg ); li->retval = 2; return false; }
if( !ignore_trailing )
{ add_error( li, trailing_msg ); li->retval = 2; return false; }
*pos = ipos + i - member_size;
+ dictionary_size = Lh_get_dictionary_size( header );
+ if( li->dictionary_size < dictionary_size )
+ li->dictionary_size = dictionary_size;
return push_back_member( li, 0, Lt_get_data_size( *trailer ), *pos,
member_size, dictionary_size );
}
- if( ipos <= 0 )
+ if( ipos == 0 )
{ Li_set_num_error( li, "Bad trailer at pos ", *pos - Lt_size );
return false; }
bsize = buffer_size;
@@ -180,7 +205,7 @@ bool Li_init( struct Lzip_index * const li, const int infd,
const bool ignore_trailing, const bool loose_trailing )
{
Lzip_header header;
- long long pos;
+ unsigned long long pos;
long i;
li->member_vector = 0;
li->error = 0;
@@ -188,6 +213,7 @@ bool Li_init( struct Lzip_index * const li, const int infd,
li->members = 0;
li->error_size = 0;
li->retval = 0;
+ li->dictionary_size = 0;
if( li->insize < 0 )
{ Li_set_errno_error( li, "Input file is not seekable: " ); return false; }
if( li->insize < min_member_size )
@@ -197,15 +223,8 @@ bool Li_init( struct Lzip_index * const li, const int infd,
{ add_error( li, "Input file is too long (2^63 bytes or more)." );
li->retval = 2; return false; }
- if( seek_read( infd, header, Lh_size, 0 ) != Lh_size )
- { Li_set_errno_error( li, "Error reading member header: " ); return false; }
- if( !Lh_verify_magic( header ) )
- { add_error( li, bad_magic_msg ); li->retval = 2; return false; }
- if( !Lh_verify_version( header ) )
- { add_error( li, bad_version( Lh_version( header ) ) ); li->retval = 2;
- return false; }
- if( !isvalid_ds( Lh_get_dictionary_size( header ) ) )
- { add_error( li, bad_dict_msg ); li->retval = 2; return false; }
+ if( !Li_read_header( li, infd, header, 0 ) ) return false;
+ if( Li_check_header_error( li, header ) ) return false;
pos = li->insize; /* always points to a header or to EOF */
while( pos >= min_member_size )
@@ -216,19 +235,16 @@ bool Li_init( struct Lzip_index * const li, const int infd,
if( seek_read( infd, trailer, Lt_size, pos - Lt_size ) != Lt_size )
{ Li_set_errno_error( li, "Error reading member trailer: " ); break; }
member_size = Lt_get_member_size( trailer );
- if( member_size > (unsigned long long)pos || !Lt_verify_consistency( trailer ) )
- {
+ if( member_size > pos || !Lt_verify_consistency( trailer ) )
+ { /* bad trailer */
if( li->members <= 0 )
{ if( Li_skip_trailing_data( li, infd, &pos, ignore_trailing,
loose_trailing ) ) continue; else return false; }
Li_set_num_error( li, "Bad trailer at pos ", pos - Lt_size );
break;
}
- if( seek_read( infd, header, Lh_size, pos - member_size ) != Lh_size )
- { Li_set_errno_error( li, "Error reading member header: " ); break; }
- dictionary_size = Lh_get_dictionary_size( header );
- if( !Lh_verify_magic( header ) || !Lh_verify_version( header ) ||
- !isvalid_ds( dictionary_size ) )
+ if( !Li_read_header( li, infd, header, pos - member_size ) ) break;
+ if( !Lh_verify( header ) ) /* bad header */
{
if( li->members <= 0 )
{ if( Li_skip_trailing_data( li, infd, &pos, ignore_trailing,
@@ -237,6 +253,9 @@ bool Li_init( struct Lzip_index * const li, const int infd,
break;
}
pos -= member_size;
+ dictionary_size = Lh_get_dictionary_size( header );
+ if( li->dictionary_size < dictionary_size )
+ li->dictionary_size = dictionary_size;
if( !push_back_member( li, 0, Lt_get_data_size( trailer ), pos,
member_size, dictionary_size ) )
return false;
diff --git a/lzip_index.h b/lzip_index.h
index 03be274..4e9cd44 100644
--- a/lzip_index.h
+++ b/lzip_index.h
@@ -1,18 +1,18 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef INT64_MAX
@@ -54,6 +54,7 @@ struct Lzip_index
long members;
int error_size;
int retval;
+ unsigned dictionary_size; /* largest dictionary size in the file */
};
bool Li_init( struct Lzip_index * const li, const int infd,
diff --git a/main.c b/main.c
index 2ff4a15..b5e458e 100644
--- a/main.c
+++ b/main.c
@@ -1,24 +1,24 @@
-/* Lunzip - Decompressor for the lzip format
- Copyright (C) 2010-2019 Antonio Diaz Diaz.
+/* Lunzip - Decompressor for the lzip format
+ Copyright (C) 2010-2021 Antonio Diaz Diaz.
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
- Exit status: 0 for a normal exit, 1 for environmental problems
- (file not found, invalid flags, I/O errors, etc), 2 to indicate a
- corrupt or invalid input file, 3 for an internal consistency error
- (eg, bug) which caused lunzip to panic.
+ Exit status: 0 for a normal exit, 1 for environmental problems
+ (file not found, invalid flags, I/O errors, etc), 2 to indicate a
+ corrupt or invalid input file, 3 for an internal consistency error
+ (eg, bug) which caused lunzip to panic.
*/
#define _FILE_OFFSET_BITS 64
@@ -70,11 +70,11 @@
int verbosity = 0;
-const char * const program_name = "lunzip";
-const char * const program_year = "2019";
-const char * invocation_name = 0;
+static const char * const program_name = "lunzip";
+static const char * const program_year = "2021";
+static const char * invocation_name = "lunzip"; /* default value */
-const struct { const char * from; const char * to; } known_extensions[] = {
+static const struct { const char * from; const char * to; } known_extensions[] = {
{ ".lz", "" },
{ ".tlz", ".tar" },
{ 0, 0 } };
@@ -83,23 +83,23 @@ enum Mode { m_compress, m_decompress, m_list, m_test };
/* Variables used in signal handler context.
They are not declared volatile because the handler never returns. */
-char * output_filename = 0;
-int outfd = -1;
-bool delete_output_on_interrupt = false;
+static char * output_filename = 0;
+static int outfd = -1;
+static bool delete_output_on_interrupt = false;
static void show_help( void )
{
- printf( "Lunzip is a decompressor for the lzip format. It is written in C and its\n"
- "small size makes it well suited for embedded devices or software\n"
- "installers that need to decompress files but don't need compression\n"
- "capabilities. Lunzip is fully compatible with lzip-1.4 or newer.\n"
+ printf( "Lunzip is a decompressor for the lzip format written in C. Its small size\n"
+ "makes it well suited for embedded devices or software installers that need\n"
+ "to decompress files but don't need compression capabilities. Lunzip is fully\n"
+ "compatible with lzip 1.4 or newer.\n"
"\nLunzip provides a 'low memory' mode able to decompress any file using as\n"
"little memory as 50 kB, irrespective of the dictionary size used to\n"
"compress the file. To activate it, specify the size of the output buffer\n"
- "with the '--buffer-size' option and lunzip will use the decompressed\n"
+ "with the option --buffer-size and lunzip will use the decompressed\n"
"file as dictionary for distances beyond the buffer size. Of course, the\n"
- "smaller the buffer size used in relation to the dictionary size, the\n"
+ "larger the difference between the buffer size and the dictionary size, the\n"
"more accesses to disk are needed and the slower the decompression is.\n"
"This 'low memory' mode only works when decompressing to a regular file\n"
"and is intended for systems without enough memory (RAM + swap) to keep\n"
@@ -114,22 +114,29 @@ static void show_help( void )
" -f, --force overwrite existing output files\n"
" -k, --keep keep (don't delete) input files\n"
" -l, --list print (un)compressed file sizes\n"
- " -o, --output=<file> if reading standard input, write to <file>\n"
+ " -o, --output=<file> write to <file>, keep input files\n"
" -q, --quiet suppress all messages\n"
" -t, --test test compressed file integrity\n"
" -u, --buffer-size=<bytes> set output buffer size in bytes\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n"
" --loose-trailing allow trailing data seeming corrupt header\n"
- "If no file names are given, or if a file is '-', lunzip decompresses\n"
+ "\nIf no file names are given, or if a file is '-', lunzip decompresses\n"
"from standard input to standard output.\n"
"Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n"
"Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n"
"Buffer sizes 12 to 29 are interpreted as powers of two, meaning 2^12\n"
"to 2^29 bytes.\n"
+ "\nTo extract all the files from archive 'foo.tar.lz', use the commands\n"
+ "'tar -xf foo.tar.lz' or 'lunzip -cd foo.tar.lz | tar -xf -'.\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
"invalid input file, 3 for an internal consistency error (eg, bug) which\n"
"caused lunzip to panic.\n"
+ "\nThe ideas embodied in lunzip are due to (at least) the following people:\n"
+ "Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for the\n"
+ "definition of Markov chains), G.N.N. Martin (for the definition of range\n"
+ "encoding), Igor Pavlov (for putting all the above together in LZMA), and\n"
+ "Julian Seward (for bzip2's CLI).\n"
"\nReport bugs to lzip-bug@nongnu.org\n"
"Lunzip home page: http://www.nongnu.org/lzip/lunzip.html\n" );
}
@@ -150,14 +157,63 @@ void * resize_buffer( void * buf, const unsigned min_size )
{
if( buf ) buf = realloc( buf, min_size );
else buf = malloc( min_size );
- if( !buf )
+ if( !buf ) { show_error( mem_msg, 0, false ); cleanup_and_fail( 1 ); }
+ return buf;
+ }
+
+
+struct Pretty_print
+ {
+ const char * name;
+ char * padded_name;
+ const char * stdin_name;
+ unsigned longest_name;
+ bool first_post;
+ };
+
+static void Pp_init( struct Pretty_print * const pp,
+ const char * const filenames[], const int num_filenames )
+ {
+ unsigned stdin_name_len;
+ int i;
+ pp->name = 0;
+ pp->padded_name = 0;
+ pp->stdin_name = "(stdin)";
+ pp->longest_name = 0;
+ pp->first_post = false;
+
+ if( verbosity <= 0 ) return;
+ stdin_name_len = strlen( pp->stdin_name );
+ for( i = 0; i < num_filenames; ++i )
{
- show_error( "Not enough memory.", 0, false );
- cleanup_and_fail( 1 );
+ const char * const s = filenames[i];
+ const unsigned len = (strcmp( s, "-" ) == 0) ? stdin_name_len : strlen( s );
+ if( pp->longest_name < len ) pp->longest_name = len;
}
- return buf;
+ if( pp->longest_name == 0 ) pp->longest_name = stdin_name_len;
+ }
+
+static void Pp_set_name( struct Pretty_print * const pp,
+ const char * const filename )
+ {
+ unsigned name_len, padded_name_len, i = 0;
+
+ if( filename && filename[0] && strcmp( filename, "-" ) != 0 )
+ pp->name = filename;
+ else pp->name = pp->stdin_name;
+ name_len = strlen( pp->name );
+ padded_name_len = max( name_len, pp->longest_name ) + 4;
+ pp->padded_name = resize_buffer( pp->padded_name, padded_name_len + 1 );
+ while( i < 2 ) pp->padded_name[i++] = ' ';
+ while( i < name_len + 2 ) { pp->padded_name[i] = pp->name[i-2]; ++i; }
+ pp->padded_name[i++] = ':';
+ while( i < padded_name_len ) pp->padded_name[i++] = ' ';
+ pp->padded_name[i] = 0;
+ pp->first_post = true;
}
+static void Pp_reset( struct Pretty_print * const pp )
+ { if( pp->name && pp->name[0] ) pp->first_post = true; }
void Pp_show_msg( struct Pretty_print * const pp, const char * const msg )
{
@@ -204,7 +260,7 @@ const char * format_ds( const unsigned dictionary_size )
void show_header( const unsigned dictionary_size )
{
- fprintf( stderr, "dictionary %s, ", format_ds( dictionary_size ) );
+ fprintf( stderr, "dict %s, ", format_ds( dictionary_size ) );
}
@@ -271,7 +327,7 @@ static int get_dict_size( const char * const arg )
}
-void set_mode( enum Mode * const program_modep, const enum Mode new_mode )
+static void set_mode( enum Mode * const program_modep, const enum Mode new_mode )
{
if( *program_modep != m_compress && *program_modep != new_mode )
{
@@ -324,7 +380,7 @@ static void set_d_outname( const char * const name, const int eindex )
int open_instream( const char * const name, struct stat * const in_statsp,
- const bool no_ofile, const bool reg_only )
+ const bool one_to_one, const bool reg_only )
{
int infd = open( name, O_RDONLY | O_BINARY );
if( infd < 0 )
@@ -336,13 +392,12 @@ int open_instream( const char * const name, struct stat * const in_statsp,
const bool can_read = ( i == 0 && !reg_only &&
( S_ISBLK( mode ) || S_ISCHR( mode ) ||
S_ISFIFO( mode ) || S_ISSOCK( mode ) ) );
- if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) )
+ if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || one_to_one ) ) )
{
if( verbosity >= 0 )
fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
- program_name, name,
- ( can_read && !no_ofile ) ?
- ",\n and '--stdout' was not specified" : "" );
+ program_name, name, ( can_read && one_to_one ) ?
+ ",\n and neither '-c' nor '-o' were specified" : "" );
close( infd );
infd = -1;
}
@@ -351,11 +406,11 @@ int open_instream( const char * const name, struct stat * const in_statsp,
}
-static bool open_outstream( const bool force, const bool from_stdin )
+static bool open_outstream( const bool force, const bool protect )
{
const mode_t usr_rw = S_IRUSR | S_IWUSR;
const mode_t all_rw = usr_rw | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
- const mode_t outfd_mode = from_stdin ? all_rw : usr_rw;
+ const mode_t outfd_mode = protect ? usr_rw : all_rw;
int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
@@ -399,7 +454,7 @@ void cleanup_and_fail( const int retval )
}
-void signal_handler( int sig )
+static void signal_handler( int sig )
{
if( sig ) {} /* keep compiler happy */
show_error( "Control-C or similar caught, quitting.", 0, false );
@@ -407,7 +462,20 @@ void signal_handler( int sig )
}
- /* Set permissions, owner and times. */
+static bool check_tty_in( const char * const input_filename, const int infd,
+ const enum Mode program_mode, int * const retval )
+ {
+ if( isatty( infd ) ) /* for example /dev/tty */
+ { show_file_error( input_filename,
+ "I won't read compressed data from a terminal.", 0 );
+ close( infd ); set_retval( retval, 1 );
+ if( program_mode != m_test ) cleanup_and_fail( *retval );
+ return false; }
+ return true;
+ }
+
+
+/* Set permissions, owner, and times. */
static void close_and_set_permissions( const struct stat * const in_statsp )
{
bool warning = false;
@@ -487,10 +555,7 @@ static int decompress( const unsigned long long cfile_size, const int infd,
int retval = 0;
bool first_member;
if( !Rd_init( &rdec, infd ) )
- {
- show_error( "Not enough memory.", 0, false );
- cleanup_and_fail( 1 );
- }
+ { show_error( mem_msg, 0, false ); cleanup_and_fail( 1 ); }
for( first_member = true; ; first_member = false )
{
@@ -589,7 +654,7 @@ void show_file_error( const char * const filename, const char * const msg,
}
-void internal_error( const char * const msg )
+static void internal_error( const char * const msg )
{
if( verbosity >= 0 )
fprintf( stderr, "%s: internal error: %s\n", program_name, msg );
@@ -631,7 +696,9 @@ void show_dprogress( const unsigned long long cfile_size,
int main( const int argc, const char * const argv[] )
{
const char * default_output_filename = "";
- const char ** filenames = 0;
+ static struct Arg_parser parser; /* static because valgrind complains */
+ static struct Pretty_print pp; /* and memory management in C sucks */
+ static const char ** filenames = 0;
int num_filenames = 0;
unsigned buffer_size = max_dictionary_size;
enum Mode program_mode = m_compress;
@@ -646,7 +713,6 @@ int main( const int argc, const char * const argv[] )
bool loose_trailing = false;
bool stdin_used = false;
bool to_stdout = false;
- struct Pretty_print pp;
enum { opt_lt = 256 };
const struct ap_Option options[] =
@@ -668,13 +734,11 @@ int main( const int argc, const char * const argv[] )
{ opt_lt, "loose-trailing", ap_no },
{ 0 , 0, ap_no } };
- struct Arg_parser parser;
-
- invocation_name = argv[0];
+ if( argc > 0 ) invocation_name = argv[0];
CRC32_init();
if( !ap_init( &parser, argc, argv, options, 0 ) )
- { show_error( "Not enough memory.", 0, false ); return 1; }
+ { show_error( mem_msg, 0, false ); return 1; }
if( ap_error( &parser ) ) /* bad option */
{ show_error( ap_error( &parser ), 0, true ); return 1; }
@@ -693,7 +757,8 @@ int main( const int argc, const char * const argv[] )
case 'k': keep_input_files = true; break;
case 'l': set_mode( &program_mode, m_list ); break;
case 'n': break;
- case 'o': default_output_filename = arg; break;
+ case 'o': if( strcmp( arg, "-" ) == 0 ) to_stdout = true;
+ else { default_output_filename = arg; } break;
case 'q': verbosity = -1; break;
case 't': set_mode( &program_mode, m_test ); break;
case 'u': buffer_size = get_dict_size( arg ); break;
@@ -722,17 +787,17 @@ int main( const int argc, const char * const argv[] )
if( program_mode == m_list )
return list_files( filenames, num_filenames, ignore_trailing, loose_trailing );
- if( program_mode == m_test )
- outfd = -1;
- else if( program_mode == m_compress )
- program_mode = m_decompress; /* default mode */
+ if( program_mode == m_compress )
+ program_mode = m_decompress; /* default mode */
+ if( program_mode == m_test ) to_stdout = false; /* apply overrides */
+ if( program_mode == m_test || to_stdout ) default_output_filename = "";
if( buffer_size < max_dictionary_size )
{
bool from_stdin = false;
if( to_stdout || program_mode == m_test )
- { show_error( "'--buffer-size' is incompatible with '--stdout' and '--test'.", 0, false );
- return 1; }
+ { show_error( "'--buffer-size' is incompatible with '--stdout' and '--test'.",
+ 0, false ); return 1; }
for( i = 0; i < num_filenames; ++i )
if( !filenames[i][0] || strcmp( filenames[i], "-" ) == 0 )
{ from_stdin = true; break; }
@@ -741,13 +806,19 @@ int main( const int argc, const char * const argv[] )
" with a reduced buffer size.", 0, false ); return 1; }
}
- if( !to_stdout && program_mode != m_test &&
- ( filenames_given || default_output_filename[0] ) )
+ output_filename = resize_buffer( output_filename, 1 );
+ output_filename[0] = 0;
+ if( to_stdout && program_mode != m_test ) outfd = STDOUT_FILENO;
+ else outfd = -1;
+
+ const bool to_file = !to_stdout && program_mode != m_test &&
+ default_output_filename[0];
+ if( !to_stdout && program_mode != m_test && ( filenames_given || to_file ) )
set_signals( signal_handler );
Pp_init( &pp, filenames, num_filenames );
- output_filename = resize_buffer( output_filename, 1 );
+ const bool one_to_one = !to_stdout && program_mode != m_test && !to_file;
for( i = 0; i < num_filenames; ++i )
{
unsigned long long cfile_size;
@@ -756,60 +827,35 @@ int main( const int argc, const char * const argv[] )
int tmp;
struct stat in_stats;
const struct stat * in_statsp;
- output_filename[0] = 0;
- if( !filenames[i][0] || strcmp( filenames[i], "-" ) == 0 )
+ Pp_set_name( &pp, filenames[i] );
+ if( strcmp( filenames[i], "-" ) == 0 )
{
if( stdin_used ) continue; else stdin_used = true;
infd = STDIN_FILENO;
- if( program_mode != m_test )
- {
- if( to_stdout || !default_output_filename[0] )
- outfd = STDOUT_FILENO;
- else
- {
- output_filename = resize_buffer( output_filename,
- strlen( default_output_filename ) + 1 );
- strcpy( output_filename, default_output_filename );
- if( !open_outstream( force, true ) )
- {
- if( retval < 1 ) retval = 1;
- close( infd );
- continue;
- }
- }
- }
+ if( !check_tty_in( pp.name, infd, program_mode, &retval ) ) continue;
+ if( one_to_one ) { outfd = STDOUT_FILENO; output_filename[0] = 0; }
}
else
{
input_filename = filenames[i];
- infd = open_instream( input_filename, &in_stats,
- to_stdout || program_mode == m_test, false );
- if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
- if( program_mode != m_test )
+ infd = open_instream( input_filename, &in_stats, one_to_one, false );
+ if( infd < 0 ) { set_retval( &retval, 1 ); continue; }
+ if( !check_tty_in( pp.name, infd, program_mode, &retval ) ) continue;
+ if( one_to_one ) /* open outfd after verifying infd */
{
- if( to_stdout ) outfd = STDOUT_FILENO;
- else
- {
- set_d_outname( input_filename, extension_index( input_filename ) );
- if( !open_outstream( force, false ) )
- {
- if( retval < 1 ) retval = 1;
- close( infd );
- continue;
- }
- }
+ set_d_outname( input_filename, extension_index( input_filename ) );
+ if( !open_outstream( force, true ) )
+ { close( infd ); set_retval( &retval, 1 ); continue; }
}
}
- Pp_set_name( &pp, input_filename );
- if( isatty( infd ) )
+ if( to_file && outfd < 0 ) /* open outfd after verifying infd */
{
- show_file_error( pp.name,
- "I won't read compressed data from a terminal.", 0 );
- if( retval < 1 ) retval = 1;
- if( program_mode == m_test ) { close( infd ); continue; }
- cleanup_and_fail( retval );
+ output_filename = resize_buffer( output_filename,
+ strlen( default_output_filename ) + 1 );
+ strcpy( output_filename, default_output_filename );
+ if( !open_outstream( force, false ) ) return 1;
}
if( delete_output_on_interrupt && buffer_size < max_dictionary_size )
@@ -821,39 +867,34 @@ int main( const int argc, const char * const argv[] )
fprintf( stderr, "%s: Output file '%s' is not a regular file,\n"
" and 'low memory' mode has been requested.\n",
program_name, output_filename );
- if( retval < 1 ) retval = 1;
- cleanup_and_fail( retval );
+ set_retval( &retval, 1 );
+ return retval; /* don't try to delete a non-regular file */
}
}
- in_statsp = input_filename[0] ? &in_stats : 0;
- cfile_size = ( in_statsp && S_ISREG( in_statsp->st_mode ) ) ?
- ( in_statsp->st_size + 99 ) / 100 : 0;
+ in_statsp = ( input_filename[0] && one_to_one ) ? &in_stats : 0;
+ cfile_size = ( input_filename[0] && S_ISREG( in_stats.st_mode ) ) ?
+ ( in_stats.st_size + 99 ) / 100 : 0;
tmp = decompress( cfile_size, infd, &pp, buffer_size, ignore_trailing,
loose_trailing, program_mode == m_test );
if( close( infd ) != 0 )
- {
- show_error( input_filename[0] ? "Error closing input file" :
- "Error closing stdin", errno, false );
- if( tmp < 1 ) tmp = 1;
- }
- if( tmp > retval ) retval = tmp;
+ { show_file_error( pp.name, "Error closing input file", errno );
+ set_retval( &tmp, 1 ); }
+ set_retval( &retval, tmp );
if( tmp )
{ if( program_mode != m_test ) cleanup_and_fail( retval );
else ++failed_tests; }
- if( delete_output_on_interrupt )
+ if( delete_output_on_interrupt && one_to_one )
close_and_set_permissions( in_statsp );
- if( input_filename[0] )
- {
- if( !keep_input_files && !to_stdout && program_mode != m_test )
- remove( input_filename );
- }
+ if( input_filename[0] && !keep_input_files && one_to_one )
+ remove( input_filename );
}
- if( outfd >= 0 && close( outfd ) != 0 )
+ if( delete_output_on_interrupt ) close_and_set_permissions( 0 ); /* -o */
+ else if( outfd >= 0 && close( outfd ) != 0 ) /* -c */
{
show_error( "Error closing stdout", errno, false );
- if( retval < 1 ) retval = 1;
+ set_retval( &retval, 1 );
}
if( failed_tests > 0 && verbosity >= 1 && num_filenames > 1 )
fprintf( stderr, "%s: warning: %d %s failed the test.\n",
diff --git a/testsuite/check.sh b/testsuite/check.sh
index cf7bb72..19928dd 100755
--- a/testsuite/check.sh
+++ b/testsuite/check.sh
@@ -1,9 +1,9 @@
#! /bin/sh
# check script for Lunzip - Decompressor for the lzip format
-# Copyright (C) 2010-2019 Antonio Diaz Diaz.
+# Copyright (C) 2010-2021 Antonio Diaz Diaz.
#
# This script is free software: you have unlimited permission
-# to copy, distribute and modify it.
+# to copy, distribute, and modify it.
LC_ALL=C
export LC_ALL
@@ -30,6 +30,8 @@ cd "${objdir}"/tmp || framework_failure
cat "${testdir}"/test.txt > in || framework_failure
in_lz="${testdir}"/test.txt.lz
+in_em="${testdir}"/test_em.txt.lz
+fox_lz="${testdir}"/fox.lz
fail=0
test_failed() { fail=1 ; printf " $1" ; [ -z "$2" ] || printf "($2)" ; }
@@ -37,7 +39,7 @@ printf "testing lunzip-%s..." "$2"
cat "${in_lz}" > uin.lz || framework_failure
for i in bad_size -1 0 4095 513MiB 1G 1T 1P 1E 1Z 1Y 10KB ; do
- "${LZIP}" -dfkqu $i uin.lz
+ "${LZIP}" -dfkq -u $i uin.lz
[ $? = 1 ] || test_failed $LINENO $i
[ ! -e uin ] || test_failed $LINENO $i
done
@@ -54,6 +56,11 @@ rm -f uin.lz || framework_failure
[ $? = 2 ] || test_failed $LINENO
"${LZIP}" -dq -o in < "${in_lz}"
[ $? = 1 ] || test_failed $LINENO
+"${LZIP}" -dq -o in "${in_lz}"
+[ $? = 1 ] || test_failed $LINENO
+"${LZIP}" -dq -o out nx_file.lz
+[ $? = 1 ] || test_failed $LINENO
+[ ! -e out ] || test_failed $LINENO
# these are for code coverage
"${LZIP}" -lt "${in_lz}" 2> /dev/null
[ $? = 1 ] || test_failed $LINENO
@@ -61,7 +68,9 @@ rm -f uin.lz || framework_failure
[ $? = 1 ] || test_failed $LINENO
"${LZIP}" -cdt "${in_lz}" > out 2> /dev/null
[ $? = 1 ] || test_failed $LINENO
-"${LZIP}" -t -- nx_file 2> /dev/null
+"${LZIP}" -t -- nx_file.lz 2> /dev/null
+[ $? = 1 ] || test_failed $LINENO
+"${LZIP}" -t "" < /dev/null 2> /dev/null
[ $? = 1 ] || test_failed $LINENO
"${LZIP}" --help > /dev/null || test_failed $LINENO
"${LZIP}" -n1 -V > /dev/null || test_failed $LINENO
@@ -85,12 +94,26 @@ printf "LZIP\001+.............................." | "${LZIP}" -t 2> /dev/null
printf "\ntesting decompression..."
-"${LZIP}" -lq "${in_lz}" || test_failed $LINENO
-"${LZIP}" -t "${in_lz}" || test_failed $LINENO
-"${LZIP}" -cd "${in_lz}" > copy || test_failed $LINENO
-cmp in copy || test_failed $LINENO
+for i in "${in_lz}" "${in_em}" ; do
+ "${LZIP}" -lq "$i" || test_failed $LINENO "$i"
+ "${LZIP}" -t "$i" || test_failed $LINENO "$i"
+ "${LZIP}" -d "$i" -o copy || test_failed $LINENO "$i"
+ cmp in copy || test_failed $LINENO "$i"
+ "${LZIP}" -cd "$i" > copy || test_failed $LINENO "$i"
+ cmp in copy || test_failed $LINENO "$i"
+ "${LZIP}" -d "$i" -o - > copy || test_failed $LINENO "$i"
+ cmp in copy || test_failed $LINENO "$i"
+ "${LZIP}" -d < "$i" > copy || test_failed $LINENO "$i"
+ cmp in copy || test_failed $LINENO "$i"
+ rm -f copy || framework_failure
+done
+
+lines=$("${LZIP}" -tvv "${in_em}" 2>&1 | wc -l) || test_failed $LINENO
+[ "${lines}" -eq 8 ] || test_failed $LINENO "${lines}"
+
+lines=$("${LZIP}" -lvv "${in_em}" | wc -l) || test_failed $LINENO
+[ "${lines}" -eq 11 ] || test_failed $LINENO "${lines}"
-rm -f copy || framework_failure
cat "${in_lz}" > copy.lz || framework_failure
"${LZIP}" -dk copy.lz || test_failed $LINENO
cmp in copy || test_failed $LINENO
@@ -102,12 +125,20 @@ printf "to be overwritten" > copy || framework_failure
cmp in copy || test_failed $LINENO
printf "to be overwritten" > copy || framework_failure
+"${LZIP}" -d -o copy < "${in_lz}" 2> /dev/null
+[ $? = 1 ] || test_failed $LINENO
"${LZIP}" -df -o copy < "${in_lz}" || test_failed $LINENO
cmp in copy || test_failed $LINENO
+rm -f out copy || framework_failure
+"${LZIP}" -d -o ./- "${in_lz}" || test_failed $LINENO
+cmp in ./- || test_failed $LINENO
+rm -f ./- || framework_failure
+"${LZIP}" -d -o ./- < "${in_lz}" || test_failed $LINENO
+cmp in ./- || test_failed $LINENO
+rm -f ./- || framework_failure
-rm -f copy || framework_failure
cat "${in_lz}" > anyothername || framework_failure
-"${LZIP}" -dv --output copy - anyothername - < "${in_lz}" 2> /dev/null ||
+"${LZIP}" -dv - anyothername - < "${in_lz}" > copy 2> /dev/null ||
test_failed $LINENO
cmp in copy || test_failed $LINENO
cmp in anyothername.out || test_failed $LINENO
@@ -148,16 +179,19 @@ done
cmp in copy || test_failed $LINENO
cat in in > in2 || framework_failure
-cat "${in_lz}" "${in_lz}" > in2.lz || framework_failure
-"${LZIP}" -lq in2.lz || test_failed $LINENO
-"${LZIP}" -t in2.lz || test_failed $LINENO
-"${LZIP}" -cd in2.lz > copy2 || test_failed $LINENO
+"${LZIP}" -lq "${in_lz}" "${in_lz}" || test_failed $LINENO
+"${LZIP}" -t "${in_lz}" "${in_lz}" || test_failed $LINENO
+"${LZIP}" -cd "${in_lz}" "${in_lz}" -o out > copy2 || test_failed $LINENO
+[ ! -e out ] || test_failed $LINENO # override -o
cmp in2 copy2 || test_failed $LINENO
+rm -f copy2 || framework_failure
+"${LZIP}" -d "${in_lz}" "${in_lz}" -o copy2 || test_failed $LINENO
+cmp in2 copy2 || test_failed $LINENO
+rm -f copy2 || framework_failure
-cat in2.lz > copy2.lz || framework_failure
+cat "${in_lz}" "${in_lz}" > copy2.lz || framework_failure
printf "\ngarbage" >> copy2.lz || framework_failure
"${LZIP}" -tvvvv copy2.lz 2> /dev/null || test_failed $LINENO
-rm -f copy2 || framework_failure
"${LZIP}" -alq copy2.lz
[ $? = 2 ] || test_failed $LINENO
"${LZIP}" -atq copy2.lz
@@ -173,13 +207,20 @@ rm -f copy2 || framework_failure
printf "to be overwritten" > copy2 || framework_failure
"${LZIP}" -df copy2.lz || test_failed $LINENO
cmp in2 copy2 || test_failed $LINENO
-rm -f in2 copy2 || framework_failure
for i in 12 5120 6Ki 29 512KiB ; do
printf "to be overwritten" > copy || framework_failure
"${LZIP}" -df -u$i -o copy < "${in_lz}" || test_failed $LINENO $i
cmp in copy || test_failed $LINENO $i
+ rm -f copy || framework_failure
+ "${LZIP}" -d -u$i -o copy "${in_lz}" || test_failed $LINENO $i
+ cmp in copy || test_failed $LINENO $i
+ rm -f copy2 || framework_failure
+ "${LZIP}" -d -u$i -o copy2 "${in_lz}" "${in_lz}" ||
+ test_failed $LINENO $i
+ cmp in2 copy2 || test_failed $LINENO $i
done
+rm -f in2 copy copy2 || framework_failure
printf "\ntesting bad input..."
@@ -238,6 +279,21 @@ else
fi
rm -f int.lz || framework_failure
+for i in fox_v2.lz fox_s11.lz fox_de20.lz \
+ fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do
+ "${LZIP}" -tq "${testdir}"/$i
+ [ $? = 2 ] || test_failed $LINENO $i
+done
+
+"${LZIP}" -cd "${fox_lz}" > fox || test_failed $LINENO
+for i in fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do
+ "${LZIP}" -cdq "${testdir}"/$i > out
+ [ $? = 2 ] || test_failed $LINENO $i
+ cmp fox out || test_failed $LINENO $i
+done
+rm -f fox out || framework_failure
+
+cat "${in_lz}" "${in_lz}" > in2.lz || framework_failure
cat "${in_lz}" "${in_lz}" "${in_lz}" > in3.lz || framework_failure
if dd if=in3.lz of=trunc.lz bs=14752 count=1 2> /dev/null &&
[ -e trunc.lz ] && cmp in2.lz trunc.lz > /dev/null 2>&1 ; then
@@ -264,13 +320,21 @@ printf "g" >> ingin.lz || framework_failure
cat "${in_lz}" >> ingin.lz || framework_failure
"${LZIP}" -lq ingin.lz
[ $? = 2 ] || test_failed $LINENO
+"${LZIP}" -atq ingin.lz
+[ $? = 2 ] || test_failed $LINENO
+"${LZIP}" -atq < ingin.lz
+[ $? = 2 ] || test_failed $LINENO
+"${LZIP}" -acdq ingin.lz > out
+[ $? = 2 ] || test_failed $LINENO
+"${LZIP}" -adq < ingin.lz > out
+[ $? = 2 ] || test_failed $LINENO
"${LZIP}" -t ingin.lz || test_failed $LINENO
+"${LZIP}" -t < ingin.lz || test_failed $LINENO
"${LZIP}" -cd ingin.lz > copy || test_failed $LINENO
cmp in copy || test_failed $LINENO
-"${LZIP}" -t < ingin.lz || test_failed $LINENO
"${LZIP}" -d < ingin.lz > copy || test_failed $LINENO
cmp in copy || test_failed $LINENO
-rm -f copy ingin.lz || framework_failure
+rm -f copy ingin.lz out || framework_failure
echo
if [ ${fail} = 0 ] ; then
diff --git a/testsuite/fox.lz b/testsuite/fox.lz
new file mode 100644
index 0000000..509da82
--- /dev/null
+++ b/testsuite/fox.lz
Binary files differ
diff --git a/testsuite/fox_bcrc.lz b/testsuite/fox_bcrc.lz
new file mode 100644
index 0000000..8f6a7c4
--- /dev/null
+++ b/testsuite/fox_bcrc.lz
Binary files differ
diff --git a/testsuite/fox_crc0.lz b/testsuite/fox_crc0.lz
new file mode 100644
index 0000000..1abe926
--- /dev/null
+++ b/testsuite/fox_crc0.lz
Binary files differ
diff --git a/testsuite/fox_das46.lz b/testsuite/fox_das46.lz
new file mode 100644
index 0000000..43ed9f9
--- /dev/null
+++ b/testsuite/fox_das46.lz
Binary files differ
diff --git a/testsuite/fox_de20.lz b/testsuite/fox_de20.lz
new file mode 100644
index 0000000..10949d8
--- /dev/null
+++ b/testsuite/fox_de20.lz
Binary files differ
diff --git a/testsuite/fox_mes81.lz b/testsuite/fox_mes81.lz
new file mode 100644
index 0000000..d50ef2e
--- /dev/null
+++ b/testsuite/fox_mes81.lz
Binary files differ
diff --git a/testsuite/fox_s11.lz b/testsuite/fox_s11.lz
new file mode 100644
index 0000000..dca909c
--- /dev/null
+++ b/testsuite/fox_s11.lz
Binary files differ
diff --git a/testsuite/fox_v2.lz b/testsuite/fox_v2.lz
new file mode 100644
index 0000000..8620981
--- /dev/null
+++ b/testsuite/fox_v2.lz
Binary files differ
diff --git a/testsuite/test_em.txt.lz b/testsuite/test_em.txt.lz
new file mode 100644
index 0000000..7e96250
--- /dev/null
+++ b/testsuite/test_em.txt.lz
Binary files differ