#!/usr/bin/perl
$blocksize=1024;
$escape=chr 167;

while(<STDIN>)
{
    $disk.=$_;
}

$size=length($disk);
if($size%$blocksize)
{
	$diff=($blocksize-($size%$blocksize));
	$disk.="\0"x$diff;
	$size=length($disk);
	warn "Padded $diff bytes to $size\n";
}

$blocknum=0;

warn "Compressing...\n";

while($pos<$size)
{
    $pos[$blocknum]=length $cdisk;
    $block=substr($disk,$pos,$blocksize);

    $s=length($block);

#    warn "Block $blocknum pos $pos length $s\n";

    $last="foo";
    $run=0;
    $i=0;
    while($i<$blocksize)
    {
	$c=substr($block,$i,1);
	$a=ord $c;
	$hist{$a}++;
	if($c eq $last)
	{
	    $run++;
	    if($run eq 255)
	    {
		$runs++;
		$runhist{$a}++;
		$runlength{$run-3}++;
		$cdisk.=pack("ACA",$escape,$run,$c);
		$run=0;
	    }
	}
	else
	{
	    if($run)
	    {
		if($last eq $escape)
		{
		    $overhead++;
		    if($run==1)
		    {
			$cdisk.=$escape."\0";
		    }
		    if($run>1)
		    {
			if($run>3)
			{
			    $runhist{ord $escape}++;
			    $runlength{$run-3}++;
			    $runs++;
			}
			$cdisk.=pack("ACA",$escape,$run,$escape);
		    }
		}
		elsif($run == 1)
		{
		    $cdisk.=$last;
		}
		elsif($run<4)
		{
		    $cdisk.=$last x $run;
		}
		elsif($run>3)
		{
		    $runs++;
		    $runhist{ord $last}++;
		    $runlength{$run-3}++;
		    $cdisk.=pack("ACA",$escape,$run,$last);
		}
	    }
	    $last=$c;
	    $run=1;
	}
	$i++;
    }

    if($run)
    {
	if($last eq $escape)
	{
	    $overhead++;
	    if($run==1)
	    {
		$cdisk.=$escape x 2;
	    }
	    if($run>1)
	    {
		if($run>3)
		{
		    $runhist{ord $escape}++;
		    $runlength{$run-3}++;
		    $runs++;
		}
		$cdisk.=pack("ACA",$escape,$run,$escape);
	    }
	}
	elsif($run == 1)
	{
	    $cdisk.=$last;
	}
	elsif($run<4)
	{
	    $cdisk.=$last x $run;
	}
	elsif($run>3)
	{
	    $runs++;
	    $runhist{ord $last}++;
	    $runlength{$run}++;
	    $cdisk.=pack("ACA",$escape,$run,$last);
	}
    }

    $pos+=$blocksize;
    $blocknum++;
}   

$offset=$blocknum*4; 

#open(DUMP,">cdisk");
#print DUMP $cdisk;
#close DUMP;

foreach $pos (@pos)
{
#    warn "$pos\n";
    $blockmap.=pack("N",$pos+$offset);
}

$cdisk=$blockmap.$cdisk;

print "/*\n";
print "Escape: ",ord $escape," Block size: $blocksize\n";
print "Input hist:\n";
foreach $a (sort {$hist{$b}<=>$hist{$a}} keys %hist)
{
    print "$a\t$hist{$a}\n";
}

print "Runchar hist:\n";
foreach $a (sort {$runhist{$b}<=>$runhist{$a}} keys %runhist)
{
    print "$a\t$runhist{$a}\n";
}

print "Runlength hist:\n";
foreach $a (sort {$runlength{$b}*$b<=>$runlength{$a}*$a} keys %runlength)
{
    print "$a\t$runlength{$a} (",$runlength{$a}*$a,")\n";
}

print "*/\n";

warn "Original size: ",length $disk," compressed: ",length $cdisk," (o: $overhead r: $runs)\n";

if(length $cdisk < length $disk)
{
    $type=1;
    $disk=$cdisk;
}

$disk=pack("NN",$size,$type).$disk;
$size=length $disk;

warn "Encoding ($size bytes)...\n";

print "const unsigned char romdisk[$size]=\n";

$i=0;
while($i<$size)
{
    $c=substr($disk,$i,1);

    $a=ord $c;
    
    if($c eq "\\")
    {
	$l.='\\';
    }
    if($c eq "\"")
    {
	$l.='\"';
    }
    elsif($a>31&&$a<127)
    {
	$l.=$c;
    }
    elsif($a==13)
    {
	$l.="\\r";
    }	
    elsif($a==10)
    {	
	$l.="\\n";
    }		
    else
    {
	$l.="\\".int($a/64).int(($a%64)/8).int($a%8);
    }
    
    $i++;
    if(length $l>74||$i==$size)
    {
	print "\"$l\"";
	$l="";
	print ";" if $i==$size;
	print "\n";
    }
}






