summaryrefslogtreecommitdiffstats
path: root/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'main.cc')
-rw-r--r--main.cc226
1 files changed, 79 insertions, 147 deletions
diff --git a/main.cc b/main.cc
index dd1fb27..6b5c430 100644
--- a/main.cc
+++ b/main.cc
@@ -1,5 +1,5 @@
/* Lzip - LZMA lossless data compressor
- Copyright (C) 2008-2014 Antonio Diaz Diaz.
+ Copyright (C) 2008-2015 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
@@ -56,6 +56,7 @@
#include "arg_parser.h"
#include "lzip.h"
#include "decoder.h"
+#include "encoder_base.h"
#include "encoder.h"
#include "fast_encoder.h"
@@ -72,7 +73,7 @@ namespace {
const char * const Program_name = "Lzip";
const char * const program_name = "lzip";
-const char * const program_year = "2014";
+const char * const program_year = "2015";
const char * invocation_name = 0;
struct { const char * from; const char * to; } const known_extensions[] = {
@@ -82,8 +83,8 @@ struct { const char * from; const char * to; } const known_extensions[] = {
struct Lzma_options
{
- int dictionary_size; // 4 KiB .. 512 MiB
- int match_len_limit; // 5 .. 273
+ int dictionary_size; /* 4 KiB .. 512 MiB */
+ int match_len_limit; /* 5 .. 273 */
};
enum Mode { m_compress, m_decompress, m_test };
@@ -126,8 +127,7 @@ void show_help()
"The bidimensional parameter space of LZMA can't be mapped to a linear\n"
"scale optimal for all files. If your files are large, very repetitive,\n"
"etc, you may need to use the --match-length and --dictionary-size\n"
- "options directly to achieve optimal performance. For example, -9m64\n"
- "usually compresses executables more (and faster) than -9.\n"
+ "options directly to achieve optimal performance.\n"
"\nExit status: 0 for a normal exit, 1 for environmental problems (file\n"
"not found, invalid flags, I/O errors, etc), 2 to indicate a corrupt or\n"
"invalid input file, 3 for an internal consistency error (eg, bug) which\n"
@@ -149,20 +149,23 @@ void show_version()
void show_header( const File_header & header )
{
- const char * const prefix[8] =
- { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
- enum { factor = 1024 };
- const char * p = "";
- const char * np = " ";
- unsigned num = header.dictionary_size();
- bool exact = ( num % factor == 0 );
-
- for( int i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i )
- { num /= factor; if( num % factor != 0 ) exact = false;
- p = prefix[i]; np = ""; }
- if( verbosity >= 4 && header.version() != 1 )
- std::fprintf( stderr, "version %d, ", header.version() );
- std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
+ if( verbosity >= 3 )
+ {
+ const char * const prefix[8] =
+ { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
+ enum { factor = 1024 };
+ const char * p = "";
+ const char * np = " ";
+ unsigned num = header.dictionary_size();
+ bool exact = ( num % factor == 0 );
+
+ for( int i = 0; i < 8 && ( num > 9999 || ( exact && num >= factor ) ); ++i )
+ { num /= factor; if( num % factor != 0 ) exact = false;
+ p = prefix[i]; np = ""; }
+ if( verbosity >= 4 && header.version() != 1 )
+ std::fprintf( stderr, "version %d, ", header.version() );
+ std::fprintf( stderr, "dictionary size %s%4u %sB. ", np, num, p );
+ }
}
@@ -337,7 +340,7 @@ bool open_outstream( const bool force )
bool check_tty( const int infd, const Mode program_mode )
{
- if( program_mode == m_compress && outfd >= 0 && isatty( outfd ) )
+ if( program_mode == m_compress && isatty( outfd ) )
{
show_error( "I won't write compressed data to a terminal.", 0, true );
return false;
@@ -368,14 +371,14 @@ void cleanup_and_fail( const int retval )
}
- // Set permissions, owner and times.
+ /* Set permissions, owner and times. */
void close_and_set_permissions( const struct stat * const in_statsp )
{
bool warning = false;
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( fchmod( outfd, mode ) != 0 ) warning = true; }
else
@@ -400,9 +403,9 @@ void close_and_set_permissions( const struct stat * const in_statsp )
bool next_filename()
{
- const unsigned len = std::strlen( known_extensions[0].from );
- if( output_filename.size() >= len + 5 ) // "*00001.lz"
- for( int i = output_filename.size() - len - 1, j = 0; j < 5; --i, ++j )
+ const unsigned ext_len = std::strlen( known_extensions[0].from );
+ if( output_filename.size() >= ext_len + 5 ) // "*00001.lz"
+ for( int i = output_filename.size() - ext_len - 1, j = 0; j < 5; --i, ++j )
{
if( output_filename[i] < '9' ) { ++output_filename[i]; return true; }
else output_filename[i] = '0';
@@ -412,114 +415,44 @@ bool next_filename()
int compress( const unsigned long long member_size,
- const unsigned long long volume_size,
- const Lzma_options & encoder_options, const int infd,
- const Pretty_print & pp, const struct stat * const in_statsp )
+ const unsigned long long volume_size, const int infd,
+ const Lzma_options & encoder_options, const Pretty_print & pp,
+ const struct stat * const in_statsp, const bool zero )
{
const unsigned long long cfile_size =
(in_statsp && S_ISREG( in_statsp->st_mode )) ? in_statsp->st_size / 100 : 0;
int retval = 0;
- File_header header;
- header.set_magic();
-
+ LZ_encoder_base * encoder = 0; // polymorphic encoder
if( verbosity >= 1 ) pp();
- if( !header.dictionary_size( encoder_options.dictionary_size ) ||
- encoder_options.match_len_limit < min_match_len_limit ||
- encoder_options.match_len_limit > max_match_len )
- internal_error( "invalid argument to encoder." );
try {
- Matchfinder matchfinder( header.dictionary_size(),
- encoder_options.match_len_limit, infd );
- header.dictionary_size( matchfinder.dictionary_size() );
-
- unsigned long long in_size = 0, out_size = 0, partial_volume_size = 0;
- while( true ) // encode one member per iteration
- {
- LZ_encoder encoder( matchfinder, header, outfd );
- const unsigned long long size = ( volume_size > 0 ) ?
- std::min( member_size, volume_size - partial_volume_size ) : member_size;
- if( verbosity >= 2 )
- show_progress( in_size, &matchfinder, &pp, cfile_size ); // init
- if( !encoder.encode_member( size ) )
- { pp( "Encoder error." ); retval = 1; break; }
- in_size += matchfinder.data_position();
- out_size += encoder.member_position();
- if( matchfinder.finished() ) break;
- if( volume_size > 0 )
- {
- partial_volume_size += encoder.member_position();
- if( partial_volume_size >= volume_size - min_dictionary_size )
- {
- partial_volume_size = 0;
- if( delete_output_on_interrupt )
- {
- close_and_set_permissions( in_statsp );
- if( !next_filename() )
- { pp( "Too many volume files." ); retval = 1; break; }
- if( !open_outstream( true ) ) { retval = 1; break; }
- delete_output_on_interrupt = true;
- }
- }
- }
- matchfinder.reset();
- }
-
- if( retval == 0 && verbosity >= 1 )
+ if( zero )
+ encoder = new FLZ_encoder( infd, outfd );
+ else
{
- if( in_size == 0 || out_size == 0 )
- std::fprintf( stderr, " no data compressed.\n" );
- else
- std::fprintf( stderr, "%6.3f:1, %6.3f bits/byte, "
- "%5.2f%% saved, %llu in, %llu out.\n",
- (double)in_size / out_size,
- ( 8.0 * out_size ) / in_size,
- 100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
- in_size, out_size );
+ File_header header;
+ if( !header.dictionary_size( encoder_options.dictionary_size ) ||
+ encoder_options.match_len_limit < min_match_len_limit ||
+ encoder_options.match_len_limit > max_match_len )
+ internal_error( "invalid argument to encoder." );
+ encoder = new LZ_encoder( header.dictionary_size(),
+ encoder_options.match_len_limit, infd, outfd );
}
- }
- catch( std::bad_alloc )
- {
- pp( "Not enough memory. Try a smaller dictionary size." );
- retval = 1;
- }
- catch( Error e ) { pp(); show_error( e.msg, errno ); retval = 1; }
- return retval;
- }
-
-
-int fcompress( const unsigned long long member_size,
- const unsigned long long volume_size, const int infd,
- const Pretty_print & pp, const struct stat * const in_statsp )
- {
- const unsigned long long cfile_size =
- (in_statsp && S_ISREG( in_statsp->st_mode )) ? in_statsp->st_size / 100 : 0;
- int retval = 0;
- File_header header;
- header.set_magic();
- if( verbosity >= 1 ) pp();
-
- try {
- Fmatchfinder fmatchfinder( infd );
- if( !header.dictionary_size( fmatchfinder.dictionary_size() ) )
- internal_error( "invalid argument to encoder." );
unsigned long long in_size = 0, out_size = 0, partial_volume_size = 0;
- while( true ) // encode one member per iteration
+ while( true ) /* encode one member per iteration */
{
- FLZ_encoder encoder( fmatchfinder, header, outfd );
const unsigned long long size = ( volume_size > 0 ) ?
std::min( member_size, volume_size - partial_volume_size ) : member_size;
- if( verbosity >= 2 )
- show_progress( in_size, &fmatchfinder, &pp, cfile_size ); // init
- if( !encoder.encode_member( size ) )
+ show_progress( in_size, encoder, &pp, cfile_size ); // init
+ if( !encoder->encode_member( size ) )
{ pp( "Encoder error." ); retval = 1; break; }
- in_size += fmatchfinder.data_position();
- out_size += encoder.member_position();
- if( fmatchfinder.finished() ) break;
+ in_size += encoder->data_position();
+ out_size += encoder->member_position();
+ if( encoder->data_finished() ) break;
if( volume_size > 0 )
{
- partial_volume_size += encoder.member_position();
+ partial_volume_size += encoder->member_position();
if( partial_volume_size >= volume_size - min_dictionary_size )
{
partial_volume_size = 0;
@@ -533,7 +466,7 @@ int fcompress( const unsigned long long member_size,
}
}
}
- fmatchfinder.reset();
+ encoder->reset();
}
if( retval == 0 && verbosity >= 1 )
@@ -555,6 +488,7 @@ int fcompress( const unsigned long long member_size,
retval = 1;
}
catch( Error e ) { pp(); show_error( e.msg, errno ); retval = 1; }
+ delete encoder;
return retval;
}
@@ -637,7 +571,7 @@ int decompress( const int infd, const Pretty_print & pp, const bool testing )
{ pp( "Invalid dictionary size in member header." ); retval = 2; break; }
if( verbosity >= 2 || ( verbosity == 1 && first_member ) )
- { pp(); if( verbosity >= 3 ) show_header( header ); }
+ { pp(); show_header( header ); }
LZ_decoder decoder( header, rdec, outfd );
const int result = decoder.decode_member( pp );
@@ -719,20 +653,23 @@ void show_progress( const unsigned long long partial_size,
const Pretty_print * const p,
const unsigned long long cfile_size )
{
- static unsigned long long csize = 0; // file_size / 100
+ static unsigned long long csize = 0; /* file_size / 100 */
static unsigned long long psize = 0;
static const Matchfinder_base * mb = 0;
static const Pretty_print * pp = 0;
- if( m ) // initialize static vars
- { csize = cfile_size; psize = partial_size; mb = m; pp = p; }
- if( mb && pp )
+ if( verbosity >= 2 )
{
- const unsigned long long pos = psize + mb->data_position();
- if( csize > 0 )
- std::fprintf( stderr, "%4llu%%", pos / csize );
- std::fprintf( stderr, " %.1f MB\r", pos / 1000000.0 );
- pp->reset(); (*pp)(); // restore cursor position
+ if( m ) /* initialize static vars */
+ { csize = cfile_size; psize = partial_size; mb = m; pp = p; }
+ if( mb && pp )
+ {
+ const unsigned long long pos = psize + mb->data_position();
+ if( csize > 0 )
+ std::fprintf( stderr, "%4llu%%", pos / csize );
+ std::fprintf( stderr, " %.1f MB\r", pos / 1000000.0 );
+ pp->reset(); (*pp)(); // restore cursor position
+ }
}
}
@@ -743,16 +680,16 @@ int main( const int argc, const char * const argv[] )
to the corresponding LZMA compression modes. */
const Lzma_options option_mapping[] =
{
- { 1 << 16, 16 }, // -0 entry values not used
- { 1 << 20, 5 }, // -1
- { 3 << 19, 6 }, // -2
- { 1 << 21, 8 }, // -3
- { 3 << 20, 12 }, // -4
- { 1 << 22, 20 }, // -5
- { 1 << 23, 36 }, // -6
- { 1 << 24, 68 }, // -7
- { 3 << 23, 132 }, // -8
- { 1 << 25, 273 } }; // -9
+ { 1 << 16, 16 }, /* -0 entry values not used */
+ { 1 << 20, 5 }, /* -1 */
+ { 3 << 19, 6 }, /* -2 */
+ { 1 << 21, 8 }, /* -3 */
+ { 3 << 20, 12 }, /* -4 */
+ { 1 << 22, 20 }, /* -5 */
+ { 1 << 23, 36 }, /* -6 */
+ { 1 << 24, 68 }, /* -7 */
+ { 3 << 23, 132 }, /* -8 */
+ { 1 << 25, 273 } }; /* -9 */
Lzma_options encoder_options = option_mapping[6]; // default = "-6"
const unsigned long long max_member_size = 0x0100000000000000ULL;
const unsigned long long max_volume_size = 0x4000000000000000ULL;
@@ -808,7 +745,7 @@ int main( const int argc, const char * const argv[] )
for( ; argind < parser.arguments(); ++argind )
{
const int code = parser.code( argind );
- if( !code ) break; // no more options
+ if( !code ) break; /* no more options */
const char * const arg = parser.argument( argind ).c_str();
switch( code )
{
@@ -837,7 +774,7 @@ int main( const int argc, const char * const argv[] )
case 'V': show_version(); return 0;
default : internal_error( "uncaught option." );
}
- } // end process options
+ } /* end process options */
#if defined(__MSVCRT__) || defined(__OS2__)
setmode( STDIN_FILENO, O_BINARY );
@@ -929,13 +866,8 @@ int main( const int argc, const char * const argv[] )
pp.set_name( input_filename );
int tmp;
if( program_mode == m_compress )
- {
- if( zero )
- tmp = fcompress( member_size, volume_size, infd, pp, in_statsp );
- else
- tmp = compress( member_size, volume_size, encoder_options, infd,
- pp, in_statsp );
- }
+ tmp = compress( member_size, volume_size, infd, encoder_options, pp,
+ in_statsp, zero );
else
tmp = decompress( infd, pp, program_mode == m_test );
if( tmp > retval ) retval = tmp;