1
0
Fork 0

Adding upstream version 1.5~rc1.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-02-17 22:13:05 +01:00
parent 44c75e168c
commit df42bf1fa4
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
11 changed files with 245 additions and 43 deletions

View file

@ -1 +1,7 @@
Lunzip was written by Antonio Diaz Diaz. Lunzip was written by Antonio Diaz Diaz.
The ideas embodied in lunzip are due to (at least) the following people:
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
the definition of Markov chains), G.N.N. Martin (for the definition of
range encoding), Igor Pavlov (for putting all the above together in
LZMA), and Julian Seward (for bzip2's CLI).

View file

@ -1,3 +1,9 @@
2013-10-30 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.5-rc1 released.
* main.c: Added new option '-u, --buffer-size' (low memory mode).
* main.c (close_and_set_permissions): Behave like 'cp -p'.
2013-09-17 Antonio Diaz Diaz <antonio@gnu.org> 2013-09-17 Antonio Diaz Diaz <antonio@gnu.org>
* Version 1.4 released. * Version 1.4 released.

View file

@ -1,8 +1,8 @@
DISTNAME = $(pkgname)-$(pkgversion) DISTNAME = $(pkgname)-$(pkgversion)
INSTALL = install INSTALL = install
INSTALL_PROGRAM = $(INSTALL) -p -m 755 INSTALL_PROGRAM = $(INSTALL) -m 755
INSTALL_DATA = $(INSTALL) -p -m 644 INSTALL_DATA = $(INSTALL) -m 644
INSTALL_DIR = $(INSTALL) -d -m 755 INSTALL_DIR = $(INSTALL) -d -m 755
SHELL = /bin/sh SHELL = /bin/sh

7
NEWS
View file

@ -1,5 +1,6 @@
Changes in version 1.4: Changes in version 1.5:
File version is no more shown in status messages. The new option "-u, --buffer-size", which activates a "low memory"
decompression mode, has been added.
Minor fixes. File date, permissions, and ownership are now copied like "cp -p" does.

26
README
View file

@ -5,13 +5,23 @@ small size makes it well suited for embedded devices or software
installers that need to decompress files but do not need compression installers that need to decompress files but do not need compression
capabilities. Lunzip is fully compatible with lzip-1.4 or newer. capabilities. Lunzip is fully compatible with lzip-1.4 or newer.
If the size of the output buffer is specified with the "--buffer-size"
option, lunzip uses the decompressed file as dictionary for distances
beyond the buffer size and is able to decompress any file using as
little memory as 50 kB, irrespective of the dictionary size used to
compress the file. Of course, the smaller the output buffer size used in
relation to the dictionary size, the more accesses to disk are needed
and the slower the decompression is. This "low memory" mode only works
when decompressing to a regular file.
The lzip file format is designed for long-term data archiving. It is The lzip file format is designed for long-term data archiving. It is
clean, provides very safe 4 factor integrity checking, and is backed by clean, provides very safe 4 factor integrity checking, and is backed by
the recovery capabilities of lziprecover. the recovery capabilities of lziprecover.
Lunzip uses the same well-defined exit status values used by lzip and Lunzip uses the same well-defined exit status values used by lzip and
bzip2, which makes it safer when used in pipes or scripts than bzip2, which makes it safer than decompressors returning ambiguous
decompressors returning ambiguous warning values, like gunzip. warning values (like gunzip) when it is used as a back end for tar or
zutils.
Lunzip replaces every file given in the command line with a decompressed Lunzip replaces every file given in the command line with a decompressed
version of itself. Each decompressed file has the same modification version of itself. Each decompressed file has the same modification
@ -35,9 +45,15 @@ two or more compressed files. The result is the concatenation of the
corresponding uncompressed files. Integrity testing of concatenated corresponding uncompressed files. Integrity testing of concatenated
compressed files is also supported. compressed files is also supported.
The amount of memory required by lunzip to decompress a file is only a The amount of memory required by lunzip to decompress a file is about
few tens of KiB larger than the dictionary size used to compress that 46 kB larger than the dictionary size used to compress that file, unless
file. the "--buffer-size" option is specified.
The ideas embodied in lunzip are due to (at least) the following people:
Abraham Lempel and Jacob Ziv (for the LZ algorithm), Andrey Markov (for
the definition of Markov chains), G.N.N. Martin (for the definition of
range encoding), Igor Pavlov (for putting all the above together in
LZMA), and Julian Seward (for bzip2's CLI).
Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz. Copyright (C) 2010, 2011, 2012, 2013 Antonio Diaz Diaz.

2
configure vendored
View file

@ -6,7 +6,7 @@
# to copy, distribute and modify it. # to copy, distribute and modify it.
pkgname=lunzip pkgname=lunzip
pkgversion=1.4 pkgversion=1.5-rc1
progname=lunzip progname=lunzip
srctrigger=doc/${progname}.1 srctrigger=doc/${progname}.1

View file

@ -87,6 +87,15 @@ static int writeblock( const int fd, const uint8_t * const buf, const int size )
} }
int seek_read( const int fd, uint8_t * const buf, const int size,
const int offset )
{
if( lseek( fd, offset, SEEK_END ) >= 0 )
return readblock( fd, buf, size );
return 0;
}
bool Rd_read_block( struct Range_decoder * const rdec ) bool Rd_read_block( struct Range_decoder * const rdec )
{ {
if( !rdec->at_stream_end ) if( !rdec->at_stream_end )
@ -193,6 +202,10 @@ int LZd_decode_member( struct LZ_decoder * const decoder,
struct Pretty_print * const pp ) struct Pretty_print * const pp )
{ {
struct Range_decoder * const rdec = decoder->rdec; struct Range_decoder * const rdec = decoder->rdec;
void (* const copy_block)
( struct LZ_decoder * const decoder, const int distance, int len ) =
( decoder->buffer_size >= decoder->dictionary_size ) ?
&LZd_copy_block : &LZd_copy_block2;
unsigned rep0 = 0; /* rep[0-3] latest four distances */ unsigned rep0 = 0; /* rep[0-3] latest four distances */
unsigned rep1 = 0; /* used for efficient coding of */ unsigned rep1 = 0; /* used for efficient coding of */
unsigned rep2 = 0; /* repeated distances */ unsigned rep2 = 0; /* repeated distances */
@ -293,10 +306,10 @@ int LZd_decode_member( struct LZ_decoder * const decoder,
rep3 = rep2; rep2 = rep1; rep1 = rep0_saved; rep3 = rep2; rep2 = rep1; rep1 = rep0_saved;
state = St_set_match( state ); state = St_set_match( state );
if( rep0 >= (unsigned)decoder->dictionary_size || if( rep0 >= (unsigned)decoder->dictionary_size ||
( rep0 >= (unsigned)decoder->pos && !decoder->partial_data_pos ) ) rep0 >= LZd_data_position( decoder ) )
{ LZd_flush_data( decoder ); return 1; } { LZd_flush_data( decoder ); return 1; }
} }
LZd_copy_block( decoder, rep0, len ); copy_block( decoder, rep0, len );
} }
} }
LZd_flush_data( decoder ); LZd_flush_data( decoder );

