#! /usr/bin/perl # Title: TTFNAME.BAT # Author: M. Hosken # Description: Change the family name of a font, thus changing full font # name. # Requirement: PERL 4 or PERL 5. TTFMOD.PL should come with this. # # 1.1 MJPH 20-MAR-1998 Add -l, -s require 'ttfmod.pl'; require 'getopts.pl'; do Getopts("f:l:n:qs:t:"); if (!defined $ARGV[1] || !defined $opt_n) { die 'TTFNAME [-f "new_full_name"] -n "new_name" [-t num] [-q] v1.1.0, 20-Mar-1998 (c) Martin_Hosken@sil.org Renames the TTF with the given name and outputs the newly named font to . -f "name" specifies new full name (optional) as opposed to the default calculated form. -l lang language number to use (default all langs) -n "name" specifies new font family name (not optional) -q disable signon message -s filename overrides -n and gets string from file. Useful for -t -t num overrides the normal naming areas to change another string -f becomes inactive. '; } if (defined $opt_s) { open(INFILE, "$opt_s") || die "Unable to open $opt_s"; $opt_n = join('', ); $opt_n =~ s/\n/ /oig; } print "TTFNAME v1.1: Freeware, (c) M. Hosken\n" if (!defined $opt_q); $fns{"name"} = "do_name"; &ttfmod($ARGV[0], $ARGV[1], *fns); # that's all folks!! # called to process "name" table sub do_name { local(*INFILE, *OUTFILE, $len) = @_; local($csum); # copy and checksum table header read(INFILE, $name_head, 6) || die "Unable to read name table header"; ($name_num) = unpack("x2n", $name_head); print OUTFILE $name_head; $csum = unpack("%32N", $name_head); # not 4 byte boundary - grrr! $csum += unpack("%32N", substr($name_head, 4, 2) . "\0\0"); if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum -= 1; } # read name directory and calculate string space $str_tot = 0; for ($i = 0; $i < $name_num; $i++) { read(INFILE, $name_dir, 12) || die "Unable to read name entry"; $names[$i] = $name_dir; ($name_id, $str_len, $str_off) = unpack("x6n3", $name_dir); $str_tot = $str_off + $str_len if ($str_off + $str_len > $str_tot); $ids[$name_id] .= "$i:"; } foreach (@ids) { chop; } # chop trailing ':' from index list read(INFILE, $str, $str_tot) || die "Unable to glob all name strings"; # copy strings or hijack them to new string space $spos = 0; for ($i = 0; $i < $name_num; $i++) { ($id_p, $id_e, $id_l, $name_id, $str_len, $str_off) = unpack("n6", $names[$i]); if (!defined $opt_t && ($name_id == 1 || $name_id == 4) # family or full name && !(defined $opt_l && $opt_l == $id_l)) { if ($name_id == 4 && !defined $opt_f) # calculate full name? { subfamily: # find subfamily name foreach $id (split(':', $ids[2])) { ($iid_p, $iid_e, $iid_l, $iid_n, $ilen, $ioff) = unpack("n6", $names[$id]); if ($id_p == $iid_p && $id_e == $iid_e && $id_l == $iid_l) { $tstr = substr($str, $ioff, $ilen); $temp = $tstr; $temp =~ s/\0//ogi; $tstr = "" if ($temp =~ m/^regular$/oi || $temp =~ m/^normal$/oi || $temp =~ m/^standard$/oi); $tlen = length($tstr); last subfamily; } } } else # nothing to add to family name { $tstr = ""; $tlen = 0; } if ($id_p == 0 || $id_p == 3 || ($id_p == 2 && $id_e == 1)) { # 16 bit character set if ($name_id == 4 && defined $opt_f) # special full name? { $outstr .= "\0" . join("\0", split('', $opt_f)); $str_len = 2 * length($opt_f); } else # make new 16 bit string { $outstr .= "\0" . join("\0", split('', $opt_n . (($tstr eq "") ? "" : " "))) . $tstr; $str_len = 2 * length($opt_n) + $tlen + ($tstr eq "" ? 0 : 2); } } # else 8 bit elsif ($name_id == 4 && defined $opt_f) # special full name? { $outstr .= $opt_f; $str_len = length($opt_f); } else # hijack 8 bit name { $outstr .= $opt_n . ($tstr eq "" ? "" : " ") . $tstr; $str_len = length($opt_n) + $tlen + ($tstr eq "" ? 0 : 1); } } elsif (defined $opt_t && $opt_t == $name_id && !(defined $opt_l && $opt_l == $id_l)) { if ($id_p == 0 || $id_p == 3 || ($id_p == 2 && $id_e == 1)) { $outstr .= "\0" . join("\0", split('', $opt_n)); $str_len = 2 * length($opt_n); } else { $outstr .= $opt_n; $str_len = length($opt_n); } } else # no hijacking, just copy from string space { $tstr = substr($str, $str_off, $str_len); $outstr .= $tstr; $str_len = length($tstr); } $str_off = $spos; # this string offset $spos += $str_len; # next string offset $outpre = pack("n", $id_p); # handle 2 byte offset in checksums $outval = pack("n5", $id_e, $id_l, $name_id, $str_len, $str_off); print OUTFILE $outpre . $outval; # output new directory entry $csum += unpack("%32N", "\0\0" . $outpre); # checksum if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum -= 1; } $csum += unpack("%32N*", $outval . "\0\0"); if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum -= 1; } } $outstr .= "\0" x (2, 1, 0, 3)[$spos & 3]; # pad string space $csum += unpack("%32N", "\0\0" . substr($outstr, 0, 2)); # checksum if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum -= 1; } $csum += unpack("%32N*", substr($outstr, 2)); if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum -= 1; } print OUTFILE $outstr; # output string space ($spos + $name_num * 12 + 6, $csum); # return length, checksum } __END__ =head1 TITLE ttfname - renames font files =head1 SYNOPSIS TTFNAME [-f "new_full_name"] -n "new_name" [-t num] [-q] Renames the TTF with the given name and outputs the newly named font to . =head1 OPTIONS -f "name" specifies new full name (optional) as opposed to the default calculated form. -l lang language number to use (default all langs) -n "name" specifies new font family name (not optional) -q disable signon message -s filename overrides -n and gets string from file. Useful for -t -t num overrides the normal naming areas to change another string -f becomes inactive. =cut @REM=(' :end @echo off @REM ') if 0 ;