Sync with trunk r47367
[reactos.git] / lib / 3rdparty / freetype / src / cff / cffparse.c
index 41af6a3..01266a1 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    CFF token stream parser (body)                                       */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2007 by                         */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2007, 2008, 2009 by             */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
 #include <ft2build.h>
 #include "cffparse.h"
 #include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_DEBUG_H
 
 #include "cfferrs.h"
+#include "cffpic.h"
 
 
   /*************************************************************************/
 #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 )
+                   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;
   }
 
 
   }
 
 
+  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_Int    power_ten )
+                  FT_Long   power_ten,
+                  FT_Long*  scaling )
   {
-    FT_Byte*  p    = start;
-    FT_Long   num, divider, result, exponent;
-    FT_Int    sign = 0, exponent_sign = 0;
+    FT_Byte*  p = start;
     FT_UInt   nib;
     FT_UInt   phase;
 
+    FT_Long   result, number, rest, exponent;
+    FT_Int    sign = 0, exponent_sign = 0;
+    FT_Long   exponent_add, integer_length, fraction_length;
+
+
+    if ( scaling )
+      *scaling  = 0;
+
+    result = 0;
+
+    number   = 0;
+    rest     = 0;
+    exponent = 0;
 
-    result  = 0;
-    num     = 0;
-    divider = 1;
+    exponent_add    = 0;
+    integer_length  = 0;
+    fraction_length = 0;
 
-    /* first of all, read the integer part */
+    FT_UNUSED( rest );
+
+    /* First of all, read the integer part. */
     phase = 4;
 
     for (;;)
 
         /* Make sure we don't read past the end. */
         if ( p >= limit )
-          goto Bad;
+          goto Exit;
       }
 
       /* Get the nibble. */
       else if ( nib > 9 )
         break;
       else
-        result = result * 10 + nib;
+      {
+        /* 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 decimal part, if any */
+    /* Read fraction part, if any. */
     if ( nib == 0xa )
       for (;;)
       {
 
           /* Make sure we don't read past the end. */
           if ( p >= limit )
-            goto Bad;
+            goto Exit;
         }
 
         /* Get the nibble. */
         if ( nib >= 10 )
           break;
 
-        if ( divider < 10000000L )
+        /* 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 )
         {
-          num      = num * 10 + nib;
-          divider *= 10;
+          fraction_length++;
+          number = number * 10 + nib;
         }
       }
 
-    /* read exponent, if any */
+    /* Read exponent, if any. */
     if ( nib == 12 )
     {
       exponent_sign = 1;
 
     if ( nib == 11 )
     {
-      exponent = 0;
-
       for (;;)
       {
-        /* If we entered this iteration with phase == 4, we need */
-        /* to read a new byte.                                   */
+        /* 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;
+            goto Exit;
         }
 
         /* Get the nibble. */
           break;
 
         exponent = exponent * 10 + nib;
+
+        /* Arbitrarily limit exponent. */
+        if ( exponent > 1000 )
+          goto Exit;
       }
 
       if ( exponent_sign )
         exponent = -exponent;
-
-      power_ten += (FT_Int)exponent;
     }
 
-    /* raise to power of ten if needed */
-    while ( power_ten > 0 )
+    /* We don't check `power_ten' and `exponent_add'. */
+    exponent += power_ten + exponent_add;
+
+    if ( scaling )
     {
-      result = result * 10;
-      num    = num * 10;
+      /* Only use `fraction_length'. */
+      fraction_length += integer_length;
+      exponent        += integer_length;
 
-      power_ten--;
-    }
+      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;
 
-    while ( power_ten < 0 )
-    {
-      result  = result / 10;
-      divider = divider * 10;
 
-      power_ten++;
+            /* 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;
+      }
+
+      /* 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];
 
-    /* Move the integer part into the high 16 bits. */
-    result <<= 16;
+        if ( number > 0x7FFFL )
+          goto Exit;
 
-    /* Place the decimal part into the low 16 bits. */
-    if ( num )
-      result |= FT_DivFix( num, divider );
+        result = number << 16;
+      }
+    }
 
     if ( sign )
       result = -result;
 
   Exit:
     return result;
-
-  Bad:
-    result = 0;
-    goto Exit;
   }
 
 
   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] ) );
+    return **d == 30 ? ( cff_parse_real( d[0], d[1], 0, NULL ) >> 16 )
+                     :   cff_parse_integer( d[0], d[1] );
   }
 
 
   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 );
+    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 1000 times the number read in.             */
+  /* 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_thousand( FT_Byte**  d )
+  cff_parse_fixed_dynamic( FT_Byte**  d,
+                           FT_Long*   scaling )
   {
-    return **d ==
-      30 ? cff_parse_real     ( d[0], d[1], 3 )
-         : (FT_Fixed)FT_MulFix( cff_parse_integer( d[0], d[1] ) << 16, 1000 );
+    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_UShort*       upm    = &dict->units_per_em;
+    FT_ULong*        upm    = &dict->units_per_em;
     FT_Byte**        data   = parser->stack;
-    FT_Error         error;
-    FT_Fixed         temp;
+    FT_Error         error  = CFF_Err_Stack_Underflow;
 
 
-    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   );
+      FT_Long  scaling;
 
-      temp = FT_ABS( matrix->yy );
 
-      *upm = (FT_UShort)FT_DivFix( 0x10000L, FT_DivFix( temp, 1000 ) );
+      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.                                             */
 
-      if ( temp != 0x10000L )
+      matrix->xx = cff_parse_fixed_dynamic( data++, &scaling );
+
+      scaling = -scaling;
+
+      if ( scaling < 0 || scaling > 9 )
       {
-        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 );
+        /* 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;
       }
 
-      /* note that the offsets must be expressed in integer font units */
-      offset->x >>= 16;
-      offset->y >>= 16;
+      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 );
 
-      error = CFF_Err_Ok;
+      *upm = power_tens[scaling];
     }
 
+  Exit:
     return error;
   }
 
     {
       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 );
+      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;
     }
 
 #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,           \
           FT_FIELD_OFFSET( num_ ## name )  \
         },
 
-#define CFFCODE_TOPDICT  0x1000
-#define CFFCODE_PRIVATE  0x2000
-
   static const CFF_Field_Handler  cff_field_handlers[] =
   {
 
   };
 
 
+#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 FT_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_Byte*    p       = start;
+    FT_Error    error   = CFF_Err_Ok;
+    FT_Library  library = parser->library;
+    FT_UNUSED(library);
 
 
     parser->top    = parser->stack;
           p++;
           for (;;)
           {
+            /* An unterminated floating point number at the */
+            /* end of a dictionary is invalid but harmless. */
             if ( p >= limit )
-              goto Syntax_Error;
+              goto Exit;
             v = p[0] >> 4;
             if ( v == 15 )
               break;
         }
         code = code | parser->object_code;
 
-        for ( field = cff_field_handlers; field->kind; field++ )
+        for ( field = FT_CFF_FIELD_HANDLERS_GET; field->kind; field++ )
         {
           if ( field->code == (FT_Int)code )
           {
               goto Store_Number;
 
             case cff_kind_fixed_thousand:
-              val = cff_parse_fixed_thousand( parser->stack );
+              val = cff_parse_fixed_scaled( parser->stack, 3 );
 
             Store_Number:
               switch ( field->size )