shithub: freetype+ttf2subf

ref: 91e52d416aedfdfcf5b4331c2156a3866898738e
dir: /src/cff/t2parse.c/

View raw version
#include <t2parse.h>
#include <freetype/fterrors.h>

#define T2_Err_Stack_Underflow   FT_Err_Invalid_Argument
#define T2_Err_Syntax_Error      FT_Err_Invalid_Argument

  enum
  {
    t2_kind_none = 0,
    t2_kind_num,
    t2_kind_fixed,
    t2_kind_string,
    t2_kind_bool,
    t2_kind_delta,
    t2_kind_callback,
    
    t2_kind_max  /* do not remove */
  };


  /* now generate handlers for the most simple fields */
  typedef FT_Error  (*T2_Field_Reader)( T2_Parser*  parser );

  typedef struct T2_Field_Handler_
  {
    int              kind;
    int              code;
    FT_UInt          offset;
    FT_Byte          size;
    T2_Field_Reader  reader;
    FT_UInt          array_max;
    FT_UInt          count_offset;
    
  } T2_Field_Handler;





  LOCAL_FUNC
  void  T2_Parser_Init( T2_Parser*  parser, FT_UInt code, void*  object )
  {
    MEM_Set(parser,0,sizeof(*parser));
    parser->top         = parser->stack;
    parser->object_code = code;
    parser->object      = object;
  }







  /* reads an integer */
  static
  FT_Long   parse_t2_integer( FT_Byte* start,
                              FT_Byte* limit )
  {
    FT_Byte* p   = start;
    FT_Int   v   = *p++;
    FT_Long  val = 0;

    if (v == 28)
    {
      if ( p+2 > limit ) goto Bad;
      val = ((FT_Long)p[0] << 8) | p[1];
      p  += 2;
    }
    else if (v == 29)
    {
      if ( p+4 > limit ) goto Bad;
      val = ((FT_Long)p[0] << 24) |
            ((FT_Long)p[1] << 16) |
            ((FT_Long)p[2] <<  8) | p[3];
      p += 4;
    }
    else if (v < 247)
    {
      val = v - 139;
    }
    else if (v < 251)
    {
      if (p+1 > limit) goto Bad;
      val = (v-247)*256 + p[0]+108;
      p  ++;
    }
    else
    {
      if (p+1 > limit) goto Bad;
      val = -(v-251)*256 - p[0]-108;
      p  ++;
    }

  Exit:
    return val;

  Bad:
    val = 0;
    goto Exit;
  }


  /* reads a real */
  static
  FT_Fixed  parse_t2_real( FT_Byte*  start,
                           FT_Byte*  limit,
                           FT_Int    power_ten )
  {
    FT_Byte*  p    = start;
    FT_Long   num, divider, result, exp;
    FT_Int    sign = 0, exp_sign = 0;
    FT_Byte   nib;
    FT_Byte   phase;

    result  = 0;
    num     = 0;
    divider = 1;

    /* first of all, read the integer part */
    phase = 4;
    p--;
    for (;;)
    {
      /* read one nibble at a time */
      if (phase && ++p >= limit) goto Bad;
      nib   = (p[0] >> phase) & 0xF;
      phase = 4-phase;

      if (nib == 0xE)
        sign = 1;
      else if (nib > 9)
        break;
      else
        result = result*10 + nib;
    }

    /* read decimal part, if any */
    if (nib == 0xa)
      for (;;)
      {
        /* read one nibble at a time */
        if (!phase && ++p >= limit) goto Bad;
        phase = 4-phase;
        nib   = (p[0] >> phase) & 0xF;

        if (nib >= 10)
          break;

        if (divider < 10000000L)
        {
          num      = num*10 + nib;
          divider *= 10;
        }
      }

    /* read exponent, if any */
    if (nib == 12)
    {
      exp_sign = 1;
      nib      = 11;
    }
    if (nib == 11)
    {
      exp = 0;
      for (;;)
      {
        /* read one nibble at a time */
        if (!phase && ++p >= limit) goto Bad;
        phase = 4-phase;
        nib   = (p[0] >> phase) & 0xF;

        if (nib >= 10)
          break;

        exp = exp*10 + nib;
      }
      if (exp_sign)
        exp = -exp;

      power_ten += exp;
    }

    /* raise to power of ten if needed */
    while (power_ten > 0)
    {
      result = result*10;
      num    = num*10;
      power_ten--;
    }

    while (power_ten < 0)
    {
      result  = result/10;
      divider = divider*10;
      power_ten++;
    }

    if (num)
      result += FT_DivFix( num, divider );

    if (sign)
      result = -result;

  Exit:
    return result;

  Bad:
    result = 0;
    goto Exit;
  }


  /* reads a number, either integer or real */
  static
  FT_Long  t2_parse_num( FT_Byte** d )
  {
    return ( **d == 30 ? (parse_t2_real   ( d[0], d[1], 0 ) >> 16):
                          parse_t2_integer( d[0], d[1] ) );
  }

  /* reads a floating point number, either integer or real */
  static
  FT_Fixed  t2_parse_fixed( FT_Byte** d )
  {
    return ( **d == 30 ? parse_t2_real( d[0], d[1], 0 ) :
                         parse_t2_integer( d[0], d[1] ) << 16 );
  }



  static
  FT_Error  parse_font_matrix( T2_Parser*  parser )
  {
    CFF_Top_Dict*  dict   = (CFF_Top_Dict*)parser->object;
    FT_Matrix*     matrix = &dict->font_matrix;
    FT_Byte**      data   = parser->stack;
    FT_Error       error;

    error = T2_Err_Stack_Underflow;
    if (parser->top >= parser->stack + 4)
    {
      matrix->xx = t2_parse_fixed( data++ );
      matrix->yx = t2_parse_fixed( data++ );
      matrix->xy = t2_parse_fixed( data++ );
      matrix->yy = t2_parse_fixed( data   );
      error = 0;
    }
    return error;
  }


  static
  FT_Error  parse_font_bbox( T2_Parser*  parser )
  {
    CFF_Top_Dict*  dict   = (CFF_Top_Dict*)parser->object;
    FT_BBox*       bbox   = &dict->font_bbox;
    FT_Byte**      data   = parser->stack;
    FT_Error       error;

    error = T2_Err_Stack_Underflow;
    if (parser->top >= parser->stack + 4)
    {
      bbox->xMin = t2_parse_fixed( data++ );
      bbox->yMin = t2_parse_fixed( data++ );
      bbox->xMax = t2_parse_fixed( data++ );
      bbox->yMax = t2_parse_fixed( data   );
      error = 0;
    }
    return error;
  }


  static
  FT_Error  parse_private_dict( T2_Parser*  parser )
  {
    CFF_Top_Dict*  dict   = (CFF_Top_Dict*)parser->object;
    FT_Byte**      data   = parser->stack;
    FT_Error       error;

    error = T2_Err_Stack_Underflow;
    if (parser->top >= parser->stack + 2)
    {
      dict->private_offset = t2_parse_num( data++ );
      dict->private_size   = t2_parse_num( data );
      error = 0;
    }
    return error;
  }


  static
  FT_Error  parse_cid_ros( T2_Parser*  parser )
  {
    CFF_Top_Dict*  dict   = (CFF_Top_Dict*)parser->object;
    FT_Byte**      data   = parser->stack;
    FT_Error       error;

    error = T2_Err_Stack_Underflow;
    if (parser->top >= parser->stack + 3)
    {
      dict->cid_registry   = (FT_UInt)t2_parse_num( data++ );
      dict->cid_ordering   = (FT_UInt)t2_parse_num( data++ );
      dict->cid_supplement = (FT_ULong)t2_parse_num( data );
      error = 0;
    }
    return error;
  }



#define T2_FIELD_NUM(code,name)        T2_FIELD( code, name, t2_kind_num )
#define T2_FIELD_FIXED(code,name)      T2_FIELD( code, name, t2_kind_fixed )
#define T2_FIELD_STRING(code,name)     T2_FIELD( code, name, t2_kind_string )
#define T2_FIELD_BOOL(code,name)       T2_FIELD( code, name, t2_kind_bool )
#define T2_FIELD_DELTA(code,name,max)  T2_FIELD( code, name, t2_kind_delta )


#define T2_REF(s,f)   (((s*)0)->f)

#define T2_FIELD_CALLBACK( code, name ) \
     { t2_kind_callback, code, 0, 0, parse_ ## name, 0, 0 },
     
#undef  T2_FIELD
#define T2_FIELD( code, name, kind )           \
    { kind, code | T2CODE,                     \
      (FT_UInt)(char*)&T2_REF( T2TYPE, name ), \
      sizeof( T2_REF( T2TYPE, name ) ),        \
      0 },

#undef T2_FIELD_DELTA
#define T2_FIELD_DELTA( code, name, max )                     \
    { t2_kind_delta, code | T2CODE,                           \
      (FT_UInt)(char*)&T2_REF( T2TYPE, name ),                \
      sizeof( T2_REF( T2TYPE, name ) ),                       \
      0,                                                      \
      max, (FT_UInt)(char*)&T2_REF( T2TYPE, num_ ## name ) },


#define T2CODE_TOPDICT  0x1000
#define T2CODE_PRIVATE  0x2000

  static const T2_Field_Handler  t2_field_handlers[] =
  {
    #include <t2tokens.h>
    { 0, 0, 0, 0, 0, 0, 0 }
  };


  LOCAL_FUNC
  FT_Error  T2_Parser_Run( T2_Parser*  parser,
                           FT_Byte*    start,
                           FT_Byte*    limit )
  {
    FT_Byte*  p     = start;
    FT_Error  error = 0;
    
    parser->top    = parser->stack;
    parser->start  = start;
    parser->limit  = limit;
    parser->cursor = start;
    
    while (p < limit)
    {
      FT_Byte  v = *p;
      if ( v >= 27 || v != 31 )
      {
        /* its a number, we'll push its position on the stack */
        if (parser->top - parser->stack >= T2_MAX_STACK_DEPTH)
          goto Stack_Overflow;

        *parser->top ++ = p;
        
        /* now, skip it */
        if (v == 30)
        {
          /* skip real number */
          for (;;)
          {
            if (p >= limit) goto Syntax_Error;
            v = p[0] >> 4;
            if (v == 15) break;
            v = p[0] & 0xF;
            if (v == 15) break;
            p++;
          }
          p++;
        }
        else if (v == 28) 
          p += 2;
        else if (v == 29)
          p += 4;
        else if (v > 246)
          p += 1;
      }
      else
      {
        /* this is not a number, hence it's an operator. Compute its code */
        /* and look for it in our current list..                          */
        FT_UInt                  code;
        FT_Int                   num_args = parser->top - parser->stack;
        const T2_Field_Handler*  field;

        /* first of all, a trivial check */
        if ( num_args < 1 ) goto Stack_Underflow;

        code = v;
        if (v == 12)
        {
          /* two byte operator */
          p++;
          code = 0x100 | p[0];
        }
        code = code | parser->object_code;
        
        for ( field = t2_field_handlers; field->kind; field++ )
        {
          if (field->code == code)
          {
            /* we found our field's handler, read it.. */
            FT_Long  val;
            FT_Byte* q = (FT_Byte*)parser->object + field->offset;
            
            switch (field->kind)
            {
              case t2_kind_bool:
              case t2_kind_string:
              case t2_kind_num:
                       val = t2_parse_num( parser->stack );
                       goto Store_Number;
                       
              case t2_kind_fixed:
                       val = t2_parse_fixed( parser->stack );
                       
                 Store_Number:                       
                       switch (field->size)
                       {
                         case 1: *(FT_Byte*) q = (FT_Byte)val; break;
                         case 2: *(FT_Short*)q = (FT_Short)val; break;
                         default: *(FT_Long*)q = val;
                       }
                       break;
              
              
              case t2_kind_delta:
                       {
                         FT_Byte*  qcount = (FT_Byte*)parser->object +
                                                field->count_offset;

                         FT_Long   val;
                         FT_Byte** data = parser->stack;
                                                
                         if (num_args > field->array_max)
                           num_args = field->array_max;
                         
                         /* store count */
                         *qcount = (FT_Byte)num_args;
                         
                         val = 0;
                         while (num_args > 0)
                         {
                           val += t2_parse_num( data++ );
                           switch (field->size)
                           {
                             case 1: *(FT_Byte*) q = (FT_Byte)val; break;
                             case 2: *(FT_Short*)q = (FT_Short)val; break;
                             default: *(FT_Long*)q = val; 
                           }
                           q += field->size;
                           num_args--;
                         }
                       }
                       break;
              
              default:  /* callback */
                  error = field->reader( parser );
                  if (error) goto Exit;
            }
            /* clear stack */
            parser->top = parser->stack;
          }
          goto Found;  /* exit loop */
        }

        /* this is an unknown operator, or it is unsupported, we will ignore */
        /* it for now...                                                     */
        
      Found:
        /* clear stack */
        parser->top = parser->stack;
      }
      p++;
    }
  Exit:
    return error;
    
  Stack_Overflow:
    error = FT_Err_Invalid_Argument;
    goto Exit;
    
  Stack_Underflow:
    error = FT_Err_Invalid_Argument;
    goto Exit;
    
  Syntax_Error:
    error = FT_Err_Invalid_Argument;
    goto Exit;
    
  }