summaryrefslogtreecommitdiffstats
path: root/main.cc
diff options
context:
space:
mode:
Diffstat (limited to 'main.cc')
-rw-r--r--main.cc146
1 files changed, 139 insertions, 7 deletions
diff --git a/main.cc b/main.cc
index 961c1e1..828ac06 100644
--- a/main.cc
+++ b/main.cc
@@ -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;