Commit 3c5a3e45c959de4b17daecb63d3aab92a6741256

David Turner 2002-05-01T08:40:32

* src/sfnt/ttcmap0.c (tt_cmap4_validate): fixed over-restrictive validation test. the charmap validator now accepts overlapping ranges in format 4 charmaps. * src/sfnt/ttcmap0.c (tt_cmap4_char_index): switched to a binary search algorithm. Certain fonts contain more than 170 distinct segments !!

diff --git a/src/sfnt/ttcmap0.c b/src/sfnt/ttcmap0.c
index be318c1..b464a5b 100644
--- a/src/sfnt/ttcmap0.c
+++ b/src/sfnt/ttcmap0.c
@@ -638,7 +638,7 @@
     offsets   = deltas  + num_segs * 2;
     glyph_ids = offsets + num_segs * 2;
 
-    if ( glyph_ids >= table + length )
+    if ( glyph_ids > table + length )
       FT_INVALID_TOO_SHORT;
 
     /* check last segment, its end count must be FFFF */
@@ -670,8 +670,15 @@
         if ( start > end )
           FT_INVALID_DATA;
 
-        if ( n > 0 && start <= last )
-          FT_INVALID_DATA;
+        /* this test should be performed at default validation level   */
+        /* unfortunately, some popular asian fonts present overlapping */
+        /* ranges in their charmaps..                                  */
+        /*                                                             */
+        if ( valid->level >= FT_VALIDATE_TIGHT )
+        {
+          if ( n > 0 && start <= last )
+            FT_INVALID_DATA;
+        }
 
         if ( offset )
         {
@@ -718,49 +725,108 @@
 
     if ( char_code < 0x10000UL )
     {
-      FT_Byte*  p;
-      FT_Byte*  q;
       FT_UInt   idx, num_segs2;
       FT_Int    delta;
-      FT_UInt   n, code = (FT_UInt)char_code;
+      FT_UInt   code = (FT_UInt)char_code;
+      FT_Byte*  p;
 
 
       p         = table + 6;
       num_segs2 = TT_PEEK_USHORT( p ) & -2;  /* be paranoid! */
 
-      p = table + 14;               /* ends table   */
-      q = table + 16 + num_segs2;   /* starts table */
-
-      for ( n = 0; n < num_segs2; n += 2 )
+#if 1
+      /* some fonts have more than 170 segments in their charmaps !! */
+      /* we changed this function to use a more efficient binary     */
+      /* search to boost its performance                             */
       {
-        FT_UInt  end   = TT_NEXT_USHORT( p );
-        FT_UInt  start = TT_NEXT_USHORT( q );
-        FT_UInt  offset;
+        FT_UInt   min = 0;
+        FT_UInt   max = num_segs2 >> 1;
+        FT_UInt   mid, start, end, offset;
+        
 
+        while ( min < max )
+        {
+          mid   = ( min + max ) >> 1;
+          p     = table + 14 + mid*2;
+          end   = TT_NEXT_USHORT( p ); 
+          p    += num_segs2;
+          start = TT_PEEK_USHORT( p);
+          
+          if ( code < start )
+            max = mid;
+          
+          else if ( code > end )
+            min = mid+1;
+          
+          else
+          {
+            /* we found the segment */
+            idx = code;
+            
+            p += num_segs2;
+            delta = TT_PEEK_SHORT( p );
+            
+            p += num_segs2;
+            offset = TT_PEEK_USHORT( p );
+            
+            if ( offset != 0 )
+            {
+              p  += offset + 2*( idx - start );
+              idx = TT_PEEK_USHORT( p );
+            }
+            
+            if ( idx != 0 )
+              result = (FT_UInt)( idx + delta ) & 0xFFFU;
+            
+            goto Exit;
+          }
+        }
+      }
 
-        if ( code < start )
-          break;
+#else /* 0 - old code */
+      {
+        FT_UInt   n;
+        FT_Byte*  q;
 
-        if ( code <= end )
-        {
-          idx = code;
 
-          p = q + num_segs2 - 2;
-          delta = TT_PEEK_SHORT( p );
-          p += num_segs2;
-          offset = TT_PEEK_USHORT( p );
+        p = table + 14;               /* ends table   */
+        q = table + 16 + num_segs2;   /* starts table */
 
-          if ( offset != 0 )
+        
+        for ( n = 0; n < num_segs2; n += 2 )
+        {
+          FT_UInt  end   = TT_NEXT_USHORT( p );
+          FT_UInt  start = TT_NEXT_USHORT( q );
+          FT_UInt  offset;
+  
+  
+          if ( code < start )
+            break;
+  
+          if ( code <= end )
           {
-            p  += offset + 2 * ( idx - start );
-            idx = TT_PEEK_USHORT( p );
+            idx = code;
+  
+            p = q + num_segs2 - 2;
+            delta = TT_PEEK_SHORT( p );
+            p += num_segs2;
+            offset = TT_PEEK_USHORT( p );
+  
+            if ( offset != 0 )
+            {
+              p  += offset + 2 * ( idx - start );
+              idx = TT_PEEK_USHORT( p );
+            }
+  
+            if ( idx != 0 )
+              result = (FT_UInt)( idx + delta ) & 0xFFFFU;
           }
-
-          if ( idx != 0 )
-            result = (FT_UInt)( idx + delta ) & 0xFFFFU;
         }
       }
+#endif /* 0 */
     }
+    
+  Exit:
     return result;
   }