diff --git a/include/freetype/internal/wofftypes.h b/include/freetype/internal/wofftypes.h index 9c827e32c..381449b73 100644 --- a/include/freetype/internal/wofftypes.h +++ b/include/freetype/internal/wofftypes.h @@ -120,12 +120,6 @@ FT_BEGIN_HEADER * Number of tables in TTC, indicating number of elements in * `table_indices`. * - * dst_offset :: - * Uncompressed table offset. - * - * header_checksum :: - * Checksum for font header. - * * table_indices :: * Array of table indices for each TTC font. */ @@ -133,8 +127,6 @@ FT_BEGIN_HEADER { FT_ULong flavor; FT_UShort num_tables; - FT_ULong dst_offset; - FT_ULong header_checksum; FT_UShort* table_indices; } WOFF2_TtcFontRec, *WOFF2_TtcFont; @@ -157,7 +149,7 @@ FT_BEGIN_HEADER * We don't care about the fields `reserved`, `majorVersion` and * `minorVersion`, so they are not included. The `totalSfntSize` field * does not necessarily represent the actual size of the uncompressed - * SFNT font stream, so that is not included either. + * SFNT font stream, so that is used as a reference value instead. */ typedef struct WOFF2_HeaderRec_ { @@ -173,13 +165,13 @@ FT_BEGIN_HEADER FT_ULong privOffset; FT_ULong privLength; - FT_ULong uncompressed_size; - FT_ULong compressed_offset; - FT_ULong header_version; - FT_UShort num_fonts; - FT_ULong actual_sfnt_size; + FT_ULong uncompressed_size; /* uncompressed brotli stream size */ + FT_ULong compressed_offset; /* compressed stream offset */ + FT_ULong header_version; /* version of original TTC Header */ + FT_UShort num_fonts; /* number of fonts in TTC */ + FT_ULong actual_sfnt_size; /* actual size of sfnt stream */ - WOFF2_TtcFont ttc_fonts; + WOFF2_TtcFont ttc_fonts; /* metadata for fonts in a TTC */ } WOFF2_HeaderRec, *WOFF2_Header; @@ -194,14 +186,17 @@ FT_BEGIN_HEADER * sfnt tables. * * @fields: + * header_checksum :: + * Checksum of SFNT offset table. + * * num_glyphs :: * Number of glyphs in the font. * * num_hmetrics :: - * `numberOfHMetrics' field in the `hhea' table. + * `numberOfHMetrics` field in the 'hhea' table. * * x_mins :: - * `xMin' values of glyph bounding box. + * `xMin` values of glyph bounding box. */ typedef struct WOFF2_InfoRec_ { @@ -236,7 +231,6 @@ FT_BEGIN_HEADER FT_ULong flags; /* calculated flags */ FT_ULong src_offset; /* compressed table offset */ FT_ULong src_length; /* compressed table length */ - FT_ULong dst_offset; /* uncompressed table offset */ } WOFF2_TableRec, *WOFF2_Table; @@ -249,7 +243,7 @@ FT_BEGIN_HEADER * * @description: * This structure stores information about a substream in the transformed - * `glyf' table in a WOFF2 stream. + * 'glyf' table in a WOFF2 stream. * * @fields: * start :: @@ -266,6 +260,7 @@ FT_BEGIN_HEADER FT_ULong start; FT_ULong offset; FT_ULong size; + } WOFF2_SubstreamRec, *WOFF2_Substream; @@ -276,7 +271,7 @@ FT_BEGIN_HEADER * * @description: * This structure stores information about a point in the transformed - * `glyf' table in a WOFF2 stream. + * 'glyf' table in a WOFF2 stream. * * @fields: * x :: @@ -286,13 +281,14 @@ FT_BEGIN_HEADER * y-coordinate. * * on_curve :: - * on-curve. + * Whether point is on-curve. */ typedef struct WOFF2_PointRec_ { FT_Int x; FT_Int y; FT_Bool on_curve; + } WOFF2_PointRec, *WOFF2_Point; diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c index 871a9ad22..dbe6a62d5 100644 --- a/src/sfnt/sfwoff2.c +++ b/src/sfnt/sfwoff2.c @@ -135,6 +135,7 @@ FT_Byte result_byte = 0; FT_UShort result_short = 0; + if ( FT_READ_BYTE( code ) ) return error; if ( code == wordCode ) @@ -176,7 +177,9 @@ FT_Byte code; FT_Error error = FT_Err_Ok; - for ( i = 0; i < 5; ++i ) { + + for ( i = 0; i < 5; ++i ) + { code = 0; if ( FT_READ_BYTE( code ) ) return error; @@ -215,7 +218,8 @@ /* We are reallocating memory for `dst', so its pointer may change. */ FT_Byte* dst = *dst_bytes; - /* Check if we are within limits. */ + + /* Check whether we are within limits. */ if ( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) return FT_THROW( Array_Too_Large ); @@ -256,6 +260,7 @@ FT_Byte zeroes[] = { 0, 0, 0 }; FT_ULong pad_bytes; + if ( dest_offset + 3 < dest_offset ) return FT_THROW( Invalid_Table ); @@ -281,6 +286,7 @@ FT_ULong i; FT_ULong v; + for ( i = 0; i < aligned_size; i += 4 ) { checksum += ( buf[i] << 24 ) | ( buf[i+1] << 16 ) | @@ -310,15 +316,16 @@ FT_ULong uncompressed_size = dst_size; BrotliDecoderResult result; + result = BrotliDecoderDecompress( src_size, src, &uncompressed_size, dst); if ( result != BROTLI_DECODER_RESULT_SUCCESS || uncompressed_size != dst_size ) - { - FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); - return FT_THROW( Invalid_Table ); - } + { + FT_ERROR(( "woff2_decompress: Stream length mismatch.\n" )); + return FT_THROW( Invalid_Table ); + } FT_TRACE2(( "woff2_decompress: Brotli stream decompressed.\n" )); return FT_Err_Ok; @@ -339,6 +346,7 @@ { FT_Int i; + for ( i = 0; i < num_tables; i++ ) { if ( tables[i]->Tag == tag ) @@ -357,6 +365,7 @@ FT_Error error = FT_Err_Ok; FT_UShort num_metrics; + if ( FT_STREAM_SKIP( 34 ) ) return FT_THROW( Invalid_Table ); @@ -411,6 +420,7 @@ FT_Int i; + if ( n_points > in_size ) return FT_THROW( Invalid_Table ); @@ -418,6 +428,8 @@ { FT_Byte flag = flags_in[i]; FT_Bool on_curve = !( flag >> 7 ); + + flag &= 0x7f; if ( flag < 84 ) data_bytes = 1; @@ -506,20 +518,20 @@ FT_ULong dst_size, FT_ULong* glyph_size ) { - FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; - FT_Int last_flag = -1; - FT_Int repeat_count = 0; - FT_Int last_x = 0; - FT_Int last_y = 0; - FT_UInt x_bytes = 0; - FT_UInt y_bytes = 0; - FT_UInt xy_bytes; - FT_UInt i; - FT_UInt x_offset; - FT_UInt y_offset; - + FT_UInt flag_offset = 10 + ( 2 * n_contours ) + 2 + instruction_len; + FT_Int last_flag = -1; + FT_Int repeat_count = 0; + FT_Int last_x = 0; + FT_Int last_y = 0; + FT_UInt x_bytes = 0; + FT_UInt y_bytes = 0; + FT_UInt xy_bytes; + FT_UInt i; + FT_UInt x_offset; + FT_UInt y_offset; FT_Byte* pointer; + for ( i = 0; i < n_points; ++i ) { const WOFF2_PointRec point = points[i]; @@ -528,6 +540,7 @@ FT_Int dx = point.x - last_x; FT_Int dy = point.y - last_y; + if ( dx == 0 ) flag |= GLYF_THIS_X_IS_SAME; else if ( dx > -256 && dx < 256 ) @@ -641,6 +654,7 @@ FT_ULong offset; FT_Byte* pointer; + if ( n_points > 0 ) { x_min = points[0].x; @@ -682,6 +696,7 @@ FT_Bool we_have_inst = FALSE; FT_UShort flags = FLAG_MORE_COMPONENTS; + if ( FT_STREAM_SEEK( start_offset ) ) goto Exit; while ( flags & FLAG_MORE_COMPONENTS ) @@ -712,8 +727,8 @@ *size = FT_STREAM_POS() - start_offset; *have_instructions = we_have_inst; - Exit: - return error; + Exit: + return error; } @@ -739,6 +754,7 @@ const FT_ULong offset_size = index_format ? 4 : 2; + if ( ( loca_values_size << 2 ) >> 2 != loca_values_size ) goto Fail; @@ -750,6 +766,8 @@ for ( i = 0; i < loca_values_size; i++ ) { FT_ULong value = loca_values[i]; + + if ( index_format ) WRITE_ULONG( dst, value ); else @@ -768,13 +786,13 @@ FT_FREE( loca_buf ); return error; - Fail: - if ( !error ) - error = FT_THROW( Invalid_Table ); + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); - FT_FREE( loca_buf ); + FT_FREE( loca_buf ); - return error; + return error; } @@ -818,6 +836,7 @@ FT_Byte* glyph_buf = NULL; WOFF2_Point points = NULL; + if ( FT_NEW_ARRAY( substreams, num_substreams ) ) goto Fail; @@ -849,6 +868,8 @@ for ( i = 0; i < num_substreams; ++i ) { FT_ULong substream_size; + + if ( FT_READ_ULONG( substream_size ) ) goto Fail; if ( substream_size > glyf_table->TransformLength - offset ) @@ -889,6 +910,7 @@ FT_ULong bbox_offset; FT_UShort x_min; + /* Set `have_bbox'. */ bbox_offset = bbox_bitmap_offset + ( i >> 3 ); if ( FT_STREAM_SEEK( bbox_offset ) || @@ -912,6 +934,7 @@ FT_ULong size_needed; FT_Byte* pointer = NULL; + /* Composite glyphs must have explicit bbox. */ if ( !have_bbox ) goto Fail; @@ -990,6 +1013,7 @@ FT_Byte* pointer = NULL; + if ( FT_NEW_ARRAY( n_points_arr, n_contours ) ) goto Fail; @@ -1149,17 +1173,17 @@ return error; - Fail: - if ( !error ) - error = FT_THROW( Invalid_Table ); + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); - FT_FREE( substreams ); - FT_FREE( loca_values ); - FT_FREE( n_points_arr ); - FT_FREE( glyph_buf ); - FT_FREE( points ); + FT_FREE( substreams ); + FT_FREE( loca_values ); + FT_FREE( n_points_arr ); + FT_FREE( glyph_buf ); + FT_FREE( points ); - return error; + return error; } @@ -1189,6 +1213,7 @@ const WOFF2_Table head_table = find_table( tables, num_tables, TTAG_head ); + /* Read `numGlyphs' from maxp table. */ if ( FT_STREAM_SEEK( maxp_table->src_offset ) && FT_STREAM_SKIP( 8 ) ) return error; @@ -1273,6 +1298,7 @@ FT_Byte* hmtx_table = NULL; FT_Byte* dst = NULL; + if ( FT_READ_BYTE( hmtx_flags ) ) goto Fail; @@ -1292,7 +1318,7 @@ ( num_hmetrics < 1 ) ) goto Fail; - /* Must have atleast one entry. */ + /* Must have at least one entry. */ if ( num_hmetrics < 1 ) goto Fail; @@ -1305,6 +1331,7 @@ { FT_UShort advance_width; + if ( FT_READ_USHORT( advance_width ) ) goto Fail; @@ -1316,6 +1343,7 @@ { FT_Short lsb; + if ( has_proportional_lsbs ) { if ( FT_READ_SHORT( lsb ) ) @@ -1332,6 +1360,7 @@ { FT_Short lsb; + if ( has_monospace_lsbs ) { if ( FT_READ_SHORT( lsb ) ) @@ -1374,10 +1403,11 @@ return error; - Fail: - if ( !error ) - error = FT_THROW( Invalid_Table ); - return error; + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); + + return error; } @@ -1419,6 +1449,7 @@ const WOFF2_Table loca_table = find_table( indices, num_tables, TTAG_loca ); + if ( ( !glyf_table && loca_table ) || ( !loca_table && glyf_table ) ) { @@ -1455,6 +1486,7 @@ { WOFF2_TableRec table = *( indices[nn] ); + FT_TRACE3(( "Seeking to %d with table size %d.\n", table.src_offset, table.src_length )); FT_TRACE3(( "Table tag: %c%c%c%c.\n", @@ -1481,7 +1513,7 @@ checksum = 0; if ( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) { - /* Check if `head' is atleast 12 bytes. */ + /* Check whether `head' is at least 12 bytes. */ if ( table.Tag == TTAG_head ) { if ( table.src_length < 12 ) @@ -1591,15 +1623,15 @@ return error; - Fail: - if ( !error ) - error = FT_THROW( Invalid_Table ); + Fail: + if ( !error ) + error = FT_THROW( Invalid_Table ); - FT_FREE( table_entry ); - FT_Stream_Close( stream ); - FT_FREE( stream ); + FT_FREE( table_entry ); + FT_Stream_Close( stream ); + FT_FREE( stream ); - return error; + return error; } @@ -1662,6 +1694,7 @@ FT_FRAME_END }; + FT_ASSERT( stream == face->root.stream ); FT_ASSERT( FT_STREAM_POS() == 0 ); @@ -1716,6 +1749,8 @@ for ( nn = 0; nn < woff2.num_tables; nn++ ) { WOFF2_Table table = tables + nn; + + if ( FT_READ_BYTE( table->FlagByte ) ) goto Exit; @@ -1824,6 +1859,7 @@ { WOFF2_TtcFont ttc_font = woff2.ttc_fonts + nn; + if ( READ_255USHORT( ttc_font->num_tables ) ) goto Exit; if ( FT_READ_ULONG( ttc_font->flavor ) ) @@ -1845,6 +1881,7 @@ FT_UShort table_index; WOFF2_Table table; + if ( READ_255USHORT( table_index ) ) goto Exit; @@ -1934,6 +1971,7 @@ { WOFF2_TtcFont ttc_font = woff2.ttc_fonts + face_index; + /* Create a temporary array. */ if ( FT_NEW_ARRAY( temp_indices, ttc_font->num_tables ) ) @@ -1975,6 +2013,7 @@ { FT_UInt searchRange, entrySelector, rangeShift, x; + x = woff2.num_tables; entrySelector = 0; while ( x )