View file

@ -85,6 +85,7 @@ static inline void Rd_load( struct Range_decoder * const rdec )
for( i = 0; i < 5; ++i ) for( i = 0; i < 5; ++i )
rdec->code = (rdec->code << 8) | Rd_get_byte( rdec ); rdec->code = (rdec->code << 8) | Rd_get_byte( rdec );
rdec->range = 0xFFFFFFFFU; rdec->range = 0xFFFFFFFFU;
rdec->code &= rdec->range; /* make sure that first byte is discarded */
} }
static inline void Rd_normalize( struct Range_decoder * const rdec ) static inline void Rd_normalize( struct Range_decoder * const rdec )
@ -259,6 +260,9 @@ void LZd_flush_data( struct LZ_decoder * const decoder );
bool LZd_verify_trailer( struct LZ_decoder * const decoder, bool LZd_verify_trailer( struct LZ_decoder * const decoder,
struct Pretty_print * const pp ); struct Pretty_print * const pp );
int seek_read( const int fd, uint8_t * const buf, const int size,
const int offset );
static inline uint8_t LZd_get_prev_byte( const struct LZ_decoder * const decoder ) static inline uint8_t LZd_get_prev_byte( const struct LZ_decoder * const decoder )
{ {
const int i = const int i =
@ -269,9 +273,14 @@ static inline uint8_t LZd_get_prev_byte( const struct LZ_decoder * const decoder
static inline uint8_t LZd_get_byte( const struct LZ_decoder * const decoder, static inline uint8_t LZd_get_byte( const struct LZ_decoder * const decoder,
const int distance ) const int distance )
{ {
int i = decoder->pos - distance - 1; uint8_t b;
if( i < 0 ) i += decoder->buffer_size; const int i = decoder->pos - distance - 1;
return decoder->buffer[i]; if( i >= 0 ) b = decoder->buffer[i];
else if( i + decoder->buffer_size >= decoder->pos )
b = decoder->buffer[i+decoder->buffer_size];
else if( seek_read( decoder->outfd, &b, 1, i - decoder->stream_pos ) != 1 )
{ show_error( "Seek error", errno, false ); cleanup_and_fail( 1 ); }
return b;
} }
static inline void LZd_put_byte( struct LZ_decoder * const decoder, static inline void LZd_put_byte( struct LZ_decoder * const decoder,
@ -300,13 +309,35 @@ static inline void LZd_copy_block( struct LZ_decoder * const decoder,
} }
} }
static inline void LZd_copy_block2( struct LZ_decoder * const decoder,
const int distance, int len )
{
if( distance < decoder->buffer_size ) /* block is in buffer */
{ LZd_copy_block( decoder, distance, len ); return; }
if( len < decoder->buffer_size - decoder->pos ) /* no wrap */
{
const int offset = decoder->pos - decoder->stream_pos - distance - 1;
if( len <= -offset ) /* block is in file */
{
if( seek_read( decoder->outfd, decoder->buffer + decoder->pos, len, offset ) != len )
{ show_error( "Seek error", errno, false ); cleanup_and_fail( 1 ); }
decoder->pos += len;
return;
}
}
for( ; len > 0; --len )
LZd_put_byte( decoder, LZd_get_byte( decoder, distance ) );
}
static inline bool LZd_init( struct LZ_decoder * const decoder, static inline bool LZd_init( struct LZ_decoder * const decoder,
const File_header header, const File_header header,
struct Range_decoder * const rde, const int ofd ) struct Range_decoder * const rde,
const int buffer_size, const int ofd )
{ {
decoder->partial_data_pos = 0; decoder->partial_data_pos = 0;
decoder->dictionary_size = Fh_get_dictionary_size( header ); decoder->dictionary_size = Fh_get_dictionary_size( header );
decoder->buffer_size = max( 65536, decoder->dictionary_size ); decoder->buffer_size =
min( buffer_size, max( 65536, decoder->dictionary_size ) );
decoder->buffer = (uint8_t *)malloc( decoder->buffer_size ); decoder->buffer = (uint8_t *)malloc( decoder->buffer_size );
if( !decoder->buffer ) return false; if( !decoder->buffer ) return false;
decoder->pos = 0; decoder->pos = 0;

View file

@ -1,12 +1,24 @@
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1. .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.37.1.
.TH LUNZIP "1" "September 2013" "Lunzip 1.4" "User Commands" .TH LUNZIP "1" "October 2013" "Lunzip 1.5-rc1" "User Commands"
.SH NAME .SH NAME
Lunzip \- decompressor for lzip files Lunzip \- decompressor for lzip files
.SH SYNOPSIS .SH SYNOPSIS
.B lunzip .B lunzip
[\fIoptions\fR] [\fIfiles\fR] [\fIoptions\fR] [\fIfiles\fR]
.SH DESCRIPTION .SH DESCRIPTION
Lunzip \- Decompressor for lzip files. Lunzip is a decompressor for lzip files. It is written in C and its
small size makes it well suited for embedded devices or software
installers that need to decompress files but do not need compression
capabilities. Lunzip is fully compatible with lzip\-1.4 or newer.
.PP
If the size of the output buffer is specified with the '\-\-buffer\-size'
option, lunzip uses the decompressed file as dictionary for distances
beyond the buffer size and is able to decompress any file using as
little memory as 50 kB, irrespective of the dictionary size used to
compress the file. Of course, the smaller the output buffer size used in
relation to the dictionary size, the more accesses to disk are needed
and the slower the decompression is. This 'low memory' mode only works
when decompressing to a regular file.
.SH OPTIONS .SH OPTIONS
.TP .TP
\fB\-h\fR, \fB\-\-help\fR \fB\-h\fR, \fB\-\-help\fR
@ -36,6 +48,9 @@ suppress all messages
\fB\-t\fR, \fB\-\-test\fR \fB\-t\fR, \fB\-\-test\fR
test compressed file integrity test compressed file integrity
.TP .TP
\fB\-u\fR, \fB\-\-buffer\-size=\fR<bytes>
set output buffer size in bytes
.TP
\fB\-v\fR, \fB\-\-verbose\fR \fB\-v\fR, \fB\-\-verbose\fR
be verbose (a 2nd \fB\-v\fR gives more) be verbose (a 2nd \fB\-v\fR gives more)
.PP .PP

140
main.c
View file

@ -54,6 +54,10 @@
#include "lzip.h" #include "lzip.h"
#include "decoder.h" #include "decoder.h"
#ifndef O_BINARY
#define O_BINARY 0
#endif
#if CHAR_BIT != 8 #if CHAR_BIT != 8
#error "Environments where CHAR_BIT != 8 are not supported." #error "Environments where CHAR_BIT != 8 are not supported."
#endif #endif
@ -64,12 +68,6 @@ const char * const program_name = "lunzip";
const char * const program_year = "2013"; const char * const program_year = "2013";
const char * invocation_name = 0; const char * invocation_name = 0;
#ifdef O_BINARY
const int o_binary = O_BINARY;
#else
const int o_binary = 0;
#endif
struct { const char * from; const char * to; } const known_extensions[] = { struct { const char * from; const char * to; } const known_extensions[] = {
{ ".lz", "" }, { ".lz", "" },
{ ".tlz", ".tar" }, { ".tlz", ".tar" },
@ -86,7 +84,18 @@ bool delete_output_on_interrupt = false;
static void show_help( void ) static void show_help( void )
{ {
printf( "%s - Decompressor for lzip files.\n", Program_name ); printf( "Lunzip is a decompressor for lzip files. It is written in C and its\n"
"small size makes it well suited for embedded devices or software\n"
"installers that need to decompress files but do not need compression\n"
"capabilities. Lunzip is fully compatible with lzip-1.4 or newer.\n"
"\nIf the size of the output buffer is specified with the '--buffer-size'\n"
"option, lunzip uses the decompressed file as dictionary for distances\n"
"beyond the buffer size and is able to decompress any file using as\n"
"little memory as 50 kB, irrespective of the dictionary size used to\n"
"compress the file. Of course, the smaller the output buffer size used in\n"
"relation to the dictionary size, the more accesses to disk are needed\n"
"and the slower the decompression is. This 'low memory' mode only works\n"
"when decompressing to a regular file.\n" );
printf( "\nUsage: %s [options] [files]\n", invocation_name ); printf( "\nUsage: %s [options] [files]\n", invocation_name );
printf( "\nOptions:\n" printf( "\nOptions:\n"
" -h, --help display this help and exit\n" " -h, --help display this help and exit\n"
@ -98,6 +107,7 @@ static void show_help( void )
" -o, --output=<file> if reading stdin, place the output into <file>\n" " -o, --output=<file> if reading stdin, place the output into <file>\n"
" -q, --quiet suppress all messages\n" " -q, --quiet suppress all messages\n"
" -t, --test test compressed file integrity\n" " -t, --test test compressed file integrity\n"
" -u, --buffer-size=<bytes> set output buffer size in bytes\n"
" -v, --verbose be verbose (a 2nd -v gives more)\n" " -v, --verbose be verbose (a 2nd -v gives more)\n"
"If no file names are given, lunzip decompresses from standard input to\n" "If no file names are given, lunzip decompresses from standard input to\n"
"standard output.\n" "standard output.\n"
@ -137,6 +147,73 @@ static void show_header( const File_header header )
} }
static unsigned long getnum( const char * const ptr,
const unsigned long llimit,
const unsigned long ulimit )
{
unsigned long result;
char * tail;
errno = 0;
result = strtoul( ptr, &tail, 0 );
if( tail == ptr )
{
show_error( "Bad or missing numerical argument.", 0, true );
exit( 1 );
}
if( !errno && tail[0] )
{
int factor = ( tail[1] == 'i' ) ? 1024 : 1000;
int exponent = 0, i;
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 );
exit( 1 );
}
for( i = 0; i < exponent; ++i )
{
if( ulimit / factor >= result ) result *= factor;
else { errno = ERANGE; break; }
}
}
if( !errno && ( result < llimit || result > ulimit ) ) errno = ERANGE;
if( errno )
{
show_error( "Numerical argument out of limits.", 0, false );
exit( 1 );
}
return result;
}
static int get_dict_size( const char * const arg )
{
char * tail;
int bits = strtol( arg, &tail, 0 );
if( bits >= min_dictionary_bits &&
bits <= max_dictionary_bits && *tail == 0 )
return ( 1 << bits );
return getnum( arg, min_dictionary_size, max_dictionary_size );
}
static int extension_index( const char * const name ) static int extension_index( const char * const name )
{ {
int i; int i;
@ -152,9 +229,9 @@ static int extension_index( const char * const name )
static int open_instream( const char * const name, struct stat * const in_statsp, static int open_instream( const char * const name, struct stat * const in_statsp,
const bool testing, const bool to_stdout ) const bool no_ofile )
{ {
int infd = open( name, O_RDONLY | o_binary ); int infd = open( name, O_RDONLY | O_BINARY );
if( infd < 0 ) if( infd < 0 )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
@ -168,7 +245,6 @@ static int open_instream( const char * const name, struct stat * const in_statsp
const bool can_read = ( i == 0 && const bool can_read = ( i == 0 &&
( S_ISBLK( mode ) || S_ISCHR( mode ) || ( S_ISBLK( mode ) || S_ISCHR( mode ) ||
S_ISFIFO( mode ) || S_ISSOCK( mode ) ) ); S_ISFIFO( mode ) || S_ISSOCK( mode ) ) );
const bool no_ofile = to_stdout || testing;
if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) ) if( i != 0 || ( !S_ISREG( mode ) && ( !can_read || !no_ofile ) ) )
{ {
if( verbosity >= 0 ) if( verbosity >= 0 )
@ -224,7 +300,7 @@ static void set_d_outname( const char * const name, const int i )
static bool open_outstream( const bool force ) static bool open_outstream( const bool force )
{ {
int flags = O_CREAT | O_WRONLY | o_binary; int flags = O_APPEND | O_CREAT | O_RDWR | O_BINARY;
if( force ) flags |= O_TRUNC; else flags |= O_EXCL; if( force ) flags |= O_TRUNC; else flags |= O_EXCL;
outfd = open( output_filename, flags, outfd_mode ); outfd = open( output_filename, flags, outfd_mode );
@ -263,10 +339,14 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
bool warning = false; bool warning = false;
if( in_statsp ) if( in_statsp )
{ {
const mode_t mode = in_statsp->st_mode;
/* fchown will in many cases return with EPERM, which can be safely ignored. */ /* fchown will in many cases return with EPERM, which can be safely ignored. */
if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 && if( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) == 0 )
errno != EPERM ) || { if( fchmod( outfd, mode ) != 0 ) warning = true; }
fchmod( outfd, in_statsp->st_mode ) != 0 ) warning = true; else
if( errno != EPERM ||
fchmod( outfd, mode & ~( S_ISUID | S_ISGID | S_ISVTX ) ) != 0 )
warning = true;
} }
if( close( outfd ) != 0 ) cleanup_and_fail( 1 ); if( close( outfd ) != 0 ) cleanup_and_fail( 1 );
outfd = -1; outfd = -1;
@ -283,8 +363,8 @@ static void close_and_set_permissions( const struct stat * const in_statsp )
} }
static int decompress( const int infd, struct Pretty_print * const pp, static int decompress( const int buffer_size, const int infd,
const bool testing ) struct Pretty_print * const pp, const bool testing )
{ {
unsigned long long partial_file_pos = 0; unsigned long long partial_file_pos = 0;
struct Range_decoder rdec; struct Range_decoder rdec;
@ -292,7 +372,7 @@ static int decompress( const int infd, struct Pretty_print * const pp,
bool first_member; bool first_member;
if( !Rd_init( &rdec, infd ) ) if( !Rd_init( &rdec, infd ) )
{ {
show_error( "Not enough memory. Find a machine with more memory.", 0, false ); show_error( "Not enough memory.", 0, false );
cleanup_and_fail( 1 ); cleanup_and_fail( 1 );
} }
@ -332,9 +412,9 @@ static int decompress( const int infd, struct Pretty_print * const pp,
if( verbosity >= 2 || ( verbosity == 1 && first_member ) ) if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
{ Pp_show_msg( pp, 0 ); if( verbosity >= 3 ) show_header( header ); } { Pp_show_msg( pp, 0 ); if( verbosity >= 3 ) show_header( header ); }
if( !LZd_init( &decoder, header, &rdec, outfd ) ) if( !LZd_init( &decoder, header, &rdec, buffer_size, outfd ) )
{ {
show_error( "Not enough memory. Find a machine with more memory.", 0, false ); show_error( "Not enough memory. Try a smaller output buffer size.", 0, false );
cleanup_and_fail( 1 ); cleanup_and_fail( 1 );
} }
result = LZd_decode_member( &decoder, pp ); result = LZd_decode_member( &decoder, pp );
@ -431,6 +511,7 @@ int main( const int argc, const char * const argv[] )
const char * default_output_filename = ""; const char * default_output_filename = "";
const char ** filenames = 0; const char ** filenames = 0;
int num_filenames = 0; int num_filenames = 0;
int buffer_size = max_dictionary_size;
int infd = -1; int infd = -1;
int argind = 0; int argind = 0;
int retval = 0; int retval = 0;
@ -453,6 +534,7 @@ int main( const int argc, const char * const argv[] )
{ 'o', "output", ap_yes }, { 'o', "output", ap_yes },
{ 'q', "quiet", ap_no }, { 'q', "quiet", ap_no },
{ 't', "test", ap_no }, { 't', "test", ap_no },
{ 'u', "buffer-size", ap_yes },
{ 'v', "verbose", ap_no }, { 'v', "verbose", ap_no },
{ 'V', "version", ap_no }, { 'V', "version", ap_no },
{ 0 , 0, ap_no } }; { 0 , 0, ap_no } };
@ -463,7 +545,7 @@ int main( const int argc, const char * const argv[] )
CRC32_init(); CRC32_init();
if( !ap_init( &parser, argc, argv, options, 0 ) ) if( !ap_init( &parser, argc, argv, options, 0 ) )
{ show_error( "Memory exhausted.", 0, false ); return 1; } { show_error( "Not enough memory.", 0, false ); return 1; }
if( ap_error( &parser ) ) /* bad option */ if( ap_error( &parser ) ) /* bad option */
{ show_error( ap_error( &parser ), 0, true ); return 1; } { show_error( ap_error( &parser ), 0, true ); return 1; }
@ -483,6 +565,7 @@ int main( const int argc, const char * const argv[] )
case 'o': default_output_filename = arg; break; case 'o': default_output_filename = arg; break;
case 'q': verbosity = -1; break; case 'q': verbosity = -1; break;
case 't': testing = true; break; case 't': testing = true; break;
case 'u': buffer_size = get_dict_size( arg ); break;
case 'v': if( verbosity < 4 ) ++verbosity; break; case 'v': if( verbosity < 4 ) ++verbosity; break;
case 'V': show_version(); return 0; case 'V': show_version(); return 0;
default : internal_error( "uncaught option" ); default : internal_error( "uncaught option" );
@ -507,6 +590,19 @@ int main( const int argc, const char * const argv[] )
if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true; if( strcmp( filenames[i], "-" ) != 0 ) filenames_given = true;
} }
if( buffer_size < max_dictionary_size )
{
if( to_stdout || testing )
{ show_error( "'--buffer-size' is incompatible with '--stdout' and '--test'.", 0, false );
return 1; }
if( !default_output_filename[0] )
for( i = 0; i < num_filenames; ++i )
if( !filenames[i][0] || strcmp( filenames[i], "-" ) == 0 )
{ show_error( "Output file must be specified when decompressing from stdin with a\n"
" reduced buffer size.", 0, false );
return 1; }
}
if( !to_stdout && !testing && if( !to_stdout && !testing &&
( filenames_given || default_output_filename[0] ) ) ( filenames_given || default_output_filename[0] ) )
set_signals(); set_signals();
@ -547,7 +643,7 @@ int main( const int argc, const char * const argv[] )
else else
{ {
input_filename = filenames[i]; input_filename = filenames[i];
infd = open_instream( input_filename, &in_stats, testing, to_stdout ); infd = open_instream( input_filename, &in_stats, to_stdout || testing );
if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; } if( infd < 0 ) { if( retval < 1 ) retval = 1; continue; }
if( !testing ) if( !testing )
{ {
@ -576,7 +672,7 @@ int main( const int argc, const char * const argv[] )
delete_output_on_interrupt = true; delete_output_on_interrupt = true;
in_statsp = input_filename[0] ? &in_stats : 0; in_statsp = input_filename[0] ? &in_stats : 0;
Pp_set_name( &pp, input_filename ); Pp_set_name( &pp, input_filename );
tmp = decompress( infd, &pp, testing ); tmp = decompress( buffer_size, infd, &pp, testing );
if( tmp > retval ) retval = tmp; if( tmp > retval ) retval = tmp;
if( tmp && !testing ) cleanup_and_fail( retval ); if( tmp && !testing ) cleanup_and_fail( retval );

View file

@ -27,6 +27,12 @@ fail=0
printf "testing lunzip-%s..." "$2" printf "testing lunzip-%s..." "$2"
"${LZIP}" -cqu-1 "${in_lz}" > /dev/null
if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi
"${LZIP}" -cqu0 "${in_lz}" > /dev/null
if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi
"${LZIP}" -cqu4095 "${in_lz}" > /dev/null
if [ $? = 1 ] ; then printf . ; else fail=1 ; printf - ; fi
"${LZIP}" -tq in "${LZIP}" -tq in
if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi if [ $? = 2 ] ; then printf . ; else fail=1 ; printf - ; fi
"${LZIP}" -tq < in "${LZIP}" -tq < in
@ -45,11 +51,23 @@ if [ $? = 2 ] ; then printf . ; else printf - ; fail=1 ; fi
cmp in copy || fail=1 cmp in copy || fail=1
printf . printf .
cat "${in_lz}" > copy.lz || framework_failure
"${LZIP}" -df copy.lz || fail=1
cmp in copy || fail=1
printf .
printf "to be overwritten" > copy || framework_failure printf "to be overwritten" > copy || framework_failure
"${LZIP}" -df -o copy < "${in_lz}" || fail=1 "${LZIP}" -df -o copy < "${in_lz}" || fail=1
cmp in copy || fail=1 cmp in copy || fail=1
printf . printf .
for i in 12 4096 4Ki 29 512KiB ; do
printf "to be overwritten" > copy || framework_failure
"${LZIP}" -df -u$i -o copy < "${in_lz}" || fail=1
cmp in copy || fail=1
printf .
done
cat "${in_lz}" > anyothername || framework_failure cat "${in_lz}" > anyothername || framework_failure
"${LZIP}" -d anyothername || fail=1 "${LZIP}" -d anyothername || fail=1
cmp in anyothername.out || fail=1 cmp in anyothername.out || fail=1
@ -65,7 +83,7 @@ printf .
printf "garbage" >> copy2.lz || framework_failure printf "garbage" >> copy2.lz || framework_failure
printf "to be overwritten" > copy2 || framework_failure printf "to be overwritten" > copy2 || framework_failure
"${LZIP}" -dfk copy2.lz || fail=1 "${LZIP}" -df copy2.lz || fail=1
cmp in2 copy2 || fail=1 cmp in2 copy2 || fail=1
printf . printf .