#! /usr/bin/perl # # initialize variables # $date = `date`; $date =~ s/\n$//; $batchmode = 0; $outputstyle = 'ps'; $reportto = 'crosspad@itojun.org'; $debug = 0; ($startpage, $endpage) = (1, 99999); $pageoutput = 0; $pspagenumber = 0; ($xoffset, $yoffset) = (0, 0); ($xscale, $yscale) = (1, 1); $tmpdir = '/tmp/' . $$ . '.' . time; ($boundingx0, $boundingy0) = (99999, 99999); ($boundingx1, $boundingy1) = (-99999, -99999); # western people may prefer letter than a4... #$papersize = 'a4 letter'; $papersize = 'letter a4'; $pslinewidth = 0; $annotate = 1; $reorder = 1; $purge = 1; $tgifscale = 0.5; $idrawscale = 0.5; $progname = $0; $progname =~ s/\.pl$//; $progname =~ s/^.*\///; $outputstyle = $1 if ($progname =~ /^crosspad2(\w+)$/); $huffman{'110101011111001'} = -16; $huffman{'110101011110'} = -15; $huffman{'1100100100'} = -14; $huffman{'110010011'} = -13; $huffman{'110101010'} = -12; $huffman{'11010100'} = -11; $huffman{'1000100'} = -10; $huffman{'1010011'} = -9; $huffman{'1101011'} = -8; $huffman{'101000'} = -7; $huffman{'110011'} = -6; $huffman{'10000'} = -5; $huffman{'11000'} = -4; $huffman{'11011'} = -3; $huffman{'1011'} = -2; $huffman{'010'} = -1; $huffman{'00'} = 0; $huffman{'011'} = 1; $huffman{'1001'} = 2; $huffman{'10101'} = 3; $huffman{'110100'} = 4; $huffman{'100011'} = 5; $huffman{'1100101'} = 6; $huffman{'1010010'} = 7; $huffman{'11001000'} = 8; $huffman{'10001010'} = 9; $huffman{'100010111'} = 10; $huffman{'100010110'} = 11; $huffman{'1100100101'} = 12; $huffman{'11010101110'} = 13; $huffman{'11010101100'} = 14; $huffman{'11010101101'} = 15; $huffman{'1101010111111'} = 16; $huffman{'11010101111101'} = 18; # long form covers signed 8bit values # slow version... #for ($i = -128; $i < 128; $i++) { # $t = unpack('B*', pack('C', $i)); # $huffman{'110101011111000' . $t} = $i + 5; # print '110101011111000' . $t . "="; # print $i + 5 . "\n"; #} $huffman{'110101011111000'} = -998; # termination $huffman{'1111111'} = -999; #$huffman{'111111111111111'} = -999; # # parse arguments # ARG: while ($ARGV[0] =~ /^-/) { $_ = shift @ARGV; if ($_ =~ /-s(\d+)/) { $startpage = $1; next ARG; } if ($_ =~ /-e(\d+)/) { $endpage = $1; next ARG; } if ($_ =~ /-p(\d+)/) { $startpage = $endpage = $1; next ARG; } if ($_ =~ /-m(\w+)/) { $outputstyle = $1; next ARG; } if ($_ =~ /-w(\d+)/) { $pslinewidth = $1; next ARG; } $t = 0; foreach $_ (split(//, substr($_, 1))) { if ($_ eq 'i') { $t++; $batchmode = 0; next; } if ($_ eq 'b') { $t++; $batchmode = 1; next; } if ($_ eq 'D') { $t++; $debug++; next; } if ($_ eq 'r') { $t++; $reorder = !$reorder; next; } if ($_ eq 'a') { $t++; $annotate = !$annotate; next; } &usage; exit 1; } next ARG if ($t); &usage; exit 1; } if (scalar(@ARGV) != 1) { &usage; exit 1; } if ($outputstyle eq 'eps') { $endpage = $startpage; } elsif ($outputstyle eq 'tgif' || $outputstyle eq 'idraw') { $endpage = $startpage; $reorder = 1; } $filename = $ARGV[0]; if (! -f $filename) { print STDERR "$filename not found\n"; exit 1; } if ($reorder) { while (-e $tmpdir) { $tmpdir .= 'x'; } mkdir($tmpdir, 0755) || die; } &pageinit(0); if (!$reorder) { &preprocess($filename); &preamble0; } &parse($filename); if (!$reorder) { &postamble0; &postprocess($filename); } else { &joinpages; system "/bin/rm -fr $tmpdir" if ($purge); } exit 0; sub pageinit { local($page) = @_; local($t); return if (!$reorder); $curpage = $page; ($boundingx0, $boundingy0) = (99999, 99999); ($boundingx1, $boundingy1) = (-99999, -99999); if (open(BOUND, "< $tmpdir/$page.bound")) { $t = ; close(BOUND); ($boundingx0, $boundingy0, $boundingx1, $boundingy1) = split(/\s+/, $t); } open(OUT, ">> $tmpdir/$page") || die; select(OUT); } sub pagefinish { return if (!$reorder); close(OUT); open(OUT, "> $tmpdir/$curpage.bound") || die; print OUT "$boundingx0 $boundingy0 $boundingx1 $boundingy1\n"; close(OUT); } sub parse { local($file) = @_; local($buf, $l, $sl, $nl, $x, $y, $len, $vers, $code); local(@unknownlen); for ($i = 0; $i < 256; $i++) { $unknownlen[$i] = -1; $unknownstr[$i] = ''; } $unknownlen[0x03] = 0x0b; $unknownstr[0x03] = 'keyword'; $unknownlen[0x0e] = 0x07; $unknownlen[0x35] = 0x06; $unknownlen[0x36] = 0x06; $unknownlen[0x39] = 0x27; $unknownlen[0x3c] = 0x12; $unknownlen[0x3d] = 0x10; $unknownlen[0x3e] = 0x0a; open(IN, "< $file") || die; sysread(IN, $buf, 5) || die; if (substr($buf, 0, 3) ne pack('C3', 0x01, 0x00, 0xff)) { close(IN); open(IN, "< $file") || die; $len = (stat($file))[7]; } else { # just for debugging... $len = (stat($file))[7] - 5; } print "% file \"$file\" data part length: $len\n" if ($debug); $l = 0; while ($l + 5 < $len) { sysread(IN, $buf, 5); ($vers, $code) = unpack('N C', $buf); # correct? printf("%% pos=%08x ver=%d code=0x%02x: ", $l, $vers, $code) if ($debug); if ($vers != 0) { print STDERR "unsupported file format version $vers\n"; close(IN); &failure("unexpected input", 0); } if ($code == 0x06) { # original crosspad sysread(IN, $buf, $nl = 0x14); $t = unpack('x19 C', $buf); if ($debug) { &printdate(substr($buf, 0, 6)); print "compress=$t\n"; } # is this correct? if ($t == 1) { ($xoffset, $yoffset) = (20, 22); ($xscale, $yscale) = (1, 1); } elsif ($t == 2) { ($xoffset, $yoffset) = (20, 2944); ($xscale, $yscale) = (1, -1); } } elsif ($code == 0x1d) { # crosspad XP sysread(IN, $buf, $nl = 0x2b); if ($debug) { &printdate(substr($buf, 0, 6)); print "compress=?\n"; } # is this correct? # handcrafted offset value, need suggestions ($xoffset, $yoffset) = (40, 3030); ($xscale, $yscale) = (1, -1); $papersize = 'a5'; } elsif ($code == 0x0d || $code == 0x0a) { sysread(IN, $buf, $nl = 0x0e); $t = substr($buf, 6, 8); $t =~ s/\000//g; if ($debug) { &printdate(substr($buf, 0, 6)); print "\"$t\"\n"; } } elsif ($code == 0x04) { sysread(IN, $buf, $nl = 10); $t = unpack('x6 N', $buf); if ($debug) { &printdate(substr($buf, 0, 6)); print "switch to " if ($reorder); print "page $t\n"; } if ($reorder) { &pagefinish; } else { &postamble if ($pageoutput); } if ($reorder) { &pageinit($t); $pageoutput = 1; } else { if ($startpage <= $t && $t <= $endpage) { $pageoutput = 1; &preamble(++$pspagenumber); print "% this is page $t ". "in the source file\n" if ($pspagenumber != $t); } else { $pageoutput = 0; print "% skipping this page\n" if ($debug); } } } elsif ($code == 0x01 || $code == 0x02) { sysread(IN, $buf, 12); ($sl, $x, $y) = unpack('x6 n3', $buf); if ($debug) { &printdate(substr($buf, 0, 6)); if ($code == 0x01) { print "stroke: "; } else { print "NEW stroke: "; } print "len=$sl start=($x, $y)\n"; } sysread(IN, $buf, $sl - 4); if ($pageoutput) { ($curx, $cury) = ($x - $xoffset, $y - $yoffset); $curx *= $xscale; $cury *= $yscale; &updatebbox($curx, $cury); if ($outputstyle =~ /^(ps|eps)$/) { printf("%d %d NP [\n", $curx, $cury); } elsif ($outputstyle =~ /^(tgif|idraw)$/) { printf("START %d %d\n", $curx, $cury); } &printstroke($buf); } $nl = 12 + length($buf); } elsif ($code == 0x05) { # clock adjust sysread(IN, $buf, $nl = 0x0c); if ($debug) { &printdate(substr($buf, 0, 6)); print "clock adjusted at "; &printdate(substr($buf, 6, 6)); print "\n"; } } elsif ($code == 0x37) { sysread(IN, $buf, $nl = 6); if ($debug) { &printdate(substr($buf, 0, 6)); print "page bookmark\n"; } if ($reorder) { open(BOOKMARK, "> $tmpdir/$curpage.bookmark"); $t = select(BOOKMARK); &printdate(substr($buf, 0, 6)); select($t); close(BOOKMARK); } } elsif ($code == 0x3a) { sysread(IN, $buf, $nl = 6); if ($debug) { &printdate(substr($buf, 0, 6)); print "is last download time\n"; } } elsif (0 <= $unknownlen[$code]) { sysread(IN, $buf, $nl = $unknownlen[$code]); if ($debug == 1) { &printdate(substr($buf, 0, 6)); print $unknownstr[$code] . "???\n"; } elsif (1 < $debug) { &printdate(substr($buf, 0, 6)); print $unknownstr[$code] . "???: "; for ($i = 6; $i < length($buf); $i++) { printf("%02x ", unpack('C', substr($buf, $i, 1))); } print "\n"; } } else { printf("unknown code %02x\n", $code); die; } $l += 5; $l += $nl; } if ($reorder) { &pagefinish; } else { &postamble if ($pageoutput); } # if ($l != $len) { # print "short file: l=$l len=$len\n"; # } close(IN); } sub printdate { local($datebcd) = @_; local(@t); @t = unpack('C6', $datebcd); printf("%02x/%02x/%02x %02x:%02x:%02x ", $t[0], $t[1], $t[2], $t[3], $t[4], $t[5]); } sub printstroke { local($stroke) = @_; local($r, $trailer, $v); local(@t); local($i); local($bits, $maxbits); local($cnt); local($npoints0, $npoints); $maxbits = -1; $r = ''; $trailer = substr($stroke, index($stroke, pack('C2', 0xff, 0xff))); $npoints0 = $npoints = unpack('x2 n', $trailer); print "% npoints=$npoints0\n" if ($debug); if ($outputstyle =~ /^(tgif|idraw)$/) { printf("NPOINTS %d\n", $npoints0); } $r = unpack('B*', $stroke); $r =~ s/\s+//g; @t = sort {length($b) <=> length($a)} (keys %huffman); $cnt = 0; $npoints *= 2; while (2 < $npoints && length($r)) { foreach $i (@t) { if (substr($r, 0, length($i)) eq $i) { $m = $i; last; } } if ($huffman{$m} == -999) { print "% huffman code length mismatch? " . "seen temrination. npoints=$npoints0\n" if ($debug); last; } elsif ($huffman{$m} == -998) { $v = unpack('c', pack('B*', substr($r, length($m), 8))); $m .= substr($r, length($m), 8); } elsif (length($m) && substr($r, 0, length($m)) eq $m) { $v = $huffman{$m}; } else { &failure("unknown huffman code ". substr($r, 0, 10), 1); print STDERR "please contact $reportto so that " . "the tool can be more perfect.\n"; &maildocument(substr($r, 0, 10)); exit 1; # print ' unknown(' . ($cnt % 2 ? 'y' : 'x') . ':' . $r. ')'; # last; } if ($cnt % 2 == 0) { $v = $v * $xscale + 5; $curx += ($v - 5); } else { $v = $v * $yscale + 5; $cury += ($v - 5); &updatebbox($curx, $cury); } print " $v"; $r = substr($r, length($m)); $cnt++; $npoints--; if ($cnt == 28) { print "\n"; $cnt = 0; } } if ($outputstyle eq 'ps' || $outputstyle eq 'eps') { print " ] ST" } print "\n"; print "% boundingbox: $boundingx0 $boundingy0 " . "$boundingx1 $boundingy1\n" if ($debug); print "\n"; } sub updatebbox { local($nx, $ny) = @_; $boundingx0 = $nx if ($nx < $boundingx0); $boundingy0 = $ny if ($ny < $boundingy0); $boundingx1 = $nx if ($nx > $boundingx1); $boundingy1 = $ny if ($ny > $boundingy1); } sub usage { print STDERR < $b} @t) { next if ($i < $startpage || $endpage < $i); $n++; print "%%Page: $n $n\n"; if ($annotate) { print "($n) pagenumber\n"; } if (-f "$tmpdir/$i.bookmark" && $annotate) { open(IN, "< $tmpdir/$i.bookmark") ||die; $t = ; close(IN); $t =~ s/\n$//; $t =~ s/\s+$//; print "($t) checkbox\n"; } print <) { print; } close(IN); print < $tmpfilename") || die; select(EPSTMP); } sub epspostprocess { local($y0, $y1); close(EPSTMP); open(IN, "< $tmpfilename") || die; select STDOUT; ($y0, $y1) = (-1 * $boundingy0, -1 * $boundingy1); while () { if ($_ =~ /^%%(Page)?BoundingBox: \(atend\)/) { print <; close(IN); ($boundingx0, $boundingy0, $boundingx1, $boundingy1) = split(/\s+/, $t); ($y0, $y1) = (-1 * $boundingy0, -1 * $boundingy1); select STDOUT; print <) { print; } close(IN); print <; close(IN); ($boundingx0, $boundingy0, $boundingx1, $boundingy1) = split(/\s+/, $t); select STDOUT; print <) { s/\n$//; s/\%.*//; s/\s+$//; s/^\s+//; next if ($_ eq ''); if (/^START (\d+) (\d+)/) { $curx = $1 - $boundingx0; $cury = $2 - $boundingy0; $curx *= $tgifscale; $cury *= $tgifscale; @xseq = ($curx); @yseq = ($cury); $cnt = 1; } elsif (/^NPOINTS (\d+)/) { $npoints = $1; } else { @t = split(/\s+/, $_); while (scalar(@t)) { $xoff = (shift @t) - 5; $yoff = (shift @t) - 5; $curx += ($xoff * $tgifscale); $cury += ($yoff * $tgifscale); push(@xseq, $curx); push(@yseq, $cury); $cnt++; } if ($cnt == $npoints) { $base = 0; while ($npoints) { $max = ($npoints < $separate) ? $npoints : $separate; print "poly('#000000',$max,["; $needcomma = 0; for ($i = 0; $i < $max; $i++) { if ($i % 8 == 0) { print "," if ($needcomma); print "\n\t"; $needcomma = 0; } print "," if ($needcomma); print $xseq[$base + $i] . ","; print $yseq[$base + $i]; $needcomma = 1; } $hinge = '0' x (($max + 3) / 4); print <; close(IN); ($boundingx0, $boundingy0, $boundingx1, $boundingy1) = split(/\s+/, $t); ($x0, $y1, $x1, $y0) = ($boundingx0, $boundingy0, $boundingx1, $boundingy1); $y0 *= -1; $y1 *= -1; $x1 -= $x0; $y1 -= $y0; $x1 *= $idrawscale; $y1 *= $idrawscale; ($x0, $y0) = (0, 0); select STDOUT; print <) { s/\n$//; s/\%.*//; s/\s+$//; s/^\s+//; next if ($_ eq ''); if (/^START (\d+) (\d+)/) { $curx = $1 - $boundingx0; $cury = $boundingy1 - $2; # flip $curx *= $idrawscale; $cury *= $idrawscale; } elsif (/^NPOINTS (\d+)/) { $npoints = $1; print <