Sync with trunk r47367
[reactos.git] / lib / 3rdparty / freetype / src / sfnt / ttload.c
index abe0278..3ad33bd 100644 (file)
@@ -5,7 +5,7 @@
 /*    Load the basic TrueType tables, i.e., tables that can be either in   */
 /*    TTF or OTF fonts (body).                                             */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007 by             */
+/*  Copyright 1996-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 by */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
@@ -58,6 +58,9 @@
   {
     TT_Table  entry;
     TT_Table  limit;
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_Bool   zero_length = FALSE;
+#endif
 
 
     FT_TRACE4(( "tt_face_lookup_table: %08p, `%c%c%c%c' -- ",
 
     for ( ; entry < limit; entry++ )
     {
-      /* For compatibility with Windows, we consider 0-length */
-      /* tables the same as missing tables.                   */
-      if ( entry->Tag == tag && entry->Length != 0 )
-      {
-        FT_TRACE4(( "found table.\n" ));
-        return entry;
+      /* For compatibility with Windows, we consider    */
+      /* zero-length tables the same as missing tables. */
+      if ( entry->Tag == tag ) {
+        if ( entry->Length != 0 )
+        {
+          FT_TRACE4(( "found table.\n" ));
+          return entry;
+        }
+#ifdef FT_DEBUG_LEVEL_TRACE
+        zero_length = TRUE;
+#endif
       }
     }
 
-    FT_TRACE4(( "could not find table!\n" ));
-    return 0;
+#ifdef FT_DEBUG_LEVEL_TRACE
+    if ( zero_length )
+      FT_TRACE4(( "ignoring empty table\n" ));
+    else
+      FT_TRACE4(( "could not find table\n" ));
+#endif
+
+    return NULL;
   }
 
 
         *length = table->Length;
 
       if ( FT_STREAM_SEEK( table->Offset ) )
-       goto Exit;
+        goto Exit;
     }
     else
       error = SFNT_Err_Table_Missing;
   }
 
 
-  /* Here, we                                                              */
-  /*                                                                       */
-  /* - check that `num_tables' is valid                                    */
-  /* - look for a `head' table, check its size, and parse it to check      */
-  /*   whether its `magic' field is correctly set                          */
-  /*                                                                       */
-  /* When checking directory entries, ignore the tables `glyx' and `locx'  */
-  /* which are hacked-out versions of `glyf' and `loca' in some PostScript */
-  /* Type 42 fonts, and which are generally invalid.                       */
-  /*                                                                       */
+  /* Here, we                                                         */
+  /*                                                                  */
+  /* - check that `num_tables' is valid (and adjust it if necessary)  */
+  /*                                                                  */
+  /* - look for a `head' table, check its size, and parse it to check */
+  /*   whether its `magic' field is correctly set                     */
+  /*                                                                  */
+  /* - errors (except errors returned by stream handling)             */
+  /*                                                                  */
+  /*     SFNT_Err_Unknown_File_Format:                                */
+  /*       no table is defined in directory, it is not sfnt-wrapped   */
+  /*       data                                                       */
+  /*     SFNT_Err_Table_Missing:                                      */
+  /*       table directory is valid, but essential tables             */
+  /*       (head/bhed/SING) are missing                               */
+  /*                                                                  */
   static FT_Error
   check_table_dir( 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' );
+    FT_Error   error;
+    FT_UShort  nn, valid_entries = 0;
+    FT_UInt    has_head = 0, has_sing = 0, has_meta = 0;
+    FT_ULong   offset = sfnt->offset + 12;
 
     static const FT_Frame_Field  table_dir_entry_fields[] =
     {
     };
 
 
-    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;
+      goto Exit;
 
     for ( nn = 0; nn < sfnt->num_tables; nn++ )
     {
 
 
       if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) )
-        return error;
+      {
+        nn--;
+        FT_TRACE2(( "check_table_dir:"
+                    " can read only %d table%s in font (instead of %d)\n",
+                    nn, nn == 1 ? "" : "s", sfnt->num_tables ));
+        sfnt->num_tables = nn;
+        break;
+      }
 
-      if ( table.Offset + table.Length > stream->size &&
-           table.Tag != glyx_tag                      &&
-           table.Tag != locx_tag                      )
-        return SFNT_Err_Unknown_File_Format;
+      /* we ignore invalid tables */
+      if ( table.Offset + table.Length > stream->size )
+      {
+        FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn ));
+        continue;
+      }
+      else
+        valid_entries++;
 
       if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed )
       {
          *
          */
         if ( table.Length < 0x36 )
-          return SFNT_Err_Unknown_File_Format;
+        {
+          FT_TRACE2(( "check_table_dir: `head' table too small\n" ));
+          error = SFNT_Err_Table_Missing;
+          goto Exit;
+        }
 
         if ( FT_STREAM_SEEK( table.Offset + 12 ) ||
              FT_READ_ULONG( magic )              )
-          return error;
+          goto Exit;
 
         if ( magic != 0x5F0F3CF5UL )
-          return SFNT_Err_Unknown_File_Format;
+        {
+          FT_TRACE2(( "check_table_dir:"
+                      " no magic number found in `head' table\n"));
+          error = SFNT_Err_Table_Missing;
+          goto Exit;
+        }
 
         if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) )
