ZSNES .cht files

General area for talk about ZSNES. The best place to ask for related questions as well as troubleshooting.

Moderator: ZSNES Mods

Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

I got it working [properly], but it cannot, for some reason I have yet to fathom, determine the value for the code. Everything else works fine, though.
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Since my signed applet won't work in Java 1.1, I updated it to work in Swing. So now it requires Java 2 on the desktop as well. But the old 1.1 version is still there if you don't want to update your Java VM.

This means file fitlers and DragNDrop support. Couple other minor things I can't remember, too.

http://games.technoplaza.net/CHTDecoder/
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Just curious, but what manner of necromancy did you perform in PHP and Java to make it like giving values? I've tried everything I can think of, but they still don't want to show up.
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Vareni Stargazer wrote:Just curious, but what manner of necromancy did you perform in PHP and Java to make it like giving values? I've tried everything I can think of, but they still don't want to show up.

Code: Select all

    function cht_decode($chtdata) {
        // parse the active bit (0 = active, 4 = inactive)
        if (ord($chtdata{0}) == 0) {
            $active = true;
        } else {
            $active = false;
        }

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

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

        $value = ord($chtdata{1}) & 0xFF;
        $code = sprintf("%06X:%02X", $address, $value);

        // parse the name
        $name = "";

        for ($pos = 8; $pos < 26; $pos++) {
            if (ord($chtdata{$pos}) == 0) {
                break;
            }

            $name .= $chtdata{$pos};
        }

        return array($name, $code, $active);
    }
The value is the 2nd byte (1 if you start counting from 0) of the 28-byte CHT record.

I think something very similar to that function will work in Perl.

The entire source for the PHP version is available on my website, btw. It may be more easier translatable into perl than the Java version.

http://games.technoplaza.net/CHTDecoder/php/index.phps
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Vareni Stargazer wrote:Just curious, but what manner of necromancy did you perform in PHP and Java to make it like giving values? I've tried everything I can think of, but they still don't want to show up.
I will post this on my website once I figure out how to get Apache to stop trying to execute it.

(edit: http://games.technoplaza.net/CHTDecoder ... decoder.pl)

This version should do what you want. It takes the files as arguments and creates .txt files of the cht codes. Any number of files, and it won't overwrite in the unusual event that the particular .txt file already exists.

Code: Select all

################################################################################
# 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
################################################################################
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
Aerdan
Winter Knight
Posts: 467
Joined: Mon Aug 16, 2004 10:16 pm
Contact:

Post by Aerdan »

Hrm... *kicks Perl*

Anyways, chttotext.pl v0.3:

Code: Select all

#!/usr/bin/perl
#
# CHT to TXT
# Copyright (C) 2004, Kiyoshi Aman
#
# This program has been released under some Creative Commons licenses.
#
# Attribution: In order to copy, distribute, display, perform, or produce
# derivative works of this program, you must give credit.
#
# Noncommercial: In order to copy, distribute, display, perform, or produce
# derivative works of this program, you must not use it to gain profit.
#
# Share Alike: In order to produce derivative works of this program, you
# must use these same licenses.

use strict;

die "Syntax: chttotext.pl cht1 cht2 [...]" if ($#ARGV == -1);

my @cht;
foreach my $i (@ARGV) {
  open CHT, "$i" or die "Cannot open $i: $!";
  open CHT, "$i" or die "Cannot open $i: $!";
  my $cht = <CHT>;
  @cht = $cht =~ /.{1,28}/g;
  close CHT;
  print "$i opened.\n";
  $i =~ s/.cht/.txt/;
  open FILE, ">$i" or die "Cannot open $i: $!";
  for (my $i = 0; $i <= $#cht; $i++) {
      my %cheat;
      ($cheat{active}{$i},$cheat{code}{$i},$cheat{desc}{$i}) = chtparse($i);

      print FILE "Active: $cheat{active}{$i}\tCode: $cheat{code}{$i}\tName: $cheat{desc}{$i}\n";
  }
  close FILE;
  print "Codes saved. Please read $i.\n";
}

sub chtparse {
    my ($active,$address,$value,$name,$code);
    my @foo = split //,$cht[$_[0]];

    if ($foo[0] == 0) { # 0 is on, 4 is off.
       $active = "on";
    } # cursed 'more' command...
    my @foo = split //,$cht[$_[0]];

    if ($foo[0] == 0) { # 0 is on, 4 is off.
       $active = "on";
    }

    # The address is backwards on little-endian x86 machines,
    # so this would be a bug on big-endian systems.
    for (my $foob = 4; $foob > 1; $foob--) {
        $address <<= 8;
        $address |= (ord($foo[$foob]) & 0xFF);
    }

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

    for (my $foob = 8; $foob < 26; $foob++) {
        last if (ord($foo[$foob]) == 0);
        $name .= chr ord($foo[$foob]);
    }
    return ($active,$code,$name);
}
Notes: This does *not* try to verify that the file is a cht--the only way to do that would be to have ZSNES add some form of indication at the front of the file and at the end so that it can be recognized as a .cht.
Last edited by Aerdan on Wed Sep 29, 2004 3:58 am, edited 1 time in total.
Noxious Ninja
Dark Wind
Posts: 1271
Joined: Thu Jul 29, 2004 8:58 pm
Location: Texas
Contact:

Post by Noxious Ninja »

You can perform a small amount of error checking by verifying the file is a multiple of 28 bytes long, and that the value for enabled is only 0 or 4.
[u][url=http://bash.org/?577451]#577451[/url][/u]
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Vareni Stargazer wrote:Hrm... *kicks Perl*

Anyways, chttotext.pl v0.3:

Code: Select all

    if ($foo[0] == 0) { # 0 is on, 4 is off.
       $active = "on";
    my @foo = split //,$cht[$_[0]];
You forgot a } curly...

Code: Select all

    if ($foo[0] == 0) { # 0 is on, 4 is off.
       $active = "on";
    }
    my @foo = split //,$cht[$_[0]];
Vareni Stargazer wrote: Notes: This does *not* try to verify that the file is a cht--the only way to do that would be to have ZSNES add some form of indication at the front of the file and at the end so that it can be recognized as a .cht.
Even if the ZSNES CHT record format had some kind of indicator in it, the same indicator could potentially be found in some unknown binary file. An unlikely coincidence, but a possibility.

There is no sure-fire way to determine that the file you gave it is a cht file. I used three tests to test for a "valid" cht file. A more accurate name for my function might have been is_good_cht_file_candidate()...

a) is it a regular file (e.g. it exists and is not a directory)
b) does the filename end with .cht
c) is the size a multiple of 28 bytes
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Sorry to bring back old threads, but all the discussion on the "does anyone use the DOS port" thread made me want to try out one of these GUI toolkits.

