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