diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/font/tfmofm.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/font/tfmofm.c | 1005 |
1 files changed, 1005 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/luatexdir/font/tfmofm.c b/Build/source/texk/web2c/luatexdir/font/tfmofm.c new file mode 100644 index 00000000000..db82f94deba --- /dev/null +++ b/Build/source/texk/web2c/luatexdir/font/tfmofm.c @@ -0,0 +1,1005 @@ +/* +Copyright (c) 1996-2006 Taco Hoekwater <taco@luatex.org> + +This file is part of LuaTeX. + +LuaTeX is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +LuaTeX is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LuaTeX; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +$Id: tfmofm.c 1013 2008-02-14 00:09:02Z oneiros $ +*/ + +#include "ptexlib.h" + +#include "luatex-api.h" + +/* Here are some macros that help process ligatures and kerns */ + +#define lig_kern_start(f,c) char_remainder(f,c) +#define stop_flag 128 /* value indicating `\.{STOP}' in a lig/kern program */ +#define kern_flag 128 /* op code for a kern step */ + +#define skip_byte(z) lig_kerns[z].b0 +#define next_char(z) lig_kerns[z].b1 +#define op_byte(z) lig_kerns[z].b2 +#define rem_byte(z) lig_kerns[z].b3 +#define lig_kern_restart(c) (256*op_byte(c)+rem_byte(c)) + +/* + +The information in a \.{TFM} file appears in a sequence of 8-bit bytes. +Since the number of bytes is always a multiple of 4, we could +also regard the file as a sequence of 32-bit words, but \TeX\ uses the +byte interpretation. The format of \.{TFM} files was designed by +Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds +@^Ramshaw, Lyle Harold@> +of information in a compact but useful form. + +$\Omega$ is capable of reading not only \.{TFM} files, but also +\.{OFM} files, which can describe fonts with up to 65536 characters +and with huge lig/kern tables. These fonts will often be virtual +fonts built up from real fonts with 256 characters, but $\Omega$ +is not aware of this. + +The documentation below describes \.{TFM} files, with slight additions +to show where \.{OFM} files differ. + */ +/* +@ The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit +integers that give the lengths of the various subsequent portions +of the file. These twelve integers are, in order: +$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr +|lf|&length of the entire file, in words;\cr +|lh|&length of the header data, in words;\cr +|bc|&smallest character code in the font;\cr +|ec|&largest character code in the font;\cr +|nw|&number of words in the width table;\cr +|nh|&number of words in the height table;\cr +|nd|&number of words in the depth table;\cr +|ni|&number of words in the italic correction table;\cr +|nl|&number of words in the lig/kern table;\cr +|nk|&number of words in the kern table;\cr +|ne|&number of words in the extensible character table;\cr +|np|&number of font parameter words.\cr}}$$ +They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|, +and +$$\hbox{|lf=6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$ +Note that a \.{TFM} font may contain as many as 256 characters +(if |bc=0| and |ec=255|), and as few as 0 characters (if |bc=ec+1|). + +Incidentally, when two or more 8-bit bytes are combined to form an integer of +16 or more bits, the most significant bytes appear first in the file. +This is called BigEndian order. +@!@^BigEndian order@> + +The first 52 bytes (13 words) of an \.{OFM} file contains thirteen +32-bit integers that give the lengths of the various subsequent +portions of the file. The first word is 0 (future versions of +\.{OFM} files could have different values; what is important is that +the first two bytes be 0 to differentiate \.{TFM} and \.{OFM} files). +The next twelve integers are as above, all nonegative and less +than~$2^{31}$. We must have |bc-1<=ec<=65535|, and +$$\hbox{|lf=13+lh+2*(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np|.}$$ +Note that an \.{OFM} font may contain as many as 65536 characters +(if |bc=0| and |ec=65535|), and as few as 0 characters (if |bc=ec+1|). + +@ The rest of the \.{TFM} file may be regarded as a sequence of ten data +arrays having the informal specification +$$\def\arr$[#1]#2${\&{array} $[#1]$ \&{of} #2} +\vbox{\halign{\hfil\\{#}&$\,:\,$\arr#\hfil\cr +header&|[0..lh-1]@t\\{stuff}@>|\cr +char\_info&|[bc..ec]char_info_word|\cr +width&|[0..nw-1]fix_word|\cr +height&|[0..nh-1]fix_word|\cr +depth&|[0..nd-1]fix_word|\cr +italic&|[0..ni-1]fix_word|\cr +lig\_kern&|[0..nl-1]lig_kern_command|\cr +kern&|[0..nk-1]fix_word|\cr +exten&|[0..ne-1]extensible_recipe|\cr +param&|[1..np]fix_word|\cr}}$$ +The most important data type used here is a |@!fix_word|, which is +a 32-bit representation of a binary fraction. A |fix_word| is a signed +quantity, with the two's complement of the entire word used to represent +negation. Of the 32 bits in a |fix_word|, exactly 12 are to the left of the +binary point; thus, the largest |fix_word| value is $2048-2^{-20}$, and +the smallest is $-2048$. We will see below, however, that all but two of +the |fix_word| values must lie between $-16$ and $+16$. + +@ The first data array is a block of header information, which contains +general facts about the font. The header must contain at least two words, +|header[0]| and |header[1]|, whose meaning is explained below. +Additional header information of use to other software routines might +also be included, but \TeX82 does not need to know about such details. +For example, 16 more words of header information are in use at the Xerox +Palo Alto Research Center; the first ten specify the character coding +scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five +give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the +last gives the ``face byte.'' The program that converts \.{DVI} files +to Xerox printing format gets this information by looking at the \.{TFM} +file, which it needs to read anyway because of other information that +is not explicitly repeated in \.{DVI}~format. + +\yskip\hang|header[0]| is a 32-bit check sum that \TeX\ will copy into +the \.{DVI} output file. Later on when the \.{DVI} file is printed, +possibly on another computer, the actual font that gets used is supposed +to have a check sum that agrees with the one in the \.{TFM} file used by +\TeX. In this way, users will be warned about potential incompatibilities. +(However, if the check sum is zero in either the font file or the \.{TFM} +file, no check is made.) The actual relation between this check sum and +the rest of the \.{TFM} file is not important; the check sum is simply an +identification number with the property that incompatible fonts almost +always have distinct check sums. +@^check sum@> + +\yskip\hang|header[1]| is a |fix_word| containing the design size of +the font, in units of \TeX\ points. This number must be at least 1.0; it is +fairly arbitrary, but usually the design size is 10.0 for a ``10 point'' +font, i.e., a font that was designed to look best at a 10-point size, +whatever that really means. When a \TeX\ user asks for a font +`\.{at} $\delta$ \.{pt}', the effect is to override the design size +and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates +of the points in the font image by a factor of $\delta$ divided by the +design size. {\sl All other dimensions in the\/ \.{TFM} file are +|fix_word|\kern-1pt\ numbers in design-size units}, with the exception of +|param[1]| (which denotes the slant ratio). Thus, for example, the value +of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value +$2^{20}=1.0$, since many fonts have a design size equal to one em. +The other dimensions must be less than 16 design-size units in absolute +value; thus, |header[1]| and |param[1]| are the only |fix_word| +entries in the whole \.{TFM} file whose first byte might be something +besides 0 or 255. + +@ Next comes the |char_info| array, which contains one |@!char_info_word| +per character. Each word in this part of a \.{TFM} file contains six fields +packed into four bytes as follows. + +\yskip\hang first byte: |@!width_index| (8 bits)\par +\hang second byte: |@!height_index| (4 bits) times 16, plus |@!depth_index| + (4~bits)\par +\hang third byte: |@!italic_index| (6 bits) times 4, plus |@!tag| + (2~bits)\par +\hang fourth byte: |@!remainder| (8 bits)\par +\yskip\noindent +The actual width of a character is \\{width}|[width_index]|, in design-size +units; this is a device for compressing information, since many characters +have the same width. Since it is quite common for many characters +to have the same height, depth, or italic correction, the \.{TFM} format +imposes a limit of 16 different heights, 16 different depths, and +64 different italic corrections. + +For \.{OFM} files, two words (eight bytes) are used. +The arrangement is as follows. + +\yskip\hang first and second bytes: |@!width_index| (16 bits)\par +\hang third byte: |@!height_index| (8 bits)\par +\hang fourth byte: |@!depth_index| (8~bits)\par +\hang fifth and sixth bytes: +|@!italic_index| (14 bits) times 4, plus |@!tag| (2~bits)\par +\hang seventh and eighth bytes: |@!remainder| (16 bits)\par +\yskip\noindent +Therefore the \.{OFM} format imposes a limit of 256 different heights, +256 different depths, and 16384 different italic corrections. + +@!@^italic correction@> +The italic correction of a character has two different uses. +(a)~In ordinary text, the italic correction is added to the width only if +the \TeX\ user specifies `\.{\\/}' after the character. +(b)~In math formulas, the italic correction is always added to the width, +except with respect to the positioning of subscripts. + +Incidentally, the relation $\\{width}[0]=\\{height}[0]=\\{depth}[0]= +\\{italic}[0]=0$ should always hold, so that an index of zero implies a +value of zero. The |width_index| should never be zero unless the +character does not exist in the font, since a character is valid if and +only if it lies between |bc| and |ec| and has a nonzero |width_index|. +*/ + + /* +@ \TeX\ checks the information of a \.{TFM} file for validity as the +file is being read in, so that no further checks will be needed when +typesetting is going on. The somewhat tedious subroutine that does this +is called |read_font_info|. It has four parameters: the user font +identifier~|u|, the file name and area strings |nom| and |aire|, and the +``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor +to be applied to the design size; |s=-1000| is the normal case. +Otherwise |s| will be substituted for the design size; in this +case, |s| must be positive and less than $2048\rm\,pt$ +(i.e., it must be less than $2^{27}$ when considered as an integer). + +The subroutine opens and closes a global file variable called |tfm_file|. +It returns the value of the internal font number that was just loaded. +If an error is detected, an error message is issued and no font +information is stored; |null_font| is returned in this case. + +@d bad_tfm=11 {label for |read_font_info|} +@d abort==goto bad_tfm {do this when the \.{TFM} data is wrong} + +*/ + +/* +The |tag| field in a |char_info_word| has four values that explain how to +interpret the |remainder| field. + +\yskip\hangg|tag=0| (|no_tag|) means that |remainder| is unused.\par +\hangg|tag=1| (|lig_tag|) means that this character has a ligature/kerning +program starting at position |remainder| in the |lig_kern| array.\par +\hangg|tag=2| (|list_tag|) means that this character is part of a chain of +characters of ascending sizes, and not the largest in the chain. The +|remainder| field gives the character code of the next larger character.\par +\hangg|tag=3| (|ext_tag|) means that this character code represents an +extensible character, i.e., a character that is built up of smaller pieces +so that it can be made arbitrarily large. The pieces are specified in +|@!exten[remainder]|.\par +\yskip\noindent +Characters with |tag=2| and |tag=3| are treated as characters with |tag=0| +unless they are used in special circumstances in math formulas. For example, +the \.{\\sum} operation looks for a |list_tag|, and the \.{\\left} +operation looks for both |list_tag| and |ext_tag|. +*/ + +/* The |lig_kern| array contains instructions in a simple programming language +that explains what to do for special letter pairs. Each word in this array, +in a \.{TFM} file, is a |@!lig_kern_command| of four bytes. + +\yskip\hang first byte: |skip_byte|, indicates that this is the final program + step if the byte is 128 or more, otherwise the next step is obtained by + skipping this number of intervening steps.\par +\hang second byte: |next_char|, ``if |next_char| follows the current character, + then perform the operation and stop, otherwise continue.''\par +\hang third byte: |op_byte|, indicates a ligature step if less than~128, + a kern step otherwise.\par +\hang fourth byte: |remainder|.\par +\yskip\noindent +In an \.{OFM} file, eight bytes are used, two bytes for each field. + +In a kern step, an +additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted +between the current character and |next_char|. This amount is +often negative, so that the characters are brought closer together +by kerning; but it might be positive. + +There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where +$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is +|remainder| is inserted between the current character and |next_char|; +then the current character is deleted if $b=0$, and |next_char| is +deleted if $c=0$; then we pass over $a$~characters to reach the next +current character (which may have a ligature/kerning program of its own). + +If the very first instruction of the |lig_kern| array has |skip_byte=255|, +the |next_char| byte is the so-called right boundary character of this font; +the value of |next_char| need not lie between |bc| and~|ec|. +If the very last instruction of the |lig_kern| array has |skip_byte=255|, +there is a special ligature/kerning program for a left boundary character, +beginning at location |256*op_byte+remainder|. +The interpretation is that \TeX\ puts implicit boundary characters +before and after each consecutive string of characters from the same font. +These implicit characters do not appear in the output, but they can affect +ligatures and kerning. + +If the very first instruction of a character's |lig_kern| program has +|skip_byte>128|, the program actually begins in location +|256*op_byte+remainder|. This feature allows access to large |lig_kern| +arrays, because the first instruction must otherwise +appear in a location |<=255| in a \.{TFM} file, |<=65535| in an \.{OFM} file. + +Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy +the condition +$$\hbox{|256*op_byte+remainder<nl|.}$$ +If such an instruction is encountered during +normal program execution, it denotes an unconditional halt; no ligature +or kerning command is performed. +*/ + +/* + Extensible characters are specified by an |@!extensible_recipe|, which +consists of four bytes in a \.{TFM} file, +called |@!top|, |@!mid|, |@!bot|, and |@!rep| (in this order). +In an \.{OFM} file, each field takes two bytes, for eight in total. +These bytes are the character codes of individual pieces used to +build up a large symbol. If |top|, |mid|, or |bot| are zero, they are not +present in the built-up result. For example, an extensible vertical line is +like an extensible bracket, except that the top and bottom pieces are missing. + +Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box +if the piece isn't present. Then the extensible characters have the form +$TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent; +in the latter case we can have $TR^kB$ for both even and odd values of~|k|. +The width of the extensible character is the width of $R$; and the +height-plus-depth is the sum of the individual height-plus-depths of the +components used, since the pieces are butted together in a vertical list. +*/ + +/* +The final portion of a \.{TFM} file is the |param| array, which is another +sequence of |fix_word| values. + +\yskip\hang|param[1]=slant| is the amount of italic slant, which is used +to help position accents. For example, |slant=.25| means that when you go +up one unit, you also go .25 units to the right. The |slant| is a pure +number; it's the only |fix_word| other than the design size itself that is +not scaled by the design size. + +\hang|param[2]=space| is the normal spacing between words in text. +Note that character |" "| in the font need not have anything to do with +blank spaces. + +\hang|param[3]=space_stretch| is the amount of glue stretching between words. + +\hang|param[4]=space_shrink| is the amount of glue shrinking between words. + +\hang|param[5]=x_height| is the size of one ex in the font; it is also +the height of letters for which accents don't have to be raised or lowered. + +\hang|param[6]=quad| is the size of one em in the font. + +\hang|param[7]=extra_space| is the amount added to |param[2]| at the +ends of sentences. + +\yskip\noindent +If fewer than seven parameters are present, \TeX\ sets the missing parameters +to zero. Fonts used for math symbols are required to have +additional parameter information, which is explained later. +*/ + +/* + There are programs called \.{TFtoPL} and \.{PLtoTF} that convert + between the \.{TFM} format and a symbolic property-list format + that can be easily edited. These programs contain extensive + diagnostic information, so \TeX\ does not have to bother giving + precise details about why it rejects a particular \.{TFM} file. + +*/ + +#define tfm_abort { font_tables[f]->_font_name = NULL; \ + font_tables[f]->_font_area = NULL; \ + xfree(tfm_buffer); xfree(kerns); \ + xfree(widths); xfree(heights); xfree(depths); \ + xfree(italics); xfree(extens); xfree(lig_kerns); \ + xfree(xligs); xfree(xkerns); \ + return 0; } + +#define tfm_success { xfree(tfm_buffer); xfree(kerns); \ + xfree(widths); xfree(heights); xfree(depths); \ + xfree(italics); xfree(extens); xfree(lig_kerns); \ + xfree(xligs); xfree(xkerns); return 1; } + + +int +open_tfm_file(char *nom, char *aire, unsigned char **tfm_buf, integer *tfm_siz) { + boolean res; /* was the callback successful? */ + boolean opened; /* was |tfm_file| successfully opened?*/ + integer callback_id; + FILE *tfm_file; + /* packfilename(nom,aire,getnullstr()); */ + if(nameoffile != NULL) + xfree(nameoffile); + nameoffile = malloc(strlen(nom)+2); + strcpy(stringcast(nameoffile+1),nom); + namelength = strlen(nom); + callback_id=callback_defined(read_font_file_callback); + if (callback_id>0) { + res = run_callback(callback_id,"S->bSd",stringcast(nameoffile+1), + &opened, tfm_buf, tfm_siz); + if (res && opened && (*tfm_siz>0)) { + return 1; + } + if (!opened) + return -1; + } else { + if (ofm_open_in(tfm_file)) { + res = read_tfm_file(tfm_file,tfm_buf,tfm_siz); + b_close(tfm_file); + if (res) { + return 1; + } + } else { + return -1; + } + } + return 0; +} + + +/* + Note: A malformed \.{TFM} file might be shorter than it claims to be; + thus |eof(tfm_file)| might be true when |read_font_info| refers to + |tfm_file^| or when it says |get(tfm_file)|. If such circumstances + cause system error messages, you will have to defeat them somehow, + for example by defining |fget| to be `\ignorespaces|begin get(tfm_file);| + |if eof(tfm_file) then abort; end|\unskip'. + @^system dependencies@> +*/ + +#define fget tfm_byte++ +#define fbyte tfm_buffer[tfm_byte] + +#define read_sixteen(a) \ + { a=tfm_buffer[tfm_byte++]; \ + if (a>127) { tfm_abort; } \ + a=(a*256)+tfm_buffer[tfm_byte]; } + +#define read_sixteen_unsigned(a) \ + { a=tfm_buffer[tfm_byte++]; \ + a=(a*256)+tfm_buffer[tfm_byte]; } + +#define read_thirtytwo(a) \ + { a=tfm_buffer[++tfm_byte]; \ + if (a>127) { tfm_abort; } \ + a=(a*256)+tfm_buffer[++tfm_byte]; \ + a=(a*256)+tfm_buffer[++tfm_byte]; \ + a=(a*256)+tfm_buffer[++tfm_byte]; } + +#define store_four_bytes(z) \ + { a=tfm_buffer[++tfm_byte]; \ + a=(a*256)+tfm_buffer[++tfm_byte]; \ + a=(a*256)+tfm_buffer[++tfm_byte]; \ + a=(a*256)+tfm_buffer[++tfm_byte]; \ + z = a; } + +#define store_char_info(z) \ + { if (font_level!=-1) { \ + fget; read_sixteen_unsigned(a); \ + ci._width_index=a; \ + fget; read_sixteen_unsigned(b); \ + ci._height_index=b>>8; \ + ci._depth_index=b%256; \ + fget; read_sixteen_unsigned(c); \ + ci._italic_index=c>>8; \ + ci._tag=c%4; \ + fget; read_sixteen_unsigned(d); \ + ci._remainder=d; \ + } else { \ + a=tfm_buffer[++tfm_byte]; \ + ci._width_index=a; \ + b=tfm_buffer[++tfm_byte]; \ + ci._height_index=b>>4; \ + ci._depth_index=b%16; \ + c=tfm_buffer[++tfm_byte]; \ + ci._italic_index=c>>2; \ + ci._tag=c%4; \ + d=tfm_buffer[++tfm_byte]; \ + ci._remainder=d; \ + } } + +#define read_four_quarters(q) \ + { if (font_level!=-1) { \ + fget; read_sixteen_unsigned(a); q.b0=a; \ + fget; read_sixteen_unsigned(b); q.b1=b; \ + fget; read_sixteen_unsigned(c); q.b2=c; \ + fget; read_sixteen_unsigned(d); q.b3=d; \ + } else { \ + a=tfm_buffer[++tfm_byte]; q.b0=a; \ + b=tfm_buffer[++tfm_byte]; q.b1=b; \ + c=tfm_buffer[++tfm_byte]; q.b2=c; \ + d=tfm_buffer[++tfm_byte]; q.b3=d; \ + } } + +#define check_byte_range(z) { if ((z<bc)||(z>ec)) tfm_abort ; } + + +/* A |fix_word| whose four bytes are $(a,b,c,d)$ from left to right represents + the number + $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr + b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=0;\cr + -16+b\cdot2^{-4}+c\cdot2^{-12}+d\cdot2^{-20}&a=255.\cr}}\right.$$ + (No other choices of |a| are allowed, since the magnitude of a number in + design-size units must be less than 16.) We want to multiply this + quantity by the integer~|z|, which is known to be less than $2^{27}$. + If $|z|<2^{23}$, the individual multiplications $b\cdot z$, + $c\cdot z$, $d\cdot z$ cannot overflow; otherwise we will divide |z| by 2, + 4, 8, or 16, to obtain a multiplier less than $2^{23}$, and we can + compensate for this later. If |z| has thereby been replaced by + $|z|^\prime=|z|/2^e$, let $\beta=2^{4-e}$; we shall compute + $$\lfloor(b+c\cdot2^{-8}+d\cdot2^{-16})\,z^\prime/\beta\rfloor$$ + if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$. + This calculation must be done exactly, in order to guarantee portability + of \TeX\ between computers. +*/ + +#define store_scaled(zz) \ + { fget; a=fbyte; fget; b=fbyte; \ + fget; c=fbyte; fget; d=fbyte; \ + sw=(((((d*z)>>8)+(c*z))>>8)+(b*z)) / beta; \ + if (a==0) { zz=sw; } else if (a==255) { zz=sw-alpha; } else tfm_abort; \ + } + +#define check_existence(z) \ + { check_byte_range(z); \ + if (!char_exists(f,z)) tfm_abort; \ + } + +typedef struct tfmcharacterinfo { + integer _kern_index; + integer _lig_index; + integer _width_index; + integer _height_index; + integer _depth_index; + integer _italic_index; + integer _remainder; + unsigned char _tag ; +} tfmcharacterinfo; + +extern charinfo *copy_charinfo(charinfo *ci); + +int +read_tfm_info(internalfontnumber f, char *cnom, char *caire, scaled s) { + integer k; /* index into |font_info| */ + halfword lf,lh,bc,ec,nw,nh,nd,ni,nl,nk,ne,np,slh; /* sizes of subfiles */ + scaled *widths, *heights, *depths, *italics, *kerns; + halfword font_dir; + integer a,b,c,d; /* byte variables */ + integer i; /* counter */ + integer font_level,header_length; + integer nco,ncw,npc,nlw,neew; + tfmcharacterinfo ci; + charinfo *co; + four_quarters qw; + four_quarters *lig_kerns, *extens; + scaled sw; /* accumulators */ + integer bch_label; /* left boundary start location, or infinity */ + int bchar; /* :0..too_big_char; */ /* right boundary character, or |too_big_char| */ + integer first_two; + scaled z; /* the design size or the ``at'' size */ + integer alpha; + char beta; /* :1..16*/ + integer *xligs, *xkerns; /* aux. for ligkern processing */ + liginfo *cligs; + kerninfo *ckerns; + int fligs, fkerns; + char *tmpnam; + integer tfm_byte = 0; /* index into |tfm_buffer| */ + integer saved_tfm_byte = 0; /* saved index into |tfm_buffer| */ + unsigned char *tfm_buffer = NULL; /* byte buffer for tfm files */ + integer tfm_size = 0; /* total size of the tfm file */ + + widths=NULL; + heights=NULL; + depths = NULL; + italics = NULL; + kerns = NULL; + lig_kerns = NULL; + extens = NULL; + xkerns = NULL; + ckerns = NULL; + xligs = NULL; + cligs = NULL; + + font_dir = 0; + + memset(&ci,0,sizeof(tfmcharacterinfo)); + + if(open_tfm_file(cnom,caire,&tfm_buffer,&tfm_size)!=1) + tfm_abort; + + /* cnom can be an absolute filename, xbasename() fixes that. */ + + tmpnam=strdup(xbasename(cnom)); + if (strcmp(tmpnam+strlen(tmpnam)-4,".tfm")==0) { + *(tmpnam+strlen(tmpnam)-4) =0; + } + set_font_name(f,tmpnam); + set_font_area(f,xstrdup(caire)); /* perhaps it leaks, but it doesnt crash */ + + /* @<Read the {\.{TFM}} size fields@>; */ + nco=0; ncw=0; npc=0; + read_sixteen(first_two); + if (first_two!=0) { + font_level=-1; + lf=first_two; + fget; read_sixteen(lh); + fget; read_sixteen(bc); + fget; read_sixteen(ec); + if ((bc>ec+1)||(ec>255)) tfm_abort; + if (bc>255) { /* |bc=256| and |ec=255| */ + bc=1; ec=0; + }; + fget; read_sixteen(nw); + fget; read_sixteen(nh); + fget; read_sixteen(nd); + fget; read_sixteen(ni); + fget; read_sixteen(nl); + fget; read_sixteen(nk); + fget; read_sixteen(ne); + fget; read_sixteen(np); + header_length=6; + ncw=(ec-bc+1); + nlw=nl; + neew=ne; + } else { + fget; read_sixteen(font_level); + if (font_level!=0) tfm_abort; + read_thirtytwo(lf); + read_thirtytwo(lh); + read_thirtytwo(bc); + read_thirtytwo(ec); + if ((bc>ec+1)||(ec>65535)) tfm_abort; + if (bc>65535) { /* |bc=65536| and |ec=65535| */ + bc=1; ec=0; + }; + read_thirtytwo(nw); + read_thirtytwo(nh); + read_thirtytwo(nd); + read_thirtytwo(ni); + read_thirtytwo(nl); + read_thirtytwo(nk); + read_thirtytwo(ne); + read_thirtytwo(np); + read_thirtytwo(font_dir); /* junk */ + nlw=2*nl; + neew=2*ne; + header_length=14; + ncw=2*(ec-bc+1); + }; + if (lf!=(header_length+lh+ncw+nw+nh+nd+ni+nlw+nk+neew+np)) tfm_abort; + + /* @<Use size fields to allocate font information@>; */ + + set_font_natural_dir(f,font_dir); + set_font_bc(f,bc); + set_font_ec(f,ec); + + /* read the arrays first */ + widths = xmalloc(nw*sizeof(scaled)); + heights = xmalloc(nh*sizeof(scaled)); + depths = xmalloc(nd*sizeof(scaled)); + italics = xmalloc(ni*sizeof(scaled)); + extens = xmalloc(ne*sizeof(four_quarters)); + lig_kerns = xmalloc(nl*sizeof(four_quarters)); + kerns = xmalloc(nk*sizeof(scaled)); + + /* @<Read the {\.{TFM}} header@>; */ + + /* Only the first two words of the header are needed by \TeX82. */ + slh = lh; + if (lh<2) + tfm_abort; + store_four_bytes(font_checksum(f)); + fget; read_sixteen(z); /* this rejects a negative design size */ + fget; z=z*256+fbyte; fget; z=(z*16)+(fbyte>>4); + if (z<unity) tfm_abort; + while (lh>2) { + fget;fget;fget;fget; + lh--; /* ignore the rest of the header */ + }; + + /* read the arrays before the character info */ + + set_font_dsize(f,z); + if (s!=-1000) { + z = (s>=0 ? s : xn_over_d(z,-s,1000)); + } + set_font_size(f,z); + + if (np>7) + set_font_params(f,np); + + saved_tfm_byte = tfm_byte; + tfm_byte = (header_length+slh+ncw)*4 - 1; + + /* @<Replace |z| by $|z|^\prime$ and compute $\alpha,\beta$@>; */ + + alpha=16; + while (z>=040000000) { + z=z>>1; alpha=alpha+alpha; + }; + beta=256/alpha; alpha=alpha*z; + + /* @<Read box dimensions@>; */ + + for (k=0;k<nw;k++) { + store_scaled(sw); widths[k] = sw; + } + if (widths[0]!=0) /* \\{width}[0] must be zero */ + tfm_abort; + for (k=0;k<nh;k++) { + store_scaled(sw); heights[k] = sw; + } + if (heights[0]!=0) + tfm_abort; /* \\{height}[0] must be zero */ + for (k=0;k<nd;k++) { + store_scaled(sw); depths[k] = sw; + } + if (depths[0]!=0) + tfm_abort; /* \\{depth}[0] must be zero */ + for (k=0;k<ni;k++) { + store_scaled(sw); italics[k] = sw; + } + if (italics[0]!=0) + tfm_abort; /* \\{italic}[0] must be zero */ + + + /* @<Read ligature/kern program@>; */ + + bch_label=nl; /* infinity*/ + bchar=65536; + if (nl>0) { + for (k=0;k<nl;k++) { + read_four_quarters(qw); + lig_kerns[k] = qw; + if (a>128) { + if (256*c+d>=nl) tfm_abort; + if (a==255 && k==0) bchar=b; + } else { + /* if (b!=bchar) check_existence(b); */ + if (c<128) { + /* check_existence(d); */ /* check ligature */ + } else if (256*(c-128)+d>=nk) { + tfm_abort; /* check kern */ + } + if ((a<128) && (k-0+a+1>=nl)) tfm_abort; + }; + }; + if (a==255) bch_label=256*c+d; + }; + + /* the actual kerns */ + for (k=0;k<nk;k++) { + store_scaled(sw); kerns[k] = sw; + } + + /* @<Read extensible character recipes@>; */ + for (k=0;k<ne;k++) { + read_four_quarters(qw); extens[k] = qw; + } + + /* @<Read font parameters@>; */ + + if (np>7) { + set_font_params(f,np); + } + for (k=1;k<=np;k++) { + if (k==1) { /* the |slant| parameter is a pure number */ + fget; sw=fbyte; + if (sw>127) sw=sw-256; + fget; sw=sw*256+fbyte; + fget; sw=sw*256+fbyte; + fget; sw=(sw*16)+(fbyte>>4); + set_font_param(f,k,sw); + } else { + store_scaled(font_param(f,k)); + } + } + + /* + We check to see that the \.{TFM} file doesn't end prematurely; but + no error message is given for files having more than |lf| words. + */ + + if (tfm_byte<tfm_size-1) tfm_abort; + + tfm_byte = saved_tfm_byte ; + + /* fix up the left boundary character */ + fligs = 0; + fkerns = 0; + if (bch_label != nl ) { + k = bch_label; + /* + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + */ + while (1) { + if (skip_byte(k) <= stop_flag) { + if(op_byte(k) >= kern_flag) { /* kern */ + fkerns++; + } else { /* lig */ + fligs++; + } + } + if (skip_byte(k) == 0) { + k++; + } else { + if (skip_byte(k) >= stop_flag) + break; + k += skip_byte(k) + 1; + } + } + } + if (fkerns >0 || fligs > 0) { + if (fligs>0) cligs = xcalloc((fligs+1),sizeof(liginfo)); + if (fkerns>0) ckerns = xcalloc((fkerns+1),sizeof(kerninfo)); + fligs = 0; + fkerns = 0; + k = bch_label; + /* + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + */ + while (1) { + if (skip_byte(k) <= stop_flag) { + if(op_byte(k) >= kern_flag) { /* kern */ + set_kern_item(ckerns[fkerns],next_char(k),kerns[256*(op_byte(k)-128)+rem_byte(k)]); + fkerns++; + } else { /* lig */ + set_ligature_item(cligs[fligs],(op_byte(k)*2+1),next_char(k),rem_byte(k)); + fligs++; + } + } + if (skip_byte(k) == 0) { + k++; + } else { + if (skip_byte(k) >= stop_flag) + break; + k += skip_byte(k) + 1; + } + } + if (fkerns>0 || fligs>0){ + co = get_charinfo(f,left_boundarychar); + if (fkerns>0) { + set_kern_item(ckerns[fkerns],end_kern,0); + fkerns++; + set_charinfo_kerns(co,ckerns); + } + if (fligs>0){ + set_ligature_item(cligs[fligs],0,end_ligature,0); + fligs++; + set_charinfo_ligatures(co,cligs); + } + set_charinfo_remainder(co,0); + } + } + + /* @<Read character data@>; */ + for (k=bc;k<=ec;k++) { + store_char_info(k); + if (ci._width_index==0) + continue; + if (ci._width_index>=nw||ci._height_index>=nh|| + ci._depth_index>=nd||ci._italic_index>=ni) tfm_abort; + d = ci._remainder; + switch (ci._tag) { + case lig_tag: if (d>=nl) tfm_abort; break; + case ext_tag: if (d>=ne) tfm_abort; break; + case list_tag: + /* We want to make sure that there is no cycle of characters linked together + by |list_tag| entries, since such a cycle would get \TeX\ into an endless + loop. If such a cycle exists, the routine here detects it when processing + the largest character code in the cycle. + */ + check_byte_range(d); + while (d<k) { /* current_character == k */ + if (char_tag(f,d)!=list_tag) + goto NOT_FOUND; /* not a cycle */ + d=char_remainder(f,d); /* next character on the list */ + }; + if (d==k) tfm_abort; /* yes, there's a cycle */ + NOT_FOUND: + break; + } + /* put it in the actual font */ + co = get_charinfo(f,k); + set_charinfo_index (co,k); + set_charinfo_tag (co,ci._tag); + if (ci._tag == ext_tag) { + set_charinfo_extensible(co, + extens[ci._remainder].b0, /* top */ + extens[ci._remainder].b2, /* bot */ + extens[ci._remainder].b1, /* mid */ + extens[ci._remainder].b3); /* rep */ + set_charinfo_remainder (co,0); + } else { + set_charinfo_remainder (co,ci._remainder); + } + set_charinfo_width (co,widths[ci._width_index]); + set_charinfo_height (co,heights[ci._height_index]); + set_charinfo_depth (co,depths[ci._depth_index]); + set_charinfo_italic (co,italics[ci._italic_index]); + }; + + /* first pass: count ligs and kerns */ + + xligs = xcalloc((ec+1),sizeof(integer)); + xkerns = xcalloc((ec+1),sizeof(integer)); + + for (i=bc;i<=ec;i++) { + if (char_tag(f,i) == lig_tag) { + k = lig_kern_start(f,i); + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + /* now k is the start index */ + while (1) { + if (skip_byte(k) <= stop_flag) { + if(op_byte(k) >= kern_flag) { /* kern */ + xkerns[i]++; + if (next_char(k) == bchar) + xkerns[i]++; + } else { /* lig */ + xligs[i]++; + if (next_char(k) == bchar) + xligs[i]++; + } + } + if (skip_byte(k) == 0) { + k++; + } else { + if (skip_byte(k) >= stop_flag) + break; + k += skip_byte(k) + 1; + } + } + } + } + + cligs = NULL; + ckerns = NULL; + + for (i=bc;i<=ec;i++) { + fligs = 0; + fkerns = 0; + if (char_tag(f,i) == lig_tag) { + k = lig_kern_start(f,i); + if (skip_byte(k) > stop_flag) + k = lig_kern_restart(k); + /* now k is the start index */ + if (xligs[i]>0) cligs = xcalloc((xligs[i]+1),sizeof(liginfo)); + if (xkerns[i]>0) ckerns = xcalloc((xkerns[i]+1),sizeof(kerninfo)); + while (1) { + if (skip_byte(k) <= stop_flag) { + if(op_byte(k) >= kern_flag) { /* kern */ + if (next_char(k) == bchar) { + set_kern_item(ckerns[fkerns],right_boundarychar,kerns[256*(op_byte(k)-128)+rem_byte(k)]); + fkerns++; + } + set_kern_item(ckerns[fkerns],next_char(k),kerns[256*(op_byte(k)-128)+rem_byte(k)]); + fkerns++; + } else { /* lig */ + if (next_char(k) == bchar) { + set_ligature_item(cligs[fligs],(op_byte(k)*2+1),right_boundarychar,rem_byte(k)); + fligs++; + } + set_ligature_item(cligs[fligs],(op_byte(k)*2+1),next_char(k),rem_byte(k)); + fligs++; + } + } + if (skip_byte(k) == 0) { + k++; + } else { + if (skip_byte(k) >= stop_flag) + break; + k += skip_byte(k) + 1; + } + } + if (fkerns>0 || fligs>0){ + co = get_charinfo(f,i); + if (fkerns>0) { + set_kern_item(ckerns[fkerns],end_kern,0); + fkerns++; + set_charinfo_kerns(co,ckerns); + } + if (fligs>0){ + set_ligature_item(cligs[fligs],0,end_ligature,0); + fligs++; + set_charinfo_ligatures(co,cligs); + } + set_charinfo_remainder(co,0); + } + } + } + + + /* @<Make final adjustments and |goto done|@> */ + + /* Now to wrap it up, we have checked all the necessary things about the \.{TFM} + file, and all we need to do is put the finishing touches on the data for + the new font. + */ + + if (bchar!= 65536) { + co = copy_charinfo(char_info(f,bchar)); + set_right_boundary(f,co); + } + + tfm_success; +} + |