mkfontscale.c revision 2d6e8b77
1/* 2 Copyright (c) 2002-2003 by Juliusz Chroboczek 3 4 Permission is hereby granted, free of charge, to any person obtaining a copy 5 of this software and associated documentation files (the "Software"), to deal 6 in the Software without restriction, including without limitation the rights 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 copies of the Software, and to permit persons to whom the Software is 9 furnished to do so, subject to the following conditions: 10 11 The above copyright notice and this permission notice shall be included in 12 all copies or substantial portions of the Software. 13 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 THE SOFTWARE. 21*/ 22 23#include "config.h" 24 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28 29#include <sys/types.h> 30#include <sys/stat.h> 31#include <dirent.h> 32#include <unistd.h> 33#include <errno.h> 34#include <ctype.h> 35 36#include <X11/Xos.h> 37#include <X11/fonts/fontenc.h> 38#include <ft2build.h> 39#include FT_FREETYPE_H 40#include FT_SFNT_NAMES_H 41#include FT_TRUETYPE_TABLES_H 42#include FT_TRUETYPE_IDS_H 43#include FT_TYPE1_TABLES_H 44#include FT_BDF_H 45#include FT_XFREE86_H 46 47#include "list.h" 48#include "hash.h" 49#include "data.h" 50#include "ident.h" 51 52#define NPREFIX 1024 53 54#ifndef MAXFONTFILENAMELEN 55#define MAXFONTFILENAMELEN 1024 56#endif 57#ifndef MAXFONTNAMELEN 58#define MAXFONTNAMELEN 1024 59#endif 60 61/* Two levels of macro calls are needed so that we stringify the value 62 of MAXFONT... and not the string "MAXFONT..." */ 63#define QUOTE(x) #x 64#define STRINGIFY(x) QUOTE(x) 65 66static char *encodings_array[] = 67 { "ascii-0", 68 "iso8859-1", "iso8859-2", "iso8859-3", "iso8859-4", "iso8859-5", 69 "iso8859-6", "iso8859-6.8", "iso8859-6.8x", "iso8859-6.16", 70 "iso8859-7", "iso8859-8", "iso8859-9", "iso8859-10", 71 "iso8859-11", "iso8859-12", "iso8859-13", "iso8859-14", 72 "iso8859-15", "iso8859-16", 73 "ansi-1251", "koi8-r", "koi8-u", "koi8-ru", "koi8-e", "koi8-uni", 74 "tis620-2", 75 "sun.unicode.india-0", "suneu-greek", 76 "adobe-standard", "adobe-symbol", 77 "ibm-cp437", "ibm-cp850", "ibm-cp852", "ibm-cp866", "microsoft-cp1252", 78 /* But not "adobe-dingbats", as it uses generic glyph names. */ 79 "cns11643-1", "cns11643-2", "cns11643-3", 80 "jisx0201.1976-0", "jisx0208.1983-0", "jisx0208.1990-0", 81 "jisx0212.1990-0", "big5-0", "big5.eten-0", "big5hkscs-0", 82 "gb2312.1980-0", "gb18030.2000-0", "gb18030.2000-1", 83 "ksc5601.1987-0", "ksc5601.1992-3"}; 84 85static char *extra_encodings_array[] = 86 { "iso10646-1", "adobe-fontspecific", "microsoft-symbol" }; 87 88static ListPtr encodings, extra_encodings; 89static const char *outfilename; 90 91#define countof(_a) (sizeof(_a)/sizeof((_a)[0])) 92 93static int doDirectory(const char*, int, ListPtr); 94static int checkEncoding(FT_Face face, char *encoding_name); 95static int checkExtraEncoding(FT_Face face, char *encoding_name, int found); 96static int find_cmap(int type, int pid, int eid, FT_Face face); 97static const char* notice_foundry(const char *notice); 98static const char* vendor_foundry(const signed char *vendor); 99static int readFontScale(HashTablePtr entries, char *dirname); 100ListPtr makeXLFD(char *filename, FT_Face face, int); 101static int readEncodings(ListPtr encodings, char *dirname); 102 103static FT_Library ft_library; 104static float bigEncodingFuzz = 0.02; 105 106static int relative; 107static int doScalable; 108static int doBitmaps; 109static int doISO10646_1_encoding; 110static int onlyEncodings; 111static ListPtr encodingsToDo; 112static int reencodeLegacy; 113static char *encodingPrefix; 114static char *exclusionSuffix; 115 116static void 117usage(void) 118{ 119 fprintf(stderr, 120 "mkfontscale [ -b ] [ -s ] [ -o filename ] [-x suffix ]\n" 121 " [ -a encoding ] [ -f fuzz ] [ -l ] " 122 " [ -e directory ] [ -p prefix ] [ -n ] [ -r ] \n" 123 " [-u] [-U] [ directory ]...\n"); 124} 125 126int 127main(int argc, char **argv) 128{ 129 int argn; 130 FT_Error ftrc; 131 int rc, ll = 0; 132 char prefix[NPREFIX]; 133 134 encodingPrefix = NULL; 135 exclusionSuffix = NULL; 136 137 if(getcwd(prefix, NPREFIX - 1) == NULL) { 138 perror("Couldn't get cwd"); 139 exit(1); 140 } 141 if(prefix[strlen(prefix) - 1] != '/') 142 strcat(prefix, "/"); 143 encodingPrefix = dsprintf("%s", prefix); 144 145 outfilename = NULL; 146 147 encodings = makeList(encodings_array, countof(encodings_array), NULL, 0); 148 149 extra_encodings = makeList(extra_encodings_array, 150 countof(extra_encodings_array), 151 NULL, 0); 152 doBitmaps = 0; 153 doISO10646_1_encoding = 1; 154 doScalable = 1; 155 onlyEncodings = 0; 156 relative = 0; 157 reencodeLegacy = 1; 158 encodingsToDo = NULL; 159 160 argn = 1; 161 while(argn < argc) { 162 if(argv[argn][0] == '\0' || argv[argn][0] != '-') 163 break; 164 if(argv[argn][1] == '-') { 165 argn++; 166 break; 167 } else if (strcmp(argv[argn], "-x") == 0) { 168 if(argn >= argc - 1) { 169 usage(); 170 exit(1); 171 } 172 exclusionSuffix = argv[argn + 1]; 173 argn += 2; 174 } else if(strcmp(argv[argn], "-a") == 0) { 175 if(argn >= argc - 1) { 176 usage(); 177 exit(1); 178 } 179 makeList(&argv[argn + 1], 1, encodings, 0); 180 argn += 2; 181 } else if(strcmp(argv[argn], "-p") == 0) { 182 if(argn >= argc - 1) { 183 usage(); 184 exit(1); 185 } 186 if(strlen(argv[argn + 1]) > NPREFIX - 1) { 187 usage(); 188 exit(1); 189 } 190 free(encodingPrefix); 191 encodingPrefix = dsprintf("%s", argv[argn + 1]); 192 argn += 2; 193 } else if(strcmp(argv[argn], "-e") == 0) { 194 if(argn >= argc - 1) { 195 usage(); 196 exit(1); 197 } 198 rc = readEncodings(encodingsToDo, argv[argn + 1]); 199 if(rc < 0) 200 exit(1); 201 argn += 2; 202 } else if(strcmp(argv[argn], "-b") == 0) { 203 doBitmaps = 1; 204 argn++; 205 } else if(strcmp(argv[argn], "-u") == 0) { 206 doISO10646_1_encoding = 0; 207 argn++; 208 } else if(strcmp(argv[argn], "-U") == 0) { 209 doISO10646_1_encoding = 1; 210 argn++; 211 } else if(strcmp(argv[argn], "-s") == 0) { 212 doScalable = 0; 213 argn++; 214 } else if(strcmp(argv[argn], "-n") == 0) { 215 onlyEncodings = 1; 216 argn++; 217 } else if(strcmp(argv[argn], "-r") == 0) { 218 relative = 1; 219 argn++; 220 } else if(strcmp(argv[argn], "-l") == 0) { 221 reencodeLegacy = !reencodeLegacy; 222 argn++; 223 } else if(strcmp(argv[argn], "-o") == 0) { 224 if(argn >= argc - 1) { 225 usage(); 226 exit(1); 227 } 228 outfilename = argv[argn + 1]; 229 argn += 2; 230 } else if(strcmp(argv[argn], "-f") == 0) { 231 if(argn >= argc - 1) { 232 usage(); 233 exit(1); 234 } 235 bigEncodingFuzz = atof(argv[argn + 1]) / 100.0; 236 argn += 2; 237 } else if (strcmp(argv[argn], "-r") == 0) { /* ignore for now */ 238 argn++; 239 } else if (strcmp(argv[argn], "-n") == 0) { 240 argn++; 241 } else { 242 usage(); 243 exit(1); 244 } 245 } 246 247 if(outfilename == NULL) { 248 if(doBitmaps) 249 outfilename = "fonts.dir"; 250 else 251 outfilename = "fonts.scale"; 252 } 253 254 ftrc = FT_Init_FreeType(&ft_library); 255 if(ftrc) { 256 fprintf(stderr, "Could not initialise FreeType library: %d\n", ftrc); 257 exit(1); 258 } 259 260 ll = listLength(encodingsToDo); 261 262 if (argn == argc) 263 doDirectory(".", ll, encodingsToDo); 264 else 265 while(argn < argc) { 266 doDirectory(argv[argn], ll, encodingsToDo); 267 argn++; 268 } 269 return 0; 270} 271 272static int 273getNameHelper(FT_Face face, int nid, int pid, int eid, 274 FT_SfntName *name_return) 275{ 276 FT_SfntName name; 277 int n, i; 278 279 n = FT_Get_Sfnt_Name_Count(face); 280 if(n <= 0) 281 return 0; 282 283 for(i = 0; i < n; i++) { 284 if(FT_Get_Sfnt_Name(face, i, &name)) 285 continue; 286 if(name.name_id == nid && 287 name.platform_id == pid && 288 (eid < 0 || name.encoding_id == eid)) { 289 switch(name.platform_id) { 290 case TT_PLATFORM_APPLE_UNICODE: 291 case TT_PLATFORM_MACINTOSH: 292 if(name.language_id != TT_MAC_LANGID_ENGLISH) 293 continue; 294 break; 295 case TT_PLATFORM_MICROSOFT: 296 if(name.language_id != TT_MS_LANGID_ENGLISH_UNITED_STATES && 297 name.language_id != TT_MS_LANGID_ENGLISH_UNITED_KINGDOM) 298 continue; 299 break; 300 default: 301 continue; 302 } 303 if(name.string_len > 0) { 304 *name_return = name; 305 return 1; 306 } 307 } 308 } 309 return 0; 310} 311 312static char * 313getName(FT_Face face, int nid) 314{ 315 FT_SfntName name; 316 char *string; 317 int i; 318 319 if(getNameHelper(face, nid, 320 TT_PLATFORM_MICROSOFT, TT_MS_ID_UNICODE_CS, &name) || 321 getNameHelper(face, nid, 322 TT_PLATFORM_APPLE_UNICODE, -1, &name)) { 323 string = malloc(name.string_len / 2 + 1); 324 if(string == NULL) { 325 fprintf(stderr, "Couldn't allocate name\n"); 326 exit(1); 327 } 328 for(i = 0; i < name.string_len / 2; i++) { 329 if(name.string[2 * i] != 0) 330 string[i] = '?'; 331 else 332 string[i] = name.string[2 * i + 1]; 333 } 334 string[i] = '\0'; 335 return string; 336 } 337 338 /* Pretend that Apple Roman is ISO 8859-1. */ 339 if(getNameHelper(face, nid, TT_PLATFORM_MACINTOSH, TT_MAC_ID_ROMAN, 340 &name)) { 341 string = malloc(name.string_len + 1); 342 if(string == NULL) { 343 fprintf(stderr, "Couldn't allocate name\n"); 344 exit(1); 345 } 346 memcpy(string, name.string, name.string_len); 347 string[name.string_len] = '\0'; 348 return string; 349 } 350 351 return NULL; 352} 353 354static const char* 355os2Weight(int weight) 356{ 357 if(weight < 150) 358 return "thin"; 359 else if(weight < 250) 360 return "extralight"; 361 else if(weight < 350) 362 return "light"; 363 else if(weight < 450) 364 return "medium"; /* officially "normal" */ 365 else if(weight < 550) 366 return "medium"; 367 else if(weight < 650) 368 return "semibold"; 369 else if(weight < 750) 370 return "bold"; 371 else if(weight < 850) 372 return "extrabold"; 373 else 374 return "black"; 375} 376 377static const char* 378os2Width(int width) 379{ 380 if(width <= 1) 381 return "ultracondensed"; 382 else if(width <= 2) 383 return "extracondensed"; 384 else if(width <= 3) 385 return "condensed"; 386 else if(width <= 4) 387 return "semicondensed"; 388 else if(width <= 5) 389 return "normal"; 390 else if(width <= 6) 391 return "semiexpanded"; 392 else if(width <= 7) 393 return "expanded"; 394 else if(width <= 8) 395 return "extraexpanded"; 396 else 397 return "ultraexpanded"; 398} 399 400static const char *widths[] = { 401 "ultracondensed", "extracondensed", "condensed", "semicondensed", 402 "normal", "semiexpanded", "expanded", "extraexpanded", "ultraexpanded" 403}; 404 405#define NUMWIDTHS (sizeof(widths) / sizeof(widths[0])) 406 407static const char* 408nameWidth(const char *name) 409{ 410 char buf[500]; 411 int i; 412 int n = strlen(name); 413 414 if(n >= 499) return NULL; 415 for(i = 0; i < n; i++) 416 buf[i] = tolower(name[i]); 417 buf[i] = '\0'; 418 419 for(i = 0; i < NUMWIDTHS; i++) 420 if(strstr(buf, widths[i])) 421 return widths[i]; 422 return NULL; 423} 424 425static const char* 426t1Weight(const char *weight) 427{ 428 if(!weight) 429 return NULL; 430 if(strcmp(weight, "Thin") == 0) 431 return "thin"; 432 if(strcmp(weight, "ExtraLight") == 0) /* FontForge uses this for 200*/ 433 return "extralight"; 434 if(strcmp(weight, "Light") == 0) 435 return "light"; 436 if(strcmp(weight, "Regular") == 0) 437 return "medium"; 438 if(strcmp(weight, "Normal") == 0) 439 return "medium"; 440 if(strcmp(weight, "Medium") == 0) 441 return "medium"; 442 if(strcmp(weight, "Book") == 0) 443 return "medium"; 444 if(strcmp(weight, "Roman") == 0) /* Some URW++ fonts do that! */ 445 return "medium"; 446 if(strcmp(weight, "Demi") == 0) 447 return "semibold"; 448 if(strcmp(weight, "DemiBold") == 0) 449 return "semibold"; 450 if(strcmp(weight, "SemiBold") == 0) /* some TeX fonts apparently do that */ 451 return "semibold"; 452 else if(strcmp(weight, "Bold") == 0) 453 return "bold"; 454 else if(strcmp(weight, "Heavy") == 0) /* FontForge uses this for 800*/ 455 return "extrabold"; 456 else if(strcmp(weight, "Black") == 0) 457 return "black"; 458 else { 459 fprintf(stderr, "Unknown Type 1 weight \"%s\"\n", weight); 460 return NULL; 461 } 462} 463 464static int 465unsafe(char c) 466{ 467 return 468 c < 0x20 || c > 0x7E || 469 c == '[' || c == ']' || c == '(' || c == ')' || c == '\\' || c == '-'; 470} 471 472static const char * 473safe(const char* s) 474{ 475 int i, len, safe_flag = 1; 476 char *t; 477 478 i = 0; 479 while(s[i] != '\0') { 480 if(unsafe(s[i])) 481 safe_flag = 0; 482 i++; 483 } 484 485 if(safe_flag) return s; 486 487 len = i; 488 t = malloc(len + 1); 489 if(t == NULL) { 490 perror("Couldn't allocate string"); 491 exit(1); 492 } 493 494 for(i = 0; i < len; i++) { 495 if(unsafe(s[i])) 496 t[i] = ' '; 497 else 498 t[i] = s[i]; 499 } 500 t[i] = '\0'; 501 return t; 502} 503 504ListPtr 505makeXLFD(char *filename, FT_Face face, int isBitmap) 506{ 507 ListPtr xlfd = NULL; 508 const char *foundry, *family, *weight, *slant, *sWidth, *adstyle, 509 *spacing, *full_name; 510 TT_Header *head; 511 TT_HoriHeader *hhea; 512 TT_OS2 *os2; 513 TT_Postscript *post; 514 PS_FontInfoRec *t1info, t1info_rec; 515 int rc; 516 517 foundry = NULL; 518 family = NULL; 519 weight = NULL; 520 slant = NULL; 521 sWidth = NULL; 522 adstyle = NULL; 523 spacing = NULL; 524 full_name = NULL; 525 526 head = FT_Get_Sfnt_Table(face, ft_sfnt_head); 527 hhea = FT_Get_Sfnt_Table(face, ft_sfnt_hhea); 528 os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2); 529 post = FT_Get_Sfnt_Table(face, ft_sfnt_post); 530 531 rc = FT_Get_PS_Font_Info(face, &t1info_rec); 532 if(rc == 0) 533 t1info = &t1info_rec; 534 else 535 t1info = NULL; 536 537 if(!family) 538 family = getName(face, TT_NAME_ID_FONT_FAMILY); 539 if(!family) 540 family = getName(face, TT_NAME_ID_FULL_NAME); 541 if(!family) 542 family = getName(face, TT_NAME_ID_PS_NAME); 543 544 if(!full_name) 545 full_name = getName(face, TT_NAME_ID_FULL_NAME); 546 if(!full_name) 547 full_name = getName(face, TT_NAME_ID_PS_NAME); 548 549 if(os2 && os2->version != 0xFFFF) { 550 if(!weight) 551 weight = os2Weight(os2->usWeightClass); 552 if(!sWidth) 553 sWidth = os2Width(os2->usWidthClass); 554 if(!foundry) 555 foundry = vendor_foundry(os2->achVendID); 556 if(!slant) 557 slant = os2->fsSelection & 1 ? "i" : "r"; 558 } 559 560 if(post) { 561 if(!spacing) { 562 if(post->isFixedPitch) { 563 if(hhea->min_Left_Side_Bearing >= 0 && 564 hhea->xMax_Extent <= hhea->advance_Width_Max) { 565 spacing = "c"; 566 } else { 567 spacing = "m"; 568 } 569 } else { 570 spacing = "p"; 571 } 572 } 573 } 574 575 if(t1info) { 576 if(!family) 577 family = t1info->family_name; 578 if(!family) 579 family = t1info->full_name; 580 if(!full_name) 581 full_name = t1info->full_name; 582 if(!foundry) 583 foundry = notice_foundry(t1info->notice); 584 if(!weight) 585 weight = t1Weight(t1info->weight); 586 if(!spacing) 587 spacing = t1info->is_fixed_pitch ? "m" : "p"; 588 if(!slant) { 589 /* Bitstream fonts have positive italic angle. */ 590 slant = 591 t1info->italic_angle <= -4 || t1info->italic_angle >= 4 ? 592 "i" : "r"; 593 } 594 } 595 596 if(!full_name) { 597 fprintf(stderr, "Couldn't determine full name for %s\n", filename); 598 full_name = filename; 599 } 600 601 if(head) { 602 if(!slant) 603 slant = head->Mac_Style & 2 ? "i" : "r"; 604 if(!weight) 605 weight = head->Mac_Style & 1 ? "bold" : "medium"; 606 } 607 608 if(!slant) { 609 fprintf(stderr, "Couldn't determine slant for %s\n", filename); 610 slant = "r"; 611 } 612 613 if(!weight) { 614 fprintf(stderr, "Couldn't determine weight for %s\n", filename); 615 weight = "medium"; 616 } 617 618 if(!foundry) { 619 char *notice; 620 notice = getName(face, TT_NAME_ID_TRADEMARK); 621 if(notice) { 622 foundry = notice_foundry(notice); 623 } 624 if(!foundry) { 625 notice = getName(face, TT_NAME_ID_MANUFACTURER); 626 if(notice) { 627 foundry = notice_foundry(notice); 628 } 629 } 630 } 631 632 if(strcmp(slant, "i") == 0) { 633 if(strstr(full_name, "Oblique")) 634 slant = "o"; 635 if(strstr(full_name, "Slanted")) 636 slant = "o"; 637 } 638 639 if(!sWidth) 640 sWidth = nameWidth(full_name); 641 642 if(!foundry) foundry = "misc"; 643 if(!family) { 644 fprintf(stderr, "Couldn't get family name for %s\n", filename); 645 family = filename; 646 } 647 648 if(!weight) weight = "medium"; 649 if(!slant) slant = "r"; 650 if(!sWidth) sWidth = "normal"; 651 if(!adstyle) adstyle = ""; 652 if(!spacing) spacing = "p"; 653 654 /* Yes, it's a memory leak. */ 655 foundry = safe(foundry); 656 family = safe(family); 657 658 if(!isBitmap) { 659 xlfd = listConsF(xlfd, 660 "-%s-%s-%s-%s-%s-%s-0-0-0-0-%s-0", 661 foundry, family, 662 weight, slant, sWidth, adstyle, spacing); 663 } else { 664 int i, w, h, xres, yres; 665 for(i = 0; i < face->num_fixed_sizes; i++) { 666 w = face->available_sizes[i].width; 667 h = face->available_sizes[i].height; 668 xres = 75; 669 yres = (double)h / w * xres; 670 xlfd = listConsF(xlfd, 671 "-%s-%s-%s-%s-%s-%s-%d-%d-%d-%d-%s-%d", 672 foundry, family, 673 weight, slant, sWidth, adstyle, 674 h, (int)(h / (double)yres * 72.27 * 10 + 0.5), 675 xres, yres, 676 spacing, 60); 677 } 678 } 679 return xlfd; 680} 681 682static int 683readFontScale(HashTablePtr entries, char *dirname) 684{ 685 int n = strlen(dirname); 686 char *filename; 687 FILE *in; 688 int rc, count, i; 689 char file[MAXFONTFILENAMELEN+1], font[MAXFONTNAMELEN+1]; 690 691 if(dirname[n - 1] == '/') 692 filename = dsprintf("%sfonts.scale", dirname); 693 else 694 filename = dsprintf("%s/fonts.scale", dirname); 695 if(filename == NULL) 696 return -1; 697 698 in = fopen(filename, "r"); 699 free(filename); 700 if(in == NULL) { 701 if(errno != ENOENT) 702 perror("open(fonts.scale)"); 703 return -1; 704 } 705 706 rc = fscanf(in, "%d\n", &count); 707 if(rc != 1) { 708 fprintf(stderr, "Invalid fonts.scale in %s.\n", dirname); 709 fclose(in); 710 return -1; 711 } 712 713 for(i = 0; i < count; i++) { 714 rc = fscanf(in, 715 "%" STRINGIFY(MAXFONTFILENAMELEN) "s " 716 "%" STRINGIFY(MAXFONTNAMELEN) "[^\n]\n", 717 file, font); 718 if(rc != 2) 719 break; 720 putHash(entries, font, file, 100); 721 } 722 fclose(in); 723 return 1; 724} 725 726static int 727filePrio(char *filename) 728{ 729 int n = strlen(filename); 730 if(n < 4) 731 return 0; 732 if(strcmp(filename + n - 4, ".otf") == 0) 733 return 6; 734 if(strcmp(filename + n - 4, ".OTF") == 0) 735 return 6; 736 if(strcmp(filename + n - 4, ".ttf") == 0) 737 return 5; 738 if(strcmp(filename + n - 4, ".TTF") == 0) 739 return 5; 740 if(strcmp(filename + n - 4, ".pcf") == 0) 741 return 4; 742 if(strcmp(filename + n - 4, ".PCF") == 0) 743 return 4; 744 if(strcmp(filename + n - 3, ".gz") == 0) 745 return 3; 746#ifdef X_BZIP2_FONT_COMPRESSION 747 if(strcmp(filename + n - 4, ".bz2") == 0) 748 return 2; 749#endif 750 if(strcmp(filename + n - 2, ".Z") == 0) 751 return 2; 752 if(strcmp(filename + n - 4, ".bdf") == 0) 753 return 1; 754 if(strcmp(filename + n - 4, ".BDF") == 0) 755 return 1; 756 return 0; 757} 758 759static int 760doDirectory(const char *dirname_given, int numEncodings, ListPtr encodingsToDo) 761{ 762 char *dirname, *fontscale_name, *filename, *encdir; 763 FILE *fontscale, *encfile; 764 DIR *dirp; 765 struct dirent *entry; 766 FT_Error ftrc; 767 FT_Face face; 768 ListPtr encoding, xlfd, lp; 769 HashTablePtr entries; 770 HashBucketPtr *array; 771 int i, n, found, rc; 772 int isBitmap=0,xl=0; 773 774 if (exclusionSuffix) 775 xl = strlen (exclusionSuffix); 776 777 i = strlen(dirname_given); 778 if(i == 0) 779 dirname = dsprintf("./"); 780 else if(dirname_given[i - 1] != '/') 781 dirname = dsprintf("%s/", dirname_given); 782 else 783 dirname = dsprintf("%s", dirname_given); 784 785 if(dirname == NULL) { 786 perror("dirname"); 787 exit(1); 788 } 789 790 if (onlyEncodings) 791 goto encodings; 792 793 entries = makeHashTable(); 794 if(doBitmaps && !doScalable) { 795 readFontScale(entries, dirname); 796 } 797 798 if(strcmp(outfilename, "-") == 0) 799 fontscale_name = NULL; 800 else { 801 if(outfilename[0] == '/') 802 fontscale_name = dsprintf("%s", outfilename); 803 else 804 fontscale_name = dsprintf("%s%s", dirname, outfilename); 805 if(fontscale_name == NULL) { 806 perror("fontscale_name"); 807 exit(1); 808 } 809 } 810 811 dirp = opendir(dirname); 812 if(dirp == NULL) { 813 fprintf(stderr, "%s: ", dirname); 814 perror("opendir"); 815 return 0; 816 } 817 818 if(fontscale_name == NULL) 819 fontscale = stdout; 820 else 821 fontscale = fopen(fontscale_name, "wb"); 822 823 if(fontscale == NULL) { 824 fprintf(stderr, "%s: ", fontscale_name); 825 perror("fopen(w)"); 826 return 0; 827 } 828 829 while((entry = readdir(dirp)) != NULL) { 830 int have_face = 0; 831 char *xlfd_name = NULL; 832 struct stat f_stat; 833 int tprio = 1; 834 835 xlfd = NULL; 836 837 if (xl) { 838 int dl = strlen (entry->d_name); 839 if (strcmp (entry->d_name + dl - xl, exclusionSuffix) == 0) 840 continue; 841 } 842 843 filename = dsprintf("%s%s", dirname, entry->d_name); 844 845#define PRIO(x) ((x << 1) + tprio) 846#ifdef DT_LNK 847 if (entry->d_type != DT_UNKNOWN) { 848 if (entry->d_type == DT_LNK) 849 tprio = 0; 850 } else 851#endif 852#ifdef S_ISLNK 853 { 854 if (lstat(filename, &f_stat)) 855 goto done; 856 if (S_ISLNK(f_stat.st_mode)) 857 tprio = 0; 858 } 859#else 860 ; 861#endif 862 if(doBitmaps) 863 rc = bitmapIdentify(filename, &xlfd_name); 864 else 865 rc = 0; 866 867 if(rc < 0) 868 goto done; 869 870 if(rc == 0) { 871 ftrc = FT_New_Face(ft_library, filename, 0, &face); 872 if(ftrc) 873 goto done; 874 have_face = 1; 875 876 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 877 878 if(!isBitmap) { 879 /* Workaround for bitmap-only SFNT fonts */ 880 if(FT_IS_SFNT(face) && face->num_fixed_sizes > 0 && 881 strcmp(FT_Get_X11_Font_Format(face), "TrueType") == 0) { 882 TT_MaxProfile *maxp; 883 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 884 if(maxp != NULL && maxp->maxContours == 0) 885 isBitmap = 1; 886 } 887 } 888 889 if(isBitmap) { 890 if(!doBitmaps) 891 goto done; 892 } else { 893 if(!doScalable) 894 goto done; 895 } 896 897 if(isBitmap) { 898 BDF_PropertyRec prop; 899 rc = FT_Get_BDF_Property(face, "FONT", &prop); 900 if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) { 901 xlfd_name = strdup(prop.u.atom); 902 if(xlfd_name == NULL) 903 goto done; 904 } 905 } 906 } 907 908 if(xlfd_name) { 909 /* We know it's a bitmap font, and we know its XLFD */ 910 int n = strlen(xlfd_name); 911 if(reencodeLegacy && 912 n >= 12 && strcasecmp(xlfd_name + n - 11, "-iso10646-1") == 0) { 913 char *s; 914 915 s = malloc(n - 10); 916 memcpy(s, xlfd_name, n - 11); 917 s[n - 11] = '\0'; 918 xlfd = listCons(s, xlfd); 919 } else { 920 /* Not a reencodable font -- skip all the rest of the loop body */ 921 putHash(entries, xlfd_name, entry->d_name, PRIO(filePrio(entry->d_name))); 922 goto done; 923 } 924 } 925 926 if(!have_face) { 927 ftrc = FT_New_Face(ft_library, filename, 0, &face); 928 if(ftrc) 929 goto done; 930 have_face = 1; 931 isBitmap = ((face->face_flags & FT_FACE_FLAG_SCALABLE) == 0); 932 933 if(!isBitmap) { 934 if(face->num_fixed_sizes > 0) { 935 TT_MaxProfile *maxp; 936 maxp = FT_Get_Sfnt_Table(face, ft_sfnt_maxp); 937 if(maxp != NULL && maxp->maxContours == 0) 938 isBitmap = 1; 939 } 940 } 941 } 942 943 if(xlfd == NULL) 944 xlfd = makeXLFD(entry->d_name, face, isBitmap); 945 946 found = 0; 947 948 for(lp = xlfd; lp; lp = lp->next) { 949 char buf[MAXFONTNAMELEN]; 950 for(encoding = encodings; encoding; encoding = encoding->next) { 951 if(checkEncoding(face, encoding->value)) { 952 found = 1; 953 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 954 lp->value, encoding->value); 955 putHash(entries, buf, entry->d_name, PRIO(filePrio(entry->d_name))); 956 } 957 } 958 for(encoding = extra_encodings; encoding; 959 encoding = encoding->next) { 960 if(checkExtraEncoding(face, encoding->value, found)) { 961 /* Do not set found! */ 962 snprintf(buf, MAXFONTNAMELEN, "%s-%s", 963 lp->value, encoding->value); 964 putHash(entries, buf, entry->d_name, PRIO(filePrio(entry->d_name))); 965 } 966 } 967 } 968 done: 969 if(have_face) 970 FT_Done_Face(face); 971 deepDestroyList(xlfd); 972 xlfd = NULL; 973 free(filename); 974#undef PRIO 975 } 976 977 closedir(dirp); 978 n = hashElements(entries); 979 fprintf(fontscale, "%d\n", n); 980 array = hashArray(entries, 1); 981 for(i = 0; i < n; i++) 982 fprintf(fontscale, "%s %s\n", array[i]->value, array[i]->key); 983 destroyHashArray(array); 984 entries = NULL; 985 if(fontscale_name) { 986 fclose(fontscale); 987 free(fontscale_name); 988 } 989 990 encodings: 991 encdir = dsprintf("%s%s", dirname, "encodings.dir"); 992 993 if(encdir == NULL) { 994 perror("encodings"); 995 exit(1); 996 } 997 unlink(encdir); 998 999 if (numEncodings) { 1000 encfile = fopen(encdir, "w"); 1001 if(encfile == NULL) { 1002 perror("open(encodings.dir)"); 1003 exit(1); 1004 } 1005 fprintf(encfile, "%d\n", numEncodings); 1006 encodingsToDo = sortList(encodingsToDo); 1007 for(lp = encodingsToDo; lp; lp = lp->next) { 1008 fprintf(encfile, "%s\n", lp->value); 1009 } 1010 fclose (encfile); 1011 } 1012 1013 free(dirname); 1014 return 1; 1015} 1016 1017#define CODE_IGNORED(c) ((c) < 0x20 || \ 1018 ((c) >= 0x7F && (c) <= 0xA0) || \ 1019 (c) == 0xAD || (c) == 0xF71B) 1020 1021static int 1022checkEncoding(FT_Face face, char *encoding_name) 1023{ 1024 FontEncPtr encoding; 1025 FontMapPtr mapping; 1026 int i, j, c, koi8; 1027 char *n; 1028 1029 encoding = FontEncFind(encoding_name, NULL); 1030 if(!encoding) 1031 return 0; 1032 1033 /* An encoding is ``small'' if one of the following is true: 1034 - it is linear and has no more than 256 codepoints; or 1035 - it is a matrix encoding and has no more than one column. 1036 1037 For small encodings using Unicode indices, we require perfect 1038 coverage except for CODE_IGNORED and KOI-8 IBM-PC compatibility. 1039 1040 For large encodings, we require coverage up to bigEncodingFuzz. 1041 1042 For encodings using PS names (currently Adobe Standard and 1043 Adobe Symbol only), we require perfect coverage. */ 1044 1045 1046 if(FT_Has_PS_Glyph_Names(face)) { 1047 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1048 if(mapping->type == FONT_ENCODING_POSTSCRIPT) { 1049 if(encoding->row_size > 0) { 1050 for(i = encoding->first; i < encoding->size; i++) { 1051 for(j = encoding->first_col; 1052 j < encoding->row_size; 1053 j++) { 1054 n = FontEncName((i<<8) | j, mapping); 1055 if(n && FT_Get_Name_Index(face, n) == 0) { 1056 return 0; 1057 } 1058 } 1059 } 1060 return 1; 1061 } else { 1062 for(i = encoding->first; i < encoding->size; i++) { 1063 n = FontEncName(i, mapping); 1064 if(n && FT_Get_Name_Index(face, n) == 0) { 1065 return 0; 1066 } 1067 } 1068 return 1; 1069 } 1070 } 1071 } 1072 } 1073 1074 for(mapping = encoding->mappings; mapping; mapping = mapping->next) { 1075 if(find_cmap(mapping->type, mapping->pid, mapping->eid, face)) { 1076 int total = 0, failed = 0; 1077 if(encoding->row_size > 0) { 1078 int estimate = 1079 (encoding->size - encoding->first) * 1080 (encoding->row_size - encoding->first_col); 1081 for(i = encoding->first; i < encoding->size; i++) { 1082 for(j = encoding->first_col; 1083 j < encoding->row_size; 1084 j++) { 1085 c = FontEncRecode((i<<8) | j, mapping); 1086 if(CODE_IGNORED(c)) { 1087 continue; 1088 } else { 1089 if(FT_Get_Char_Index(face, c) == 0) { 1090 failed++; 1091 } 1092 total++; 1093 if((encoding->size <= 1 && failed > 0) || 1094 ((float)failed >= bigEncodingFuzz * estimate)) { 1095 return 0; 1096 } 1097 } 1098 } 1099 } 1100 if((float)failed >= total * bigEncodingFuzz) 1101 return 0; 1102 else 1103 return 1; 1104 } else { 1105 int estimate = encoding->size - encoding->first; 1106 /* For the KOI8 encodings, we ignore the lack of 1107 linedrawing and pseudo-math characters */ 1108 if(strncmp(encoding->name, "koi8-", 5) == 0) 1109 koi8 = 1; 1110 else 1111 koi8 = 0; 1112 for(i = encoding->first; i < encoding->size; i++) { 1113 c = FontEncRecode(i, mapping); 1114 if(CODE_IGNORED(c) || 1115 (koi8 && ((c >= 0x2200 && c < 0x2600) || c == 0x00b2))) { 1116 continue; 1117 } else { 1118 if(FT_Get_Char_Index(face, c) == 0) { 1119 failed++; 1120 } 1121 total++; 1122 if((encoding->size <= 256 && failed > 0) || 1123 ((float)failed >= bigEncodingFuzz * estimate)) { 1124 return 0; 1125 } 1126 } 1127 } 1128 if((float)failed >= total * bigEncodingFuzz) 1129 return 0; 1130 else 1131 return 1; 1132 } 1133 } 1134 } 1135 return 0; 1136} 1137 1138static int 1139find_cmap(int type, int pid, int eid, FT_Face face) 1140{ 1141 int i, n, rc; 1142 FT_CharMap cmap = NULL; 1143 1144 n = face->num_charmaps; 1145 1146 switch(type) { 1147 case FONT_ENCODING_TRUETYPE: /* specific cmap */ 1148 for(i=0; i<n; i++) { 1149 cmap = face->charmaps[i]; 1150 if(cmap->platform_id == pid && cmap->encoding_id == eid) { 1151 rc = FT_Set_Charmap(face, cmap); 1152 if(rc == 0) 1153 return 1; 1154 } 1155 } 1156 break; 1157 case FONT_ENCODING_UNICODE: /* any Unicode cmap */ 1158 /* prefer Microsoft Unicode */ 1159 for(i=0; i<n; i++) { 1160 cmap = face->charmaps[i]; 1161 if(cmap->platform_id == TT_PLATFORM_MICROSOFT && 1162 cmap->encoding_id == TT_MS_ID_UNICODE_CS) { 1163 rc = FT_Set_Charmap(face, cmap); 1164 if(rc == 0) 1165 return 1; 1166 } 1167 } 1168 /* Try Apple Unicode */ 1169 for(i=0; i<n; i++) { 1170 cmap = face->charmaps[i]; 1171 if(cmap->platform_id == TT_PLATFORM_APPLE_UNICODE) { 1172 rc = FT_Set_Charmap(face, cmap); 1173 if(rc == 0) 1174 return 1; 1175 } 1176 } 1177 /* ISO Unicode? */ 1178 for(i=0; i<n; i++) { 1179 cmap = face->charmaps[i]; 1180 if(cmap->platform_id == TT_PLATFORM_ISO) { 1181 rc = FT_Set_Charmap(face, cmap); 1182 if(rc == 0) 1183 return 1; 1184 } 1185 } 1186 break; 1187 default: 1188 return 0; 1189 } 1190 return 0; 1191} 1192 1193static int 1194checkExtraEncoding(FT_Face face, char *encoding_name, int found) 1195{ 1196 int c; 1197 1198 if(strcasecmp(encoding_name, "iso10646-1") == 0) { 1199 if(doISO10646_1_encoding && find_cmap(FONT_ENCODING_UNICODE, -1, -1, face)) { 1200 int found = 0; 1201 /* Export as Unicode if there are at least 15 BMP 1202 characters that are not a space or ignored. */ 1203 for(c = 0x21; c < 0x10000; c++) { 1204 if(CODE_IGNORED(c)) 1205 continue; 1206 if(FT_Get_Char_Index(face, c) > 0) 1207 found++; 1208 if(found >= 15) 1209 return 1; 1210 } 1211 return 0; 1212 } else 1213 return 0; 1214 } else if(strcasecmp(encoding_name, "microsoft-symbol") == 0) { 1215 if(find_cmap(FONT_ENCODING_TRUETYPE, 1216 TT_PLATFORM_MICROSOFT, TT_MS_ID_SYMBOL_CS, 1217 face)) 1218 return 1; 1219 else 1220 return 0; 1221 } else if(strcasecmp(encoding_name, "adobe-fontspecific") == 0) { 1222 if(!found) { 1223 if(FT_Has_PS_Glyph_Names(face)) 1224 return 1; 1225 else 1226 return 0; 1227 } else 1228 return 0; 1229 } else { 1230 fprintf(stderr, "Unknown extra encoding %s\n", encoding_name); 1231 return 0; 1232 } 1233} 1234 1235static const char* 1236notice_foundry(const char *notice) 1237{ 1238 int i; 1239 for(i = 0; i < countof(notice_foundries); i++) 1240 if(notice && strstr(notice, notice_foundries[i][0])) 1241 return notice_foundries[i][1]; 1242 return NULL; 1243} 1244 1245static int 1246vendor_match(const signed char *vendor, const char *vendor_string) 1247{ 1248 /* vendor is not necessarily NUL-terminated. */ 1249 int i, len; 1250 len = strlen(vendor_string); 1251 if(memcmp(vendor, vendor_string, len) != 0) 1252 return 0; 1253 for(i = len; i < 4; i++) 1254 if(vendor[i] != ' ' && vendor[i] != '\0') 1255 return 0; 1256 return 1; 1257} 1258 1259static const char* 1260vendor_foundry(const signed char *vendor) 1261{ 1262 int i; 1263 for(i = 0; i < countof(vendor_foundries); i++) 1264 if(vendor_match(vendor, vendor_foundries[i][0])) 1265 return vendor_foundries[i][1]; 1266 return NULL; 1267} 1268 1269static int 1270readEncodings(ListPtr encodings, char *dirname) 1271{ 1272 char *fullname; 1273 DIR *dirp; 1274 struct dirent *file; 1275 char **names, **name; 1276 1277 if(strlen(dirname) > 1 && dirname[strlen(dirname) - 1] == '/') 1278 dirname[strlen(dirname) - 1] = '\0'; 1279 1280 dirp = opendir(dirname); 1281 if(dirp == NULL) { 1282 perror("opendir"); 1283 return -1; 1284 } 1285 1286 while((file = readdir(dirp)) != NULL) { 1287 fullname = dsprintf("%s/%s", dirname, file->d_name); 1288 if(fullname == NULL) { 1289 fprintf(stderr, "Couldn't allocate fullname\n"); 1290 closedir(dirp); 1291 return -1; 1292 } 1293 1294 names = FontEncIdentify(fullname); 1295 if(!names) 1296 continue; 1297 1298 for(name = names; *name; name++) { 1299 if(fullname[0] != '/' && !relative) { 1300 char *n; 1301 n = dsprintf("%s%s", encodingPrefix, fullname); 1302 if(n == NULL) { 1303 fprintf(stderr, "Couldn't allocate name\n"); 1304 closedir(dirp); 1305 return -1; 1306 } 1307 encodingsToDo = listConsF(encodingsToDo, "%s %s", *name, n); 1308 free(n); 1309 } else { 1310 encodingsToDo = 1311 listConsF(encodingsToDo, "%s %s", *name, fullname); 1312 } 1313 if(encodingsToDo == NULL) { 1314 fprintf(stderr, "Couldn't allocate encodings\n"); 1315 closedir(dirp); 1316 return -1; 1317 } 1318 } 1319 free(names); /* only the spine */ 1320 } 1321 closedir(dirp); 1322 return 0; 1323} 1324