|
|
1.1 root 1: /*
2: * fwt_TFM.c
3: * 3/30/93
4: * Build troff font width table from HP TFM file.
5: * Reference: Hewlett Packard, "Tagged Font Metric Specification".
6: * However, as of 6/7/91, steve has not seen the official spec,
7: * so this code is based on the braindamaged source code for HP TFM reader.
8: * Prints useful debugging output to stderr if compiled with DEBUG true.
9: * INCOMPLETE.
10: */
11:
12: #include <stdio.h>
13: #include "fwtable.h"
14:
15: /* Manifest constants. */
16: #define INTEL_ORDER 0x4949
17: #define MOTOROLA_ORDER 0x4D4D
18: #define N_SYMBOL_SET 14 /* bytes per symbol set entry */
19:
20: /* Tag values; this list does not include unused tags. */
21: #define T_SYMBOL_SET 404
22: #define T_POINT 406
23: #define T_NOMINAL_PT 407
24: #define T_DESIGN_UNITS 408
25: #define T_TYPE_STRUCT 410
26: #define T_STROKE_WT 411
27: #define T_SPACING 412
28: #define T_SLANT 413
29: #define T_APPEAR_WIDTH 414
30: #define T_TYPEFACE 417
31: #define T_HORIZ_ESC 433
32: #define T_SELECT_STR 442
33:
34: /* Type. */
35: typedef struct rational {
36: long r_mul; /* multiplier */
37: long r_div; /* divisor */
38: } RATIONAL;
39:
40: /* Data type lengths. */
41: #define MAXTYPE 18 /* Max data type */
42: int type_size[MAXTYPE+1] = {
43: 0, /* 0 == unused */
44: 1, /* 1 == BYTE */
45: 1, /* 2 == ASCII */
46: 2, /* 3 == SHORT */
47: 4, /* 4 == LONG */
48: 8, /* 5 == RATIONAL */
49: 0,0,0,0,0,0,0,0,0,0, /* 6 to 15 == unused */
50: 1, /* 16 == SIGNEDBYTE */
51: 2, /* 17 == SIGNEDSHORT */
52: 4 /* 18 == SIGNEDLONG */
53: };
54:
55: /* Global. */
56: int appear_width; /* Width. */
57: RATIONAL design_units; /* Design units. */
58: int Intel_order; /* Use Intel i8086 byte order. */
59: RATIONAL nominal_point; /* Nominal pointsize. */
60: RATIONAL point; /* Point size. */
61: int selector; /* Selector. */
62: int slant; /* Slant. */
63: int spacing; /* Spacing. */
64: int stroke_weight; /* Stroke weight. */
65: short *symbol_horiz; /* Symbol map horizontal esc. */
66: short *symbol_set; /* Symbol set indices. */
67: int symbol_set_size; /* Symbol set size. */
68: int symset_val; /* Encoded symbol set value. */
69: char *typeface; /* Typeface name. */
70: int type_structure; /* Type structure. */
71:
72: /*
73: * Return the GCD of two longs.
74: * Euclid's algorithm.
75: */
76: long
77: gcd(m, n) long m, n;
78: {
79: long r;
80:
81: while ((r = m % n) != 0) {
82: m = n;
83: n = r;
84: }
85: return n;
86: }
87:
88: /*
89: * Read and return a long, observing specified byte order.
90: */
91: long
92: getlong()
93: {
94: register int c;
95:
96: c = getword();
97: if (Intel_order)
98: return (((long)getword()) << 16) | c;
99: else
100: return (((long)c) << 16) | getword();
101: }
102:
103: /*
104: * Read a rational and store it through the supplied pointer.
105: */
106: void
107: getrational(rp) RATIONAL *rp;
108: {
109: rp->r_mul = getlong();
110: rp->r_div = getlong();
111: }
112:
113: /*
114: * Read a NUL-terminated string into buf[] and return a pointer to it.
115: * No overflow check, for shame...
116: */
117: char *
118: getstring()
119: {
120: register char *cp;
121:
122: for (cp = buf; *cp++ = getuchar(); )
123: ;
124: return buf;
125: }
126:
127: /*
128: * Read and return a short (2 bytes), observing specified byte order.
129: */
130: int
131: getword()
132: {
133: register int c;
134:
135: c = getuchar();
136: if (Intel_order)
137: return (getuchar() << 8) | c;
138: else
139: return (c << 8) | getuchar();
140: }
141:
142: /*
143: * Read TFM file.
144: */
145: void
146: inputTFM()
147: {
148: register int i, ntags;
149: int tag, type;
150: long size, length, curpos, offset;
151:
152: /* Read byte order word. */
153: if ((i = getword()) == INTEL_ORDER)
154: ++Intel_order;
155: else if (i != MOTOROLA_ORDER)
156: fatal("unknown byte order 0x%x in TFM header", i);
157:
158: /* Skip TFM version number. */
159: getword();
160:
161: /* Read typeface offset, warn if not equal to current position. */
162: if ((offset = getlong()) != 8L) {
163: nonfatal("warning: TFM file contains multiple typefaces; using first");
164: xseek(offset);
165: }
166:
167: /* Read tag count and process tags. */
168: ntags = getword();
169: dbprintf((stderr, "ntags=%d\n", ntags));
170: for (i = 1; i <= ntags; i++) {
171:
172: /* Read tag, type, size; compute length. */
173: tag = getword();
174: type = getword();
175: size = getlong();
176: length = size * type_size[type];
177: dbprintf((stderr, "tag=%d type=%d size=%ld length=%ld\n", tag, type, size, length));
178:
179: /* Save current position, seek to data position if required. */
180: curpos = xtell();
181: if (length > 4) {
182: offset = getlong();
183: dbprintf((stderr, "length=%ld, data at offset %ld\n", length, offset));
184: xseek(offset);
185: }
186:
187: /* Process the tag. */
188: switch(tag) {
189:
190: case T_SYMBOL_SET: read_symbol_set((int)size / N_SYMBOL_SET);
191: break;
192: case T_POINT: getrational(&point); break;
193: case T_NOMINAL_PT: getrational(&nominal_point); break;
194: case T_DESIGN_UNITS: getrational(&design_units); break;
195: case T_TYPE_STRUCT: type_structure = getuchar(); break;
196: case T_STROKE_WT: stroke_weight = getuchar(); break;
197: case T_SPACING: spacing = getword(); break;
198: case T_SLANT: slant = getword(); break;
199: case T_APPEAR_WIDTH: appear_width = PCL_width(getuchar());
200: break;
201: case T_TYPEFACE: typeface = newstring(getstring());
202: break;
203: case T_HORIZ_ESC: symbol_horiz = read_array((int)size);
204: break;
205: case T_SELECT_STR: selector = atoi(getstring()); break;
206: default:
207: dbprintf((stderr, "tag %d IGNORED\n", tag));
208: break; /* Ignore other tags. */
209: }
210:
211: /* Restore position for next tag. */
212: xseek(curpos+4);
213: }
214: }
215:
216: /*
217: * Write font width table output from TFM.
218: */
219: void
220: outputTFM()
221: {
222: register int i, j, width, max, mul;
223: long g, lmul, ldiv;
224:
225: /* Calculate maximum width of characters in character set. */
226: for (max = i = 0; i < NWIDTH && i < symbol_set_size; i++) {
227: j = symbol_set[i];
228: width = (j == -1) ? 0 : symbol_horiz[j];
229: dbprintf((stderr, "i=%d j=%d width=%d\n", i, j, width));
230: if (width > max)
231: max = width;
232: }
233: mul = (max / 256) + 1;
234: dbprintf((stderr, "max=%d\n", max));
235: dbprintf((stderr, "mul=%d\n", mul));
236: dbprintf((stderr, "design_unit: %ld/%ld\n", design_units.r_mul, design_units.r_div));
237: dbprintf((stderr, "nominal pt: %ld/%ld\n", nominal_point.r_mul, nominal_point.r_div));
238: dbprintf((stderr, "point: %ld/%ld\n", point.r_mul, point.r_div));
239:
240: /* A little fuss to convert tag values to PCL values; thanks, HP. */
241: if (vflag)
242: fprintf(stderr, "%s %s\n", typeface, symset);
243: fprintf(ofp, "%s %s", typeface, symset); /* descriptor string */
244: fputc('\0', ofp); /* NUL-terminated */
245: fputc('\0', ofp); /* PS name */
246: putshort(FLAG_PCL); /* flags */
247: putshort(0); /* fonttype */
248: putshort(0); /* orientation */
249: putshort(spacing == 0); /* spacing */
250: putshort(symset_val); /* symbol set */
251: if (spacing == 0)
252: putshort(0); /* pitch, proportional */
253: else {
254: /* UNTESTED, is this right? */
255: i = (point.r_div * nominal_point.r_div * design_units.r_mul) /
256: (point.r_mul * nominal_point.r_mul * design_units.r_div * spacing);
257: putshort(i); /* pitch, fixed spacing */
258: }
259: i = 10 * nominal_point.r_mul / nominal_point.r_div;
260: putshort(i); /* 10 * pointsize */
261: i = ((type_structure/8) << 5) | (appear_width << 2) | (slant != 0);
262: putshort(i); /* style */
263: i = (stroke_weight == 0) ? -7 : (stroke_weight-1)/17 - 7;
264: putshort(i); /* weight */
265: putshort(selector); /* face */
266:
267: /* Compute multiplier and divisor. */
268: #if 0
269: /*
270: * I think this is philosophically right,
271: * but the factors get too big when point==100/7231;
272: * just assume a point is 1/72" instead.
273: */
274: if (point.r_mul == 1 && point.r_div == 72) {
275: lmul = design_units.r_div * mul;
276: ldiv = design_units.r_mul;
277: } else {
278: lmul = design_units.r_div * point.r_mul * 72 * mul;
279: ldiv = design_units.r_mul * point.r_div;
280: }
281: #else
282: lmul = design_units.r_div * mul;
283: ldiv = design_units.r_mul;
284: #endif
285: dbprintf((stderr, "lmul=%ld ldiv=%ld\n", lmul, ldiv));
286: if ((g = gcd(lmul, ldiv)) != 1) {
287: lmul /= g;
288: ldiv /= g;
289: }
290: dbprintf((stderr, "g=%ld lmul=%ld ldiv=%ld\n", g, lmul, ldiv));
291: putshort((int)lmul); /* mul */
292: putshort((int)ldiv); /* div */
293:
294: /* Write width table. */
295: for (i = 0; i < 256; i++) {
296: j = (i < symbol_set_size) ? symbol_set[i] : -1;
297: width = (j == -1) ? 0 : symbol_horiz[j];
298: fputc(width/mul, ofp);
299: dbprintf((stderr, "i=%d width=%d\n", i, width/mul));
300: }
301: }
302:
303: /*
304: * Convert appearance width tag value to PCL value.
305: * Cf. "LJ III Printer Developer's Guide", p. 6-37.
306: */
307: int
308: PCL_width(n) int n;
309: {
310: if (n <= 20) return 4;
311: else if (n <= 47) return 3;
312: else if (n <= 74) return 2;
313: else if (n <= 101) return 1;
314: else if (n <= 182) return 0;
315: else if (n <= 209) return 6;
316: else return 7;
317: }
318:
319: /*
320: * Allocate space for n integer words.
321: * Read the array of integers and return a pointer to the array.
322: */
323: int *
324: read_array(n) int n;
325: {
326: register int i;
327: register short *ip, *p;
328:
329: p = ip = alloc(n * sizeof(short));
330: for (i = 0; i < n; i++, ip++) {
331: *ip = getword();
332: #if 0
333: dbprintf((stderr, "index=%d val=%d\n", i, *ip));
334: #endif
335: }
336: return p;
337: }
338:
339: /*
340: * Read the symbol set directory.
341: */
342: void
343: read_symbol_set(n) int n;
344: {
345: register int i, found;
346: long curpos, offset, symset_seek, symsel_seek;
347: char *s;
348:
349: dbprintf((stderr, "n_symbol_sets=%d\n", n));
350: for (found = i = 0; i < n && !found; i++) {
351: dbprintf((stderr, "symbol set %d: ", i));
352: symset_seek = getlong();
353: symsel_seek = getlong();
354: offset = getlong();
355: symbol_set_size = getword();
356: curpos = xtell();
357: xseek(symset_seek);
358: s = getstring(); /* symbol set */
359: xseek(curpos);
360: dbprintf((stderr, "symset=%s ", s));
361: dbprintf((stderr, "index offset=%ld ", offset));
362: dbprintf((stderr, "index length=%d\n", symbol_set_size));
363: if (symset == NULL) {
364: symset = newstring(s); /* no -s option, take first */
365: ++found;
366: } else if (strcmp(symset, s) == 0)
367: ++found;
368: }
369: if (!found)
370: fatal("symbol set %s not found", symset);
371: dbprintf((stderr, "found symset %s\n", symset));
372: xseek(symsel_seek);
373: s = getstring(); /* read symbol set selector */
374: dbprintf((stderr, "selector=%s ", s));
375: symset_val = atoi(s) * 32 + s[strlen(s)-1] - 64;
376: dbprintf((stderr, "symset_val=%d\n", i));
377: xseek(offset);
378: symbol_set = read_array(symbol_set_size);
379: }
380:
381: /*
382: * Seek to given offset, die on error.
383: */
384: void
385: xseek(offset) long offset;
386: {
387: if (fseek(ifp, offset, SEEK_SET) == -1L)
388: fatal("fseek failed");
389: }
390:
391: /*
392: * Return current seek position, die on error.
393: */
394: long
395: xtell()
396: {
397: register long offset;
398:
399: if ((offset = ftell(ifp)) == -1L)
400: fatal("ftell failed");
401: return offset;
402: }
403:
404: /* end of fwt_TFM.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.