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