[truetype] Fix handling of packed deltas in Variation Fonts.
* src/truetype/ttgxvar (ft_var_readpackeddeltas): Don't expect the number of bytes used to encode the deltas to be higher than the number of encoded values. The specification allows a very compact encoding; for example, a list of 200 zeros can be encoded with just a couple of bytes. We now count the consumed bytes to make sure to not read more than expected.
This commit is contained in:
parent
9ed5332fe6
commit
fc55291b1c
|
@ -264,55 +264,80 @@
|
||||||
FT_Fixed *deltas = NULL;
|
FT_Fixed *deltas = NULL;
|
||||||
FT_UInt runcnt, cnt;
|
FT_UInt runcnt, cnt;
|
||||||
FT_UInt i, j;
|
FT_UInt i, j;
|
||||||
|
FT_UInt bytes_used;
|
||||||
FT_Memory memory = stream->memory;
|
FT_Memory memory = stream->memory;
|
||||||
FT_Error error = FT_Err_Ok;
|
FT_Error error = FT_Err_Ok;
|
||||||
|
|
||||||
FT_UNUSED( error );
|
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 ) )
|
if ( FT_NEW_ARRAY( deltas, delta_cnt ) )
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while ( i < delta_cnt )
|
bytes_used = 0;
|
||||||
|
|
||||||
|
while ( i < delta_cnt && bytes_used < size )
|
||||||
{
|
{
|
||||||
runcnt = FT_GET_BYTE();
|
runcnt = FT_GET_BYTE();
|
||||||
cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
|
cnt = runcnt & GX_DT_DELTA_RUN_COUNT_MASK;
|
||||||
|
|
||||||
|
bytes_used++;
|
||||||
|
|
||||||
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
|
if ( runcnt & GX_DT_DELTAS_ARE_ZERO )
|
||||||
{
|
{
|
||||||
/* `runcnt' zeroes get added */
|
/* `cnt` + 1 zeroes get added */
|
||||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||||
deltas[i++] = 0;
|
deltas[i++] = 0;
|
||||||
}
|
}
|
||||||
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
|
else if ( runcnt & GX_DT_DELTAS_ARE_WORDS )
|
||||||
{
|
{
|
||||||
/* `runcnt' shorts from the stack */
|
/* `cnt` + 1 shorts from the stack */
|
||||||
|
bytes_used += 2 * ( cnt + 1 );
|
||||||
|
if ( bytes_used > size )
|
||||||
|
{
|
||||||
|
FT_TRACE1(( "ft_var_readpackeddeltas:"
|
||||||
|
" number of short deltas too large\n" ));
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||||
deltas[i++] = FT_intToFixed( FT_GET_SHORT() );
|
deltas[i++] = FT_intToFixed( FT_GET_SHORT() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* `runcnt' signed bytes from the stack */
|
/* `cnt` + 1 signed bytes from the stack */
|
||||||
|
bytes_used += cnt + 1;
|
||||||
|
if ( bytes_used > size )
|
||||||
|
{
|
||||||
|
FT_TRACE1(( "ft_var_readpackeddeltas:"
|
||||||
|
" number of byte deltas too large\n" ));
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
for ( j = 0; j <= cnt && i < delta_cnt; j++ )
|
||||||
deltas[i++] = FT_intToFixed( FT_GET_CHAR() );
|
deltas[i++] = FT_intToFixed( FT_GET_CHAR() );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( j <= cnt )
|
if ( j <= cnt )
|
||||||
{
|
{
|
||||||
/* bad format */
|
FT_TRACE1(( "ft_var_readpackeddeltas:"
|
||||||
FT_FREE( deltas );
|
" number of deltas too large\n" ));
|
||||||
return NULL;
|
goto Fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( i < delta_cnt )
|
||||||
|
{
|
||||||
|
FT_TRACE1(( "ft_var_readpackeddeltas: not enough deltas\n" ));
|
||||||
|
goto Fail;
|
||||||
|
}
|
||||||
|
|
||||||
return deltas;
|
return deltas;
|
||||||
|
|
||||||
|
Fail:
|
||||||
|
FT_FREE( deltas );
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue