diff options
Diffstat (limited to '')
-rw-r--r-- | main.cc | 226 |
1 files changed, 79 insertions, 147 deletions
@@ -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; |