misc/libfreetype/src/cff/cffparse.c
changeset 5172 88f2e05288ba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/libfreetype/src/cff/cffparse.c	Mon Apr 25 01:46:54 2011 +0200
@@ -0,0 +1,924 @@
+/***************************************************************************/
+/*                                                                         */
+/*  cffparse.c                                                             */
+/*                                                                         */
+/*    CFF token stream parser (body)                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2007, 2008, 2009, 2010 by       */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include "cffparse.h"
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
+
+#include "cfferrs.h"
+#include "cffpic.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_cffparse
+
+
+
+
+  FT_LOCAL_DEF( void )
+  cff_parser_init( CFF_Parser  parser,
+                   FT_UInt     code,
+                   void*       object,
+                   FT_Library  library)
+  {
+    FT_MEM_ZERO( parser, sizeof ( *parser ) );
+
+    parser->top         = parser->stack;
+    parser->object_code = code;
+    parser->object      = object;
+    parser->library     = library;
+  }
+
+
+  /* read an integer */
+  static FT_Long
+  cff_parse_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_Short)( ( (FT_Int)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;
+  }
+
+
+  static const FT_Long power_tens[] =
+  {
+    1L,
+    10L,
+    100L,
+    1000L,
+    10000L,
+    100000L,
+    1000000L,
+    10000000L,
+    100000000L,
+    1000000000L
+  };
+
+
+  /* read a real */
+  static FT_Fixed
+  cff_parse_real( FT_Byte*  start,
+                  FT_Byte*  limit,
+                  FT_Long   power_ten,
+                  FT_Long*  scaling )
+  {
+    FT_Byte*  p = start;
+    FT_UInt   nib;
+    FT_UInt   phase;
+
+    FT_Long   result, number, exponent;
+    FT_Int    sign = 0, exponent_sign = 0;
+    FT_Long   exponent_add, integer_length, fraction_length;
+
+
+    if ( scaling )
+      *scaling = 0;
+
+    result = 0;
+
+    number   = 0;
+    exponent = 0;
+
+    exponent_add    = 0;
+    integer_length  = 0;
+    fraction_length = 0;
+
+    /* First of all, read the integer part. */
+    phase = 4;
+
+    for (;;)
+    {
+      /* If we entered this iteration with phase == 4, we need to */
+      /* read a new byte.  This also skips past the initial 0x1E. */
+      if ( phase )
+      {
+        p++;
+
+        /* Make sure we don't read past the end. */
+        if ( p >= limit )
+          goto Exit;
+      }
+
+      /* Get the nibble. */
+      nib   = ( p[0] >> phase ) & 0xF;
+      phase = 4 - phase;
+
+      if ( nib == 0xE )
+        sign = 1;
+      else if ( nib > 9 )
+        break;
+      else
+      {
+        /* Increase exponent if we can't add the digit. */
+        if ( number >= 0xCCCCCCCL )
+          exponent_add++;
+        /* Skip leading zeros. */
+        else if ( nib || number )
+        {
+          integer_length++;
+          number = number * 10 + nib;
+        }
+      }
+    }
+
+    /* Read fraction part, if any. */
+    if ( nib == 0xa )
+      for (;;)
+      {
+        /* If we entered this iteration with phase == 4, we need */
+        /* to read a new byte.                                   */
+        if ( phase )
+        {
+          p++;
+
+          /* Make sure we don't read past the end. */
+          if ( p >= limit )
+            goto Exit;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        /* Skip leading zeros if possible. */
+        if ( !nib && !number )
+          exponent_add--;
+        /* Only add digit if we don't overflow. */
+        else if ( number < 0xCCCCCCCL && fraction_length < 9 )
+        {
+          fraction_length++;
+          number = number * 10 + nib;
+        }
+      }
+
+    /* Read exponent, if any. */
+    if ( nib == 12 )
+    {
+      exponent_sign = 1;
+      nib           = 11;
+    }
+
+    if ( nib == 11 )
+    {
+      for (;;)
+      {
+        /* If we entered this iteration with phase == 4, */
+        /* we need to read a new byte.                   */
+        if ( phase )
+        {
+          p++;
+
+          /* Make sure we don't read past the end. */
+          if ( p >= limit )
+            goto Exit;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        exponent = exponent * 10 + nib;
+
+        /* Arbitrarily limit exponent. */
+        if ( exponent > 1000 )
+          goto Exit;
+      }
+
+      if ( exponent_sign )
+        exponent = -exponent;
+    }
+
+    /* We don't check `power_ten' and `exponent_add'. */
+    exponent += power_ten + exponent_add;
+
+    if ( scaling )
+    {
+      /* Only use `fraction_length'. */
+      fraction_length += integer_length;
+      exponent        += integer_length;
+
+      if ( fraction_length <= 5 )
+      {
+        if ( number > 0x7FFFL )
+        {
+          result   = FT_DivFix( number, 10 );
+          *scaling = exponent - fraction_length + 1;
+        }
+        else
+        {
+          if ( exponent > 0 )
+          {
+            FT_Long  new_fraction_length, shift;
+
+
+            /* Make `scaling' as small as possible. */
+            new_fraction_length = FT_MIN( exponent, 5 );
+            exponent           -= new_fraction_length;
+            shift               = new_fraction_length - fraction_length;
+
+            number *= power_tens[shift];
+            if ( number > 0x7FFFL )
+            {
+              number   /= 10;
+              exponent += 1;
+            }
+          }
+          else
+            exponent -= fraction_length;
+
+          result   = number << 16;
+          *scaling = exponent;
+        }
+      }
+      else
+      {
+        if ( ( number / power_tens[fraction_length - 5] ) > 0x7FFFL )
+        {
+          result   = FT_DivFix( number, power_tens[fraction_length - 4] );
+          *scaling = exponent - 4;
+        }
+        else
+        {
+          result   = FT_DivFix( number, power_tens[fraction_length - 5] );
+          *scaling = exponent - 5;
+        }
+      }
+    }
+    else
+    {
+      integer_length  += exponent;
+      fraction_length -= exponent;
+
+      /* Check for overflow and underflow. */
+      if ( FT_ABS( integer_length ) > 5 )
+        goto Exit;
+
+      /* Remove non-significant digits. */
+      if ( integer_length < 0 )
+      {
+        number          /= power_tens[-integer_length];
+        fraction_length += integer_length;
+      }
+
+      /* this can only happen if exponent was non-zero */
+      if ( fraction_length == 10 )
+      {
+        number          /= 10;
+        fraction_length -= 1;
+      }
+
+      /* Convert into 16.16 format. */
+      if ( fraction_length > 0 )
+      {
+        if ( ( number / power_tens[fraction_length] ) > 0x7FFFL )
+          goto Exit;
+
+        result = FT_DivFix( number, power_tens[fraction_length] );
+      }
+      else
+      {
+        number *= power_tens[-fraction_length];
+
+        if ( number > 0x7FFFL )
+          goto Exit;
+
+        result = number << 16;
+      }
+    }
+
+    if ( sign )
+      result = -result;
+
+  Exit:
+    return result;
+  }
+
+
+  /* read a number, either integer or real */
+  static FT_Long
+  cff_parse_num( FT_Byte**  d )
+  {
+    return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 )
+                     :   cff_parse_integer( d[0], d[1] );
+  }
+
+
+  /* read a floating point number, either integer or real */
+  static FT_Fixed
+  cff_parse_fixed( FT_Byte**  d )
+  {
+    return **d == 30 ? cff_parse_real( d[0], d[1], 0, NULL )
+                     : cff_parse_integer( d[0], d[1] ) << 16;
+  }
+
+
+  /* read a floating point number, either integer or real, */
+  /* but return `10^scaling' times the number read in      */
+  static FT_Fixed
+  cff_parse_fixed_scaled( FT_Byte**  d,
+                          FT_Long    scaling )
+  {
+    return **d == 30 ? cff_parse_real( d[0], d[1], scaling, NULL )
+                     : ( cff_parse_integer( d[0], d[1] ) *
+                           power_tens[scaling] ) << 16;
+  }
+
+
+  /* read a floating point number, either integer or real,     */
+  /* and return it as precise as possible -- `scaling' returns */
+  /* the scaling factor (as a power of 10)                     */
+  static FT_Fixed
+  cff_parse_fixed_dynamic( FT_Byte**  d,
+                           FT_Long*   scaling )
+  {
+    FT_ASSERT( scaling );
+
+    if ( **d == 30 )
+      return cff_parse_real( d[0], d[1], 0, scaling );
+    else
+    {
+      FT_Long  number;
+      FT_Int   integer_length;
+
+
+      number = cff_parse_integer( d[0], d[1] );
+
+      if ( number > 0x7FFFL )
+      {
+        for ( integer_length = 5; integer_length < 10; integer_length++ )
+          if ( number < power_tens[integer_length] )
+            break;
+
+        if ( ( number / power_tens[integer_length - 5] ) > 0x7FFFL )
+        {
+          *scaling = integer_length - 4;
+          return FT_DivFix( number, power_tens[integer_length - 4] );
+        }
+        else
+        {
+          *scaling = integer_length - 5;
+          return FT_DivFix( number, power_tens[integer_length - 5] );
+        }
+      }
+      else
+      {
+        *scaling = 0;
+        return number << 16;
+      }
+    }
+  }
+
+
+  static FT_Error
+  cff_parse_font_matrix( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict   = (CFF_FontRecDict)parser->object;
+    FT_Matrix*       matrix = &dict->font_matrix;
+    FT_Vector*       offset = &dict->font_offset;
+    FT_ULong*        upm    = &dict->units_per_em;
+    FT_Byte**        data   = parser->stack;
+    FT_Error         error  = CFF_Err_Stack_Underflow;
+
+
+    if ( parser->top >= parser->stack + 6 )
+    {
+      FT_Long  scaling;
+
+
+      error = CFF_Err_Ok;
+
+      /* We expect a well-formed font matrix, this is, the matrix elements */
+      /* `xx' and `yy' are of approximately the same magnitude.  To avoid  */
+      /* loss of precision, we use the magnitude of element `xx' to scale  */
+      /* all other elements.  The scaling factor is then contained in the  */
+      /* `units_per_em' value.                                             */
+
+      matrix->xx = cff_parse_fixed_dynamic( data++, &scaling );
+
+      scaling = -scaling;
+
+      if ( scaling < 0 || scaling > 9 )
+      {
+        /* Return default matrix in case of unlikely values. */
+        matrix->xx = 0x10000L;
+        matrix->yx = 0;
+        matrix->yx = 0;
+        matrix->yy = 0x10000L;
+        offset->x  = 0;
+        offset->y  = 0;
+        *upm       = 1;
+
+        goto Exit;
+      }
+
+      matrix->yx = cff_parse_fixed_scaled( data++, scaling );
+      matrix->xy = cff_parse_fixed_scaled( data++, scaling );
+      matrix->yy = cff_parse_fixed_scaled( data++, scaling );
+      offset->x  = cff_parse_fixed_scaled( data++, scaling );
+      offset->y  = cff_parse_fixed_scaled( data,   scaling );
+
+      *upm = power_tens[scaling];
+    }
+
+  Exit:
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_font_bbox( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_BBox*         bbox = &dict->font_bbox;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 4 )
+    {
+      bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );
+      bbox->yMax = FT_RoundFix( cff_parse_fixed( data   ) );
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_private_dict( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 2 )
+    {
+      dict->private_size   = cff_parse_num( data++ );
+      dict->private_offset = cff_parse_num( data   );
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+  static FT_Error
+  cff_parse_cid_ros( CFF_Parser  parser )
+  {
+    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;
+    FT_Byte**        data = parser->stack;
+    FT_Error         error;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 3 )
+    {
+      dict->cid_registry   = (FT_UInt)cff_parse_num ( data++ );
+      dict->cid_ordering   = (FT_UInt)cff_parse_num ( data++ );
+      if ( **data == 30 )
+        FT_TRACE1(( "cff_parse_cid_ros: real supplement is rounded\n" ));
+      dict->cid_supplement = cff_parse_num( data );
+      if ( dict->cid_supplement < 0 )
+        FT_TRACE1(( "cff_parse_cid_ros: negative supplement %d is found\n",
+                   dict->cid_supplement ));
+      error = CFF_Err_Ok;
+    }
+
+    return error;
+  }
+
+
+#define CFF_FIELD_NUM( code, name ) \
+          CFF_FIELD( code, name, cff_kind_num )
+#define CFF_FIELD_FIXED( code, name ) \
+          CFF_FIELD( code, name, cff_kind_fixed )
+#define CFF_FIELD_FIXED_1000( code, name ) \
+          CFF_FIELD( code, name, cff_kind_fixed_thousand )
+#define CFF_FIELD_STRING( code, name ) \
+          CFF_FIELD( code, name, cff_kind_string )
+#define CFF_FIELD_BOOL( code, name ) \
+          CFF_FIELD( code, name, cff_kind_bool )
+#define CFF_FIELD_DELTA( code, name, max ) \
+          CFF_FIELD( code, name, cff_kind_delta )
+
+#define CFFCODE_TOPDICT  0x1000
+#define CFFCODE_PRIVATE  0x2000
+
+#ifndef FT_CONFIG_OPTION_PIC
+
+#define CFF_FIELD_CALLBACK( code, name ) \
+          {                              \
+            cff_kind_callback,           \
+            code | CFFCODE,              \
+            0, 0,                        \
+            cff_parse_ ## name,          \
+            0, 0                         \
+          },
+
+#undef  CFF_FIELD
+#define CFF_FIELD( code, name, kind ) \
+          {                          \
+            kind,                    \
+            code | CFFCODE,          \
+            FT_FIELD_OFFSET( name ), \
+            FT_FIELD_SIZE( name ),   \
+            0, 0, 0                  \
+          },
+
+#undef  CFF_FIELD_DELTA
+#define CFF_FIELD_DELTA( code, name, max ) \
+        {                                  \
+          cff_kind_delta,                  \
+          code | CFFCODE,                  \
+          FT_FIELD_OFFSET( name ),         \
+          FT_FIELD_SIZE_DELTA( name ),     \
+          0,                               \
+          max,                             \
+          FT_FIELD_OFFSET( num_ ## name )  \
+        },
+
+  static const CFF_Field_Handler  cff_field_handlers[] =
+  {
+
+#include "cfftoken.h"
+
+    { 0, 0, 0, 0, 0, 0, 0 }
+  };
+
+
+#else /* FT_CONFIG_OPTION_PIC */
+
+  void FT_Destroy_Class_cff_field_handlers(FT_Library library, CFF_Field_Handler* clazz)
+  {
+    FT_Memory memory = library->memory;
+    if ( clazz )
+      FT_FREE( clazz );
+  }
+
+  FT_Error FT_Create_Class_cff_field_handlers(FT_Library library, CFF_Field_Handler** output_class)
+  {
+    CFF_Field_Handler*  clazz;
+    FT_Error          error;
+    FT_Memory memory = library->memory;
+    int i=0;
+
+#undef CFF_FIELD
+#undef CFF_FIELD_DELTA
+#undef CFF_FIELD_CALLBACK
+#define CFF_FIELD_CALLBACK( code, name ) i++;
+#define CFF_FIELD( code, name, kind ) i++;
+#define CFF_FIELD_DELTA( code, name, max ) i++;
+
+#include "cfftoken.h"
+    i++;/*{ 0, 0, 0, 0, 0, 0, 0 }*/
+
+    if ( FT_ALLOC( clazz, sizeof(CFF_Field_Handler)*i ) )
+      return error;
+
+    i=0;
+#undef CFF_FIELD
+#undef CFF_FIELD_DELTA
+#undef CFF_FIELD_CALLBACK
+
+#define CFF_FIELD_CALLBACK( code_, name_ )                                   \
+    clazz[i].kind = cff_kind_callback;                                       \
+    clazz[i].code = code_ | CFFCODE;                                         \
+    clazz[i].offset = 0;                                                     \
+    clazz[i].size = 0;                                                       \
+    clazz[i].reader = cff_parse_ ## name_;                                   \
+    clazz[i].array_max = 0;                                                  \
+    clazz[i].count_offset = 0;                                               \
+    i++;
+
+#undef  CFF_FIELD
+#define CFF_FIELD( code_, name_, kind_ )                                     \
+    clazz[i].kind = kind_;                                                   \
+    clazz[i].code = code_ | CFFCODE;                                         \
+    clazz[i].offset = FT_FIELD_OFFSET( name_ );                              \
+    clazz[i].size = FT_FIELD_SIZE( name_ );                                  \
+    clazz[i].reader = 0;                                                     \
+    clazz[i].array_max = 0;                                                  \
+    clazz[i].count_offset = 0;                                               \
+    i++;                                                                     \
+
+#undef  CFF_FIELD_DELTA
+#define CFF_FIELD_DELTA( code_, name_, max_ )                                \
+    clazz[i].kind = cff_kind_delta;                                          \
+    clazz[i].code = code_ | CFFCODE;                                         \
+    clazz[i].offset = FT_FIELD_OFFSET( name_ );                              \
+    clazz[i].size = FT_FIELD_SIZE_DELTA( name_ );                            \
+    clazz[i].reader = 0;                                                     \
+    clazz[i].array_max = max_;                                               \
+    clazz[i].count_offset = FT_FIELD_OFFSET( num_ ## name_ );                \
+    i++;
+
+#include "cfftoken.h"
+
+    clazz[i].kind = 0;
+    clazz[i].code = 0;
+    clazz[i].offset = 0;
+    clazz[i].size = 0;
+    clazz[i].reader = 0;
+    clazz[i].array_max = 0;
+    clazz[i].count_offset = 0;
+
+    *output_class = clazz;
+    return CFF_Err_Ok;
+  }
+
+
+#endif /* FT_CONFIG_OPTION_PIC */
+
+
+  FT_LOCAL_DEF( FT_Error )
+  cff_parser_run( CFF_Parser  parser,
+                  FT_Byte*    start,
+                  FT_Byte*    limit )
+  {
+    FT_Byte*    p       = start;
+    FT_Error    error   = CFF_Err_Ok;
+    FT_Library  library = parser->library;
+    FT_UNUSED(library);
+
+
+    parser->top    = parser->stack;
+    parser->start  = start;
+    parser->limit  = limit;
+    parser->cursor = start;
+
+    while ( p < limit )
+    {
+      FT_UInt  v = *p;
+
+
+      if ( v >= 27 && v != 31 )
+      {
+        /* it's a number; we will push its position on the stack */
+        if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )
+          goto Stack_Overflow;
+
+        *parser->top ++ = p;
+
+        /* now, skip it */
+        if ( v == 30 )
+        {
+          /* skip real number */
+          p++;
+          for (;;)
+          {
+            /* An unterminated floating point number at the */
+            /* end of a dictionary is invalid but harmless. */
+            if ( p >= limit )
+              goto Exit;
+            v = p[0] >> 4;
+            if ( v == 15 )
+              break;
+            v = p[0] & 0xF;
+            if ( v == 15 )
+              break;
+            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_UInt                   num_args = (FT_UInt)
+                                             ( parser->top - parser->stack );
+        const CFF_Field_Handler*  field;
+
+
+        *parser->top = p;
+        code = v;
+        if ( v == 12 )
+        {
+          /* two byte operator */
+          p++;
+          if ( p >= limit )
+            goto Syntax_Error;
+
+          code = 0x100 | p[0];
+        }
+        code = code | parser->object_code;
+
+        for ( field = FT_CFF_FIELD_HANDLERS_GET; field->kind; field++ )
+        {
+          if ( field->code == (FT_Int)code )
+          {
+            /* we found our field's handler; read it */
+            FT_Long   val;
+            FT_Byte*  q = (FT_Byte*)parser->object + field->offset;
+
+
+            /* check that we have enough arguments -- except for */
+            /* delta encoded arrays, which can be empty          */
+            if ( field->kind != cff_kind_delta && num_args < 1 )
+              goto Stack_Underflow;
+
+            switch ( field->kind )
+            {
+            case cff_kind_bool:
+            case cff_kind_string:
+            case cff_kind_num:
+              val = cff_parse_num( parser->stack );
+              goto Store_Number;
+
+            case cff_kind_fixed:
+              val = cff_parse_fixed( parser->stack );
+              goto Store_Number;
+
+            case cff_kind_fixed_thousand:
+              val = cff_parse_fixed_scaled( parser->stack, 3 );
+
+            Store_Number:
+              switch ( field->size )
+              {
+              case (8 / FT_CHAR_BIT):
+                *(FT_Byte*)q = (FT_Byte)val;
+                break;
+
+              case (16 / FT_CHAR_BIT):
+                *(FT_Short*)q = (FT_Short)val;
+                break;
+
+              case (32 / FT_CHAR_BIT):
+                *(FT_Int32*)q = (FT_Int)val;
+                break;
+
+              default:  /* for 64-bit systems */
+                *(FT_Long*)q = val;
+              }
+              break;
+
+            case cff_kind_delta:
+              {
+                FT_Byte*   qcount = (FT_Byte*)parser->object +
+                                      field->count_offset;
+
+                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 += cff_parse_num( data++ );
+                  switch ( field->size )
+                  {
+                  case (8 / FT_CHAR_BIT):
+                    *(FT_Byte*)q = (FT_Byte)val;
+                    break;
+
+                  case (16 / FT_CHAR_BIT):
+                    *(FT_Short*)q = (FT_Short)val;
+                    break;
+
+                  case (32 / FT_CHAR_BIT):
+                    *(FT_Int32*)q = (FT_Int)val;
+                    break;
+
+                  default:  /* for 64-bit systems */
+                    *(FT_Long*)q = val;
+                  }
+
+                  q += field->size;
+                  num_args--;
+                }
+              }
+              break;
+
+            default:  /* callback */
+              error = field->reader( parser );
+              if ( error )
+                goto Exit;
+            }
+            goto Found;
+          }
+        }
+
+        /* 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 = CFF_Err_Invalid_Argument;
+    goto Exit;
+
+  Stack_Underflow:
+    error = CFF_Err_Invalid_Argument;
+    goto Exit;
+
+  Syntax_Error:
+    error = CFF_Err_Invalid_Argument;
+    goto Exit;
+  }
+
+
+/* END */