#!/usr/bin/perl

# Reads a compiled binary (ProDOS header) and loads it via the debugger.
#
# Binary should be created and loaded something like
# 
# cc65 -t apple2enh -O testbin.c 
# ca65 -t apple2enh testbin.s
# ld65 -t apple2enh -o testbin testbin.o --lib apple2enh.lib
# ./debug-bin.pl testbin

use strict;
use warnings;
use IO::Socket;

$| = 1;

my $filename = shift || die "No file provided";

my $fh;
open($fh, $filename) || die "Unable to open file: $!";

my $data;
die unless (read($fh, $data, 26) == 26);
my $pos = 26;

my ($magic, $version, $volume, $numEntries) = unpack("H8H8H32H4", $data);
die "Bad magic [$magic]" unless ($magic eq "00051600");
$numEntries = int($numEntries);

print "Entries: " . $numEntries . "\n";

my ($dataoffset, $datalength, $infoOffset, $infoLength, $entryPoint);
while ($numEntries) {
    die unless (read($fh, $data, 12) == 12);
    $pos += 12;
    my ($entryID, $entryOffset, $entryLength) = unpack("H8H8H8", $data);
    if (hex($entryID) == 11) {
	print "ProDOS chunk found at offset 0x$entryOffset length 0x$entryLength\n";
	$infoOffset = hex($entryOffset);
	$infoLength = hex($entryLength);
    }
    if (hex($entryID) == 1) {
	print "Data found at offset 0x$entryOffset length 0x$entryLength\n";
	$dataoffset = hex($entryOffset);
	$datalength = hex($entryLength);
    }
    $numEntries--;
}
die "Failed to find info chunk"
    unless ($infoOffset || $infoLength);
die "Failed to find data chunk"
    unless ($dataoffset || $datalength);

die "Haven't figured out how to read in this order"
    unless ($infoOffset < $dataoffset);

while ($pos < $infoOffset) {
    die unless (read($fh, $data, 1) == 1);
    $pos++;
}
die "Failed to read info chunk" unless (read($fh, $data, $infoLength) == $infoLength);
$pos += $infoLength;

my $unpacked = unpack('H*', $data);
my @hex    = ($unpacked =~ /(..)/g);
my @bytes    = map { hex($_) } @hex;
$entryPoint=($bytes[6] << 8) |$bytes[7];

while ($pos < $dataoffset) {
    die unless (read($fh, $data, 1) == 1);
    $pos++;
}

die "Failed to read data chunk" unless (read($fh, $data, $datalength) == $datalength);
$unpacked = unpack('H*', $data);
@hex    = ($unpacked =~ /(..)/g);
@bytes    = map { hex($_) } @hex;

my $socket = new IO::Socket::INET (PeerHost => '127.0.0.1',
				   PeerPort => '12345',
				   Proto => 'tcp',
				   ) or die "ERROR in Socket Creation : $!\n";
print $socket sprintf("L 0x%X\n", $entryPoint);
my $count = 0;
foreach my $i (@bytes) {
    print $socket sprintf("%.2X", $i);
    print sprintf("%.2X ", $i);
    $count++;
    if ($count >= 16) {
	print $socket "\n";
	print "\n";
	$count = 0;
    }
}
print $socket "\n"; # End data entry mode

# Goto new code
print $socket sprintf("G 0x%X\n\n", $entryPoint);
<$socket>;
#sleep(5);
print sprintf("EntryPoint: 0x%X\n", $entryPoint);
exit(0);

__END__
Each entry:
  Entry ID (4 bytes): 00 00 00 01 = data form
  Entry Offset (4 bytes): 00 00 00 3a = 0x3a
  Entry Length: 4 bytes: 00 00 18 40 = 0x1840 bytes
---
  00 00 00 0B = ProDOS file info
  00 00 00 32 = offset
  00 00 00 08 = length
---

Header w/ size of $3A bytes; then file data

Offset $24/$25 are length (big endian)
$35 -> file type ($06: BIN; $FF: SYS)
$38/$39: aux type for bin (big endian)

$33: ProDOS Access Byte %11000011 (enable access, destroy, rename, write, read)