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