diff --git a/src/sfnt/sfwoff2.c b/src/sfnt/sfwoff2.c index a44cd6f80..cc6a4d167 100644 --- a/src/sfnt/sfwoff2.c +++ b/src/sfnt/sfwoff2.c @@ -64,6 +64,8 @@ \ } while ( 0 ) +#define WRITE_SFNT_BUF( buf, s ) \ + write_buf( &sfnt, &dest_offset, buf, s, memory ) static void stream_close( FT_Stream stream ) @@ -182,6 +184,41 @@ } + static FT_Error + write_buf( FT_Byte** dst_bytes, + FT_ULong* offset, + FT_Byte* src, + FT_ULong size, + FT_Memory memory ) + { + FT_Error error = FT_Err_Ok; + /* We are reallocating memory for `dst', so its pointer may change. */ + FT_Byte* dst = *dst_bytes; + + /* Check if we are within limits. */ + if( ( *offset + size ) > WOFF2_DEFAULT_MAX_SIZE ) + return FT_THROW( Array_Too_Large ); + + /* DEBUG - Remove later */ + FT_TRACE2(( "Reallocating %lu to %lu.\n", *offset, (*offset + size) )); + /* Reallocate `dst'. */ + if ( FT_REALLOC( dst, + (FT_ULong)(*offset), + (FT_ULong)(*offset + size ) ) ) + goto Exit; + + /* Copy data. */ + ft_memcpy( dst + *offset, src, size ); + + *offset += size; + /* Set pointer of `dst' to its correct value. */ + *dst_bytes = dst; + + Exit: + return error; + } + + static FT_Offset CollectionHeaderSize( FT_ULong header_version, FT_UShort num_fonts ) @@ -216,6 +253,32 @@ return offset; } + static FT_Long + compute_ULong_sum( FT_Byte* buf, + FT_ULong size ) + { + FT_ULong checksum = 0; + FT_ULong aligned_size = size & ~3; + FT_ULong i; + FT_ULong v; + + for( i = 0; i < aligned_size; i += 4 ) + { + checksum += ( buf[i] << 24 ) | ( buf[i+1] << 16 ) | + ( buf[i+2] << 8 ) | ( buf[i+3] << 0 ); + } + + /* If size is not aligned to 4, treat as if it is padded with 0s */ + if( size != aligned_size ) + { + v = 0; + for( i = aligned_size ; i < size; ++i ) + v |= buf[i] << ( 24 - 8 * ( i & 3 ) ); + checksum += v; + } + return checksum; + } + static FT_Error woff2_uncompress( FT_Byte* dst, @@ -293,15 +356,17 @@ FT_ULong transformed_buf_size, WOFF2_Table* indices, WOFF2_Header woff2, - FT_Byte* sfnt, + FT_Byte** sfnt_bytes, FT_Memory memory ) { FT_Error error = FT_Err_Ok; FT_Stream stream = NULL; + FT_Byte* buf_cursor = NULL; + /* We are reallocating memory for `sfnt', so its pointer may change. */ + FT_Byte* sfnt = *sfnt_bytes; - /* 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 dest_offset = 12 + num_tables * 16UL; FT_ULong checksum = 0; FT_ULong loca_checksum = 0; @@ -333,7 +398,6 @@ } } - FT_UNUSED( dst_offset ); FT_UNUSED( loca_checksum ); FT_UNUSED( checksum ); @@ -351,12 +415,14 @@ 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(( "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 ); @@ -370,6 +436,7 @@ return FT_THROW( Invalid_Table ); } + checksum = 0; if( ( table.flags & WOFF2_FLAGS_TRANSFORM ) != WOFF2_FLAGS_TRANSFORM ) { /* Check if `head' is atleast 12 bytes. */ @@ -377,12 +444,30 @@ { if( table.src_length < 12 ) return FT_THROW( Invalid_Table ); + buf_cursor = transformed_buf + table.src_offset + 8; + WRITE_ULONG( buf_cursor, 0 ); } + table.dst_offset = dest_offset; + checksum = compute_ULong_sum( transformed_buf + table.src_offset, + table.src_length ); + /* DEBUG - Remove later */ + FT_TRACE2(( "Checksum = %u\n", checksum )); + + if( WRITE_SFNT_BUF( transformed_buf + table.src_offset, + table.src_length ) ) + return FT_THROW( Invalid_Table ); + } + else{ + /* DEBUG - Remove later */ + FT_TRACE2(( "This table has xform.\n" )); + + /* TODO reconstruct transformed font tables! */ } } - /* TODO reconstruct the font tables! */ + /* Set pointer of sfnt stream to its correct value. */ + *sfnt_bytes = sfnt; return FT_Err_Ok; } @@ -793,7 +878,7 @@ /* TODO Write table entries. */ reconstruct_font( uncompressed_buf, woff2.uncompressed_size, - indices, &woff2, sfnt, memory ); + indices, &woff2, &sfnt, memory ); error = FT_THROW( Unimplemented_Feature ); /* DEBUG - Remove later */ @@ -821,6 +906,7 @@ #undef ROUND4 #undef WRITE_USHORT #undef WRITE_ULONG +#undef WRITE_SFNT_BUF /* END */ diff --git a/src/sfnt/woff2tags.h b/src/sfnt/woff2tags.h index 6579b859d..422567dac 100644 --- a/src/sfnt/woff2tags.h +++ b/src/sfnt/woff2tags.h @@ -33,6 +33,9 @@ FT_BEGIN_HEADER #define WOFF2_SFNT_HEADER_SIZE 12 #define WOFF2_SFNT_ENTRY_SIZE 16 + /* Suggested max size for output. */ +#define WOFF2_DEFAULT_MAX_SIZE 30 * 1024 * 1024 + FT_LOCAL( FT_ULong ) woff2_known_tags( FT_Byte index );