Commit 6f1eca046074c024a8c9235caa887b9cbadde5c1

Wu, Chia-I (吳佳一) 2005-11-20T08:24:24

* src/sfnt/ttload.c (sfnt_dir_check): Clean up and return correct error code. (sfnt_init): New function to fill in face->ttc_header. A non-TTC font is synthesized into a TTC font with one offset table. (tt_face_load_sfnt_header): Use sfnt_init. Fix an invalid access when the font is TTC and face_index is -1.

diff --git a/ChangeLog b/ChangeLog
index 1b18a00..f731573 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-11-20  Chia-I Wu  <b90201047@ntu.edu.tw>
+
+	* src/sfnt/ttload.c (sfnt_dir_check): Clean up and return correct
+	error code.
+	(sfnt_init): New function to fill in face->ttc_header.  A non-TTC font
+	is synthesized into a TTC font with one offset table.
+	(tt_face_load_sfnt_header): Use sfnt_init.
+	Fix an invalid access when the font is TTC and face_index is -1.
+
 2005-11-18  Werner Lemberg  <wl@gnu.org>
 
 	* src/sfnt/ttload.c (tt_face_load_metrics): Ignore excess number
diff --git a/src/sfnt/ttload.c b/src/sfnt/ttload.c
index 0c3d357..6a9a7a2 100644
--- a/src/sfnt/ttload.c
+++ b/src/sfnt/ttload.c
@@ -151,13 +151,13 @@
   /* Type 42 fonts, and will generally be invalid.                         */
   /*                                                                       */
   static FT_Error
-  sfnt_dir_check( FT_Stream  stream,
-                  FT_ULong   offset,
-                  FT_UInt    num_tables )
-   {
+  sfnt_dir_check( SFNT_Header  sfnt,
+                  FT_Stream    stream )
+  {
     FT_Error        error;
     FT_UInt         nn;
     FT_UInt         has_head = 0, has_sing = 0, has_meta = 0;
+    FT_ULong        offset = sfnt->offset + 12;
 
     const FT_ULong  glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' );
     const FT_ULong  locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' );
@@ -176,43 +176,33 @@
     };
 
 
-    /* if 'num_tables' is 0, read the table count from the file */
-    if ( num_tables == 0 )
-    {
-      if ( FT_STREAM_SEEK( offset )     ||
-           FT_STREAM_SKIP( 4 )          ||
-           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;
+    if ( sfnt->num_tables == 0 ||
+         offset + sfnt->num_tables * 16 > stream->size )
+      return SFNT_Err_Unknown_File_Format;
+
+    if ( FT_STREAM_SEEK( offset ) )
+      return error;
 
-    for ( nn = 0; nn < num_tables; nn++ )
+    for ( nn = 0; nn < sfnt->num_tables; nn++ )
     {
       TT_TableRec  table;
 
 
       if ( FT_STREAM_READ_FIELDS( sfnt_dir_entry_fields, &table ) )
-        goto Bad_Format;
+        return error;
 
       if ( table.Offset + table.Length > stream->size     &&
            table.Tag != glyx_tag && table.Tag != locx_tag )
-        goto Bad_Format;
+        return SFNT_Err_Unknown_File_Format;
 
-      if ( table.Tag == TTAG_head )
+      if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed )
       {
         FT_UInt32  magic;
 
-
-#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-      head_retry:
-#endif  /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */
-
-        has_head = 1;
+#ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+        if ( table.Tag == TTAG_head )
+#endif
+          has_head = 1;
 
         /* The table length should be 0x36, but certain font tools
          * make it 0x38, so we will just check that it is greater.
@@ -221,41 +211,98 @@
          * the table must be padded to 32-bit lengths, but this doesn't
          * apply to the value of its "Length" field!
          */
-        if ( table.Length < 0x36                 ||
-             FT_STREAM_SEEK( table.Offset + 12 ) ||
-             FT_READ_ULONG( magic )              ||
-             magic != 0x5F0F3CF5UL               )
-          goto Bad_Format;
-
-        if ( FT_STREAM_SEEK( offset + 28 + 16*nn ) )
-          goto Bad_Format;
-      }
+        if ( table.Length < 0x36 )
+          return SFNT_Err_Unknown_File_Format;
 
-#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
-      else if ( table.Tag == TTAG_bhed )
-        goto head_retry;
-#endif  /* TT_CONFIG_OPTION_EMBEDDED_BITMAPS */      
+        if ( FT_STREAM_SEEK( table.Offset + 12 ) ||
+             FT_READ_ULONG( magic ) )
+          return error;
+
+        if ( magic != 0x5F0F3CF5UL )
+          return SFNT_Err_Unknown_File_Format;
 
+        if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) )
+          return error;
+      }
       else if ( table.Tag == TTAG_SING )
         has_sing = 1;
       else if ( table.Tag == TTAG_META )
         has_meta = 1;
     }
 
-    /* when sing and meta are present, head is not present */
-    if ( has_sing && has_meta && has_head == 0 )
-        goto Exit;
+    if ( has_head || ( has_sing && has_meta ) )
+      return SFNT_Err_Ok;
+    else
+      return SFNT_Err_Unknown_File_Format;
+  }
 
-    /* otherwise, treat a missing head as a failure */
-    if ( has_head == 0 )
-      goto Bad_Format;
 
