#! /usr/bin/perl

#   Title:          ADDPCLT.BAT
#   Author:         M. Hosken
#   Description:
# 1.0.0 MJPH    18-MAR-1998     Original

require 'ttfmod.pl';
require 'getopts.pl';
do Getopts("d:z");

$[ = 0;
if ((defined $opt_d && !defined $ARGV[0]) || (!defined $opt_d && !defined $ARGV[1]))
    {
    die 'ADDPCLT [-d directory] [-z] <infile> <outfile>

v1.0.0, 18-Mar-1998  (c) Martin_Hosken@sil.org

Adds a PCLT table to a font which does not have one. Much of the information is
guesswork or made up from investigation made in the font.
    -d      specifies output directory for processing multiple files. In which
            case <outfile> is not used and <infile> may be a list including
            wildcards.
    -z      debug
';
}

$old = select(STDERR); $| = 1; select($old);

$fns{"PCLT"} = "make_pclt";

if (defined $opt_d)
    {
    foreach $f (@ARGV)
        {
        print STDERR "$f -> $opt_d/$f\n" unless (defined $opt_q);
        &ttfmod($f, "$opt_d/$f", *fns);
        }
    }
else
    {
    &ttfmod($ARGV[0], $ARGV[1], *fns, "PCLT");
    }

sub make_pclt
{
    local(*INFILE, *OUTFILE, $len) = @_;
    local($csum);

    return (&ttfmod'copytab(*INFILE, *OUTFILE, $len)) if ($len != 0);

    $len = 54;
    $inf[0] = 1 << 16;      # version 1
    $inf[1] = 1 << 31;      # fontnumber (derived)
    $inf[4] = 0;            # black normal uncondensed
    $inf[5] = 6 << 12;      # derived font
    $inf[7] = 629;          # symbol set Win3.1
    $inf[8] = " " x 16;    
    $inf[9] = -1;
    $inf[10] = 0x37FFFFFE;   # character complement Windows ANSI
    $inf[12] = 0;           # normal stroke weight
    $inf[13] = 0;           # normal widthType
    $inf[14] = 0;           # normal serif style
    $inf[15] = 0;           # reserved

# Now for the tricky stuff!
# Get some glyph ids
    $off = (split(':', $ttfmod'dir{'post'}))[2];
    seek(INFILE, $off, 0);                          # go to post table
    printf "%s @ %x\n", "post", $off if defined $opt_z;
    read(INFILE, $tdat, 4);                         # get format
    ($tmaj, $tmin) = unpack("n2", $tdat);
    read(INFILE, $tdat, 28);                        # chuck the rest of the header
    print STDERR "$tmaj.$tmin " if defined $opt_z;
    if ($tmaj == 1)
    { ($sid, $hid, $xid) = (3, 43, 91); }
    elsif ($tmaj == 3 || $tmaj == 4)
    {
        warn "No effective post table";
        ($sid, $hid, $xid) = (0, 0, 0);
    }
    elsif ($tmaj == 2)
    {
        read(INFILE, $tdat, 2);
        $numglyphs = unpack("n", $tdat);
        for ($i = 0; $i < $numglyphs; $i++)
        {
            if ($tmin == 5)
            {
                read(INFILE, $tdat, 1);
                $id = unpack("c", $tdat) + $i;
            }
            else
            {
                read(INFILE, $tdat, 2);
                $id = unpack("n", $tdat);
            }
            $sid = $i if ($id == 3);
            $hid = $i if ($id == 43);
            $xid = $i if ($id == 91);
        }
    }

    print STDERR ".0." if defined $opt_z;
    if ($sid == 0)
    { $inf[2] = 0; }
    else
    {
        $off = (split(':', $ttfmod'dir{'hhea'}))[2];
        seek(INFILE, $off, 0);
        read(INFILE, $tdat, 36);
        $numhmet = unpack("x34n", $tdat);

        $off = (split(':', $ttfmod'dir{'hmtx'}))[2];
        seek(INFILE, $off, 0);
        $sid = $numhmet if ($sid > $numhmet);
        read(INFILE, $tdat, $sid * 4 - 4);
        read(INFILE, $tdat, 4);
        $inf[2] = unpack("n", $tdat);
    }

    $off = (split(':', $ttfmod'dir{'head'}))[2];
    seek(INFILE, $off+50, 0);
    read(INFILE, $tdat, 4);
    ($locfmt, $glyfmt) = (unpack("n2", $tdat));

    print STDERR "[$locfmt, $glyfmt]\n" if defined $opt_z;
    $off = (split(':', $ttfmod'dir{'loca'}))[2];
    $locfmt += 1;                                   # 0 -> 1; 1 -> 2
    if ($xid != 0)
    {
        seek(INFILE, $off + $xid * $locfmt * 2, 0);
        read(INFILE, $tdat, $locfmt * 2);
        if ($locfmt == 1)
        { ($xloc) = unpack("n", $tdat) * 2; }
        else
        { ($xloc) = unpack("N", $tdat); }
    }
    if ($hid != 0)
    {
        seek(INFILE, $off + $hid * $locfmt * 2, 0);
        read(INFILE, $tdat, $locfmt * 2);
        if ($locfmt == 1)
        { $hloc = unpack("n", $tdat) * 2; }
        else
        { $hloc = unpack("N", $tdat); }
    }

    print STDERR ".3." if defined $opt_z;
    $off = (split(':', $ttfmod'dir{'glyf'}))[2];
    if ($xid != 0)
    {
        seek(INFILE, $off + $xloc, 0);
        read(INFILE, $tdat, 10);
        ($inf[3]) = unpack("x8n", $tdat);
    } else
    { $inf[3] = 0; }
    if ($hid != 0)
    {
        seek(INFILE, $off + $hloc, 0);
        read(INFILE, $tdat, 10);
        $inf[6] = unpack("x8n", $tdat);
    } else
    { $inf[6] = 0; }
    print STDERR "s = ($sid, $sloc); h = ($hid, $hloc); x = ($xid, $xloc)\n"
            if defined $opt_z;

# Now for some names
    $off = (split(':', $ttfmod'dir{'name'}))[2];
    printf STDERR "%s @ %08x\n", "name", $off if defined $opt_z;
    seek(INFILE, $off, 0);
    read(INFILE, $tdat, 6);
    ($name_num) = unpack("x2n", $tdat);
    for ($i = 0; $i < $name_num; $i++)
        {
        read(INFILE, $tdat, 12) || die "Unable to read name entry: $off";
        ($id_p, $id_e, $id_l, $name_id, $str_len, $str_off)
                = unpack("n6", $tdat);
        ($sl, $sf) = ($str_len, $str_off)
                if ($name_id == 2 && $id_p == 3 && $id_e == 1 && $id_l == 1033);
        ($fl, $ff) = ($str_len, $str_off)
                if ($name_id == 1 && $id_p == 3 && $id_e == 1 && $id_l == 1033);
        }    
    $base = tell(INFILE);
    seek(INFILE, $base + $sf, 0);
    read(INFILE, $subfam, $sl);
    $subfam =~ s/.(.)/$1/oig;
    seek(INFILE, $base + $ff, 0);
    read(INFILE, $fam, $fl);
    $fam =~ s/.(.)/$1/oig;
    substr($inf[8], 0, 11) = substr($fam, 0, 11);
    $inf[11] = substr($fam, 0, 3) . "R00";
    $off = 0;
    if ($subfam =~ m/bold/oi)
    {
        substr($inf[8], 12 + $off, 2) = "Bd";
        substr($inf[11], 3, 1) = "B";
        $off += 2;
    }
    if ($subfam =~ m/italic/oi)
    {
        substr($inf[8], 12 + $off, 2) = "It";
        substr($inf[11], 3, 1) = $off > 0 ? "J" : "I";
    }
    $inf[11] =~ tr/[a-z]/[A-Z]/;
    
    $dat = pack("N2n6A16N2A6C4", @inf);
    $csum = unpack("%32N", $dat);
    print OUTFILE $dat;
    print STDERR "$len, $csum, $ttfmod'dir{'PCLT'}";
    ($len, $csum);
}
    

