#! /usr/bin/perl
#   Title:          HACKOS2.BAT
#   Author:         M. Hosken
#   Description:
# 1.001 MJPH    05-AUG-1997     Fix &makestr() to work properly
# 1.002 MJPH    06-AUG-1997     Add -d & -q support
# 1.1   MJPH    22-MAR-1998     Add -f support
# 1.2   MJPH    11-JUN-1999     Add -t support
# 1.3   MJPH     9-AUG-1999     Fix -d glob
# 1.4   MJPH    17-FEB-2000     Fix typo for type 1 tables
# 1.5   MJPH    19-SEP-2000     Add -n, -x
# 1.6   MJPH    10-NOV-2000     Add -v
# 1.7	RMH	 2-Dec-2003	Add -w

require 'ttfmod.pl';
require 'getopts.pl';
do Getopts("c:d:f:n:p:qt:u:v:x:w:");

$[ = 0;
if ((defined $opt_d && !defined $ARGV[0]) || (!defined $opt_d && !defined $ARGV[1]))
    {
    die 'HACKOS2 [-c hex] [-d directory] [-f fsSelection] [-p hex] [-q]
        [-t num] [-u hex] [-w width] <infile> <outfile>

v1.6.0, 10-NOV-2000  (c) martin_hosken@sil.org

Hacks the OS/2 table of a ttf file copying from infile to outfile.
    -c      change codepage information (a 64 bit hex number)
    -d      specifies output directory for processing multiple files. In which
            case <outfile> is not used and <infile> may be a list including
            wildcards.
    -f      fsSelection value (16 bit hex) (e.g. 4240 for Thai fonts)
    -n      sets usFirstCharIndex given a hex value
    -p      change panose info
                (10 bytes of hex in reverse order: 0A090807060504030201)
    -q      Quiet mode (do not list names as they are processed)
    -t      Sets fsType (embedding) information (decimal)
    -u      change unicode info (a 128 bit hex number)
    -v      sets vendor tag to the first 4 chars of the string
    -w      set average char width (decimal)
    -x      sets usLastCharIndex given a hex value

For example, to convert a Win3.1 ANSI font to Win95 use the following:
    hackos2 -c01 -u03 old.ttf new.ttf
or for a Symbol font use:
    hackos2 -c80000000 -u0 old.ttf new.ttf
Or to revert:
    hackos2 -cnone other.ttf new.ttf
';
    }

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

if ($opt_c =~ m/^none/oi)
    {
    undef $opt_c;
    $revert = 1;
    }
else
    { $revert = 0; }

$fns{"OS/2"} = "hackos2";

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

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

    read(INFILE, $dat, 78);
    $ver = unpack("n", substr($dat, 0, 2));
    if ($revert)
        {
        if ($ver == 1)
            {
            substr($dat, 0, 2) = pack("n", 0);
            $len = 78;
            }
        }
    else
        {
        if ($ver == 1)
            {
            read(INFILE, $dat1, 8);
            $dat .= $dat1;
            }
        elsif (defined $opt_c)
            {
            substr($dat, 0, 2) = pack("n", 1);
            $dat .= pack("x8", 0);
            $len = 86;
            }
        }
    if (defined $opt_c)
        { substr($dat, 78, 8) = &makestr($opt_c, 8, 4); }
#                pack("NN", unpack("LL", &makestr($opt_c, 8))); }
    if (defined $opt_p)
        { substr($dat, 32, 10) = &makestr($opt_p, 10, 1); }
    if (defined $opt_u)
        { substr($dat, 42, 16) = &makestr($opt_u, 16, 4); }
#                pack("NNNN", unpack("LLLL", &makestr($opt_u, 16))); }
    if (defined $opt_f)
        { substr($dat, 62, 2) = &makestr($opt_f, 2, 2); }
    if (defined $opt_t)
        { substr($dat, 8, 2) = pack("n", $opt_t); }
    if (defined $opt_n)
        { substr($dat, 64, 2) = &makestr($opt_n, 2, 2); }
    if (defined $opt_x)
        { substr($dat, 66, 2) = &makestr($opt_x, 2, 2); }
    if (defined $opt_v)
        { substr($dat, 58, 4) = pack("A4", $opt_v); }
    if (defined $opt_w)
        { substr($dat, 2, 2) = pack("n", $opt_w); }
    $csum = unpack("%32N", $dat);
    print OUTFILE $dat;
    ($len, $csum);
    }

# &makestr($string, $number_of_bytes, $granule)
#   converts $string as a big hex number into a packed string no longer than
#   $number_of_bytes long. The string is then swapped on the $granule byte
#   boundary so that the least significant bundle comes first. This is unless
#   $granule is 0 or -ve.
#
#   returns its string in Network order.

sub makestr
    {
    local($str, $len, $group) = @_;
    local($res, $have, $temp);

    $have = length($str);
    if ($have % 2)
        {
        $str = "0" . $str;
        $have++;
        }
    $have >>= 1;
    $have = $len if ($have > $len);
    $res = "\000" x ($len - $have);
    for ($i = 0; $i < $have; $i++)
        { $res .= pack("C", hex(substr($str, $i << 1, 2))); }
    if ($group > 0)
        {
        $temp = "";
        for ($i = 0; $i < $len / $group; $i++)
            {
            $temp = substr($res, $i * $group, $group) . $temp;
            }
        $res = $temp;
        }
    ($res);
    }
