#!/usr/bin/perl
#
# zip2pz.pl ... convert .zip file into pz archive.
#

$overwrite = 0;
$testing = 0;
$verbose = 1;

$zipfile = shift;
while ($zipfile =~ /^-/) {
    if ($zipfile eq "-f") {
	$overwrite = 1;
    } elsif ($zipfile eq "-n") {
	$testing = 1;
    } elsif ($zipfile eq "-q") {
	$verbose = 0;
    } else {
	print STDERR "unknown option `$zipfile'\n";
	$zipfile = "";
	last;
    }
    $zipfile = shift;
}

if ($zipfile eq "") {
    print STDERR "usage: $0 [-f|-n|-q] file.zip [(directory|out-file.pz.pdb) [dbname.pz]]\n";
    exit(2);
}

$pzfile = shift;
if ($pzfile eq "") {
    $pzfile = $zipfile;
    $pzfile =~ s/(\.[zZ][iI][pP])?$/.pz.pdb/;
} elsif (-d $pzfile) {
    $tmp = $zipfile;
    $tmp =~ s/^.*\///;
    $tmp =~ s/(\.[zZ][iI][pP])?$/.pz.pdb/;
    $pzfile .= "/" unless $pzfile =~ /\/$/;
    $pzfile = "" if $pzfile eq "./";
    $pzfile .= $tmp;
}

$pzname = shift;
if ($pzname eq "") {
    $pzname = $pzfile;
    $pzname =~ s/^.*\///;
    $pzname =~ s/(\.[pP][zZ])?(\.[pP][dD][bB])?$/.pz/;
}

if ($pzfile eq $zipfile) {
    die "input and output files are same\n";
}

if (! $overwrite && ! $testing && -f $pzfile) {
    die "`$pzfile' already exists\n";
}

if (length $pzname >= 32) {
    die "db name `$pzname' is too long\n";
}

@recs = ();
$nfiles = 0;

open(F, $zipfile) || die "can't open `$zipfile'\n";
binmode F;
while (! eof(F)) {
    read(F, $head, 4) == 4 || die;
    if ($head ne "PK\x03\x04") {
	last;
    }
    read(F, $head, 26) == 26 || die;
    ($ver, $flag, $meth, $mtime, $mdate, $crc32, $compr, $uncompr,
     $namelen, $extlen) = unpack("vvvvvVVVvv", $head);
    if ($flag & 0x29) {
	die "flag $flag is not supported\n";
    }
    read(F, $name, $namelen) == $namelen || die;
    if ($name eq "") {
	$name = "(no name)";
    }
    read(F, $ext, $extlen) == $extlen || die;
    read(F, $data, $compr) == $compr || die;
    if ($meth != 8) {
	if ($verbose) {
	    print "skipping `$name' (method = $meth, compr = $compr)\n";
	}
    } else {
	if ($verbose) {
	    print "found `$name' (compr = $compr, uncompr = $uncompr)\n";
	}
	$rec = pack("ccccVcc", 0x1f, 0x8b, $meth, 8, 0, $flag & 6, 0)
		. $name . pack("c", 0) . $data . pack("V", $crc32);
	while ($rec ne "") {
	    if (length $rec > 32764) {
		push(@recs, substr($rec, 0, 32764) . pack("V", 0xffffffff));
		$rec = substr($rec, 32764);
	    } else {
		push(@recs, $rec . pack("V", $uncompr));
		$rec = "";
	    }
	}
	++$nfiles;
    }
}
close F;

if ($#recs < 0) {
    die "`$zipfile' has no valid item\n";
}

if ($testing && $verbose) {
    print "$pzfile: not written\n";
}
exit(0) if $testing;

open(F, ">$pzfile") || die "can't open `$pzfile'\n";
binmode F;
print F pack("a32nnNNNNNNa4a4NNn", $pzname, 0, 0,
	0xadc0bea0, 0xadc0bea0, 0, 0, 0, 0, "PZDB", "PZIP", 0, 0, $#recs + 1);
$off = 78 + 8 * ($#recs + 1) + 2;
foreach (@recs) {
    print F pack("NN", $off, 0);
    $off += length $_;
}
print F pack("n", 0);
foreach (@recs) {
    print F $_;
}
close F;

if ($verbose) {
    $nrecs = $#recs + 1;
    print "$pzfile: $nfiles files ($nrecs recs), total $off bytes\n";
}
