1 /**************************************************************************** 2 * 3 * ttpost.c 4 * 5 * PostScript name table processing for TrueType and OpenType fonts 6 * (body). 7 * 8 * Copyright (C) 1996-2020 by 9 * David Turner, Robert Wilhelm, and Werner Lemberg. 10 * 11 * This file is part of the FreeType project, and may only be used, 12 * modified, and distributed under the terms of the FreeType project 13 * license, LICENSE.TXT. By continuing to use, modify, or distribute 14 * this file you indicate that you have read the license and 15 * understand and accept it fully. 16 * 17 */ 18 19 /************************************************************************** 20 * 21 * The post table is not completely loaded by the core engine. This 22 * file loads the missing PS glyph names and implements an API to access 23 * them. 24 * 25 */ 26 27 28 #include <freetype/internal/ftdebug.h> 29 #include <freetype/internal/ftstream.h> 30 #include <freetype/tttags.h> 31 32 33 #ifdef TT_CONFIG_OPTION_POSTSCRIPT_NAMES 34 35 #include "ttpost.h" 36 37 #include "sferrors.h" 38 39 40 /************************************************************************** 41 * 42 * The macro FT_COMPONENT is used in trace mode. It is an implicit 43 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log 44 * messages during execution. 45 */ 46 #undef FT_COMPONENT 47 #define FT_COMPONENT ttpost 48 49 50 /* If this configuration macro is defined, we rely on the `psnames' */ 51 /* module to grab the glyph names. */ 52 53 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES 54 55 56 #include <freetype/internal/services/svpscmap.h> 57 58 #define MAC_NAME( x ) (FT_String*)psnames->macintosh_name( (FT_UInt)(x) ) 59 60 61 #else /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ 62 63 64 /* Otherwise, we ignore the `psnames' module, and provide our own */ 65 /* table of Mac names. Thus, it is possible to build a version of */ 66 /* FreeType without the Type 1 driver & psnames module. */ 67 68 #define MAC_NAME( x ) (FT_String*)tt_post_default_names[x] 69 70 /* the 258 default Mac PS glyph names; see file `tools/glnames.py' */ 71 72 static const FT_String* const tt_post_default_names[258] = 73 { 74 /* 0 */ 75 ".notdef", ".null", "nonmarkingreturn", "space", "exclam", 76 "quotedbl", "numbersign", "dollar", "percent", "ampersand", 77 /* 10 */ 78 "quotesingle", "parenleft", "parenright", "asterisk", "plus", 79 "comma", "hyphen", "period", "slash", "zero", 80 /* 20 */ 81 "one", "two", "three", "four", "five", 82 "six", "seven", "eight", "nine", "colon", 83 /* 30 */ 84 "semicolon", "less", "equal", "greater", "question", 85 "at", "A", "B", "C", "D", 86 /* 40 */ 87 "E", "F", "G", "H", "I", 88 "J", "K", "L", "M", "N", 89 /* 50 */ 90 "O", "P", "Q", "R", "S", 91 "T", "U", "V", "W", "X", 92 /* 60 */ 93 "Y", "Z", "bracketleft", "backslash", "bracketright", 94 "asciicircum", "underscore", "grave", "a", "b", 95 /* 70 */ 96 "c", "d", "e", "f", "g", 97 "h", "i", "j", "k", "l", 98 /* 80 */ 99 "m", "n", "o", "p", "q", 100 "r", "s", "t", "u", "v", 101 /* 90 */ 102 "w", "x", "y", "z", "braceleft", 103 "bar", "braceright", "asciitilde", "Adieresis", "Aring", 104 /* 100 */ 105 "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", 106 "aacute", "agrave", "acircumflex", "adieresis", "atilde", 107 /* 110 */ 108 "aring", "ccedilla", "eacute", "egrave", "ecircumflex", 109 "edieresis", "iacute", "igrave", "icircumflex", "idieresis", 110 /* 120 */ 111 "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", 112 "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", 113 /* 130 */ 114 "dagger", "degree", "cent", "sterling", "section", 115 "bullet", "paragraph", "germandbls", "registered", "copyright", 116 /* 140 */ 117 "trademark", "acute", "dieresis", "notequal", "AE", 118 "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", 119 /* 150 */ 120 "yen", "mu", "partialdiff", "summation", "product", 121 "pi", "integral", "ordfeminine", "ordmasculine", "Omega", 122 /* 160 */ 123 "ae", "oslash", "questiondown", "exclamdown", "logicalnot", 124 "radical", "florin", "approxequal", "Delta", "guillemotleft", 125 /* 170 */ 126 "guillemotright", "ellipsis", "nonbreakingspace", "Agrave", "Atilde", 127 "Otilde", "OE", "oe", "endash", "emdash", 128 /* 180 */ 129 "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", 130 "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", 131 /* 190 */ 132 "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", 133 "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", 134 /* 200 */ 135 "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", 136 "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", 137 /* 210 */ 138 "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", 139 "dotlessi", "circumflex", "tilde", "macron", "breve", 140 /* 220 */ 141 "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", 142 "caron", "Lslash", "lslash", "Scaron", "scaron", 143 /* 230 */ 144 "Zcaron", "zcaron", "brokenbar", "Eth", "eth", 145 "Yacute", "yacute", "Thorn", "thorn", "minus", 146 /* 240 */ 147 "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", 148 "onequarter", "threequarters", "franc", "Gbreve", "gbreve", 149 /* 250 */ 150 "Idotaccent", "Scedilla", "scedilla", "Cacute", "cacute", 151 "Ccaron", "ccaron", "dcroat", 152 }; 153 154 155 #endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ 156 157 158 static FT_Error load_format_20(TT_Face face,FT_Stream stream,FT_ULong post_limit)159 load_format_20( TT_Face face, 160 FT_Stream stream, 161 FT_ULong post_limit ) 162 { 163 FT_Memory memory = stream->memory; 164 FT_Error error; 165 166 FT_Int num_glyphs; 167 FT_UShort num_names; 168 169 FT_UShort* glyph_indices = NULL; 170 FT_Char** name_strings = NULL; 171 172 173 if ( FT_READ_USHORT( num_glyphs ) ) 174 goto Exit; 175 176 /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ 177 /* than the value in the maxp table (cf. cyberbit.ttf). */ 178 179 /* There already exist fonts which have more than 32768 glyph names */ 180 /* in this table, so the test for this threshold has been dropped. */ 181 182 if ( num_glyphs > face->max_profile.numGlyphs ) 183 { 184 error = FT_THROW( Invalid_File_Format ); 185 goto Exit; 186 } 187 188 /* load the indices */ 189 { 190 FT_Int n; 191 192 193 if ( FT_NEW_ARRAY ( glyph_indices, num_glyphs ) || 194 FT_FRAME_ENTER( num_glyphs * 2L ) ) 195 goto Fail; 196 197 for ( n = 0; n < num_glyphs; n++ ) 198 glyph_indices[n] = FT_GET_USHORT(); 199 200 FT_FRAME_EXIT(); 201 } 202 203 /* compute number of names stored in table */ 204 { 205 FT_Int n; 206 207 208 num_names = 0; 209 210 for ( n = 0; n < num_glyphs; n++ ) 211 { 212 FT_Int idx; 213 214 215 idx = glyph_indices[n]; 216 if ( idx >= 258 ) 217 { 218 idx -= 257; 219 if ( idx > num_names ) 220 num_names = (FT_UShort)idx; 221 } 222 } 223 } 224 225 /* now load the name strings */ 226 { 227 FT_UShort n; 228 229 230 if ( FT_NEW_ARRAY( name_strings, num_names ) ) 231 goto Fail; 232 233 for ( n = 0; n < num_names; n++ ) 234 { 235 FT_UInt len; 236 237 238 if ( FT_STREAM_POS() >= post_limit ) 239 break; 240 else 241 { 242 FT_TRACE6(( "load_format_20: %ld byte left in post table\n", 243 post_limit - FT_STREAM_POS() )); 244 245 if ( FT_READ_BYTE( len ) ) 246 goto Fail1; 247 } 248 249 if ( len > post_limit || 250 FT_STREAM_POS() > post_limit - len ) 251 { 252 FT_Int d = (FT_Int)post_limit - (FT_Int)FT_STREAM_POS(); 253 254 255 FT_ERROR(( "load_format_20:" 256 " exceeding string length (%d)," 257 " truncating at end of post table (%d byte left)\n", 258 len, d )); 259 len = (FT_UInt)FT_MAX( 0, d ); 260 } 261 262 if ( FT_NEW_ARRAY( name_strings[n], len + 1 ) || 263 FT_STREAM_READ( name_strings[n], len ) ) 264 goto Fail1; 265 266 name_strings[n][len] = '\0'; 267 } 268 269 if ( n < num_names ) 270 { 271 FT_ERROR(( "load_format_20:" 272 " all entries in post table are already parsed," 273 " using NULL names for gid %d - %d\n", 274 n, num_names - 1 )); 275 for ( ; n < num_names; n++ ) 276 if ( FT_NEW_ARRAY( name_strings[n], 1 ) ) 277 goto Fail1; 278 else 279 name_strings[n][0] = '\0'; 280 } 281 } 282 283 /* all right, set table fields and exit successfully */ 284 { 285 TT_Post_20 table = &face->postscript_names.names.format_20; 286 287 288 table->num_glyphs = (FT_UShort)num_glyphs; 289 table->num_names = (FT_UShort)num_names; 290 table->glyph_indices = glyph_indices; 291 table->glyph_names = name_strings; 292 } 293 return FT_Err_Ok; 294 295 Fail1: 296 { 297 FT_UShort n; 298 299 300 for ( n = 0; n < num_names; n++ ) 301 FT_FREE( name_strings[n] ); 302 } 303 304 Fail: 305 FT_FREE( name_strings ); 306 FT_FREE( glyph_indices ); 307 308 Exit: 309 return error; 310 } 311 312 313 static FT_Error load_format_25(TT_Face face,FT_Stream stream,FT_ULong post_limit)314 load_format_25( TT_Face face, 315 FT_Stream stream, 316 FT_ULong post_limit ) 317 { 318 FT_Memory memory = stream->memory; 319 FT_Error error; 320 321 FT_Int num_glyphs; 322 FT_Char* offset_table = NULL; 323 324 FT_UNUSED( post_limit ); 325 326 327 if ( FT_READ_USHORT( num_glyphs ) ) 328 goto Exit; 329 330 /* check the number of glyphs */ 331 if ( num_glyphs > face->max_profile.numGlyphs || 332 num_glyphs > 258 || 333 num_glyphs < 1 ) 334 { 335 error = FT_THROW( Invalid_File_Format ); 336 goto Exit; 337 } 338 339 if ( FT_NEW_ARRAY( offset_table, num_glyphs ) || 340 FT_STREAM_READ( offset_table, num_glyphs ) ) 341 goto Fail; 342 343 /* now check the offset table */ 344 { 345 FT_Int n; 346 347 348 for ( n = 0; n < num_glyphs; n++ ) 349 { 350 FT_Long idx = (FT_Long)n + offset_table[n]; 351 352 353 if ( idx < 0 || idx > num_glyphs ) 354 { 355 error = FT_THROW( Invalid_File_Format ); 356 goto Fail; 357 } 358 } 359 } 360 361 /* OK, set table fields and exit successfully */ 362 { 363 TT_Post_25 table = &face->postscript_names.names.format_25; 364 365 366 table->num_glyphs = (FT_UShort)num_glyphs; 367 table->offsets = offset_table; 368 } 369 370 return FT_Err_Ok; 371 372 Fail: 373 FT_FREE( offset_table ); 374 375 Exit: 376 return error; 377 } 378 379 380 static FT_Error load_post_names(TT_Face face)381 load_post_names( TT_Face face ) 382 { 383 FT_Stream stream; 384 FT_Error error; 385 FT_Fixed format; 386 FT_ULong post_len; 387 FT_ULong post_limit; 388 389 390 /* get a stream for the face's resource */ 391 stream = face->root.stream; 392 393 /* seek to the beginning of the PS names table */ 394 error = face->goto_table( face, TTAG_post, stream, &post_len ); 395 if ( error ) 396 goto Exit; 397 398 post_limit = FT_STREAM_POS() + post_len; 399 400 format = face->postscript.FormatType; 401 402 /* go to beginning of subtable */ 403 if ( FT_STREAM_SKIP( 32 ) ) 404 goto Exit; 405 406 /* now read postscript table */ 407 if ( format == 0x00020000L ) 408 error = load_format_20( face, stream, post_limit ); 409 else if ( format == 0x00025000L ) 410 error = load_format_25( face, stream, post_limit ); 411 else 412 error = FT_THROW( Invalid_File_Format ); 413 414 face->postscript_names.loaded = 1; 415 416 Exit: 417 return error; 418 } 419 420 421 FT_LOCAL_DEF( void ) tt_face_free_ps_names(TT_Face face)422 tt_face_free_ps_names( TT_Face face ) 423 { 424 FT_Memory memory = face->root.memory; 425 TT_Post_Names names = &face->postscript_names; 426 FT_Fixed format; 427 428 429 if ( names->loaded ) 430 { 431 format = face->postscript.FormatType; 432 433 if ( format == 0x00020000L ) 434 { 435 TT_Post_20 table = &names->names.format_20; 436 FT_UShort n; 437 438 439 FT_FREE( table->glyph_indices ); 440 table->num_glyphs = 0; 441 442 for ( n = 0; n < table->num_names; n++ ) 443 FT_FREE( table->glyph_names[n] ); 444 445 FT_FREE( table->glyph_names ); 446 table->num_names = 0; 447 } 448 else if ( format == 0x00025000L ) 449 { 450 TT_Post_25 table = &names->names.format_25; 451 452 453 FT_FREE( table->offsets ); 454 table->num_glyphs = 0; 455 } 456 } 457 names->loaded = 0; 458 } 459 460 461 /************************************************************************** 462 * 463 * @Function: 464 * tt_face_get_ps_name 465 * 466 * @Description: 467 * Get the PostScript glyph name of a glyph. 468 * 469 * @Input: 470 * face :: 471 * A handle to the parent face. 472 * 473 * idx :: 474 * The glyph index. 475 * 476 * @InOut: 477 * PSname :: 478 * The address of a string pointer. Undefined in case of 479 * error, otherwise it is a pointer to the glyph name. 480 * 481 * You must not modify the returned string! 482 * 483 * @Output: 484 * FreeType error code. 0 means success. 485 */ 486 FT_LOCAL_DEF( FT_Error ) tt_face_get_ps_name(TT_Face face,FT_UInt idx,FT_String ** PSname)487 tt_face_get_ps_name( TT_Face face, 488 FT_UInt idx, 489 FT_String** PSname ) 490 { 491 FT_Error error; 492 TT_Post_Names names; 493 FT_Fixed format; 494 495 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES 496 FT_Service_PsCMaps psnames; 497 #endif 498 499 500 if ( !face ) 501 return FT_THROW( Invalid_Face_Handle ); 502 503 if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) 504 return FT_THROW( Invalid_Glyph_Index ); 505 506 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES 507 psnames = (FT_Service_PsCMaps)face->psnames; 508 if ( !psnames ) 509 return FT_THROW( Unimplemented_Feature ); 510 #endif 511 512 names = &face->postscript_names; 513 514 /* `.notdef' by default */ 515 *PSname = MAC_NAME( 0 ); 516 517 format = face->postscript.FormatType; 518 519 if ( format == 0x00010000L ) 520 { 521 if ( idx < 258 ) /* paranoid checking */ 522 *PSname = MAC_NAME( idx ); 523 } 524 else if ( format == 0x00020000L ) 525 { 526 TT_Post_20 table = &names->names.format_20; 527 528 529 if ( !names->loaded ) 530 { 531 error = load_post_names( face ); 532 if ( error ) 533 goto End; 534 } 535 536 if ( idx < (FT_UInt)table->num_glyphs ) 537 { 538 FT_UShort name_index = table->glyph_indices[idx]; 539 540 541 if ( name_index < 258 ) 542 *PSname = MAC_NAME( name_index ); 543 else 544 *PSname = (FT_String*)table->glyph_names[name_index - 258]; 545 } 546 } 547 else if ( format == 0x00025000L ) 548 { 549 TT_Post_25 table = &names->names.format_25; 550 551 552 if ( !names->loaded ) 553 { 554 error = load_post_names( face ); 555 if ( error ) 556 goto End; 557 } 558 559 if ( idx < (FT_UInt)table->num_glyphs ) /* paranoid checking */ 560 *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] ); 561 } 562 563 /* nothing to do for format == 0x00030000L */ 564 565 End: 566 return FT_Err_Ok; 567 } 568 569 #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ 570 571 /* ANSI C doesn't like empty source files */ 572 typedef int _tt_post_dummy; 573 574 #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */ 575 576 577 /* END */ 578