[CMAKE]
[reactos.git] / lib / 3rdparty / freetype / src / truetype / ttpload.c
index 9d3381b..68a5453 100644 (file)
@@ -4,7 +4,7 @@
 /*                                                                         */
 /*    TrueType-specific tables loader (body).                              */
 /*                                                                         */
-/*  Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007 by                   */
+/*  Copyright 1996-2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010 by */
 /*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
 /*                                                                         */
 /*  This file is part of the FreeType project, and may only be used,       */
   /* <Return>                                                              */
   /*    FreeType error code.  0 means success.                             */
   /*                                                                       */
-
   FT_LOCAL_DEF( FT_Error )
   tt_face_load_loca( TT_Face    face,
                      FT_Stream  stream )
   {
     FT_Error  error;
     FT_ULong  table_len;
+    FT_Int    shift;
 
 
     /* we need the size of the `glyf' table for malformed `loca' tables */
     error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len );
-    if ( error )
+
+    /* it is possible that a font doesn't have a glyf table at all */
+    /* or its size is zero                                         */
+    if ( error == TT_Err_Table_Missing )
+      face->glyf_len = 0;
+    else if ( error )
       goto Exit;
 
     FT_TRACE2(( "Locations " ));
 
     if ( face->header.Index_To_Loc_Format != 0 )
     {
+      shift = 2;
+
       if ( table_len >= 0x40000L )
       {
-        FT_TRACE2(( "table too large!\n" ));
+        FT_TRACE2(( "table too large\n" ));
         error = TT_Err_Invalid_Table;
         goto Exit;
       }
-      face->num_locations = (FT_UInt)( table_len >> 2 );
+      face->num_locations = table_len >> shift;
     }
     else
     {
+      shift = 1;
+
       if ( table_len >= 0x20000L )
       {
-        FT_TRACE2(( "table too large!\n" ));
+        FT_TRACE2(( "table too large\n" ));
         error = TT_Err_Invalid_Table;
         goto Exit;
       }
-      face->num_locations = (FT_UInt)( table_len >> 1 );
+      face->num_locations = table_len >> shift;
+    }
+
+    if ( face->num_locations != (FT_ULong)face->root.num_glyphs )
+    {
+      FT_TRACE2(( "glyph count mismatch!  loca: %d, maxp: %d\n",
+                  face->num_locations, face->root.num_glyphs ));
+
+      /* we only handle the case where `maxp' gives a larger value */
+      if ( face->num_locations < (FT_ULong)face->root.num_glyphs )
+      {
+        FT_Long   new_loca_len = (FT_Long)face->root.num_glyphs << shift;
+
+        TT_Table  entry = face->dir_tables;
+        TT_Table  limit = entry + face->num_tables;
+
+        FT_Long   pos  = FT_Stream_Pos( stream );
+        FT_Long   dist = 0x7FFFFFFFL;
+
+
+        /* compute the distance to next table in font file */
+        for ( ; entry < limit; entry++ )
+        {
+          FT_Long  diff = entry->Offset - pos;
+
+
+          if ( diff > 0 && diff < dist )
+            dist = diff;
+        }
+
+        if ( entry == limit )
+        {
+          /* `loca' is the last table */
+          dist = stream->size - pos;
+        }
+
+        if ( new_loca_len <= dist )
+        {
+          face->num_locations = face->root.num_glyphs;
+          table_len           = new_loca_len;
+
+          FT_TRACE2(( "adjusting num_locations to %d\n",
+                      face->num_locations ));
+        }
+      }
     }
 
     /*
       }
     }
 
-    /* It isn't mentioned explicitly that the `loca' table must be  */
-    /* ordered, but implicitly it refers to the length of an entry  */
-    /* as the difference between the current and the next position. */
-    /* Anyway, there do exist (malformed) fonts which don't obey    */
-    /* this rule, so we are only able to provide an upper bound for */
-    /* the size.                                                    */
+    /* Check broken location data */
+    if ( pos1 >= face->glyf_len )
+    {
+      FT_TRACE1(( "tt_face_get_location:"
+                 " too large offset=0x%08lx found for gid=0x%04lx,"
+                 " exceeding the end of glyf table (0x%08lx)\n",
+                 pos1, gindex, face->glyf_len ));
+      *asize = 0;
+      return 0;
+    }
+
+    if ( pos2 >= face->glyf_len )
+    {
+      FT_TRACE1(( "tt_face_get_location:"
+                 " too large offset=0x%08lx found for gid=0x%04lx,"
+                 " truncate at the end of glyf table (0x%08lx)\n",
+                 pos2, gindex + 1, face->glyf_len ));
+      pos2 = face->glyf_len;
+    }
+
+    /* The `loca' table must be ordered; it refers to the length of */
+    /* an entry as the difference between the current and the next  */
+    /* position.  However, there do exist (malformed) fonts which   */
+    /* don't obey this rule, so we are only able to provide an      */
+    /* upper bound for the size.                                    */
+    /*                                                              */
+    /* We get (intentionally) a wrong, non-zero result in case the  */
+    /* `glyf' table is missing.                                     */
     if ( pos2 >= pos1 )
       *asize = (FT_UInt)( pos2 - pos1 );
     else
     error = face->goto_table( face, TTAG_cvt, stream, &table_len );
     if ( error )
     {
-      FT_TRACE2(( "is missing!\n" ));
+      FT_TRACE2(( "is missing\n" ));
 
       face->cvt_size = 0;
       face->cvt      = NULL;
       FT_Short*  limit = cur + face->cvt_size;
 
 
-      for ( ; cur <  limit; cur++ )
+      for ( ; cur < limit; cur++ )
         *cur = FT_GET_SHORT();
     }
 
       face->font_program_size = 0;
       error                   = TT_Err_Ok;
 
-      FT_TRACE2(( "is missing!\n" ));
+      FT_TRACE2(( "is missing\n" ));
     }
     else
     {
       face->cvt_program_size = 0;
       error                  = TT_Err_Ok;
 
-      FT_TRACE2(( "is missing!\n" ));
+      FT_TRACE2(( "is missing\n" ));
     }
     else
     {