Compare commits
10 commits
2902fcb6e5
...
9a45d2df81
Author | SHA1 | Date | |
---|---|---|---|
9a45d2df81 | |||
d9ee6fc0c5 | |||
4ebeeeb191 | |||
5fa8d2a83d | |||
6a0f9dafa8 | |||
dcb57f45d5 | |||
29dc774230 | |||
4502486013 | |||
2c6d5ecc7e | |||
64ab85d0eb |
22 changed files with 1090 additions and 879 deletions
7
AUTHORS
7
AUTHORS
|
@ -1,7 +1,6 @@
|
|||
Lzd was written by Antonio Diaz Diaz.
|
||||
|
||||
The ideas embodied in lzd 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), and Igor Pavlov (for putting all the above together in
|
||||
LZMA).
|
||||
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the
|
||||
definition of Markov chains), G.N.N. Martin (for the definition of range
|
||||
encoding), and Igor Pavlov (for putting all the above together in LZMA).
|
||||
|
|
17
COPYING
Normal file
17
COPYING
Normal file
|
@ -0,0 +1,17 @@
|
|||
Lzd - Educational decompressor for the lzip format
|
||||
Copyright (C) Antonio Diaz Diaz.
|
||||
|
||||
This program 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.
|
||||
|
||||
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 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.
|
68
ChangeLog
68
ChangeLog
|
@ -1,3 +1,60 @@
|
|||
2025-01-02 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.5 released.
|
||||
* lzd.cc: Reject empty members and nonzero first LZMA byte.
|
||||
|
||||
2024-01-02 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.4 released.
|
||||
* lzd.cc: Use header_size and trailer_size instead of 6 and 20.
|
||||
|
||||
2022-10-24 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.3 released.
|
||||
* lzd.cc (Range_decoder): Discard first LZMA byte explicitly.
|
||||
|
||||
2021-01-04 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.2 released.
|
||||
* lzd.cc (main): Check also mismatches in member size.
|
||||
Accept and ignore the option '-d' for compatibility with zutils.
|
||||
Remove warning about "lzd not safe for real work".
|
||||
Print license notice.
|
||||
* testsuite: Add 10 new test files.
|
||||
|
||||
2019-01-11 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.1 released.
|
||||
* Rename File_* to Lzip_*.
|
||||
* lzd.cc: Compile on DOS with DJGPP.
|
||||
* configure: Accept appending to CXXFLAGS; 'CXXFLAGS+=OPTIONS'.
|
||||
|
||||
2017-05-02 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 1.0 released.
|
||||
* lzd.cc: Minor code improvements.
|
||||
* check.sh: Require a POSIX shell.
|
||||
|
||||
2016-05-10 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.9 released.
|
||||
* configure: Avoid warning on some shells when testing for g++.
|
||||
|
||||
2016-01-23 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.8 released.
|
||||
* Document that lzip does not use 'literal_pos_state_bits'.
|
||||
|
||||
2015-07-07 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.7 released.
|
||||
* Minor changes.
|
||||
|
||||
2014-08-25 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.6 released.
|
||||
* Minor changes.
|
||||
|
||||
2013-09-17 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.5 released.
|
||||
|
@ -6,7 +63,7 @@
|
|||
2013-08-01 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.4 released.
|
||||
* testsuite/check.sh: Removed '/dev/full' from tests.
|
||||
* check.sh: Remove '/dev/full' from tests.
|
||||
|
||||
2013-07-24 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
|
@ -16,15 +73,14 @@
|
|||
2013-05-06 Antonio Diaz Diaz <antonio@gnu.org>
|
||||
|
||||
* Version 0.2 released.
|
||||
* main.c: Added a missing '#include' for OS/2.
|
||||
* main.c: Add a missing '#include' for OS/2.
|
||||
|
||||
2013-03-21 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 0.1 released.
|
||||
|
||||
|
||||
Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
Copyright (C) 2013-2025 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
|
||||
modify it.
|
||||
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 modify it.
|
||||
|
|
41
INSTALL
41
INSTALL
|
@ -1,9 +1,11 @@
|
|||
Requirements
|
||||
------------
|
||||
You will need a C++ compiler.
|
||||
I use gcc 4.8.1 and 3.3.6, but the code should compile with any
|
||||
standards compliant compiler.
|
||||
Gcc is available at http://gcc.gnu.org.
|
||||
You will need a C++98 compiler with support for 'long long'.
|
||||
(gcc 3.3.6 or newer is recommended).
|
||||
I use gcc 6.1.0 and 3.3.6, but the code should compile with any standards
|
||||
compliant compiler.
|
||||
Gcc is available at http://gcc.gnu.org
|
||||
Lzip is available at http://www.nongnu.org/lzip/lzip.html
|
||||
|
||||
|
||||
Procedure
|
||||
|
@ -14,8 +16,8 @@ Procedure
|
|||
or
|
||||
lzip -cd lzd[version].tar.lz | tar -xf -
|
||||
|
||||
This creates the directory ./lzd[version] containing the source from
|
||||
the main archive.
|
||||
This creates the directory ./lzd[version] containing the source code
|
||||
extracted from the archive.
|
||||
|
||||
2. Change to lzd directory and run configure.
|
||||
(Try 'configure --help' for usage instructions).
|
||||
|
@ -30,31 +32,28 @@ the main archive.
|
|||
4. Optionally, type 'make check' to run the tests that come with lzd.
|
||||
|
||||
5. Type 'make install' to install the program and any data files and
|
||||
documentation.
|
||||
|
||||
You can install only the program, the info manual or the man page
|
||||
typing 'make install-bin', 'make install-info' or 'make install-man'
|
||||
respectively.
|
||||
documentation. You need root privileges to install into a prefix owned
|
||||
by root.
|
||||
|
||||
|
||||
Another way
|
||||
-----------
|
||||
You can also compile lzd 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 object files
|
||||
and executables to go and run the 'configure' script. 'configure'
|
||||
automatically checks for the source code in '.', in '..' and in the
|
||||
directory that 'configure' is in.
|
||||
You can also compile lzd into a separate directory.
|
||||
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
|
||||
in the directory that 'configure' is in.
|
||||
|
||||
'configure' recognizes the option '--srcdir=DIR' to control where to
|
||||
look for the sources. Usually 'configure' can determine that directory
|
||||
'configure' recognizes the option '--srcdir=DIR' to control where to look
|
||||
for the source code. Usually 'configure' can determine that directory
|
||||
automatically.
|
||||
|
||||
After running 'configure', you can run 'make' and 'make install' as
|
||||
explained above.
|
||||
|
||||
|
||||
Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
Copyright (C) 2013-2025 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
||||
distribute, and modify it.
|
||||
|
|
68
Makefile.in
68
Makefile.in
|
@ -1,44 +1,47 @@
|
|||
|
||||
DISTNAME = $(pkgname)-$(pkgversion)
|
||||
INSTALL = install
|
||||
INSTALL_PROGRAM = $(INSTALL) -p -m 755
|
||||
INSTALL_DATA = $(INSTALL) -p -m 644
|
||||
INSTALL_PROGRAM = $(INSTALL) -m 755
|
||||
INSTALL_DIR = $(INSTALL) -d -m 755
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
SHELL = /bin/sh
|
||||
CAN_RUN_INSTALLINFO = $(SHELL) -c "install-info --version" > /dev/null 2>&1
|
||||
|
||||
objs = lzd.o
|
||||
|
||||
|
||||
.PHONY : all install install-bin install-info install-man install-strip \
|
||||
.PHONY : all install install-bin install-info install-man \
|
||||
install-strip install-compress install-strip-compress \
|
||||
install-bin-strip install-info-compress install-man-compress \
|
||||
uninstall uninstall-bin uninstall-info uninstall-man \
|
||||
doc info man check dist clean distclean
|
||||
|
||||
all : $(progname)
|
||||
|
||||
$(progname) : $(objs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(objs)
|
||||
|
||||
$(progname)_profiled : $(objs)
|
||||
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
|
||||
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(objs)
|
||||
|
||||
%.o : %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
$(objs) : Makefile
|
||||
# prevent 'make' from trying to remake source files
|
||||
$(VPATH)/configure $(VPATH)/Makefile.in $(VPATH)/doc/$(pkgname).texi : ;
|
||||
MAKEFLAGS += -r
|
||||
.SUFFIXES :
|
||||
|
||||
$(objs) : Makefile
|
||||
|
||||
doc :
|
||||
|
||||
info : $(VPATH)/doc/$(pkgname).info
|
||||
|
||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texinfo
|
||||
cd $(VPATH)/doc && makeinfo $(pkgname).texinfo
|
||||
$(VPATH)/doc/$(pkgname).info : $(VPATH)/doc/$(pkgname).texi
|
||||
cd $(VPATH)/doc && $(MAKEINFO) $(pkgname).texi
|
||||
|
||||
man : $(VPATH)/doc/$(progname).1
|
||||
|
||||
$(VPATH)/doc/$(progname).1 : $(progname)
|
||||
help2man -n 'educational decompressor for lzip files' \
|
||||
-o $@ --no-info ./$(progname)
|
||||
help2man -n 'educational decompressor for the lzip format' -o $@ --no-info ./$(progname)
|
||||
|
||||
Makefile : $(VPATH)/configure $(VPATH)/Makefile.in
|
||||
./config.status
|
||||
|
@ -47,54 +50,73 @@ check : all
|
|||
@$(VPATH)/testsuite/check.sh $(VPATH)/testsuite $(pkgversion)
|
||||
|
||||
install : install-bin
|
||||
install-strip : install-bin-strip
|
||||
install-compress : install-bin
|
||||
install-strip-compress : install-bin-strip
|
||||
|
||||
install-bin : all
|
||||
if [ ! -d "$(DESTDIR)$(bindir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(bindir)" ; fi
|
||||
$(INSTALL_PROGRAM) ./$(progname) "$(DESTDIR)$(bindir)/$(progname)"
|
||||
|
||||
install-bin-strip : all
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install-bin
|
||||
|
||||
install-info :
|
||||
if [ ! -d "$(DESTDIR)$(infodir)" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(infodir)" ; fi
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(pkgname).info "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||
fi
|
||||
|
||||
install-info-compress : install-info
|
||||
lzip -v -9 "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
|
||||
install-man :
|
||||
if [ ! -d "$(DESTDIR)$(mandir)/man1" ] ; then $(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" ; fi
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||
$(INSTALL_DATA) $(VPATH)/doc/$(progname).1 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
|
||||
install-strip : all
|
||||
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
|
||||
install-man-compress : install-man
|
||||
lzip -v -9 "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
|
||||
uninstall : uninstall-bin uninstall-info uninstall-man
|
||||
uninstall : uninstall-bin
|
||||
|
||||
uninstall-bin :
|
||||
-rm -f "$(DESTDIR)$(bindir)/$(progname)"
|
||||
|
||||
uninstall-info :
|
||||
-install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"
|
||||
-if $(CAN_RUN_INSTALLINFO) ; then \
|
||||
install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$(pkgname).info" ; \
|
||||
fi
|
||||
-rm -f "$(DESTDIR)$(infodir)/$(pkgname).info"*
|
||||
|
||||
uninstall-man :
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"
|
||||
-rm -f "$(DESTDIR)$(mandir)/man1/$(progname).1"*
|
||||
|
||||
dist : doc
|
||||
ln -sf $(VPATH) $(DISTNAME)
|
||||
tar -cvf $(DISTNAME).tar \
|
||||
tar -Hustar --owner=root --group=root -cvf $(DISTNAME).tar \
|
||||
$(DISTNAME)/AUTHORS \
|
||||
$(DISTNAME)/COPYING \
|
||||
$(DISTNAME)/ChangeLog \
|
||||
$(DISTNAME)/INSTALL \
|
||||
$(DISTNAME)/Makefile.in \
|
||||
$(DISTNAME)/NEWS \
|
||||
$(DISTNAME)/README \
|
||||
$(DISTNAME)/configure \
|
||||
$(DISTNAME)/*.cc \
|
||||
$(DISTNAME)/testsuite/check.sh \
|
||||
$(DISTNAME)/testsuite/test.txt \
|
||||
$(DISTNAME)/testsuite/test.txt.lz \
|
||||
$(DISTNAME)/*.cc
|
||||
$(DISTNAME)/testsuite/em.lz \
|
||||
$(DISTNAME)/testsuite/fox.lz \
|
||||
$(DISTNAME)/testsuite/fox_*.lz \
|
||||
$(DISTNAME)/testsuite/test.txt.lz
|
||||
rm -f $(DISTNAME)
|
||||
lzip -v -9 $(DISTNAME).tar
|
||||
|
||||
clean :
|
||||
-rm -f $(progname) $(progname)_profiled $(objs)
|
||||
-rm -f $(progname) $(objs)
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile config.status *.tar *.tar.lz
|
||||
|
|
8
NEWS
8
NEWS
|
@ -1,3 +1,7 @@
|
|||
Changes in version 0.5:
|
||||
Changes in version 1.5:
|
||||
|
||||
Minor changes.
|
||||
lzd now exits with error status 2 if any empty member is found in a
|
||||
multimember file.
|
||||
|
||||
lzd now exits with error status 2 if the first byte of the LZMA stream is
|
||||
not 0.
|
||||
|
|
47
README
47
README
|
@ -1,30 +1,39 @@
|
|||
See the file INSTALL for compilation and installation instructions.
|
||||
|
||||
Description
|
||||
|
||||
Lzd is a simplified decompressor for lzip files with an educational
|
||||
purpose. Studying its source is a good first step to understand how lzip
|
||||
works. It is not safe to use lzd for any real work.
|
||||
Lzd is a simplified decompressor for the lzip format with an educational
|
||||
purpose. Studying its source code is a good first step to understand how
|
||||
lzip works. Lzd is written in C++.
|
||||
|
||||
The source of lzd is used in the lzip manual as a reference decompressor
|
||||
in the description of the lzip file format. Reading the lzip manual will
|
||||
help you understand the source.
|
||||
The source code of lzd is used in the lzip manual as a reference
|
||||
decompressor in the description of the lzip file format. Reading the lzip
|
||||
manual will help you understand the source code. Lzd is compliant with the
|
||||
lzip specification; it checks the 3 integrity factors.
|
||||
|
||||
Lzd decompresses from standard input to standard output. Lzd will
|
||||
correctly decompress the concatenation of two or more compressed files.
|
||||
The result is the concatenation of the corresponding decompressed data.
|
||||
Integrity of such concatenated compressed input is also verified.
|
||||
The source code of lzd is also used as a reference in the description of the
|
||||
media type 'application/lzip'.
|
||||
See http://datatracker.ietf.org/doc/draft-diaz-lzip
|
||||
|
||||
Lzd decompresses from standard input to standard output. It accepts (and
|
||||
ignores) the option '-d' for compatibility with other lzip tools. In
|
||||
particular, accepting the option '-d' allows lzd to be used as argument to
|
||||
the option '--lz' of the tools from the zutils package.
|
||||
|
||||
Lzd correctly decompresses the concatenation of two or more compressed
|
||||
files. The result is the concatenation of the corresponding decompressed
|
||||
data. Integrity of such concatenated compressed input is also checked.
|
||||
|
||||
The ideas embodied in lzd 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), and Igor Pavlov (for putting all the above together in
|
||||
LZMA).
|
||||
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrei Markov (for the
|
||||
definition of Markov chains), G.N.N. Martin (for the definition of range
|
||||
encoding), and Igor Pavlov (for putting all the above together in LZMA).
|
||||
|
||||
|
||||
Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
Copyright (C) 2013-2025 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
|
||||
itself.
|
||||
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 itself.
|
||||
|
|
65
configure
vendored
65
configure
vendored
|
@ -1,12 +1,12 @@
|
|||
#! /bin/sh
|
||||
# configure script for Lzd - Educational decompressor for lzip files
|
||||
# Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
# configure script for Lzd - Educational decompressor for the lzip format
|
||||
# Copyright (C) 2013-2025 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=lzd
|
||||
pkgversion=0.5
|
||||
pkgversion=1.5
|
||||
progname=lzd
|
||||
srctrigger=lzd.cc
|
||||
|
||||
|
@ -24,13 +24,10 @@ CXX=g++
|
|||
CPPFLAGS=
|
||||
CXXFLAGS='-Wall -W -O2'
|
||||
LDFLAGS=
|
||||
MAKEINFO=makeinfo
|
||||
|
||||
# checking whether we are using GNU C++.
|
||||
${CXX} --version > /dev/null 2>&1
|
||||
if [ $? != 0 ] ; then
|
||||
CXX=c++
|
||||
CXXFLAGS='-W -O2'
|
||||
fi
|
||||
/bin/sh -c "${CXX} --version" > /dev/null 2>&1 || { CXX=c++ ; CXXFLAGS=-O2 ; }
|
||||
|
||||
# Loop over all args
|
||||
args=
|
||||
|
@ -42,32 +39,38 @@ 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
|
||||
case ${option} in
|
||||
--help | -h)
|
||||
echo "Usage: configure [options]"
|
||||
echo "Usage: $0 [OPTION]... [VAR=VALUE]..."
|
||||
echo
|
||||
echo "Options: [defaults in brackets]"
|
||||
echo "To assign makefile variables (e.g., CXX, CXXFLAGS...), specify them as"
|
||||
echo "arguments to configure in the form VAR=VALUE."
|
||||
echo
|
||||
echo "Options and variables: [defaults in brackets]"
|
||||
echo " -h, --help display this help and exit"
|
||||
echo " -V, --version output version information and exit"
|
||||
echo " --srcdir=DIR find the sources in DIR [. or ..]"
|
||||
echo " --srcdir=DIR find the source code in DIR [. or ..]"
|
||||
echo " --prefix=DIR install into DIR [${prefix}]"
|
||||
echo " --exec-prefix=DIR base directory for arch-dependent files [${exec_prefix}]"
|
||||
echo " --bindir=DIR user executables directory [${bindir}]"
|
||||
echo " --datarootdir=DIR base directory for doc and data [${datarootdir}]"
|
||||
echo " --infodir=DIR info files directory [${infodir}]"
|
||||
echo " --mandir=DIR man pages directory [${mandir}]"
|
||||
echo " CXX=COMPILER C++ compiler to use [g++]"
|
||||
echo " CPPFLAGS=OPTIONS command line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " LDFLAGS=OPTIONS command line options for the linker [${LDFLAGS}]"
|
||||
echo " CXX=COMPILER C++ compiler to use [${CXX}]"
|
||||
echo " CPPFLAGS=OPTIONS command-line options for the preprocessor [${CPPFLAGS}]"
|
||||
echo " CXXFLAGS=OPTIONS command-line options for the C++ compiler [${CXXFLAGS}]"
|
||||
echo " CXXFLAGS+=OPTIONS append options to the current value of CXXFLAGS"
|
||||
echo " LDFLAGS=OPTIONS command-line options for the linker [${LDFLAGS}]"
|
||||
echo " MAKEINFO=NAME makeinfo program to use [${MAKEINFO}]"
|
||||
echo
|
||||
exit 0 ;;
|
||||
--version | -V)
|
||||
|
@ -93,7 +96,9 @@ while [ $# != 0 ] ; do
|
|||
CXX=*) CXX=${optarg} ;;
|
||||
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
|
||||
CXXFLAGS=*) CXXFLAGS=${optarg} ;;
|
||||
CXXFLAGS+=*) CXXFLAGS="${CXXFLAGS} ${optarg}" ;;
|
||||
LDFLAGS=*) LDFLAGS=${optarg} ;;
|
||||
MAKEINFO=*) MAKEINFO=${optarg} ;;
|
||||
|
||||
--*)
|
||||
echo "configure: WARNING: unrecognized option: '${option}'" 1>&2 ;;
|
||||
|
@ -104,7 +109,7 @@ while [ $# != 0 ] ; do
|
|||
exit 1 ;;
|
||||
esac
|
||||
|
||||
# Check if the option took a separate argument
|
||||
# Check whether the option took a separate argument
|
||||
if [ "${arg2}" = yes ] ; then
|
||||
if [ $# != 0 ] ; then args="${args} \"$1\"" ; shift
|
||||
else echo "configure: Missing argument to '${option}'" 1>&2
|
||||
|
@ -113,19 +118,19 @@ while [ $# != 0 ] ; do
|
|||
fi
|
||||
done
|
||||
|
||||
# Find the source files, if location was not specified.
|
||||
# Find the source code, if location was not specified.
|
||||
srcdirtext=
|
||||
if [ -z "${srcdir}" ] ; then
|
||||
srcdirtext="or . or .." ; srcdir=.
|
||||
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
|
||||
|
||||
if [ ! -r "${srcdir}/${srctrigger}" ] ; then
|
||||
echo "configure: Can't find sources in ${srcdir} ${srcdirtext}" 1>&2
|
||||
echo "configure: Can't find source code in ${srcdir} ${srcdirtext}" 1>&2
|
||||
echo "configure: (At least ${srctrigger} is missing)." 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
@ -139,13 +144,13 @@ if [ -z "${no_create}" ] ; then
|
|||
rm -f config.status
|
||||
cat > config.status << EOF
|
||||
#! /bin/sh
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
# This file was generated automatically by configure. Don't edit.
|
||||
# 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
|
||||
exec /bin/sh "$0" ${args} --no-create
|
||||
EOF
|
||||
chmod +x config.status
|
||||
fi
|
||||
|
@ -162,14 +167,15 @@ echo "CXX = ${CXX}"
|
|||
echo "CPPFLAGS = ${CPPFLAGS}"
|
||||
echo "CXXFLAGS = ${CXXFLAGS}"
|
||||
echo "LDFLAGS = ${LDFLAGS}"
|
||||
echo "MAKEINFO = ${MAKEINFO}"
|
||||
rm -f Makefile
|
||||
cat > Makefile << EOF
|
||||
# Makefile for Lzd - Educational decompressor for lzip files
|
||||
# Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
# Makefile for Lzd - Educational decompressor for the lzip format
|
||||
# Copyright (C) 2013-2025 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}
|
||||
|
@ -185,6 +191,7 @@ CXX = ${CXX}
|
|||
CPPFLAGS = ${CPPFLAGS}
|
||||
CXXFLAGS = ${CXXFLAGS}
|
||||
LDFLAGS = ${LDFLAGS}
|
||||
MAKEINFO = ${MAKEINFO}
|
||||
EOF
|
||||
cat "${srcdir}/Makefile.in" >> Makefile
|
||||
|
||||
|
|
262
lzd.cc
262
lzd.cc
|
@ -1,8 +1,16 @@
|
|||
/* Lzd - Educational decompressor for lzip files
|
||||
Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
/* Lzd - Educational decompressor for the lzip format
|
||||
Copyright (C) 2013-2025 Antonio Diaz Diaz.
|
||||
|
||||
This program is free software: you have unlimited permission
|
||||
to copy, distribute and modify it.
|
||||
This program 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.
|
||||
|
||||
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 program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
|
@ -10,8 +18,8 @@
|
|||
*/
|
||||
/*
|
||||
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.
|
||||
(file not found, invalid command-line options, I/O errors, etc), 2 to
|
||||
indicate a corrupt or invalid input file.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -21,7 +29,7 @@
|
|||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
@ -39,7 +47,7 @@ public:
|
|||
|
||||
void set_char()
|
||||
{
|
||||
static const int next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
const int next[states] = { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
st = next[st];
|
||||
}
|
||||
void set_match() { st = ( st < 7 ) ? 7 : 10; }
|
||||
|
@ -52,6 +60,7 @@ enum {
|
|||
min_dictionary_size = 1 << 12,
|
||||
max_dictionary_size = 1 << 29,
|
||||
literal_context_bits = 3,
|
||||
literal_pos_state_bits = 0, // not used
|
||||
pos_state_bits = 2,
|
||||
pos_states = 1 << pos_state_bits,
|
||||
pos_state_mask = pos_states - 1,
|
||||
|
@ -60,7 +69,7 @@ enum {
|
|||
dis_slot_bits = 6,
|
||||
start_dis_model = 4,
|
||||
end_dis_model = 14,
|
||||
modeled_distances = 1 << (end_dis_model / 2), // 128
|
||||
modeled_distances = 1 << ( end_dis_model / 2 ), // 128
|
||||
dis_align_bits = 4,
|
||||
dis_align_size = 1 << dis_align_bits,
|
||||
|
||||
|
@ -121,74 +130,82 @@ public:
|
|||
const CRC32 crc32;
|
||||
|
||||
|
||||
typedef uint8_t File_header[6]; // 0-3 magic, 4 version, 5 coded_dict_size
|
||||
|
||||
typedef uint8_t File_trailer[20];
|
||||
enum { header_size = 6, trailer_size = 20 };
|
||||
typedef uint8_t Lzip_header[header_size]; // 0-3 magic bytes
|
||||
// 4 version
|
||||
// 5 coded dictionary size
|
||||
typedef uint8_t Lzip_trailer[trailer_size];
|
||||
// 0-3 CRC32 of the uncompressed data
|
||||
// 4-11 size of the uncompressed data
|
||||
// 12-19 member size including header and trailer
|
||||
|
||||
class Range_decoder
|
||||
{
|
||||
unsigned long long member_pos;
|
||||
uint32_t code;
|
||||
uint32_t range;
|
||||
|
||||
public:
|
||||
Range_decoder() : code( 0 ), range( 0xFFFFFFFFU )
|
||||
Range_decoder()
|
||||
: member_pos( header_size ), code( 0 ), range( 0xFFFFFFFFU )
|
||||
{
|
||||
for( int i = 0; i < 5; ++i ) code = (code << 8) | get_byte();
|
||||
if( get_byte() != 0 ) // check first LZMA byte
|
||||
{ std::fputs( "Nonzero first LZMA byte.\n", stderr ); std::exit( 2 ); }
|
||||
for( int i = 0; i < 4; ++i ) code = ( code << 8 ) | get_byte();
|
||||
}
|
||||
|
||||
uint8_t get_byte() { return std::getc( stdin ); }
|
||||
uint8_t get_byte() { ++member_pos; return std::getc( stdin ); }
|
||||
unsigned long long member_position() const { return member_pos; }
|
||||
|
||||
int decode( const int num_bits )
|
||||
unsigned decode( const int num_bits )
|
||||
{
|
||||
int symbol = 0;
|
||||
for( int i = 0; i < num_bits; ++i )
|
||||
unsigned symbol = 0;
|
||||
for( int i = num_bits; i > 0; --i )
|
||||
{
|
||||
range >>= 1;
|
||||
symbol <<= 1;
|
||||
if( code >= range ) { code -= range; symbol |= 1; }
|
||||
if( range <= 0x00FFFFFFU ) // normalize
|
||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||
{ range <<= 8; code = ( code << 8 ) | get_byte(); }
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
int decode_bit( Bit_model & bm )
|
||||
bool decode_bit( Bit_model & bm )
|
||||
{
|
||||
int symbol;
|
||||
bool symbol;
|
||||
const uint32_t bound = ( range >> bit_model_total_bits ) * bm.probability;
|
||||
if( code < bound )
|
||||
{
|
||||
range = bound;
|
||||
bm.probability += (bit_model_total - bm.probability) >> bit_model_move_bits;
|
||||
bm.probability +=
|
||||
( bit_model_total - bm.probability ) >> bit_model_move_bits;
|
||||
symbol = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
range -= bound;
|
||||
code -= bound;
|
||||
range -= bound;
|
||||
bm.probability -= bm.probability >> bit_model_move_bits;
|
||||
symbol = 1;
|
||||
}
|
||||
if( range <= 0x00FFFFFFU ) // normalize
|
||||
{ range <<= 8; code = (code << 8) | get_byte(); }
|
||||
{ range <<= 8; code = ( code << 8 ) | get_byte(); }
|
||||
return symbol;
|
||||
}
|
||||
|
||||
int decode_tree( Bit_model bm[], const int num_bits )
|
||||
unsigned decode_tree( Bit_model bm[], const int num_bits )
|
||||
{
|
||||
int symbol = 1;
|
||||
unsigned symbol = 1;
|
||||
for( int i = 0; i < num_bits; ++i )
|
||||
symbol = ( symbol << 1 ) | decode_bit( bm[symbol] );
|
||||
return symbol - (1 << num_bits);
|
||||
return symbol - ( 1 << num_bits );
|
||||
}
|
||||
|
||||
int decode_tree_reversed( Bit_model bm[], const int num_bits )
|
||||
unsigned decode_tree_reversed( Bit_model bm[], const int num_bits )
|
||||
{
|
||||
int symbol = decode_tree( bm, num_bits );
|
||||
int reversed_symbol = 0;
|
||||
unsigned symbol = decode_tree( bm, num_bits );
|
||||
unsigned reversed_symbol = 0;
|
||||
for( int i = 0; i < num_bits; ++i )
|
||||
{
|
||||
reversed_symbol = ( reversed_symbol << 1 ) | ( symbol & 1 );
|
||||
|
@ -197,14 +214,13 @@ public:
|
|||
return reversed_symbol;
|
||||
}
|
||||
|
||||
int decode_matched( Bit_model bm[], const int match_byte )
|
||||
unsigned decode_matched( Bit_model bm[], const unsigned match_byte )
|
||||
{
|
||||
Bit_model * const bm1 = bm + 0x100;
|
||||
int symbol = 1;
|
||||
unsigned symbol = 1;
|
||||
for( int i = 7; i >= 0; --i )
|
||||
{
|
||||
const int match_bit = ( match_byte >> i ) & 1;
|
||||
const int bit = decode_bit( bm1[(match_bit<<8)+symbol] );
|
||||
const bool match_bit = ( match_byte >> i ) & 1;
|
||||
const bool bit = decode_bit( bm[symbol+(match_bit<<8)+0x100] );
|
||||
symbol = ( symbol << 1 ) | bit;
|
||||
if( match_bit != bit )
|
||||
{
|
||||
|
@ -213,17 +229,18 @@ public:
|
|||
break;
|
||||
}
|
||||
}
|
||||
return symbol - 0x100;
|
||||
return symbol & 0xFF;
|
||||
}
|
||||
|
||||
int decode_len( Len_model & lm, const int pos_state )
|
||||
unsigned decode_len( Len_model & lm, const int pos_state )
|
||||
{
|
||||
if( decode_bit( lm.choice1 ) == 0 )
|
||||
return decode_tree( lm.bm_low[pos_state], len_low_bits );
|
||||
return min_match_len +
|
||||
decode_tree( lm.bm_low[pos_state], len_low_bits );
|
||||
if( decode_bit( lm.choice2 ) == 0 )
|
||||
return len_low_symbols +
|
||||
return min_match_len + len_low_symbols +
|
||||
decode_tree( lm.bm_mid[pos_state], len_mid_bits );
|
||||
return len_low_symbols + len_mid_symbols +
|
||||
return min_match_len + len_low_symbols + len_mid_symbols +
|
||||
decode_tree( lm.bm_high, len_high_bits );
|
||||
}
|
||||
};
|
||||
|
@ -238,14 +255,15 @@ class LZ_decoder
|
|||
unsigned pos; // current pos in buffer
|
||||
unsigned stream_pos; // first byte not yet written to stdout
|
||||
uint32_t crc_;
|
||||
bool pos_wrapped;
|
||||
|
||||
void flush_data();
|
||||
|
||||
uint8_t get_byte( const unsigned distance ) const
|
||||
uint8_t peek( const unsigned distance ) const
|
||||
{
|
||||
unsigned i = pos - distance - 1;
|
||||
if( pos <= distance ) i += dictionary_size;
|
||||
return buffer[i];
|
||||
if( pos > distance ) return buffer[pos - distance - 1];
|
||||
if( pos_wrapped ) return buffer[dictionary_size + pos - distance - 1];
|
||||
return 0; // prev_byte of first byte
|
||||
}
|
||||
|
||||
void put_byte( const uint8_t b )
|
||||
|
@ -255,20 +273,25 @@ class LZ_decoder
|
|||
}
|
||||
|
||||
public:
|
||||
LZ_decoder( const unsigned dict_size )
|
||||
explicit LZ_decoder( const unsigned dict_size )
|
||||
:
|
||||
partial_data_pos( 0 ),
|
||||
dictionary_size( dict_size ),
|
||||
buffer( new uint8_t[dictionary_size] ),
|
||||
pos( 0 ),
|
||||
stream_pos( 0 ),
|
||||
crc_( 0xFFFFFFFFU )
|
||||
{ buffer[dictionary_size-1] = 0; } // prev_byte of first_byte
|
||||
crc_( 0xFFFFFFFFU ),
|
||||
pos_wrapped( false )
|
||||
{}
|
||||
|
||||
~LZ_decoder() { delete[] buffer; }
|
||||
|
||||
unsigned crc() const { return crc_ ^ 0xFFFFFFFFU; }
|
||||
unsigned long long data_position() const { return partial_data_pos + pos; }
|
||||
unsigned long long data_position() const
|
||||
{ return partial_data_pos + pos; }
|
||||
uint8_t get_byte() { return rdec.get_byte(); }
|
||||
unsigned long long member_position() const
|
||||
{ return rdec.member_position(); }
|
||||
|
||||
bool decode_member();
|
||||
};
|
||||
|
@ -280,17 +303,17 @@ void LZ_decoder::flush_data()
|
|||
{
|
||||
const unsigned size = pos - stream_pos;
|
||||
crc32.update_buf( crc_, buffer + stream_pos, size );
|
||||
errno = 0;
|
||||
if( std::fwrite( buffer + stream_pos, 1, size, stdout ) != size )
|
||||
{ std::fprintf( stderr, "Write error: %s\n", std::strerror( errno ) );
|
||||
std::exit( 1 ); }
|
||||
if( pos >= dictionary_size ) { partial_data_pos += pos; pos = 0; }
|
||||
if( pos >= dictionary_size )
|
||||
{ partial_data_pos += pos; pos = 0; pos_wrapped = true; }
|
||||
stream_pos = pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LZ_decoder::decode_member() // Returns false if error
|
||||
bool LZ_decoder::decode_member() // Return false if error
|
||||
{
|
||||
Bit_model bm_literal[1<<literal_context_bits][0x300];
|
||||
Bit_model bm_match[State::states][pos_states];
|
||||
|
@ -300,7 +323,7 @@ bool LZ_decoder::decode_member() // Returns false if error
|
|||
Bit_model bm_rep2[State::states];
|
||||
Bit_model bm_len[State::states][pos_states];
|
||||
Bit_model bm_dis_slot[len_states][1<<dis_slot_bits];
|
||||
Bit_model bm_dis[modeled_distances-end_dis_model];
|
||||
Bit_model bm_dis[modeled_distances-end_dis_model+1];
|
||||
Bit_model bm_align[dis_align_size];
|
||||
Len_model match_len_model;
|
||||
Len_model rep_len_model;
|
||||
|
@ -315,21 +338,27 @@ bool LZ_decoder::decode_member() // Returns false if error
|
|||
const int pos_state = data_position() & pos_state_mask;
|
||||
if( rdec.decode_bit( bm_match[state()][pos_state] ) == 0 ) // 1st bit
|
||||
{
|
||||
const uint8_t prev_byte = get_byte( 0 );
|
||||
// literal byte
|
||||
const uint8_t prev_byte = peek( 0 );
|
||||
const int literal_state = prev_byte >> ( 8 - literal_context_bits );
|
||||
Bit_model * const bm = bm_literal[literal_state];
|
||||
if( state.is_char() )
|
||||
put_byte( rdec.decode_tree( bm, 8 ) );
|
||||
else
|
||||
put_byte( rdec.decode_matched( bm, get_byte( rep0 ) ) );
|
||||
put_byte( rdec.decode_matched( bm, peek( rep0 ) ) );
|
||||
state.set_char();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// match or repeated match
|
||||
int len;
|
||||
if( rdec.decode_bit( bm_rep[state()] ) != 0 ) // 2nd bit
|
||||
{
|
||||
if( rdec.decode_bit( bm_rep0[state()] ) != 0 ) // 3rd bit
|
||||
if( rdec.decode_bit( bm_rep0[state()] ) == 0 ) // 3rd bit
|
||||
{
|
||||
if( rdec.decode_bit( bm_len[state()][pos_state] ) == 0 ) // 4th bit
|
||||
{ state.set_short_rep(); put_byte( peek( rep0 ) ); continue; }
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned distance;
|
||||
if( rdec.decode_bit( bm_rep1[state()] ) == 0 ) // 4th bit
|
||||
|
@ -345,116 +374,119 @@ bool LZ_decoder::decode_member() // Returns false if error
|
|||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( rdec.decode_bit( bm_len[state()][pos_state] ) == 0 ) // 4th bit
|
||||
{ state.set_short_rep(); put_byte( get_byte( rep0 ) ); continue; }
|
||||
}
|
||||
state.set_rep();
|
||||
len = min_match_len + rdec.decode_len( rep_len_model, pos_state );
|
||||
len = rdec.decode_len( rep_len_model, pos_state );
|
||||
}
|
||||
else
|
||||
else // match
|
||||
{
|
||||
rep3 = rep2; rep2 = rep1; rep1 = rep0;
|
||||
len = min_match_len + rdec.decode_len( match_len_model, pos_state );
|
||||
len = rdec.decode_len( match_len_model, pos_state );
|
||||
const int len_state = std::min( len - min_match_len, len_states - 1 );
|
||||
const int dis_slot =
|
||||
rdec.decode_tree( bm_dis_slot[len_state], dis_slot_bits );
|
||||
if( dis_slot < start_dis_model ) rep0 = dis_slot;
|
||||
else
|
||||
rep0 = rdec.decode_tree( bm_dis_slot[len_state], dis_slot_bits );
|
||||
if( rep0 >= start_dis_model )
|
||||
{
|
||||
const unsigned dis_slot = rep0;
|
||||
const int direct_bits = ( dis_slot >> 1 ) - 1;
|
||||
rep0 = ( 2 | ( dis_slot & 1 ) ) << direct_bits;
|
||||
if( dis_slot < end_dis_model )
|
||||
rep0 += rdec.decode_tree_reversed( bm_dis + rep0 - dis_slot - 1,
|
||||
rep0 += rdec.decode_tree_reversed( bm_dis + ( rep0 - dis_slot ),
|
||||
direct_bits );
|
||||
else
|
||||
{
|
||||
rep0 += rdec.decode( direct_bits - dis_align_bits ) << dis_align_bits;
|
||||
rep0 += rdec.decode( direct_bits-dis_align_bits ) << dis_align_bits;
|
||||
rep0 += rdec.decode_tree_reversed( bm_align, dis_align_bits );
|
||||
if( rep0 == 0xFFFFFFFFU ) // Marker found
|
||||
if( rep0 == 0xFFFFFFFFU ) // marker found
|
||||
{
|
||||
flush_data();
|
||||
return ( len == min_match_len ); // End Of Stream marker
|
||||
return len == min_match_len; // End Of Stream marker
|
||||
}
|
||||
}
|
||||
}
|
||||
state.set_match();
|
||||
if( rep0 >= dictionary_size || ( rep0 >= pos && !partial_data_pos ) )
|
||||
return false;
|
||||
}
|
||||
for( int i = 0; i < len; ++i )
|
||||
put_byte( get_byte( rep0 ) );
|
||||
if( rep0 >= dictionary_size || ( rep0 >= pos && !pos_wrapped ) )
|
||||
{ flush_data(); return false; }
|
||||
}
|
||||
for( int i = 0; i < len; ++i ) put_byte( peek( rep0 ) );
|
||||
}
|
||||
flush_data();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int main( const int argc, const char * const argv[] )
|
||||
{
|
||||
if( argc > 1 )
|
||||
if( argc > 2 || ( argc == 2 && std::strcmp( argv[1], "-d" ) != 0 ) )
|
||||
{
|
||||
std::printf( "Lzd %s - Educational decompressor for lzip files.\n",
|
||||
PROGVERSION );
|
||||
std::printf( "Study the source to learn how a lzip decompressor works.\n"
|
||||
std::printf(
|
||||
"Lzd %s - Educational decompressor for the lzip format.\n"
|
||||
"Study the source code to learn how a lzip decompressor works.\n"
|
||||
"See the lzip manual for an explanation of the code.\n"
|
||||
"It is not safe to use lzd for any real work.\n"
|
||||
"\nUsage: %s < file.lz > file\n", argv[0] );
|
||||
std::printf( "Lzd decompresses from standard input to standard output.\n"
|
||||
"\nCopyright (C) 2013 Antonio Diaz Diaz.\n"
|
||||
"This is free software: you are free to change and redistribute it.\n"
|
||||
"There is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"\nUsage: %s [-d] < file.lz > file\n"
|
||||
"Lzd decompresses from standard input to standard output.\n"
|
||||
"\nCopyright (C) 2025 Antonio Diaz Diaz.\n"
|
||||
"License 2-clause BSD.\n"
|
||||
"This is free software: you are free to change and redistribute "
|
||||
"it.\nThere is NO WARRANTY, to the extent permitted by law.\n"
|
||||
"Report bugs to lzip-bug@nongnu.org\n"
|
||||
"Lzd home page: http://www.nongnu.org/lzip/lzd.html\n" );
|
||||
"Lzd home page: http://www.nongnu.org/lzip/lzd.html\n",
|
||||
PROGVERSION, argv[0] );
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
#if defined __MSVCRT__ || defined __OS2__ || defined __DJGPP__
|
||||
setmode( STDIN_FILENO, O_BINARY );
|
||||
setmode( STDOUT_FILENO, O_BINARY );
|
||||
#endif
|
||||
|
||||
bool empty = false, multi = false;
|
||||
for( bool first_member = true; ; first_member = false )
|
||||
{
|
||||
File_header header;
|
||||
for( int i = 0; i < 6; ++i )
|
||||
header[i] = std::getc( stdin );
|
||||
if( std::feof( stdin ) || std::memcmp( header, "LZIP", 4 ) != 0 )
|
||||
Lzip_header header; // check header
|
||||
for( int i = 0; i < header_size; ++i ) header[i] = std::getc( stdin );
|
||||
if( std::feof( stdin ) || std::memcmp( header, "LZIP\x01", 5 ) != 0 )
|
||||
{
|
||||
if( first_member )
|
||||
{ std::fprintf( stderr, "Bad magic number (file not in lzip format)\n" );
|
||||
return 2; }
|
||||
break;
|
||||
}
|
||||
if( header[4] != 1 )
|
||||
{
|
||||
std::fprintf( stderr, "Version %d member format not supported.\n",
|
||||
header[4] );
|
||||
return 2;
|
||||
{ std::fputs( "Bad magic number (file not in lzip format).\n",
|
||||
stderr ); return 2; }
|
||||
break; // ignore trailing data
|
||||
}
|
||||
unsigned dict_size = 1 << ( header[5] & 0x1F );
|
||||
dict_size -= ( dict_size / 16 ) * ( ( header[5] >> 5 ) & 7 );
|
||||
if( dict_size < min_dictionary_size || dict_size > max_dictionary_size )
|
||||
{ std::fprintf( stderr, "Invalid dictionary size in member header\n" );
|
||||
return 2; }
|
||||
{ std::fputs( "Invalid dictionary size in member header.\n",
|
||||
stderr ); return 2; }
|
||||
|
||||
LZ_decoder decoder( dict_size );
|
||||
LZ_decoder decoder( dict_size ); // decode LZMA stream
|
||||
if( !decoder.decode_member() )
|
||||
{ std::fprintf( stderr, "Data error\n" ); return 2; }
|
||||
{ std::fputs( "Data error.\n", stderr ); return 2; }
|
||||
|
||||
File_trailer trailer;
|
||||
for( int i = 0; i < 20; ++i ) trailer[i] = std::getc( stdin );
|
||||
Lzip_trailer trailer; // check trailer
|
||||
for( int i = 0; i < trailer_size; ++i ) trailer[i] = decoder.get_byte();
|
||||
int retval = 0;
|
||||
unsigned crc = 0;
|
||||
for( int i = 3; i >= 0; --i ) { crc <<= 8; crc += trailer[i]; }
|
||||
for( int i = 3; i >= 0; --i ) crc = ( crc << 8 ) + trailer[i];
|
||||
if( crc != decoder.crc() )
|
||||
{ std::fputs( "CRC mismatch.\n", stderr ); retval = 2; }
|
||||
|
||||
unsigned long long data_size = 0;
|
||||
for( int i = 11; i >= 4; --i ) { data_size <<= 8; data_size += trailer[i]; }
|
||||
if( crc != decoder.crc() || data_size != decoder.data_position() )
|
||||
{ std::fprintf( stderr, "CRC error\n" ); return 2; }
|
||||
for( int i = 11; i >= 4; --i )
|
||||
data_size = ( data_size << 8 ) + trailer[i];
|
||||
if( data_size != decoder.data_position() )
|
||||
{ std::fputs( "Data size mismatch.\n", stderr ); retval = 2; }
|
||||
multi = !first_member; if( data_size == 0 ) empty = true;
|
||||
|
||||
unsigned long long member_size = 0;
|
||||
for( int i = 19; i >= 12; --i )
|
||||
member_size = ( member_size << 8 ) + trailer[i];
|
||||
if( member_size != decoder.member_position() )
|
||||
{ std::fputs( "Member size mismatch.\n", stderr ); retval = 2; }
|
||||
if( retval ) return retval;
|
||||
}
|
||||
|
||||
if( std::fclose( stdout ) != 0 )
|
||||
{ std::fprintf( stderr, "Can't close stdout: %s\n", std::strerror( errno ) );
|
||||
return 1; }
|
||||
{ std::fprintf( stderr, "Error closing stdout: %s\n",
|
||||
std::strerror( errno ) ); return 1; }
|
||||
if( empty && multi )
|
||||
{ std::fputs( "Empty member not allowed.\n", stderr ); return 2; }
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#! /bin/sh
|
||||
# check script for Lzd - Educational decompressor for lzip files
|
||||
# Copyright (C) 2013 Antonio Diaz Diaz.
|
||||
# check script for Lzd - Educational decompressor for the lzip format
|
||||
# Copyright (C) 2013-2025 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
|
||||
|
@ -12,36 +12,104 @@ testdir=`cd "$1" ; pwd`
|
|||
LZIP="${objdir}"/lzd
|
||||
framework_failure() { echo "failure in testing framework" ; exit 1 ; }
|
||||
|
||||
if [ ! -x "${LZIP}" ] ; then
|
||||
if [ ! -f "${LZIP}" ] || [ ! -x "${LZIP}" ] ; then
|
||||
echo "${LZIP}: cannot execute"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -e "${LZIP}" ] 2> /dev/null ||
|
||||
{
|
||||
echo "$0: a POSIX shell is required to run the tests"
|
||||
echo "Try bash -c \"$0 $1 $2\""
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ -d tmp ] ; then rm -rf tmp ; fi
|
||||
mkdir tmp
|
||||
cd "${objdir}"/tmp
|
||||
cd "${objdir}"/tmp || framework_failure
|
||||
|
||||
in="${testdir}"/test.txt
|
||||
in_lz="${testdir}"/test.txt.lz
|
||||
em_lz="${testdir}"/em.lz
|
||||
fox_lz="${testdir}"/fox.lz
|
||||
fnz_lz="${testdir}"/fox_nz.lz
|
||||
fail=0
|
||||
test_failed() { fail=1 ; printf " $1" ; [ -z "$2" ] || printf "($2)" ; }
|
||||
|
||||
printf "testing lzd-%s..." "$2"
|
||||
|
||||
"${LZIP}" < "${in}" 2> /dev/null
|
||||
if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi
|
||||
dd if="${in_lz}" bs=1 count=6 2> /dev/null | "${LZIP}" 2> /dev/null
|
||||
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||
dd if="${in_lz}" bs=1 count=20 2> /dev/null | "${LZIP}" 2> /dev/null
|
||||
if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
|
||||
"${LZIP}" < "${in_lz}" > copy || fail=1
|
||||
cmp "${in}" copy || fail=1
|
||||
printf .
|
||||
"${LZIP}" < "${in_lz}" > out || test_failed $LINENO
|
||||
cmp "${in}" out || test_failed $LINENO
|
||||
|
||||
cat "${in}" "${in}" > in2 || framework_failure
|
||||
cat "${in_lz}" "${in_lz}" | "${LZIP}" > copy2 || fail=1
|
||||
cmp in2 copy2 || fail=1
|
||||
printf .
|
||||
cat "${in_lz}" "${in_lz}" | "${LZIP}" > out2 || test_failed $LINENO
|
||||
cmp in2 out2 || test_failed $LINENO
|
||||
rm -f out2 || framework_failure
|
||||
|
||||
cat "${in_lz}" "${in_lz}" > out2.lz || framework_failure
|
||||
printf "\ngarbage" >> out2.lz || framework_failure
|
||||
"${LZIP}" -d < out2.lz > out2 || test_failed $LINENO
|
||||
cmp in2 out2 || test_failed $LINENO
|
||||
rm -f in2 out2 out2.lz || framework_failure
|
||||
|
||||
touch empty || framework_failure
|
||||
"${LZIP}" -d < "${em_lz}" > em || test_failed $LINENO
|
||||
cmp empty em || test_failed $LINENO
|
||||
|
||||
printf "\ntesting bad input..."
|
||||
|
||||
cat "${em_lz}" "${em_lz}" | "${LZIP}" -d > em 2> /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
cmp empty em || test_failed $LINENO
|
||||
rm -f empty em || framework_failure
|
||||
cat "${em_lz}" "${in_lz}" | "${LZIP}" -d > out 2> /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
cmp "${in}" out || test_failed $LINENO
|
||||
cat "${in_lz}" "${em_lz}" | "${LZIP}" -d > out 2> /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
cmp "${in}" out || test_failed $LINENO
|
||||
|
||||
"${LZIP}" < "${fnz_lz}" 2> /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO
|
||||
|
||||
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}" < "${testdir}"/$i > /dev/null 2>&1
|
||||
[ $? = 2 ] || test_failed $LINENO $i
|
||||
done
|
||||
|
||||
"${LZIP}" < "${fox_lz}" > fox || test_failed $LINENO
|
||||
for i in fox_bcrc.lz fox_crc0.lz fox_das46.lz fox_mes81.lz ; do
|
||||
"${LZIP}" < "${testdir}"/$i > out 2> /dev/null
|
||||
[ $? = 2 ] || test_failed $LINENO $i
|
||||
cmp fox out || test_failed $LINENO $i
|
||||
done
|
||||
rm -f fox || 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=14682 count=1 2> /dev/null &&
|
||||
[ -e trunc.lz ] && cmp in2.lz trunc.lz ; then
|
||||
# can't detect truncated header of non-first member
|
||||
for i in 6 20 14664 14688 ; do
|
||||
dd if=in3.lz of=trunc.lz bs=$i count=1 2> /dev/null
|
||||
"${LZIP}" < trunc.lz > /dev/null 2>&1
|
||||
[ $? = 2 ] || test_failed $LINENO $i
|
||||
done
|
||||
else
|
||||
printf "warning: skipping truncation test: 'dd' does not work on your system."
|
||||
fi
|
||||
rm -f in2.lz in3.lz trunc.lz || framework_failure
|
||||
|
||||
cp "${in_lz}" ingin.lz || framework_failure
|
||||
printf "g" >> ingin.lz || framework_failure
|
||||
cat "${in_lz}" >> ingin.lz || framework_failure
|
||||
"${LZIP}" -d < ingin.lz > out || test_failed $LINENO
|
||||
cmp "${in}" out || test_failed $LINENO
|
||||
rm -f out ingin.lz || framework_failure
|
||||
|
||||
echo
|
||||
if [ ${fail} = 0 ] ; then
|
||||
|
|
BIN
testsuite/em.lz
Normal file
BIN
testsuite/em.lz
Normal file
Binary file not shown.
BIN
testsuite/fox.lz
Normal file
BIN
testsuite/fox.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_bcrc.lz
Normal file
BIN
testsuite/fox_bcrc.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_crc0.lz
Normal file
BIN
testsuite/fox_crc0.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_das46.lz
Normal file
BIN
testsuite/fox_das46.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_de20.lz
Normal file
BIN
testsuite/fox_de20.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_mes81.lz
Normal file
BIN
testsuite/fox_mes81.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_nz.lz
Normal file
BIN
testsuite/fox_nz.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_s11.lz
Normal file
BIN
testsuite/fox_s11.lz
Normal file
Binary file not shown.
BIN
testsuite/fox_v2.lz
Normal file
BIN
testsuite/fox_v2.lz
Normal file
Binary file not shown.
1202
testsuite/test.txt
1202
testsuite/test.txt
File diff suppressed because it is too large
Load diff
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue