tor-browser

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

t1parse.c (14896B)


      1 /****************************************************************************
      2 *
      3 * t1parse.c
      4 *
      5 *   Type 1 parser (body).
      6 *
      7 * Copyright (C) 1996-2025 by
      8 * David Turner, Robert Wilhelm, and Werner Lemberg.
      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  /**************************************************************************
     20   *
     21   * The Type 1 parser is in charge of the following:
     22   *
     23   * - provide an implementation of a growing sequence of objects called
     24   *   a `T1_Table' (used to build various tables needed by the loader).
     25   *
     26   * - opening .pfb and .pfa files to extract their top-level and private
     27   *   dictionaries.
     28   *
     29   * - read numbers, arrays & strings from any dictionary.
     30   *
     31   * See `t1load.c' to see how data is loaded from the font file.
     32   *
     33   */
     34 
     35 
     36 #include <freetype/internal/ftdebug.h>
     37 #include <freetype/internal/ftstream.h>
     38 #include <freetype/internal/psaux.h>
     39 
     40 #include "t1parse.h"
     41 
     42 #include "t1errors.h"
     43 
     44 
     45  /**************************************************************************
     46   *
     47   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     48   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     49   * messages during execution.
     50   */
     51 #undef  FT_COMPONENT
     52 #define FT_COMPONENT  t1parse
     53 
     54 
     55  /*************************************************************************/
     56  /*************************************************************************/
     57  /*************************************************************************/
     58  /*****                                                               *****/
     59  /*****                   INPUT STREAM PARSER                         *****/
     60  /*****                                                               *****/
     61  /*************************************************************************/
     62  /*************************************************************************/
     63  /*************************************************************************/
     64 
     65 
     66  /* see Adobe Technical Note 5040.Download_Fonts.pdf */
     67 
     68  static FT_Error
     69  read_pfb_tag( FT_Stream   stream,
     70                FT_UShort  *atag,
     71                FT_ULong   *asize )
     72  {
     73    FT_Error   error;
     74    FT_UShort  tag;
     75    FT_ULong   size;
     76 
     77 
     78    *atag  = 0;
     79    *asize = 0;
     80 
     81    if ( !FT_READ_USHORT( tag ) )
     82    {
     83      if ( tag == 0x8001U || tag == 0x8002U )
     84      {
     85        if ( !FT_READ_ULONG_LE( size ) )
     86          *asize = size;
     87      }
     88 
     89      *atag = tag;
     90    }
     91 
     92    return error;
     93  }
     94 
     95 
     96  static FT_Error
     97  check_type1_format( FT_Stream    stream,
     98                      const char*  header_string,
     99                      size_t       header_length )
    100  {
    101    FT_Error   error;
    102    FT_UShort  tag;
    103    FT_ULong   dummy;
    104 
    105 
    106    if ( FT_STREAM_SEEK( 0 ) )
    107      goto Exit;
    108 
    109    error = read_pfb_tag( stream, &tag, &dummy );
    110    if ( error )
    111      goto Exit;
    112 
    113    /* We assume that the first segment in a PFB is always encoded as   */
    114    /* text.  This might be wrong (and the specification doesn't insist */
    115    /* on that), but we have never seen a counterexample.               */
    116    if ( tag != 0x8001U && FT_STREAM_SEEK( 0 ) )
    117      goto Exit;
    118 
    119    if ( !FT_FRAME_ENTER( header_length ) )
    120    {
    121      error = FT_Err_Ok;
    122 
    123      if ( ft_memcmp( stream->cursor, header_string, header_length ) != 0 )
    124        error = FT_THROW( Unknown_File_Format );
    125 
    126      FT_FRAME_EXIT();
    127    }
    128 
    129  Exit:
    130    return error;
    131  }
    132 
    133 
    134  FT_LOCAL_DEF( FT_Error )
    135  T1_New_Parser( T1_Parser      parser,
    136                 FT_Stream      stream,
    137                 FT_Memory      memory,
    138                 PSAux_Service  psaux )
    139  {
    140    FT_Error   error;
    141    FT_UShort  tag;
    142    FT_ULong   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->private_len  = 0;
    151    parser->private_dict = NULL;
    152    parser->in_pfb       = 0;
    153    parser->in_memory    = 0;
    154    parser->single_block = 0;
    155 
    156    /* check the header format */
    157    error = check_type1_format( stream, "%!PS-AdobeFont", 14 );
    158    if ( error )
    159    {
    160      if ( FT_ERR_NEQ( error, Unknown_File_Format ) )
    161        goto Exit;
    162 
    163      error = check_type1_format( stream, "%!FontType", 10 );
    164      if ( error )
    165      {
    166        FT_TRACE2(( "  not a Type 1 font\n" ));
    167        goto Exit;
    168      }
    169    }
    170 
    171    /*******************************************************************
    172     *
    173     * Here a short summary of what is going on:
    174     *
    175     *   When creating a new Type 1 parser, we try to locate and load
    176     *   the base dictionary if this is possible (i.e., for PFB
    177     *   files).  Otherwise, we load the whole font into memory.
    178     *
    179     *   When `loading' the base dictionary, we only setup pointers
    180     *   in the case of a memory-based stream.  Otherwise, we
    181     *   allocate and load the base dictionary in it.
    182     *
    183     *   parser->in_pfb is set if we are in a binary (`.pfb') font.
    184     *   parser->in_memory is set if we have a memory stream.
    185     */
    186 
    187    /* try to compute the size of the base dictionary;     */
    188    /* look for a Postscript binary file tag, i.e., 0x8001 */
    189    if ( FT_STREAM_SEEK( 0L ) )
    190      goto Exit;
    191 
    192    error = read_pfb_tag( stream, &tag, &size );
    193    if ( error )
    194      goto Exit;
    195 
    196    if ( tag != 0x8001U )
    197    {
    198      /* assume that this is a PFA file for now; an error will */
    199      /* be produced later when more things are checked        */
    200      if ( FT_STREAM_SEEK( 0L ) )
    201        goto Exit;
    202      size = stream->size;
    203    }
    204    else
    205      parser->in_pfb = 1;
    206 
    207    /* now, try to load `size' bytes of the `base' dictionary we */
    208    /* found previously                                          */
    209 
    210    /* if it is a memory-based resource, set up pointers */
    211    if ( !stream->read )
    212    {
    213      parser->base_dict = (FT_Byte*)stream->base + stream->pos;
    214      parser->base_len  = size;
    215      parser->in_memory = 1;
    216 
    217      /* check that the `size' field is valid */
    218      if ( FT_STREAM_SKIP( size ) )
    219        goto Exit;
    220    }
    221    else
    222    {
    223      /* read segment in memory -- this is clumsy, but so does the format */
    224      if ( FT_QALLOC( parser->base_dict, size )      ||
    225           FT_STREAM_READ( parser->base_dict, size ) )
    226        goto Exit;
    227      parser->base_len = size;
    228    }
    229 
    230    parser->root.base   = parser->base_dict;
    231    parser->root.cursor = parser->base_dict;
    232    parser->root.limit  = parser->root.cursor + parser->base_len;
    233 
    234  Exit:
    235    if ( error && !parser->in_memory )
    236      FT_FREE( parser->base_dict );
    237 
    238    return error;
    239  }
    240 
    241 
    242  FT_LOCAL_DEF( void )
    243  T1_Finalize_Parser( T1_Parser  parser )
    244  {
    245    FT_Memory  memory = parser->root.memory;
    246 
    247 
    248    /* always free the private dictionary */
    249    FT_FREE( parser->private_dict );
    250 
    251    /* free the base dictionary only when we have a disk stream */
    252    if ( !parser->in_memory )
    253      FT_FREE( parser->base_dict );
    254 
    255    parser->root.funcs.done( &parser->root );
    256  }
    257 
    258 
    259  FT_LOCAL_DEF( FT_Error )
    260  T1_Get_Private_Dict( T1_Parser      parser,
    261                       PSAux_Service  psaux )
    262  {
    263    FT_Stream  stream = parser->stream;
    264    FT_Memory  memory = parser->root.memory;
    265    FT_Error   error  = FT_Err_Ok;
    266    FT_ULong   size;
    267 
    268 
    269    if ( parser->in_pfb )
    270    {
    271      /* in the case of the PFB format, the private dictionary can be  */
    272      /* made of several segments.  We thus first read the number of   */
    273      /* segments to compute the total size of the private dictionary  */
    274      /* then re-read them into memory.                                */
    275      FT_ULong   start_pos = FT_STREAM_POS();
    276      FT_UShort  tag;
    277 
    278 
    279      parser->private_len = 0;
    280      for (;;)
    281      {
    282        error = read_pfb_tag( stream, &tag, &size );
    283        if ( error )
    284          goto Fail;
    285 
    286        if ( tag != 0x8002U )
    287          break;
    288 
    289        parser->private_len += size;
    290 
    291        if ( FT_STREAM_SKIP( size ) )
    292          goto Fail;
    293      }
    294 
    295      /* Check that we have a private dictionary there */
    296      /* and allocate private dictionary buffer        */
    297      if ( parser->private_len == 0 )
    298      {
    299        FT_ERROR(( "T1_Get_Private_Dict:"
    300                   " invalid private dictionary section\n" ));
    301        error = FT_THROW( Invalid_File_Format );
    302        goto Fail;
    303      }
    304 
    305      if ( FT_STREAM_SEEK( start_pos )                            ||
    306           FT_QALLOC( parser->private_dict, parser->private_len ) )
    307        goto Fail;
    308 
    309      parser->private_len = 0;
    310      for (;;)
    311      {
    312        error = read_pfb_tag( stream, &tag, &size );
    313        if ( error || tag != 0x8002U )
    314        {
    315          error = FT_Err_Ok;
    316          break;
    317        }
    318 
    319        if ( FT_STREAM_READ( parser->private_dict + parser->private_len,
    320                             size ) )
    321          goto Fail;
    322 
    323        parser->private_len += size;
    324      }
    325    }
    326    else
    327    {
    328      /* We have already `loaded' the whole PFA font file into memory; */
    329      /* if this is a memory resource, allocate a new block to hold    */
    330      /* the private dict.  Otherwise, simply overwrite into the base  */
    331      /* dictionary block in the heap.                                 */
    332 
    333      /* First look for the `eexec' keyword. Ensure `eexec' is real -- */
    334      /* it could be in a comment or string (as e.g. in u003043t.gsf   */
    335      /* from ghostscript).                                            */
    336      FT_Byte*    cur   = parser->base_dict;
    337      FT_Byte*    limit = cur + parser->base_len;
    338      FT_Pointer  pos_lf;
    339      FT_Bool     test_cr;
    340 
    341 
    342      parser->root.cursor = parser->base_dict;
    343      parser->root.limit  = parser->base_dict + parser->base_len;
    344 
    345      cur   = parser->root.cursor;
    346      limit = parser->root.limit;
    347 
    348      while ( cur < limit )
    349      {
    350        /* 9 = 5 letters for `eexec' + whitespace + 4 chars */
    351        if ( cur[0] == 'e' && cur + 9 < limit )
    352        {
    353          if ( cur[1] == 'e' &&
    354               cur[2] == 'x' &&
    355               cur[3] == 'e' &&
    356               cur[4] == 'c' )
    357            goto Found;
    358        }
    359 
    360        T1_Skip_PS_Token( parser );
    361        if ( parser->root.error )
    362          break;
    363        T1_Skip_Spaces  ( parser );
    364        cur = parser->root.cursor;
    365      }
    366 
    367      FT_ERROR(( "T1_Get_Private_Dict: could not find `eexec' keyword\n" ));
    368      error = FT_THROW( Invalid_File_Format );
    369      goto Exit;
    370 
    371      /* now determine where to write the _encrypted_ binary private  */
    372      /* dictionary.  We overwrite the base dictionary for disk-based */
    373      /* resources and allocate a new block otherwise                 */
    374 
    375    Found:
    376      parser->root.limit = parser->base_dict + parser->base_len;
    377 
    378      T1_Skip_PS_Token( parser );
    379      cur   = parser->root.cursor;
    380      limit = parser->root.limit;
    381 
    382      /* According to the Type 1 spec, the first cipher byte must not be */
    383      /* an ASCII whitespace character code (blank, tab, carriage return */
    384      /* or line feed).  We have seen Type 1 fonts with two line feed    */
    385      /* characters...  So skip now all whitespace character codes.      */
    386      /*                                                                 */
    387      /* On the other hand, Adobe's Type 1 parser handles fonts just     */
    388      /* fine that are violating this limitation, so we add a heuristic  */
    389      /* test to stop at \r only if it is not used for EOL.              */
    390 
    391      pos_lf  = ft_memchr( cur, '\n', (size_t)( limit - cur ) );
    392      test_cr = FT_BOOL( !pos_lf                                       ||
    393                         pos_lf > ft_memchr( cur,
    394                                             '\r',
    395                                             (size_t)( limit - cur ) ) );
    396 
    397      while ( cur < limit                    &&
    398              ( *cur == ' '                ||
    399                *cur == '\t'               ||
    400                (test_cr && *cur == '\r' ) ||
    401                *cur == '\n'               ) )
    402        cur++;
    403      if ( cur >= limit )
    404      {
    405        FT_ERROR(( "T1_Get_Private_Dict:"
    406                   " `eexec' not properly terminated\n" ));
    407        error = FT_THROW( Invalid_File_Format );
    408        goto Exit;
    409      }
    410 
    411      size = parser->base_len - (FT_ULong)( cur - parser->base_dict );
    412 
    413      if ( parser->in_memory )
    414      {
    415        /* note that we allocate one more byte to put a terminating `0' */
    416        if ( FT_QALLOC( parser->private_dict, size + 1 ) )
    417          goto Fail;
    418        parser->private_len = size;
    419      }
    420      else
    421      {
    422        parser->single_block = 1;
    423        parser->private_dict = parser->base_dict;
    424        parser->private_len  = size;
    425        parser->base_dict    = NULL;
    426        parser->base_len     = 0;
    427      }
    428 
    429      /* now determine whether the private dictionary is encoded in binary */
    430      /* or hexadecimal ASCII format -- decode it accordingly              */
    431 
    432      /* we need to access the next 4 bytes (after the final whitespace */
    433      /* following the `eexec' keyword); if they all are hexadecimal    */
    434      /* digits, then we have a case of ASCII storage                   */
    435 
    436      if ( cur + 3 < limit                                &&
    437           ft_isxdigit( cur[0] ) && ft_isxdigit( cur[1] ) &&
    438           ft_isxdigit( cur[2] ) && ft_isxdigit( cur[3] ) )
    439      {
    440        /* ASCII hexadecimal encoding */
    441        FT_ULong  len;
    442 
    443 
    444        parser->root.cursor = cur;
    445        (void)psaux->ps_parser_funcs->to_bytes( &parser->root,
    446                                                parser->private_dict,
    447                                                parser->private_len,
    448                                                &len,
    449                                                0 );
    450        parser->private_len = len;
    451 
    452        /* put a safeguard */
    453        parser->private_dict[len] = '\0';
    454      }
    455      else
    456        /* binary encoding -- copy the private dict */
    457        FT_MEM_MOVE( parser->private_dict, cur, size );
    458    }
    459 
    460    /* we now decrypt the encoded binary private dictionary */
    461    psaux->t1_decrypt( parser->private_dict, parser->private_len, 55665U );
    462 
    463    if ( parser->private_len < 4 )
    464    {
    465      FT_ERROR(( "T1_Get_Private_Dict:"
    466                 " invalid private dictionary section\n" ));
    467      error = FT_THROW( Invalid_File_Format );
    468      goto Fail;
    469    }
    470 
    471    /* replace the four random bytes at the beginning with whitespace */
    472    parser->private_dict[0] = ' ';
    473    parser->private_dict[1] = ' ';
    474    parser->private_dict[2] = ' ';
    475    parser->private_dict[3] = ' ';
    476 
    477    parser->root.base   = parser->private_dict;
    478    parser->root.cursor = parser->private_dict;
    479    parser->root.limit  = parser->root.cursor + parser->private_len;
    480 
    481  Fail:
    482  Exit:
    483    return error;
    484  }
    485 
    486 
    487 /* END */