1
/* Lzip - Data compressor based on the LZMA algorithm
2
Copyright (C) 2008, 2009, 2010, 2011 Antonio Diaz Diaz.
4
This program is free software: you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation, either version 3 of the License, or
7
(at your option) any later version.
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program. If not, see <http://www.gnu.org/licenses/>.
18
Return values: 0 for a normal exit, 1 for environmental problems
19
(file not found, invalid flags, I/O errors, etc), 2 to indicate a
20
corrupt or invalid input file, 3 for an internal consistency error
21
(eg, bug) which caused lzip to panic.
24
#define _FILE_OFFSET_BITS 64
36
#if defined(__MSVCRT__)
39
#define fchown(x,y,z) 0
40
#define SIGHUP SIGTERM
56
#include "fast_encoder.h"
60
#error "Environments where CHAR_BIT != 8 are not supported."
64
#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
67
#define LLONG_MIN (-LLONG_MAX - 1LL)
70
#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL
74
void pp(const char *p) { if (p) fputs(p, stderr); }
78
const char * const Program_name = "Lzip";
79
const char * const program_name = "lzip";
80
const char * const program_year = "2011";
81
const char * invocation_name = 0;
84
const int o_binary = O_BINARY;
86
const int o_binary = 0;
89
struct { const char * from; const char * to; } const known_extensions[] = {
96
int dictionary_size; // 4KiB..512MiB
97
int match_len_limit; // 5..273
100
enum Mode { m_compress, m_decompress, m_test };
104
bool delete_output_on_interrupt = false;
109
printf( "%s - Data compressor based on the LZMA algorithm.\n", Program_name );
110
printf( "<< Most of these are unsupported. Compressing/decompressing from stdin to stdout is the right way! >>\n" );
111
printf( "\nUsage: %s [options] [files]\n", invocation_name );
112
printf( "\nOptions:\n" );
113
printf( " -h, --help display this help and exit\n" );
114
printf( " -V, --version output version information and exit\n" );
115
printf( " -b, --member-size=<n> set member size limit in bytes\n" );
116
printf( " -c, --stdout send output to standard output\n" );
117
printf( " -d, --decompress decompress\n" );
118
printf( " -f, --force overwrite existing output files\n" );
119
printf( " -F, --recompress force recompression of compressed files\n" );
120
printf( " -k, --keep keep (don't delete) input files\n" );
121
printf( " -m, --match-length=<n> set match length limit in bytes [36]\n" );
122
printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" );
123
printf( " -q, --quiet suppress all messages\n" );
124
printf( " -s, --dictionary-size=<n> set dictionary size limit in bytes [8MiB]\n" );
125
printf( " -S, --volume-size=<n> set volume size limit in bytes\n" );
126
printf( " -t, --test test compressed file integrity\n" );
127
printf( " -v, --verbose be verbose (a 2nd -v gives more)\n" );
128
printf( " -0 .. -9 set compression level [default 6]\n" );
129
printf( " --fast alias for -0\n" );
130
printf( " --best alias for -9\n" );
131
printf( "If no file names are given, %s compresses or decompresses\n", program_name );
132
printf( "from standard input to standard output.\n" );
133
printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" );
134
printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
135
printf( "\nReport bugs to lzip-bug@nongnu.org\n" );
136
printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
142
printf( "%s %s\n", Program_name, PROGVERSION );
143
printf( "Copyright (C) %s Antonio Diaz Diaz.\n", program_year );
144
printf( "License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" );
145
printf( "This is free software: you are free to change and redistribute it.\n" );
146
printf( "There is NO WARRANTY, to the extent permitted by law.\n" );
150
const char * format_num( long long num )
152
const char * const prefix[8] =
153
{ "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
154
enum { buf_size = 16, factor = 1024 };
155
static char buf[buf_size];
158
for( int i = 0; i < 8 && ( llabs( num ) > 9999 ||
159
( llabs( num ) >= factor && num % factor == 0 ) ); ++i )
160
{ num /= factor; p = prefix[i]; }
161
snprintf( buf, buf_size, "%lld %s", num, p );
166
bool open_outstream( const bool force )
172
bool check_tty( const int infd, const Mode program_mode )
174
if( program_mode == m_compress && outfd >= 0 && isatty( outfd ) )
176
show_error( "I won't write compressed data to a terminal.", 0, true );
179
if( ( program_mode == m_decompress || program_mode == m_test ) &&
182
show_error( "I won't read compressed data from a terminal.", 0, true );
189
void cleanup_and_fail( const int retval )
195
// Set permissions, owner and times.
196
void close_and_set_permissions( const struct stat * const in_statsp )
201
if( ( fchown( outfd, in_statsp->st_uid, in_statsp->st_gid ) != 0 &&
203
fchmod( outfd, in_statsp->st_mode ) != 0 )
205
// fchown will in many cases return with EPERM, which can be safely ignored.
207
if( close( outfd ) == 0 ) outfd = -1;
208
else cleanup_and_fail( 1 );
209
delete_output_on_interrupt = false;
210
if( !in_statsp ) return;
214
t.actime = in_statsp->st_atime;
215
t.modtime = in_statsp->st_mtime;
216
//if( utime( output_filename.c_str(), &t ) != 0 ) error = true;
220
show_error( "Can't change output file attributes." );
221
cleanup_and_fail( 1 );
232
int compress( const long long member_size, const long long volume_size,
233
const Lzma_options & encoder_options, const int infd,
234
const struct stat * const in_statsp )
238
if( !header.dictionary_size( encoder_options.dictionary_size ) ||
239
encoder_options.match_len_limit < min_match_len_limit ||
240
encoder_options.match_len_limit > max_match_len )
241
internal_error( "invalid argument to encoder" );
244
Matchfinder matchfinder( header.dictionary_size(),
245
encoder_options.match_len_limit, infd );
246
header.dictionary_size( matchfinder.dictionary_size() );
248
long long in_size = 0, out_size = 0, partial_volume_size = 0;
249
while( true ) // encode one member per iteration
251
LZ_encoder encoder( matchfinder, header, outfd );
252
const long long size =
253
min( member_size, volume_size - partial_volume_size );
254
if( !encoder.encode_member( size ) )
255
{ pp( "Encoder error" ); retval = 1; break; }
256
in_size += matchfinder.data_position();
257
out_size += encoder.member_position();
258
if( matchfinder.finished() ) break;
259
partial_volume_size += encoder.member_position();
260
if( partial_volume_size >= volume_size - min_dictionary_size )
262
partial_volume_size = 0;
263
if( delete_output_on_interrupt )
265
close_and_set_permissions( in_statsp );
266
if( !next_filename() )
267
{ pp( "Too many volume files" ); retval = 1; break; }
268
if( !open_outstream( true ) ) { retval = 1; break; }
269
delete_output_on_interrupt = true;
275
if( retval == 0 && verbosity >= 1 )
277
if( in_size <= 0 || out_size <= 0 )
278
fprintf( stderr, "No data compressed.\n" );
280
fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
281
"%5.2f%% saved, %lld in, %lld out.\n",
282
(double)in_size / out_size,
283
( 8.0 * out_size ) / in_size,
284
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
291
int fcompress( const long long member_size, const long long volume_size,
293
const struct stat * const in_statsp )
295
if( verbosity >= 1 ) pp();
300
Fmatchfinder fmatchfinder( infd );
301
header.dictionary_size( fmatchfinder.dictionary_size() );
303
long long in_size = 0, out_size = 0, partial_volume_size = 0;
304
while( true ) // encode one member per iteration
306
FLZ_encoder encoder( fmatchfinder, header, outfd );
307
const long long size =
308
min( member_size, volume_size - partial_volume_size );
309
if( !encoder.encode_member( size ) )
310
{ pp( "Encoder error" ); retval = 1; break; }
311
in_size += fmatchfinder.data_position();
312
out_size += encoder.member_position();
313
if( fmatchfinder.finished() ) break;
314
partial_volume_size += encoder.member_position();
315
if( partial_volume_size >= volume_size - min_dictionary_size )
317
partial_volume_size = 0;
318
if( delete_output_on_interrupt )
320
close_and_set_permissions( in_statsp );
321
if( !next_filename() )
322
{ pp( "Too many volume files" ); retval = 1; break; }
323
if( !open_outstream( true ) ) { retval = 1; break; }
324
delete_output_on_interrupt = true;
327
fmatchfinder.reset();
330
if( retval == 0 && verbosity >= 1 )
332
if( in_size <= 0 || out_size <= 0 )
333
fprintf( stderr, "No data compressed.\n" );
335
fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
336
"%5.2f%% saved, %lld in, %lld out.\n",
337
(double)in_size / out_size,
338
( 8.0 * out_size ) / in_size,
339
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
346
int decompress( const int infd, const bool testing )
350
Range_decoder rdec( infd );
351
long long partial_file_pos = 0;
352
for( bool first_member = true; ; first_member = false )
356
rdec.reset_member_position();
357
for( size = 0; size < File_header::size && !rdec.finished(); ++size )
358
header.data[size] = rdec.get_byte();
359
if( rdec.finished() ) // End Of File
362
{ pp( "Error reading member header" ); retval = 1; }
365
if( !header.verify_magic() )
368
{ pp( "Bad magic number (file not in lzip format)" ); retval = 2; }
371
if( !header.verify_version() )
375
fprintf( stderr, "Version %d member format not supported.\n",
376
header.version() ); }
379
if( header.dictionary_size() < min_dictionary_size ||
380
header.dictionary_size() > max_dictionary_size )
381
{ pp( "Invalid dictionary size in member header" ); retval = 2; break; }
383
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
387
fprintf( stderr, "version %d, dictionary size %7sB. ",
389
format_num( header.dictionary_size() ) );
391
LZ_decoder decoder( header, rdec, outfd );
393
const int result = decoder.decode_member();
394
partial_file_pos += rdec.member_position();
397
if( verbosity >= 0 && result <= 2 )
401
fprintf( stderr, "File ends unexpectedly at pos %lld\n",
404
fprintf( stderr, "Decoder error at pos %lld\n",
410
{ if( testing ) fprintf( stderr, "ok\n" );
411
else fprintf( stderr, "done\n" ); }
413
if( verbosity == 1 && retval == 0 )
414
{ if( testing ) fprintf( stderr, "ok\n" );
415
else fprintf( stderr, "done\n" ); }
423
void show_error( const char * const msg, const int errcode, const bool help )
429
fprintf( stderr, "%s: %s", program_name, msg );
431
fprintf( stderr, ": %s", strerror( errcode ) );
432
fprintf( stderr, "\n" );
434
if( help && invocation_name && invocation_name[0] )
435
fprintf( stderr, "Try `%s --help' for more information.\n",
441
void internal_error( const char * const msg )
444
fprintf( stderr, "%s: internal error: %s.\n", program_name, msg );
449
int main( const int argc, const char * const argv[] )
451
// Mapping from gzip/bzip2 style 1..9 compression modes
452
// to the corresponding LZMA compression modes.
453
const Lzma_options option_mapping[] =
455
{ 1 << 16, 16 }, // -0 entry values not used
456
{ 1 << 20, 5 }, // -1
457
{ 3 << 19, 6 }, // -2
458
{ 1 << 21, 8 }, // -3
459
{ 3 << 20, 12 }, // -4
460
{ 1 << 22, 20 }, // -5
461
{ 1 << 23, 36 }, // -6
462
{ 1 << 24, 68 }, // -7
463
{ 3 << 23, 132 }, // -8
464
{ 1 << 25, 273 } }; // -9
465
Lzma_options encoder_options = option_mapping[6]; // default = "-6"
466
long long member_size = LLONG_MAX;
467
long long volume_size = LLONG_MAX;
469
Mode program_mode = m_compress;
470
bool keep_input_files = false;
471
bool to_stdout = false;
473
invocation_name = argv[0];
475
// Greatly simplified argument parsing
477
for( ; argind < argc; ++argind )
479
const int code = argv[argind][1];
482
case 'c': to_stdout = true; break;
483
case 'd': program_mode = m_decompress; break;
484
case 'h': show_help(); return 0;
485
case 'k': keep_input_files = true; break;
486
case 'q': verbosity = -1; break;
488
case 'v': if( verbosity < 4 ) ++verbosity; break;
489
case 'V': show_version(); return 0;
490
default : internal_error( "uncaught option" );
492
} // end process options
494
#if defined(__MSVCRT__) || defined(__OS2__)
495
_setmode( STDIN_FILENO, O_BINARY );
496
_setmode( STDOUT_FILENO, O_BINARY );
499
if( program_mode == m_test )
502
else if( program_mode == m_compress )
511
struct stat in_stats;
514
outfd = STDOUT_FILENO;
516
if( !check_tty( infd, program_mode ) ) return 1;
518
const struct stat * const in_statsp = 0;
519
//pp.set_name( "-" );
522
if( program_mode == m_compress )
525
tmp = fcompress( member_size, volume_size, infd, in_statsp );
527
tmp = compress( member_size, volume_size, encoder_options, infd,
532
tmp = decompress( infd, program_mode == m_test );
533
if( tmp > retval ) retval = tmp;
534
//if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
536
if( delete_output_on_interrupt )
537
close_and_set_permissions( in_statsp );
539
if( outfd >= 0 && close( outfd ) != 0 )
541
show_error( "Can't close stdout", errno );
542
if( retval < 1 ) retval = 1;