diff options
Diffstat (limited to '')
-rw-r--r-- | main.cc | 146 |
1 files changed, 139 insertions, 7 deletions
@@ -134,6 +134,7 @@ void show_help() throw() // std::printf( " -d, --decompress decompress\n" ); // std::printf( " -f, --force overwrite existing output files\n" ); // std::printf( " -k, --keep keep (don't delete) input files\n" ); + std::printf( " -m, --magic=<type> output magic bytes for given file type\n" ); // std::printf( " -o, --output=<file> if reading stdin, place the output into <file>\n" ); std::printf( " -q, --quiet suppress all messages\n" ); std::printf( " -t, --test test compressed file type\n" ); @@ -492,6 +493,129 @@ int decompress( const int inhandle, const Pretty_print & pp ) } */ +unsigned char xdigit( const int value ) throw() + { + if( value >= 0 && value <= 9 ) return '0' + value; + if( value >= 10 && value <= 15 ) return 'A' + value - 10; + return 0; + } + + +int xtoi( const unsigned char ch ) throw() + { + switch( ch ) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'a': + case 'A': return 0x0A; + case 'b': + case 'B': return 0x0B; + case 'c': + case 'C': return 0x0C; + case 'd': + case 'D': return 0x0D; + case 'e': + case 'E': return 0x0E; + case 'f': + case 'F': return 0x0F; + default: return -1; + } + } + + +bool hex_to_data( const std::string & hex, std::string & data ) + { + data.clear(); + if( hex.size() == 0 || hex.size() % 2 != 0 ) return false; + for( unsigned int i = 0; 2 * i + 1 < hex.size(); ++i ) + { + int uch = xtoi( hex[2*i] ); + int lch = xtoi( hex[2*i+1] ); + if( uch < 0 || lch < 0 ) return false; + data.push_back( ( uch << 4 ) | lch ); + } + return true; + } + + +int print_magic_type( const std::string & magic_type ) + { + std::string data; + + if( magic_type == "gzip" ) std::printf( "\x1F\x8B" ); + else if( magic_type == "bzip2" ) std::printf( "BZh" ); + else if( magic_type == "lzip" ) std::printf( "LZIP" ); + else if( magic_type == "xz" ) std::printf( "%c7zXZ", '\xFD' ); + else if( hex_to_data( magic_type, data ) ) std::printf( data.c_str() ); + else return 1; + return 0; + } + + +int test_stdin_type( const int inhandle, const Pretty_print & pp ) + { + unsigned char buf[5]; + const char * msg = 0; + int i = 0; + if( readblock( inhandle, (char *)buf, 1 ) == 1 ) + { + if( buf[0] == 0x1F ) + { + if( readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 0x8B ) + msg = "gzip"; + } + else if( buf[0] == 'B' ) + { + if( readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'Z' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'h' ) + msg = "bzip2"; + } + else if( buf[0] == 'L' ) + { + if( readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'Z' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'I' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'P' ) + msg = "lzip"; + } + else if( buf[0] == 0xFD ) + { + if( readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == '7' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'z' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'X' && + readblock( inhandle, (char *)&buf[++i], 1 ) == 1 && buf[i] == 'Z' ) + msg = "xz"; + } + } + const int retval = ( msg ? 0 : 1 ); + if( verbosity >= 0 ) + { + if( verbosity >= 1 ) pp(); + if( !msg ) + { + char hexmsg[(2*sizeof buf)+1]; + for( int j = 0; j <= i; ++j ) + { + hexmsg[2*j] = xdigit( buf[j] >> 4 ); + hexmsg[2*j+1] = xdigit( buf[j] & 0x0F ); + } + hexmsg[2*i+2] = 0; + msg = hexmsg; + } + std::printf( "%s\n", msg ); + } + return retval; + } + + int test_type( const int inhandle, const Pretty_print & pp ) { unsigned char buf[5]; @@ -505,7 +629,7 @@ int test_type( const int inhandle, const Pretty_print & pp ) msg = "bzip2"; else if( buf[0] == 'L' && buf[1] == 'Z' && buf[2] == 'I' && buf[3] == 'P' ) msg = "lzip"; - else if( buf[1] == '7' && buf[2] == 'z' && buf[3] == 'X' && buf[4] == 'Z' ) + else if( buf[0] == 0xFD && buf[1] == '7' && buf[2] == 'z' && buf[3] == 'X' && buf[4] == 'Z' ) msg = "xz"; } const int retval = ( msg ? 0 : 1 ); @@ -546,6 +670,7 @@ int main( const int argc, const char * argv[] ) std::string input_filename; std::string default_output_filename; std::vector< std::string > filenames; + std::string magic_type; invocation_name = argv[0]; const Arg_parser::Option options[] = @@ -555,6 +680,7 @@ int main( const int argc, const char * argv[] ) { 'f', "force", Arg_parser::no }, { 'h', "help", Arg_parser::no }, { 'k', "keep", Arg_parser::no }, + { 'm', "magic", Arg_parser::yes }, { 'o', "output", Arg_parser::yes }, { 'q', "quiet", Arg_parser::no }, { 't', "test", Arg_parser::no }, @@ -571,7 +697,7 @@ int main( const int argc, const char * argv[] ) { const int code = parser.code( argind ); if( !code ) break; // no more options - const char * arg = parser.argument( argind ).c_str(); + const std::string & arg = parser.argument( argind ); switch( code ) { case 'c': to_stdout = true; break; @@ -579,6 +705,7 @@ int main( const int argc, const char * argv[] ) case 'f': force = true; break; case 'h': show_help(); return 0; case 'k': keep_input_files = true; break; + case 'm': magic_type = arg; break; case 'o': default_output_filename = arg; break; case 'q': verbosity = -1; break; case 't': program_mode = m_test; break; @@ -588,6 +715,8 @@ int main( const int argc, const char * argv[] ) } } + if( magic_type.size() ) return print_magic_type( magic_type ); + bool filenames_given = false; for( ; argind < parser.arguments(); ++argind ) { @@ -669,19 +798,22 @@ int main( const int argc, const char * argv[] ) case m_decompress: /*tmp = decompress( inhandle, pp );*/ break; case m_test: - tmp = test_type( inhandle, pp ); break; + if( inhandle == STDIN_FILENO ) + tmp = test_stdin_type( inhandle, pp ); + else tmp = test_type( inhandle, pp ); + break; } 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 ); + +// if( delete_output_on_interrupt ) +// close_and_set_permissions( in_statsp, &retval ); if( input_filename.size() ) { close( inhandle ); inhandle = -1; if( !keep_input_files && !to_stdout && program_mode != m_test ) std::remove( input_filename.c_str() ); - }*/ + } } if( outhandle >= 0 ) close( outhandle ); return retval; |