- Remove svn:needs-lock, svn:eol-type, and svn:eol-tyle properties.
[reactos.git] / reactos / lib / 3rdparty / freetype / src / cff / cffparse.c
index 16e1aab..41af6a3 100644 (file)
-/***************************************************************************/\r
-/*                                                                         */\r
-/*  cffparse.c                                                             */\r
-/*                                                                         */\r
-/*    CFF token stream parser (body)                                       */\r
-/*                                                                         */\r
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2007 by                         */\r
-/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */\r
-/*                                                                         */\r
-/*  This file is part of the FreeType project, and may only be used,       */\r
-/*  modified, and distributed under the terms of the FreeType project      */\r
-/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */\r
-/*  this file you indicate that you have read the license and              */\r
-/*  understand and accept it fully.                                        */\r
-/*                                                                         */\r
-/***************************************************************************/\r
-\r
-\r
-#include <ft2build.h>\r
-#include "cffparse.h"\r
-#include FT_INTERNAL_STREAM_H\r
-\r
-#include "cfferrs.h"\r
-\r
-\r
-  /*************************************************************************/\r
-  /*                                                                       */\r
-  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */\r
-  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */\r
-  /* messages during execution.                                            */\r
-  /*                                                                       */\r
-#undef  FT_COMPONENT\r
-#define FT_COMPONENT  trace_cffparse\r
-\r
-\r
-  enum\r
-  {\r
-    cff_kind_none = 0,\r
-    cff_kind_num,\r
-    cff_kind_fixed,\r
-    cff_kind_fixed_thousand,\r
-    cff_kind_string,\r
-    cff_kind_bool,\r
-    cff_kind_delta,\r
-    cff_kind_callback,\r
-\r
-    cff_kind_max  /* do not remove */\r
-  };\r
-\r
-\r
-  /* now generate handlers for the most simple fields */\r
-  typedef FT_Error  (*CFF_Field_Reader)( CFF_Parser  parser );\r
-\r
-  typedef struct  CFF_Field_Handler_\r
-  {\r
-    int               kind;\r
-    int               code;\r
-    FT_UInt           offset;\r
-    FT_Byte           size;\r
-    CFF_Field_Reader  reader;\r
-    FT_UInt           array_max;\r
-    FT_UInt           count_offset;\r
-\r
-  } CFF_Field_Handler;\r
-\r
-\r
-  FT_LOCAL_DEF( void )\r
-  cff_parser_init( CFF_Parser  parser,\r
-                   FT_UInt     code,\r
-                   void*       object )\r
-  {\r
-    FT_MEM_ZERO( parser, sizeof ( *parser ) );\r
-\r
-    parser->top         = parser->stack;\r
-    parser->object_code = code;\r
-    parser->object      = object;\r
-  }\r
-\r
-\r
-  /* read an integer */\r
-  static FT_Long\r
-  cff_parse_integer( FT_Byte*  start,\r
-                     FT_Byte*  limit )\r
-  {\r
-    FT_Byte*  p   = start;\r
-    FT_Int    v   = *p++;\r
-    FT_Long   val = 0;\r
-\r
-\r
-    if ( v == 28 )\r
-    {\r
-      if ( p + 2 > limit )\r
-        goto Bad;\r
-\r
-      val = (FT_Short)( ( (FT_Int)p[0] << 8 ) | p[1] );\r
-      p  += 2;\r
-    }\r
-    else if ( v == 29 )\r
-    {\r
-      if ( p + 4 > limit )\r
-        goto Bad;\r
-\r
-      val = ( (FT_Long)p[0] << 24 ) |\r
-            ( (FT_Long)p[1] << 16 ) |\r
-            ( (FT_Long)p[2] <<  8 ) |\r
-                       p[3];\r
-      p += 4;\r
-    }\r
-    else if ( v < 247 )\r
-    {\r
-      val = v - 139;\r
-    }\r
-    else if ( v < 251 )\r
-    {\r
-      if ( p + 1 > limit )\r
-        goto Bad;\r
-\r
-      val = ( v - 247 ) * 256 + p[0] + 108;\r
-      p++;\r
-    }\r
-    else\r
-    {\r
-      if ( p + 1 > limit )\r
-        goto Bad;\r
-\r
-      val = -( v - 251 ) * 256 - p[0] - 108;\r
-      p++;\r
-    }\r
-\r
-  Exit:\r
-    return val;\r
-\r
-  Bad:\r
-    val = 0;\r
-    goto Exit;\r
-  }\r
-\r
-\r
-  /* read a real */\r
-  static FT_Fixed\r
-  cff_parse_real( FT_Byte*  start,\r
-                  FT_Byte*  limit,\r
-                  FT_Int    power_ten )\r
-  {\r
-    FT_Byte*  p    = start;\r
-    FT_Long   num, divider, result, exponent;\r
-    FT_Int    sign = 0, exponent_sign = 0;\r
-    FT_UInt   nib;\r
-    FT_UInt   phase;\r
-\r
-\r
-    result  = 0;\r
-    num     = 0;\r
-    divider = 1;\r
-\r
-    /* first of all, read the integer part */\r
-    phase = 4;\r
-\r
-    for (;;)\r
-    {\r
-      /* If we entered this iteration with phase == 4, we need to */\r
-      /* read a new byte.  This also skips past the initial 0x1E. */\r
-      if ( phase )\r
-      {\r
-        p++;\r
-\r
-        /* Make sure we don't read past the end. */\r
-        if ( p >= limit )\r
-          goto Bad;\r
-      }\r
-\r
-      /* Get the nibble. */\r
-      nib   = ( p[0] >> phase ) & 0xF;\r
-      phase = 4 - phase;\r
-\r
-      if ( nib == 0xE )\r
-        sign = 1;\r
-      else if ( nib > 9 )\r
-        break;\r
-      else\r
-        result = result * 10 + nib;\r
-    }\r
-\r
-    /* read decimal part, if any */\r
-    if ( nib == 0xa )\r
-      for (;;)\r
-      {\r
-        /* If we entered this iteration with phase == 4, we need */\r
-        /* to read a new byte.                                   */\r
-        if ( phase )\r
-        {\r
-          p++;\r
-\r
-          /* Make sure we don't read past the end. */\r
-          if ( p >= limit )\r
-            goto Bad;\r
-        }\r
-\r
-        /* Get the nibble. */\r
-        nib   = ( p[0] >> phase ) & 0xF;\r
-        phase = 4 - phase;\r
-        if ( nib >= 10 )\r
-          break;\r
-\r
-        if ( divider < 10000000L )\r
-        {\r
-          num      = num * 10 + nib;\r
-          divider *= 10;\r
-        }\r
-      }\r
-\r
-    /* read exponent, if any */\r
-    if ( nib == 12 )\r
-    {\r
-      exponent_sign = 1;\r
-      nib           = 11;\r
-    }\r
-\r
-    if ( nib == 11 )\r
-    {\r
-      exponent = 0;\r
-\r
-      for (;;)\r
-      {\r
-        /* If we entered this iteration with phase == 4, we need */\r
-        /* to read a new byte.                                   */\r
-        if ( phase )\r
-        {\r
-          p++;\r
-\r
-          /* Make sure we don't read past the end. */\r
-          if ( p >= limit )\r
-            goto Bad;\r
-        }\r
-\r
-        /* Get the nibble. */\r
-        nib   = ( p[0] >> phase ) & 0xF;\r
-        phase = 4 - phase;\r
-        if ( nib >= 10 )\r
-          break;\r
-\r
-        exponent = exponent * 10 + nib;\r
-      }\r
-\r
-      if ( exponent_sign )\r
-        exponent = -exponent;\r
-\r
-      power_ten += (FT_Int)exponent;\r
-    }\r
-\r
-    /* raise to power of ten if needed */\r
-    while ( power_ten > 0 )\r
-    {\r
-      result = result * 10;\r
-      num    = num * 10;\r
-\r
-      power_ten--;\r
-    }\r
-\r
-    while ( power_ten < 0 )\r
-    {\r
-      result  = result / 10;\r
-      divider = divider * 10;\r
-\r
-      power_ten++;\r
-    }\r
-\r
-    /* Move the integer part into the high 16 bits. */\r
-    result <<= 16;\r
-\r
-    /* Place the decimal part into the low 16 bits. */\r
-    if ( num )\r
-      result |= FT_DivFix( num, divider );\r
-\r
-    if ( sign )\r
-      result = -result;\r
-\r
-  Exit:\r
-    return result;\r
-\r
-  Bad:\r
-    result = 0;\r
-    goto Exit;\r
-  }\r
-\r
-\r
-  /* read a number, either integer or real */\r
-  static FT_Long\r
-  cff_parse_num( FT_Byte**  d )\r
-  {\r
-    return ( **d == 30 ? ( cff_parse_real   ( d[0], d[1], 0 ) >> 16 )\r
-                       :   cff_parse_integer( d[0], d[1] ) );\r
-  }\r
-\r
-\r
-  /* read a floating point number, either integer or real */\r
-  static FT_Fixed\r
-  cff_parse_fixed( FT_Byte**  d )\r
-  {\r
-    return ( **d == 30 ? cff_parse_real   ( d[0], d[1], 0 )\r
-                       : cff_parse_integer( d[0], d[1] ) << 16 );\r
-  }\r
-\r
-  /* read a floating point number, either integer or real, */\r
-  /* but return 1000 times the number read in.             */\r
-  static FT_Fixed\r
-  cff_parse_fixed_thousand( FT_Byte**  d )\r
-  {\r
-    return **d ==\r
-      30 ? cff_parse_real     ( d[0], d[1], 3 )\r
-         : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );\r
-  }\r
-\r
-  static FT_Error\r
-  cff_parse_font_matrix( CFF_Parser  parser )\r
-  {\r
-    CFF_FontRecDict  dict   = (CFF_FontRecDict)parser->object;\r
-    FT_Matrix*       matrix = &dict->font_matrix;\r
-    FT_Vector*       offset = &dict->font_offset;\r
-    FT_UShort*       upm    = &dict->units_per_em;\r
-    FT_Byte**        data   = parser->stack;\r
-    FT_Error         error;\r
-    FT_Fixed         temp;\r
-\r
-\r
-    error = CFF_Err_Stack_Underflow;\r
-\r
-    if ( parser->top >= parser->stack + 6 )\r
-    {\r
-      matrix->xx = cff_parse_fixed_thousand( data++ );\r
-      matrix->yx = cff_parse_fixed_thousand( data++ );\r
-      matrix->xy = cff_parse_fixed_thousand( data++ );\r
-      matrix->yy = cff_parse_fixed_thousand( data++ );\r
-      offset->x  = cff_parse_fixed_thousand( data++ );\r
-      offset->y  = cff_parse_fixed_thousand( data   );\r
-\r
-      temp = FT_ABS( matrix->yy );\r
-\r
-      *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );\r
-\r
-      if ( temp != 0x10000L )\r
-      {\r
-        matrix->xx = FT_DivFix( matrix->xx, temp );\r
-        matrix->yx = FT_DivFix( matrix->yx, temp );\r
-        matrix->xy = FT_DivFix( matrix->xy, temp );\r
-        matrix->yy = FT_DivFix( matrix->yy, temp );\r
-        offset->x  = FT_DivFix( offset->x,  temp );\r
-        offset->y  = FT_DivFix( offset->y,  temp );\r
-      }\r
-\r
-      /* note that the offsets must be expressed in integer font units */\r
-      offset->x >>= 16;\r
-      offset->y >>= 16;\r
-\r
-      error = CFF_Err_Ok;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  cff_parse_font_bbox( CFF_Parser  parser )\r
-  {\r
-    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;\r
-    FT_BBox*         bbox = &dict->font_bbox;\r
-    FT_Byte**        data = parser->stack;\r
-    FT_Error         error;\r
-\r
-\r
-    error = CFF_Err_Stack_Underflow;\r
-\r
-    if ( parser->top >= parser->stack + 4 )\r
-    {\r
-      bbox->xMin = FT_RoundFix( cff_parse_fixed( data++ ) );\r
-      bbox->yMin = FT_RoundFix( cff_parse_fixed( data++ ) );\r
-      bbox->xMax = FT_RoundFix( cff_parse_fixed( data++ ) );\r
-      bbox->yMax = FT_RoundFix( cff_parse_fixed( data   ) );\r
-      error = CFF_Err_Ok;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  cff_parse_private_dict( CFF_Parser  parser )\r
-  {\r
-    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;\r
-    FT_Byte**        data = parser->stack;\r
-    FT_Error         error;\r
-\r
-\r
-    error = CFF_Err_Stack_Underflow;\r
-\r
-    if ( parser->top >= parser->stack + 2 )\r
-    {\r
-      dict->private_size   = cff_parse_num( data++ );\r
-      dict->private_offset = cff_parse_num( data   );\r
-      error = CFF_Err_Ok;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-  static FT_Error\r
-  cff_parse_cid_ros( CFF_Parser  parser )\r
-  {\r
-    CFF_FontRecDict  dict = (CFF_FontRecDict)parser->object;\r
-    FT_Byte**        data = parser->stack;\r
-    FT_Error         error;\r
-\r
-\r
-    error = CFF_Err_Stack_Underflow;\r
-\r
-    if ( parser->top >= parser->stack + 3 )\r
-    {\r
-      dict->cid_registry   = (FT_UInt)cff_parse_num ( data++ );\r
-      dict->cid_ordering   = (FT_UInt)cff_parse_num ( data++ );\r
-      dict->cid_supplement = (FT_ULong)cff_parse_num( data );\r
-      error = CFF_Err_Ok;\r
-    }\r
-\r
-    return error;\r
-  }\r
-\r
-\r
-#define CFF_FIELD_NUM( code, name ) \\r
-          CFF_FIELD( code, name, cff_kind_num )\r
-#define CFF_FIELD_FIXED( code, name ) \\r
-          CFF_FIELD( code, name, cff_kind_fixed )\r
-#define CFF_FIELD_FIXED_1000( code, name ) \\r
-          CFF_FIELD( code, name, cff_kind_fixed_thousand )\r
-#define CFF_FIELD_STRING( code, name ) \\r
-          CFF_FIELD( code, name, cff_kind_string )\r
-#define CFF_FIELD_BOOL( code, name ) \\r
-          CFF_FIELD( code, name, cff_kind_bool )\r
-#define CFF_FIELD_DELTA( code, name, max ) \\r
-          CFF_FIELD( code, name, cff_kind_delta )\r
-\r
-#define CFF_FIELD_CALLBACK( code, name ) \\r
-          {                              \\r
-            cff_kind_callback,           \\r
-            code | CFFCODE,              \\r
-            0, 0,                        \\r
-            cff_parse_ ## name,          \\r
-            0, 0                         \\r
-          },\r
-\r
-#undef  CFF_FIELD\r
-#define CFF_FIELD( code, name, kind ) \\r
-          {                          \\r
-            kind,                    \\r
-            code | CFFCODE,          \\r
-            FT_FIELD_OFFSET( name ), \\r
-            FT_FIELD_SIZE( name ),   \\r
-            0, 0, 0                  \\r
-          },\r
-\r
-#undef  CFF_FIELD_DELTA\r
-#define CFF_FIELD_DELTA( code, name, max ) \\r
-        {                                  \\r
-          cff_kind_delta,                  \\r
-          code | CFFCODE,                  \\r
-          FT_FIELD_OFFSET( name ),         \\r
-          FT_FIELD_SIZE_DELTA( name ),     \\r
-          0,                               \\r
-          max,                             \\r
-          FT_FIELD_OFFSET( num_ ## name )  \\r
-        },\r
-\r
-#define CFFCODE_TOPDICT  0x1000\r
-#define CFFCODE_PRIVATE  0x2000\r
-\r
-  static const CFF_Field_Handler  cff_field_handlers[] =\r
-  {\r
-\r
-#include "cfftoken.h"\r
-\r
-    { 0, 0, 0, 0, 0, 0, 0 }\r
-  };\r
-\r
-\r
-  FT_LOCAL_DEF( FT_Error )\r
-  cff_parser_run( CFF_Parser  parser,\r
-                  FT_Byte*    start,\r
-                  FT_Byte*    limit )\r
-  {\r
-    FT_Byte*  p     = start;\r
-    FT_Error  error = CFF_Err_Ok;\r
-\r
-\r
-    parser->top    = parser->stack;\r
-    parser->start  = start;\r
-    parser->limit  = limit;\r
-    parser->cursor = start;\r
-\r
-    while ( p < limit )\r
-    {\r
-      FT_UInt  v = *p;\r
-\r
-\r
-      if ( v >= 27 && v != 31 )\r
-      {\r
-        /* it's a number; we will push its position on the stack */\r
-        if ( parser->top - parser->stack >= CFF_MAX_STACK_DEPTH )\r
-          goto Stack_Overflow;\r
-\r
-        *parser->top ++ = p;\r
-\r
-        /* now, skip it */\r
-        if ( v == 30 )\r
-        {\r
-          /* skip real number */\r
-          p++;\r
-          for (;;)\r
-          {\r
-            if ( p >= limit )\r
-              goto Syntax_Error;\r
-            v = p[0] >> 4;\r
-            if ( v == 15 )\r
-              break;\r
-            v = p[0] & 0xF;\r
-            if ( v == 15 )\r
-              break;\r
-            p++;\r
-          }\r
-        }\r
-        else if ( v == 28 )\r
-          p += 2;\r
-        else if ( v == 29 )\r
-          p += 4;\r
-        else if ( v > 246 )\r
-          p += 1;\r
-      }\r
-      else\r
-      {\r
-        /* This is not a number, hence it's an operator.  Compute its code */\r
-        /* and look for it in our current list.                            */\r
-\r
-        FT_UInt                   code;\r
-        FT_UInt                   num_args = (FT_UInt)\r
-                                             ( parser->top - parser->stack );\r
-        const CFF_Field_Handler*  field;\r
-\r
-\r
-        *parser->top = p;\r
-        code = v;\r
-        if ( v == 12 )\r
-        {\r
-          /* two byte operator */\r
-          p++;\r
-          if ( p >= limit )\r
-            goto Syntax_Error;\r
-\r
-          code = 0x100 | p[0];\r
-        }\r
-        code = code | parser->object_code;\r
-\r
-        for ( field = cff_field_handlers; field->kind; field++ )\r
-        {\r
-          if ( field->code == (FT_Int)code )\r
-          {\r
-            /* we found our field's handler; read it */\r
-            FT_Long   val;\r
-            FT_Byte*  q = (FT_Byte*)parser->object + field->offset;\r
-\r
-\r
-            /* check that we have enough arguments -- except for */\r
-            /* delta encoded arrays, which can be empty          */\r
-            if ( field->kind != cff_kind_delta && num_args < 1 )\r
-              goto Stack_Underflow;\r
-\r
-            switch ( field->kind )\r
-            {\r
-            case cff_kind_bool:\r
-            case cff_kind_string:\r
-            case cff_kind_num:\r
-              val = cff_parse_num( parser->stack );\r
-              goto Store_Number;\r
-\r
-            case cff_kind_fixed:\r
-              val = cff_parse_fixed( parser->stack );\r
-              goto Store_Number;\r
-\r
-            case cff_kind_fixed_thousand:\r
-              val = cff_parse_fixed_thousand( parser->stack );\r
-\r
-            Store_Number:\r
-              switch ( field->size )\r
-              {\r
-              case (8 / FT_CHAR_BIT):\r
-                *(FT_Byte*)q = (FT_Byte)val;\r
-                break;\r
-\r
-              case (16 / FT_CHAR_BIT):\r
-                *(FT_Short*)q = (FT_Short)val;\r
-                break;\r
-\r
-              case (32 / FT_CHAR_BIT):\r
-                *(FT_Int32*)q = (FT_Int)val;\r
-                break;\r
-\r
-              default:  /* for 64-bit systems */\r
-                *(FT_Long*)q = val;\r
-              }\r
-              break;\r
-\r
-            case cff_kind_delta:\r
-              {\r
-                FT_Byte*   qcount = (FT_Byte*)parser->object +\r
-                                      field->count_offset;\r
-\r
-                FT_Byte**  data = parser->stack;\r
-\r
-\r
-                if ( num_args > field->array_max )\r
-                  num_args = field->array_max;\r
-\r
-                /* store count */\r
-                *qcount = (FT_Byte)num_args;\r
-\r
-                val = 0;\r
-                while ( num_args > 0 )\r
-                {\r
-                  val += cff_parse_num( data++ );\r
-                  switch ( field->size )\r
-                  {\r
-                  case (8 / FT_CHAR_BIT):\r
-                    *(FT_Byte*)q = (FT_Byte)val;\r
-                    break;\r
-\r
-                  case (16 / FT_CHAR_BIT):\r
-                    *(FT_Short*)q = (FT_Short)val;\r
-                    break;\r
-\r
-                  case (32 / FT_CHAR_BIT):\r
-                    *(FT_Int32*)q = (FT_Int)val;\r
-                    break;\r
-\r
-                  default:  /* for 64-bit systems */\r
-                    *(FT_Long*)q = val;\r
-                  }\r
-\r
-                  q += field->size;\r
-                  num_args--;\r
-                }\r
-              }\r
-              break;\r
-\r
-            default:  /* callback */\r
-              error = field->reader( parser );\r
-              if ( error )\r
-                goto Exit;\r
-            }\r
-            goto Found;\r
-          }\r
-        }\r
-\r
-        /* this is an unknown operator, or it is unsupported; */\r
-        /* we will ignore it for now.                         */\r
-\r
-      Found:\r
-        /* clear stack */\r
-        parser->top = parser->stack;\r
-      }\r
-      p++;\r
-    }\r
-\r
-  Exit:\r
-    return error;\r
-\r
-  Stack_Overflow:\r
-    error = CFF_Err_Invalid_Argument;\r
-    goto Exit;\r
-\r
-  Stack_Underflow:\r
-    error = CFF_Err_Invalid_Argument;\r
-    goto Exit;\r
-\r
-  Syntax_Error:\r
-    error = CFF_Err_Invalid_Argument;\r
-    goto Exit;\r
-  }\r
-\r
-\r
-/* END */\r
+/***************************************************************************/
+/*                                                                         */
+/*  cffparse.c                                                             */
+/*                                                                         */
+/*    CFF token stream parser (body)                                       */
+/*                                                                         */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2007 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 "cfferrs.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
+
+
+  enum
+  {
+    cff_kind_none = 0,
+    cff_kind_num,
+    cff_kind_fixed,
+    cff_kind_fixed_thousand,
+    cff_kind_string,
+    cff_kind_bool,
+    cff_kind_delta,
+    cff_kind_callback,
+
+    cff_kind_max  /* do not remove */
+  };
+
+
+  /* now generate handlers for the most simple fields */
+  typedef FT_Error  (*CFF_Field_Reader)( CFF_Parser  parser );
+
+  typedef struct  CFF_Field_Handler_
+  {
+    int               kind;
+    int               code;
+    FT_UInt           offset;
+    FT_Byte           size;
+    CFF_Field_Reader  reader;
+    FT_UInt           array_max;
+    FT_UInt           count_offset;
+
+  } CFF_Field_Handler;
+
+
+  FT_LOCAL_DEF( void )
+  cff_parser_init( CFF_Parser  parser,
+                   FT_UInt     code,
+                   void*       object )
+  {
+    FT_MEM_ZERO( parser, sizeof ( *parser ) );
+
+    parser->top         = parser->stack;
+    parser->object_code = code;
+    parser->object      = object;
+  }
+
+
+  /* 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;
+  }
+
+
+  /* read a real */
+  static FT_Fixed
+  cff_parse_real( FT_Byte*  start,
+                  FT_Byte*  limit,
+                  FT_Int    power_ten )
+  {
+    FT_Byte*  p    = start;
+    FT_Long   num, divider, result, exponent;
+    FT_Int    sign = 0, exponent_sign = 0;
+    FT_UInt   nib;
+    FT_UInt   phase;
+
+
+    result  = 0;
+    num     = 0;
+    divider = 1;
+
+    /* 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 Bad;
+      }
+
+      /* Get the nibble. */
+      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 (;;)
+      {
+        /* 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 Bad;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        if ( divider < 10000000L )
+        {
+          num      = num * 10 + nib;
+          divider *= 10;
+        }
+      }
+
+    /* read exponent, if any */
+    if ( nib == 12 )
+    {
+      exponent_sign = 1;
+      nib           = 11;
+    }
+
+    if ( nib == 11 )
+    {
+      exponent = 0;
+
+      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 Bad;
+        }
+
+        /* Get the nibble. */
+        nib   = ( p[0] >> phase ) & 0xF;
+        phase = 4 - phase;
+        if ( nib >= 10 )
+          break;
+
+        exponent = exponent * 10 + nib;
+      }
+
+      if ( exponent_sign )
+        exponent = -exponent;
+
+      power_ten += (FT_Int)exponent;
+    }
+
+    /* 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++;
+    }
+
+    /* Move the integer part into the high 16 bits. */
+    result <<= 16;
+
+    /* Place the decimal part into the low 16 bits. */
+    if ( num )
+      result |= FT_DivFix( num, divider );
+
+    if ( sign )
+      result = -result;
+
+  Exit:
+    return result;
+
+  Bad:
+    result = 0;
+    goto Exit;
+  }
+
+
+  /* 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 ) >> 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 )
+                       : cff_parse_integer( d[0], d[1] ) << 16 );
+  }
+
+  /* read a floating point number, either integer or real, */
+  /* but return 1000 times the number read in.             */
+  static FT_Fixed
+  cff_parse_fixed_thousand( FT_Byte**  d )
+  {
+    return **d ==
+      30 ? cff_parse_real     ( d[0], d[1], 3 )
+         : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );
+  }
+
+  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_UShort*       upm    = &dict->units_per_em;
+    FT_Byte**        data   = parser->stack;
+    FT_Error         error;
+    FT_Fixed         temp;
+
+
+    error = CFF_Err_Stack_Underflow;
+
+    if ( parser->top >= parser->stack + 6 )
+    {
+      matrix->xx = cff_parse_fixed_thousand( data++ );
+      matrix->yx = cff_parse_fixed_thousand( data++ );
+      matrix->xy = cff_parse_fixed_thousand( data++ );
+      matrix->yy = cff_parse_fixed_thousand( data++ );
+      offset->x  = cff_parse_fixed_thousand( data++ );
+      offset->y  = cff_parse_fixed_thousand( data   );
+
+      temp = FT_ABS( matrix->yy );
+
+      *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );
+
+      if ( temp != 0x10000L )
+      {
+        matrix->xx = FT_DivFix( matrix->xx, temp );
+        matrix->yx = FT_DivFix( matrix->yx, temp );
+        matrix->xy = FT_DivFix( matrix->xy, temp );
+        matrix->yy = FT_DivFix( matrix->yy, temp );
+        offset->x  = FT_DivFix( offset->x,  temp );
+        offset->y  = FT_DivFix( offset->y,  temp );
+      }
+
+      /* note that the offsets must be expressed in integer font units */
+      offset->x >>= 16;
+      offset->y >>= 16;
+
+      error = CFF_Err_Ok;
+    }
+
+    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++ );
+      dict->cid_supplement = (FT_ULong)cff_parse_num( data );
+      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 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 )  \
+        },
+
+#define CFFCODE_TOPDICT  0x1000
+#define CFFCODE_PRIVATE  0x2000
+
+  static const CFF_Field_Handler  cff_field_handlers[] =
+  {
+
+#include "cfftoken.h"
+
+    { 0, 0, 0, 0, 0, 0, 0 }
+  };
+
+
+  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;
+
+
+    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 (;;)
+          {
+            if ( p >= limit )
+              goto Syntax_Error;
+            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 = cff_field_handlers; 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_thousand( parser->stack );
+
+            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 */