summaryrefslogtreecommitdiffstats
path: root/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'main.cc')
-rw-r--r--main.cc219
1 files changed, 117 insertions, 102 deletions
diff --git a/main.cc b/main.cc
index 7a415a9..f751c2a 100644
--- a/main.cc
+++ b/main.cc
@@ -1,5 +1,5 @@
/* Minilzip - A test program for the lzlib library
- Copyright (C) 2009 Antonio Diaz Diaz.
+ Copyright (C) 2009, 2010 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
@@ -63,7 +63,7 @@ namespace {
const char * invocation_name = 0;
const char * const Program_name = "Minilzip";
const char * const program_name = "minilzip";
-const char * const program_year = "2009";
+const char * const program_year = "2010";
struct { const char * from; const char * to; } const known_extensions[] = {
{ ".lz", "" },
@@ -145,7 +145,7 @@ void show_help() throw()
std::printf( "Numbers may be followed by a multiplier: k = kB = 10^3 = 1000,\n" );
std::printf( "Ki = KiB = 2^10 = 1024, M = 10^6, Mi = 2^20, G = 10^9, Gi = 2^30, etc...\n" );
std::printf( "\nReport bugs to lzip-bug@nongnu.org\n" );
- std::printf( "Lzip home page: http://www.nongnu.org/lzip/lzip.html\n" );
+ std::printf( "Lzlib home page: http://www.nongnu.org/lzip/lzlib.html\n" );
}
@@ -159,30 +159,6 @@ void show_version() throw()
}
-const char * format_num( long long num, long long limit = 9999,
- const int set_prefix = 0 ) throw()
- {
- const char * const si_prefix[8] =
- { "k", "M", "G", "T", "P", "E", "Z", "Y" };
- const char * const binary_prefix[8] =
- { "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi" };
- static bool si = false;
- static char buf[16];
-
- if( set_prefix ) si = ( set_prefix > 0 );
- const int factor = ( si ) ? 1000 : 1024;
- const char * const *prefix = ( si ) ? si_prefix : binary_prefix;
- const char *p = "";
- limit = std::max( 999LL, std::min( 999999LL, limit ) );
-
- for( int i = 0; i < 8 && ( llabs( num ) > limit ||
- ( llabs( num ) >= factor && num % factor == 0 ) ); ++i )
- { num /= factor; p = prefix[i]; }
- snprintf( buf, sizeof buf, "%lld %s", num, p );
- return buf;
- }
-
-
long long getnum( const char * ptr, const int bs = 0,
const long long llimit = LLONG_MIN + 1,
const long long ulimit = LLONG_MAX ) throw()
@@ -218,7 +194,7 @@ long long getnum( const char * ptr, const int bs = 0,
break;
case 'k': if( factor == 1000 ) exponent = 1; else bad_multiplier = true;
break;
- default: bad_multiplier = true;
+ default : bad_multiplier = true;
}
if( bad_multiplier )
{
@@ -245,9 +221,10 @@ int get_dict_size( const char * arg ) throw()
{
char *tail;
int bits = std::strtol( arg, &tail, 0 );
- if( bits >= min_dictionary_bits && bits <= max_dictionary_bits && *tail == 0 )
+ if( bits >= LZ_min_dictionary_bits() &&
+ bits <= LZ_max_dictionary_bits() && *tail == 0 )
return ( 1 << bits );
- return getnum( arg, 0, min_dictionary_size, max_dictionary_size );
+ return getnum( arg, 0, LZ_min_dictionary_size(), LZ_max_dictionary_size() );
}
@@ -390,31 +367,30 @@ void cleanup_and_fail( const int retval ) throw()
// Set permissions, owner and times.
-void close_and_set_permissions( const struct stat * in_statsp, int * retvalp )
+void close_and_set_permissions( const struct stat * const in_statsp )
{
- int tmp = 0;
+ bool error = false;
if( in_statsp )
{
- if( fchmod( outhandle, in_statsp->st_mode ) != 0 ) tmp = 1;
- if( !tmp ) (void)fchown( outhandle, in_statsp->st_uid, in_statsp->st_gid );
+ if( fchmod( outhandle, in_statsp->st_mode ) != 0 ) error = true;
+ else (void)fchown( outhandle, in_statsp->st_uid, in_statsp->st_gid );
// fchown will in many cases return with EPERM, which can be safely ignored.
}
if( close( outhandle ) == 0 ) outhandle = -1;
else cleanup_and_fail( 1 );
delete_output_on_interrupt = false;
if( !in_statsp ) return;
- if( !tmp )
+ if( !error )
{
struct utimbuf t;
t.actime = in_statsp->st_atime;
t.modtime = in_statsp->st_mtime;
- tmp = utime( output_filename.c_str(), &t );
+ if( utime( output_filename.c_str(), &t ) != 0 ) error = true;
}
- if( tmp )
+ if( error )
{
- if( tmp > *retvalp ) *retvalp = tmp;
show_error( "I can't change output file attributes." );
- cleanup_and_fail( *retvalp );
+ cleanup_and_fail( 1 );
}
}
@@ -432,58 +408,55 @@ bool next_filename()
}
-int compress( const long long member_size, const long long volume_size,
- lzma_options encoder_options, const int inhandle,
- const Pretty_print & pp, const struct stat * in_statsp,
- int * retvalp )
+int do_compress( LZ_Encoder * const encoder, const long long member_size,
+ const long long volume_size, const int inhandle,
+ const Pretty_print & pp, const struct stat * const in_statsp )
{
- if( verbosity >= 1 ) pp();
- void * encoder = LZ_compress_open( encoder_options.dictionary_size,
- encoder_options.match_len_limit,
- std::min( member_size, volume_size ) );
- if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
- {
- const bool mem_error = ( LZ_compress_errno( encoder ) == LZ_mem_error );
- LZ_compress_close( encoder );
- if( mem_error )
- { pp( "not enough memory. Try a smaller dictionary size" ); return 1; }
- internal_error( "invalid argument to encoder" );
- }
-
long long partial_volume_size = 0;
const int out_buffer_size = 65536, in_buffer_size = 8 * out_buffer_size;
uint8_t in_buffer[in_buffer_size], out_buffer[out_buffer_size];
+
+ if( verbosity >= 1 ) pp();
while( true )
{
int in_size = std::min( LZ_compress_write_size( encoder ), in_buffer_size );
if( in_size > 0 )
{
- in_size = readblock( inhandle, (char *)in_buffer, in_size );
+ const int max_in_size = in_size;
+ in_size = readblock( inhandle, (char *)in_buffer, max_in_size );
+ if( in_size != max_in_size && errno )
+ { pp(); show_error( "read error", errno ); return 1; }
if( in_size == 0 ) LZ_compress_finish( encoder );
else if( in_size != LZ_compress_write( encoder, in_buffer, in_size ) )
- internal_error( "library error" );
+ internal_error( "library error (LZ_compress_write)" );
}
int out_size = LZ_compress_read( encoder, out_buffer, out_buffer_size );
// std::fprintf( stderr, "%6d in_size, %5d out_size.\n", in_size, out_size );
if( out_size < 0 )
- { pp(); show_error( "read error", errno ); return 1; }
+ {
+ pp();
+ if( verbosity >= 0 )
+ std::fprintf( stderr, "LZ_compress_read error: %s.\n",
+ LZ_strerror( LZ_compress_errno( encoder ) ) );
+ return 1;
+ }
else if( out_size > 0 )
{
const int wr = writeblock( outhandle, (char *)out_buffer, out_size );
if( wr != out_size )
{ pp(); show_error( "write error", errno ); return 1; }
}
- else if( in_size == 0 ) internal_error( "library error" );
+ else if( in_size == 0 ) internal_error( "library error (LZ_compress_read)" );
if( LZ_compress_member_finished( encoder ) )
{
if( LZ_compress_finished( encoder ) == 1 ) break;
partial_volume_size += LZ_compress_member_position( encoder );
- if( partial_volume_size >= volume_size - min_dictionary_size )
+ if( partial_volume_size >= volume_size - LZ_min_dictionary_size() )
{
partial_volume_size = 0;
if( delete_output_on_interrupt )
{
- close_and_set_permissions( in_statsp, retvalp );
+ close_and_set_permissions( in_statsp );
if( !next_filename() )
{ pp(); show_error( "too many volume files" ); return 1; }
if( !open_outstream( true ) ) return 1;
@@ -493,7 +466,13 @@ int compress( const long long member_size, const long long volume_size,
const long long size =
std::min( member_size, volume_size - partial_volume_size );
if( LZ_compress_restart_member( encoder, size ) < 0 )
- { pp(); show_error( "read error", errno ); return 1; }
+ {
+ pp();
+ if( verbosity >= 0 )
+ std::fprintf( stderr, "LZ_compress_restart_member error: %s.\n",
+ LZ_strerror( LZ_compress_errno( encoder ) ) );
+ return 1;
+ }
}
}
@@ -511,51 +490,60 @@ int compress( const long long member_size, const long long volume_size,
100.0 * ( 1.0 - ( (double)out_size / in_size ) ),
in_size, out_size );
}
- LZ_compress_close( encoder );
return 0;
}
-int decompress( const int inhandle, const Pretty_print & pp,
- const bool testing )
+int compress( const long long member_size, const long long volume_size,
+ const lzma_options & encoder_options, const int inhandle,
+ const Pretty_print & pp, const struct stat * const in_statsp )
{
- void * decoder = LZ_decompress_open();
- if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
+ LZ_Encoder * const encoder =
+ LZ_compress_open( encoder_options.dictionary_size,
+ encoder_options.match_len_limit,
+ std::min( member_size, volume_size ) );
+ int retval;
+
+ if( !encoder || LZ_compress_errno( encoder ) != LZ_ok )
{
- LZ_decompress_close( decoder );
- pp( "not enough memory. Find a machine with more memory" );
- return 1;
+ if( LZ_compress_errno( encoder ) == LZ_mem_error )
+ pp( "not enough memory. Try a smaller dictionary size" );
+ else
+ internal_error( "invalid argument to encoder" );
+ retval = 1;
}
- if( verbosity >= 1 ) pp();
+ else retval = do_compress( encoder, member_size, volume_size,
+ inhandle, pp, in_statsp );
+ LZ_compress_close( encoder );
+ return retval;
+ }
+
+int do_decompress( LZ_Decoder * const decoder, const int inhandle,
+ const Pretty_print & pp, const bool testing )
+ {
const int in_buffer_size = 65536, out_buffer_size = 8 * in_buffer_size;
uint8_t in_buffer[in_buffer_size], out_buffer[out_buffer_size];
- int in_pos = 0, in_stream_pos = 0;
- bool finished = false;
+
+ if( verbosity >= 1 ) pp();
while( true )
{
- int in_size = 0;
- if( !finished )
+ int in_size = std::min( LZ_decompress_write_size( decoder ), in_buffer_size );
+ if( in_size > 0 )
{
- if( in_stream_pos == 0 )
- in_stream_pos = readblock( inhandle, (char *)in_buffer, in_buffer_size );
- if( in_pos < in_stream_pos )
- {
- in_size = LZ_decompress_write( decoder, in_buffer + in_pos, in_stream_pos - in_pos );
- in_pos += in_size;
- }
- if( in_pos >= in_stream_pos )
- {
- if( in_stream_pos < in_buffer_size )
- { finished = true; LZ_decompress_finish( decoder ); }
- in_stream_pos = 0; in_pos = 0;
- }
+ const int max_in_size = in_size;
+ in_size = readblock( inhandle, (char *)in_buffer, max_in_size );
+ if( in_size != max_in_size && errno )
+ { pp(); show_error( "read error", errno ); return 1; }
+ if( in_size == 0 ) LZ_decompress_finish( decoder );
+ else if( in_size != LZ_decompress_write( decoder, in_buffer, in_size ) )
+ internal_error( "library error (LZ_decompress_write)" );
}
int out_size = LZ_decompress_read( decoder, out_buffer, out_buffer_size );
// std::fprintf( stderr, "%5d in_size, %6d out_size.\n", in_size, out_size );
if( out_size < 0 )
{
- const LZ_errno lz_errno = LZ_decompress_errno( decoder );
+ const LZ_Errno lz_errno = LZ_decompress_errno( decoder );
if( lz_errno == LZ_header_error )
{
if( LZ_decompress_total_out_size( decoder ) > 0 )
@@ -568,15 +556,18 @@ int decompress( const int inhandle, const Pretty_print & pp,
pp( "not enough memory. Find a machine with more memory" );
return 1;
}
+ pp();
if( lz_errno == LZ_unexpected_eof )
{
if( verbosity >= 0 )
- { pp();
- std::fprintf( stderr, "file ends unexpectedly at pos %lld\n",
- LZ_decompress_total_in_size( decoder ) ); }
+ std::fprintf( stderr, "file ends unexpectedly at pos %lld\n",
+ LZ_decompress_total_in_size( decoder ) );
return 2;
}
- pp(); show_error( "read error", errno ); return 1;
+ if( verbosity >= 0 )
+ std::fprintf( stderr, "LZ_decompress_read error: %s.\n",
+ LZ_strerror( LZ_decompress_errno( decoder ) ) );
+ return 1;
}
else if( out_size > 0 && outhandle >= 0 )
{
@@ -585,17 +576,34 @@ int decompress( const int inhandle, const Pretty_print & pp,
{ pp(); show_error( "write error", errno ); return 1; }
}
if( LZ_decompress_finished( decoder ) == 1 ) break;
- if( finished && in_size == 0 && out_size == 0 )
- internal_error( "library error" );
+ if( in_size == 0 && out_size == 0 )
+ internal_error( "library error (LZ_decompress_read)" );
}
if( verbosity >= 1 )
{ if( testing ) std::fprintf( stderr, "ok\n" );
else std::fprintf( stderr, "done\n" ); }
- LZ_decompress_close( decoder );
return 0;
}
+int decompress( const int inhandle, const Pretty_print & pp,
+ const bool testing )
+ {
+ LZ_Decoder * const decoder = LZ_decompress_open();
+ int retval;
+
+ if( !decoder || LZ_decompress_errno( decoder ) != LZ_ok )
+ {
+ pp( "not enough memory. Find a machine with more memory" );
+ retval = 1;
+ }
+ else retval = do_decompress( decoder, inhandle, pp, testing );
+
+ LZ_decompress_close( decoder );
+ return retval;
+ }
+
+
extern "C" void signal_handler( int ) throw()
{
show_error( "Control-C or similar caught, quitting." );
@@ -775,7 +783,8 @@ int main( const int argc, const char * argv[] )
case 'h': show_help(); return 0;
case 'k': keep_input_files = true; break;
case 'm': encoder_options.match_len_limit =
- getnum( arg, 0, 5, 273 ); break;
+ getnum( arg, 0, LZ_min_match_len_limit(),
+ LZ_max_match_len_limit() ); break;
case 'o': default_output_filename = arg; break;
case 'q': verbosity = -1; break;
case 's': encoder_options.dictionary_size = get_dict_size( arg );
@@ -859,19 +868,19 @@ int main( const int argc, const char * argv[] )
if( output_filename.size() && !to_stdout && program_mode != m_test )
delete_output_on_interrupt = true;
- const struct stat * in_statsp = input_filename.size() ? &in_stats : 0;
+ const struct stat * const in_statsp = input_filename.size() ? &in_stats : 0;
pp.set_name( input_filename );
int tmp = 0;
if( program_mode == m_compress )
tmp = compress( member_size, volume_size, encoder_options, inhandle,
- pp, in_statsp, &retval );
+ pp, in_statsp );
else
tmp = decompress( inhandle, pp, program_mode == m_test );
if( tmp > retval ) retval = tmp;
if( tmp && program_mode != m_test ) cleanup_and_fail( retval );
if( delete_output_on_interrupt )
- close_and_set_permissions( in_statsp, &retval );
+ close_and_set_permissions( in_statsp );
if( input_filename.size() )
{
close( inhandle ); inhandle = -1;
@@ -879,6 +888,12 @@ int main( const int argc, const char * argv[] )
std::remove( input_filename.c_str() );
}
}
- if( outhandle >= 0 ) close( outhandle );
+ if( outhandle >= 0 && close( outhandle ) != 0 )
+ {
+ if( verbosity >= 0 )
+ std::fprintf( stderr, "%s: Can't close stdout: %s.\n",
+ program_name, std::strerror( errno ) );
+ if( retval < 1 ) retval = 1;
+ }
return retval;
}