#!perl -w
use strict;
use Compress::Zlib;
use MIME::Base64;
use IO::File;

my $ifn= shift || "-";
my $ofn= shift || "-";
if (-e $ofn) {
    die "$ofn already exists\n";
}
decode_file($ifn, $ofn);

sub decode_file {
    my ($ifn, $ofn)= @_;
    my $ifh= ($ifn eq "-") ? *STDIN : IO::File->new($ifn, "r");
    if (!$ifh) {
        warn "open input $ifn: $!\n";
        return;
    }
    binmode $ifh;
    my $ofh= ($ofn eq "-") ? *STDOUT : IO::File->new($ofn, "w");
    if (!$ofh) {
        warn "open output $ofn: $!\n";
        return;
    }
    binmode $ofh;
    my $ofs= 0;
    while (!$ifh->eof()) {
        my $hdrofs= $ofs;
        my $hdr;
        $ifh->read($hdr, 0x18) or die "$ifn: no header: $!\n";
        $ofs+=0x18;
        my ($version, $crypt, $encoding, $full_size, $comp_size);
        if ($hdr =~ /^XlxV(\d\d)(\w)(\w)\s+(\w+)\s+(\w+)/) {
            ($version, $crypt, $encoding, $full_size, $comp_size)= ($1, $2, $3, hex($4), hex($5));
        }
        else {
            warn sprintf("%s: invalid header @%08lx: %s\n", $ifn, $ofs, unpack("H*", $hdr));
            return;
        }

        my $data="";
        $ifh->read($data, $comp_size) or die "$ifn: $!\n";
        $ofs += $comp_size;

        if ($encoding eq "B") {
            # nop
        }
        elsif ($encoding eq "M") {
            $data= decode_base64($data);
        }
        else {
            warn sprintf("%s: unknown encoding: %s\n", $ifn, $encoding);
            return;
        }

        my $d= Compress::Zlib::inflateInit();
        my ($fulldata, $status)= $d->inflate($data."\x00");

        if ($status!=1) {
            warn printf("$ifn: INFLATE ERROR %08lx\n", $status);
            return;
        }
        else {
            if (length($fulldata) != $full_size) {
                warn sprintf("%s: l(fd)=%x  hdr.f=%x\n", $ifn, length($fulldata), $full_size);
            }
            $ofh->print($fulldata);
        }
    }
}
