1 /****************************************************************************
   2  *
   3  * ttpost.c
   4  *
   5  *   PostScript name table processing for TrueType and OpenType fonts
   6  *   (body).
   7  *
   8  * Copyright (C) 1996-2019 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  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
 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
 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
 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 )
 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 ::
 472    *     A handle to the parent face.
 473    *
 474    *   idx ::
 475    *     The glyph index.
 476    *
 477    * @InOut:
 478    *   PSname ::
 479    *     The address of a string pointer.  Undefined in case of
 480    *     error, otherwise it is a pointer to the glyph name.
 481    *
 482    *     You must not modify the returned string!
 483    *
 484    * @Output:
 485    *   FreeType error code.  0 means success.
 486    */
 487   FT_LOCAL_DEF( FT_Error )
 488   tt_face_get_ps_name( TT_Face      face,
 489                        FT_UInt      idx,
 490                        FT_String**  PSname )
 491   {
 492     FT_Error       error;
 493     TT_Post_Names  names;
 494     FT_Fixed       format;
 495 
 496 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
 497     FT_Service_PsCMaps  psnames;
 498 #endif
 499 
 500 
 501     if ( !face )
 502       return FT_THROW( Invalid_Face_Handle );
 503 
 504     if ( idx >= (FT_UInt)face->max_profile.numGlyphs )
 505       return FT_THROW( Invalid_Glyph_Index );
 506 
 507 #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
 508     psnames = (FT_Service_PsCMaps)face->psnames;
 509     if ( !psnames )
 510       return FT_THROW( Unimplemented_Feature );
 511 #endif
 512 
 513     names = &face->postscript_names;
 514 
 515     /* `.notdef' by default */
 516     *PSname = MAC_NAME( 0 );
 517 
 518     format = face->postscript.FormatType;
 519 
 520     if ( format == 0x00010000L )
 521     {
 522       if ( idx < 258 )                    /* paranoid checking */
 523         *PSname = MAC_NAME( idx );
 524     }
 525     else if ( format == 0x00020000L )
 526     {
 527       TT_Post_20  table = &names->names.format_20;
 528 
 529 
 530       if ( !names->loaded )
 531       {
 532         error = load_post_names( face );
 533         if ( error )
 534           goto End;
 535       }
 536 
 537       if ( idx < (FT_UInt)table->num_glyphs )
 538       {
 539         FT_UShort  name_index = table->glyph_indices[idx];
 540 
 541 
 542         if ( name_index < 258 )
 543           *PSname = MAC_NAME( name_index );
 544         else
 545           *PSname = (FT_String*)table->glyph_names[name_index - 258];
 546       }
 547     }
 548     else if ( format == 0x00025000L )
 549     {
 550       TT_Post_25  table = &names->names.format_25;
 551 
 552 
 553       if ( !names->loaded )
 554       {
 555         error = load_post_names( face );
 556         if ( error )
 557           goto End;
 558       }
 559 
 560       if ( idx < (FT_UInt)table->num_glyphs )    /* paranoid checking */
 561         *PSname = MAC_NAME( (FT_Int)idx + table->offsets[idx] );
 562     }
 563 
 564     /* nothing to do for format == 0x00030000L */
 565 
 566   End:
 567     return FT_Err_Ok;
 568   }
 569 
 570 #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
 571 
 572   /* ANSI C doesn't like empty source files */
 573   typedef int  _tt_post_dummy;
 574 
 575 #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
 576 
 577 
 578 /* END */