tor-browser

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

cidparse.c (9681B)


      1 /****************************************************************************
      2 *
      3 * cidparse.c
      4 *
      5 *   CID-keyed Type1 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 #include <freetype/internal/ftdebug.h>
     20 #include <freetype/internal/ftobjs.h>
     21 #include <freetype/internal/ftstream.h>
     22 
     23 #include "cidparse.h"
     24 
     25 #include "ciderrs.h"
     26 
     27 
     28  /**************************************************************************
     29   *
     30   * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     31   * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     32   * messages during execution.
     33   */
     34 #undef  FT_COMPONENT
     35 #define FT_COMPONENT  cidparse
     36 
     37 
     38  /*************************************************************************/
     39  /*************************************************************************/
     40  /*************************************************************************/
     41  /*****                                                               *****/
     42  /*****                    INPUT STREAM PARSER                        *****/
     43  /*****                                                               *****/
     44  /*************************************************************************/
     45  /*************************************************************************/
     46  /*************************************************************************/
     47 
     48 
     49 #define STARTDATA      "StartData"
     50 #define STARTDATA_LEN  ( sizeof ( STARTDATA ) - 1 )
     51 #define SFNTS          "/sfnts"
     52 #define SFNTS_LEN      ( sizeof ( SFNTS ) - 1 )
     53 
     54 
     55  FT_LOCAL_DEF( FT_Error )
     56  cid_parser_new( CID_Parser*    parser,
     57                  FT_Stream      stream,
     58                  FT_Memory      memory,
     59                  PSAux_Service  psaux )
     60  {
     61    FT_Error  error;
     62    FT_ULong  base_offset, offset, ps_len;
     63    FT_Byte   *cur, *limit;
     64    FT_Byte   *arg1, *arg2;
     65 
     66 
     67    FT_ZERO( parser );
     68    psaux->ps_parser_funcs->init( &parser->root, 0, 0, memory );
     69 
     70    parser->stream = stream;
     71 
     72    base_offset = FT_STREAM_POS();
     73 
     74    /* first of all, check the font format in the header */
     75    if ( FT_FRAME_ENTER( 31 ) )
     76    {
     77      FT_TRACE2(( "  not a CID-keyed font\n" ));
     78      error = FT_THROW( Unknown_File_Format );
     79      goto Exit;
     80    }
     81 
     82    if ( ft_strncmp( (char *)stream->cursor,
     83                     "%!PS-Adobe-3.0 Resource-CIDFont", 31 ) )
     84    {
     85      FT_TRACE2(( "  not a CID-keyed font\n" ));
     86      error = FT_THROW( Unknown_File_Format );
     87    }
     88 
     89    FT_FRAME_EXIT();
     90    if ( error )
     91      goto Exit;
     92 
     93    if ( !stream->read ) {
     94      /* just parse memory-based streams */
     95      offset = stream->size;
     96    }
     97    else
     98    {
     99      /* Find the last `StartData` or `/sfnts`.  The parser requires */
    100      /* contiguous memory; attempt to pin as little as necessary.   */
    101 
    102      /*
    103       * The algorithm is as follows (omitting the case with less than 256
    104       * bytes to fill for simplicity).
    105       *
    106       * 1. Fill the buffer with 256 + STARTDATA_LEN bytes.
    107       *
    108       * 2. Search for the STARTDATA and SFNTS strings at positions
    109       *    buffer[0], buffer[1], ...,
    110       *    buffer[255 + STARTDATA_LEN - SFNTS_LEN].
    111       *
    112       * 3. Move the last STARTDATA_LEN bytes to buffer[0].
    113       *
    114       * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN.
    115       *
    116       * 5. Repeat with step 2.
    117       *
    118       */
    119      FT_Byte  buffer[256 + STARTDATA_LEN + 1];
    120 
    121      /* values for the first loop */
    122      FT_ULong  read_len    = 256 + STARTDATA_LEN;
    123      FT_ULong  read_offset = 0;
    124      FT_Byte*  p           = buffer;
    125 
    126 
    127      offset = 0;
    128      while ( 1 )
    129      {
    130        FT_ULong  stream_len;
    131 
    132 
    133        stream_len = stream->size - FT_STREAM_POS();
    134 
    135        read_len = FT_MIN( read_len, stream_len );
    136        if ( read_len && FT_STREAM_READ( p, read_len ) )
    137          goto Exit;
    138 
    139        /* ensure that we do not compare with data beyond the buffer */
    140        p[read_len] = '\0';
    141 
    142        limit = p + read_len - SFNTS_LEN;
    143 
    144        for ( p = buffer; p < limit; p++ )
    145        {
    146          if ( p[0] == 'S'                                           &&
    147               ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
    148          {
    149            /* save offset of binary data after `StartData' */
    150            offset = FT_STREAM_POS() - read_len - read_offset
    151                     + (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
    152          }
    153          else if ( p[1] == 's'                                   &&
    154                    ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
    155          {
    156            offset = FT_STREAM_POS() - read_len - read_offset
    157                     + (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
    158          }
    159        }
    160 
    161        if ( read_offset + read_len <= STARTDATA_LEN )
    162        {
    163          if ( offset )
    164            goto Found;
    165 
    166          FT_TRACE2(( "cid_parser_new: no `StartData` keyword found\n" ));
    167          error = FT_THROW( Invalid_File_Format );
    168          goto Exit;
    169        }
    170 
    171        FT_MEM_MOVE( buffer,
    172                     buffer + read_offset + read_len - STARTDATA_LEN,
    173                     STARTDATA_LEN );
    174 
    175        /* values for the next loop */
    176        read_len    = 256;
    177        read_offset = STARTDATA_LEN;
    178        p           = buffer + read_offset;
    179      }
    180    }
    181 
    182  Found:
    183    /* We have found an efficient range to look for the binary data or    */
    184    /* `/sfnts' token.  Now rewind and extract the frame corresponding to */
    185    /* this PostScript section.                                           */
    186 
    187    ps_len = offset - base_offset;
    188    if ( FT_STREAM_SEEK( base_offset )                  ||
    189         FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
    190      goto Exit;
    191 
    192    parser->data_offset    = offset;
    193    parser->postscript_len = ps_len;
    194    parser->root.base      = parser->postscript;
    195    parser->root.cursor    = parser->postscript;
    196    parser->root.limit     = parser->root.cursor + ps_len;
    197    parser->num_dict       = FT_UINT_MAX;
    198 
    199    /* Find the first real `StartData' or `/sfnts' -- the last one    */
    200    /* could be in a comment or string.  We also get the arguments    */
    201    /* of `StartData' to find out whether the data is represented in  */
    202    /* binary or hex format.                                          */
    203 
    204    arg1 = parser->root.cursor;
    205    cid_parser_skip_PS_token( parser );
    206    cid_parser_skip_spaces  ( parser );
    207    arg2 = parser->root.cursor;
    208    cid_parser_skip_PS_token( parser );
    209    cid_parser_skip_spaces  ( parser );
    210 
    211    limit = parser->root.limit;
    212    cur   = parser->root.cursor;
    213 
    214    while ( cur <= limit - SFNTS_LEN )
    215    {
    216      if ( parser->root.error )
    217      {
    218        error = parser->root.error;
    219        goto Exit;
    220      }
    221 
    222      if ( cur[0] == 'S'                                           &&
    223           cur <= limit - STARTDATA_LEN                            &&
    224           ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
    225      {
    226        T1_TokenRec  type_token;
    227        FT_Long      binary_length;
    228        FT_ULong     found_offset;
    229 
    230 
    231        parser->root.cursor = arg1;
    232        cid_parser_to_token( parser, &type_token );
    233        if ( type_token.limit - type_token.start == 5              &&
    234             ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
    235        {
    236          parser->root.cursor = arg2;
    237          binary_length = cid_parser_to_int( parser );
    238          if ( binary_length < 0 )
    239          {
    240            FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
    241            error = FT_THROW( Invalid_File_Format );
    242          }
    243          else
    244            parser->binary_length = (FT_ULong)binary_length;
    245        }
    246 
    247        /* set the real values for the parser, if different */
    248        found_offset = (FT_ULong)( cur - parser->postscript )
    249                       + STARTDATA_LEN + 1;
    250        if ( found_offset != offset )
    251        {
    252          FT_FRAME_RELEASE( parser->postscript );
    253 
    254          ps_len = found_offset - base_offset;
    255          if ( FT_STREAM_SEEK( base_offset )                  ||
    256               FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
    257            goto Exit;
    258 
    259          parser->data_offset    = found_offset;
    260          parser->postscript_len = ps_len;
    261          parser->root.base      = parser->postscript;
    262          parser->root.cursor    = parser->postscript;
    263          parser->root.limit     = parser->root.cursor + ps_len;
    264        }
    265        goto Exit;
    266      }
    267      else if ( cur[1] == 's'                                   &&
    268                ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 )
    269      {
    270        FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" ));
    271        error = FT_THROW( Unknown_File_Format );
    272        goto Exit;
    273      }
    274 
    275      cid_parser_skip_PS_token( parser );
    276      cid_parser_skip_spaces  ( parser );
    277      arg1 = arg2;
    278      arg2 = cur;
    279      cur  = parser->root.cursor;
    280    }
    281 
    282    FT_TRACE2(( "cid_parser_new: no `StartData` token found\n" ));
    283    error = FT_THROW( Invalid_File_Format );
    284 
    285  Exit:
    286    return error;
    287  }
    288 
    289 
    290 #undef STARTDATA
    291 #undef STARTDATA_LEN
    292 #undef SFNTS
    293 #undef SFNTS_LEN
    294 
    295 
    296  FT_LOCAL_DEF( void )
    297  cid_parser_done( CID_Parser*  parser )
    298  {
    299    /* always free the private dictionary */
    300    if ( parser->postscript )
    301    {
    302      FT_Stream  stream = parser->stream;
    303 
    304 
    305      FT_FRAME_RELEASE( parser->postscript );
    306    }
    307    parser->root.funcs.done( &parser->root );
    308  }
    309 
    310 
    311 /* END */