tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

t42parse.c (39687B)


      1 /****************************************************************************
      2 *
      3 * t42parse.c
      4 *
      5 *   Type 42 font parser (body).
      6 *
      7 * Copyright (C) 2002-2025 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    T1_FIELD_ZERO
    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 (%ld)\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 
   1199 
   1200    parser->root.cursor = base;
   1201    parser->root.limit  = base + size;
   1202    parser->root.error  = FT_Err_Ok;
   1203 
   1204    limit = parser->root.limit;
   1205 
   1206    T1_Skip_Spaces( parser );
   1207 
   1208    while ( parser->root.cursor < limit )
   1209    {
   1210      FT_Byte*  cur;
   1211 
   1212 
   1213      cur = parser->root.cursor;
   1214 
   1215      /* look for `FontDirectory' which causes problems for some fonts */
   1216      if ( *cur == 'F' && cur + 25 < limit                    &&
   1217           ft_strncmp( (char*)cur, "FontDirectory", 13 ) == 0 )
   1218      {
   1219        FT_Byte*  cur2;
   1220 
   1221 
   1222        /* skip the `FontDirectory' keyword */
   1223        T1_Skip_PS_Token( parser );
   1224        T1_Skip_Spaces  ( parser );
   1225        cur = cur2 = parser->root.cursor;
   1226 
   1227        /* look up the `known' keyword */
   1228        while ( cur < limit )
   1229        {
   1230          if ( *cur == 'k' && cur + 5 < limit             &&
   1231                ft_strncmp( (char*)cur, "known", 5 ) == 0 )
   1232            break;
   1233 
   1234          T1_Skip_PS_Token( parser );
   1235          if ( parser->root.error )
   1236            goto Exit;
   1237          T1_Skip_Spaces  ( parser );
   1238          cur = parser->root.cursor;
   1239        }
   1240 
   1241        if ( cur < limit )
   1242        {
   1243          T1_TokenRec  token;
   1244 
   1245 
   1246          /* skip the `known' keyword and the token following it */
   1247          T1_Skip_PS_Token( parser );
   1248          T1_ToToken( parser, &token );
   1249 
   1250          /* if the last token was an array, skip it! */
   1251          if ( token.type == T1_TOKEN_TYPE_ARRAY )
   1252            cur2 = parser->root.cursor;
   1253        }
   1254        parser->root.cursor = cur2;
   1255      }
   1256 
   1257      /* look for immediates */
   1258      else if ( *cur == '/' && cur + 2 < limit )
   1259      {
   1260        FT_UInt  len;
   1261 
   1262 
   1263        cur++;
   1264 
   1265        parser->root.cursor = cur;
   1266        T1_Skip_PS_Token( parser );
   1267        if ( parser->root.error )
   1268          goto Exit;
   1269 
   1270        len = (FT_UInt)( parser->root.cursor - cur );
   1271 
   1272        if ( len > 0 && len < 22 && parser->root.cursor < limit )
   1273        {
   1274          T1_Field  keyword = (T1_Field)t42_keywords;
   1275 
   1276 
   1277          /* now compare the immediate name to the keyword table */
   1278          while ( keyword->len )
   1279          {
   1280            FT_Byte*  name = (FT_Byte*)keyword->ident;
   1281 
   1282 
   1283            if ( !name )
   1284              continue;
   1285 
   1286            if ( keyword->len == len              &&
   1287                 ft_memcmp( cur, name, len ) == 0 )
   1288            {
   1289              /* we found it -- run the parsing callback! */
   1290              parser->root.error = t42_load_keyword( face,
   1291                                                     loader,
   1292                                                     keyword );
   1293              if ( parser->root.error )
   1294                return parser->root.error;
   1295              break;
   1296            }
   1297 
   1298            keyword++;
   1299          }
   1300        }
   1301      }
   1302      else
   1303      {
   1304        T1_Skip_PS_Token( parser );
   1305        if ( parser->root.error )
   1306          goto Exit;
   1307      }
   1308 
   1309      T1_Skip_Spaces( parser );
   1310    }
   1311 
   1312  Exit:
   1313    return parser->root.error;
   1314  }
   1315 
   1316 
   1317  FT_LOCAL_DEF( void )
   1318  t42_loader_init( T42_Loader  loader,
   1319                   T42_Face    face )
   1320  {
   1321    FT_UNUSED( face );
   1322 
   1323    FT_ZERO( loader );
   1324    loader->num_glyphs = 0;
   1325    loader->num_chars  = 0;
   1326 
   1327    /* initialize the tables -- simply set their `init' field to 0 */
   1328    loader->encoding_table.init = 0;
   1329    loader->charstrings.init    = 0;
   1330    loader->glyph_names.init    = 0;
   1331  }
   1332 
   1333 
   1334  FT_LOCAL_DEF( void )
   1335  t42_loader_done( T42_Loader  loader )
   1336  {
   1337    T42_Parser  parser = &loader->parser;
   1338 
   1339 
   1340    /* finalize tables */
   1341    T1_Release_Table( &loader->encoding_table );
   1342    T1_Release_Table( &loader->charstrings );
   1343    T1_Release_Table( &loader->glyph_names );
   1344    T1_Release_Table( &loader->swap_table );
   1345 
   1346    /* finalize parser */
   1347    t42_parser_done( parser );
   1348  }
   1349 
   1350 
   1351 /* END */