(root)/
freetype-2.13.2/
src/
type42/
t42parse.c
       1  /****************************************************************************
       2   *
       3   * t42parse.c
       4   *
       5   *   Type 42 font parser (body).
       6   *
       7   * Copyright (C) 2002-2023 by
       8   * Roberto Alameda.
       9   *
      10   * This file is part of the FreeType project, and may only be used,
      11   * modified, and distributed under the terms of the FreeType project
      12   * license, LICENSE.TXT.  By continuing to use, modify, or distribute
      13   * this file you indicate that you have read the license and
      14   * understand and accept it fully.
      15   *
      16   */
      17  
      18  
      19  #include "t42parse.h"
      20  #include "t42error.h"
      21  #include <freetype/internal/ftdebug.h>
      22  #include <freetype/internal/ftstream.h>
      23  #include <freetype/internal/psaux.h>
      24  
      25  
      26    /**************************************************************************
      27     *
      28     * The macro FT_COMPONENT is used in trace mode.  It is an implicit
      29     * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
      30     * messages during execution.
      31     */
      32  #undef  FT_COMPONENT
      33  #define FT_COMPONENT  t42
      34  
      35  
      36    static void
      37    t42_parse_font_matrix( FT_Face  face,
      38                           void*    loader_ );
      39    static void
      40    t42_parse_encoding( FT_Face  face,
      41                        void*    loader_ );
      42  
      43    static void
      44    t42_parse_charstrings( FT_Face  face,
      45                           void*    loader_ );
      46  
      47    static void
      48    t42_parse_sfnts( FT_Face  face,
      49                     void*    loader_ );
      50  
      51  
      52    /* as Type42 fonts have no Private dict,         */
      53    /* we set the last argument of T1_FIELD_XXX to 0 */
      54    static const
      55    T1_FieldRec  t42_keywords[] =
      56    {
      57  
      58  #undef  FT_STRUCTURE
      59  #define FT_STRUCTURE  T1_FontInfo
      60  #undef  T1CODE
      61  #define T1CODE        T1_FIELD_LOCATION_FONT_INFO
      62  
      63      T1_FIELD_STRING( "version",            version,             0 )
      64      T1_FIELD_STRING( "Notice",             notice,              0 )
      65      T1_FIELD_STRING( "FullName",           full_name,           0 )
      66      T1_FIELD_STRING( "FamilyName",         family_name,         0 )
      67      T1_FIELD_STRING( "Weight",             weight,              0 )
      68      T1_FIELD_NUM   ( "ItalicAngle",        italic_angle,        0 )
      69      T1_FIELD_BOOL  ( "isFixedPitch",       is_fixed_pitch,      0 )
      70      T1_FIELD_NUM   ( "UnderlinePosition",  underline_position,  0 )
      71      T1_FIELD_NUM   ( "UnderlineThickness", underline_thickness, 0 )
      72  
      73  #undef  FT_STRUCTURE
      74  #define FT_STRUCTURE  PS_FontExtraRec
      75  #undef  T1CODE
      76  #define T1CODE        T1_FIELD_LOCATION_FONT_EXTRA
      77  
      78      T1_FIELD_NUM   ( "FSType",             fs_type,             0 )
      79  
      80  #undef  FT_STRUCTURE
      81  #define FT_STRUCTURE  T1_FontRec
      82  #undef  T1CODE
      83  #define T1CODE        T1_FIELD_LOCATION_FONT_DICT
      84  
      85      T1_FIELD_KEY  ( "FontName",    font_name,    0 )
      86      T1_FIELD_NUM  ( "PaintType",   paint_type,   0 )
      87      T1_FIELD_NUM  ( "FontType",    font_type,    0 )
      88      T1_FIELD_FIXED( "StrokeWidth", stroke_width, 0 )
      89  
      90  #undef  FT_STRUCTURE
      91  #define FT_STRUCTURE  FT_BBox
      92  #undef  T1CODE
      93  #define T1CODE        T1_FIELD_LOCATION_BBOX
      94  
      95      T1_FIELD_BBOX( "FontBBox", xMin, 0 )
      96  
      97      T1_FIELD_CALLBACK( "FontMatrix",  t42_parse_font_matrix, 0 )
      98      T1_FIELD_CALLBACK( "Encoding",    t42_parse_encoding,    0 )
      99      T1_FIELD_CALLBACK( "CharStrings", t42_parse_charstrings, 0 )
     100      T1_FIELD_CALLBACK( "sfnts",       t42_parse_sfnts,       0 )
     101  
     102      { 0, T1_FIELD_LOCATION_CID_INFO, T1_FIELD_TYPE_NONE, 0, 0, 0, 0, 0, 0 }
     103    };
     104  
     105  
     106  #define T1_Add_Table( p, i, o, l )  (p)->funcs.add( (p), i, o, l )
     107  #define T1_Release_Table( p )          \
     108            do                           \
     109            {                            \
     110              if ( (p)->funcs.release )  \
     111                (p)->funcs.release( p ); \
     112            } while ( 0 )
     113  
     114  #define T1_Skip_Spaces( p )    (p)->root.funcs.skip_spaces( &(p)->root )
     115  #define T1_Skip_PS_Token( p )  (p)->root.funcs.skip_PS_token( &(p)->root )
     116  
     117  #define T1_ToInt( p )                          \
     118            (p)->root.funcs.to_int( &(p)->root )
     119  #define T1_ToBytes( p, b, m, n, d )                          \
     120            (p)->root.funcs.to_bytes( &(p)->root, b, m, n, d )
     121  
     122  #define T1_ToFixedArray( p, m, f, t )                           \
     123            (p)->root.funcs.to_fixed_array( &(p)->root, m, f, t )
     124  #define T1_ToToken( p, t )                          \
     125            (p)->root.funcs.to_token( &(p)->root, t )
     126  
     127  #define T1_Load_Field( p, f, o, m, pf )                         \
     128            (p)->root.funcs.load_field( &(p)->root, f, o, m, pf )
     129  #define T1_Load_Field_Table( p, f, o, m, pf )                         \
     130            (p)->root.funcs.load_field_table( &(p)->root, f, o, m, pf )
     131  
     132  
     133    /********************* Parsing Functions ******************/
     134  
     135    FT_LOCAL_DEF( FT_Error )
     136    t42_parser_init( T42_Parser     parser,
     137                     FT_Stream      stream,
     138                     FT_Memory      memory,
     139                     PSAux_Service  psaux )
     140    {
     141      FT_Error  error = FT_Err_Ok;
     142      FT_Long   size;
     143  
     144  
     145      psaux->ps_parser_funcs->init( &parser->root, NULL, NULL, memory );
     146  
     147      parser->stream    = stream;
     148      parser->base_len  = 0;
     149      parser->base_dict = NULL;
     150      parser->in_memory = 0;
     151  
     152      /********************************************************************
     153       *
     154       * Here a short summary of what is going on:
     155       *
     156       *   When creating a new Type 42 parser, we try to locate and load
     157       *   the base dictionary, loading the whole font into memory.
     158       *
     159       *   When `loading' the base dictionary, we only set up pointers
     160       *   in the case of a memory-based stream.  Otherwise, we allocate
     161       *   and load the base dictionary in it.
     162       *
     163       *   parser->in_memory is set if we have a memory stream.
     164       */
     165  
     166      if ( FT_STREAM_SEEK( 0L ) ||
     167           FT_FRAME_ENTER( 17 ) )
     168        goto Exit;
     169  
     170      if ( ft_memcmp( stream->cursor, "%!PS-TrueTypeFont", 17 ) != 0 )
     171      {
     172        FT_TRACE2(( "  not a Type42 font\n" ));
     173        error = FT_THROW( Unknown_File_Format );
     174      }
     175  
     176      FT_FRAME_EXIT();
     177  
     178      if ( error || FT_STREAM_SEEK( 0 ) )
     179        goto Exit;
     180  
     181      size = (FT_Long)stream->size;
     182  
     183      /* now, try to load `size' bytes of the `base' dictionary we */
     184      /* found previously                                          */
     185  
     186      /* if it is a memory-based resource, set up pointers */
     187      if ( !stream->read )
     188      {
     189        parser->base_dict = (FT_Byte*)stream->base + stream->pos;
     190        parser->base_len  = size;
     191        parser->in_memory = 1;
     192  
     193        /* check that the `size' field is valid */
     194        if ( FT_STREAM_SKIP( size ) )
     195          goto Exit;
     196      }
     197      else
     198      {
     199        /* read segment in memory */
     200        if ( FT_QALLOC( parser->base_dict, size )      ||
     201             FT_STREAM_READ( parser->base_dict, size ) )
     202          goto Exit;
     203  
     204        parser->base_len = size;
     205      }
     206  
     207      parser->root.base   = parser->base_dict;
     208      parser->root.cursor = parser->base_dict;
     209      parser->root.limit  = parser->root.cursor + parser->base_len;
     210  
     211    Exit:
     212      if ( error && !parser->in_memory )
     213        FT_FREE( parser->base_dict );
     214  
     215      return error;
     216    }
     217  
     218  
     219    FT_LOCAL_DEF( void )
     220    t42_parser_done( T42_Parser  parser )
     221    {
     222      FT_Memory  memory = parser->root.memory;
     223  
     224  
     225      /* free the base dictionary only when we have a disk stream */
     226      if ( !parser->in_memory )
     227        FT_FREE( parser->base_dict );
     228  
     229      if ( parser->root.funcs.done )
     230        parser->root.funcs.done( &parser->root );
     231    }
     232  
     233  
     234    static int
     235    t42_is_space( FT_Byte  c )
     236    {
     237      return ( c == ' '  || c == '\t'              ||
     238               c == '\r' || c == '\n' || c == '\f' ||
     239               c == '\0'                           );
     240    }
     241  
     242  
     243    static void
     244    t42_parse_font_matrix( FT_Face  face,     /* T42_Face */
     245                           void*    loader_ )
     246    {
     247      T42_Face    t42face = (T42_Face)face;
     248      T42_Loader  loader  = (T42_Loader)loader_;
     249      T42_Parser  parser  = &loader->parser;
     250      FT_Matrix*  matrix  = &t42face->type1.font_matrix;
     251      FT_Vector*  offset  = &t42face->type1.font_offset;
     252      FT_Fixed    temp[6];
     253      FT_Fixed    temp_scale;
     254      FT_Int      result;
     255  
     256  
     257      result = T1_ToFixedArray( parser, 6, temp, 0 );
     258  
     259      if ( result < 6 )
     260      {
     261        parser->root.error = FT_THROW( Invalid_File_Format );
     262        return;
     263      }
     264  
     265      temp_scale = FT_ABS( temp[3] );
     266  
     267      if ( temp_scale == 0 )
     268      {
     269        FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
     270        parser->root.error = FT_THROW( Invalid_File_Format );
     271        return;
     272      }
     273  
     274      /* atypical case */
     275      if ( temp_scale != 0x10000L )
     276      {
     277        temp[0] = FT_DivFix( temp[0], temp_scale );
     278        temp[1] = FT_DivFix( temp[1], temp_scale );
     279        temp[2] = FT_DivFix( temp[2], temp_scale );
     280        temp[4] = FT_DivFix( temp[4], temp_scale );
     281        temp[5] = FT_DivFix( temp[5], temp_scale );
     282        temp[3] = temp[3] < 0 ? -0x10000L : 0x10000L;
     283      }
     284  
     285      matrix->xx = temp[0];
     286      matrix->yx = temp[1];
     287      matrix->xy = temp[2];
     288      matrix->yy = temp[3];
     289  
     290      if ( !FT_Matrix_Check( matrix ) )
     291      {
     292        FT_ERROR(( "t42_parse_font_matrix: invalid font matrix\n" ));
     293        parser->root.error = FT_THROW( Invalid_File_Format );
     294        return;
     295      }
     296  
     297      /* note that the offsets must be expressed in integer font units */
     298      offset->x = temp[4] >> 16;
     299      offset->y = temp[5] >> 16;
     300    }
     301  
     302  
     303    static void
     304    t42_parse_encoding( FT_Face  face,
     305                        void*    loader_ )
     306    {
     307      T42_Face    t42face = (T42_Face)face;
     308      T42_Loader  loader  = (T42_Loader)loader_;
     309      T42_Parser  parser  = &loader->parser;
     310      FT_Byte*    cur;
     311      FT_Byte*    limit   = parser->root.limit;
     312  
     313      PSAux_Service  psaux  = (PSAux_Service)t42face->psaux;
     314  
     315  
     316      T1_Skip_Spaces( parser );
     317      cur = parser->root.cursor;
     318      if ( cur >= limit )
     319      {
     320        FT_ERROR(( "t42_parse_encoding: out of bounds\n" ));
     321        parser->root.error = FT_THROW( Invalid_File_Format );
     322        return;
     323      }
     324  
     325      /* if we have a number or `[', the encoding is an array, */
     326      /* and we must load it now                               */
     327      if ( ft_isdigit( *cur ) || *cur == '[' )
     328      {
     329        T1_Encoding  encode          = &t42face->type1.encoding;
     330        FT_Int       count, n;
     331        PS_Table     char_table      = &loader->encoding_table;
     332        FT_Memory    memory          = parser->root.memory;
     333        FT_Error     error;
     334        FT_Bool      only_immediates = 0;
     335  
     336  
     337        /* read the number of entries in the encoding; should be 256 */
     338        if ( *cur == '[' )
     339        {
     340          count           = 256;
     341          only_immediates = 1;
     342          parser->root.cursor++;
     343        }
     344        else
     345          count = (FT_Int)T1_ToInt( parser );
     346  
     347        /* only composite fonts (which we don't support) */
     348        /* can have larger values                        */
     349        if ( count > 256 )
     350        {
     351          FT_ERROR(( "t42_parse_encoding: invalid encoding array size\n" ));
     352          parser->root.error = FT_THROW( Invalid_File_Format );
     353          return;
     354        }
     355  
     356        T1_Skip_Spaces( parser );
     357        if ( parser->root.cursor >= limit )
     358          return;
     359  
     360        /* PostScript happily allows overwriting of encoding arrays */
     361        if ( encode->char_index )
     362        {
     363          FT_FREE( encode->char_index );
     364          FT_FREE( encode->char_name );
     365          T1_Release_Table( char_table );
     366        }
     367  
     368        /* we use a T1_Table to store our charnames */
     369        loader->num_chars = encode->num_chars = count;
     370        if ( FT_QNEW_ARRAY( encode->char_index, count )    ||
     371             FT_QNEW_ARRAY( encode->char_name,  count )    ||
     372             FT_SET_ERROR( psaux->ps_table_funcs->init(
     373                             char_table, count, memory ) ) )
     374        {
     375          parser->root.error = error;
     376          return;
     377        }
     378  
     379        /* We need to `zero' out encoding_table.elements */
     380        for ( n = 0; n < count; n++ )
     381          (void)T1_Add_Table( char_table, n, ".notdef", 8 );
     382  
     383        /* Now we need to read records of the form                */
     384        /*                                                        */
     385        /*   ... charcode /charname ...                           */
     386        /*                                                        */
     387        /* for each entry in our table.                           */
     388        /*                                                        */
     389        /* We simply look for a number followed by an immediate   */
     390        /* name.  Note that this ignores correctly the sequence   */
     391        /* that is often seen in type42 fonts:                    */
     392        /*                                                        */
     393        /*   0 1 255 { 1 index exch /.notdef put } for dup        */
     394        /*                                                        */
     395        /* used to clean the encoding array before anything else. */
     396        /*                                                        */
     397        /* Alternatively, if the array is directly given as       */
     398        /*                                                        */
     399        /*   /Encoding [ ... ]                                    */
     400        /*                                                        */
     401        /* we only read immediates.                               */
     402  
     403        n = 0;
     404        T1_Skip_Spaces( parser );
     405  
     406        while ( parser->root.cursor < limit )
     407        {
     408          cur = parser->root.cursor;
     409  
     410          /* we stop when we encounter `def' or `]' */
     411          if ( *cur == 'd' && cur + 3 < limit )
     412          {
     413            if ( cur[1] == 'e'          &&
     414                 cur[2] == 'f'          &&
     415                 t42_is_space( cur[3] ) )
     416            {
     417              FT_TRACE6(( "encoding end\n" ));
     418              cur += 3;
     419              break;
     420            }
     421          }
     422          if ( *cur == ']' )
     423          {
     424            FT_TRACE6(( "encoding end\n" ));
     425            cur++;
     426            break;
     427          }
     428  
     429          /* check whether we have found an entry */
     430          if ( ft_isdigit( *cur ) || only_immediates )
     431          {
     432            FT_Int  charcode;
     433  
     434  
     435            if ( only_immediates )
     436              charcode = n;
     437            else
     438            {
     439              charcode = (FT_Int)T1_ToInt( parser );
     440              T1_Skip_Spaces( parser );
     441  
     442              /* protect against invalid charcode */
     443              if ( cur == parser->root.cursor )
     444              {
     445                parser->root.error = FT_THROW( Unknown_File_Format );
     446                return;
     447              }
     448            }
     449  
     450            cur = parser->root.cursor;
     451  
     452            if ( cur + 2 < limit && *cur == '/' && n < count )
     453            {
     454              FT_UInt  len;
     455  
     456  
     457              cur++;
     458  
     459              parser->root.cursor = cur;
     460              T1_Skip_PS_Token( parser );
     461              if ( parser->root.cursor >= limit )
     462                return;
     463              if ( parser->root.error )
     464                return;
     465  
     466              len = (FT_UInt)( parser->root.cursor - cur );
     467  
     468              parser->root.error = T1_Add_Table( char_table, charcode,
     469                                                 cur, len + 1 );
     470              if ( parser->root.error )
     471                return;
     472              char_table->elements[charcode][len] = '\0';
     473  
     474              n++;
     475            }
     476            else if ( only_immediates )
     477            {
     478              /* Since the current position is not updated for           */
     479              /* immediates-only mode we would get an infinite loop if   */
     480              /* we don't do anything here.                              */
     481              /*                                                         */
     482              /* This encoding array is not valid according to the       */
     483              /* type42 specification (it might be an encoding for a CID */
     484              /* type42 font, however), so we conclude that this font is */
     485              /* NOT a type42 font.                                      */
     486              parser->root.error = FT_THROW( Unknown_File_Format );
     487              return;
     488            }
     489          }
     490          else
     491          {
     492            T1_Skip_PS_Token( parser );
     493            if ( parser->root.error )
     494              return;
     495          }
     496  
     497          T1_Skip_Spaces( parser );
     498        }
     499  
     500        t42face->type1.encoding_type = T1_ENCODING_TYPE_ARRAY;
     501        parser->root.cursor          = cur;
     502      }
     503  
     504      /* Otherwise, we should have either `StandardEncoding', */
     505      /* `ExpertEncoding', or `ISOLatin1Encoding'             */
     506      else
     507      {
     508        if ( cur + 17 < limit                                            &&
     509             ft_strncmp( (const char*)cur, "StandardEncoding", 16 ) == 0 )
     510          t42face->type1.encoding_type = T1_ENCODING_TYPE_STANDARD;
     511  
     512        else if ( cur + 15 < limit                                          &&
     513                  ft_strncmp( (const char*)cur, "ExpertEncoding", 14 ) == 0 )
     514          t42face->type1.encoding_type = T1_ENCODING_TYPE_EXPERT;
     515  
     516        else if ( cur + 18 < limit                                             &&
     517                  ft_strncmp( (const char*)cur, "ISOLatin1Encoding", 17 ) == 0 )
     518          t42face->type1.encoding_type = T1_ENCODING_TYPE_ISOLATIN1;
     519  
     520        else
     521          parser->root.error = FT_ERR( Ignore );
     522      }
     523    }
     524  
     525  
     526    typedef enum  T42_Load_Status_
     527    {
     528      BEFORE_START,
     529      BEFORE_TABLE_DIR,
     530      OTHER_TABLES
     531  
     532    } T42_Load_Status;
     533  
     534  
     535    static void
     536    t42_parse_sfnts( FT_Face  face,
     537                     void*    loader_ )
     538    {
     539      T42_Face    t42face = (T42_Face)face;
     540      T42_Loader  loader  = (T42_Loader)loader_;
     541      T42_Parser  parser = &loader->parser;
     542      FT_Memory   memory = parser->root.memory;
     543      FT_Byte*    cur;
     544      FT_Byte*    limit  = parser->root.limit;
     545      FT_Error    error;
     546      FT_Int      num_tables = 0;
     547      FT_Long     ttf_count;
     548      FT_Long     ttf_reserved;
     549  
     550      FT_ULong    n, string_size, old_string_size, real_size;
     551      FT_Byte*    string_buf = NULL;
     552      FT_Bool     allocated  = 0;
     553  
     554      T42_Load_Status  status;
     555  
     556      /** There should only be one sfnts array, but free any previous. */
     557      FT_FREE( t42face->ttf_data );
     558      t42face->ttf_size = 0;
     559  
     560      /* The format is                                */
     561      /*                                              */
     562      /*   /sfnts [ <hexstring> <hexstring> ... ] def */
     563      /*                                              */
     564      /* or                                           */
     565      /*                                              */
     566      /*   /sfnts [                                   */
     567      /*      <num_bin_bytes> RD <binary data>        */
     568      /*      <num_bin_bytes> RD <binary data>        */
     569      /*      ...                                     */
     570      /*   ] def                                      */
     571      /*                                              */
     572      /* with exactly one space after the `RD' token. */
     573  
     574      T1_Skip_Spaces( parser );
     575  
     576      if ( parser->root.cursor >= limit || *parser->root.cursor++ != '[' )
     577      {
     578        FT_ERROR(( "t42_parse_sfnts: can't find begin of sfnts vector\n" ));
     579        error = FT_THROW( Invalid_File_Format );
     580        goto Fail;
     581      }
     582  
     583      T1_Skip_Spaces( parser );
     584      status          = BEFORE_START;
     585      string_size     = 0;
     586      old_string_size = 0;
     587      ttf_count       = 0;
     588      ttf_reserved    = 12;
     589      if ( FT_QALLOC( t42face->ttf_data, ttf_reserved ) )
     590        goto Fail;
     591  
     592      FT_TRACE2(( "\n" ));
     593      FT_TRACE2(( "t42_parse_sfnts:\n" ));
     594  
     595      while ( parser->root.cursor < limit )
     596      {
     597        FT_ULong  size;
     598  
     599  
     600        cur = parser->root.cursor;
     601  
     602        if ( *cur == ']' )
     603        {
     604          parser->root.cursor++;
     605          t42face->ttf_size = ttf_count;
     606          goto Exit;
     607        }
     608  
     609        else if ( *cur == '<' )
     610        {
     611          if ( string_buf && !allocated )
     612          {
     613            FT_ERROR(( "t42_parse_sfnts: "
     614                       "can't handle mixed binary and hex strings\n" ));
     615            error = FT_THROW( Invalid_File_Format );
     616            goto Fail;
     617          }
     618  
     619          T1_Skip_PS_Token( parser );
     620          if ( parser->root.error )
     621            goto Exit;
     622  
     623          /* don't include delimiters */
     624          string_size = (FT_ULong)( ( parser->root.cursor - cur - 2 + 1 ) / 2 );
     625          if ( !string_size )
     626          {
     627            FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
     628            error = FT_THROW( Invalid_File_Format );
     629            goto Fail;
     630          }
     631          if ( FT_QREALLOC( string_buf, old_string_size, string_size ) )
     632            goto Fail;
     633  
     634          allocated = 1;
     635  
     636          parser->root.cursor = cur;
     637          (void)T1_ToBytes( parser, string_buf, string_size, &real_size, 1 );
     638          old_string_size = string_size;
     639          string_size     = real_size;
     640        }
     641  
     642        else if ( ft_isdigit( *cur ) )
     643        {
     644          FT_Long  tmp;
     645  
     646  
     647          if ( allocated )
     648          {
     649            FT_ERROR(( "t42_parse_sfnts: "
     650                       "can't handle mixed binary and hex strings\n" ));
     651            error = FT_THROW( Invalid_File_Format );
     652            goto Fail;
     653          }
     654  
     655          tmp = T1_ToInt( parser );
     656          if ( tmp < 0 )
     657          {
     658            FT_ERROR(( "t42_parse_sfnts: invalid string size\n" ));
     659            error = FT_THROW( Invalid_File_Format );
     660            goto Fail;
     661          }
     662          else
     663            string_size = (FT_ULong)tmp;
     664  
     665          T1_Skip_PS_Token( parser );             /* `RD' */
     666          if ( parser->root.error )
     667            return;
     668  
     669          string_buf = parser->root.cursor + 1;   /* one space after `RD' */
     670  
     671          if ( (FT_ULong)( limit - parser->root.cursor ) <= string_size )
     672          {
     673            FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
     674            error = FT_THROW( Invalid_File_Format );
     675            goto Fail;
     676          }
     677          else
     678            parser->root.cursor += string_size + 1;
     679        }
     680  
     681        if ( !string_buf )
     682        {
     683          FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
     684          error = FT_THROW( Invalid_File_Format );
     685          goto Fail;
     686        }
     687  
     688        /* A string can have a trailing zero (odd) byte for padding. */
     689        /* Ignore it.                                                */
     690        if ( ( string_size & 1 ) && string_buf[string_size - 1] == 0 )
     691          string_size--;
     692  
     693        if ( !string_size )
     694        {
     695          FT_ERROR(( "t42_parse_sfnts: invalid string\n" ));
     696          error = FT_THROW( Invalid_File_Format );
     697          goto Fail;
     698        }
     699  
     700        FT_TRACE2(( "  PS string size %5lu bytes, offset 0x%08lx (%lu)\n",
     701                    string_size, ttf_count, ttf_count ));
     702  
     703        /* The whole TTF is now loaded into `string_buf'.  We are */
     704        /* checking its contents while copying it to `ttf_data'.  */
     705  
     706        size = (FT_ULong)( limit - parser->root.cursor );
     707  
     708        for ( n = 0; n < string_size; n++ )
     709        {
     710          switch ( status )
     711          {
     712          case BEFORE_START:
     713            /* load offset table, 12 bytes */
     714            if ( ttf_count < 12 )
     715            {
     716              t42face->ttf_data[ttf_count++] = string_buf[n];
     717              continue;
     718            }
     719            else
     720            {
     721              FT_Long ttf_reserved_prev = ttf_reserved;
     722  
     723  
     724              num_tables   = 16 * t42face->ttf_data[4] + t42face->ttf_data[5];
     725              status       = BEFORE_TABLE_DIR;
     726              ttf_reserved = 12 + 16 * num_tables;
     727  
     728              FT_TRACE2(( "  SFNT directory contains %d tables\n",
     729                          num_tables ));
     730  
     731              if ( (FT_Long)size < ttf_reserved )
     732              {
     733                FT_ERROR(( "t42_parse_sfnts: invalid data in sfnts array\n" ));
     734                error = FT_THROW( Invalid_File_Format );
     735                goto Fail;
     736              }
     737  
     738              if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
     739                                ttf_reserved ) )
     740                goto Fail;
     741            }
     742            FALL_THROUGH;
     743  
     744          case BEFORE_TABLE_DIR:
     745            /* the offset table is read; read the table directory */
     746            if ( ttf_count < ttf_reserved )
     747            {
     748              t42face->ttf_data[ttf_count++] = string_buf[n];
     749              continue;
     750            }
     751            else
     752            {
     753              int       i;
     754              FT_ULong  len;
     755              FT_Long ttf_reserved_prev = ttf_reserved;
     756  
     757  
     758              FT_TRACE2(( "\n" ));
     759              FT_TRACE2(( "  table    length\n" ));
     760              FT_TRACE2(( "  ------------------------------\n" ));
     761  
     762              for ( i = 0; i < num_tables; i++ )
     763              {
     764                FT_Byte*  p = t42face->ttf_data + 12 + 16 * i + 12;
     765  
     766  
     767                len = FT_PEEK_ULONG( p );
     768                FT_TRACE2(( "   %4i  0x%08lx (%lu)\n", i, len, len ));
     769  
     770                if ( len > size                               ||
     771                     ttf_reserved > (FT_Long)( size - len ) )
     772                {
     773                  FT_ERROR(( "t42_parse_sfnts:"
     774                             " invalid data in sfnts array\n" ));
     775                  error = FT_THROW( Invalid_File_Format );
     776                  goto Fail;
     777                }
     778  
     779                /* Pad to a 4-byte boundary length */
     780                ttf_reserved += (FT_Long)( ( len + 3 ) & ~3U );
     781              }
     782              ttf_reserved += 1;
     783  
     784              status = OTHER_TABLES;
     785  
     786              FT_TRACE2(( "\n" ));
     787              FT_TRACE2(( "  allocating %ld bytes\n", ttf_reserved ));
     788              FT_TRACE2(( "\n" ));
     789  
     790              if ( FT_QREALLOC( t42face->ttf_data, ttf_reserved_prev,
     791                                ttf_reserved ) )
     792                goto Fail;
     793            }
     794            FALL_THROUGH;
     795  
     796          case OTHER_TABLES:
     797            /* all other tables are just copied */
     798            if ( ttf_count >= ttf_reserved )
     799            {
     800              FT_ERROR(( "t42_parse_sfnts: too much binary data\n" ));
     801              error = FT_THROW( Invalid_File_Format );
     802              goto Fail;
     803            }
     804            t42face->ttf_data[ttf_count++] = string_buf[n];
     805          }
     806        }
     807  
     808        T1_Skip_Spaces( parser );
     809      }
     810  
     811      /* if control reaches this point, the format was not valid */
     812      error = FT_THROW( Invalid_File_Format );
     813  
     814    Fail:
     815      parser->root.error = error;
     816  
     817    Exit:
     818      if ( parser->root.error )
     819      {
     820        FT_FREE( t42face->ttf_data );
     821        t42face->ttf_size = 0;
     822      }
     823      if ( allocated )
     824        FT_FREE( string_buf );
     825    }
     826  
     827  
     828    static void
     829    t42_parse_charstrings( FT_Face  face,     /* T42_Face */
     830                           void*    loader_ )
     831    {
     832      T42_Face       t42face      = (T42_Face)face;
     833      T42_Loader     loader       = (T42_Loader)loader_;
     834      T42_Parser     parser       = &loader->parser;
     835      PS_Table       code_table   = &loader->charstrings;
     836      PS_Table       name_table   = &loader->glyph_names;
     837      PS_Table       swap_table   = &loader->swap_table;
     838      FT_Memory      memory       = parser->root.memory;
     839      FT_Error       error;
     840  
     841      PSAux_Service  psaux        = (PSAux_Service)t42face->psaux;
     842  
     843      FT_Byte*       cur;
     844      FT_Byte*       limit        = parser->root.limit;
     845      FT_Int         n;
     846      FT_Int         notdef_index = 0;
     847      FT_Byte        notdef_found = 0;
     848  
     849  
     850      T1_Skip_Spaces( parser );
     851  
     852      if ( parser->root.cursor >= limit )
     853      {
     854        FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
     855        error = FT_THROW( Invalid_File_Format );
     856        goto Fail;
     857      }
     858  
     859      if ( ft_isdigit( *parser->root.cursor ) )
     860      {
     861        loader->num_glyphs = T1_ToInt( parser );
     862        if ( parser->root.error )
     863          return;
     864        if ( loader->num_glyphs < 0 )
     865        {
     866          FT_ERROR(( "t42_parse_encoding: invalid number of glyphs\n" ));
     867          error = FT_THROW( Invalid_File_Format );
     868          goto Fail;
     869        }
     870  
     871        /* we certainly need more than 4 bytes per glyph */
     872        if ( loader->num_glyphs > ( limit - parser->root.cursor ) >> 2 )
     873        {
     874          FT_TRACE0(( "t42_parse_charstrings: adjusting number of glyphs"
     875                      " (from %d to %zu)\n",
     876                      loader->num_glyphs,
     877                      ( limit - parser->root.cursor ) >> 2 ));
     878          loader->num_glyphs = ( limit - parser->root.cursor ) >> 2;
     879        }
     880  
     881      }
     882      else if ( *parser->root.cursor == '<' )
     883      {
     884        /* We have `<< ... >>'.  Count the number of `/' in the dictionary */
     885        /* to get its size.                                                */
     886        FT_Int  count = 0;
     887  
     888  
     889        T1_Skip_PS_Token( parser );
     890        if ( parser->root.error )
     891          return;
     892        T1_Skip_Spaces( parser );
     893        cur = parser->root.cursor;
     894  
     895        while ( parser->root.cursor < limit )
     896        {
     897          if ( *parser->root.cursor == '/' )
     898            count++;
     899          else if ( *parser->root.cursor == '>' )
     900          {
     901            loader->num_glyphs  = count;
     902            parser->root.cursor = cur;        /* rewind */
     903            break;
     904          }
     905          T1_Skip_PS_Token( parser );
     906          if ( parser->root.error )
     907            return;
     908          T1_Skip_Spaces( parser );
     909        }
     910      }
     911      else
     912      {
     913        FT_ERROR(( "t42_parse_charstrings: invalid token\n" ));
     914        error = FT_THROW( Invalid_File_Format );
     915        goto Fail;
     916      }
     917  
     918      if ( parser->root.cursor >= limit )
     919      {
     920        FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
     921        error = FT_THROW( Invalid_File_Format );
     922        goto Fail;
     923      }
     924  
     925      /* initialize tables */
     926  
     927      /* contrary to Type1, we disallow multiple CharStrings arrays */
     928      if ( swap_table->init )
     929      {
     930        FT_ERROR(( "t42_parse_charstrings:"
     931                   " only one CharStrings array allowed\n" ));
     932        error = FT_THROW( Invalid_File_Format );
     933        goto Fail;
     934      }
     935  
     936      error = psaux->ps_table_funcs->init( code_table,
     937                                           loader->num_glyphs,
     938                                           memory );
     939      if ( error )
     940        goto Fail;
     941  
     942      error = psaux->ps_table_funcs->init( name_table,
     943                                           loader->num_glyphs,
     944                                           memory );
     945      if ( error )
     946        goto Fail;
     947  
     948      /* Initialize table for swapping index notdef_index and */
     949      /* index 0 names and codes (if necessary).              */
     950  
     951      error = psaux->ps_table_funcs->init( swap_table, 4, memory );
     952      if ( error )
     953        goto Fail;
     954  
     955      n = 0;
     956  
     957      for (;;)
     958      {
     959        /* We support two formats.                     */
     960        /*                                             */
     961        /*   `/glyphname' + index [+ `def']            */
     962        /*   `(glyphname)' [+ `cvn'] + index [+ `def'] */
     963        /*                                             */
     964        /* The latter format gets created by the       */
     965        /* LilyPond typesetting program.               */
     966  
     967        T1_Skip_Spaces( parser );
     968  
     969        cur = parser->root.cursor;
     970        if ( cur >= limit )
     971          break;
     972  
     973        /* We stop when we find an `end' keyword or '>' */
     974        if ( *cur   == 'e'          &&
     975             cur + 3 < limit        &&
     976             cur[1] == 'n'          &&
     977             cur[2] == 'd'          &&
     978             t42_is_space( cur[3] ) )
     979          break;
     980        if ( *cur == '>' )
     981          break;
     982  
     983        T1_Skip_PS_Token( parser );
     984        if ( parser->root.cursor >= limit )
     985        {
     986          FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
     987          error = FT_THROW( Invalid_File_Format );
     988          goto Fail;
     989        }
     990        if ( parser->root.error )
     991          return;
     992  
     993        if ( *cur == '/' || *cur == '(' )
     994        {
     995          FT_UInt  len;
     996          FT_Bool  have_literal = FT_BOOL( *cur == '(' );
     997  
     998  
     999          if ( cur + ( have_literal ? 3 : 2 ) >= limit )
    1000          {
    1001            FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
    1002            error = FT_THROW( Invalid_File_Format );
    1003            goto Fail;
    1004          }
    1005  
    1006          cur++;                              /* skip `/' */
    1007          len = (FT_UInt)( parser->root.cursor - cur );
    1008          if ( have_literal )
    1009            len--;
    1010  
    1011          error = T1_Add_Table( name_table, n, cur, len + 1 );
    1012          if ( error )
    1013            goto Fail;
    1014  
    1015          /* add a trailing zero to the name table */
    1016          name_table->elements[n][len] = '\0';
    1017  
    1018          /* record index of /.notdef */
    1019          if ( *cur == '.'                                                &&
    1020               ft_strcmp( ".notdef",
    1021                          (const char*)( name_table->elements[n] ) ) == 0 )
    1022          {
    1023            notdef_index = n;
    1024            notdef_found = 1;
    1025          }
    1026  
    1027          T1_Skip_Spaces( parser );
    1028  
    1029          if ( have_literal )
    1030            T1_Skip_PS_Token( parser );
    1031  
    1032          cur = parser->root.cursor;
    1033  
    1034          (void)T1_ToInt( parser );
    1035          if ( parser->root.cursor >= limit )
    1036          {
    1037            FT_ERROR(( "t42_parse_charstrings: out of bounds\n" ));
    1038            error = FT_THROW( Invalid_File_Format );
    1039            goto Fail;
    1040          }
    1041  
    1042          len = (FT_UInt)( parser->root.cursor - cur );
    1043  
    1044          error = T1_Add_Table( code_table, n, cur, len + 1 );
    1045          if ( error )
    1046            goto Fail;
    1047  
    1048          code_table->elements[n][len] = '\0';
    1049  
    1050          n++;
    1051          if ( n >= loader->num_glyphs )
    1052            break;
    1053        }
    1054      }
    1055  
    1056      loader->num_glyphs = n;
    1057  
    1058      if ( !notdef_found )
    1059      {
    1060        FT_ERROR(( "t42_parse_charstrings: no /.notdef glyph\n" ));
    1061        error = FT_THROW( Invalid_File_Format );
    1062        goto Fail;
    1063      }
    1064  
    1065      /* if /.notdef does not occupy index 0, do our magic. */
    1066      if ( ft_strcmp( ".notdef", (const char*)name_table->elements[0] ) )
    1067      {
    1068        /* Swap glyph in index 0 with /.notdef glyph.  First, add index 0  */
    1069        /* name and code entries to swap_table.  Then place notdef_index   */
    1070        /* name and code entries into swap_table.  Then swap name and code */
    1071        /* entries at indices notdef_index and 0 using values stored in    */
    1072        /* swap_table.                                                     */
    1073  
    1074        /* Index 0 name */
    1075        error = T1_Add_Table( swap_table, 0,
    1076                              name_table->elements[0],
    1077                              name_table->lengths [0] );
    1078        if ( error )
    1079          goto Fail;
    1080  
    1081        /* Index 0 code */
    1082        error = T1_Add_Table( swap_table, 1,
    1083                              code_table->elements[0],
    1084                              code_table->lengths [0] );
    1085        if ( error )
    1086          goto Fail;
    1087  
    1088        /* Index notdef_index name */
    1089        error = T1_Add_Table( swap_table, 2,
    1090                              name_table->elements[notdef_index],
    1091                              name_table->lengths [notdef_index] );
    1092        if ( error )
    1093          goto Fail;
    1094  
    1095        /* Index notdef_index code */
    1096        error = T1_Add_Table( swap_table, 3,
    1097                              code_table->elements[notdef_index],
    1098                              code_table->lengths [notdef_index] );
    1099        if ( error )
    1100          goto Fail;
    1101  
    1102        error = T1_Add_Table( name_table, notdef_index,
    1103                              swap_table->elements[0],
    1104                              swap_table->lengths [0] );
    1105        if ( error )
    1106          goto Fail;
    1107  
    1108        error = T1_Add_Table( code_table, notdef_index,
    1109                              swap_table->elements[1],
    1110                              swap_table->lengths [1] );
    1111        if ( error )
    1112          goto Fail;
    1113  
    1114        error = T1_Add_Table( name_table, 0,
    1115                              swap_table->elements[2],
    1116                              swap_table->lengths [2] );
    1117        if ( error )
    1118          goto Fail;
    1119  
    1120        error = T1_Add_Table( code_table, 0,
    1121                              swap_table->elements[3],
    1122                              swap_table->lengths [3] );
    1123        if ( error )
    1124          goto Fail;
    1125  
    1126      }
    1127  
    1128      return;
    1129  
    1130    Fail:
    1131      parser->root.error = error;
    1132    }
    1133  
    1134  
    1135    static FT_Error
    1136    t42_load_keyword( T42_Face    face,
    1137                      T42_Loader  loader,
    1138                      T1_Field    field )
    1139    {
    1140      FT_Error  error;
    1141      void*     dummy_object;
    1142      void**    objects;
    1143      FT_UInt   max_objects = 0;
    1144  
    1145  
    1146      /* if the keyword has a dedicated callback, call it */
    1147      if ( field->type == T1_FIELD_TYPE_CALLBACK )
    1148      {
    1149        field->reader( (FT_Face)face, loader );
    1150        error = loader->parser.root.error;
    1151        goto Exit;
    1152      }
    1153  
    1154      /* now the keyword is either a simple field or a table of fields; */
    1155      /* we are now going to take care of it                            */
    1156  
    1157      switch ( field->location )
    1158      {
    1159      case T1_FIELD_LOCATION_FONT_INFO:
    1160        dummy_object = &face->type1.font_info;
    1161        break;
    1162  
    1163      case T1_FIELD_LOCATION_FONT_EXTRA:
    1164        dummy_object = &face->type1.font_extra;
    1165        break;
    1166  
    1167      case T1_FIELD_LOCATION_BBOX:
    1168        dummy_object = &face->type1.font_bbox;
    1169        break;
    1170  
    1171      default:
    1172        dummy_object = &face->type1;
    1173      }
    1174  
    1175      objects = &dummy_object;
    1176  
    1177      if ( field->type == T1_FIELD_TYPE_INTEGER_ARRAY ||
    1178           field->type == T1_FIELD_TYPE_FIXED_ARRAY   )
    1179        error = T1_Load_Field_Table( &loader->parser, field,
    1180                                     objects, max_objects, 0 );
    1181      else
    1182        error = T1_Load_Field( &loader->parser, field,
    1183                               objects, max_objects, 0 );
    1184  
    1185     Exit:
    1186      return error;
    1187    }
    1188  
    1189  
    1190    FT_LOCAL_DEF( FT_Error )
    1191    t42_parse_dict( T42_Face    face,
    1192                    T42_Loader  loader,
    1193                    FT_Byte*    base,
    1194                    FT_Long     size )
    1195    {
    1196      T42_Parser  parser     = &loader->parser;
    1197      FT_Byte*    limit;
    1198      FT_Int      n_keywords = (FT_Int)( sizeof ( t42_keywords ) /
    1199                                           sizeof ( t42_keywords[0] ) );
    1200  
    1201  
    1202      parser->root.cursor = base;
    1203      parser->root.limit  = base + size;
    1204      parser->root.error  = FT_Err_Ok;
    1205  
    1206      limit = parser->root.limit;
    1207  
    1208      T1_Skip_Spaces( parser );
    1209  
    1210      while ( parser->root.cursor < limit )
    1211      {
    1212        FT_Byte*  cur;
    1213  
    1214  
    1215        cur = parser->root.cursor;
    1216  
    1217        /* look for `FontDirectory' which causes problems for some fonts */
    1218        if ( *cur == 'F' && cur + 25 < limit                    &&
    1219             ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
    1220        {
    1221          FT_Byte*  cur2;
    1222  
    1223  
    1224          /* skip the `FontDirectory' keyword */
    1225          T1_Skip_PS_Token( parser );
    1226          T1_Skip_Spaces  ( parser );
    1227          cur = cur2 = parser->root.cursor;
    1228  
    1229          /* look up the `known' keyword */
    1230          while ( cur < limit )
    1231          {
    1232            if ( *cur == 'k' && cur + 5 < limit             &&
    1233                  ft_strncmp( (char*)cur, "known", 5 ) == 0 )
    1234              break;
    1235  
    1236            T1_Skip_PS_Token( parser );
    1237            if ( parser->root.error )
    1238              goto Exit;
    1239            T1_Skip_Spaces  ( parser );
    1240            cur = parser->root.cursor;
    1241          }
    1242  
    1243          if ( cur < limit )
    1244          {
    1245            T1_TokenRec  token;
    1246  
    1247  
    1248            /* skip the `known' keyword and the token following it */
    1249            T1_Skip_PS_Token( parser );
    1250            T1_ToToken( parser, &token );
    1251  
    1252            /* if the last token was an array, skip it! */
    1253            if ( token.type == T1_TOKEN_TYPE_ARRAY )
    1254              cur2 = parser->root.cursor;
    1255          }
    1256          parser->root.cursor = cur2;
    1257        }
    1258  
    1259        /* look for immediates */
    1260        else if ( *cur == '/' && cur + 2 < limit )
    1261        {
    1262          FT_UInt  len;
    1263  
    1264  
    1265          cur++;
    1266  
    1267          parser->root.cursor = cur;
    1268          T1_Skip_PS_Token( parser );
    1269          if ( parser->root.error )
    1270            goto Exit;
    1271  
    1272          len = (FT_UInt)( parser->root.cursor - cur );
    1273  
    1274          if ( len > 0 && len < 22 && parser->root.cursor < limit )
    1275          {
    1276            int  i;
    1277  
    1278  
    1279            /* now compare the immediate name to the keyword table */
    1280  
    1281            /* loop through all known keywords */
    1282            for ( i = 0; i < n_keywords; i++ )
    1283            {
    1284              T1_Field  keyword = (T1_Field)&t42_keywords[i];
    1285              FT_Byte   *name   = (FT_Byte*)keyword->ident;
    1286  
    1287  
    1288              if ( !name )
    1289                continue;
    1290  
    1291              if ( cur[0] == name[0]                      &&
    1292                   len == ft_strlen( (const char *)name ) &&
    1293                   ft_memcmp( cur, name, len ) == 0       )
    1294              {
    1295                /* we found it -- run the parsing callback! */
    1296                parser->root.error = t42_load_keyword( face,
    1297                                                       loader,
    1298                                                       keyword );
    1299                if ( parser->root.error )
    1300                  return parser->root.error;
    1301                break;
    1302              }
    1303            }
    1304          }
    1305        }
    1306        else
    1307        {
    1308          T1_Skip_PS_Token( parser );
    1309          if ( parser->root.error )
    1310            goto Exit;
    1311        }
    1312  
    1313        T1_Skip_Spaces( parser );
    1314      }
    1315  
    1316    Exit:
    1317      return parser->root.error;
    1318    }
    1319  
    1320  
    1321    FT_LOCAL_DEF( void )
    1322    t42_loader_init( T42_Loader  loader,
    1323                     T42_Face    face )
    1324    {
    1325      FT_UNUSED( face );
    1326  
    1327      FT_ZERO( loader );
    1328      loader->num_glyphs = 0;
    1329      loader->num_chars  = 0;
    1330  
    1331      /* initialize the tables -- simply set their `init' field to 0 */
    1332      loader->encoding_table.init = 0;
    1333      loader->charstrings.init    = 0;
    1334      loader->glyph_names.init    = 0;
    1335    }
    1336  
    1337  
    1338    FT_LOCAL_DEF( void )
    1339    t42_loader_done( T42_Loader  loader )
    1340    {
    1341      T42_Parser  parser = &loader->parser;
    1342  
    1343  
    1344      /* finalize tables */
    1345      T1_Release_Table( &loader->encoding_table );
    1346      T1_Release_Table( &loader->charstrings );
    1347      T1_Release_Table( &loader->glyph_names );
    1348      T1_Release_Table( &loader->swap_table );
    1349  
    1350      /* finalize parser */
    1351      t42_parser_done( parser );
    1352    }
    1353  
    1354  
    1355  /* END */