|
|
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.