#!/usr/bin/perl
#
# Unpack Stardust installers
#
# Author: PinkFreud@Nightstar
#
# License: GPL
#
my $version = 0.0.1;
#
#
# Changelog:
#
# 0.0.1:	Initial release
#
# TODO:
#
#  * Parse timestamp
#
# Disclaimer: Use at your own risk.  I accept no responsibility for anything
#             this script might do.
#
# Authors:	PinkFreud: Original idea, reverse engineering of
#		           Stardust-packaged bots


use Compress::Zlib;


sub inflate {
  # Most of this was gratuitously stolen from the man page for Compress::Zlib
  my $x = inflateInit()
     or die "Cannot create an inflation stream\n";
  my $data = $_[0];
  
  my ($output, $status);
  ($output, $status) = $x->inflate(\$data) ;
  return $output;
}


$offset = 0x1b000;
$doffset = 0x01b45c;
$file = shift @ARGV;

open (F, $file);
seek (F, $offset, 0);
read (F, $data, 12);
($sig1, $sig2, $numfiles) = unpack (VVV, $data);
die "This doesn't look like a Stardust installer!\n"
  unless $sig1 == $sig2 and $sig1 == 0x12345678;
seek (F, $doffset, 0);

for (1..$numfiles) {
  read (F, $data, 280);

  ($fn, $u1, $size, $psize, $doffset, $f1, $f2) = unpack (Z256VVVVVV, $data);
  push (@file,
	  {
	    filename	=> $fn,
	    unknown	=> $u1,
	    size	=> $size,
	    packedsize	=> $psize,
	    dataoffset	=> $doffset,
	    flag1	=> $f1,
	    flag2	=> $f2
	  }
       );
}

$curoffset = tell (F);

for $file (@file) {
  if ($file->{dataoffset} != $curoffset) {
    warn "$file->{filename}:\n";
    warn "dataoffset is $file->{dataoffset}, but I'm at $curoffset!\n";
    warn "Possible extra data?\n";
    unless (seek (F, $file->{dataoffset}, 0)) {
      die "seek failed: $file->{dataoffset} ($!)\n";
    }
  }
  printf "[%08x] Inflating %s (%d -> %d bytes, u: %d, flag1: %d, flag2: %d)\n",
    @{$file}{dataoffset,filename,packedsize,size,unknown,flag1,flag2};
  $bytesread = read (F, $data, $file->{packedsize});
  die "Requested $file->{packedsize} bytes, got bytesread bytes instead!\n"
    unless $bytesread == $file->{packedsize};
  $curoffset = tell (F);

  $filedata = inflate $data;
  $filesize = length $filedata;
  warn "Corrupt $file->{filename}?  $file->{size} != $filesize bytes!\n"
    unless $filesize == $file->{size};

  open (FILE, "> $file->{filename}");
  print FILE $filedata;
  close (FILE);
}

close (F);
