Commit 7acd73fd6a6f34a2d40dfcbe47d18f5b5cb81888

David Turner 2002-07-11T23:41:14

* src/sfnt/ttload.c, src/sfnt/ttload.h, src/sfnt/ttdriver.c: changing the SFNT loader to check for SFNT-based font files differently. We now ignore the range "helper" fields and check the "head" table's magic number instead.

diff --git a/ChangeLog b/ChangeLog
index deceb2f..57c05ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,17 @@
 2002-07-11  David Turner  <david@freetype.org>
 
+    * src/sfnt/ttload.c, src/sfnt/ttload.h, src/sfnt/ttdriver.c: changing
+    the SFNT loader to check for SFNT-based font files differently. We now
+    ignore the range "helper" fields and check the "head" table's magic
+    number instead.
+
+    * src/base/ftobject.c, src/base/fthash.c: updated object sub-system and
+    dynamic hash table implementation (still experimental, don't use)
+
     * include/freetype/t1tables.h, include/freetype/internal/psaux.h,
     src/psaux/psobjs.c, src/type1/t1load.c, src/type1/t1tokens.h:
     fixing a bug in the Type 1 loader that prevented valid font bounding
-    boxes to be loaded from multiple master fonts. 
+    boxes to be loaded from multiple master fonts.
 
 2002-07-10  David Turner  <david@freetype.org>
 
diff --git a/include/freetype/internal/tttypes.h b/include/freetype/internal/tttypes.h
index b440aa5..ec3df9d 100644
--- a/include/freetype/internal/tttypes.h
+++ b/include/freetype/internal/tttypes.h
@@ -100,6 +100,8 @@ FT_BEGIN_HEADER
     FT_UShort  entry_selector;
     FT_UShort  range_shift;
 
+    FT_ULong   offset;  /* not in file */
+
   } SFNT_HeaderRec, *SFNT_Header;
 
 
diff --git a/src/base/fthash.c b/src/base/fthash.c
index 0369224..c42b1dc 100644
--- a/src/base/fthash.c
+++ b/src/base/fthash.c
@@ -197,7 +197,7 @@
 
     num_buckets = ( table->p + table->mask + 1) ;
 
-    if ( ++ table->slack > num_buckets*FT_HASH_SUB_LOAD )
+    if ( ++ table->slack > (FT_Long)num_buckets*FT_HASH_SUB_LOAD )
     {
       FT_UInt       p         = table->p;
       FT_UInt       mask      = table->mask;
diff --git a/src/base/ftobject.c b/src/base/ftobject.c
index f51e6c0..413384c 100644
--- a/src/base/ftobject.c
+++ b/src/base/ftobject.c
@@ -312,6 +312,7 @@
 
       return (clazz == NULL);
     }
+    return 0;
   }
 
 
diff --git a/src/sfnt/sfdriver.c b/src/sfnt/sfdriver.c
index f0316e2..6411d91 100644
--- a/src/sfnt/sfdriver.c
+++ b/src/sfnt/sfdriver.c
@@ -251,7 +251,7 @@
     SFNT_Get_Interface,
 
     TT_Load_Any,
-    TT_Load_SFNT_HeaderRec,
+    TT_Load_SFNT_Header,
     TT_Load_Directory,
 
     TT_Load_Header,
diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c
index e3dada2..4c05958 100644
--- a/src/sfnt/ttload.c
+++ b/src/sfnt/ttload.c
@@ -135,6 +135,91 @@
   }
 
 
+ /* in theory, we should check the values of `search_range',               */
+ /* `entry_selector' and `range_shift' to detect non-SFNT based files      */
+ /* whose header might also start with 0x100000L (yes, these exist).       */
+ /*                                                                        */
+ /* Very unfortunately, many TrueType fonts don't have these fields        */
+ /* set correctly and we must ignore them to support them. An alternative  */
+ /* way to check the font file is thus to:                                 */
+ /*                                                                        */
+ /* - check that `num_tables' is valid                                     */
+ /* - look for a "head" table, check its size, and parse it to             */
+ /*   see if its "magic" field is correctly set to                         */
+ /*                                                                        */
+ /* Voila, here comes robust though tolerant font format checking :-)      */
+ /*                                                                        */
+  static FT_Error
+  sfnt_dir_check( FT_Stream    stream,
+                  FT_ULong     offset,
+                  FT_UInt      num_tables )
+  {
+    FT_Error  error;
+    FT_UInt   nn;
+
+    static const FT_Frame_Field  sfnt_dir_entry_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TT_TableRec
+
+      FT_FRAME_START( 16 ),
+        FT_FRAME_ULONG( Tag ),
+        FT_FRAME_ULONG( CheckSum ),
+        FT_FRAME_ULONG( Offset ),
+        FT_FRAME_ULONG( Length ),
+      FT_FRAME_END
+    };
+
+    /* if 'num_tables' is 0, read the table count from the file */
+    if ( num_tables == 0 )
+    {
+      FT_ULong  format_tag;
+
+      if ( FT_STREAM_SEEK( offset )     ||
+           FT_READ_ULONG ( format_tag ) ||
+           FT_READ_USHORT( num_tables ) ||
+           FT_STREAM_SKIP( 6 )          )
+        goto Bad_Format;
+
+      if ( offset + 12 + num_tables*16 > stream->size )
+        goto Bad_Format;
+    }
+    else if ( FT_STREAM_SEEK( offset + 12 ) )
+      goto Bad_Format;
+
+    for ( nn = 0; nn < num_tables; nn++ )
+    {
+      TT_TableRec  table;
+
+      if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) )
+        goto Bad_Format;
+
+      if ( offset + table.Offset + table.Length > stream->size )
+        goto Bad_Format;
+
+      if ( table.Tag == TTAG_head )
+      {
+        FT_UInt32  magic;
+
+        if ( table.Length != 0x36                         ||
+             FT_STREAM_SEEK( offset + table.Offset + 12 ) ||
+             FT_READ_ULONG( magic )                       ||
+             magic != 0x5F0F3CF5U                         )
+          goto Bad_Format;
+
+        if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) )
+          goto Bad_Format;
+      }
+    }
+
+  Exit:
+    return  error;
+
+  Bad_Format:
+    error = FT_Err_Unknown_File_Format;
+    goto Exit;
+  }
+
   /*************************************************************************/
   /*                                                                       */
   /* <Function>                                                            */