I have never used GTK (I tried once, but found it hard to get started). I looked at it again, and since they don't port to Windows (at least the authors don't, I know there are ports, but the one I found said it had been discontinued), I decided to give up on GTK.

wxWidgets however looked very interesting. I can't quite figure out how to change the default behavior of DnD for a text control, and my new source does some things in C++ that are stupid, but made sense in Java. I'll probably clean those things up later.

It seems to require more than one DLL to run the executable. So I would like to know if someone wants to test it and tell me if the archive works without having to compile wxWidgets or have MinGW/msys installed.

If anyone wants to,

http://games.technoplaza.net/CHTDecoder ... er-1.0.zip

Includes the full source. It's GPL. Forgot to add my notice, but it's GPL.

I'm also wondering how well it works in Linux. I've only tested in windows, but the Makefile should compile in Linux. I've also forgotten how to correctly write Makefiles, so the dependency graph is non-existent. But since you probably won't be altering the source, that shouldn't matter. It only matters because it won't recompile files when you change their headers, even though it should.

The download is unfortunately 2 MB. The wx widgets DLL is 6 MB, so compressed with my 80 K exe and the mingw DLL = 2 MB zipped.
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
Anime-niac
Rookie
Posts: 14
Joined: Sun Aug 08, 2004 5:22 pm

Post by Anime-niac »

It seems to require more than one DLL to run the executable. So I would like to know if someone wants to test it and tell me if the archive works without having to compile wxWidgets or have MinGW/msys installed.
The program runs fine for me. Using WinXP Pro SP1, and I don't have the wxWidgets or MinGW programs installed.
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Anime-niac wrote:
It seems to require more than one DLL to run the executable. So I would like to know if someone wants to test it and tell me if the archive works without having to compile wxWidgets or have MinGW/msys installed.
The program runs fine for me. Using WinXP Pro SP1, and I don't have the wxWidgets or MinGW programs installed.
Great. Thanks.
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

The long anticipated wxCHTDecoder 1.1 is at last a reality.

I know all of you out there were thinking I couldn't top that 1.0 version I posted. But I think I've done it.

Drag and Drop support and Text mode.

Thought text mode is a little funny on windows. For some reason, it won't display anything on the console from the command (cmd.exe) prompt. But it works just fine in msys. I couldn't figure out how to create a VC.NET project for it that would compile and I didn't feel like looking for another compiler. mingw/msys should work.

Whatever. I know, probably nobody cares. But it was fun for me and a nice way to learn wxWidgets and reaquaint myself with C++.

http://games.technoplaza.net/CHTDecoder/

Hey Nach, think I could be a ZSNES developer? I'll help rewrite the GUI in wxWidgets. :-)
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

jdratlif wrote: Hey Nach, think I could be a ZSNES developer? I'll help rewrite the GUI in wxWidgets. :-)
If you love ZSNES, willing to spend some time on it, know pretty well how to work with C, and have at least a basic understanding of x86, you should have no trouble being a ZSNES dev.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
jdratlif
Regular
Posts: 317
Joined: Tue Sep 14, 2004 12:48 am
Location: In a small padded white room
Contact:

Post by jdratlif »

Does anyone use Mac OS 9 (or earlier, just not OS-X, even in classic mode -- I want real OS 9)

I'm going to try and build a Mac version, but I only have access to OS-X machines. I'd like to test on Mac OS 9.

Even though ZSNES can't run on Macs, this tool could. And I believe Snes9x cht files use a similar format (maybe identical, I'm pretty sure they can use .cht files).

If anyone wants to help me Mac OS 9 beta test, TIA.
http://jdrrant.blogspot.com/ - CODEpendent Blog
http://games.technoplaza.net/ - Emulation Goodies
Post Reply