Commit bd4b8976a36fd49dc2e04516aa76687c784c4c3a

Werner Lemberg 2015-12-20T19:36:04

[type1, psaux] Handle large values of num_subrs correctly (#46692). We now use a hash to map from subr indices to array elements holding the subroutines, if necessary. * include/freetype/internal/t1types.h: Include FT_INTERNAL_HASH_H. (T1_FontRec): Add `subrs_hash' field. * include/freetype/internal/psaux.h: Include FT_INTERNAL_HASH_H. (T1_DecoderRec): Add `subrs_hash' field. * src/type1/t1load.h (T1_LoaderRec): Add `subrs_hash' field. * src/type1/t1driver.c: Include FT_INTERNAL_HASH_H. (t1_ps_get_font_value) [PS_DICT_SUBR]: Look up hash if necessary. * src/type1/t1load.c: Include FT_INTERNAL_HASH_H. (parse_subrs): Use hash for subr indices that exceed the allocated number of subr slots. (t1_init_loader): Remove unnecessary code. (t1_done_loader, T1_Open_Face): Updated. * src/type1/t1gload.c (T1_Compute_Max_Advance, T1_Get_Advances, T1_Load_Glyph): Updated. * src/type1/t1objs.c (T1_Face_Done): Updated. * src/psaux/t1decode.c: Include FT_INTERNAL_HASH_H. (t1_decoder_parse_charstrings) [op_callsubr]: Look up hash if necessary. * src/cid/cidgload.c (cid_load_glyph): Updated.

diff --git a/ChangeLog b/ChangeLog
index 7e62e2e..fa32735 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,40 @@
 2015-12-20  Werner Lemberg  <wl@gnu.org>
 
+	[type1, psaux] Handle large values of num_subrs correctly (#46692).
+
+	We now use a hash to map from subr indices to array elements holding
+	the subroutines, if necessary.
+
+	* include/freetype/internal/t1types.h: Include FT_INTERNAL_HASH_H.
+	(T1_FontRec): Add `subrs_hash' field.
+
+	* include/freetype/internal/psaux.h: Include FT_INTERNAL_HASH_H.
+	(T1_DecoderRec): Add `subrs_hash' field.
+
+	* src/type1/t1load.h (T1_LoaderRec): Add `subrs_hash' field.
+
+	* src/type1/t1driver.c: Include FT_INTERNAL_HASH_H.
+	(t1_ps_get_font_value) [PS_DICT_SUBR]: Look up hash if necessary.
+
+	* src/type1/t1load.c: Include FT_INTERNAL_HASH_H.
+	(parse_subrs): Use hash for subr indices that exceed the allocated
+	number of subr slots.
+	(t1_init_loader): Remove unnecessary code.
+	(t1_done_loader, T1_Open_Face): Updated.
+
+	* src/type1/t1gload.c (T1_Compute_Max_Advance, T1_Get_Advances,
+	T1_Load_Glyph): Updated.
+
+	* src/type1/t1objs.c (T1_Face_Done): Updated.
+
+	* src/psaux/t1decode.c: Include FT_INTERNAL_HASH_H.
+	(t1_decoder_parse_charstrings) [op_callsubr]: Look up hash if
+	necessary.
+
+	* src/cid/cidgload.c (cid_load_glyph): Updated.
+
+2015-12-20  Werner Lemberg  <wl@gnu.org>
+
 	[base] Thinko: Remove free function pointer.
 
 	We don't copy keys or values while hashing.
diff --git a/include/freetype/internal/psaux.h b/include/freetype/internal/psaux.h
index 1c5f784..63aac88 100644
--- a/include/freetype/internal/psaux.h
+++ b/include/freetype/internal/psaux.h
@@ -24,6 +24,7 @@
 #include <ft2build.h>
 #include FT_INTERNAL_OBJECTS_H
 #include FT_INTERNAL_TYPE1_TYPES_H
+#include FT_INTERNAL_HASH_H
 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
 
 
@@ -678,6 +679,7 @@ FT_BEGIN_HEADER
     FT_Int               num_subrs;
     FT_Byte**            subrs;
     FT_UInt*             subrs_len;    /* array of subrs length (optional) */
+    FT_Hash              subrs_hash;   /* used if `num_subrs' was massaged */
 
     FT_Matrix            font_matrix;
     FT_Vector            font_offset;
diff --git a/include/freetype/internal/t1types.h b/include/freetype/internal/t1types.h
index 029acc4..a35a4fd 100644
--- a/include/freetype/internal/t1types.h
+++ b/include/freetype/internal/t1types.h
@@ -25,6 +25,7 @@
 #include FT_TYPE1_TABLES_H
 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
 #include FT_INTERNAL_SERVICE_H
+#include FT_INTERNAL_HASH_H
 #include FT_SERVICE_POSTSCRIPT_CMAPS_H
 
 
@@ -107,6 +108,7 @@ FT_BEGIN_HEADER
     FT_Int           num_subrs;
     FT_Byte**        subrs;
     FT_UInt*         subrs_len;
+    FT_Hash          subrs_hash;
 
     FT_Int           num_glyphs;
     FT_String**      glyph_names;       /* array of glyph names       */
diff --git a/src/cid/cidgload.c b/src/cid/cidgload.c
index d402f8e..99962db 100644
--- a/src/cid/cidgload.c
+++ b/src/cid/cidgload.c
@@ -142,9 +142,10 @@
 
 
       /* Set up subrs */
-      decoder->num_subrs = cid_subrs->num_subrs;
-      decoder->subrs     = cid_subrs->code;
-      decoder->subrs_len = 0;
+      decoder->num_subrs  = cid_subrs->num_subrs;
+      decoder->subrs      = cid_subrs->code;
+      decoder->subrs_len  = 0;
+      decoder->subrs_hash = NULL;
 
       /* Set up font matrix */
       dict                 = cid->font_dicts + fd_select;
diff --git a/src/psaux/t1decode.c b/src/psaux/t1decode.c
index 5811fcb..9e2d277 100644
--- a/src/psaux/t1decode.c
+++ b/src/psaux/t1decode.c
@@ -20,6 +20,7 @@
 #include FT_INTERNAL_CALC_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_POSTSCRIPT_HINTS_H
+#include FT_INTERNAL_HASH_H
 #include FT_OUTLINE_H
 
 #include "t1decode.h"
@@ -1348,6 +1349,19 @@
             FT_TRACE4(( " callsubr" ));
 
             idx = Fix2Int( top[0] );
+
+            if ( decoder->subrs_hash )
+            {
+              size_t*  val = ft_hash_num_lookup( idx,
+                                                 decoder->subrs_hash );
+
+
+              if ( val )
+                idx = *val;
+              else
+                idx = -1;
+            }
+
             if ( idx < 0 || idx >= decoder->num_subrs )
             {
               FT_ERROR(( "t1_decoder_parse_charstrings:"
diff --git a/src/type1/t1driver.c b/src/type1/t1driver.c
index 716dd55..e1e2852 100644
--- a/src/type1/t1driver.c
+++ b/src/type1/t1driver.c
@@ -29,6 +29,7 @@
 
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_HASH_H
 
 #include FT_SERVICE_MULTIPLE_MASTERS_H
 #include FT_SERVICE_GLYPH_DICT_H
@@ -329,13 +330,36 @@
       break;
 
     case PS_DICT_SUBR:
-      if ( idx < (FT_UInt)type1->num_subrs )
       {
-        retval = type1->subrs_len[idx] + 1;
-        if ( value && value_len >= retval )
+        FT_Bool  ok = 0;
+
+
+        if ( type1->subrs_hash )
         {
-          ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 );
-          ((FT_Char *)value)[retval - 1] = (FT_Char)'\0';
+          /* convert subr index to array index */
+          size_t*  val = ft_hash_num_lookup( idx, type1->subrs_hash );
+
+
+          if ( val )
+          {
+            idx = *val;
+            ok  = 1;
+          }
+        }
+        else
+        {
+          if ( idx < (FT_UInt)type1->num_subrs )
+            ok = 1;
+        }
+
+        if ( ok )
+        {
+          retval = type1->subrs_len[idx] + 1;
+          if ( value && value_len >= retval )
+          {
+            ft_memcpy( value, (void *)( type1->subrs[idx] ), retval - 1 );
+            ((FT_Char *)value)[retval - 1] = (FT_Char)'\0';
+          }
         }
       }
       break;
diff --git a/src/type1/t1gload.c b/src/type1/t1gload.c
index 85ada2e..81ea226 100644
--- a/src/type1/t1gload.c
+++ b/src/type1/t1gload.c
@@ -183,6 +183,7 @@
     decoder.num_subrs     = type1->num_subrs;
     decoder.subrs         = type1->subrs;
     decoder.subrs_len     = type1->subrs_len;
+    decoder.subrs_hash    = type1->subrs_hash;
 
     decoder.buildchar     = face->buildchar;
     decoder.len_buildchar = face->len_buildchar;
@@ -245,9 +246,10 @@
     decoder.builder.metrics_only = 1;
     decoder.builder.load_points  = 0;
 
-    decoder.num_subrs = type1->num_subrs;
-    decoder.subrs     = type1->subrs;
-    decoder.subrs_len = type1->subrs_len;
+    decoder.num_subrs  = type1->num_subrs;
+    decoder.subrs      = type1->subrs;
+    decoder.subrs_len  = type1->subrs_len;
+    decoder.subrs_hash = type1->subrs_hash;
 
     decoder.buildchar     = face->buildchar;
     decoder.len_buildchar = face->len_buildchar;
@@ -346,6 +348,7 @@
     decoder.num_subrs     = type1->num_subrs;
     decoder.subrs         = type1->subrs;
     decoder.subrs_len     = type1->subrs_len;
+    decoder.subrs_hash    = type1->subrs_hash;
 
     decoder.buildchar     = face->buildchar;
     decoder.len_buildchar = face->len_buildchar;
diff --git a/src/type1/t1load.c b/src/type1/t1load.c
index 4ce1e35..3fb3cd2 100644
--- a/src/type1/t1load.c
+++ b/src/type1/t1load.c
@@ -66,6 +66,7 @@
 #include FT_MULTIPLE_MASTERS_H
 #include FT_INTERNAL_TYPE1_TYPES_H
 #include FT_INTERNAL_CALC_H
+#include FT_INTERNAL_HASH_H
 
 #include "t1load.h"
 #include "t1errors.h"
@@ -1404,6 +1405,8 @@
     FT_Memory  memory = parser->root.memory;
     FT_Error   error;
     FT_Int     num_subrs;
+    FT_Int     count;
+    FT_Hash    hash = NULL;
 
     PSAux_Service  psaux = (PSAux_Service)face->psaux;
 
@@ -1432,11 +1435,36 @@
     /* we certainly need more than 8 bytes per subroutine */
     if ( num_subrs > ( parser->root.limit - parser->root.cursor ) >> 3 )
     {
+      /*
+       * There are two possibilities.  Either the font contains an invalid
+       * value for `num_subrs', or we have a subsetted font where the
+       * subroutine indices are not adjusted, e.g.
+       *
+       *   /Subrs 812 array
+       *     dup 0 { ... } NP
+       *     dup 51 { ... } NP
+       *     dup 681 { ... } NP
+       *   ND
+       *
+       * In both cases, we use a number hash that maps from subr indices to
+       * actual array elements.
+       */
+
       FT_TRACE0(( "parse_subrs: adjusting number of subroutines"
                   " (from %d to %d)\n",
                   num_subrs,
                   ( parser->root.limit - parser->root.cursor ) >> 3 ));
       num_subrs = ( parser->root.limit - parser->root.cursor ) >> 3;
+
+      if ( !hash )
+      {
+        if ( FT_NEW( hash ) )
+          goto Fail;
+
+        error = ft_hash_init( hash, 1, memory );
+        if ( error )
+          goto Fail;
+      }
     }
 
     /* position the parser right before the `dup' of the first subr */
@@ -1458,7 +1486,7 @@
     /*                         */
     /*   `index' + binary data */
     /*                         */
-    for (;;)
+    for ( count = 0; ; count++ )
     {
       FT_Long   idx;
       FT_ULong  size;
@@ -1494,6 +1522,14 @@
         T1_Skip_Spaces  ( parser );
       }
 
+      /* if we use a hash, the subrs index is the key, and a running */
+      /* counter specified for `T1_Add_Table' acts as the value      */
+      if ( hash )
+      {
+        ft_hash_num_insert( idx, count, hash, memory );
+        idx = count;
+      }
+
       /* with synthetic fonts it is possible we get here twice */
       if ( loader->num_subrs )
         continue;
@@ -1534,7 +1570,10 @@
     }
 
     if ( !loader->num_subrs )
-      loader->num_subrs = num_subrs;
+    {
+      loader->num_subrs  = num_subrs;
+      loader->subrs_hash = hash;
+    }
 
     return;
 
@@ -2105,17 +2144,6 @@
     FT_UNUSED( face );
 
     FT_MEM_ZERO( loader, sizeof ( *loader ) );
-    loader->num_glyphs = 0;
-    loader->num_chars  = 0;
-
-    /* initialize the tables -- simply set their `init' field to 0 */
-    loader->encoding_table.init  = 0;
-    loader->charstrings.init     = 0;
-    loader->glyph_names.init     = 0;
-    loader->subrs.init           = 0;
-    loader->swap_table.init      = 0;
-    loader->fontdata             = 0;
-    loader->keywords_encountered = 0;
   }
 
 
@@ -2123,6 +2151,7 @@
   t1_done_loader( T1_Loader  loader )
   {
     T1_Parser  parser = &loader->parser;
+    FT_Memory  memory = parser->root.memory;
 
 
     /* finalize tables */
@@ -2132,6 +2161,10 @@
     T1_Release_Table( &loader->swap_table );
     T1_Release_Table( &loader->subrs );
 
+    /* finalize hash */
+    ft_hash_free( loader->subrs_hash, memory );
+    FT_FREE( loader->subrs_hash );
+
     /* finalize parser */
     T1_Finalize_Parser( parser );
   }
@@ -2248,11 +2281,15 @@
 
     if ( loader.subrs.init )
     {
-      loader.subrs.init  = 0;
       type1->num_subrs   = loader.num_subrs;
       type1->subrs_block = loader.subrs.block;
       type1->subrs       = loader.subrs.elements;
       type1->subrs_len   = loader.subrs.lengths;
+      type1->subrs_hash  = loader.subrs_hash;
+
+      /* prevent `t1_done_loader' from freeing the propagated data */
+      loader.subrs.init = 0;
+      loader.subrs_hash = NULL;
     }
 
     if ( !IS_INCREMENTAL )
diff --git a/src/type1/t1load.h b/src/type1/t1load.h
index de422e7..58b1eee 100644
--- a/src/type1/t1load.h
+++ b/src/type1/t1load.h
@@ -46,6 +46,7 @@ FT_BEGIN_HEADER
 
     FT_Int        num_subrs;
     PS_TableRec   subrs;
+    FT_Hash       subrs_hash;
     FT_Bool       fontdata;
 
     FT_UInt       keywords_encountered; /* T1_LOADER_ENCOUNTERED_XXX */
diff --git a/src/type1/t1objs.c b/src/type1/t1objs.c
index d921063..7c92256 100644
--- a/src/type1/t1objs.c
+++ b/src/type1/t1objs.c
@@ -247,6 +247,9 @@
     FT_FREE( type1->subrs );
     FT_FREE( type1->subrs_len );
 
+    ft_hash_free( type1->subrs_hash, memory );
+    FT_FREE( type1->subrs_hash );
+
     FT_FREE( type1->subrs_block );
     FT_FREE( type1->charstrings_block );
     FT_FREE( type1->glyph_names_block );