-          return error;
+          goto Exit;
       }
       else if ( table.Tag == TTAG_SING )
         has_sing = 1;
         has_meta = 1;
     }
 
+    sfnt->num_tables = valid_entries;
+
+    if ( sfnt->num_tables == 0 )
+    {
+      FT_TRACE2(( "check_table_dir: no tables found\n" ));
+      error = SFNT_Err_Unknown_File_Format;
+      goto Exit;
+    }
+
     /* if `sing' and `meta' tables are present, there is no `head' table */
     if ( has_head || ( has_sing && has_meta ) )
-      return SFNT_Err_Ok;
+    {
+      error = SFNT_Err_Ok;
+      goto Exit;
+    }
     else
-      return SFNT_Err_Unknown_File_Format;
+    {
+      FT_TRACE2(( "check_table_dir:" ));
+#ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS
+      FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" ));
+#else
+      FT_TRACE2(( " neither `head' nor `sing' table found\n" ));
+#endif
+      error = SFNT_Err_Table_Missing;
+    }
+
+  Exit:
+    return error;
   }
 
 
     FT_Error        error;
     FT_Memory       memory = stream->memory;
     TT_TableRec*    entry;
-    TT_TableRec*    limit;
+    FT_Int          nn;
 
     static const FT_Frame_Field  offset_table_fields[] =
     {
 
     if ( FT_READ_ULONG( sfnt.format_tag )                    ||
          FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) )
-      return error;
+      goto Exit;
 
     /* many fonts don't have these fields set correctly */
 #if 0
 
     /* load the table directory */
 
-    FT_TRACE2(( "-- Tables count:   %12u\n",  sfnt.num_tables ));
-    FT_TRACE2(( "-- Format version: %08lx\n", sfnt.format_tag ));
+    FT_TRACE2(( "-- Number of tables: %10u\n",    sfnt.num_tables ));
+    FT_TRACE2(( "-- Format version:   0x%08lx\n", sfnt.format_tag ));
 
     /* check first */
     error = check_table_dir( &sfnt, stream );
     if ( error )
     {
-      FT_TRACE2(( "tt_face_load_font_dir: invalid table directory!\n" ));
+      FT_TRACE2(( "tt_face_load_font_dir:"
+                  " invalid table directory for TrueType\n" ));
 
-      return error;
+      goto Exit;
     }
 
     face->num_tables = sfnt.num_tables;
     face->format_tag = sfnt.format_tag;
 
     if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) )
-      return error;
+      goto Exit;
 
     if ( FT_STREAM_SEEK( sfnt.offset + 12 )       ||
          FT_FRAME_ENTER( face->num_tables * 16L ) )
-      return error;
+      goto Exit;
 
     entry = face->dir_tables;
-    limit = entry + face->num_tables;
 
-    for ( ; entry < limit; entry++ )
+    for ( nn = 0; nn < sfnt.num_tables; nn++ )
     {
       entry->Tag      = FT_GET_TAG4();
       entry->CheckSum = FT_GET_ULONG();
       entry->Offset   = FT_GET_LONG();
       entry->Length   = FT_GET_LONG();
 
-      FT_TRACE2(( "  %c%c%c%c  -  %08lx  -  %08lx\n",
-                  (FT_Char)( entry->Tag >> 24 ),
-                  (FT_Char)( entry->Tag >> 16 ),
-                  (FT_Char)( entry->Tag >> 8  ),
-                  (FT_Char)( entry->Tag       ),
-                  entry->Offset,
-                  entry->Length ));
+      /* ignore invalid tables */
+      if ( entry->Offset + entry->Length > stream->size )
+        continue;
+      else
+      {
+        FT_TRACE2(( "  %c%c%c%c  -  %08lx  -  %08lx\n",
+                    (FT_Char)( entry->Tag >> 24 ),
+                    (FT_Char)( entry->Tag >> 16 ),
+                    (FT_Char)( entry->Tag >> 8  ),
+                    (FT_Char)( entry->Tag       ),
+                    entry->Offset,
+                    entry->Length ));
+        entry++;
+      }
     }
 
     FT_FRAME_EXIT();
 
     FT_TRACE2(( "table directory loaded\n\n" ));
 
+  Exit:
     return error;
   }
 
 
       if ( maxProfile->maxFunctionDefs == 0 )
         maxProfile->maxFunctionDefs = 64;
+
+      /* we add 4 phantom points later */
+      if ( maxProfile->maxTwilightPoints > ( 0xFFFFU - 4 ) )
+      {
+        FT_TRACE0(( "tt_face_load_maxp:"
+                    " too much twilight points in `maxp' table;\n"
+                    "                  "
+                    " some glyphs might be rendered incorrectly\n" ));
+
+        maxProfile->maxTwilightPoints = 0xFFFFU - 4;
+      }
     }
 
     FT_TRACE3(( "numGlyphs: %u\n", maxProfile->numGlyphs ));
 
     if ( storage_start > storage_limit )
     {
-      FT_ERROR(( "invalid `name' table\n" ));
+      FT_ERROR(( "tt_face_load_name: invalid `name' table\n" ));
       error = SFNT_Err_Name_Table_Missing;
       goto Exit;
     }