(root)/
freetype-2.13.2/
src/
cid/
cidparse.c
       1  /****************************************************************************
       2   *
       3   * cidparse.c
       4   *
       5   *   CID-keyed Type1 parser (body).
       6   *
       7   * Copyright (C) 1996-2023 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    Again:
      94      /* now, read the rest of the file until we find */
      95      /* `StartData' or `/sfnts'                      */
      96      {
      97        /*
      98         * The algorithm is as follows (omitting the case with less than 256
      99         * bytes to fill for simplicity).
     100         *
     101         * 1. Fill the buffer with 256 + STARTDATA_LEN bytes.
     102         *
     103         * 2. Search for the STARTDATA and SFNTS strings at positions
     104         *    buffer[0], buffer[1], ...,
     105         *    buffer[255 + STARTDATA_LEN - SFNTS_LEN].
     106         *
     107         * 3. Move the last STARTDATA_LEN bytes to buffer[0].
     108         *
     109         * 4. Fill the buffer with 256 bytes, starting at STARTDATA_LEN.
     110         *
     111         * 5. Repeat with step 2.
     112         *
     113         */
     114        FT_Byte  buffer[256 + STARTDATA_LEN + 1];
     115  
     116        /* values for the first loop */
     117        FT_ULong  read_len    = 256 + STARTDATA_LEN;
     118        FT_ULong  read_offset = 0;
     119        FT_Byte*  p           = buffer;
     120  
     121  
     122        for ( offset = FT_STREAM_POS(); ; offset += 256 )
     123        {
     124          FT_ULong  stream_len;
     125  
     126  
     127          stream_len = stream->size - FT_STREAM_POS();
     128  
     129          read_len = FT_MIN( read_len, stream_len );
     130          if ( FT_STREAM_READ( p, read_len ) )
     131            goto Exit;
     132  
     133          /* ensure that we do not compare with data beyond the buffer */
     134          p[read_len] = '\0';
     135  
     136          limit = p + read_len - SFNTS_LEN;
     137  
     138          for ( p = buffer; p < limit; p++ )
     139          {
     140            if ( p[0] == 'S'                                           &&
     141                 ft_strncmp( (char*)p, STARTDATA, STARTDATA_LEN ) == 0 )
     142            {
     143              /* save offset of binary data after `StartData' */
     144              offset += (FT_ULong)( p - buffer ) + STARTDATA_LEN + 1;
     145              goto Found;
     146            }
     147            else if ( p[1] == 's'                                   &&
     148                      ft_strncmp( (char*)p, SFNTS, SFNTS_LEN ) == 0 )
     149            {
     150              offset += (FT_ULong)( p - buffer ) + SFNTS_LEN + 1;
     151              goto Found;
     152            }
     153          }
     154  
     155          if ( read_offset + read_len < STARTDATA_LEN )
     156          {
     157            FT_TRACE2(( "cid_parser_new: no `StartData' keyword found\n" ));
     158            error = FT_THROW( Invalid_File_Format );
     159            goto Exit;
     160          }
     161  
     162          FT_MEM_MOVE( buffer,
     163                       buffer + read_offset + read_len - STARTDATA_LEN,
     164                       STARTDATA_LEN );
     165  
     166          /* values for the next loop */
     167          read_len    = 256;
     168          read_offset = STARTDATA_LEN;
     169          p           = buffer + read_offset;
     170        }
     171      }
     172  
     173    Found:
     174      /* We have found the start of the binary data or the `/sfnts' token. */
     175      /* Now rewind and extract the frame corresponding to this PostScript */
     176      /* section.                                                          */
     177  
     178      ps_len = offset - base_offset;
     179      if ( FT_STREAM_SEEK( base_offset )                  ||
     180           FT_FRAME_EXTRACT( ps_len, parser->postscript ) )
     181        goto Exit;
     182  
     183      parser->data_offset    = offset;
     184      parser->postscript_len = ps_len;
     185      parser->root.base      = parser->postscript;
     186      parser->root.cursor    = parser->postscript;
     187      parser->root.limit     = parser->root.cursor + ps_len;
     188      parser->num_dict       = FT_UINT_MAX;
     189  
     190      /* Finally, we check whether `StartData' or `/sfnts' was real --  */
     191      /* it could be in a comment or string.  We also get the arguments */
     192      /* of `StartData' to find out whether the data is represented in  */
     193      /* binary or hex format.                                          */
     194  
     195      arg1 = parser->root.cursor;
     196      cid_parser_skip_PS_token( parser );
     197      cid_parser_skip_spaces  ( parser );
     198      arg2 = parser->root.cursor;
     199      cid_parser_skip_PS_token( parser );
     200      cid_parser_skip_spaces  ( parser );
     201  
     202      limit = parser->root.limit;
     203      cur   = parser->root.cursor;
     204  
     205      while ( cur <= limit - SFNTS_LEN )
     206      {
     207        if ( parser->root.error )
     208        {
     209          error = parser->root.error;
     210          goto Exit;
     211        }
     212  
     213        if ( cur[0] == 'S'                                           &&
     214             cur <= limit - STARTDATA_LEN                            &&
     215             ft_strncmp( (char*)cur, STARTDATA, STARTDATA_LEN ) == 0 )
     216        {
     217          T1_TokenRec  type_token;
     218          FT_Long      binary_length;
     219  
     220  
     221          parser->root.cursor = arg1;
     222          cid_parser_to_token( parser, &type_token );
     223          if ( type_token.limit - type_token.start == 5              &&
     224               ft_memcmp( (char*)type_token.start, "(Hex)", 5 ) == 0 )
     225          {
     226            parser->root.cursor = arg2;
     227            binary_length = cid_parser_to_int( parser );
     228            if ( binary_length < 0 )
     229            {
     230              FT_ERROR(( "cid_parser_new: invalid length of hex data\n" ));
     231              error = FT_THROW( Invalid_File_Format );
     232            }
     233            else
     234              parser->binary_length = (FT_ULong)binary_length;
     235          }
     236  
     237          goto Exit;
     238        }
     239        else if ( cur[1] == 's'                                   &&
     240                  ft_strncmp( (char*)cur, SFNTS, SFNTS_LEN ) == 0 )
     241        {
     242          FT_TRACE2(( "cid_parser_new: cannot handle Type 11 fonts\n" ));
     243          error = FT_THROW( Unknown_File_Format );
     244          goto Exit;
     245        }
     246  
     247        cid_parser_skip_PS_token( parser );
     248        cid_parser_skip_spaces  ( parser );
     249        arg1 = arg2;
     250        arg2 = cur;
     251        cur  = parser->root.cursor;
     252      }
     253  
     254      /* we haven't found the correct `StartData'; go back and continue */
     255      /* searching                                                      */
     256      FT_FRAME_RELEASE( parser->postscript );
     257      if ( !FT_STREAM_SEEK( offset ) )
     258        goto Again;
     259  
     260    Exit:
     261      return error;
     262    }
     263  
     264  
     265  #undef STARTDATA
     266  #undef STARTDATA_LEN
     267  #undef SFNTS
     268  #undef SFNTS_LEN
     269  
     270  
     271    FT_LOCAL_DEF( void )
     272    cid_parser_done( CID_Parser*  parser )
     273    {
     274      /* always free the private dictionary */
     275      if ( parser->postscript )
     276      {
     277        FT_Stream  stream = parser->stream;
     278  
     279  
     280        FT_FRAME_RELEASE( parser->postscript );
     281      }
     282      parser->root.funcs.done( &parser->root );
     283    }
     284  
     285  
     286  /* END */