(root)/
freetype-2.13.2/
src/
sfnt/
ttpost.c
       1  /****************************************************************************
       2   *
       3   * ttpost.c
       4   *
       5   *   PostScript name table processing for TrueType and OpenType fonts
       6   *   (body).
       7   *
       8   * Copyright (C) 1996-2023 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
     159    load_format_20( TT_Post_Names  names,
     160                    FT_Stream      stream,
     161                    FT_UShort      num_glyphs,
     162                    FT_ULong       post_len )
     163    {
     164      FT_Memory   memory = stream->memory;
     165      FT_Error    error;
     166  
     167      FT_UShort   n;
     168      FT_UShort   num_names = 0;
     169  
     170      FT_UShort*  glyph_indices = NULL;
     171      FT_Byte**   name_strings  = NULL;
     172      FT_Byte*    q;
     173  
     174  
     175      if ( (FT_ULong)num_glyphs * 2 > post_len )
     176      {
     177        error = FT_THROW( Invalid_File_Format );
     178        goto Exit;
     179      }
     180  
     181      /* load the indices and note their maximum */
     182      if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
     183           FT_FRAME_ENTER( num_glyphs * 2 )           )
     184        goto Fail;
     185  
     186      q = (FT_Byte*)stream->cursor;
     187  
     188      for ( n = 0; n < num_glyphs; n++ )
     189      {
     190        FT_UShort  idx = FT_NEXT_USHORT( q );
     191  
     192  
     193        if ( idx > num_names )
     194          num_names = idx;
     195  
     196        glyph_indices[n] = idx;
     197      }
     198  
     199      FT_FRAME_EXIT();
     200  
     201      /* compute number of names stored in the table */
     202      num_names = num_names > 257 ? num_names - 257 : 0;
     203  
     204      /* now load the name strings */
     205      if ( num_names )
     206      {
     207        FT_ULong   p;
     208        FT_Byte*   strings;
     209  
     210  
     211        post_len -= (FT_ULong)num_glyphs * 2;
     212  
     213        if ( FT_QALLOC( name_strings, num_names * sizeof ( FT_Byte* ) +
     214                                      post_len + 1 ) )
     215          goto Fail;
     216  
     217        strings = (FT_Byte*)( name_strings + num_names );
     218        if ( FT_STREAM_READ( strings, post_len ) )
     219          goto Fail;
     220  
     221        /* convert from Pascal- to C-strings and set pointers */
     222        for ( p = 0, n = 0; p < post_len && n < num_names; n++ )
     223        {
     224          FT_UInt  len = strings[p];
     225  
     226  
     227          if ( len > 63U )
     228          {
     229            error = FT_THROW( Invalid_File_Format );
     230            goto Fail;
     231          }
     232  
     233          strings[p]      = 0;
     234          name_strings[n] = strings + p + 1;
     235          p              += len + 1;
     236        }
     237        strings[post_len] = 0;
     238  
     239        /* deal with missing or insufficient string data */
     240        if ( n < num_names )
     241        {
     242          FT_TRACE4(( "load_format_20: %hu PostScript names are truncated\n",
     243                      num_names - n ));
     244  
     245          for ( ; n < num_names; n++ )
     246            name_strings[n] = strings + post_len;
     247        }
     248      }
     249  
     250      /* all right, set table fields and exit successfully */
     251      names->num_glyphs    = num_glyphs;
     252      names->num_names     = num_names;
     253      names->glyph_indices = glyph_indices;
     254      names->glyph_names   = name_strings;
     255  
     256      return FT_Err_Ok;
     257  
     258    Fail:
     259      FT_FREE( name_strings );
     260      FT_FREE( glyph_indices );
     261  
     262    Exit:
     263      return error;
     264    }
     265  
     266  
     267    static FT_Error
     268    load_format_25( TT_Post_Names  names,
     269                    FT_Stream      stream,
     270                    FT_UShort      num_glyphs,
     271                    FT_ULong       post_len )
     272    {
     273      FT_Memory  memory = stream->memory;
     274      FT_Error   error;
     275  
     276      FT_UShort   n;
     277      FT_UShort*  glyph_indices = NULL;
     278      FT_Byte*    q;
     279  
     280  
     281      /* check the number of glyphs, including the theoretical limit */
     282      if ( num_glyphs > post_len  ||
     283           num_glyphs > 258 + 128 )
     284      {
     285        error = FT_THROW( Invalid_File_Format );
     286        goto Exit;
     287      }
     288  
     289      /* load the indices and check their Mac range */
     290      if ( FT_QNEW_ARRAY( glyph_indices, num_glyphs ) ||
     291           FT_FRAME_ENTER( num_glyphs )               )
     292        goto Fail;
     293  
     294      q = (FT_Byte*)stream->cursor;
     295  
     296      for ( n = 0; n < num_glyphs; n++ )
     297      {
     298        FT_Int  idx = n + FT_NEXT_CHAR( q );
     299  
     300  
     301        if ( idx < 0 || idx > 257 )
     302          idx = 0;
     303  
     304        glyph_indices[n] = (FT_UShort)idx;
     305      }
     306  
     307      FT_FRAME_EXIT();
     308  
     309      /* OK, set table fields and exit successfully */
     310      names->num_glyphs    = num_glyphs;
     311      names->glyph_indices = glyph_indices;
     312  
     313      return FT_Err_Ok;
     314  
     315    Fail:
     316      FT_FREE( glyph_indices );
     317  
     318    Exit:
     319      return error;
     320    }
     321  
     322  
     323    static FT_Error
     324    load_post_names( TT_Face  face )
     325    {
     326      FT_Error   error = FT_Err_Ok;
     327      FT_Stream  stream = face->root.stream;
     328      FT_Fixed   format = face->postscript.FormatType;
     329      FT_ULong   post_len;
     330      FT_UShort  num_glyphs;
     331  
     332  
     333      /* seek to the beginning of the PS names table */
     334      error = face->goto_table( face, TTAG_post, stream, &post_len );
     335      if ( error )
     336        goto Exit;
     337  
     338      /* UNDOCUMENTED!  The number of glyphs in this table can be smaller */
     339      /* than the value in the maxp table (cf. cyberbit.ttf).             */
     340      if ( post_len < 34                            ||
     341           FT_STREAM_SKIP( 32 )                     ||
     342           FT_READ_USHORT( num_glyphs )             ||
     343           num_glyphs > face->max_profile.numGlyphs ||
     344           num_glyphs == 0 )
     345        goto Exit;
     346  
     347      /* now read postscript names data */
     348      if ( format == 0x00020000L )
     349        error = load_format_20( &face->postscript_names, stream,
     350                                num_glyphs, post_len - 34 );
     351      else if ( format == 0x00025000L )
     352        error = load_format_25( &face->postscript_names, stream,
     353                                num_glyphs, post_len - 34 );
     354  
     355    Exit:
     356      face->postscript_names.loaded = 1;  /* even if failed */
     357      return error;
     358    }
     359  
     360  
     361    FT_LOCAL_DEF( void )
     362    tt_face_free_ps_names( TT_Face  face )
     363    {
     364      FT_Memory      memory = face->root.memory;
     365      TT_Post_Names  names  = &face->postscript_names;
     366  
     367  
     368      if ( names->num_glyphs )
     369      {
     370        FT_FREE( names->glyph_indices );
     371        names->num_glyphs = 0;
     372      }
     373  
     374      if ( names->num_names )
     375      {
     376        FT_FREE( names->glyph_names );
     377        names->num_names = 0;
     378      }
     379  
     380      names->loaded = 0;
     381    }
     382  
     383  
     384    /**************************************************************************
     385     *
     386     * @Function:
     387     *   tt_face_get_ps_name
     388     *
     389     * @Description:
     390     *   Get the PostScript glyph name of a glyph.
     391     *
     392     * @Input:
     393     *   face ::
     394     *     A handle to the parent face.
     395     *
     396     *   idx ::
     397     *     The glyph index.
     398     *
     399     * @InOut:
     400     *   PSname ::
     401     *     The address of a string pointer.  Undefined in case of
     402     *     error, otherwise it is a pointer to the glyph name.
     403     *
     404     *     You must not modify the returned string!
     405     *
     406     * @Output:
     407     *   FreeType error code.  0 means success.
     408     */
     409    FT_LOCAL_DEF( FT_Error )
     410    tt_face_get_ps_name( TT_Face      face,
     411                         FT_UInt      idx,
     412                         FT_String**  PSname )
     413    {
     414      FT_Error       error;
     415      FT_Fixed       format;
     416  
     417  #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
     418      FT_Service_PsCMaps  psnames;
     419  #endif
     420  
     421  
     422      if ( !face )
     423        return FT_THROW( Invalid_Face_Handle );
     424  
     425      if ( idx >= (FT_UInt)face->max_profile.numGlyphs )
     426        return FT_THROW( Invalid_Glyph_Index );
     427  
     428  #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES
     429      psnames = (FT_Service_PsCMaps)face->psnames;
     430      if ( !psnames )
     431        return FT_THROW( Unimplemented_Feature );
     432  #endif
     433  
     434      /* `.notdef' by default */
     435      *PSname = MAC_NAME( 0 );
     436  
     437      format = face->postscript.FormatType;
     438  
     439      if ( format == 0x00010000L )
     440      {
     441        if ( idx < 258 )                    /* paranoid checking */
     442          *PSname = MAC_NAME( idx );
     443      }
     444      else if ( format == 0x00020000L ||
     445                format == 0x00025000L )
     446      {
     447        TT_Post_Names  names = &face->postscript_names;
     448  
     449  
     450        if ( !names->loaded )
     451        {
     452          error = load_post_names( face );
     453          if ( error )
     454            goto End;
     455        }
     456  
     457        if ( idx < (FT_UInt)names->num_glyphs )
     458        {
     459          FT_UShort  name_index = names->glyph_indices[idx];
     460  
     461  
     462          if ( name_index < 258 )
     463            *PSname = MAC_NAME( name_index );
     464          else  /* only for version 2.0 */
     465            *PSname = (FT_String*)names->glyph_names[name_index - 258];
     466        }
     467      }
     468  
     469      /* nothing to do for format == 0x00030000L */
     470  
     471    End:
     472      /* post format errors ignored */
     473      return FT_Err_Ok;
     474    }
     475  
     476  #else /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
     477  
     478    /* ANSI C doesn't like empty source files */
     479    typedef int  tt_post_dummy_;
     480  
     481  #endif /* !TT_CONFIG_OPTION_POSTSCRIPT_NAMES */
     482  
     483  
     484  /* END */