Back to index

tetex-bin  3.0
tfm.c
Go to the documentation of this file.
00001 /* $Id: tfm.c,v 2.0 1996/05/12 22:25:04 neumann Exp $ */
00002 /* Read tfm widths resident font support in dvilj. Originally
00003    written by kb@cs.umb.edu in early 1994. Public domain. */
00004 
00005 #ifdef KPATHSEA
00006 #include <kpathsea/config.h>
00007 #include <kpathsea/c-fopen.h>
00008 #include <kpathsea/lib.h>
00009 #include <kpathsea/tex-file.h>
00010 #include <c-auto.h>
00011 #else
00012 #include <stdio.h>
00013 #include <stdlib.h>
00014 extern char* TFMpath;
00015 #endif
00016 
00017 #include "config.h" /* for STRSIZE and tfm_info_type, at least */
00018                     /* and for IO-functions (since RISC OS) */
00019 
00020 #ifdef NeedVarargsPrototypes
00021 extern void Fatal(char *, ...);
00022 #else
00023 void Fatal();
00024 #endif
00025 
00026 #ifdef vms
00027 #include <ssdef.h>
00028 #include <stsdef.h>
00029 #define getenv vms_getenv
00030 #endif
00031 
00032 #if NeedFunctionPrototypes
00033 # define DVIPROTO(x) x
00034 #else
00035 # define DVIPROTO(x) ()
00036 #endif
00037 
00038 /* Defined in dvi2xx.c. */
00039 extern long4 NoSignExtend DVIPROTO((FILEPTR, int));
00040 
00041 #define TFM_GET_TWO()  NoSignExtend (tfm_fp, 2)
00042 #define TFM_GET_FOUR() NoSignExtend (tfm_fp, 4)
00043 
00044 extern bool G_quiet;
00045 extern void Warning();
00046 
00047 /* Read N words (N * 4 bytes) from TFM_FP and return it in *OUTBUF, unless
00048    OUTBUF==NULL, in which case throw them away. */
00049 
00050 static void
00051 #if NeedFunctionPrototypes
00052 tfm_get_n (FILEPTR tfm_fp, unsigned nwords, unsigned char **outbuf)
00053 #else
00054 tfm_get_n (tfm_fp, nwords, outbuf)
00055     FILE *tfm_fp;
00056     unsigned nwords;
00057     void **outbuf;
00058 #endif
00059 {
00060   unsigned n = nwords * 4;
00061   void *buf = (void *) malloc (n);
00062 
00063   if (buf == NULL) {BCLOSE(tfm_fp); Fatal("(tfm): out of memory error!\n");}
00064   read_multi (buf, 1, n, tfm_fp);
00065   if (FEOF(tfm_fp)) {
00066     BCLOSE(tfm_fp); Fatal("dvilj(tfm): Could not read %u bytes from TFM file.\n", n);
00067     exit (1);
00068   }
00069 
00070   /* If OUTBUF is null, free what we just read, else return it. */
00071   if (outbuf) {
00072     *outbuf = buf;
00073   } else {
00074     free (buf);
00075   }
00076 }
00077 
00078 
00079 /* Read a string in BCPL format from DATA into STR, and terminate with a
00080    null byte. First byte of DATA says how many characters follow.
00081    Assume STR is long enough.  */
00082 
00083 static void
00084 #if NeedFunctionPrototypes
00085 get_bcpl (unsigned char *data, unsigned char *str)
00086 #else
00087 get_bcpl (data, str)
00088 unsigned char *data;
00089 unsigned char *str;
00090 #endif
00091 {
00092   unsigned length;
00093   
00094   for (length = *(data ++); length; length --) {
00095     *(str ++) = *(data ++);
00096   }
00097  *str = 0;
00098 }
00099 
00100 /* Header word 18:
00101      2 bytes: "KN" for Karl and Norm---this identifies our extensions
00102      1 byte : 1 if proportional, 0 otherwise
00103      1 byte : reserved (to extend the style, if necessary)
00104    Header word 19:
00105      2 bytes: PCL style selection number
00106      1 byte : reserved (to extend weight, if necessary)
00107      1 byte : weight (signed, 2's complement, valid -7 to +7)
00108    Header word 20:
00109      2 bytes: reserved (to extend typeface id, if necessary)
00110      2 bytes: PCL typeface selection number
00111 
00112    The first (BigEndian) byte of header word #18 is DATA[0].
00113    Assume DATA is long enough for everything we might try to read. */
00114 
00115 static bool
00116 #if NeedFunctionPrototypes
00117 get_pcl_info (unsigned char *data, unsigned *spacing, unsigned *style, 
00118              int *weight, unsigned *typeface_id)
00119 #else
00120 get_pcl_info (data, spacing, style, weight, typeface_id)
00121     unsigned char *data;
00122     unsigned *spacing;
00123     unsigned *style;
00124     int *weight;
00125     unsigned *typeface_id;
00126 #endif
00127 {
00128   /* No magic number for our extensions => forget it. */
00129   if (data[0] != 'K' && data[1] != 'N')
00130     return _FALSE;
00131 
00132   *spacing = data[(0* 4) + 2]; /* Third byte of first word. */
00133 
00134   /* First two bytes of second word. */
00135   *style = (data[(1 * 4)] << 8) + data[(1 * 4) + 1];
00136 
00137   /* Last byte of second word, signed two-complement. */
00138   *weight = data[(1 * 4) + 3];
00139   if (*weight >= 128) *weight -= 256;
00140 
00141   /* Effectively all four bytes of third word. */
00142   *typeface_id = (data[(2 * 4) + 0] << 24) + (data[(2 * 4) + 1] << 16)
00143                + (data[(2 * 4) + 2] << 8)  + (data[(2 * 4) + 3]);
00144 
00145   return _TRUE;
00146 }
00147 
00148 /* If the TFM file NAME exists, set the elements of RET and return true.
00149    Otherwise, return false.  */
00150 
00151 bool
00152 #if NeedFunctionPrototypes
00153 tfm_read_info (char *name, tfm_info_type *ret)
00154 #else
00155 tfm_read_info (name, ret)
00156     char *name;
00157     tfm_info_type *ret;
00158 #endif
00159 {
00160   /* Don't use a structure for this, since then it might occupy more
00161      than the exactly four bytes that we need. */
00162   unsigned char *char_info;
00163   FILEPTR tfm_fp;
00164   unsigned char *header_data;
00165   unsigned char *width_raw; /* array of 1-byte data */
00166   unsigned long4 *width_table; /* array of 4-byte fixes */
00167   unsigned i;
00168   unsigned lh, bc, ec, nw, nh, nd, ni, nl, nk, ne, np;
00169 #ifdef KPATHSEA
00170   char *full_name = kpse_find_tfm (name);
00171 
00172   if (full_name == NULL) {
00173     return _FALSE;
00174   }
00175   tfm_fp = xfopen (full_name, FOPEN_RBIN_MODE);
00176 #else /* not KPATHSEA */
00177   char full_name[STRSIZE];
00178   if (findfile(TFMpath, name, 0, full_name, _TRUE, 0)) {
00179 
00180     /* fprintf(ERR_STREAM,"full_name=<%s>\n", full_name);*/
00181     tfm_fp = BINOPEN(full_name);
00182     if (tfm_fp == FPNULL) {
00183       /* this can happen, if the calculation for max number of open
00184        * files has to be corrected
00185        */
00186       fprintf(ERR_STREAM,"Error: file <%s> could not be opened\n", full_name);
00187       return _FALSE;
00188     }
00189   } else {
00190     Warning("tfm file %s.tfm not found on path <%s>\n", name, TFMpath);
00191     return _FALSE;
00192   }
00193 #endif /* not KPATHSEA */
00194 
00195   (void) TFM_GET_TWO ();   /* word length of file */
00196   lh = TFM_GET_TWO ();     /* words of header data */
00197   bc = TFM_GET_TWO ();     /* smallest character code */
00198   ec = TFM_GET_TWO ();     /* largest character code */
00199   nw = TFM_GET_TWO ();     /* words in width table */
00200   nh = TFM_GET_TWO ();     /* words in height table */
00201   nd = TFM_GET_TWO ();     /* words in depth table */
00202   ni = TFM_GET_TWO ();     /* words in italic correction table */
00203   nl = TFM_GET_TWO ();     /* words in lig/kern table */
00204   nk = TFM_GET_TWO ();     /* words in kern table */
00205   ne = TFM_GET_TWO ();     /* words in extensible char table */
00206   np = TFM_GET_TWO ();     /* words of font parameter data */
00207 
00208   tfm_get_n (tfm_fp, lh, &header_data);
00209   /* Only two headerbyte words are required by the TFM format, so don't
00210      insist on all this extra stuff. */
00211   if (lh > 2) {
00212     get_bcpl (header_data + (2 * 4), ret->coding_scheme);
00213   } else {
00214     ret->coding_scheme[0] = 0;
00215   }
00216 
00217   if (lh > 12) {
00218     get_bcpl (header_data + (12 * 4), ret->family);
00219   } else {
00220     ret->family[0] = 0;
00221   }
00222 
00223   /* Sorry for the convoluted logic. The idea is that if the family
00224      is HPAUTOTFM, we better have our extensions -- so if we don't
00225      have enough header words, or if we don't find what we need in
00226      the header words, something's seriously wrong, and we shouldn't
00227      claim to have succeeded at reading a good TFM file.  */
00228 
00229   if (strcmp ((char *)ret->family, "HPAUTOTFM") == 0
00230       && (lh < 20
00231           || !get_pcl_info (&(header_data[18 * 4]),
00232                             &ret->spacing, &ret->style, &ret->weight,
00233                             &ret->typeface_id))) {
00234     BCLOSE (tfm_fp);
00235     return _FALSE;
00236   }
00237 
00238   /* Initialize our returned array of widths to zero, since the TFM file
00239      need not contain info for all character codes. */
00240   for (i = 0; i < bc; i++) {
00241     ret->widths[i] = 0;
00242   }
00243   for (i = ec + 1; i < 256; i++) {
00244     ret->widths[i] = 0;
00245   }
00246 
00247   /* The char_info is one word (four bytes) for each character in the font. */
00248   tfm_get_n (tfm_fp, ec - bc + 1, &char_info);
00249 
00250   /* The width table is just nw words. */
00251   tfm_get_n (tfm_fp, nw, &width_raw);
00252   width_table = (unsigned long4 *) malloc (nw * 4);
00253   if (width_table == NULL) {BCLOSE(tfm_fp); Fatal("dvilj(tfm): out of memory!\n");}
00254 
00255   /* But the width table contains four-byte numbers, so have to convert
00256      from BigEndian to host order. */
00257   for (i = 0; i < nw; i++) {
00258     unsigned byte_offset = i * 4;
00259     unsigned b1 = width_raw[byte_offset];
00260     unsigned b2 = width_raw[byte_offset + 1];
00261     unsigned b3 = width_raw[byte_offset + 2];
00262     unsigned b4 = width_raw[byte_offset + 3];
00263     width_table[i] = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
00264   }
00265 
00266   /* For each character, retrieve and store the TFM width. */
00267   for (i = bc; i <= ec; i++) {
00268     unsigned char w_i = char_info[(i - bc) * 4];
00269     ret->widths[i] = width_table[w_i];
00270   }
00271 
00272   /* Throw away everything up to the second font parameter. (Could just
00273      seek, but I don't want to pull in the include files, etc.) */
00274   if (np >= 2) {
00275     tfm_get_n (tfm_fp, nh + nd + ni + nl + nk + ne + 1, NULL);
00276     ret->interword = TFM_GET_FOUR ();
00277   } else {
00278     ret->interword = 0;
00279   }
00280 
00281   free (header_data);
00282   free (char_info);
00283   free (width_raw);
00284   free (width_table);
00285 
00286   BCLOSE (tfm_fp);
00287   return _TRUE;
00288 }