Merging upstream version 1.13.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
e51de8f895
commit
a4df31fc03
21 changed files with 720 additions and 282 deletions
51
ChangeLog
51
ChangeLog
|
@ -1,49 +1,49 @@
|
|||
2011-11-20 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
2012-02-24 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.13-rc2 released.
|
||||
* Added new option `-D, --range-decompress' which extracts a
|
||||
range of bytes decompressing only the members containing the
|
||||
desired data.
|
||||
* Added new option `-l, --list' which prints correct total file
|
||||
sizes and ratios even for multimember files.
|
||||
* New file range_dec.cc.
|
||||
* testsuite/check.sh: Do not use `ln'. `ln' doesn't work on OS/2.
|
||||
|
||||
2011-11-12 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.13-rc1 released.
|
||||
* Version 1.13 released.
|
||||
* Lziprecover is now distributed in its own package. Until
|
||||
version 1.12 it was included in the lzip package.
|
||||
version 1.12 it was included in the lzip package. Previous
|
||||
entries in this file are taken from there.
|
||||
* lziprecover.cc: Renamed to main.cc.
|
||||
* New files merge.cc, repair.cc, split.cc, and range_dec.cc.
|
||||
* main.cc: Added decompressor options (-c, -d, -k, -t) so that
|
||||
a external decompressor is not needed for recovery nor for
|
||||
"make check".
|
||||
* New files merge.cc, repair.cc and split.cc.
|
||||
* Added new option '-D, --range-decompress' which extracts a
|
||||
range of bytes decompressing only the members containing the
|
||||
desired data.
|
||||
* Added new option '-l, --list' which prints correct total file
|
||||
sizes and ratios even for multi-member files.
|
||||
* merge.cc repair.cc: Remove output file if recovery fails.
|
||||
* Changed quote characters in messages as advised by GNU Standards.
|
||||
* split.cc: Use Boyer-Moore algorithm to search for headers.
|
||||
* testsuite/check.sh: Use `ln' instead of `cat' for input files.
|
||||
* configure: 'datadir' renamed to 'datarootdir'.
|
||||
|
||||
2011-04-30 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.12 released.
|
||||
* lziprecover.cc: If `-v' is not specified show errors only.
|
||||
* lziprecover.cc: If '-v' is not specified show errors only.
|
||||
* testsuite/unzcrash.cc: Use Arg_parser.
|
||||
* testsuite/unzcrash.cc: Added new option '-b, --bits'.
|
||||
* testsuite/unzcrash.cc: Added new option '-p, --position'.
|
||||
* testsuite/unzcrash.cc: Added new option '-s, --size'.
|
||||
|
||||
2010-09-16 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.11 released.
|
||||
* lziprecover.cc: Added new option `-m, --merge' which tries to
|
||||
* lziprecover.cc: Added new option '-m, --merge' which tries to
|
||||
produce a correct file merging the good parts of two or more
|
||||
damaged copies.
|
||||
* lziprecover.cc: Added new option `-R, --repair' for repairing
|
||||
* lziprecover.cc: Added new option '-R, --repair' for repairing
|
||||
a 1-byte error in single-member files.
|
||||
* decoder.cc (decode_member): Detect file errors earlier to
|
||||
improve efficiency of lziprecover's new repair capability.
|
||||
This change also prevents (harmless) access to uninitialized
|
||||
memory when decompressing a corrupt file.
|
||||
* lziprecover.cc: Added new option `-f, --force'.
|
||||
* lziprecover.cc: Added new option `-o, --output'.
|
||||
* lziprecover.cc: Added new option `-s, --split' to select the
|
||||
until now only operation of splitting multimember files.
|
||||
* lziprecover.cc: Added new option '-f, --force'.
|
||||
* lziprecover.cc: Added new option '-o, --output'.
|
||||
* lziprecover.cc: Added new option '-s, --split' to select the
|
||||
until now only operation of splitting multi-member files.
|
||||
* lziprecover.cc: If no operation is specified, warn the user
|
||||
and do nothing.
|
||||
|
||||
|
@ -56,10 +56,11 @@
|
|||
2009-01-24 Antonio Diaz Diaz <ant_diaz@teleline.es>
|
||||
|
||||
* Version 1.4 released.
|
||||
* Added `lziprecover', a member recoverer program.
|
||||
* Added 'lziprecover', a member recoverer program.
|
||||
* testsuite/unzcrash.cc: Test all 1-byte errors.
|
||||
|
||||
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
|
24
INSTALL
24
INSTALL
|
@ -18,7 +18,7 @@ This creates the directory ./lziprecover[version] containing the source
|
|||
from the main archive.
|
||||
|
||||
2. Change to lziprecover directory and run configure.
|
||||
(Try `configure --help' for usage instructions).
|
||||
(Try 'configure --help' for usage instructions).
|
||||
|
||||
cd lziprecover[version]
|
||||
./configure
|
||||
|
@ -27,31 +27,31 @@ from the main archive.
|
|||
|
||||
make
|
||||
|
||||
4. Optionally, type `make check' to run the tests that come with
|
||||
4. Optionally, type 'make check' to run the tests that come with
|
||||
lziprecover.
|
||||
|
||||
5. Type `make install' to install the programs and any data files and
|
||||
5. Type 'make install' to install the programs and any data files and
|
||||
documentation.
|
||||
|
||||
|
||||
Another way
|
||||
-----------
|
||||
You can also compile lziprecover 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 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.
|
||||
|
||||
`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 sources. Usually 'configure' can determine that directory
|
||||
automatically.
|
||||
|
||||
After running `configure', you can run `make' and `make install' as
|
||||
After running 'configure', you can run 'make' and 'make install' as
|
||||
explained above.
|
||||
|
||||
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
distribute and modify it.
|
||||
|
|
10
Makefile.in
10
Makefile.in
|
@ -7,6 +7,7 @@ INSTALL_DIR = $(INSTALL) -d -m 755
|
|||
SHELL = /bin/sh
|
||||
|
||||
objs = arg_parser.o decoder.o merge.o range_dec.o repair.o split.o main.o
|
||||
unzobjs = arg_parser.o unzcrash.o
|
||||
|
||||
|
||||
.PHONY : all install install-info install-man install-strip \
|
||||
|
@ -21,9 +22,15 @@ $(progname) : $(objs)
|
|||
$(progname)_profiled : $(objs)
|
||||
$(CXX) $(LDFLAGS) -pg -o $@ $(objs)
|
||||
|
||||
unzcrash : $(unzobjs)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(unzobjs)
|
||||
|
||||
main.o : main.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
unzcrash.o : testsuite/unzcrash.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -DPROGVERSION=\"$(pkgversion)\" -c -o $@ $<
|
||||
|
||||
%.o : %.cc
|
||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
|
@ -35,6 +42,7 @@ merge.o : lzip.h decoder.h
|
|||
range_dec.o : lzip.h decoder.h
|
||||
repair.o : lzip.h
|
||||
split.o : lzip.h
|
||||
unzcrash.o : arg_parser.h Makefile
|
||||
|
||||
|
||||
doc : info man
|
||||
|
@ -101,6 +109,7 @@ dist : doc
|
|||
$(DISTNAME)/testsuite/test921-1921.txt \
|
||||
$(DISTNAME)/testsuite/test_bad[1-5].lz \
|
||||
$(DISTNAME)/testsuite/test_v[01].lz \
|
||||
$(DISTNAME)/testsuite/unzcrash.cc \
|
||||
$(DISTNAME)/*.h \
|
||||
$(DISTNAME)/*.cc
|
||||
rm -f $(DISTNAME)
|
||||
|
@ -108,6 +117,7 @@ dist : doc
|
|||
|
||||
clean :
|
||||
-rm -f $(progname) $(progname)_profiled $(objs)
|
||||
-rm -f unzcrash unzcrash.o
|
||||
|
||||
distclean : clean
|
||||
-rm -f Makefile config.status *.tar *.tar.lz
|
||||
|
|
8
NEWS
8
NEWS
|
@ -12,6 +12,12 @@ decompressing only the members containing the desired data, has been
|
|||
added.
|
||||
|
||||
The new option "-l, --list" which prints correct total file sizes and
|
||||
ratios even for multimember files, has been added.
|
||||
ratios even for multi-member files, has been added.
|
||||
|
||||
"--merge" and "--repair" now remove the output file if recovery fails.
|
||||
|
||||
Quote characters in messages have been changed as advised by GNU Coding
|
||||
Standards.
|
||||
|
||||
Configure option "--datadir" has been renamed to "--datarootdir" to
|
||||
follow GNU Standards.
|
||||
|
|
17
README
17
README
|
@ -11,6 +11,13 @@ the compressors in the lzip family; lzip, plzip, minilzip/lzlib, clzip
|
|||
and pdlzip. This recovery capability contributes to make the lzip format
|
||||
one of the best options for long-term data archiving.
|
||||
|
||||
Lziprecover is able to efficiently extract a range of bytes from a
|
||||
multi-member file, because it only decompresses the members containing
|
||||
the desired data.
|
||||
|
||||
Lziprecover can print correct total file sizes and ratios even for
|
||||
multi-member files.
|
||||
|
||||
When recovering data, lziprecover takes as arguments the names of the
|
||||
damaged files and writes zero or more recovered files depending on the
|
||||
operation selected and whether the recovery succeeded or not. The
|
||||
|
@ -32,3 +39,13 @@ copies.
|
|||
If the cause of file corruption is damaged media, the combination
|
||||
GNU ddrescue + lziprecover is the best option for recovering data from
|
||||
multiple damaged copies.
|
||||
|
||||
|
||||
Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
|
||||
This file is free documentation: you have unlimited permission to copy,
|
||||
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.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Antonio Diaz Diaz.
|
||||
|
||||
This library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -55,30 +56,30 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
|
|||
|
||||
if( ambig && !exact )
|
||||
{
|
||||
error_ = "option `"; error_ += opt; error_ += "' is ambiguous";
|
||||
error_ = "option '"; error_ += opt; error_ += "' is ambiguous";
|
||||
return false;
|
||||
}
|
||||
|
||||
if( index < 0 ) // nothing found
|
||||
{
|
||||
error_ = "unrecognized option `"; error_ += opt; error_ += '\'';
|
||||
error_ = "unrecognized option '"; error_ += opt; error_ += '\'';
|
||||
return false;
|
||||
}
|
||||
|
||||
++argind;
|
||||
data.push_back( Record( options[index].code ) );
|
||||
|
||||
if( opt[len+2] ) // `--<long_option>=<argument>' syntax
|
||||
if( opt[len+2] ) // '--<long_option>=<argument>' syntax
|
||||
{
|
||||
if( options[index].has_arg == no )
|
||||
{
|
||||
error_ = "option `--"; error_ += options[index].name;
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' doesn't allow an argument";
|
||||
return false;
|
||||
}
|
||||
if( options[index].has_arg == yes && !opt[len+3] )
|
||||
{
|
||||
error_ = "option `--"; error_ += options[index].name;
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' requires an argument";
|
||||
return false;
|
||||
}
|
||||
|
@ -90,7 +91,7 @@ bool Arg_parser::parse_long_option( const char * const opt, const char * const a
|
|||
{
|
||||
if( !arg || !arg[0] )
|
||||
{
|
||||
error_ = "option `--"; error_ += options[index].name;
|
||||
error_ = "option '--"; error_ += options[index].name;
|
||||
error_ += "' requires an argument";
|
||||
return false;
|
||||
}
|
||||
|
|
27
arg_parser.h
27
arg_parser.h
|
@ -1,5 +1,6 @@
|
|||
/* Arg_parser - POSIX/GNU command line argument parser. (C++ version)
|
||||
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012
|
||||
Antonio Diaz Diaz.
|
||||
|
||||
This library is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
|
@ -25,12 +26,12 @@
|
|||
Public License.
|
||||
*/
|
||||
|
||||
/* Arg_parser reads the arguments in `argv' and creates a number of
|
||||
/* Arg_parser reads the arguments in 'argv' and creates a number of
|
||||
option codes, option arguments and non-option arguments.
|
||||
|
||||
In case of error, `error' returns a non-empty error message.
|
||||
In case of error, 'error' returns a non-empty error message.
|
||||
|
||||
`options' is an array of `struct Option' terminated by an element
|
||||
'options' is an array of 'struct 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.
|
||||
|
@ -39,13 +40,13 @@
|
|||
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 `Arg_parser' with `in_order' = true.
|
||||
the user typed them, call 'Arg_parser' with 'in_order' = true.
|
||||
|
||||
The argument `--' terminates all options; any following arguments are
|
||||
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>'.
|
||||
*/
|
||||
|
||||
class Arg_parser
|
||||
|
@ -65,7 +66,7 @@ private:
|
|||
{
|
||||
int code;
|
||||
std::string argument;
|
||||
Record( const int c = 0 ) : code( c ) {}
|
||||
explicit Record( const int c = 0 ) : code( c ) {}
|
||||
};
|
||||
|
||||
std::string error_;
|
||||
|
@ -84,20 +85,20 @@ public:
|
|||
Arg_parser( const char * const opt, const char * const arg,
|
||||
const Option options[] );
|
||||
|
||||
const std::string & error() const throw() { return error_; }
|
||||
const std::string & error() const { return error_; }
|
||||
|
||||
// The number of arguments parsed (may be different from argc)
|
||||
int arguments() const throw() { return data.size(); }
|
||||
int arguments() const { return data.size(); }
|
||||
|
||||
// If code( i ) is 0, argument( i ) is a non-option.
|
||||
// Else argument( i ) is the option's argument (or empty).
|
||||
int code( const int i ) const throw()
|
||||
int code( const int i ) const
|
||||
{
|
||||
if( i >= 0 && i < arguments() ) return data[i].code;
|
||||
else return 0;
|
||||
}
|
||||
|
||||
const std::string & argument( const int i ) const throw()
|
||||
const std::string & argument( const int i ) const
|
||||
{
|
||||
if( i >= 0 && i < arguments() ) return data[i].argument;
|
||||
else return error_;
|
||||
|
|
54
configure
vendored
54
configure
vendored
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# configure script for Lziprecover - Data recovery tool for lzipped files
|
||||
# Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
#
|
||||
# This configure script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
@ -8,7 +8,7 @@
|
|||
args=
|
||||
no_create=
|
||||
pkgname=lziprecover
|
||||
pkgversion=1.13-rc2
|
||||
pkgversion=1.13
|
||||
progname=lziprecover
|
||||
srctrigger=lzip.h
|
||||
|
||||
|
@ -19,10 +19,9 @@ srcdir=
|
|||
prefix=/usr/local
|
||||
exec_prefix='$(prefix)'
|
||||
bindir='$(exec_prefix)/bin'
|
||||
datadir='$(prefix)/share'
|
||||
infodir='$(datadir)/info'
|
||||
mandir='$(datadir)/man'
|
||||
sysconfdir='$(prefix)/etc'
|
||||
datarootdir='$(prefix)/share'
|
||||
infodir='$(datarootdir)/info'
|
||||
mandir='$(datarootdir)/man'
|
||||
CXX=
|
||||
CPPFLAGS=
|
||||
CXXFLAGS='-Wall -W -O2'
|
||||
|
@ -40,12 +39,12 @@ while [ -n "$1" ] ; do
|
|||
|
||||
# Split out the argument for options that take them
|
||||
case ${option} in
|
||||
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,'` ;;
|
||||
*=*) optarg=`echo ${option} | sed -e 's,^[^=]*=,,;s,/$,,'` ;;
|
||||
esac
|
||||
|
||||
# Process the options
|
||||
case ${option} in
|
||||
--help | --he* | -h)
|
||||
--help | -h)
|
||||
echo "Usage: configure [options]"
|
||||
echo
|
||||
echo "Options: [defaults in brackets]"
|
||||
|
@ -55,37 +54,26 @@ while [ -n "$1" ] ; do
|
|||
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 " --datadir=DIR base directory for doc and data [${datadir}]"
|
||||
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 " --sysconfdir=DIR read-only single-machine data directory [${sysconfdir}]"
|
||||
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
|
||||
exit 0 ;;
|
||||
--version | --ve* | -V)
|
||||
--version | -V)
|
||||
echo "Configure script for ${pkgname} version ${pkgversion}"
|
||||
exit 0 ;;
|
||||
--srcdir* | --sr*)
|
||||
srcdir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--prefix* | --pr*)
|
||||
prefix=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--exec-prefix* | --ex*)
|
||||
exec_prefix=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--bindir* | --bi*)
|
||||
bindir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--datadir* | --da*)
|
||||
datadir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--infodir* | --inf*)
|
||||
infodir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--mandir* | --ma*)
|
||||
mandir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--sysconfdir* | --sy*)
|
||||
sysconfdir=`echo ${optarg} | sed -e 's,/$,,'` ;;
|
||||
--no-create | --no-c*)
|
||||
no_create=yes ;;
|
||||
--srcdir=*) srcdir=${optarg} ;;
|
||||
--prefix=*) prefix=${optarg} ;;
|
||||
--exec-prefix=*) exec_prefix=${optarg} ;;
|
||||
--bindir=*) bindir=${optarg} ;;
|
||||
--datarootdir=*) datarootdir=${optarg} ;;
|
||||
--infodir=*) infodir=${optarg} ;;
|
||||
--mandir=*) mandir=${optarg} ;;
|
||||
--no-create) no_create=yes ;;
|
||||
|
||||
CXX=*) CXX=${optarg} ;;
|
||||
CPPFLAGS=*) CPPFLAGS=${optarg} ;;
|
||||
|
@ -154,10 +142,9 @@ echo "VPATH = ${srcdir}"
|
|||
echo "prefix = ${prefix}"
|
||||
echo "exec_prefix = ${exec_prefix}"
|
||||
echo "bindir = ${bindir}"
|
||||
echo "datadir = ${datadir}"
|
||||
echo "datarootdir = ${datarootdir}"
|
||||
echo "infodir = ${infodir}"
|
||||
echo "mandir = ${mandir}"
|
||||
echo "sysconfdir = ${sysconfdir}"
|
||||
echo "CXX = ${CXX}"
|
||||
echo "CPPFLAGS = ${CPPFLAGS}"
|
||||
echo "CXXFLAGS = ${CXXFLAGS}"
|
||||
|
@ -165,7 +152,7 @@ echo "LDFLAGS = ${LDFLAGS}"
|
|||
rm -f Makefile
|
||||
cat > Makefile << EOF
|
||||
# Makefile for Lziprecover - Data recovery tool for lzipped files
|
||||
# Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
# This file was generated automatically by configure. Do not edit.
|
||||
#
|
||||
# This Makefile is free software: you have unlimited permission
|
||||
|
@ -178,10 +165,9 @@ VPATH = ${srcdir}
|
|||
prefix = ${prefix}
|
||||
exec_prefix = ${exec_prefix}
|
||||
bindir = ${bindir}
|
||||
datadir = ${datadir}
|
||||
datarootdir = ${datarootdir}
|
||||
infodir = ${infodir}
|
||||
mandir = ${mandir}
|
||||
sysconfdir = ${sysconfdir}
|
||||
CXX = ${CXX}
|
||||
CPPFLAGS = ${CPPFLAGS}
|
||||
CXXFLAGS = ${CXXFLAGS}
|
||||
|
|
24
decoder.cc
24
decoder.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -34,7 +34,7 @@
|
|||
const CRC32 crc32;
|
||||
|
||||
|
||||
void Pretty_print::operator()( const char * const msg ) const throw()
|
||||
void Pretty_print::operator()( const char * const msg ) const
|
||||
{
|
||||
if( verbosity_ >= 0 )
|
||||
{
|
||||
|
@ -54,7 +54,7 @@ void Pretty_print::operator()( const char * const msg ) const throw()
|
|||
// Returns the number of bytes really read.
|
||||
// If (returned value < size) and (errno == 0), means EOF was reached.
|
||||
//
|
||||
int readblock( const int fd, uint8_t * const buf, const int size ) throw()
|
||||
int readblock( const int fd, uint8_t * const buf, const int size )
|
||||
{
|
||||
int rest = size;
|
||||
errno = 0;
|
||||
|
@ -73,7 +73,7 @@ int readblock( const int fd, uint8_t * const buf, const int size ) throw()
|
|||
// Returns the number of bytes really written.
|
||||
// If (returned value < size), it is always an error.
|
||||
//
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size ) throw()
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size )
|
||||
{
|
||||
int rest = size;
|
||||
errno = 0;
|
||||
|
@ -82,7 +82,7 @@ int writeblock( const int fd, const uint8_t * const buf, const int size ) throw(
|
|||
errno = 0;
|
||||
const int n = write( fd, buf + size - rest, rest );
|
||||
if( n > 0 ) rest -= n;
|
||||
else if( errno && errno != EINTR && errno != EAGAIN ) break;
|
||||
else if( n < 0 && errno != EINTR && errno != EAGAIN ) break;
|
||||
}
|
||||
return ( rest > 0 ) ? size - rest : size;
|
||||
}
|
||||
|
@ -129,21 +129,17 @@ bool LZ_decoder::verify_trailer( const Pretty_print & pp ) const
|
|||
const long long member_size = range_decoder.member_position() + trailer_size;
|
||||
bool error = false;
|
||||
|
||||
for( int i = 0; i < trailer_size && !error; ++i )
|
||||
{
|
||||
if( !range_decoder.finished() )
|
||||
trailer.data[i] = range_decoder.get_byte();
|
||||
else
|
||||
const int size = range_decoder.read( trailer.data, trailer_size );
|
||||
if( size < trailer_size )
|
||||
{
|
||||
error = true;
|
||||
if( pp.verbosity() >= 0 )
|
||||
{
|
||||
pp();
|
||||
std::fprintf( stderr, "Trailer truncated at trailer position %d;"
|
||||
" some checks may fail.\n", i );
|
||||
}
|
||||
for( ; i < trailer_size; ++i ) trailer.data[i] = 0;
|
||||
" some checks may fail.\n", size );
|
||||
}
|
||||
for( int i = size; i < trailer_size; ++i ) trailer.data[i] = 0;
|
||||
}
|
||||
if( member_version == 0 ) trailer.member_size( member_size );
|
||||
if( !range_decoder.code_is_zero() )
|
||||
|
@ -297,7 +293,7 @@ int LZ_decoder::decode_member( const Pretty_print & pp )
|
|||
if( pp.verbosity() >= 0 )
|
||||
{
|
||||
pp();
|
||||
std::fprintf( stderr, "Unsupported marker code `%d'.\n", len );
|
||||
std::fprintf( stderr, "Unsupported marker code '%d'.\n", len );
|
||||
}
|
||||
return 4;
|
||||
}
|
||||
|
|
45
decoder.h
45
decoder.h
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -29,8 +29,11 @@ class Range_decoder
|
|||
|
||||
bool read_block();
|
||||
|
||||
Range_decoder( const Range_decoder & ); // declared as private
|
||||
void operator=( const Range_decoder & ); // declared as private
|
||||
|
||||
public:
|
||||
Range_decoder( const int ifd )
|
||||
explicit Range_decoder( const int ifd )
|
||||
:
|
||||
partial_member_pos( 0 ),
|
||||
buffer( new uint8_t[buffer_size] ),
|
||||
|
@ -43,12 +46,10 @@ public:
|
|||
|
||||
~Range_decoder() { delete[] buffer; }
|
||||
|
||||
bool code_is_zero() const throw() { return ( code == 0 ); }
|
||||
bool code_is_zero() const { return ( code == 0 ); }
|
||||
bool finished() { return pos >= stream_pos && !read_block(); }
|
||||
long long member_position() const throw()
|
||||
{ return partial_member_pos + pos; }
|
||||
void reset_member_position() throw()
|
||||
{ partial_member_pos = -pos; }
|
||||
long long member_position() const { return partial_member_pos + pos; }
|
||||
void reset_member_position() { partial_member_pos = -pos; }
|
||||
|
||||
uint8_t get_byte()
|
||||
{
|
||||
|
@ -56,6 +57,19 @@ public:
|
|||
return buffer[pos++];
|
||||
}
|
||||
|
||||
int read( uint8_t * const outbuf, const int size )
|
||||
{
|
||||
int rest = size;
|
||||
while( rest > 0 && !finished() )
|
||||
{
|
||||
const int rd = std::min( rest, stream_pos - pos );
|
||||
std::memcpy( outbuf + size - rest, buffer + pos, rd );
|
||||
pos += rd;
|
||||
rest -= rd;
|
||||
}
|
||||
return ( rest > 0 ) ? size - rest : size;
|
||||
}
|
||||
|
||||
void load()
|
||||
{
|
||||
code = 0;
|
||||
|
@ -176,7 +190,7 @@ class Literal_decoder
|
|||
{
|
||||
Bit_model bm_literal[1<<literal_context_bits][0x300];
|
||||
|
||||
int lstate( const int prev_byte ) const throw()
|
||||
int lstate( const uint8_t prev_byte ) const
|
||||
{ return ( prev_byte >> ( 8 - literal_context_bits ) ); }
|
||||
|
||||
public:
|
||||
|
@ -205,18 +219,17 @@ class LZ_decoder
|
|||
const int member_version;
|
||||
Range_decoder & range_decoder;
|
||||
|
||||
long long stream_position() const throw()
|
||||
{ return partial_data_pos + stream_pos; }
|
||||
long long stream_position() const { return partial_data_pos + stream_pos; }
|
||||
void flush_data();
|
||||
bool verify_trailer( const Pretty_print & pp ) const;
|
||||
|
||||
uint8_t get_prev_byte() const throw()
|
||||
uint8_t get_prev_byte() const
|
||||
{
|
||||
const int i = ( ( pos > 0 ) ? pos : buffer_size ) - 1;
|
||||
return buffer[i];
|
||||
}
|
||||
|
||||
uint8_t get_byte( const int distance ) const throw()
|
||||
uint8_t get_byte( const int distance ) const
|
||||
{
|
||||
int i = pos - distance - 1;
|
||||
if( i < 0 ) i += buffer_size;
|
||||
|
@ -246,6 +259,9 @@ class LZ_decoder
|
|||
}
|
||||
}
|
||||
|
||||
LZ_decoder( const LZ_decoder & ); // declared as private
|
||||
void operator=( const LZ_decoder & ); // declared as private
|
||||
|
||||
public:
|
||||
LZ_decoder( const File_header & header, Range_decoder & rdec, const int ofd,
|
||||
const long long oskip = 0, const long long oend = LLONG_MAX )
|
||||
|
@ -266,10 +282,9 @@ public:
|
|||
|
||||
~LZ_decoder() { delete[] buffer; }
|
||||
|
||||
uint32_t crc() const throw() { return crc_ ^ 0xFFFFFFFFU; }
|
||||
uint32_t crc() const { return crc_ ^ 0xFFFFFFFFU; }
|
||||
|
||||
long long data_position() const throw()
|
||||
{ return partial_data_pos + pos; }
|
||||
long long data_position() const { return partial_data_pos + pos; }
|
||||
|
||||
int decode_member( const Pretty_print & pp );
|
||||
};
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
|
||||
.TH LZIPRECOVER "1" "November 2011" "Lziprecover 1.13-rc2" "User Commands"
|
||||
.TH LZIPRECOVER "1" "February 2012" "Lziprecover 1.13" "User Commands"
|
||||
.SH NAME
|
||||
Lziprecover \- recovers data from damaged lzip files
|
||||
.SH SYNOPSIS
|
||||
|
@ -46,7 +46,7 @@ suppress all messages
|
|||
try to repair a small error in file
|
||||
.TP
|
||||
\fB\-s\fR, \fB\-\-split\fR
|
||||
split multimember file in single\-member files
|
||||
split multi\-member file in single\-member files
|
||||
.TP
|
||||
\fB\-t\fR, \fB\-\-test\fR
|
||||
test compressed file integrity
|
||||
|
@ -61,7 +61,7 @@ Report bugs to lzip\-bug@nongnu.org
|
|||
.br
|
||||
Lziprecover home page: http://www.nongnu.org/lzip/lziprecover.html
|
||||
.SH COPYRIGHT
|
||||
Copyright \(co 2011 Antonio Diaz Diaz.
|
||||
Copyright \(co 2012 Antonio Diaz Diaz.
|
||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
||||
.br
|
||||
This is free software: you are free to change and redistribute it.
|
||||
|
|
|
@ -12,7 +12,7 @@ File: lziprecover.info, Node: Top, Next: Introduction, Up: (dir)
|
|||
Lziprecover Manual
|
||||
******************
|
||||
|
||||
This manual is for Lziprecover (version 1.13-rc2, 20 November 2011).
|
||||
This manual is for Lziprecover (version 1.13, 24 February 2012).
|
||||
|
||||
* Menu:
|
||||
|
||||
|
@ -24,7 +24,7 @@ This manual is for Lziprecover (version 1.13-rc2, 20 November 2011).
|
|||
* Concept Index:: Index of concepts
|
||||
|
||||
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
|
||||
This manual is free documentation: you have unlimited permission to
|
||||
copy, distribute and modify it.
|
||||
|
@ -46,6 +46,13 @@ the compressors in the lzip family; lzip, plzip, minilzip/lzlib, clzip
|
|||
and pdlzip. This recovery capability contributes to make the lzip format
|
||||
one of the best options for long-term data archiving.
|
||||
|
||||
Lziprecover is able to efficiently extract a range of bytes from a
|
||||
multi-member file, because it only decompresses the members containing
|
||||
the desired data.
|
||||
|
||||
Lziprecover can print correct total file sizes and ratios even for
|
||||
multi-member files.
|
||||
|
||||
When recovering data, lziprecover takes as arguments the names of the
|
||||
damaged files and writes zero or more recovered files depending on the
|
||||
operation selected and whether the recovery succeeded or not. The
|
||||
|
@ -111,7 +118,7 @@ The format for running lziprecover is:
|
|||
`--output' option is used. In order to guarantee the correctness
|
||||
of the data produced, all members containing any part of the
|
||||
desired data are decompressed and their integrity is verified.
|
||||
This operation is more efficient in multimember files because it
|
||||
This operation is more efficient in multi-member files because it
|
||||
only decompresses the members containing the desired data.
|
||||
|
||||
`-f'
|
||||
|
@ -125,7 +132,7 @@ The format for running lziprecover is:
|
|||
`-l'
|
||||
`--list'
|
||||
Print total file sizes and ratios. The values produced are correct
|
||||
even for multimember files.
|
||||
even for multi-member files.
|
||||
|
||||
`-m'
|
||||
`--merge'
|
||||
|
@ -266,7 +273,7 @@ additional information before, between, or after them.
|
|||
|
||||
`Member size (8 bytes)'
|
||||
Total size of the member, including header and trailer. This
|
||||
facilitates safe recovery of undamaged members from multimember
|
||||
facilitates safe recovery of undamaged members from multi-member
|
||||
files.
|
||||
|
||||
|
||||
|
@ -291,13 +298,13 @@ show status.
|
|||
Example 3: Decompress `file.lz' partially until 10KiB of decompressed
|
||||
data are produced.
|
||||
|
||||
lziprecover -cd file.lz | dd bs=1024 count=10
|
||||
lziprecover -D 10KiB file.lz
|
||||
|
||||
|
||||
Example 4: Decompress `file.lz' partially from decompressed byte 10000
|
||||
to decompressed byte 15000 (5000 bytes are produced).
|
||||
|
||||
lziprecover -cd file.lz | dd bs=1000 skip=10 count=5
|
||||
lziprecover -D 10000-15000 file.lz
|
||||
|
||||
|
||||
Example 5: Repair a one-byte corruption in the single-member file
|
||||
|
@ -317,8 +324,9 @@ the integrity of the resulting files.
|
|||
lziprecover -tv rec*file.lz
|
||||
|
||||
|
||||
Example 7: Recover a compressed backup from two copies on CD-ROM (see
|
||||
the GNU ddrescue manual for details about ddrescue)
|
||||
Example 7: Recover a compressed backup from two copies on CD-ROM with
|
||||
error-checked merging of copies (*Note GNU ddrescue manual:
|
||||
(ddrescue)Top, for details about ddrescue).
|
||||
|
||||
ddrescue -b2048 /dev/cdrom cdimage1 logfile1
|
||||
mount -t iso9660 -o loop,ro cdimage1 /mnt/cdimage
|
||||
|
@ -391,12 +399,17 @@ Concept Index
|
|||
|
||||
Tag Table:
|
||||
Node: Top231
|
||||
Node: Introduction898
|
||||
Node: Invoking Lziprecover2684
|
||||
Node: File Format7727
|
||||
Node: Examples9733
|
||||
Ref: ddrescue-example10986
|
||||
Node: Problems12765
|
||||
Node: Concept Index13315
|
||||
Node: Introduction900
|
||||
Node: Invoking Lziprecover2937
|
||||
Node: File Format7982
|
||||
Node: Examples9989
|
||||
Ref: ddrescue-example11207
|
||||
Node: Problems13038
|
||||
Node: Concept Index13588
|
||||
|
||||
End Tag Table
|
||||
|
||||
|
||||
Local Variables:
|
||||
coding: iso-8859-15
|
||||
End:
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename lziprecover.info
|
||||
@documentencoding ISO-8859-15
|
||||
@settitle Lziprecover Manual
|
||||
@finalout
|
||||
@c %**end of header
|
||||
|
||||
@set UPDATED 20 November 2011
|
||||
@set VERSION 1.13-rc2
|
||||
@set UPDATED 24 February 2012
|
||||
@set VERSION 1.13
|
||||
|
||||
@dircategory Data Compression
|
||||
@direntry
|
||||
|
@ -43,7 +44,7 @@ This manual is for Lziprecover (version @value{VERSION}, @value{UPDATED}).
|
|||
@end menu
|
||||
|
||||
@sp 1
|
||||
Copyright @copyright{} 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright @copyright{} 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
|
||||
This manual is free documentation: you have unlimited permission
|
||||
to copy, distribute and modify it.
|
||||
|
@ -64,6 +65,13 @@ the compressors in the lzip family; lzip, plzip, minilzip/lzlib, clzip
|
|||
and pdlzip. This recovery capability contributes to make the lzip format
|
||||
one of the best options for long-term data archiving.
|
||||
|
||||
Lziprecover is able to efficiently extract a range of bytes from a
|
||||
multi-member file, because it only decompresses the members containing
|
||||
the desired data.
|
||||
|
||||
Lziprecover can print correct total file sizes and ratios even for
|
||||
multi-member files.
|
||||
|
||||
When recovering data, lziprecover takes as arguments the names of the
|
||||
damaged files and writes zero or more recovered files depending on the
|
||||
operation selected and whether the recovery succeeded or not. The
|
||||
|
@ -133,7 +141,7 @@ produced bytes are sent to standard output unless the @samp{--output}
|
|||
option is used. In order to guarantee the correctness of the data
|
||||
produced, all members containing any part of the desired data are
|
||||
decompressed and their integrity is verified. This operation is more
|
||||
efficient in multimember files because it only decompresses the members
|
||||
efficient in multi-member files because it only decompresses the members
|
||||
containing the desired data.
|
||||
|
||||
@item -f
|
||||
|
@ -147,7 +155,7 @@ Keep (don't delete) input files during decompression.
|
|||
@item -l
|
||||
@itemx --list
|
||||
Print total file sizes and ratios. The values produced are correct even
|
||||
for multimember files.
|
||||
for multi-member files.
|
||||
|
||||
@item -m
|
||||
@itemx --merge
|
||||
|
@ -295,7 +303,7 @@ Size of the uncompressed original data.
|
|||
|
||||
@item Member size (8 bytes)
|
||||
Total size of the member, including header and trailer. This facilitates
|
||||
safe recovery of undamaged members from multimember files.
|
||||
safe recovery of undamaged members from multi-member files.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -327,7 +335,7 @@ Example 3: Decompress @samp{file.lz} partially until 10KiB of
|
|||
decompressed data are produced.
|
||||
|
||||
@example
|
||||
lziprecover -cd file.lz | dd bs=1024 count=10
|
||||
lziprecover -D 10KiB file.lz
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
|
@ -336,7 +344,7 @@ Example 4: Decompress @samp{file.lz} partially from decompressed byte
|
|||
10000 to decompressed byte 15000 (5000 bytes are produced).
|
||||
|
||||
@example
|
||||
lziprecover -cd file.lz | dd bs=1000 skip=10 count=5
|
||||
lziprecover -D 10000-15000 file.lz
|
||||
@end example
|
||||
|
||||
@sp 1
|
||||
|
@ -365,8 +373,16 @@ lziprecover -tv rec*file.lz
|
|||
@sp 1
|
||||
@anchor{ddrescue-example}
|
||||
@noindent
|
||||
Example 7: Recover a compressed backup from two copies on CD-ROM (see
|
||||
the GNU ddrescue manual for details about ddrescue)
|
||||
Example 7: Recover a compressed backup from two copies on CD-ROM with
|
||||
error-checked merging of copies
|
||||
@ifnothtml
|
||||
(@xref{Top,GNU ddrescue manual,,ddrescue},
|
||||
@end ifnothtml
|
||||
@ifhtml
|
||||
(See the
|
||||
@uref{http://www.gnu.org/software/ddrescue/manual/ddrescue_manual.html,,ddrescue manual}
|
||||
@end ifhtml
|
||||
for details about ddrescue).
|
||||
|
||||
@example
|
||||
ddrescue -b2048 /dev/cdrom cdimage1 logfile1
|
||||
|
|
102
lzip.h
102
lzip.h
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -21,32 +21,32 @@ class State
|
|||
|
||||
public:
|
||||
enum { states = 12 };
|
||||
State() throw() : st( 0 ) {}
|
||||
unsigned char operator()() const throw() { return st; }
|
||||
bool is_char() const throw() { return st < 7; }
|
||||
State() : st( 0 ) {}
|
||||
unsigned char operator()() const { return st; }
|
||||
bool is_char() const { return st < 7; }
|
||||
|
||||
void set_char() throw()
|
||||
void set_char()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_match() throw()
|
||||
void set_match()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_rep() throw()
|
||||
void set_rep()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11 };
|
||||
st = next[st];
|
||||
}
|
||||
|
||||
void set_short_rep() throw()
|
||||
void set_short_rep()
|
||||
{
|
||||
static const unsigned char next[states] =
|
||||
{ 9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11 };
|
||||
|
@ -87,7 +87,7 @@ enum {
|
|||
|
||||
max_dis_states = 4 };
|
||||
|
||||
inline int get_dis_state( int len ) throw()
|
||||
inline int get_dis_state( int len )
|
||||
{
|
||||
len -= min_match_len;
|
||||
if( len >= max_dis_states ) len = max_dis_states - 1;
|
||||
|
@ -102,7 +102,7 @@ enum { bit_model_move_bits = 5,
|
|||
struct Bit_model
|
||||
{
|
||||
unsigned int probability;
|
||||
Bit_model() throw() : probability( bit_model_total / 2 ) {}
|
||||
Bit_model() : probability( bit_model_total / 2 ) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -145,10 +145,10 @@ public:
|
|||
first_post = true;
|
||||
}
|
||||
|
||||
void reset() const throw() { if( name_.size() ) first_post = true; }
|
||||
const char * name() const throw() { return name_.c_str(); }
|
||||
int verbosity() const throw() { return verbosity_; }
|
||||
void operator()( const char * const msg = 0 ) const throw();
|
||||
void reset() const { if( name_.size() ) first_post = true; }
|
||||
const char * name() const { return name_.c_str(); }
|
||||
int verbosity() const { return verbosity_; }
|
||||
void operator()( const char * const msg = 0 ) const;
|
||||
};
|
||||
|
||||
|
||||
|
@ -168,10 +168,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t operator[]( const uint8_t byte ) const throw() { return data[byte]; }
|
||||
void update( uint32_t & crc, const uint8_t byte ) const throw()
|
||||
uint32_t operator[]( const uint8_t byte ) const { return data[byte]; }
|
||||
void update( uint32_t & crc, const uint8_t byte ) const
|
||||
{ crc = data[(crc^byte)&0xFF] ^ ( crc >> 8 ); }
|
||||
void update( uint32_t & crc, const uint8_t * const buffer, const int size ) const throw()
|
||||
void update( uint32_t & crc, const uint8_t * const buffer, const int size ) const
|
||||
{
|
||||
for( int i = 0; i < size; ++i )
|
||||
crc = data[(crc^buffer[i])&0xFF] ^ ( crc >> 8 );
|
||||
|
@ -181,14 +181,15 @@ public:
|
|||
extern const CRC32 crc32;
|
||||
|
||||
|
||||
inline int real_bits( const int value ) throw()
|
||||
inline int real_bits( const unsigned int value )
|
||||
{
|
||||
int bits = 0;
|
||||
for( int i = 1, mask = 1; mask > 0; ++i, mask <<= 1 )
|
||||
if( value & mask ) bits = i;
|
||||
int bits = 0, i = 1;
|
||||
unsigned int mask = 1;
|
||||
for( ; mask > 0; ++i, mask <<= 1 ) if( value & mask ) bits = i;
|
||||
return bits;
|
||||
}
|
||||
|
||||
|
||||
const uint8_t magic_string[4] = { 'L', 'Z', 'I', 'P' };
|
||||
|
||||
struct File_header
|
||||
|
@ -198,16 +199,14 @@ struct File_header
|
|||
// 5 coded_dict_size
|
||||
enum { size = 6 };
|
||||
|
||||
void set_magic() throw()
|
||||
{ std::memcpy( data, magic_string, 4 ); data[4] = 1; }
|
||||
|
||||
bool verify_magic() const throw()
|
||||
void set_magic() { std::memcpy( data, magic_string, 4 ); data[4] = 1; }
|
||||
bool verify_magic() const
|
||||
{ return ( std::memcmp( data, magic_string, 4 ) == 0 ); }
|
||||
|
||||
uint8_t version() const throw() { return data[4]; }
|
||||
bool verify_version() const throw() { return ( data[4] <= 1 ); }
|
||||
uint8_t version() const { return data[4]; }
|
||||
bool verify_version() const { return ( data[4] <= 1 ); }
|
||||
|
||||
int dictionary_size() const throw()
|
||||
int dictionary_size() const
|
||||
{
|
||||
int sz = ( 1 << ( data[5] & 0x1F ) );
|
||||
if( sz > min_dictionary_size && sz <= max_dictionary_size )
|
||||
|
@ -215,7 +214,7 @@ struct File_header
|
|||
return sz;
|
||||
}
|
||||
|
||||
bool dictionary_size( const int sz ) throw()
|
||||
bool dictionary_size( const int sz )
|
||||
{
|
||||
if( sz >= min_dictionary_size && sz <= max_dictionary_size )
|
||||
{
|
||||
|
@ -244,36 +243,36 @@ struct File_trailer
|
|||
static int size( const int version = 1 )
|
||||
{ return ( ( version >= 1 ) ? 20 : 12 ); }
|
||||
|
||||
uint32_t data_crc() const throw()
|
||||
uint32_t data_crc() const
|
||||
{
|
||||
uint32_t tmp = 0;
|
||||
for( int i = 3; i >= 0; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void data_crc( uint32_t crc ) throw()
|
||||
void data_crc( uint32_t crc )
|
||||
{ for( int i = 0; i <= 3; ++i ) { data[i] = (uint8_t)crc; crc >>= 8; } }
|
||||
|
||||
long long data_size() const throw()
|
||||
long long data_size() const
|
||||
{
|
||||
long long tmp = 0;
|
||||
for( int i = 11; i >= 4; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void data_size( long long sz ) throw()
|
||||
void data_size( long long sz )
|
||||
{
|
||||
for( int i = 4; i <= 11; ++i ) { data[i] = (uint8_t)sz; sz >>= 8; }
|
||||
}
|
||||
|
||||
long long member_size() const throw()
|
||||
long long member_size() const
|
||||
{
|
||||
long long tmp = 0;
|
||||
for( int i = 19; i >= 12; --i ) { tmp <<= 8; tmp += data[i]; }
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void member_size( long long sz ) throw()
|
||||
void member_size( long long sz )
|
||||
{
|
||||
for( int i = 12; i <= 19; ++i ) { data[i] = (uint8_t)sz; sz >>= 8; }
|
||||
}
|
||||
|
@ -283,7 +282,7 @@ struct File_trailer
|
|||
struct Error
|
||||
{
|
||||
const char * const msg;
|
||||
Error( const char * const s ) throw() : msg( s ) {}
|
||||
explicit Error( const char * const s ) : msg( s ) {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -303,41 +302,40 @@ class Block
|
|||
long long pos_, size_; // pos + size <= LLONG_MAX
|
||||
|
||||
public:
|
||||
Block( const long long p, const long long s ) throw()
|
||||
: pos_( p ), size_( s ) {}
|
||||
Block( const long long p, const long long s ) : pos_( p ), size_( s ) {}
|
||||
|
||||
long long pos() const throw() { return pos_; }
|
||||
long long size() const throw() { return size_; }
|
||||
long long end() const throw() { return pos_ + size_; }
|
||||
long long pos() const { return pos_; }
|
||||
long long size() const { return size_; }
|
||||
long long end() const { return pos_ + size_; }
|
||||
|
||||
void pos( const long long p ) throw() { pos_ = p; }
|
||||
void size( const long long s ) throw() { size_ = s; }
|
||||
void pos( const long long p ) { pos_ = p; }
|
||||
void size( const long long s ) { size_ = s; }
|
||||
|
||||
bool overlaps( const Block & b ) const throw()
|
||||
bool overlaps( const Block & b ) const
|
||||
{ return ( pos_ < b.end() && b.pos_ < end() ); }
|
||||
void shift( Block & b ) throw() { ++size_; ++b.pos_; --b.size_; }
|
||||
void shift( Block & b ) { ++size_; ++b.pos_; --b.size_; }
|
||||
};
|
||||
|
||||
|
||||
// defined in decoder.cc
|
||||
int readblock( const int fd, uint8_t * const buf, const int size ) throw();
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size ) throw();
|
||||
int readblock( const int fd, uint8_t * const buf, const int size );
|
||||
int writeblock( const int fd, const uint8_t * const buf, const int size );
|
||||
|
||||
// defined in main.cc
|
||||
extern int verbosity;
|
||||
const char * format_num( long long num, long long limit = LLONG_MAX,
|
||||
const int set_prefix = 0 ) throw();
|
||||
const int set_prefix = 0 );
|
||||
int open_instream( const std::string & name, struct stat * const in_statsp,
|
||||
const bool to_stdout, const bool reg_only = false ) throw();
|
||||
const bool to_stdout, const bool reg_only = false );
|
||||
int open_outstream_rw( const std::string & output_filename,
|
||||
const bool force ) throw();
|
||||
const bool force );
|
||||
void show_error( const char * const msg, const int errcode = 0,
|
||||
const bool help = false ) throw();
|
||||
const bool help = false );
|
||||
void internal_error( const char * const msg );
|
||||
|
||||
// defined in merge.cc
|
||||
void cleanup_and_fail( const std::string & output_filename,
|
||||
const int outfd, const int retval ) throw();
|
||||
const int outfd, const int retval );
|
||||
bool copy_file( const int infd, const int outfd,
|
||||
const long long size = LLONG_MAX );
|
||||
bool try_decompress( const int fd, const long long file_size,
|
||||
|
|
90
main.cc
90
main.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -38,6 +38,10 @@
|
|||
#include <utime.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(__MSVCRT__)
|
||||
#define fchmod(x,y) 0
|
||||
#define fchown(x,y,z) 0
|
||||
#define SIGHUP SIGTERM
|
||||
#define S_ISSOCK(x) 0
|
||||
#define S_IRGRP 0
|
||||
#define S_IWGRP 0
|
||||
#define S_IROTH 0
|
||||
|
@ -57,7 +61,7 @@ namespace {
|
|||
|
||||
const char * const Program_name = "Lziprecover";
|
||||
const char * const program_name = "lziprecover";
|
||||
const char * const program_year = "2011";
|
||||
const char * const program_year = "2012";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
#ifdef O_BINARY
|
||||
|
@ -82,7 +86,7 @@ mode_t outfd_mode = usr_rw;
|
|||
bool delete_output_on_interrupt = false;
|
||||
|
||||
|
||||
void show_help() throw()
|
||||
void show_help()
|
||||
{
|
||||
std::printf( "%s - Data recovery tool and decompressor for lzipped files.\n", Program_name );
|
||||
std::printf( "\nUsage: %s [options] [files]\n", invocation_name );
|
||||
|
@ -101,7 +105,7 @@ void show_help() throw()
|
|||
" -q, --quiet suppress all messages\n"
|
||||
// " -r, --recover correct errors in file using a recover file\n"
|
||||
" -R, --repair try to repair a small error in file\n"
|
||||
" -s, --split split multimember file in single-member files\n"
|
||||
" -s, --split split multi-member file in single-member files\n"
|
||||
" -t, --test test compressed file integrity\n"
|
||||
// " -u, --update convert file from version 0 to version 1\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
|
@ -112,7 +116,7 @@ void show_help() throw()
|
|||
}
|
||||
|
||||
|
||||
void show_version() throw()
|
||||
void show_version()
|
||||
{
|
||||
std::printf( "%s %s\n", Program_name, PROGVERSION );
|
||||
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
|
||||
|
@ -122,7 +126,7 @@ void show_version() throw()
|
|||
}
|
||||
|
||||
|
||||
void one_file( const int argind, const int arguments ) throw()
|
||||
void one_file( const int argind, const int arguments )
|
||||
{
|
||||
if( argind + 1 != arguments )
|
||||
{
|
||||
|
@ -132,7 +136,7 @@ void one_file( const int argind, const int arguments ) throw()
|
|||
}
|
||||
|
||||
|
||||
void set_mode( Mode & program_mode, const Mode new_mode ) throw()
|
||||
void set_mode( Mode & program_mode, const Mode new_mode )
|
||||
{
|
||||
if( program_mode != m_none && program_mode != new_mode )
|
||||
{
|
||||
|
@ -143,7 +147,7 @@ void set_mode( Mode & program_mode, const Mode new_mode ) throw()
|
|||
}
|
||||
|
||||
|
||||
int extension_index( const std::string & name ) throw()
|
||||
int extension_index( const std::string & name )
|
||||
{
|
||||
for( int i = 0; known_extensions[i].from; ++i )
|
||||
{
|
||||
|
@ -156,7 +160,7 @@ int extension_index( const std::string & name ) throw()
|
|||
}
|
||||
|
||||
|
||||
void set_d_outname( const std::string & name, const int i ) throw()
|
||||
void set_d_outname( const std::string & name, const int i )
|
||||
{
|
||||
if( i >= 0 )
|
||||
{
|
||||
|
@ -170,12 +174,12 @@ void set_d_outname( const std::string & name, const int i ) throw()
|
|||
}
|
||||
output_filename = name; output_filename += ".out";
|
||||
if( verbosity >= 1 )
|
||||
std::fprintf( stderr, "%s: Can't guess original name for `%s' -- using `%s'.\n",
|
||||
std::fprintf( stderr, "%s: Can't guess original name for '%s' -- using '%s'.\n",
|
||||
program_name, name.c_str(), output_filename.c_str() );
|
||||
}
|
||||
|
||||
|
||||
bool open_outstream( const bool force ) throw()
|
||||
bool open_outstream( const bool force )
|
||||
{
|
||||
int flags = O_CREAT | O_WRONLY | o_binary;
|
||||
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
||||
|
@ -184,17 +188,17 @@ bool open_outstream( const bool force ) throw()
|
|||
if( outfd < 0 && verbosity >= 0 )
|
||||
{
|
||||
if( errno == EEXIST )
|
||||
std::fprintf( stderr, "%s: Output file `%s' already exists, skipping.\n",
|
||||
std::fprintf( stderr, "%s: Output file '%s' already exists, skipping.\n",
|
||||
program_name, output_filename.c_str() );
|
||||
else
|
||||
std::fprintf( stderr, "%s: Can't create output file `%s': %s.\n",
|
||||
std::fprintf( stderr, "%s: Can't create output file '%s': %s.\n",
|
||||
program_name, output_filename.c_str(), std::strerror( errno ) );
|
||||
}
|
||||
return ( outfd >= 0 );
|
||||
}
|
||||
|
||||
|
||||
bool check_tty( const int infd ) throw()
|
||||
bool check_tty( const int infd )
|
||||
{
|
||||
if( isatty( infd ) )
|
||||
{
|
||||
|
@ -205,13 +209,13 @@ bool check_tty( const int infd ) throw()
|
|||
}
|
||||
|
||||
|
||||
void cleanup_and_fail( const int retval ) throw()
|
||||
void cleanup_and_fail( const int retval )
|
||||
{
|
||||
if( delete_output_on_interrupt )
|
||||
{
|
||||
delete_output_on_interrupt = false;
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: Deleting output file `%s', if it exists.\n",
|
||||
std::fprintf( stderr, "%s: Deleting output file '%s', if it exists.\n",
|
||||
program_name, output_filename.c_str() );
|
||||
if( outfd >= 0 ) { close( outfd ); outfd = -1; }
|
||||
if( std::remove( output_filename.c_str() ) != 0 && errno != ENOENT )
|
||||
|
@ -247,7 +251,7 @@ void close_and_set_permissions( const struct stat * const in_statsp )
|
|||
}
|
||||
|
||||
|
||||
std::string insert_fixed( std::string name ) throw()
|
||||
std::string insert_fixed( std::string name )
|
||||
{
|
||||
if( name.size() > 4 && name.compare( name.size() - 4, 4, ".tlz" ) == 0 )
|
||||
name.insert( name.size() - 4, "_fixed" );
|
||||
|
@ -258,7 +262,7 @@ std::string insert_fixed( std::string name ) throw()
|
|||
}
|
||||
|
||||
|
||||
unsigned char xdigit( const int value ) throw()
|
||||
unsigned char xdigit( const int value )
|
||||
{
|
||||
if( value >= 0 && value <= 9 ) return '0' + value;
|
||||
if( value >= 10 && value <= 15 ) return 'A' + value - 10;
|
||||
|
@ -267,7 +271,7 @@ unsigned char xdigit( const int value ) throw()
|
|||
|
||||
|
||||
void show_trailing_garbage( const uint8_t * const data, const int size,
|
||||
const Pretty_print & pp, const bool all ) throw()
|
||||
const Pretty_print & pp, const bool all )
|
||||
{
|
||||
std::string garbage_msg;
|
||||
if( !all ) garbage_msg = "first bytes of ";
|
||||
|
@ -277,7 +281,7 @@ void show_trailing_garbage( const uint8_t * const data, const int size,
|
|||
if( !std::isprint( data[i] ) ) { text = false; break; }
|
||||
if( text )
|
||||
{
|
||||
garbage_msg += '`';
|
||||
garbage_msg += '\'';
|
||||
garbage_msg.append( (const char *)data, size );
|
||||
garbage_msg += '\'';
|
||||
}
|
||||
|
@ -304,10 +308,8 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing )
|
|||
for( bool first_member = true; ; first_member = false, pp.reset() )
|
||||
{
|
||||
File_header header;
|
||||
int size;
|
||||
rdec.reset_member_position();
|
||||
for( size = 0; size < File_header::size && !rdec.finished(); ++size )
|
||||
header.data[size] = rdec.get_byte();
|
||||
const int size = rdec.read( header.data, File_header::size );
|
||||
if( rdec.finished() ) // End Of File
|
||||
{
|
||||
if( first_member )
|
||||
|
@ -344,8 +346,8 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing )
|
|||
header.version(),
|
||||
format_num( header.dictionary_size(), 9999, -1 ) );
|
||||
}
|
||||
LZ_decoder decoder( header, rdec, outfd );
|
||||
|
||||
LZ_decoder decoder( header, rdec, outfd );
|
||||
const int result = decoder.decode_member( pp );
|
||||
partial_file_pos += rdec.member_position();
|
||||
if( result != 0 )
|
||||
|
@ -380,14 +382,14 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing )
|
|||
}
|
||||
|
||||
|
||||
extern "C" void signal_handler( int ) throw()
|
||||
extern "C" void signal_handler( int )
|
||||
{
|
||||
show_error( "Control-C or similar caught, quitting." );
|
||||
cleanup_and_fail( 1 );
|
||||
}
|
||||
|
||||
|
||||
void set_signals() throw()
|
||||
void set_signals()
|
||||
{
|
||||
std::signal( SIGHUP, signal_handler );
|
||||
std::signal( SIGINT, signal_handler );
|
||||
|
@ -401,7 +403,7 @@ int verbosity = 0;
|
|||
|
||||
|
||||
const char * format_num( long long num, long long limit,
|
||||
const int set_prefix ) throw()
|
||||
const int set_prefix )
|
||||
{
|
||||
const char * const si_prefix[8] =
|
||||
{ "k", "M", "G", "T", "P", "E", "Z", "Y" };
|
||||
|
@ -425,13 +427,13 @@ const char * format_num( long long num, long long limit,
|
|||
|
||||
|
||||
int open_instream( const std::string & name, struct stat * const in_statsp,
|
||||
const bool to_stdout, const bool reg_only ) throw()
|
||||
const bool to_stdout, const bool reg_only )
|
||||
{
|
||||
int infd = open( name.c_str(), O_RDONLY | o_binary );
|
||||
if( infd < 0 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: Can't open input file `%s': %s.\n",
|
||||
std::fprintf( stderr, "%s: Can't open input file '%s': %s.\n",
|
||||
program_name, name.c_str(), std::strerror( errno ) );
|
||||
}
|
||||
else
|
||||
|
@ -444,10 +446,10 @@ int open_instream( const std::string & name, struct stat * const in_statsp,
|
|||
if( i != 0 || ( !S_ISREG( mode ) && ( !to_stdout || !can_read ) ) )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: Input file `%s' is not a regular file%s.\n",
|
||||
std::fprintf( stderr, "%s: Input file '%s' is not a regular file%s.\n",
|
||||
program_name, name.c_str(),
|
||||
( can_read && !to_stdout ) ?
|
||||
" and `--stdout' was not specified" : "" );
|
||||
" and '--stdout' was not specified" : "" );
|
||||
close( infd );
|
||||
infd = -1;
|
||||
}
|
||||
|
@ -457,7 +459,7 @@ int open_instream( const std::string & name, struct stat * const in_statsp,
|
|||
|
||||
|
||||
int open_outstream_rw( const std::string & output_filename,
|
||||
const bool force ) throw()
|
||||
const bool force )
|
||||
{
|
||||
int flags = O_CREAT | O_RDWR | o_binary;
|
||||
if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
|
||||
|
@ -466,18 +468,18 @@ int open_outstream_rw( const std::string & output_filename,
|
|||
if( outfd < 0 && verbosity >= 0 )
|
||||
{
|
||||
if( errno == EEXIST )
|
||||
std::fprintf( stderr, "%s: Output file `%s' already exists."
|
||||
" Use `--force' to overwrite it.\n",
|
||||
std::fprintf( stderr, "%s: Output file '%s' already exists."
|
||||
" Use '--force' to overwrite it.\n",
|
||||
program_name, output_filename.c_str() );
|
||||
else
|
||||
std::fprintf( stderr, "%s: Can't create output file `%s': %s.\n",
|
||||
std::fprintf( stderr, "%s: Can't create output file '%s': %s.\n",
|
||||
program_name, output_filename.c_str(), std::strerror( errno ) );
|
||||
}
|
||||
return outfd;
|
||||
}
|
||||
|
||||
|
||||
void show_error( const char * const msg, const int errcode, const bool help ) throw()
|
||||
void show_error( const char * const msg, const int errcode, const bool help )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{
|
||||
|
@ -489,7 +491,7 @@ void show_error( const char * const msg, const int errcode, const bool help ) th
|
|||
std::fprintf( stderr, "\n" );
|
||||
}
|
||||
if( help && invocation_name && invocation_name[0] )
|
||||
std::fprintf( stderr, "Try `%s --help' for more information.\n",
|
||||
std::fprintf( stderr, "Try '%s --help' for more information.\n",
|
||||
invocation_name );
|
||||
}
|
||||
}
|
||||
|
@ -567,6 +569,11 @@ int main( const int argc, const char * const argv[] )
|
|||
}
|
||||
} // end process options
|
||||
|
||||
#if defined(__MSVCRT__) || defined(__OS2__)
|
||||
_fsetmode( stdin, "b" );
|
||||
_fsetmode( stdout, "b" );
|
||||
#endif
|
||||
|
||||
if( program_mode == m_none )
|
||||
{
|
||||
show_error( "You must specify the operation to be performed.", 0, true );
|
||||
|
@ -607,6 +614,11 @@ int main( const int argc, const char * const argv[] )
|
|||
case m_test: break;
|
||||
}
|
||||
|
||||
if( program_mode == m_test )
|
||||
outfd = -1;
|
||||
else if( program_mode != m_decompress )
|
||||
internal_error( "invalid decompressor operation" );
|
||||
|
||||
bool filenames_given = false;
|
||||
for( ; argind < parser.arguments(); ++argind )
|
||||
{
|
||||
|
@ -620,10 +632,6 @@ int main( const int argc, const char * const argv[] )
|
|||
set_signals();
|
||||
|
||||
Pretty_print pp( filenames, verbosity );
|
||||
if( program_mode == m_test )
|
||||
outfd = -1;
|
||||
else if( program_mode != m_decompress )
|
||||
internal_error( "invalid decompressor operation" );
|
||||
|
||||
int retval = 0;
|
||||
for( unsigned int i = 0; i < filenames.size(); ++i )
|
||||
|
|
13
merge.cc
13
merge.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -102,7 +102,7 @@ bool copy_and_diff_file( const std::vector< int > & infd_vector,
|
|||
}
|
||||
|
||||
|
||||
int ipow( const unsigned int base, const unsigned int exponent ) throw()
|
||||
int ipow( const unsigned int base, const unsigned int exponent )
|
||||
{
|
||||
int result = 1;
|
||||
for( unsigned int i = 0; i < exponent; ++i )
|
||||
|
@ -142,13 +142,14 @@ int open_input_files( const std::vector< std::string > & filenames,
|
|||
if( tmp < 0 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "File `%s' is not seekable.\n", filenames[i].c_str() );
|
||||
std::fprintf( stderr, "File '%s' is not seekable.\n", filenames[i].c_str() );
|
||||
return 1;
|
||||
}
|
||||
if( i == 0 )
|
||||
{
|
||||
isize = tmp;
|
||||
if( isize < min_member_size ) { show_error( "Input file is too short." ); return 2; }
|
||||
if( isize < min_member_size )
|
||||
{ show_error( "Input file is too short." ); return 2; }
|
||||
}
|
||||
else if( isize != tmp )
|
||||
{ show_error( "Sizes of input files are different." ); return 1; }
|
||||
|
@ -165,7 +166,7 @@ int open_input_files( const std::vector< std::string > & filenames,
|
|||
if( try_decompress( infd_vector[i], isize ) )
|
||||
{
|
||||
if( verbosity >= 1 )
|
||||
std::printf( "File `%s' has no errors. Recovery is not needed.\n",
|
||||
std::printf( "File '%s' has no errors. Recovery is not needed.\n",
|
||||
filenames[i].c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
@ -179,7 +180,7 @@ int open_input_files( const std::vector< std::string > & filenames,
|
|||
|
||||
|
||||
void cleanup_and_fail( const std::string & output_filename,
|
||||
const int outfd, const int retval ) throw()
|
||||
const int outfd, const int retval )
|
||||
{
|
||||
if( outfd >= 0 ) close( outfd );
|
||||
if( std::remove( output_filename.c_str() ) != 0 && errno != ENOENT )
|
||||
|
|
36
range_dec.cc
36
range_dec.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -44,15 +44,15 @@ public:
|
|||
const long long mp, const long long ms )
|
||||
: dblock_( dp, ds ), mblock_( mp, ms ) {}
|
||||
|
||||
const Block & dblock() const throw() { return dblock_; }
|
||||
Block & dblock() throw() { return dblock_; }
|
||||
const Block & mblock() const throw() { return mblock_; }
|
||||
Block & mblock() throw() { return mblock_; }
|
||||
const Block & dblock() const { return dblock_; }
|
||||
Block & dblock() { return dblock_; }
|
||||
const Block & mblock() const { return mblock_; }
|
||||
Block & mblock() { return mblock_; }
|
||||
};
|
||||
|
||||
|
||||
int seek_read( const int fd, uint8_t * const buf, const int size,
|
||||
const long long pos ) throw()
|
||||
const long long pos )
|
||||
{
|
||||
if( lseek( fd, pos, SEEK_SET ) == pos )
|
||||
return readblock( fd, buf, size );
|
||||
|
@ -95,30 +95,28 @@ public:
|
|||
member_vector[i+1].dblock().pos( member_vector[i].dblock().end() );
|
||||
}
|
||||
|
||||
long long data_end() const throw()
|
||||
long long data_end() const
|
||||
{ if( member_vector.size() ) return member_vector.back().dblock().end();
|
||||
else return 0; }
|
||||
|
||||
const Member & member( const int i ) const throw()
|
||||
{ return member_vector[i]; }
|
||||
const Block & dblock( const int i ) const throw()
|
||||
const Member & member( const int i ) const { return member_vector[i]; }
|
||||
const Block & dblock( const int i ) const
|
||||
{ return member_vector[i].dblock(); }
|
||||
const Block & mblock( const int i ) const throw()
|
||||
const Block & mblock( const int i ) const
|
||||
{ return member_vector[i].mblock(); }
|
||||
int members() const throw() { return (int)member_vector.size(); }
|
||||
int members() const { return (int)member_vector.size(); }
|
||||
};
|
||||
|
||||
|
||||
// Returns the number of chars read, or 0 if error.
|
||||
//
|
||||
int parse_long_long( const char * const ptr, long long & value ) throw()
|
||||
int parse_long_long( const char * const ptr, long long & value )
|
||||
{
|
||||
char * tail;
|
||||
int c = 0;
|
||||
errno = 0;
|
||||
value = strtoll( ptr, &tail, 0 );
|
||||
if( tail == ptr || errno ) return 0;
|
||||
c = tail - ptr;
|
||||
int c = tail - ptr;
|
||||
|
||||
if( ptr[c] )
|
||||
{
|
||||
|
@ -133,8 +131,8 @@ int parse_long_long( const char * const ptr, long long & value ) throw()
|
|||
case 'T': exponent = 4; break;
|
||||
case 'G': exponent = 3; break;
|
||||
case 'M': exponent = 2; break;
|
||||
case 'K': if( factor == 1024 ) exponent = 1; break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; break;
|
||||
case 'K': if( factor == 1024 ) exponent = 1; else return 0; break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; else return 0; break;
|
||||
}
|
||||
if( exponent > 0 )
|
||||
{
|
||||
|
@ -154,7 +152,7 @@ int parse_long_long( const char * const ptr, long long & value ) throw()
|
|||
|
||||
// Recognized formats: <begin> <begin>-<end> <begin>,<size>
|
||||
//
|
||||
void parse_range( const char * const ptr, Block & range ) throw()
|
||||
void parse_range( const char * const ptr, Block & range )
|
||||
{
|
||||
long long value = 0;
|
||||
int c = parse_long_long( ptr, value ); // pos
|
||||
|
@ -176,7 +174,7 @@ void parse_range( const char * const ptr, Block & range ) throw()
|
|||
}
|
||||
|
||||
|
||||
bool safe_seek( const int fd, const long long pos ) throw()
|
||||
bool safe_seek( const int fd, const long long pos )
|
||||
{
|
||||
if( lseek( fd, pos, SEEK_SET ) == pos ) return true;
|
||||
show_error( "Seek error", errno ); return false;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
|
4
split.cc
4
split.cc
|
@ -1,5 +1,5 @@
|
|||
/* Lziprecover - Data recovery tool for lzipped files
|
||||
Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
Copyright (C) 2009, 2010, 2011, 2012 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
|
||||
|
@ -62,7 +62,7 @@ bool next_filename( std::string & output_filename )
|
|||
// Search forward from 'pos' for "LZIP" (Boyer-Moore algorithm)
|
||||
// Return pos of found string or 'pos+size' if not found.
|
||||
//
|
||||
int find_magic( const uint8_t * const buffer, const int pos, const int size ) throw()
|
||||
int find_magic( const uint8_t * const buffer, const int pos, const int size )
|
||||
{
|
||||
const unsigned char table[256] = {
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#! /bin/sh
|
||||
# check script for Lziprecover - Data recovery tool for lzipped files
|
||||
# Copyright (C) 2009, 2010, 2011 Antonio Diaz Diaz.
|
||||
# Copyright (C) 2009, 2010, 2011, 2012 Antonio Diaz Diaz.
|
||||
#
|
||||
# This script is free software: you have unlimited permission
|
||||
# to copy, distribute and modify it.
|
||||
|
@ -9,11 +9,12 @@ LC_ALL=C
|
|||
export LC_ALL
|
||||
objdir=`pwd`
|
||||
testdir=`cd "$1" ; pwd`
|
||||
LZIP="${objdir}"/lziprecover
|
||||
LZIPRECOVER="${objdir}"/lziprecover
|
||||
framework_failure() { echo "failure in testing framework" ; exit 1 ; }
|
||||
|
||||
if [ ! -x "${LZIPRECOVER}" ] ; then
|
||||
echo "${LZIPRECOVER}: cannot execute"
|
||||
if [ ! -x "${LZIP}" ] ; then
|
||||
echo "${LZIP}: cannot execute"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
@ -40,7 +41,19 @@ fail=0
|
|||
|
||||
printf "testing lziprecover-%s..." "$2"
|
||||
|
||||
"${LZIPRECOVER}" -D 921-1921 -o copy ${in_lz} || fail=1
|
||||
"${LZIP}" -t "${testdir}"/test_v0.lz || fail=1
|
||||
printf .
|
||||
"${LZIP}" -cd "${testdir}"/test_v0.lz > copy || fail=1
|
||||
cmp ${in} copy || fail=1
|
||||
printf .
|
||||
|
||||
"${LZIP}" -t "${testdir}"/test_v1.lz || fail=1
|
||||
printf .
|
||||
"${LZIP}" -cd "${testdir}"/test_v1.lz > copy || fail=1
|
||||
cmp ${in} copy || fail=1
|
||||
printf .
|
||||
|
||||
"${LZIPRECOVER}" -D 921-1921 -fo copy ${in_lz} || fail=1
|
||||
cmp ${inD} copy || fail=1
|
||||
printf .
|
||||
"${LZIPRECOVER}" -D 921,1000 ${in_lz} > copy || fail=1
|
||||
|
@ -102,6 +115,11 @@ for i in 1 2 3 ; do
|
|||
printf .
|
||||
done
|
||||
|
||||
cat ${in_lz} > anyothername || framework_failure
|
||||
"${LZIP}" -d anyothername || fail=1
|
||||
cmp ${in} anyothername.out || fail=1
|
||||
printf .
|
||||
|
||||
echo
|
||||
if [ ${fail} = 0 ] ; then
|
||||
echo "tests completed successfully."
|
||||
|
|
353
testsuite/unzcrash.cc
Normal file
353
testsuite/unzcrash.cc
Normal file
|
@ -0,0 +1,353 @@
|
|||
/* Unzcrash - A test program written to test robustness to
|
||||
decompression of corrupted data.
|
||||
Inspired by unzcrash.c from Julian Seward's bzip2.
|
||||
Copyright (C) 2008, 2009, 2010, 2011, 2012 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 3 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.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../arg_parser.h"
|
||||
|
||||
#if CHAR_BIT != 8
|
||||
#error "Environments where CHAR_BIT != 8 are not supported."
|
||||
#endif
|
||||
|
||||
#ifndef LLONG_MAX
|
||||
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
|
||||
#endif
|
||||
#ifndef LLONG_MIN
|
||||
#define LLONG_MIN (-LLONG_MAX - 1LL)
|
||||
#endif
|
||||
#ifndef ULLONG_MAX
|
||||
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
|
||||
#endif
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
const char * const Program_name = "Unzcrash";
|
||||
const char * const program_name = "unzcrash";
|
||||
const char * const program_year = "2012";
|
||||
const char * invocation_name = 0;
|
||||
|
||||
int verbosity = 0;
|
||||
|
||||
|
||||
void show_help()
|
||||
{
|
||||
std::printf( "%s - A test program written to test robustness to\n", Program_name );
|
||||
std::printf( "decompression of corrupted data.\n"
|
||||
"\nUsage: %s [options] \"lzip -tv\" filename.lz\n", invocation_name );
|
||||
std::printf( "\nThis program reads the specified file and then repeatedly decompresses\n"
|
||||
"it, increasing 256 times each byte of the compressed data, so as to test\n"
|
||||
"all possible one-byte errors. This should not cause any invalid memory\n"
|
||||
"accesses. If it does, please, report it as a bug.\n"
|
||||
"\nOptions:\n"
|
||||
" -h, --help display this help and exit\n"
|
||||
" -V, --version output version information and exit\n"
|
||||
" -b, --bits=<n>[,<n>]... test <n>-bit errors instead of full byte\n"
|
||||
" -p, --position=<bytes> first byte position to test\n"
|
||||
" -q, --quiet suppress all messages\n"
|
||||
" -s, --size=<bytes> number of byte positions to test\n"
|
||||
" -v, --verbose be verbose (a 2nd -v gives more)\n"
|
||||
"\nReport bugs to lzip-bug@nongnu.org\n"
|
||||
"Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
|
||||
}
|
||||
|
||||
|
||||
void show_version()
|
||||
{
|
||||
std::printf( "%s %s\n", Program_name, PROGVERSION );
|
||||
std::printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
|
||||
std::printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\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" );
|
||||
}
|
||||
|
||||
|
||||
void show_error( const char * const msg, const int errcode = 0,
|
||||
const bool help = false )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
{
|
||||
if( msg && msg[0] )
|
||||
{
|
||||
std::fprintf( stderr, "%s: %s", program_name, msg );
|
||||
if( errcode > 0 )
|
||||
std::fprintf( stderr, ": %s", std::strerror( errcode ) );
|
||||
std::fprintf( stderr, "\n" );
|
||||
}
|
||||
if( help && invocation_name && invocation_name[0] )
|
||||
std::fprintf( stderr, "Try '%s --help' for more information.\n",
|
||||
invocation_name );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void internal_error( const char * const msg )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
|
||||
std::exit( 3 );
|
||||
}
|
||||
|
||||
|
||||
long long getnum( const char * const ptr,
|
||||
const long long llimit = LLONG_MIN + 1,
|
||||
const long long ulimit = LLONG_MAX )
|
||||
{
|
||||
errno = 0;
|
||||
char *tail;
|
||||
long long result = strtoll( ptr, &tail, 0 );
|
||||
if( tail == ptr )
|
||||
{
|
||||
show_error( "Bad or missing numerical argument.", 0, true );
|
||||
std::exit( 1 );
|
||||
}
|
||||
|
||||
if( !errno && tail[0] )
|
||||
{
|
||||
int factor = ( tail[1] == 'i' ) ? 1024 : 1000;
|
||||
int exponent = 0;
|
||||
bool bad_multiplier = false;
|
||||
switch( tail[0] )
|
||||
{
|
||||
case ' ': break;
|
||||
case 'Y': exponent = 8; break;
|
||||
case 'Z': exponent = 7; break;
|
||||
case 'E': exponent = 6; break;
|
||||
case 'P': exponent = 5; break;
|
||||
case 'T': exponent = 4; break;
|
||||
case 'G': exponent = 3; break;
|
||||
case 'M': exponent = 2; break;
|
||||
case 'K': if( factor == 1024 ) exponent = 1; else bad_multiplier = true;
|
||||
break;
|
||||
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
|
||||
break;
|
||||
default : bad_multiplier = true;
|
||||
}
|
||||
if( bad_multiplier )
|
||||
{
|
||||
show_error( "Bad multiplier in numerical argument.", 0, true );
|
||||
std::exit( 1 );
|
||||
}
|
||||
for( int i = 0; i < exponent; ++i )
|
||||
{
|
||||
if( LLONG_MAX / factor >= llabs( result ) ) result *= factor;
|
||||
else { errno = ERANGE; break; }
|
||||
}
|
||||
}
|
||||
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
|
||||
if( errno )
|
||||
{
|
||||
show_error( "Numerical argument out of limits." );
|
||||
std::exit( 1 );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
class Bitset8 // 8 value bitset (1..8)
|
||||
{
|
||||
bool data[8];
|
||||
static bool valid_digit( const unsigned char ch )
|
||||
{ return ( ch >= '1' && ch <= '8' ); }
|
||||
|
||||
public:
|
||||
Bitset8() { for( int i = 0; i < 8; ++i ) data[i] = true; }
|
||||
|
||||
bool includes( const int i ) const
|
||||
{ return ( i >= 1 && i <= 8 && data[i-1] ); }
|
||||
|
||||
// Recognized formats: 1 1,2,3 1-4 1,3-5,8
|
||||
bool parse( const char * p )
|
||||
{
|
||||
for( int i = 0; i < 8; ++i ) data[i] = false;
|
||||
while( true )
|
||||
{
|
||||
const unsigned char ch1 = *p++;
|
||||
if( !valid_digit( ch1 ) ) break;
|
||||
if( *p != '-' ) data[ch1-'1'] = true;
|
||||
else
|
||||
{
|
||||
++p;
|
||||
if( !valid_digit( *p ) || ch1 > *p ) break;
|
||||
for( int c = ch1; c <= *p; ++c ) data[c-'1'] = true;
|
||||
++p;
|
||||
}
|
||||
if( *p == 0 ) return true;
|
||||
if( *p == ',' ) ++p; else break;
|
||||
}
|
||||
show_error( "Invalid value or range." );
|
||||
return false;
|
||||
}
|
||||
|
||||
// number of n-bit errors per byte (n=0..8): 1 8 28 56 70 56 28 8 1
|
||||
void print() const
|
||||
{
|
||||
std::fflush( stderr );
|
||||
int c = 0;
|
||||
for( int i = 0; i < 8; ++i ) if( data[i] ) ++c;
|
||||
if( c == 8 ) std::printf( "Testing full byte.\n" );
|
||||
else if( c == 0 ) std::printf( "Nothing to test.\n" );
|
||||
else
|
||||
{
|
||||
std::printf( "Testing " );
|
||||
for( int i = 0; i < 8; ++i )
|
||||
if( data[i] )
|
||||
{
|
||||
std::printf( "%d", i + 1 );
|
||||
if( --c ) std::printf( "," );
|
||||
}
|
||||
std::printf( " bit errors.\n" );
|
||||
}
|
||||
std::fflush( stdout );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int differing_bits( const uint8_t byte1, const uint8_t byte2 )
|
||||
{
|
||||
int count = 0;
|
||||
uint8_t dif = byte1 ^ byte2;
|
||||
while( dif )
|
||||
{ count += ( dif & 1 ); dif >>= 1; }
|
||||
return count;
|
||||
}
|
||||
|
||||
} // end namespace
|
||||
|
||||
|
||||
int main( const int argc, const char * const argv[] )
|
||||
{
|
||||
enum { buffer_size = 3 << 20 };
|
||||
Bitset8 bits; // if Bitset8::parse not called test full byte
|
||||
int pos = 0;
|
||||
int max_size = buffer_size;
|
||||
invocation_name = argv[0];
|
||||
|
||||
const Arg_parser::Option options[] =
|
||||
{
|
||||
{ 'h', "help", Arg_parser::no },
|
||||
{ 'b', "bits", Arg_parser::yes },
|
||||
{ 'p', "position", Arg_parser::yes },
|
||||
{ 'q', "quiet", Arg_parser::no },
|
||||
{ 's', "size", Arg_parser::yes },
|
||||
{ 'v', "verbose", Arg_parser::no },
|
||||
{ 'V', "version", Arg_parser::no },
|
||||
{ 0 , 0, Arg_parser::no } };
|
||||
|
||||
const Arg_parser parser( argc, argv, options );
|
||||
if( parser.error().size() ) // bad option
|
||||
{ show_error( parser.error().c_str(), 0, true ); return 1; }
|
||||
|
||||
int argind = 0;
|
||||
for( ; argind < parser.arguments(); ++argind )
|
||||
{
|
||||
const int code = parser.code( argind );
|
||||
if( !code ) break; // no more options
|
||||
const char * const arg = parser.argument( argind ).c_str();
|
||||
switch( code )
|
||||
{
|
||||
case 'h': show_help(); return 0;
|
||||
case 'b': if( !bits.parse( arg ) ) return 1; break;
|
||||
case 'p': pos = getnum( arg, 0, buffer_size - 1 ); break;
|
||||
case 'q': verbosity = -1; break;
|
||||
case 's': max_size = getnum( arg, 1, buffer_size ); break;
|
||||
case 'v': if( verbosity < 4 ) ++verbosity; break;
|
||||
case 'V': show_version(); return 0;
|
||||
default : internal_error( "uncaught option" );
|
||||
}
|
||||
} // end process options
|
||||
|
||||
if( argind + 2 != parser.arguments() )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "Usage: %s \"lzip -tv\" filename.lz\n",
|
||||
invocation_name );
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *f = std::fopen( parser.argument( argind + 1 ).c_str(), "rb" );
|
||||
if( !f )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "Can't open file '%s' for reading\n",
|
||||
parser.argument( argind + 1 ).c_str() );
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t * const buffer = new uint8_t[buffer_size];
|
||||
const int size = std::fread( buffer, 1, buffer_size, f );
|
||||
if( size >= buffer_size )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "input file '%s' is too big.\n",
|
||||
parser.argument( argind + 1 ).c_str() );
|
||||
return 1;
|
||||
}
|
||||
std::fclose( f );
|
||||
|
||||
f = popen( parser.argument( argind ).c_str(), "w" );
|
||||
if( !f )
|
||||
{ show_error( "Can't open pipe", errno ); return 1; }
|
||||
const int wr = std::fwrite( buffer, 1, size, f );
|
||||
if( wr != size || pclose( f ) != 0 )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "Could not run '%s' : %s.\n",
|
||||
parser.argument( argind ).c_str(), std::strerror( errno ) );
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::signal( SIGPIPE, SIG_IGN );
|
||||
if( verbosity >= 1 ) bits.print();
|
||||
|
||||
const int end = ( ( pos + max_size < size ) ? pos + max_size : size );
|
||||
for( int i = pos; i < end; ++i )
|
||||
{
|
||||
if( verbosity >= 0 )
|
||||
std::fprintf( stderr, "byte %d\n", i );
|
||||
const uint8_t byte = buffer[i];
|
||||
for( int j = 0; j < 255; ++j )
|
||||
{
|
||||
++buffer[i];
|
||||
if( bits.includes( differing_bits( byte, buffer[i] ) ) )
|
||||
{
|
||||
f = popen( parser.argument( argind ).c_str(), "w" );
|
||||
if( !f )
|
||||
{ show_error( "Can't open pipe", errno ); return 1; }
|
||||
std::fwrite( buffer, 1, size, f );
|
||||
if( pclose( f ) == 0 && verbosity >= 0 )
|
||||
std::fprintf( stderr, "0x%02X (0x%02X+0x%02X) passed the test\n",
|
||||
buffer[i], byte, j + 1 );
|
||||
}
|
||||
}
|
||||
buffer[i] = byte;
|
||||
}
|
||||
|
||||
delete[] buffer;
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Reference in a new issue