summaryrefslogtreecommitdiffstats
path: root/src/truetype/ttgxvar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/truetype/ttgxvar.c')
-rw-r--r--src/truetype/ttgxvar.c147
1 files changed, 115 insertions, 32 deletions
diff --git a/src/truetype/ttgxvar.c b/src/truetype/ttgxvar.c
index 2b12483..5d4384e 100644
--- a/src/truetype/ttgxvar.c
+++ b/src/truetype/ttgxvar.c
@@ -112,6 +112,8 @@
/* <Input> */
/* stream :: The data stream. */
/* */
+ /* size :: The size of the table holding the data. */
+ /* */
/* <Output> */
/* point_cnt :: The number of points read. A zero value means that */
/* all points in the glyph will be affected, without */
@@ -123,6 +125,7 @@
/* */
static FT_UShort*
ft_var_readpackedpoints( FT_Stream stream,
+ FT_ULong size,
FT_UInt *point_cnt )
{
FT_UShort *points = NULL;
@@ -149,6 +152,12 @@
n |= FT_GET_BYTE();
}
+ if ( n > size )
+ {
+ FT_TRACE1(( "ft_var_readpackedpoints: number of points too large\n" ));
+ return NULL;
+ }
+
if ( FT_NEW_ARRAY( points, n ) )
return NULL;
@@ -212,6 +221,8 @@
/* <Input> */
/* stream :: The data stream. */
/* */
+ /* size :: The size of the table holding the data. */
+ /* */
/* delta_cnt :: The number of deltas to be read. */
/* */
/* <Return> */
@@ -222,6 +233,7 @@
/* */
static FT_Short*
ft_var_readpackeddeltas( FT_Stream stream,
+ FT_ULong size,
FT_UInt delta_cnt )
{
FT_Short *deltas = NULL;
@@ -233,6 +245,12 @@
FT_UNUSED( error );
+ if ( delta_cnt > size )
+ {
+ FT_TRACE1(( "ft_var_readpackeddeltas: number of points too large\n" ));
+ return NULL;
+ }
+
if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
return NULL;
@@ -341,7 +359,8 @@
FT_TRACE5(( " axis %d:\n", i ));
segment->pairCount = FT_GET_USHORT();
- if ( FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
+ if ( (FT_ULong)segment->pairCount * 4 > table_len ||
+ FT_NEW_ARRAY( segment->correspondence, segment->pairCount ) )
{
/* Failure. Free everything we have done so far. We must do */
/* it right now since loading the `avar' table is optional. */
@@ -357,8 +376,8 @@
for ( j = 0; j < segment->pairCount; j++ )
{
/* convert to Fixed */
- segment->correspondence[j].fromCoord = FT_GET_SHORT() << 2;
- segment->correspondence[j].toCoord = FT_GET_SHORT() << 2;
+ segment->correspondence[j].fromCoord = FT_GET_SHORT() * 4;
+ segment->correspondence[j].toCoord = FT_GET_SHORT() * 4;
FT_TRACE5(( " mapping %.4f to %.4f\n",
segment->correspondence[j].fromCoord / 65536.0,
@@ -447,10 +466,6 @@
if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) )
goto Exit;
- blend->tuplecount = gvar_head.globalCoordCount;
- blend->gv_glyphcnt = gvar_head.glyphCount;
- offsetToData = gvar_start + gvar_head.offsetToData;
-
if ( gvar_head.version != 0x00010000L )
{
FT_TRACE1(( "bad table version\n" ));
@@ -458,8 +473,6 @@
goto Exit;
}
- FT_TRACE2(( "loaded\n" ));
-
if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis )
{
FT_TRACE1(( "ft_var_load_gvar: number of axes in `gvar' and `cvar'\n"
@@ -468,6 +481,33 @@
goto Exit;
}
+ /* rough sanity check, ignoring offsets */
+ if ( (FT_ULong)gvar_head.globalCoordCount * gvar_head.axisCount >
+ table_len / 2 )
+ {
+ FT_TRACE1(( "ft_var_load_gvar:"
+ " invalid number of global coordinates\n" ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ /* rough sanity check: offsets can be either 2 or 4 bytes, */
+ /* and a single variation needs at least 4 bytes per glyph */
+ if ( (FT_ULong)gvar_head.glyphCount *
+ ( ( gvar_head.flags & 1 ) ? 8 : 6 ) > table_len )
+ {
+ FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" ));
+ error = FT_THROW( Invalid_Table );
+ goto Exit;
+ }
+
+ FT_TRACE2(( "loaded\n" ));
+
+ blend->gvar_size = table_len;
+ blend->tuplecount = gvar_head.globalCoordCount;
+ blend->gv_glyphcnt = gvar_head.glyphCount;
+ offsetToData = gvar_start + gvar_head.offsetToData;
+
FT_TRACE5(( "gvar: there are %d shared coordinates:\n",
blend->tuplecount ));
@@ -514,7 +554,7 @@
for ( j = 0 ; j < (FT_UInt)gvar_head.axisCount; j++ )
{
blend->tuplecoords[i * gvar_head.axisCount + j] =
- FT_GET_SHORT() << 2; /* convert to FT_Fixed */
+ FT_GET_SHORT() * 4; /* convert to FT_Fixed */
FT_TRACE5(( "%.4f ",
blend->tuplecoords[i * gvar_head.axisCount + j] / 65536.0 ));
}
@@ -698,7 +738,8 @@
/* TT_Get_MM_Var initializes the blend structure. */
/* */
/* <Output> */
- /* master :: The `fvar' data (must be freed by caller). */
+ /* master :: The `fvar' data (must be freed by caller). Can be NULL, */
+ /* which makes this function simply load MM support. */
/* */
/* <Return> */
/* FreeType error code. 0 means success. */
@@ -1352,13 +1393,25 @@
goto FExit;
tupleCount = FT_GET_USHORT();
- offsetToData = table_start + FT_GET_USHORT();
+ offsetToData = FT_GET_USHORT();
+
+ /* rough sanity test */
+ if ( offsetToData + tupleCount * 4 > table_len )
+ {
+ FT_TRACE2(( "tt_face_vary_cvt:"
+ " invalid CVT variation array header\n" ));
+
+ error = FT_THROW( Invalid_Table );
+ goto FExit;
+ }
- /* The documentation implies there are flags packed into the */
- /* tuplecount, but John Jenkins says that shared points don't apply */
- /* to `cvar', and no other flags are defined. */
+ offsetToData += table_start;
- FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount ));
+ /* The documentation implies there are flags packed into */
+ /* `tupleCount', but John Jenkins says that shared points don't apply */
+ /* to `cvar', and no other flags are defined. */
+
+ FT_TRACE5(( "cvar: there are %d tuples:\n", tupleCount & 0xFFF ));
for ( i = 0; i < ( tupleCount & 0xFFF ); i++ )
{
@@ -1378,7 +1431,7 @@
if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
{
for ( j = 0; j < blend->num_axis; j++ )
- tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
+ tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
/* short frac to fixed */
}
else
@@ -1396,9 +1449,9 @@
if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
{
for ( j = 0; j < blend->num_axis; j++ )
- im_start_coords[j] = FT_GET_SHORT() << 2;
+ im_start_coords[j] = FT_GET_SHORT() * 4;
for ( j = 0; j < blend->num_axis; j++ )
- im_end_coords[j] = FT_GET_SHORT() << 2;
+ im_end_coords[j] = FT_GET_SHORT() * 4;
}
apply = ft_var_apply_tuple( blend,
@@ -1420,8 +1473,11 @@
FT_Stream_SeekSet( stream, offsetToData );
- localpoints = ft_var_readpackedpoints( stream, &point_count );
+ localpoints = ft_var_readpackedpoints( stream,
+ table_len,
+ &point_count );
deltas = ft_var_readpackeddeltas( stream,
+ table_len,
point_count == 0 ? face->cvt_size
: point_count );
if ( localpoints == NULL || deltas == NULL )
@@ -1649,13 +1705,13 @@
{
FT_Vector* out_points;
- FT_UInt first_point;
- FT_UInt end_point;
+ FT_Int first_point;
+ FT_Int end_point;
- FT_UInt first_delta;
- FT_UInt cur_delta;
+ FT_Int first_delta;
+ FT_Int cur_delta;
- FT_UInt point;
+ FT_Int point;
FT_Short contour;
@@ -1818,7 +1874,19 @@
goto Fail2;
tupleCount = FT_GET_USHORT();
- offsetToData = glyph_start + FT_GET_USHORT();
+ offsetToData = FT_GET_USHORT();
+
+ /* rough sanity test */
+ if ( offsetToData + tupleCount * 4 > blend->gvar_size )
+ {
+ FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+ " invalid glyph variation array header\n" ));
+
+ error = FT_THROW( Invalid_Table );
+ goto Fail2;
+ }
+
+ offsetToData += glyph_start;
if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS )
{
@@ -1826,13 +1894,16 @@
FT_Stream_SeekSet( stream, offsetToData );
- sharedpoints = ft_var_readpackedpoints( stream, &spoint_count );
+ sharedpoints = ft_var_readpackedpoints( stream,
+ blend->gvar_size,
+ &spoint_count );
offsetToData = FT_Stream_FTell( stream );
FT_Stream_SeekSet( stream, here );
}
- FT_TRACE5(( "gvar: there are %d tuples:\n", tupleCount ));
+ FT_TRACE5(( "gvar: there are %d tuples:\n",
+ tupleCount & GX_TC_TUPLE_COUNT_MASK ));
for ( i = 0; i < ( tupleCount & GX_TC_TUPLE_COUNT_MASK ); i++ )
{
@@ -1849,11 +1920,14 @@
if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD )
{
for ( j = 0; j < blend->num_axis; j++ )
- tuple_coords[j] = FT_GET_SHORT() << 2; /* convert from */
+ tuple_coords[j] = FT_GET_SHORT() * 4; /* convert from */
/* short frac to fixed */
}
else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) >= blend->tuplecount )
{
+ FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:"
+ " invalid tuple index\n" ));
+
error = FT_THROW( Invalid_Table );
goto Fail2;
}
@@ -1866,9 +1940,9 @@
if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE )
{
for ( j = 0; j < blend->num_axis; j++ )
- im_start_coords[j] = FT_GET_SHORT() << 2;
+ im_start_coords[j] = FT_GET_SHORT() * 4;
for ( j = 0; j < blend->num_axis; j++ )
- im_end_coords[j] = FT_GET_SHORT() << 2;
+ im_end_coords[j] = FT_GET_SHORT() * 4;
}
apply = ft_var_apply_tuple( blend,
@@ -1889,7 +1963,9 @@
{
FT_Stream_SeekSet( stream, offsetToData );
- localpoints = ft_var_readpackedpoints( stream, &point_count );
+ localpoints = ft_var_readpackedpoints( stream,
+ blend->gvar_size,
+ &point_count );
points = localpoints;
}
else
@@ -1899,9 +1975,11 @@
}
deltas_x = ft_var_readpackeddeltas( stream,
+ blend->gvar_size,
point_count == 0 ? n_points
: point_count );
deltas_y = ft_var_readpackeddeltas( stream,
+ blend->gvar_size,
point_count == 0 ? n_points
: point_count );
@@ -1949,6 +2027,9 @@
#endif
}
+ else if ( localpoints == NULL )
+ ; /* failure, ignore it */
+
else
{
#ifdef FT_DEBUG_LEVEL_TRACE
@@ -2020,6 +2101,8 @@
FT_TRACE5(( "\n" ));
Fail2:
+ if ( sharedpoints != ALL_POINTS )
+ FT_FREE( sharedpoints );
FT_FREE( tuple_coords );
FT_FREE( im_start_coords );
FT_FREE( im_end_coords );