################################################################################
# Perl CHTDecoder 1.0
# Copyright (C) 2004 emuWorks (http://games.technoplaza.net)
# by John David Ratliff
#

if ($#ARGV == -1) {
    die qq|syntax: perl chtdecoder.pl cht_file[, cht_file2, ...]\n|;
}

foreach $arg (@ARGV) {
    if (is_valid_cht_file($arg)) {
        decode_cht_file($arg);
    } else {
        print "error: ${arg} does not seem to be a valid .CHT file.\n";
    }
}

################################################################################
# checks for a valid .CHT file
#

sub is_valid_cht_file($) {
    my ($chtfile) = @_;
    my (@stats);
    
    # it must be a regular file
    if (! -f $chtfile) {
        return 0;
    }
    
    # it must end in .cht
    if (($chtfile =~ m/\.cht$/i) == 0) {
        return 0;
    }
    
    # filesize must be a multiple of 28 (the record size)
    @stats = stat($chtfile);
    
    if (($stats[7] % 28) != 0) {
        return 0;
    }
    
    # if we're here, it is likely a pretty good candidate
    return 1;
}

################################################################################
# decodes a cht record into the name, address, and active pieces
#

sub decode_cht_data($) {
    my ($chtdata, @data, $pos) = @_;
    my ($active, $address, $value, $code, $name);
    
    @data = split(//, $chtdata);
    
    # parse the active bit (0 = active, 4 = inactive)
    if (ord($data[0]) == 0) {
        $active = 1;
    } else {
        $active = 0;
    }

    # parse the code (address + value)
    $address = 0;

    for ($pos = 4; $pos > 1; $pos--) {
        $address <<= 8;
        $address |= (ord($data[$pos]) & 0xFF);
    }

    $value = ord($data[1]) & 0xFF;
    $code = sprintf("%06X:%02X", $address, $value);

    # parse the name
    $name = "";

    for ($pos = 8; $pos < 26; $pos++) {
        if (ord($data[$pos]) == 0) {
            last;
        }

        $name .= $data[$pos];
    }

    return ($name, $code, $active);
}

################################################################################
# decodes the cht file to a txt file
#

sub decode_cht_file($) {
    my ($chtfile) = @_;
    my ($txtfile, @stats, $codes, $count);
    my ($chtdata, $cht_name, $cht_code, $cht_active);
    
    $txtfile = $chtfile . ".txt";
    
    if (-e $txtfile) {
        print "error: ${txtfile} exists. I won't overwrite an existing file!\n";        
        return;
    }
    
    open(CHT, $chtfile);
    binmode(CHT);
    open(TXT, ">$txtfile");
    
    @stats = stat($chtfile);
    $codes = $stats[7] / 28;
    
    print(TXT "Decoding ${chtfile} into ${codes} PAR codes.\n\n");
    
    for ($count = 0; $count < $codes; $count++) {
        read(CHT, $chtdata, 28);
        ($cht_name, $cht_code, $cht_active) = decode_cht_data($chtdata);
        printf(TXT "%2d: %-18s %s %-8s\n", ($count + 1), $cht_name, $cht_code, 
               ($cht_active ? "active" : "inactive"));
    }
    
    close(CHT);
    close(TXT);
    
    print "wrote the decoded output of ${chtfile} to ${txtfile}.\n";
}

#
# end of script
################################################################################
