#!/usr/bin/perl

#use strict;

use Fcntl;
use Digest::MD5;

my $file_name = $ARGV[0];

sysopen my $bin, $file_name, O_RDONLY | O_BINARY or die "can't open file: $!";

sysread $bin, my $header, 4;
print "File Format: " . $header . "\n";

my $rsid = $header == 'RSID';

sysread $bin, my $version, 2;
print "Format Version: " . unpack("n", $version) . "\n";

# This is the offset from the start of the file to the C64 binary data area.
# Because of the fixed size of the header, this is either 0x0076 for version 1
# and 0x007C for version 2 and 3.
sysread $bin, my $dataOffset, 2;
printf "Data offset: \$%04x\n", unpack("n", $dataOffset);

# The C64 memory location where to put the C64 data. 0 means the data are in
# original C64 binary file format, i.e. the first two bytes of the data contain
# the little-endian load address (low byte, high byte). This must always be true
# for RSID files. Furthermore, the actual load address must NOT be less than
# $07E8 in RSID files.
sysread $bin, my $loadAddress, 2;
if (unpack("n", $loadAddress) > 0) {
	if ($rsid) {
		printf "Broken RSID tune, laod address must be 0 but was: \$%04x\n", $loadAddress
	}
	else {
		printf "Load Address: \$%04x\n", unpack("n", $loadAddress);
	}
}

sysread $bin, my $initAddress, 2;
printf "Init Address: \$%04x\n", unpack("n", $initAddress);

sysread $bin, my $playAddress, 2;
printf "Play Address: \$%04x\n", unpack("n", $playAddress);

sysread $bin, my $songs, 2;
printf "Number of tunes: %d\n", unpack("n", $songs);

sysread $bin, my $startSong, 2;
printf "Default tune: %d\n", unpack("n", $startSong);

sysread $bin, my $speed, 4;
printf "Speed: \$%08x\n", unpack("N", $speed);

sysread $bin, my $name, 32;
printf "Title: %s\n", $name;

sysread $bin, my $author, 32;
printf "Author: %s\n", $author;

sysread $bin, my $released, 32;
printf "Released: %s\n", $released;

if (unpack("n", $version) > 1) {
	sysread $bin, my $binflags, 2;
	my $flags = unpack("n", $binflags);

	printf "MUS: %s\n", ($flags & 0x01)?"true":"false";
	if ($header == "PSID") {
		printf "PlaySID Specific: %s\n", ($flags & 0x02)?"true":"false";
	} else {
		printf "BASIC: %s\n", ($flags & 0x02)?"true":"false";
	}
	
	my %clock = (
		0b00 => "Unknown",
		0b01 => "PAL",
		0b10 => "NTSC",
		0b11 => "PAL and NTSC"
	);
	printf "Clock: %s\n", $clock {($flags & 0x0C) >> 2};

	my %model = (
		0b00 => "Unknown",
		0b01 => "6581",
		0b10 => "8580",
		0b11 => "6581 and 8580"
	);
	printf "SID Model: %s\n", $model {($flags & 0x30) >> 4};

	if (unpack("n", $version) > 2) {
		printf "2nd SID Model: %s\n", $model {($flags & 0xC0) >> 6};
		if (unpack("n", $version) > 3) {
			printf "3rd SID Model: %s\n", $model {($flags & 0x300) >> 8};
		}
	}

	sysread $bin, my $startPage, 1;
	printf "Start Page: \$%02x\n", unpack("C", $startPage);

	sysread $bin, my $pageLength, 1;
	printf "Page Length: \$%02x\n", unpack("C", $pageLength);

	sysread $bin, my $secondSIDAddress, 1;
	sysread $bin, my $thirdSIDAddress, 1;
	if (unpack("n", $version) > 2) {
		printf "2nd SID Address: \$D%02x0\n", unpack("C", $secondSIDAddress);
		if (unpack("n", $version) > 3) {
			printf "3rd SID Address: \$D%02x0\n", unpack("C", $thirdSIDAddress);
		}
	}
}

if (unpack("n", $loadAddress) == 0) {
	sysread $bin, my $realLoadAddr, 2;
	if ($rsid && unpack("v", $realLoadAddr) < 0x07E8) {
		printf "Broken RSID tune, laod address must be at least \$07E8 but was: \$%04x\n", $realLoadAddr
	}
	else {
		printf "Load Address: \$%04x\n", unpack("v", $realLoadAddr);
	}
}

# new method (since HVSC #68)
my $ctx = Digest::MD5->new;

sysseek $bin, 0, SEEK_SET;

$ctx->addfile($bin);

printf "MD5 new method: %s\n",  $ctx->hexdigest;

# old method
$ctx->reset;

# Include C64 data
my $offset = unpack("n", $dataOffset);
if (unpack("n", $loadAddress) == 0) {
    $offset += 2;
}
sysseek $bin, $offset, SEEK_SET;
do {
	my $datalen = sysread $bin, my $buffer, 65536;
	$ctx->add($buffer);
} while ($datalen > 0);

# Include INIT and PLAY address
$ctx->add(pack("v", unpack("n", $initAddress)));
$ctx->add(pack("v", unpack("n", $playAddress)));

# # Include number of songs
$ctx->add(pack("v", unpack("n", $songs)));

# Include song speed for each song
my $mask = 1;
for (my $i = 1; $i <= unpack("n", $songs); $i++, $mask <<= 1) {
    if (unpack("N", $speed) & $mask) {
        $ctx->add(pack("c", 1));
    } else {
        $ctx->add(pack("c", 0));
    }
}

# Include clock speed flags
if (($flags & 0x0C) >> 2 == 0b10) {
    $ctx->add(ack("c", 2));
}

printf "MD5 old method: %s\n",  $ctx->hexdigest;


close $bin;