-  Exit:
-    return error;
+  /* Fill in face->ttc_header.  If the font is not a TTC, it is            */
+  /* synthesized into a TTC with one offset table.                         */
+  static FT_Error
+  sfnt_init( FT_Stream  stream,
+             TT_Face    face )
+  {
+    FT_Memory  memory = stream->memory;
+    FT_Error   error;
+    FT_ULong   tag, offset;
 
-  Bad_Format:
-    error = SFNT_Err_Unknown_File_Format;
-    goto Exit;
+    static const FT_Frame_Field  ttc_header_fields[] =
+    {
+#undef  FT_STRUCTURE
+#define FT_STRUCTURE  TTC_HeaderRec
+
+      FT_FRAME_START( 8 ),
+        FT_FRAME_LONG( version ),
+        FT_FRAME_LONG( count   ),
+      FT_FRAME_END
+    };
+
+    face->ttc_header.tag = 0;
+    face->ttc_header.version = 0;
+    face->ttc_header.count = 0;
+
+    offset = FT_STREAM_POS();
+
+    if ( FT_READ_ULONG( tag ) )
+      return error;
+
+    face->ttc_header.tag = TTAG_ttcf;
+
+    if ( tag == TTAG_ttcf )
+    {
+      FT_Int  n;
+
+
+      FT_TRACE3(( "sfnt_init: file is a collection\n" ));
+
+      if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
+        return error;
+
+      /* now read the offsets of each font in the file */
+      if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) )
+        return error;
+
+      if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) )
+        return error;
+
+      for ( n = 0; n < face->ttc_header.count; n++ )
+        face->ttc_header.offsets[n] = FT_GET_ULONG();
+
+      FT_FRAME_EXIT();
+    }
+    else
+    {
+      face->ttc_header.version = 1 << 16;
+      face->ttc_header.count = 1;
+
+      if ( FT_NEW( face->ttc_header.offsets) )
+        return error;
+
+      face->ttc_header.offsets[0] = offset;
+    }
+
+    return error;
   }
 
 
@@ -295,9 +342,7 @@
                             FT_Long      face_index,
                             SFNT_Header  sfnt )
   {
-    FT_Error   error;
-    FT_ULong   font_format_tag, format_tag, offset;
-    FT_Memory  memory = stream->memory;
+    FT_Error  error;
 
     static const FT_Frame_Field  sfnt_header_fields[] =
     {
@@ -312,95 +357,35 @@
       FT_FRAME_END
     };
 
-    static const FT_Frame_Field  ttc_header_fields[] =
-    {
-#undef  FT_STRUCTURE
-#define FT_STRUCTURE  TTC_HeaderRec
-
-      FT_FRAME_START( 8 ),
-        FT_FRAME_LONG( version ),
-        FT_FRAME_LONG( count   ),
-      FT_FRAME_END
-    };
-
 
     FT_TRACE2(( "tt_face_load_sfnt_header: %08p, %ld\n",
                 face, face_index ));
 
-    face->ttc_header.tag     = 0;
-    face->ttc_header.version = 0;
-    face->ttc_header.count   = 0;
-
-    face->num_tables = 0;
-
-    /* First of all, read the first 4 bytes.  If it is `ttcf', then the   */
-    /* file is a TrueType collection, otherwise it is a single-face font. */
-    /*                                                                    */
-    offset = FT_STREAM_POS();
-
-    if ( FT_READ_ULONG( font_format_tag ) )
-      goto Exit;
-
-    format_tag = font_format_tag;
-
-    if ( font_format_tag == TTAG_ttcf )
-    {
-      FT_Int  n;
-
-
-      FT_TRACE3(( "tt_face_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                    */
-      if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) )
-        goto Exit;
-
-      /* now read the offsets of each font in the file */
-      if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ||
-           FT_FRAME_ENTER( face->ttc_header.count * 4L )                    )
-        goto Exit;
-
-      for ( n = 0; n < face->ttc_header.count; n++ )
-        face->ttc_header.offsets[n] = FT_GET_ULONG();
-
-      FT_FRAME_EXIT();
+    error = sfnt_init( stream, face );
+    if ( error )
+      return error;
 
-      /* check face index */
-      if ( face_index >= face->ttc_header.count )
-      {
-        error = SFNT_Err_Bad_Argument;
-        goto Exit;
-      }
+    if ( face_index < 0 )
+      face_index = 0;
 
-      /* seek to the appropriate TrueType file, then read tag */
-      offset = face->ttc_header.offsets[face_index];
+    if ( face_index >= face->ttc_header.count )
+        return SFNT_Err_Bad_Argument;
 
-      if ( FT_STREAM_SEEK( offset )   ||
-           FT_READ_LONG( format_tag ) )
-        goto Exit;
-    }
+    sfnt->offset = face->ttc_header.offsets[face_index];
 
-    /* the format tag was read, now check the rest of the header */
-    sfnt->format_tag = format_tag;
-    sfnt->offset     = offset;
+    if ( FT_STREAM_SEEK( sfnt->offset ) )
+      return error;
 
-    if ( FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
-      goto Exit;
+    /* read offset table */
+    if ( FT_READ_ULONG( sfnt->format_tag ) ||
+         FT_STREAM_READ_FIELDS( sfnt_header_fields, sfnt ) )
+      return error;
 
     /* now check the sfnt directory */
-    error = sfnt_dir_check( stream, offset, sfnt->num_tables );
+    error = sfnt_dir_check( sfnt, stream );
     if ( error )
-    {
-      FT_TRACE2(( "tt_face_load_sfnt_header: file is not SFNT!\n" ));
-      error = SFNT_Err_Unknown_File_Format;
-      goto Exit;
-    }
-
-    /* disallow face index values > 0 for non-TTC files */
-    if ( font_format_tag != TTAG_ttcf && face_index > 0 )
-      error = SFNT_Err_Bad_Argument;
+      FT_TRACE2(( "tt_face_load_sfnt_header: invalid SFNT!\n" ));
 
-  Exit:
     return error;
   }