#!/usr/bin/perl -w
#
# gettypes - read the image file 512 bytes at a time, check
# the type of data with File::MMagic and store the type
# returned with it's offset into a hash.  This is slow
# because we are reading 512 bytes at a time and then
# testing the buffer.  A quick buffer check to determine
# if all 512 bytes are the same value was added to speed
# up the process.
#
# MMagic at http://search.cpan.org/author/KNOK/File-MMagic-1.16/MMagic.pm
# CRC32 at ftp://ftp.ntua.gr/pub/linux/asplinux/sources/SRPMS.7.3/SRPMS/perl-String-CRC32-1.2-15.src.rpm
#
# usage: gettypes imagefile
#
#
# N. DeBaggis 10/23/2002
#

use strict;
use File::MMagic;
use String::CRC32;


my $magicfile = '/usr/share/magic/magic.mime';
my $buf;
my %typehash;
my $blocksize = 512;
my $magic;
my %crchash;


if(! -f $magicfile){
   print "$magicfile file not found, using defaults\n";
   $magic = File::MMagic::new();
}
else{
   $magic = File::MMagic::new($magicfile);
}

# precompute the CRC32's for each block from 0 - 255
# this will be used later to do a quick check on a block
# so we can ignore blocks that have all the same byte values.
for(my $z = 0; $z < 256; $z++){
   my $temp = chr($z) x $blocksize;
   $crchash{crc32($temp)}++;
}

open(FH, "$ARGV[0]") or die "can't open $ARGV[0] : $!";
binmode(FH);

print STDERR "attempting to find data types in $ARGV[0]...\n";

my $offset = 0;

while(! eof(FH)){
   $offset += $blocksize;
   $buf = ();
   read(FH, $buf, $blocksize);
   next if checkblock($buf);
   $typehash{$magic->checktype_contents($buf)} = $offset - $blocksize;
}
close(FH);

print "\nPossible data types found in $ARGV[0] with offsets:\n\n";
print "  hex         dec         type\n";
print '-' x 50 . "\n";

foreach(sort {$typehash{$a} <=> $typehash{$b}} keys %typehash){
   printf("0x%08x  %10d  %s\n", $typehash{$_}, $typehash{$_}, $_);
}

print "\n";


#
# checkblock($buffer)
#
# check if the buffer is all the same byte, return 1 if
# the whole block is the same.  This will
# speed up the analysis a bit.
#
sub checkblock{
   my $tmp = shift;
   my $check = 0;

   if($crchash{crc32($tmp)}){
      return 1;
   }
#   if((unpack('%32C*', $buf) % $blocksize) == 0){
#      return 1;
#   }
   return 0;
}



