1114402Sru// -*- C++ -*- 2151497Sru/* Copyright (C) 1994, 2000, 2001, 2003, 2004 Free Software Foundation, Inc. 3114402Sru Written by James Clark (jjc@jclark.com) 4114402Sru 5114402SruThis file is part of groff. 6114402Sru 7114402Srugroff is free software; you can redistribute it and/or modify it under 8114402Sruthe terms of the GNU General Public License as published by the Free 9114402SruSoftware Foundation; either version 2, or (at your option) any later 10114402Sruversion. 11114402Sru 12114402Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 13114402SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 14114402SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15114402Srufor more details. 16114402Sru 17114402SruYou should have received a copy of the GNU General Public License along 18114402Sruwith groff; see the file COPYING. If not, write to the Free Software 19151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20114402Sru 21114402Sru/* 22114402SruTODO 23114402Srudevise new names for useful characters 24114402Sruoption to specify symbol sets to look in 25114402Sruput filename in error messages (or fix lib) 26114402Sru*/ 27114402Sru 28114402Sru#include "lib.h" 29114402Sru 30151497Sru#include <stdio.h> 31114402Sru#include <stdlib.h> 32151497Sru#include <string.h> 33151497Sru#include <ctype.h> 34114402Sru#include <math.h> 35114402Sru#include <errno.h> 36114402Sru#include "assert.h" 37114402Sru#include "posix.h" 38114402Sru#include "errarg.h" 39114402Sru#include "error.h" 40114402Sru#include "cset.h" 41114402Sru#include "nonposix.h" 42151497Sru#include "unicode.h" 43114402Sru 44114402Sruextern "C" const char *Version_string; 45151497Sruextern const char *hp_msl_to_unicode_code(const char *); 46114402Sru 47114402Sru#define SIZEOF(v) (sizeof(v)/sizeof(v[0])) 48151497Sru#define equal(a, b) (strcmp(a, b) == 0) 49151497Sru// only valid if is_uname(c) has returned true 50151497Sru#define is_decomposed(c) strchr(c, '_') 51114402Sru 52151497Sru#define NO 0 53151497Sru#define YES 1 54114402Sru 55151497Sru#define MSL 0 56151497Sru#define SYMSET 1 57151497Sru#define UNICODE 2 58151497Sru 59151497Sru#define UNNAMED "---" 60151497Sru 61151497Srustatic double multiplier = 3.0; // make Agfa-based unitwidth an integer 62151497Sru 63114402Sruinline 64114402Sruint scale(int n) 65114402Sru{ 66151497Sru return int(n * multiplier + 0.5); 67114402Sru} 68114402Sru 69114402Sru// tags in TFM file 70114402Sru 71114402Sruenum tag_type { 72114402Sru min_tag = 400, 73114402Sru type_tag = 400, 74151497Sru copyright_tag = 401, 75151497Sru comment_tag = 402, 76151497Sru charcode_tag = 403, // MSL for Intellifont, Unicode for TrueType 77114402Sru symbol_set_tag = 404, 78151497Sru unique_identifier_tag = 405, 79114402Sru inches_per_point_tag = 406, 80151497Sru nominal_point_size_tag = 407, 81114402Sru design_units_per_em_tag = 408, 82114402Sru posture_tag = 409, 83151497Sru type_structure_tag = 410, 84114402Sru stroke_weight_tag = 411, 85114402Sru spacing_tag = 412, 86114402Sru slant_tag = 413, 87114402Sru appearance_width_tag = 414, 88151497Sru serif_style_tag = 415, 89151497Sru font_name_tag = 417, 90151497Sru typeface_source_tag = 418, 91151497Sru average_width_tag = 419, 92151497Sru max_width_tag = 420, 93114402Sru word_spacing_tag = 421, 94151497Sru recommended_line_spacing_tag = 422, 95151497Sru cap_height_tag = 423, 96114402Sru x_height_tag = 424, 97151497Sru max_ascent_tag = 425, 98151497Sru max_descent_tag = 426, 99114402Sru lower_ascent_tag = 427, 100114402Sru lower_descent_tag = 428, 101151497Sru underscore_depth_tag = 429, 102151497Sru underscore_thickness_tag = 430, 103151497Sru uppercase_accent_height_tag = 431, 104151497Sru lowercase_accent_height_tag = 432, 105114402Sru width_tag = 433, 106151497Sru vertical_escapement_tag = 434, 107114402Sru left_extent_tag = 435, 108114402Sru right_extent_tag = 436, 109114402Sru ascent_tag = 437, 110114402Sru descent_tag = 438, 111114402Sru pair_kern_tag = 439, 112151497Sru sector_kern_tag = 440, 113151497Sru track_kern_tag = 441, 114114402Sru typeface_tag = 442, 115151497Sru panose_tag = 443, 116114402Sru max_tag = 443 117151497Sru}; 118114402Sru 119151497Sruconst char *tag_name[] = { 120151497Sru "Symbol Set", 121151497Sru "Font Type" // MSL for Intellifont, Unicode for TrueType 122151497Sru}; 123151497Sru 124114402Sru// types in TFM file 125114402Sruenum { 126151497Sru BYTE_TYPE = 1, 127151497Sru ASCII_TYPE = 2, // NUL-terminated string 128114402Sru USHORT_TYPE = 3, 129151497Sru LONG_TYPE = 4, // unused 130151497Sru RATIONAL_TYPE = 5, // 8-byte numerator + 8-byte denominator 131151497Sru SIGNED_BYTE_TYPE = 16, // unused 132151497Sru SIGNED_SHORT_TYPE = 17, 133151497Sru SIGNED_LONG_TYPE = 18 // unused 134151497Sru}; 135114402Sru 136114402Srutypedef unsigned char byte; 137114402Srutypedef unsigned short uint16; 138114402Srutypedef short int16; 139114402Srutypedef unsigned int uint32; 140114402Sru 141114402Sruclass File { 142114402Srupublic: 143114402Sru File(const char *); 144114402Sru void skip(int n); 145114402Sru byte get_byte(); 146114402Sru uint16 get_uint16(); 147114402Sru uint32 get_uint32(); 148151497Sru uint32 get_uint32(char *orig); 149114402Sru void seek(uint32 n); 150114402Sruprivate: 151114402Sru unsigned char *buf_; 152114402Sru const unsigned char *ptr_; 153114402Sru const unsigned char *end_; 154114402Sru}; 155114402Sru 156114402Srustruct entry { 157114402Sru char present; 158114402Sru uint16 type; 159114402Sru uint32 count; 160114402Sru uint32 value; 161151497Sru char orig_value[4]; 162114402Sru entry() : present(0) { } 163114402Sru}; 164114402Sru 165114402Srustruct char_info { 166151497Sru uint16 charcode; 167114402Sru uint16 width; 168114402Sru int16 ascent; 169114402Sru int16 descent; 170114402Sru int16 left_extent; 171114402Sru uint16 right_extent; 172114402Sru uint16 symbol_set; 173114402Sru unsigned char code; 174114402Sru}; 175114402Sru 176151497Sruconst uint16 NO_GLYPH = 0xffff; 177114402Sruconst uint16 NO_SYMBOL_SET = 0; 178114402Sru 179114402Srustruct name_list { 180114402Sru char *name; 181114402Sru name_list *next; 182114402Sru name_list(const char *s, name_list *p) : name(strsave(s)), next(p) { } 183114402Sru ~name_list() { a_delete name; } 184114402Sru}; 185114402Sru 186114402Srustruct symbol_set { 187114402Sru uint16 select; 188114402Sru uint16 index[256]; 189114402Sru}; 190114402Sru 191114402Sru#define SYMBOL_SET(n, c) ((n) * 32 + ((c) - 64)) 192114402Sru 193114402Sruuint16 text_symbol_sets[] = { 194151497Sru SYMBOL_SET(19, 'U'), // Windows Latin 1 ("ANSI", code page 1252) 195151497Sru SYMBOL_SET(9, 'E'), // Windows Latin 2, Code Page 1250 196151497Sru SYMBOL_SET(5, 'T'), // Code Page 1254 197151497Sru SYMBOL_SET(7, 'J'), // Desktop 198114402Sru SYMBOL_SET(6, 'J'), // Microsoft Publishing 199151497Sru SYMBOL_SET(0, 'N'), // Latin 1 (subset of 19U, 200151497Sru // so we should never get here) 201151497Sru SYMBOL_SET(2, 'N'), // Latin 2 (subset of 9E, 202151497Sru // so we should never get here) 203151497Sru SYMBOL_SET(8, 'U'), // HP Roman 8 204151497Sru SYMBOL_SET(10, 'J'), // PS Standard 205151497Sru SYMBOL_SET(9, 'U'), // Windows 3.0 "ANSI" 206151497Sru SYMBOL_SET(1, 'U'), // U.S. Legal 207151497Sru 208151497Sru SYMBOL_SET(12, 'J'), // MC Text 209151497Sru SYMBOL_SET(10, 'U'), // PC Code Page 437 210151497Sru SYMBOL_SET(11, 'U'), // PC Code Page 437N 211151497Sru SYMBOL_SET(17, 'U'), // PC Code Page 852 212151497Sru SYMBOL_SET(12, 'U'), // PC Code Page 850 213151497Sru SYMBOL_SET(9, 'T'), // PC Code Page 437T 214114402Sru 0 215151497Sru}; 216114402Sru 217114402Sruuint16 special_symbol_sets[] = { 218151497Sru SYMBOL_SET(8, 'M'), // Math 8 219151497Sru SYMBOL_SET(5, 'M'), // PS Math 220151497Sru SYMBOL_SET(15, 'U'), // Pi font 221151497Sru SYMBOL_SET(13, 'J'), // Ventura International 222151497Sru SYMBOL_SET(19, 'M'), // Symbol font 223151497Sru SYMBOL_SET(579, 'L'), // Wingdings 224114402Sru 0 225151497Sru}; 226114402Sru 227114402Sruentry tags[max_tag + 1 - min_tag]; 228114402Sru 229114402Sruchar_info *char_table; 230151497Sruuint32 nchars = 0; 231114402Sru 232151497Sruunsigned int charcode_name_table_size = 0; 233151497Sruname_list **charcode_name_table = NULL; 234114402Sru 235151497Srusymbol_set *symbol_set_table; 236114402Sruunsigned int n_symbol_sets; 237114402Sru 238151497Srustatic int debug_flag = NO; 239151497Srustatic int special_flag = NO; // not a special font 240151497Srustatic int italic_flag = NO; // don't add italic correction 241114402Srustatic int italic_sep; 242151497Srustatic int all_flag = NO; // don't include glyphs not in mapfile 243151497Srustatic int quiet_flag = NO; // don't suppress warnings about symbols not found 244114402Sru 245151497Srustatic char *hp_msl_to_ucode_name(int); 246151497Srustatic char *unicode_to_ucode_name(int); 247151497Srustatic int is_uname(char *); 248151497Srustatic char *show_symset(unsigned int); 249151497Srustatic void usage(FILE *); 250114402Srustatic void usage(); 251114402Srustatic const char *xbasename(const char *); 252114402Srustatic void read_tags(File &); 253151497Srustatic int check_type(); 254151497Srustatic void check_units(File &, const int, double *, double *); 255151497Srustatic int read_map(const char *, const int); 256114402Srustatic void require_tag(tag_type); 257151497Srustatic void dump_ascii(File &, tag_type); 258151497Srustatic void dump_tags(File &); 259151497Srustatic void dump_symbol_sets(File &); 260151497Srustatic void dump_symbols(int); 261151497Srustatic void output_font_name(File &); 262114402Srustatic void output_spacewidth(); 263114402Srustatic void output_pclweight(); 264114402Srustatic void output_pclproportional(); 265114402Srustatic void read_and_output_pcltypeface(File &); 266114402Srustatic void output_pclstyle(); 267114402Srustatic void output_slant(); 268114402Srustatic void output_ligatures(); 269114402Srustatic void read_symbol_sets(File &); 270114402Srustatic void read_and_output_kernpairs(File &); 271151497Srustatic void output_charset(const int); 272151497Srustatic void read_char_table(File &); 273114402Sru 274114402Sruinline 275114402Sruentry &tag_info(tag_type t) 276114402Sru{ 277114402Sru return tags[t - min_tag]; 278114402Sru} 279114402Sru 280151497Sruint 281151497Srumain(int argc, char **argv) 282114402Sru{ 283114402Sru program_name = argv[0]; 284114402Sru 285114402Sru int opt; 286151497Sru int res = 1200; // PCL unit of measure for cursor moves 287151497Sru int scalesize = 4; // LaserJet 4 only allows 1/4 point increments 288151497Sru int unitwidth = 6350; 289151497Sru double ppi; // points per inch 290151497Sru double upem; // design units per em 291114402Sru 292114402Sru static const struct option long_options[] = { 293114402Sru { "help", no_argument, 0, CHAR_MAX + 1 }, 294114402Sru { "version", no_argument, 0, 'v' }, 295114402Sru { NULL, 0, 0, 0 } 296114402Sru }; 297151497Sru while ((opt = getopt_long(argc, argv, "adsqvi:", long_options, NULL)) != EOF) { 298114402Sru switch (opt) { 299151497Sru case 'a': 300151497Sru all_flag = YES; 301151497Sru break; 302114402Sru case 'd': 303151497Sru debug_flag = YES; 304114402Sru break; 305114402Sru case 's': 306151497Sru special_flag = YES; 307114402Sru break; 308114402Sru case 'i': 309151497Sru italic_flag = YES; 310151497Sru italic_sep = atoi(optarg); // design units 311114402Sru break; 312151497Sru case 'q': 313151497Sru quiet_flag = YES; // suppress warnings about symbols not found 314151497Sru break; 315114402Sru case 'v': 316151497Sru printf("GNU hpftodit (groff) version %s\n", Version_string); 317151497Sru exit(0); 318114402Sru break; 319114402Sru case CHAR_MAX + 1: // --help 320114402Sru usage(stdout); 321114402Sru exit(0); 322114402Sru break; 323114402Sru case '?': 324114402Sru usage(); 325114402Sru break; 326114402Sru default: 327114402Sru assert(0); 328114402Sru } 329114402Sru } 330151497Sru 331151497Sru if (debug_flag && argc - optind < 1) 332114402Sru usage(); 333151497Sru else if (!debug_flag && argc - optind != 3) 334151497Sru usage(); 335114402Sru File f(argv[optind]); 336151497Sru read_tags(f); 337151497Sru int tfm_type = check_type(); 338151497Sru if (debug_flag) 339151497Sru dump_tags(f); 340151497Sru if (!debug_flag && !read_map(argv[optind + 1], tfm_type)) 341114402Sru exit(1); 342151497Sru else if (debug_flag && argc - optind > 1) 343151497Sru read_map(argv[optind + 1], tfm_type); 344151497Sru current_filename = NULL; 345114402Sru current_lineno = -1; // no line numbers 346151497Sru if (!debug_flag && !equal(argv[optind + 2], "-")) 347151497Sru if (freopen(argv[optind + 2], "w", stdout) == NULL) 348151497Sru fatal("cannot open `%1': %2", argv[optind + 2], strerror(errno)); 349114402Sru current_filename = argv[optind]; 350151497Sru 351151497Sru check_units(f, tfm_type, &ppi, &upem); 352151497Sru if (tfm_type == UNICODE) // don't calculate for Intellifont TFMs 353151497Sru multiplier = double(res) / upem / ppi * unitwidth / scalesize; 354151497Sru if (italic_flag) 355151497Sru // convert from thousandths of an em to design units 356151497Sru italic_sep = int(italic_sep * upem / 1000 + 0.5); 357151497Sru 358114402Sru read_char_table(f); 359151497Sru if (nchars == 0) 360151497Sru fatal("no characters"); 361151497Sru 362151497Sru if (!debug_flag) { 363151497Sru output_font_name(f); 364151497Sru printf("name %s\n", xbasename(argv[optind + 2])); 365151497Sru if (special_flag) 366151497Sru printf("special\n"); 367151497Sru output_spacewidth(); 368151497Sru output_slant(); 369151497Sru read_and_output_pcltypeface(f); 370151497Sru output_pclproportional(); 371151497Sru output_pclweight(); 372151497Sru output_pclstyle(); 373151497Sru } 374114402Sru read_symbol_sets(f); 375151497Sru if (debug_flag) 376151497Sru dump_symbols(tfm_type); 377151497Sru else { 378151497Sru output_ligatures(); 379151497Sru read_and_output_kernpairs(f); 380151497Sru output_charset(tfm_type); 381151497Sru } 382114402Sru return 0; 383114402Sru} 384114402Sru 385151497Srustatic void 386151497Sruusage(FILE *stream) 387114402Sru{ 388151497Sru fprintf(stream, 389151497Sru "usage: %s [-s] [-a] [-q] [-i n] tfm_file map_file output_font\n" 390151497Sru " %s -d tfm_file [map_file]\n", 391151497Sru program_name, program_name); 392114402Sru} 393151497Sru 394151497Srustatic void 395151497Sruusage() 396114402Sru{ 397114402Sru usage(stderr); 398114402Sru exit(1); 399114402Sru} 400114402Sru 401114402SruFile::File(const char *s) 402114402Sru{ 403114402Sru // We need to read the file in binary mode because hpftodit relies 404114402Sru // on byte counts. 405114402Sru int fd = open(s, O_RDONLY | O_BINARY); 406114402Sru if (fd < 0) 407114402Sru fatal("cannot open `%1': %2", s, strerror(errno)); 408114402Sru current_filename = s; 409114402Sru struct stat sb; 410114402Sru if (fstat(fd, &sb) < 0) 411114402Sru fatal("cannot stat: %1", strerror(errno)); 412114402Sru if (!S_ISREG(sb.st_mode)) 413114402Sru fatal("not a regular file"); 414114402Sru buf_ = new unsigned char[sb.st_size]; 415114402Sru long nread = read(fd, buf_, sb.st_size); 416114402Sru if (nread < 0) 417114402Sru fatal("read error: %1", strerror(errno)); 418114402Sru if (nread != sb.st_size) 419114402Sru fatal("read unexpected number of bytes"); 420114402Sru ptr_ = buf_; 421114402Sru end_ = buf_ + sb.st_size; 422114402Sru} 423114402Sru 424151497Sruvoid 425151497SruFile::skip(int n) 426114402Sru{ 427114402Sru if (end_ - ptr_ < n) 428114402Sru fatal("unexpected end of file"); 429114402Sru ptr_ += n; 430114402Sru} 431114402Sru 432151497Sruvoid 433151497SruFile::seek(uint32 n) 434114402Sru{ 435151497Sru if (uint32(end_ - buf_) < n) 436114402Sru fatal("unexpected end of file"); 437114402Sru ptr_ = buf_ + n; 438114402Sru} 439114402Sru 440151497Srubyte 441151497SruFile::get_byte() 442114402Sru{ 443114402Sru if (ptr_ >= end_) 444114402Sru fatal("unexpected end of file"); 445114402Sru return *ptr_++; 446114402Sru} 447114402Sru 448151497Sruuint16 449151497SruFile::get_uint16() 450114402Sru{ 451114402Sru if (end_ - ptr_ < 2) 452114402Sru fatal("unexpected end of file"); 453114402Sru uint16 n = *ptr_++; 454114402Sru return n + (*ptr_++ << 8); 455114402Sru} 456114402Sru 457151497Sruuint32 458151497SruFile::get_uint32() 459114402Sru{ 460114402Sru if (end_ - ptr_ < 4) 461114402Sru fatal("unexpected end of file"); 462114402Sru uint32 n = *ptr_++; 463114402Sru for (int i = 0; i < 3; i++) 464114402Sru n += *ptr_++ << (i + 1)*8; 465114402Sru return n; 466114402Sru} 467114402Sru 468151497Sruuint32 469151497SruFile::get_uint32(char *orig) 470114402Sru{ 471151497Sru if (end_ - ptr_ < 4) 472151497Sru fatal("unexpected end of file"); 473151497Sru unsigned char v = *ptr_++; 474151497Sru uint32 n = v; 475151497Sru orig[0] = v; 476151497Sru for (int i = 1; i < 4; i++) { 477151497Sru v = *ptr_++; 478151497Sru orig[i] = v; 479151497Sru n += v << i*8; 480151497Sru } 481151497Sru return n; 482151497Sru} 483151497Sru 484151497Srustatic void 485151497Sruread_tags(File &f) 486151497Sru{ 487114402Sru if (f.get_byte() != 'I' || f.get_byte() != 'I') 488114402Sru fatal("not an Intel format TFM file"); 489114402Sru f.skip(6); 490114402Sru uint16 ntags = f.get_uint16(); 491114402Sru entry dummy; 492114402Sru for (uint16 i = 0; i < ntags; i++) { 493114402Sru uint16 tag = f.get_uint16(); 494114402Sru entry *p; 495114402Sru if (min_tag <= tag && tag <= max_tag) 496114402Sru p = tags + (tag - min_tag); 497114402Sru else 498114402Sru p = &dummy; 499114402Sru p->present = 1; 500114402Sru p->type = f.get_uint16(); 501114402Sru p->count = f.get_uint32(); 502151497Sru p->value = f.get_uint32(p->orig_value); 503114402Sru } 504114402Sru} 505114402Sru 506151497Srustatic int 507151497Srucheck_type() 508114402Sru{ 509114402Sru require_tag(type_tag); 510151497Sru int tfm_type = tag_info(type_tag).value; 511151497Sru switch (tfm_type) { 512151497Sru case MSL: 513151497Sru case UNICODE: 514151497Sru break; 515151497Sru case SYMSET: 516151497Sru fatal("cannot handle Symbol Set TFM files"); 517151497Sru break; 518151497Sru default: 519151497Sru fatal("unknown type tag %1", tfm_type); 520114402Sru } 521151497Sru return tfm_type; 522114402Sru} 523114402Sru 524151497Srustatic void 525151497Srucheck_units(File &f, const int tfm_type, double *ppi, double *upem) 526114402Sru{ 527114402Sru require_tag(design_units_per_em_tag); 528114402Sru f.seek(tag_info(design_units_per_em_tag).value); 529114402Sru uint32 num = f.get_uint32(); 530114402Sru uint32 den = f.get_uint32(); 531151497Sru if (tfm_type == MSL && (num != 8782 || den != 1)) 532114402Sru fatal("design units per em != 8782/1"); 533151497Sru *upem = double(num) / den; 534114402Sru require_tag(inches_per_point_tag); 535114402Sru f.seek(tag_info(inches_per_point_tag).value); 536114402Sru num = f.get_uint32(); 537114402Sru den = f.get_uint32(); 538151497Sru if (tfm_type == MSL && (num != 100 || den != 7231)) 539114402Sru fatal("inches per point not 100/7231"); 540151497Sru *ppi = double(den) / num; 541114402Sru} 542114402Sru 543151497Srustatic void 544151497Srurequire_tag(tag_type t) 545114402Sru{ 546114402Sru if (!tag_info(t).present) 547114402Sru fatal("tag %1 missing", int(t)); 548114402Sru} 549114402Sru 550151497Sru// put a human-readable font name in the file 551151497Srustatic void 552151497Sruoutput_font_name(File &f) 553114402Sru{ 554151497Sru char *p; 555151497Sru 556151497Sru if (!tag_info(font_name_tag).present) 557151497Sru return; 558151497Sru int count = tag_info(font_name_tag).count; 559151497Sru char *font_name = new char[count]; 560151497Sru 561151497Sru if (count > 4) { // value is a file offset to the string 562151497Sru f.seek(tag_info(font_name_tag).value); 563151497Sru int n = count; 564151497Sru p = font_name; 565151497Sru while (--n) 566151497Sru *p++ = f.get_byte(); 567151497Sru } 568151497Sru else // orig_value contains the string 569151497Sru sprintf(font_name, "%.*s", 570151497Sru count, tag_info(font_name_tag).orig_value); 571151497Sru 572151497Sru // remove any trailing space 573151497Sru p = font_name + count - 1; 574151497Sru while (csspace(*--p)) 575151497Sru ; 576151497Sru *(p + 1) = '\0'; 577151497Sru printf("# %s\n", font_name); 578151497Sru delete font_name; 579151497Sru} 580151497Sru 581151497Srustatic void 582151497Sruoutput_spacewidth() 583151497Sru{ 584114402Sru require_tag(word_spacing_tag); 585114402Sru printf("spacewidth %d\n", scale(tag_info(word_spacing_tag).value)); 586114402Sru} 587114402Sru 588151497Srustatic void 589151497Sruread_symbol_sets(File &f) 590114402Sru{ 591114402Sru uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count; 592151497Sru uint16 *symbol_set_selectors; 593114402Sru n_symbol_sets = symbol_set_dir_length/14; 594114402Sru symbol_set_table = new symbol_set[n_symbol_sets]; 595114402Sru unsigned int i; 596151497Sru 597151497Sru for (i = 0; i < nchars; i++) 598151497Sru char_table[i].symbol_set = NO_SYMBOL_SET; 599151497Sru 600114402Sru for (i = 0; i < n_symbol_sets; i++) { 601114402Sru f.seek(tag_info(symbol_set_tag).value + i*14); 602151497Sru (void)f.get_uint32(); // offset to symbol set name 603151497Sru uint32 off1 = f.get_uint32(); // offset to selection string 604151497Sru uint32 off2 = f.get_uint32(); // offset to symbol set index array 605151497Sru 606114402Sru f.seek(off1); 607151497Sru uint16 kind = 0; // HP-GL "Kind 1" symbol set value 608114402Sru unsigned int j; 609114402Sru for (j = 0; j < off2 - off1; j++) { 610114402Sru unsigned char c = f.get_byte(); 611151497Sru if ('0' <= c && c <= '9') // value 612114402Sru kind = kind*10 + (c - '0'); 613151497Sru else if ('A' <= c && c <= 'Z') // terminator 614114402Sru kind = kind*32 + (c - 64); 615114402Sru } 616114402Sru symbol_set_table[i].select = kind; 617114402Sru for (j = 0; j < 256; j++) 618114402Sru symbol_set_table[i].index[j] = f.get_uint16(); 619114402Sru } 620114402Sru 621151497Sru symbol_set_selectors = (special_flag ? special_symbol_sets 622151497Sru : text_symbol_sets); 623114402Sru for (i = 0; symbol_set_selectors[i] != 0; i++) { 624114402Sru unsigned int j; 625114402Sru for (j = 0; j < n_symbol_sets; j++) 626114402Sru if (symbol_set_table[j].select == symbol_set_selectors[i]) 627114402Sru break; 628114402Sru if (j < n_symbol_sets) { 629114402Sru for (int k = 0; k < 256; k++) { 630151497Sru uint16 idx = symbol_set_table[j].index[k]; 631151497Sru if (idx != NO_GLYPH 632151497Sru && char_table[idx].symbol_set == NO_SYMBOL_SET) { 633151497Sru char_table[idx].symbol_set = symbol_set_table[j].select; 634151497Sru char_table[idx].code = k; 635114402Sru } 636114402Sru } 637114402Sru } 638114402Sru } 639151497Sru 640151497Sru if (all_flag) 641151497Sru return; 642151497Sru 643151497Sru symbol_set_selectors = (special_flag ? text_symbol_sets 644151497Sru : special_symbol_sets); 645151497Sru for (i = 0; symbol_set_selectors[i] != 0; i++) { 646151497Sru unsigned int j; 647151497Sru for (j = 0; j < n_symbol_sets; j++) 648151497Sru if (symbol_set_table[j].select == symbol_set_selectors[i]) 649151497Sru break; 650151497Sru if (j < n_symbol_sets) { 651151497Sru for (int k = 0; k < 256; k++) { 652151497Sru uint16 idx = symbol_set_table[j].index[k]; 653151497Sru if (idx != NO_GLYPH 654151497Sru && char_table[idx].symbol_set == NO_SYMBOL_SET) { 655151497Sru char_table[idx].symbol_set = symbol_set_table[j].select; 656151497Sru char_table[idx].code = k; 657151497Sru } 658151497Sru } 659151497Sru } 660151497Sru } 661151497Sru return; 662114402Sru} 663114402Sru 664151497Srustatic void 665151497Sruread_char_table(File &f) 666114402Sru{ 667151497Sru require_tag(charcode_tag); 668151497Sru nchars = tag_info(charcode_tag).count; 669114402Sru char_table = new char_info[nchars]; 670114402Sru 671151497Sru f.seek(tag_info(charcode_tag).value); 672114402Sru uint32 i; 673114402Sru for (i = 0; i < nchars; i++) 674151497Sru char_table[i].charcode = f.get_uint16(); 675151497Sru 676114402Sru require_tag(width_tag); 677114402Sru f.seek(tag_info(width_tag).value); 678114402Sru for (i = 0; i < nchars; i++) 679114402Sru char_table[i].width = f.get_uint16(); 680114402Sru 681114402Sru require_tag(ascent_tag); 682114402Sru f.seek(tag_info(ascent_tag).value); 683114402Sru for (i = 0; i < nchars; i++) { 684114402Sru char_table[i].ascent = f.get_uint16(); 685114402Sru if (char_table[i].ascent < 0) 686114402Sru char_table[i].ascent = 0; 687114402Sru } 688114402Sru 689114402Sru require_tag(descent_tag); 690114402Sru f.seek(tag_info(descent_tag).value); 691114402Sru for (i = 0; i < nchars; i++) { 692114402Sru char_table[i].descent = f.get_uint16(); 693114402Sru if (char_table[i].descent > 0) 694114402Sru char_table[i].descent = 0; 695114402Sru } 696114402Sru 697114402Sru require_tag(left_extent_tag); 698114402Sru f.seek(tag_info(left_extent_tag).value); 699114402Sru for (i = 0; i < nchars; i++) 700114402Sru char_table[i].left_extent = int16(f.get_uint16()); 701114402Sru 702114402Sru require_tag(right_extent_tag); 703114402Sru f.seek(tag_info(right_extent_tag).value); 704114402Sru for (i = 0; i < nchars; i++) 705114402Sru char_table[i].right_extent = f.get_uint16(); 706114402Sru} 707114402Sru 708151497Srustatic void 709151497Sruoutput_pclweight() 710114402Sru{ 711114402Sru require_tag(stroke_weight_tag); 712114402Sru int stroke_weight = tag_info(stroke_weight_tag).value; 713114402Sru int pcl_stroke_weight; 714114402Sru if (stroke_weight < 128) 715114402Sru pcl_stroke_weight = -3; 716114402Sru else if (stroke_weight == 128) 717114402Sru pcl_stroke_weight = 0; 718114402Sru else if (stroke_weight <= 145) 719114402Sru pcl_stroke_weight = 1; 720114402Sru else if (stroke_weight <= 179) 721114402Sru pcl_stroke_weight = 3; 722114402Sru else 723114402Sru pcl_stroke_weight = 4; 724114402Sru printf("pclweight %d\n", pcl_stroke_weight); 725114402Sru} 726114402Sru 727151497Srustatic void 728151497Sruoutput_pclproportional() 729114402Sru{ 730114402Sru require_tag(spacing_tag); 731114402Sru printf("pclproportional %d\n", tag_info(spacing_tag).value == 0); 732114402Sru} 733114402Sru 734151497Srustatic void 735151497Sruread_and_output_pcltypeface(File &f) 736114402Sru{ 737114402Sru printf("pcltypeface "); 738114402Sru require_tag(typeface_tag); 739151497Sru if (tag_info(typeface_tag).count > 4) { 740151497Sru f.seek(tag_info(typeface_tag).value); 741151497Sru for (uint32 i = 0; i < tag_info(typeface_tag).count; i++) { 742151497Sru unsigned char c = f.get_byte(); 743151497Sru if (c == '\0') 744151497Sru break; 745151497Sru putchar(c); 746151497Sru } 747114402Sru } 748151497Sru else 749151497Sru printf("%.4s", tag_info(typeface_tag).orig_value); 750114402Sru printf("\n"); 751114402Sru} 752114402Sru 753151497Srustatic void 754151497Sruoutput_pclstyle() 755114402Sru{ 756114402Sru unsigned pcl_style = 0; 757114402Sru // older tfms don't have the posture tag 758114402Sru if (tag_info(posture_tag).present) { 759114402Sru if (tag_info(posture_tag).value) 760114402Sru pcl_style |= 1; 761114402Sru } 762114402Sru else { 763114402Sru require_tag(slant_tag); 764114402Sru if (tag_info(slant_tag).value != 0) 765114402Sru pcl_style |= 1; 766114402Sru } 767114402Sru require_tag(appearance_width_tag); 768114402Sru if (tag_info(appearance_width_tag).value < 100) // guess 769114402Sru pcl_style |= 4; 770114402Sru printf("pclstyle %d\n", pcl_style); 771114402Sru} 772114402Sru 773151497Srustatic void 774151497Sruoutput_slant() 775114402Sru{ 776114402Sru require_tag(slant_tag); 777114402Sru int slant = int16(tag_info(slant_tag).value); 778114402Sru if (slant != 0) 779114402Sru printf("slant %f\n", slant/100.0); 780114402Sru} 781114402Sru 782151497Srustatic void 783151497Sruoutput_ligatures() 784114402Sru{ 785114402Sru // don't use ligatures for fixed space font 786114402Sru require_tag(spacing_tag); 787114402Sru if (tag_info(spacing_tag).value != 0) 788114402Sru return; 789114402Sru static const char *ligature_names[] = { 790114402Sru "fi", "fl", "ff", "ffi", "ffl" 791114402Sru }; 792114402Sru 793114402Sru static const char *ligature_chars[] = { 794114402Sru "fi", "fl", "ff", "Fi", "Fl" 795114402Sru }; 796151497Sru 797114402Sru unsigned ligature_mask = 0; 798114402Sru unsigned int i; 799114402Sru for (i = 0; i < nchars; i++) { 800151497Sru uint16 charcode = char_table[i].charcode; 801151497Sru if (charcode < charcode_name_table_size 802114402Sru && char_table[i].symbol_set != NO_SYMBOL_SET) { 803151497Sru for (name_list *p = charcode_name_table[charcode]; p; p = p->next) 804114402Sru for (unsigned int j = 0; j < SIZEOF(ligature_chars); j++) 805114402Sru if (strcmp(p->name, ligature_chars[j]) == 0) { 806114402Sru ligature_mask |= 1 << j; 807114402Sru break; 808114402Sru } 809114402Sru } 810114402Sru } 811114402Sru if (ligature_mask) { 812114402Sru printf("ligatures"); 813114402Sru for (i = 0; i < SIZEOF(ligature_names); i++) 814114402Sru if (ligature_mask & (1 << i)) 815114402Sru printf(" %s", ligature_names[i]); 816114402Sru printf(" 0\n"); 817114402Sru } 818114402Sru} 819114402Sru 820151497Srustatic void 821151497Sruread_and_output_kernpairs(File &f) 822114402Sru{ 823114402Sru if (tag_info(pair_kern_tag).present) { 824114402Sru printf("kernpairs\n"); 825114402Sru f.seek(tag_info(pair_kern_tag).value); 826114402Sru uint16 n_pairs = f.get_uint16(); 827114402Sru for (int i = 0; i < n_pairs; i++) { 828114402Sru uint16 i1 = f.get_uint16(); 829114402Sru uint16 i2 = f.get_uint16(); 830114402Sru int16 val = int16(f.get_uint16()); 831114402Sru if (char_table[i1].symbol_set != NO_SYMBOL_SET 832114402Sru && char_table[i2].symbol_set != NO_SYMBOL_SET 833151497Sru && char_table[i1].charcode < charcode_name_table_size 834151497Sru && char_table[i2].charcode < charcode_name_table_size) { 835151497Sru for (name_list *p = charcode_name_table[char_table[i1].charcode]; 836114402Sru p; 837114402Sru p = p->next) 838151497Sru for (name_list *q = charcode_name_table[char_table[i2].charcode]; 839114402Sru q; 840114402Sru q = q->next) 841151497Sru if (!equal(p->name, UNNAMED) && !equal(q->name, UNNAMED)) 842151497Sru printf("%s %s %d\n", p->name, q->name, scale(val)); 843114402Sru } 844114402Sru } 845114402Sru } 846114402Sru} 847114402Sru 848151497Srustatic void 849151497Sruoutput_charset(const int tfm_type) 850114402Sru{ 851114402Sru require_tag(slant_tag); 852114402Sru double slant_angle = int16(tag_info(slant_tag).value)*PI/18000.0; 853114402Sru double slant = sin(slant_angle)/cos(slant_angle); 854114402Sru 855151497Sru if (italic_flag) 856151497Sru require_tag(x_height_tag); 857114402Sru require_tag(lower_ascent_tag); 858114402Sru require_tag(lower_descent_tag); 859114402Sru 860114402Sru printf("charset\n"); 861114402Sru unsigned int i; 862114402Sru for (i = 0; i < nchars; i++) { 863151497Sru uint16 charcode = char_table[i].charcode; 864151497Sru 865151497Sru // the glyph is bound to one of the searched symbol sets 866151497Sru if (char_table[i].symbol_set != NO_SYMBOL_SET) { 867151497Sru // the character was in the map file 868151497Sru if (charcode < charcode_name_table_size && charcode_name_table[charcode]) 869151497Sru printf("%s", charcode_name_table[charcode]->name); 870151497Sru else if (!all_flag) 871151497Sru continue; 872151497Sru else if (tfm_type == MSL) 873222083Sbenl fputs(hp_msl_to_ucode_name(charcode), stdout); 874151497Sru else 875222083Sbenl fputs(unicode_to_ucode_name(charcode), stdout); 876151497Sru 877151497Sru printf("\t%d,%d", 878151497Sru scale(char_table[i].width), scale(char_table[i].ascent)); 879151497Sru 880151497Sru int depth = scale(-char_table[i].descent); 881151497Sru if (depth < 0) 882151497Sru depth = 0; 883151497Sru int italic_correction = 0; 884151497Sru int left_italic_correction = 0; 885151497Sru int subscript_correction = 0; 886151497Sru 887151497Sru if (italic_flag) { 888151497Sru italic_correction = scale(char_table[i].right_extent 889151497Sru - char_table[i].width 890151497Sru + italic_sep); 891151497Sru if (italic_correction < 0) 892151497Sru italic_correction = 0; 893151497Sru subscript_correction = int((tag_info(x_height_tag).value 894151497Sru * slant * .8) + .5); 895151497Sru if (subscript_correction > italic_correction) 896151497Sru subscript_correction = italic_correction; 897151497Sru left_italic_correction = scale(italic_sep 898151497Sru - char_table[i].left_extent); 899114402Sru } 900151497Sru 901151497Sru if (subscript_correction != 0) 902151497Sru printf(",%d,%d,%d,%d", 903151497Sru depth, italic_correction, left_italic_correction, 904151497Sru subscript_correction); 905151497Sru else if (left_italic_correction != 0) 906151497Sru printf(",%d,%d,%d", depth, italic_correction, left_italic_correction); 907151497Sru else if (italic_correction != 0) 908151497Sru printf(",%d,%d", depth, italic_correction); 909151497Sru else if (depth != 0) 910151497Sru printf(",%d", depth); 911151497Sru // This is fairly arbitrary. Fortunately it doesn't much matter. 912151497Sru unsigned type = 0; 913151497Sru if (char_table[i].ascent > int16(tag_info(lower_ascent_tag).value)*9/10) 914151497Sru type |= 2; 915151497Sru if (char_table[i].descent < int16(tag_info(lower_descent_tag).value)*9/10) 916151497Sru type |= 1; 917151497Sru printf("\t%d\t%d", type, 918151497Sru char_table[i].symbol_set*256 + char_table[i].code); 919151497Sru 920151497Sru if (tfm_type == UNICODE) { 921151497Sru if (charcode >= 0xE000 && charcode <= 0xF8FF) 922151497Sru printf("\t-- HP PUA U+%04X", charcode); 923151497Sru else 924151497Sru printf("\t-- U+%04X", charcode); 925151497Sru } 926114402Sru else 927151497Sru printf("\t-- MSL %4d", charcode); 928151497Sru printf(" (%3s %3d)\n", 929151497Sru show_symset(char_table[i].symbol_set), char_table[i].code); 930151497Sru 931151497Sru if (charcode < charcode_name_table_size 932151497Sru && charcode_name_table[charcode]) 933151497Sru for (name_list *p = charcode_name_table[charcode]->next; 934151497Sru p; p = p->next) 935151497Sru printf("%s\t\"\n", p->name); 936114402Sru } 937151497Sru // warnings about characters in mapfile not found in TFM 938151497Sru else if (charcode < charcode_name_table_size 939151497Sru && charcode_name_table[charcode]) { 940151497Sru char *name = charcode_name_table[charcode]->name; 941151497Sru // don't warn about Unicode or unnamed glyphs 942151497Sru // that aren't in the the TFM file 943151497Sru if (tfm_type == UNICODE && !quiet_flag && !equal(name, UNNAMED) 944151497Sru && !is_uname(name)) { 945151497Sru fprintf(stderr, "%s: warning: symbol U+%04X (%s", 946151497Sru program_name, charcode, name); 947151497Sru for (name_list *p = charcode_name_table[charcode]->next; 948151497Sru p; p = p->next) 949151497Sru fprintf(stderr, ", %s", p->name); 950151497Sru fprintf(stderr, ") not in any searched symbol set\n"); 951151497Sru } 952151497Sru else if (!quiet_flag && !equal(name, UNNAMED) && !is_uname(name)) { 953151497Sru fprintf(stderr, "%s: warning: symbol MSL %d (%s", 954151497Sru program_name, charcode, name); 955151497Sru for (name_list *p = charcode_name_table[charcode]->next; 956151497Sru p; p = p->next) 957151497Sru fprintf(stderr, ", %s", p->name); 958151497Sru fprintf(stderr, ") not in any searched symbol set\n"); 959151497Sru } 960151497Sru } 961114402Sru } 962114402Sru} 963114402Sru 964151497Sru#define em_fract(a) (upem >= 0 ? double(a)/upem : 0) 965151497Sru 966151497Srustatic void 967151497Srudump_tags(File &f) 968114402Sru{ 969151497Sru double upem = -1.0; 970151497Sru 971151497Sru printf("TFM tags\n" 972151497Sru "\n" 973151497Sru "tag# type count value\n" 974151497Sru "---------------------\n"); 975151497Sru 976151497Sru for (int i = min_tag; i <= max_tag; i++) { 977114402Sru enum tag_type t = tag_type(i); 978114402Sru if (tag_info(t).present) { 979151497Sru printf("%4d %4d %5d", i, tag_info(t).type, tag_info(t).count); 980151497Sru switch (tag_info(t).type) { 981151497Sru case BYTE_TYPE: 982151497Sru case USHORT_TYPE: 983151497Sru printf(" %5u", tag_info(t).value); 984151497Sru switch (i) { 985151497Sru case type_tag: 986151497Sru printf(" Font Type "); 987151497Sru switch (tag_info(t).value) { 988151497Sru case MSL: 989151497Sru case SYMSET: 990151497Sru printf("(Intellifont)"); 991151497Sru break; 992151497Sru case UNICODE: 993151497Sru printf("(TrueType)"); 994151497Sru } 995151497Sru break; 996151497Sru case charcode_tag: 997151497Sru printf(" Number of Symbols (%u)", tag_info(t).count); 998151497Sru break; 999151497Sru case symbol_set_tag: 1000151497Sru printf(" Symbol Sets (%u): ", 1001151497Sru tag_info(symbol_set_tag).count / 14); 1002151497Sru dump_symbol_sets(f); 1003151497Sru break; 1004151497Sru case type_structure_tag: 1005151497Sru printf(" Type Structure (%u)", tag_info(t).value); 1006151497Sru break; 1007151497Sru case stroke_weight_tag: 1008151497Sru printf(" Stroke Weight (%u)", tag_info(t).value); 1009151497Sru break; 1010151497Sru case spacing_tag: 1011151497Sru printf(" Spacing "); 1012151497Sru switch (tag_info(t).value) { 1013151497Sru case 0: 1014151497Sru printf("(Proportional)"); 1015151497Sru break; 1016151497Sru case 1: 1017151497Sru printf("(Fixed Pitch: %u DU: %.2f em)", tag_info(t).value, 1018151497Sru em_fract(tag_info(t).value)); 1019151497Sru break; 1020151497Sru } 1021151497Sru break; 1022151497Sru case appearance_width_tag: 1023151497Sru printf(" Appearance Width (%u)", tag_info(t).value); 1024151497Sru break; 1025151497Sru case serif_style_tag: 1026151497Sru printf(" Serif Style (%u)", tag_info(t).value); 1027151497Sru break; 1028151497Sru case posture_tag: 1029151497Sru printf(" Posture (%s)", tag_info(t).value == 0 1030151497Sru ? "Upright" 1031151497Sru : tag_info(t).value == 1 1032151497Sru ? "Italic" 1033151497Sru : "Alternate Italic"); 1034151497Sru break; 1035151497Sru case max_width_tag: 1036151497Sru printf(" Maximum Width (%u DU: %.2f em)", tag_info(t).value, 1037151497Sru em_fract(tag_info(t).value)); 1038151497Sru break; 1039151497Sru case word_spacing_tag: 1040151497Sru printf(" Interword Spacing (%u DU: %.2f em)", tag_info(t).value, 1041151497Sru em_fract(tag_info(t).value)); 1042151497Sru break; 1043151497Sru case recommended_line_spacing_tag: 1044151497Sru printf(" Recommended Line Spacing (%u DU: %.2f em)", tag_info(t).value, 1045151497Sru em_fract(tag_info(t).value)); 1046151497Sru break; 1047151497Sru case x_height_tag: 1048151497Sru printf(" x-Height (%u DU: %.2f em)", tag_info(t).value, 1049151497Sru em_fract(tag_info(t).value)); 1050151497Sru break; 1051151497Sru case cap_height_tag: 1052151497Sru printf(" Cap Height (%u DU: %.2f em)", tag_info(t).value, 1053151497Sru em_fract(tag_info(t).value)); 1054151497Sru break; 1055151497Sru case max_ascent_tag: 1056151497Sru printf(" Maximum Ascent (%u DU: %.2f em)", tag_info(t).value, 1057151497Sru em_fract(tag_info(t).value)); 1058151497Sru break; 1059151497Sru case lower_ascent_tag: 1060151497Sru printf(" Lowercase Ascent (%u DU: %.2f em)", tag_info(t).value, 1061151497Sru em_fract(tag_info(t).value)); 1062151497Sru break; 1063151497Sru case underscore_thickness_tag: 1064151497Sru printf(" Underscore Thickness (%u DU: %.2f em)", tag_info(t).value, 1065151497Sru em_fract(tag_info(t).value)); 1066151497Sru break; 1067151497Sru case uppercase_accent_height_tag: 1068151497Sru printf(" Uppercase Accent Height (%u DU: %.2f em)", tag_info(t).value, 1069151497Sru em_fract(tag_info(t).value)); 1070151497Sru break; 1071151497Sru case lowercase_accent_height_tag: 1072151497Sru printf(" Lowercase Accent Height (%u DU: %.2f em)", tag_info(t).value, 1073151497Sru em_fract(tag_info(t).value)); 1074151497Sru break; 1075151497Sru case width_tag: 1076151497Sru printf(" Horizontal Escapement array"); 1077151497Sru break; 1078151497Sru case vertical_escapement_tag: 1079151497Sru printf(" Vertical Escapement array"); 1080151497Sru break; 1081151497Sru case right_extent_tag: 1082151497Sru printf(" Right Extent array"); 1083151497Sru break; 1084151497Sru case ascent_tag: 1085151497Sru printf(" Character Ascent array"); 1086151497Sru break; 1087151497Sru case pair_kern_tag: 1088151497Sru f.seek(tag_info(t).value); 1089151497Sru printf(" Kern Pairs (%u)", f.get_uint16()); 1090151497Sru break; 1091151497Sru case panose_tag: 1092151497Sru printf(" PANOSE Classification array"); 1093151497Sru break; 1094151497Sru } 1095151497Sru break; 1096151497Sru case SIGNED_SHORT_TYPE: 1097151497Sru printf(" %5d", int16(tag_info(t).value)); 1098151497Sru switch (i) { 1099151497Sru case slant_tag: 1100151497Sru printf(" Slant (%.2f degrees)", double(tag_info(t).value) / 100); 1101151497Sru break; 1102151497Sru case max_descent_tag: 1103151497Sru printf(" Maximum Descent (%d DU: %.2f em)", int16(tag_info(t).value), 1104151497Sru em_fract(int16(tag_info(t).value))); 1105151497Sru break; 1106151497Sru case lower_descent_tag: 1107151497Sru printf(" Lowercase Descent (%d DU: %.2f em)", int16(tag_info(t).value), 1108151497Sru em_fract(int16(tag_info(t).value))); 1109151497Sru break; 1110151497Sru case underscore_depth_tag: 1111151497Sru printf(" Underscore Depth (%d DU: %.2f em)", int16(tag_info(t).value), 1112151497Sru em_fract(int16(tag_info(t).value))); 1113151497Sru break; 1114151497Sru case left_extent_tag: 1115151497Sru printf(" Left Extent array"); 1116151497Sru break; 1117151497Sru // The type of this tag has changed from SHORT to SIGNED SHORT 1118151497Sru // in TFM version 1.3.0. 1119151497Sru case ascent_tag: 1120151497Sru printf(" Character Ascent array"); 1121151497Sru break; 1122151497Sru case descent_tag: 1123151497Sru printf(" Character Descent array"); 1124151497Sru break; 1125151497Sru } 1126151497Sru break; 1127151497Sru case RATIONAL_TYPE: 1128151497Sru printf(" %5u", tag_info(t).value); 1129151497Sru switch (i) { 1130151497Sru case inches_per_point_tag: 1131151497Sru printf(" Inches per Point"); 1132151497Sru break; 1133151497Sru case nominal_point_size_tag: 1134151497Sru printf(" Nominal Point Size"); 1135151497Sru break; 1136151497Sru case design_units_per_em_tag: 1137151497Sru printf(" Design Units per Em"); 1138151497Sru break; 1139151497Sru case average_width_tag: 1140151497Sru printf(" Average Width"); 1141151497Sru break; 1142151497Sru } 1143151497Sru if (tag_info(t).count == 1) { 1144151497Sru f.seek(tag_info(t).value); 1145151497Sru uint32 num = f.get_uint32(); 1146151497Sru uint32 den = f.get_uint32(); 1147151497Sru if (i == design_units_per_em_tag) 1148151497Sru upem = double(num) / den; 1149151497Sru printf(" (%u/%u = %g)", num, den, double(num)/den); 1150151497Sru } 1151151497Sru break; 1152151497Sru case ASCII_TYPE: 1153151497Sru printf(" %5u ", tag_info(t).value); 1154151497Sru switch (i) { 1155151497Sru case comment_tag: 1156151497Sru printf("Comment "); 1157151497Sru break; 1158151497Sru case copyright_tag: 1159151497Sru printf("Copyright "); 1160151497Sru break; 1161151497Sru case unique_identifier_tag: 1162151497Sru printf("Unique ID "); 1163151497Sru break; 1164151497Sru case font_name_tag: 1165151497Sru printf("Typeface Name "); 1166151497Sru break; 1167151497Sru case typeface_source_tag: 1168151497Sru printf("Typeface Source "); 1169151497Sru break; 1170151497Sru case typeface_tag: 1171151497Sru printf("PCL Typeface "); 1172151497Sru break; 1173151497Sru } 1174151497Sru dump_ascii(f, t); 1175114402Sru } 1176151497Sru putchar('\n'); 1177114402Sru } 1178114402Sru } 1179151497Sru putchar('\n'); 1180114402Sru} 1181151497Sru#undef em_fract 1182114402Sru 1183151497Srustatic void 1184151497Srudump_ascii(File &f, tag_type t) 1185114402Sru{ 1186151497Sru putchar('"'); 1187151497Sru if (tag_info(t).count > 4) { 1188151497Sru int count = tag_info(t).count; 1189151497Sru f.seek(tag_info(t).value); 1190151497Sru while (--count) 1191151497Sru printf("%c", f.get_byte()); 1192151497Sru } 1193151497Sru else 1194151497Sru printf("%.4s", tag_info(t).orig_value); 1195151497Sru putchar('"'); 1196151497Sru} 1197151497Sru 1198151497Srustatic void 1199151497Srudump_symbol_sets(File &f) 1200151497Sru{ 1201151497Sru uint32 symbol_set_dir_length = tag_info(symbol_set_tag).count; 1202151497Sru uint32 num_symbol_sets = symbol_set_dir_length / 14; 1203151497Sru 1204151497Sru for (uint32 i = 0; i < num_symbol_sets; i++) { 1205151497Sru f.seek(tag_info(symbol_set_tag).value + i * 14); 1206151497Sru (void)f.get_uint32(); // offset to symbol set name 1207151497Sru uint32 off1 = f.get_uint32(); // offset to selection string 1208151497Sru uint32 off2 = f.get_uint32(); // offset to symbol set index array 1209151497Sru f.seek(off1); 1210151497Sru for (uint32 j = 0; j < off2 - off1; j++) { 1211151497Sru unsigned char c = f.get_byte(); 1212151497Sru if ('0' <= c && c <= '9') 1213151497Sru putchar(c); 1214151497Sru else if ('A' <= c && c <= 'Z') 1215151497Sru printf(i < num_symbol_sets - 1 ? "%c," : "%c", c); 1216151497Sru } 1217151497Sru } 1218151497Sru} 1219151497Sru 1220151497Srustatic void 1221151497Srudump_symbols(int tfm_type) 1222151497Sru{ 1223151497Sru printf("Symbols:\n" 1224151497Sru "\n" 1225151497Sru " glyph id# symbol set name(s)\n" 1226151497Sru "----------------------------------\n"); 1227151497Sru for (uint32 i = 0; i < nchars; i++) { 1228151497Sru uint16 charcode = char_table[i].charcode; 1229151497Sru if (charcode < charcode_name_table_size 1230151497Sru && charcode_name_table[charcode]) { 1231151497Sru if (char_table[i].symbol_set != NO_SYMBOL_SET) { 1232151497Sru printf(tfm_type == UNICODE ? "%4d (U+%04X) (%3s %3d) %s" 1233151497Sru : "%4d (MSL %4d) (%3s %3d) %s", 1234151497Sru i, charcode, 1235151497Sru show_symset(char_table[i].symbol_set), 1236151497Sru char_table[i].code, 1237151497Sru charcode_name_table[charcode]->name); 1238151497Sru for (name_list *p = charcode_name_table[charcode]->next; 1239151497Sru p; p = p->next) 1240151497Sru printf(", %s", p->name); 1241151497Sru putchar('\n'); 1242151497Sru } 1243151497Sru } 1244151497Sru else { 1245151497Sru printf(tfm_type == UNICODE ? "%4d (U+%04X) " 1246151497Sru : "%4d (MSL %4d) ", 1247151497Sru i, charcode); 1248151497Sru if (char_table[i].symbol_set != NO_SYMBOL_SET) 1249151497Sru printf("(%3s %3d)", 1250151497Sru show_symset(char_table[i].symbol_set), char_table[i].code); 1251151497Sru putchar('\n'); 1252151497Sru } 1253151497Sru } 1254151497Sru putchar('\n'); 1255151497Sru} 1256151497Sru 1257151497Srustatic char * 1258151497Srushow_symset(unsigned int symset) 1259151497Sru{ 1260151497Sru static char symset_str[8]; 1261151497Sru 1262151497Sru sprintf(symset_str, "%d%c", symset / 32, (symset & 31) + 64); 1263151497Sru return symset_str; 1264151497Sru} 1265151497Sru 1266151497Srustatic char * 1267151497Sruhp_msl_to_ucode_name(int msl) 1268151497Sru{ 1269151497Sru char codestr[8]; 1270151497Sru 1271151497Sru sprintf(codestr, "%d", msl); 1272151497Sru const char *ustr = hp_msl_to_unicode_code(codestr); 1273151497Sru if (ustr == NULL) 1274151497Sru ustr = UNNAMED; 1275151497Sru else { 1276151497Sru char *nonum; 1277151497Sru int ucode = int(strtol(ustr, &nonum, 16)); 1278151497Sru // don't allow PUA code points as Unicode names 1279151497Sru if (ucode >= 0xE000 && ucode <= 0xF8FF) 1280151497Sru ustr = UNNAMED; 1281151497Sru } 1282151497Sru if (!equal(ustr, UNNAMED)) { 1283151497Sru const char *uname_decomposed = decompose_unicode(ustr); 1284151497Sru if (uname_decomposed) 1285151497Sru // 1st char is the number of components 1286151497Sru ustr = uname_decomposed + 1; 1287151497Sru } 1288151497Sru char *value = new char[strlen(ustr) + 1]; 1289151497Sru sprintf(value, equal(ustr, UNNAMED) ? ustr : "u%s", ustr); 1290151497Sru return value; 1291151497Sru} 1292151497Sru 1293151497Srustatic char * 1294151497Sruunicode_to_ucode_name(int ucode) 1295151497Sru{ 1296151497Sru const char *ustr; 1297151497Sru char codestr[8]; 1298151497Sru 1299151497Sru // don't allow PUA code points as Unicode names 1300151497Sru if (ucode >= 0xE000 && ucode <= 0xF8FF) 1301151497Sru ustr = UNNAMED; 1302151497Sru else { 1303151497Sru sprintf(codestr, "%04X", ucode); 1304151497Sru ustr = codestr; 1305151497Sru } 1306151497Sru if (!equal(ustr, UNNAMED)) { 1307151497Sru const char *uname_decomposed = decompose_unicode(ustr); 1308151497Sru if (uname_decomposed) 1309151497Sru // 1st char is the number of components 1310151497Sru ustr = uname_decomposed + 1; 1311151497Sru } 1312151497Sru char *value = new char[strlen(ustr) + 1]; 1313151497Sru sprintf(value, equal(ustr, UNNAMED) ? ustr : "u%s", ustr); 1314151497Sru return value; 1315151497Sru} 1316151497Sru 1317151497Srustatic int 1318151497Sruis_uname(char *name) 1319151497Sru{ 1320151497Sru size_t i; 1321151497Sru size_t len = strlen(name); 1322151497Sru if (len % 5) 1323151497Sru return 0; 1324151497Sru 1325151497Sru if (name[0] != 'u') 1326151497Sru return 0; 1327151497Sru for (i = 1; i < 4; i++) 1328151497Sru if (!csxdigit(name[i])) 1329151497Sru return 0; 1330151497Sru for (i = 5; i < len; i++) 1331151497Sru if (i % 5 ? !csxdigit(name[i]) : name[i] != '_') 1332151497Sru return 0; 1333151497Sru 1334151497Sru return 1; 1335151497Sru} 1336151497Sru 1337151497Srustatic int 1338151497Sruread_map(const char *file, const int tfm_type) 1339151497Sru{ 1340114402Sru errno = 0; 1341114402Sru FILE *fp = fopen(file, "r"); 1342114402Sru if (!fp) { 1343114402Sru error("can't open `%1': %2", file, strerror(errno)); 1344114402Sru return 0; 1345114402Sru } 1346114402Sru current_filename = file; 1347114402Sru char buf[512]; 1348114402Sru current_lineno = 0; 1349151497Sru char *nonum; 1350114402Sru while (fgets(buf, int(sizeof(buf)), fp)) { 1351114402Sru current_lineno++; 1352114402Sru char *ptr = buf; 1353114402Sru while (csspace(*ptr)) 1354114402Sru ptr++; 1355114402Sru if (*ptr == '\0' || *ptr == '#') 1356114402Sru continue; 1357114402Sru ptr = strtok(ptr, " \n\t"); 1358114402Sru if (!ptr) 1359114402Sru continue; 1360151497Sru 1361151497Sru int msl_code = int(strtol(ptr, &nonum, 10)); 1362151497Sru if (*nonum != '\0') { 1363151497Sru if (csxdigit(*nonum)) 1364151497Sru error("bad MSL map: got hex code (%1)", ptr); 1365151497Sru else if (ptr == nonum) 1366151497Sru error("bad MSL map: bad MSL code (%1)", ptr); 1367151497Sru else 1368151497Sru error("bad MSL map"); 1369114402Sru fclose(fp); 1370114402Sru return 0; 1371114402Sru } 1372151497Sru 1373151497Sru ptr = strtok(NULL, " \n\t"); 1374151497Sru if (!ptr) 1375151497Sru continue; 1376151497Sru int unicode = int(strtol(ptr, &nonum, 16)); 1377151497Sru if (*nonum != '\0') { 1378151497Sru if (ptr == nonum) 1379151497Sru error("bad Unicode value (%1)", ptr); 1380151497Sru else 1381151497Sru error("bad Unicode map"); 1382114402Sru fclose(fp); 1383114402Sru return 0; 1384114402Sru } 1385151497Sru if (strlen(ptr) != 4) { 1386151497Sru error("bad Unicode value (%1)", ptr); 1387151497Sru return 0; 1388151497Sru } 1389151497Sru 1390151497Sru int n = tfm_type == MSL ? msl_code : unicode; 1391151497Sru if (tfm_type == UNICODE && n > 0xFFFF) { 1392151497Sru // greatest value supported by TFM files 1393151497Sru error("bad Unicode value (%1): greatest value is 0xFFFF", ptr); 1394151497Sru fclose(fp); 1395151497Sru return 0; 1396151497Sru } 1397151497Sru else if (n < 0) { 1398151497Sru error("negative code value (%1)", ptr); 1399151497Sru fclose(fp); 1400151497Sru return 0; 1401151497Sru } 1402151497Sru 1403151497Sru ptr = strtok(NULL, " \n\t"); 1404151497Sru if (!ptr) { // groff name 1405151497Sru error("missing name(s)"); 1406151497Sru fclose(fp); 1407151497Sru return 0; 1408151497Sru } 1409151497Sru // leave decomposed Unicode values alone 1410151497Sru else if (is_uname(ptr) && !is_decomposed(ptr)) 1411151497Sru ptr = unicode_to_ucode_name(strtol(ptr + 1, &nonum, 16)); 1412151497Sru 1413151497Sru if (size_t(n) >= charcode_name_table_size) { 1414151497Sru size_t old_size = charcode_name_table_size; 1415151497Sru name_list **old_table = charcode_name_table; 1416151497Sru charcode_name_table_size = n + 256; 1417151497Sru charcode_name_table = new name_list *[charcode_name_table_size]; 1418114402Sru if (old_table) { 1419151497Sru memcpy(charcode_name_table, old_table, old_size*sizeof(name_list *)); 1420114402Sru a_delete old_table; 1421114402Sru } 1422151497Sru for (size_t i = old_size; i < charcode_name_table_size; i++) 1423151497Sru charcode_name_table[i] = NULL; 1424114402Sru } 1425151497Sru 1426151497Sru // a '#' that isn't the first groff name begins a comment 1427151497Sru for (int names = 1; ptr; ptr = strtok(NULL, " \n\t")) { 1428151497Sru if (names++ > 1 && *ptr == '#') 1429151497Sru break; 1430151497Sru charcode_name_table[n] = new name_list(ptr, charcode_name_table[n]); 1431114402Sru } 1432114402Sru } 1433114402Sru fclose(fp); 1434114402Sru return 1; 1435114402Sru} 1436114402Sru 1437151497Srustatic const char * 1438151497Sruxbasename(const char *s) 1439114402Sru{ 1440114402Sru // DIR_SEPS[] are possible directory separator characters, see 1441114402Sru // nonposix.h. We want the rightmost separator of all possible 1442114402Sru // ones. Example: d:/foo\\bar. 1443114402Sru const char *b = strrchr(s, DIR_SEPS[0]), *b1; 1444114402Sru const char *sep = &DIR_SEPS[1]; 1445114402Sru 1446114402Sru while (*sep) 1447114402Sru { 1448114402Sru b1 = strrchr(s, *sep); 1449114402Sru if (b1 && (!b || b1 > b)) 1450114402Sru b = b1; 1451114402Sru sep++; 1452114402Sru } 1453114402Sru return b ? b + 1 : s; 1454114402Sru} 1455