diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c index 38025c60d..a44cd6f80 100644 --- a/src/sfnt/sfwoff2.c +++ b/src/sfnt/sfwoff2.c @@ -65,6 +65,20 @@ } while ( 0 ) + static void + stream_close( FT_Stream stream ) + { + FT_Memory memory = stream->memory; + + + FT_FREE( stream->base ); + + stream->size = 0; + stream->base = NULL; + stream->close = NULL; + } + + FT_CALLBACK_DEF( int ) compare_tags( const void* a, const void* b ) @@ -235,23 +249,140 @@ } + static WOFF2_Table + find_table( WOFF2_Table* tables, + FT_UShort num_tables, + FT_ULong tag ) + { + FT_Int i; + + for ( i = 0; i < num_tables; i++ ) + { + if( tables[i]->Tag == tag ) + return tables[i]; + } + return NULL; + } + + + /* Read `numberOfHMetrics' from `hhea' table. */ + static FT_Error + read_num_hmetrics( FT_Stream stream, + FT_ULong table_len, + FT_UShort* num_hmetrics ) + { + FT_Error error = FT_Err_Ok; + FT_UShort num_metrics; + + if( FT_STREAM_SKIP( 34 ) ) + return FT_THROW( Invalid_Table ); + + if( FT_READ_USHORT( num_metrics ) ) + return FT_THROW( Invalid_Table ); + + *num_hmetrics = num_metrics; + + FT_TRACE2(( "num_hmetrics = %d\n", *num_hmetrics )); + + return error; + } + + static FT_Error reconstruct_font( FT_Byte* transformed_buf, FT_ULong transformed_buf_size, WOFF2_Table* indices, WOFF2_Header woff2, - FT_Int face_index, - FT_Byte* sfnt ) + FT_Byte* sfnt, + FT_Memory memory ) { - /* We're writing only one face per call, so offset is fixed. */ - FT_ULong dst_offset = 12; - FT_Byte* table_entry = NULL; + FT_Error error = FT_Err_Ok; + FT_Stream stream = NULL; + + /* We're writing only one face per call, so initial offset is fixed. */ + FT_ULong dst_offset = 12; + FT_UShort num_tables = woff2->num_tables; + + FT_ULong checksum = 0; + FT_ULong loca_checksum = 0; + FT_Int nn = 0; + FT_UShort num_hmetrics; + + /* Few table checks before reconstruction. */ + /* `glyf' must be present with `loca'. */ + const WOFF2_Table glyf_table = find_table( indices, num_tables, + TTAG_glyf ); + const WOFF2_Table loca_table = find_table( indices, num_tables, + TTAG_loca ); + + if( ( !glyf_table && loca_table ) || + ( !loca_table && glyf_table ) ) + { + FT_ERROR(( "Cannot have only one of glyf/loca.\n" )); + return FT_THROW( Invalid_Table ); + } + + /* Both `glyf' and `loca' must have same transformation. */ + if( glyf_table != NULL ) + { + if( ( glyf_table->flags & WOFF2_FLAGS_TRANSFORM ) != + ( loca_table->flags & WOFF2_FLAGS_TRANSFORM ) ) + { + FT_ERROR(( "Transformation mismatch in glyf and loca." )); + return FT_THROW( Invalid_Table ); + } + } FT_UNUSED( dst_offset ); - FT_UNUSED( table_entry ); + FT_UNUSED( loca_checksum ); + FT_UNUSED( checksum ); + + /* Create a stream for the uncompressed buffer. */ + if ( FT_NEW( stream ) ) + return FT_THROW( Invalid_Table ); + FT_Stream_OpenMemory( stream, transformed_buf, transformed_buf_size ); + stream->close = stream_close; + + FT_ASSERT( FT_STREAM_POS() == 0 ); + + /* Reconstruct/copy tables to output stream. */ + for ( nn = 0; nn < num_tables; nn++ ) + { + WOFF2_TableRec table = *( indices[nn] ); + + /* DEBUG - Remove later */ + FT_TRACE2(( "Seeking to %d with table size %d.\n", table.src_offset, table.src_length )); + FT_TRACE2(( "Table tag: %c%c%c%c.\n", + (FT_Char)( table.Tag >> 24 ), + (FT_Char)( table.Tag >> 16 ), + (FT_Char)( table.Tag >> 8 ), + (FT_Char)( table.Tag ) )); + if ( FT_STREAM_SEEK( table.src_offset ) ) + return FT_THROW( Invalid_Table ); + + if( table.src_offset + table.src_length > transformed_buf_size ) + return FT_THROW( Invalid_Table ); + + /* Get stream size for fields of `hmtx' table. */ + if( table.Tag == TTAG_hhea ) + { + if( read_num_hmetrics( stream, table.src_length, &num_hmetrics ) ) + return FT_THROW( Invalid_Table ); + } + + if( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) + { + /* Check if `head' is atleast 12 bytes. */ + if( table.Tag == TTAG_head ) + { + if( table.src_length < 12 ) + return FT_THROW( Invalid_Table ); + } + } + + } /* TODO reconstruct the font tables! */ - return FT_Err_Ok; } @@ -564,6 +695,8 @@ ttc_font->num_tables ) ) goto Exit; + /* DEBUG - Remove later */ + FT_TRACE2(( "Storing tables for TTC face index %d.\n", face_index )); for ( nn = 0; nn < ttc_font->num_tables; nn++ ) { /* DEBUG - Remove later */ @@ -660,7 +793,7 @@ /* TODO Write table entries. */ reconstruct_font( uncompressed_buf, woff2.uncompressed_size, - indices, &woff2, face_index, sfnt ); + indices, &woff2, sfnt, memory ); error = FT_THROW( Unimplemented_Feature ); /* DEBUG - Remove later */