[woff2] Improve memory and error handling.

Free up memory after use, and improve error handling.

* src/sfnt/sfwoff2.c: Implement changes.
This commit is contained in:
Nikhil Ramakrishnan 2019-07-28 19:38:05 +05:30
parent befd05c060
commit af7d2967d5
1 changed files with 61 additions and 23 deletions

View File

@ -1333,6 +1333,7 @@
FT_Int nn = 0; FT_Int nn = 0;
FT_UShort num_hmetrics; FT_UShort num_hmetrics;
FT_ULong font_checksum = info->header_checksum; FT_ULong font_checksum = info->header_checksum;
FT_Bool is_glyf_xform = FALSE;
FT_ULong table_entry_offset = 12; FT_ULong table_entry_offset = 12;
WOFF2_Table head_table; WOFF2_Table head_table;
@ -1370,7 +1371,8 @@
if ( FT_NEW( stream ) ) if ( FT_NEW( stream ) )
return FT_THROW( Invalid_Table ); return FT_THROW( Invalid_Table );
FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size );
stream->close = stream_close; stream->memory = memory;
stream->close = stream_close;
FT_ASSERT( FT_STREAM_POS() == 0 ); FT_ASSERT( FT_STREAM_POS() == 0 );
@ -1432,6 +1434,7 @@
if( table.Tag == TTAG_glyf ) if( table.Tag == TTAG_glyf )
{ {
is_glyf_xform = TRUE;
table.dst_offset = dest_offset; table.dst_offset = dest_offset;
if( reconstruct_glyf( stream, &table, &checksum, if( reconstruct_glyf( stream, &table, &checksum,
@ -1447,6 +1450,12 @@
} }
else if( table.Tag == TTAG_hmtx ) else if( table.Tag == TTAG_hmtx )
{ {
if( !is_glyf_xform )
{
FT_ERROR(( "hmtx is transformed but glyf is not.\n" ));
error = FT_THROW( Unimplemented_Feature );
goto Fail;
}
table.dst_offset = dest_offset; table.dst_offset = dest_offset;
if( reconstruct_hmtx( stream, table.src_length, info->num_glyphs, if( reconstruct_hmtx( stream, table.src_length, info->num_glyphs,
info->num_hmetrics, info->x_mins, &checksum, info->num_hmetrics, info->x_mins, &checksum,
@ -1501,7 +1510,11 @@
/* Set pointer of sfnt stream to its correct value. */ /* Set pointer of sfnt stream to its correct value. */
*sfnt_bytes = sfnt; *sfnt_bytes = sfnt;
FT_FREE( table_entry ); FT_FREE( table_entry );
FT_Stream_Close( stream );
FT_FREE( stream );
return error; return error;
Fail: Fail:
@ -1509,10 +1522,10 @@
error = FT_THROW( Invalid_Table ); error = FT_THROW( Invalid_Table );
FT_FREE( table_entry ); FT_FREE( table_entry );
FT_Stream_Close( stream );
FT_FREE( stream );
return error; return error;
/* TODO free the uncompressed stream after everything is done. */
} }
@ -1673,14 +1686,16 @@
if( table->Tag == TTAG_loca && table->TransformLength ) if( table->Tag == TTAG_loca && table->TransformLength )
{ {
FT_ERROR(( "woff_font_open: Invalid loca `transformLength'.\n" )); FT_ERROR(( "woff_font_open: Invalid loca `transformLength'.\n" ));
return FT_THROW( Invalid_Table ); error = FT_THROW( Invalid_Table );
goto Exit;
} }
} }
if ( src_offset + table->TransformLength < src_offset ) if ( src_offset + table->TransformLength < src_offset )
{ {
FT_ERROR(( "woff_font_open: invalid WOFF2 table directory.\n" )); FT_ERROR(( "woff_font_open: invalid WOFF2 table directory.\n" ));
return FT_THROW( Invalid_Table ); error = FT_THROW( Invalid_Table );
goto Exit;
} }
table->src_offset = src_offset; table->src_offset = src_offset;
@ -1708,7 +1723,11 @@
woff2.uncompressed_size = last_table->src_offset woff2.uncompressed_size = last_table->src_offset
+ last_table->src_length; + last_table->src_length;
if( woff2.uncompressed_size < last_table->src_offset ) if( woff2.uncompressed_size < last_table->src_offset )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
/* DEBUG - Remove later. */ /* DEBUG - Remove later. */
FT_TRACE2(( "Uncompressed size: %ld\n", woff2.uncompressed_size )); FT_TRACE2(( "Uncompressed size: %ld\n", woff2.uncompressed_size ));
@ -1724,7 +1743,10 @@
FT_TRACE2(( "Header version: %lx\n", woff2.header_version )); FT_TRACE2(( "Header version: %lx\n", woff2.header_version ));
if( woff2.header_version != 0x00010000 && if( woff2.header_version != 0x00010000 &&
woff2.header_version != 0x00020000 ) woff2.header_version != 0x00020000 )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
if( READ_255USHORT( woff2.num_fonts ) ) if( READ_255USHORT( woff2.num_fonts ) )
goto Exit; goto Exit;
@ -1779,10 +1801,10 @@
{ {
if( glyf_index > loca_index || if( glyf_index > loca_index ||
loca_index - glyf_index != 1 ) loca_index - glyf_index != 1 )
return FT_THROW( Invalid_Table ); {
/* DEBUG - Remove later */ error = FT_THROW( Invalid_Table );
else goto Exit;
FT_TRACE2(( "glyf and loca indices are valid.\n" )); }
} }
} }
/* Collection directory reading complete. */ /* Collection directory reading complete. */
@ -1795,24 +1817,36 @@
/* Few more checks before we start reading the tables. */ /* Few more checks before we start reading the tables. */
if( file_offset > woff2.length ) if( file_offset > woff2.length )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
if ( woff2.metaOffset ) if ( woff2.metaOffset )
{ {
if ( file_offset != woff2.metaOffset ) if ( file_offset != woff2.metaOffset )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
file_offset = ROUND4(woff2.metaOffset + woff2.metaLength); file_offset = ROUND4(woff2.metaOffset + woff2.metaLength);
} }
if( woff2.privOffset ) if( woff2.privOffset )
{ {
if( file_offset != woff2.privOffset ) if( file_offset != woff2.privOffset )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
file_offset = ROUND4(woff2.privOffset + woff2.privLength); file_offset = ROUND4(woff2.privOffset + woff2.privLength);
} }
if( file_offset != ( ROUND4( woff2.length ) ) ) if( file_offset != ( ROUND4( woff2.length ) ) )
return FT_THROW( Invalid_Table ); {
error = FT_THROW( Invalid_Table );
goto Exit;
}
/* Only retain tables of the requested face in a TTC. */ /* Only retain tables of the requested face in a TTC. */
/* TODO Check whether it is OK for rest of the code to be unaware of the /* TODO Check whether it is OK for rest of the code to be unaware of the
@ -1919,13 +1953,15 @@
error = woff2_uncompress( uncompressed_buf, woff2.uncompressed_size, error = woff2_uncompress( uncompressed_buf, woff2.uncompressed_size,
stream->cursor, woff2.totalCompressedSize ); stream->cursor, woff2.totalCompressedSize );
if( error ) if( error )
goto Exit; goto Exit;
FT_FRAME_EXIT(); FT_FRAME_EXIT();
reconstruct_font( uncompressed_buf, woff2.uncompressed_size, error = reconstruct_font( uncompressed_buf, woff2.uncompressed_size,
indices, &woff2, &info, &sfnt, &sfnt_size, indices, &woff2, &info, &sfnt, &sfnt_size,
memory ); memory );
if( error )
goto Exit;
/* Resize `sfnt' to actual size of sfnt stream. */ /* Resize `sfnt' to actual size of sfnt stream. */
if ( woff2.actual_sfnt_size < sfnt_size ) if ( woff2.actual_sfnt_size < sfnt_size )
@ -1953,7 +1989,7 @@
face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM; face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
/* Set face_index to 0. */ /* Set face_index to 0. */
*face_instance_index = 0; *face_instance_index = 0;
/* error = FT_THROW( Unimplemented_Feature ); */ /* error = FT_THROW( Unimplemented_Feature ); */
@ -1964,13 +2000,15 @@
Exit: Exit:
FT_FREE( tables ); FT_FREE( tables );
FT_FREE( indices ); FT_FREE( indices );
FT_FREE( uncompressed_buf );
if( error ) if( error )
{ {
FT_FREE( sfnt ); FT_FREE( sfnt );
FT_Stream_Close( sfnt_stream ); if ( sfnt_stream )
FT_FREE( sfnt_stream ); {
FT_Stream_Close( sfnt_stream );
FT_FREE( sfnt_stream );
}
} }
return error; return error;