@@ -166,16 +251,16 @@
   /*    values of `search_range', `entry_selector', and `range_shift'.     */
   /*                                                                       */
   FT_LOCAL_DEF( FT_Error )
-  TT_Load_SFNT_HeaderRec( TT_Face       face,
-                          FT_Stream     stream,
-                          FT_Long       face_index,
-                          SFNT_Header   sfnt )
+  TT_Load_SFNT_Header( TT_Face       face,
+                       FT_Stream     stream,
+                       FT_Long       face_index,
+                       SFNT_Header   sfnt )
   {
     FT_Error   error;
-    FT_ULong   format_tag;
+    FT_ULong   format_tag, offset;
     FT_Memory  memory = stream->memory;
 
-    const FT_Frame_Field  sfnt_header_fields[] =
+    static const FT_Frame_Field  sfnt_header_fields[] =
     {
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  SFNT_HeaderRec
@@ -188,7 +273,7 @@
       FT_FRAME_END
     };
 
-    const FT_Frame_Field  ttc_header_fields[] =
+    static const FT_Frame_Field  ttc_header_fields[] =
     {
 #undef  FT_STRUCTURE
 #define FT_STRUCTURE  TTC_HeaderRec
@@ -200,7 +285,7 @@
     };
 
 
-    FT_TRACE2(( "TT_Load_SFNT_HeaderRec: %08p, %ld\n",
+    FT_TRACE2(( "TT_Load_SFNT_Header: %08p, %ld\n",
                 face, face_index ));
 
     face->ttc_header.tag     = 0;
@@ -213,6 +298,8 @@
     /* file is a TrueType collection, otherwise it can be any other     */
     /* kind of font.                                                    */
     /*                                                                  */
+    offset = FT_STREAM_POS();
+
     if ( FT_READ_ULONG( format_tag ) )
       goto Exit;
 
@@ -221,7 +308,7 @@
       FT_Int  n;
 
 
-      FT_TRACE3(( "TT_Load_SFNT_HeaderRec: file is a collection\n" ));
+      FT_TRACE3(( "TT_Load_SFNT_Header: file is a collection\n" ));
 
       /* It is a TrueType collection, i.e. a file containing several */
       /* font files.  Read the font directory now                    */
@@ -246,32 +333,26 @@
       }
 
       /* seek to the appropriate TrueType file, then read tag */
-      if ( FT_STREAM_SEEK( face->ttc_header.offsets[face_index] ) ||
+      offset = face->ttc_header.offsets[ face_index ];
+
+      if ( FT_STREAM_SEEK( offset ) ||
            FT_READ_LONG( format_tag )                             )
         goto Exit;
     }
 
     /* the format tag was read, now check the rest of the header */
     sfnt->format_tag = format_tag;
+    sfnt->offset     = offset;
+
     if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
       goto Exit;
 
-    /* now, check the values of `num_tables', `seach_range', etc. */
+    /* now check the sfnt directory */
+    error = sfnt_dir_check( stream, offset, sfnt->num_tables );
+    if ( error )
     {
-      FT_UInt   num_tables     = sfnt->num_tables;
-      FT_ULong  entry_selector = 1L << sfnt->entry_selector;
-
-
-      /* IMPORTANT: Many fonts have an incorrect `search_range' value, so */
-      /*            we only check the `entry_selector' correctness here.  */
-      /*                                                                  */
-      if ( num_tables == 0                  ||
-           entry_selector > num_tables      ||
-           entry_selector * 2 <= num_tables )
-      {
-        FT_TRACE2(( "TT_Load_SFNT_HeaderRec: file is not SFNT!\n" ));
-        error = SFNT_Err_Unknown_File_Format;
-      }
+      FT_TRACE2(( "TT_Load_SFNT_Header: file is not SFNT!\n" ));
+      error = SFNT_Err_Unknown_File_Format;
     }
 
   Exit:
@@ -322,7 +403,8 @@
     if ( FT_NEW_ARRAY( face->dir_tables, face->num_tables ) )
       goto Exit;
 
-    if ( FT_FRAME_ENTER( face->num_tables * 16L ) )
+    if ( FT_STREAM_SEEK( sfnt->offset + 12 )      ||
+         FT_FRAME_ENTER( face->num_tables * 16L ) )
       goto Exit;
 
     entry = face->dir_tables;
diff --git a/src/sfnt/ttload.h b/src/sfnt/ttload.h
index 67ec052..f7981dd 100644
--- a/src/sfnt/ttload.h
+++ b/src/sfnt/ttload.h
@@ -41,10 +41,10 @@ FT_BEGIN_HEADER
 
 
   FT_LOCAL( FT_Error )
-  TT_Load_SFNT_HeaderRec( TT_Face       face,
-                          FT_Stream     stream,
-                          FT_Long       face_index,
-                          SFNT_Header   sfnt );
+  TT_Load_SFNT_Header( TT_Face       face,
+                       FT_Stream     stream,
+                       FT_Long       face_index,
+                       SFNT_Header   sfnt );
 
   FT_LOCAL( FT_Error )
   TT_Load_Directory( TT_Face       face,