/* synthesized into a TTC with one offset table. */ static FT_Error sfnt_open_font(FT_Stream stream, TT_Face face) { FT_Memory memory = stream->memory; FT_Error error; FT_ULong tag, offset; static const FT_Frame_Field ttc_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TTC_HeaderRec FT_FRAME_START(8), FT_FRAME_LONG(version), FT_FRAME_LONG(count), FT_FRAME_END }; face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; offset = FT_STREAM_POS(); if (FT_READ_ULONG(tag)) return error; if (tag != 0x00010000UL && tag != TTAG_ttcf && tag != TTAG_OTTO && tag != TTAG_true && tag != TTAG_typ1 && tag != 0x00020000UL) return SFNT_Err_Unknown_File_Format; face->ttc_header.tag = TTAG_ttcf; if (tag == TTAG_ttcf) { FT_Int n; FT_TRACE3(("sfnt_open_font: file is a collection\n")); if (FT_STREAM_READ_FIELDS(ttc_header_fields, &face->ttc_header)) return error; /* now read the offsets of each font in the file */ if (FT_NEW_ARRAY(face->ttc_header.offsets, face->ttc_header.count)) return error; if (FT_FRAME_ENTER(face->ttc_header.count * 4L)) return error; for (n = 0; n < face->ttc_header.count; n++) face->ttc_header.offsets[n] = FT_GET_ULONG(); FT_FRAME_EXIT(); } else { FT_TRACE3(("sfnt_open_font: synthesize TTC\n")); face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; if (FT_NEW(face->ttc_header.offsets)) return error; face->ttc_header.offsets[0] = offset; } return error; }
static FT_Error check_table_dir( SFNT_Header sfnt, FT_Stream stream ) { FT_Error error; FT_UInt nn, valid_entries = 0; FT_UInt has_head = 0, has_sing = 0, has_meta = 0; FT_ULong offset = sfnt->offset + 12; static const FT_Frame_Field table_dir_entry_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_TableRec FT_FRAME_START( 16 ), FT_FRAME_ULONG( Tag ), FT_FRAME_ULONG( CheckSum ), FT_FRAME_ULONG( Offset ), FT_FRAME_ULONG( Length ), FT_FRAME_END }; if ( FT_STREAM_SEEK( offset ) ) goto Exit; for ( nn = 0; nn < sfnt->num_tables; nn++ ) { TT_TableRec table; if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) { nn--; FT_TRACE2(( "check_table_dir:" " can read only %d table%s in font (instead of %d)\n", nn, nn == 1 ? "" : "s", sfnt->num_tables )); sfnt->num_tables = nn; break; } /* we ignore invalid tables */ if ( table.Offset + table.Length > stream->size ) { FT_TRACE2(( "check_table_dir: table entry %d invalid\n", nn )); continue; } else valid_entries++; if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) { FT_UInt32 magic; #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS if ( table.Tag == TTAG_head ) #endif has_head = 1; /* * The table length should be 0x36, but certain font tools make it * 0x38, so we will just check that it is greater. * * Note that according to the specification, the table must be * padded to 32-bit lengths, but this doesn't apply to the value of * its `Length' field! * */ if ( table.Length < 0x36 ) { FT_TRACE2(( "check_table_dir: `head' table too small\n" )); error = SFNT_Err_Table_Missing; goto Exit; } if ( FT_STREAM_SEEK( table.Offset + 12 ) || FT_READ_ULONG( magic ) ) goto Exit; if ( magic != 0x5F0F3CF5UL ) { FT_TRACE2(( "check_table_dir:" " no magic number found in `head' table\n")); error = SFNT_Err_Table_Missing; goto Exit; } if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) goto Exit; } else if ( table.Tag == TTAG_SING ) has_sing = 1; else if ( table.Tag == TTAG_META ) has_meta = 1; } sfnt->num_tables = valid_entries; if ( sfnt->num_tables == 0 ) { FT_TRACE2(( "check_table_dir: no tables found\n" )); error = SFNT_Err_Unknown_File_Format; goto Exit; } /* if `sing' and `meta' tables are present, there is no `head' table */ if ( has_head || ( has_sing && has_meta ) ) { error = SFNT_Err_Ok; goto Exit; } else { FT_TRACE2(( "check_table_dir:" )); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS FT_TRACE2(( " neither `head', `bhed', nor `sing' table found\n" )); #else FT_TRACE2(( " neither `head' nor `sing' table found\n" )); #endif error = SFNT_Err_Table_Missing; } Exit: return error; }
tt_face_load_font_dir( TT_Face face, FT_Stream stream ) { SFNT_HeaderRec sfnt; FT_Error error; FT_Memory memory = stream->memory; TT_TableRec* entry; FT_Int nn; static const FT_Frame_Field offset_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE SFNT_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_USHORT( num_tables ), FT_FRAME_USHORT( search_range ), FT_FRAME_USHORT( entry_selector ), FT_FRAME_USHORT( range_shift ), FT_FRAME_END }; FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); /* read the offset table */ sfnt.offset = FT_STREAM_POS(); if ( FT_READ_ULONG( sfnt.format_tag ) || FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) goto Exit; /* many fonts don't have these fields set correctly */ #if 0 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) return SFNT_Err_Unknown_File_Format; #endif /* load the table directory */ FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); /* check first */ error = check_table_dir( &sfnt, stream ); if ( error ) { FT_TRACE2(( "tt_face_load_font_dir:" " invalid table directory for TrueType\n" )); goto Exit; } face->num_tables = sfnt.num_tables; face->format_tag = sfnt.format_tag; if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) goto Exit; if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || FT_FRAME_ENTER( face->num_tables * 16L ) ) goto Exit; entry = face->dir_tables; for ( nn = 0; nn < sfnt.num_tables; nn++ ) { entry->Tag = FT_GET_TAG4(); entry->CheckSum = FT_GET_ULONG(); entry->Offset = FT_GET_LONG(); entry->Length = FT_GET_LONG(); /* ignore invalid tables */ if ( entry->Offset + entry->Length > stream->size ) continue; else { FT_TRACE2(( " %c%c%c%c - %08lx - %08lx\n", (FT_Char)( entry->Tag >> 24 ), (FT_Char)( entry->Tag >> 16 ), (FT_Char)( entry->Tag >> 8 ), (FT_Char)( entry->Tag ), entry->Offset, entry->Length )); entry++; } } FT_FRAME_EXIT(); FT_TRACE2(( "table directory loaded\n\n" )); Exit: return error; }
static FT_Error pcf_get_properties( FT_Stream stream, PCF_Face face ) { PCF_ParseProperty props = 0; PCF_Property properties; FT_UInt nprops, i; FT_ULong format, size; FT_Error error; FT_Memory memory = FT_FACE(face)->memory; FT_ULong string_size; FT_String* strings = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_PROPERTIES, &format, &size ); if ( error ) goto Bail; if ( FT_READ_ULONG_LE( format ) ) goto Bail; FT_TRACE4(( "pcf_get_properties:\n" )); FT_TRACE4(( " format = %ld\n", format )); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) goto Bail; if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nprops ); else (void)FT_READ_ULONG_LE( nprops ); if ( error ) goto Bail; FT_TRACE4(( " nprop = %d\n", nprops )); /* rough estimate */ if ( nprops > size / PCF_PROPERTY_SIZE ) { error = PCF_Err_Invalid_Table; goto Bail; } face->nprops = nprops; if ( FT_NEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) goto Bail; } else { if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) goto Bail; } } /* pad the property array */ /* */ /* clever here - nprops is the same as the number of odd-units read, */ /* as only isStringProp are odd length (Keith Packard) */ /* */ if ( nprops & 3 ) { i = 4 - ( nprops & 3 ); if ( FT_STREAM_SKIP( i ) ) { error = PCF_Err_Invalid_Stream_Skip; goto Bail; } } if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( string_size ); else (void)FT_READ_ULONG_LE( string_size ); if ( error ) goto Bail; FT_TRACE4(( " string_size = %ld\n", string_size )); /* rough estimate */ if ( string_size > size - nprops * PCF_PROPERTY_SIZE ) { error = PCF_Err_Invalid_Table; goto Bail; } if ( FT_NEW_ARRAY( strings, string_size ) ) goto Bail; error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); if ( error ) goto Bail; if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; face->properties = properties; for ( i = 0; i < nprops; i++ ) { FT_Long name_offset = props[i].name; if ( ( name_offset < 0 ) || ( (FT_ULong)name_offset > string_size ) ) { error = PCF_Err_Invalid_Offset; goto Bail; } if ( FT_STRDUP( properties[i].name, strings + name_offset ) ) goto Bail; FT_TRACE4(( " %s:", properties[i].name )); properties[i].isString = props[i].isString; if ( props[i].isString ) { FT_Long value_offset = props[i].value; if ( ( value_offset < 0 ) || ( (FT_ULong)value_offset > string_size ) ) { error = PCF_Err_Invalid_Offset; goto Bail; } if ( FT_STRDUP( properties[i].value.atom, strings + value_offset ) ) goto Bail; FT_TRACE4(( " `%s'\n", properties[i].value.atom )); } else { properties[i].value.integer = props[i].value; FT_TRACE4(( " %d\n", properties[i].value.integer )); } } error = PCF_Err_Ok; Bail: FT_FREE( props ); FT_FREE( strings ); return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format, size; PCF_Metric metrics = 0; FT_ULong nmetrics, i; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; if ( FT_READ_ULONG_LE( format ) ) goto Bail; if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return PCF_Err_Invalid_File_Format; if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error ) return PCF_Err_Invalid_File_Format; face->nmetrics = nmetrics; FT_TRACE4(( "pcf_get_metrics:\n" )); FT_TRACE4(( " number of metrics: %d\n", nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( nmetrics > size / PCF_METRIC_SIZE ) return PCF_Err_Invalid_Table; } else { if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) return PCF_Err_Invalid_Table; } if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return PCF_Err_Out_Of_Memory; metrics = face->metrics; for ( i = 0; i < nmetrics; i++ ) { error = pcf_get_metric( stream, format, metrics + i ); metrics[i].bits = 0; FT_TRACE5(( " idx %d: width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, ( metrics + i )->characterWidth, ( metrics + i )->leftSideBearing, ( metrics + i )->rightSideBearing, ( metrics + i )->ascent, ( metrics + i )->descent, ( metrics + i )->attributes )); if ( error ) break; } if ( error ) FT_FREE( face->metrics ); Bail: return error; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error; FT_Memory memory = FT_FACE( face )->memory; FT_ULong format, size; PCF_Metric metrics = 0; FT_ULong nmetrics, i; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; if ( FT_READ_ULONG_LE( format ) ) goto Bail; if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return FT_THROW( Invalid_File_Format ); if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error ) return FT_THROW( Invalid_File_Format ); face->nmetrics = nmetrics; if ( !nmetrics ) return FT_THROW( Invalid_Table ); FT_TRACE4(( "pcf_get_metrics:\n" )); FT_TRACE4(( " number of metrics: %d\n", nmetrics )); /* rough estimate */ if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( nmetrics > size / PCF_METRIC_SIZE ) return FT_THROW( Invalid_Table ); } else { if ( nmetrics > size / PCF_COMPRESSED_METRIC_SIZE ) return FT_THROW( Invalid_Table ); } if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return FT_THROW( Out_Of_Memory ); metrics = face->metrics; for ( i = 0; i < nmetrics; i++, metrics++ ) { error = pcf_get_metric( stream, format, metrics ); metrics->bits = 0; FT_TRACE5(( " idx %d: width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, metrics->characterWidth, metrics->leftSideBearing, metrics->rightSideBearing, metrics->ascent, metrics->descent, metrics->attributes )); if ( error ) break; /* sanity checks -- those values are used in `PCF_Glyph_Load' to */ /* compute a glyph's bitmap dimensions, thus setting them to zero in */ /* case of an error disables this particular glyph only */ if ( metrics->rightSideBearing < metrics->leftSideBearing || metrics->ascent + metrics->descent < 0 ) { metrics->characterWidth = 0; metrics->leftSideBearing = 0; metrics->rightSideBearing = 0; metrics->ascent = 0; metrics->descent = 0; FT_TRACE0(( "pcf_get_metrics:" " invalid metrics for glyph %d\n", i )); } } if ( error ) FT_FREE( face->metrics ); Bail: return error; }
tt_face_load_font_dir( TT_Face face, FT_Stream stream ) { SFNT_HeaderRec sfnt; FT_Error error; FT_Memory memory = stream->memory; TT_TableRec* entry; FT_Int nn; static const FT_Frame_Field offset_table_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE SFNT_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_USHORT( num_tables ), FT_FRAME_USHORT( search_range ), FT_FRAME_USHORT( entry_selector ), FT_FRAME_USHORT( range_shift ), FT_FRAME_END }; FT_TRACE2(( "tt_face_load_font_dir: %08p\n", face )); /* read the offset table */ sfnt.offset = FT_STREAM_POS(); if ( FT_READ_ULONG( sfnt.format_tag ) || FT_STREAM_READ_FIELDS( offset_table_fields, &sfnt ) ) goto Exit; /* many fonts don't have these fields set correctly */ #if 0 if ( sfnt.search_range != 1 << ( sfnt.entry_selector + 4 ) || sfnt.search_range + sfnt.range_shift != sfnt.num_tables << 4 ) return FT_THROW( Unknown_File_Format ); #endif /* load the table directory */ FT_TRACE2(( "-- Number of tables: %10u\n", sfnt.num_tables )); FT_TRACE2(( "-- Format version: 0x%08lx\n", sfnt.format_tag )); if ( sfnt.format_tag != TTAG_OTTO ) { /* check first */ error = check_table_dir( &sfnt, stream ); if ( error ) { FT_TRACE2(( "tt_face_load_font_dir:" " invalid table directory for TrueType\n" )); goto Exit; } } face->num_tables = sfnt.num_tables; face->format_tag = sfnt.format_tag; if ( FT_QNEW_ARRAY( face->dir_tables, face->num_tables ) ) goto Exit; if ( FT_STREAM_SEEK( sfnt.offset + 12 ) || FT_FRAME_ENTER( face->num_tables * 16L ) ) goto Exit; entry = face->dir_tables; FT_TRACE2(( "\n" " tag offset length checksum\n" " ----------------------------------\n" )); for ( nn = 0; nn < sfnt.num_tables; nn++ ) { entry->Tag = FT_GET_TAG4(); entry->CheckSum = FT_GET_ULONG(); entry->Offset = FT_GET_ULONG(); entry->Length = FT_GET_ULONG(); /* ignore invalid tables that can't be sanitized */ if ( entry->Offset > stream->size ) continue; else if ( entry->Length > stream->size - entry->Offset ) { if ( entry->Tag == TTAG_hmtx || entry->Tag == TTAG_vmtx ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_ULong old_length = entry->Length; #endif /* make metrics table length a multiple of 4 */ entry->Length = ( stream->size - entry->Offset ) & ~3U; FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx" " (sanitized; original length %08lx)\n", (FT_Char)( entry->Tag >> 24 ), (FT_Char)( entry->Tag >> 16 ), (FT_Char)( entry->Tag >> 8 ), (FT_Char)( entry->Tag ), entry->Offset, entry->Length, entry->CheckSum, old_length )); entry++; } else continue; }
static FT_Error pcf_get_metrics( FT_Stream stream, PCF_Face face ) { FT_Error error = PCF_Err_Ok; FT_Memory memory = FT_FACE(face)->memory; FT_ULong format = 0; FT_ULong size = 0; PCF_Metric metrics = 0; int i; int nmetrics = -1; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_METRICS, &format, &size ); if ( error ) return error; error = FT_READ_ULONG_LE( format ); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) && !PCF_FORMAT_MATCH( format, PCF_COMPRESSED_METRICS ) ) return PCF_Err_Invalid_File_Format; if ( PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nmetrics ); else (void)FT_READ_ULONG_LE( nmetrics ); } else { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_USHORT( nmetrics ); else (void)FT_READ_USHORT_LE( nmetrics ); } if ( error || nmetrics == -1 ) return PCF_Err_Invalid_File_Format; face->nmetrics = nmetrics; if ( FT_NEW_ARRAY( face->metrics, nmetrics ) ) return PCF_Err_Out_Of_Memory; metrics = face->metrics; for ( i = 0; i < nmetrics; i++ ) { pcf_get_metric( stream, format, metrics + i ); metrics[i].bits = 0; FT_TRACE4(( "%d : width=%d, " "lsb=%d, rsb=%d, ascent=%d, descent=%d, swidth=%d\n", i, ( metrics + i )->characterWidth, ( metrics + i )->leftSideBearing, ( metrics + i )->rightSideBearing, ( metrics + i )->ascent, ( metrics + i )->descent, ( metrics + i )->attributes )); if ( error ) break; } if ( error ) FT_FREE( face->metrics ); return error; }
static FT_Error pcf_get_properties( FT_Stream stream, PCF_Face face ) { PCF_ParseProperty props = 0; PCF_Property properties = 0; FT_Int nprops, i; FT_ULong format, size; FT_Error error; FT_Memory memory = FT_FACE(face)->memory; FT_ULong string_size; FT_String* strings = 0; error = pcf_seek_to_table_type( stream, face->toc.tables, face->toc.count, PCF_PROPERTIES, &format, &size ); if ( error ) goto Bail; if ( FT_READ_ULONG_LE( format ) ) goto Bail; FT_TRACE4(( "get_prop: format = %ld\n", format )); if ( !PCF_FORMAT_MATCH( format, PCF_DEFAULT_FORMAT ) ) goto Bail; if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( nprops ); else (void)FT_READ_ULONG_LE( nprops ); if ( error ) goto Bail; FT_TRACE4(( "get_prop: nprop = %d\n", nprops )); if ( FT_NEW_ARRAY( props, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { if ( PCF_BYTE_ORDER( format ) == MSBFirst ) { if ( FT_STREAM_READ_FIELDS( pcf_property_msb_header, props + i ) ) goto Bail; } else { if ( FT_STREAM_READ_FIELDS( pcf_property_header, props + i ) ) goto Bail; } } /* pad the property array */ /* */ /* clever here - nprops is the same as the number of odd-units read, */ /* as only isStringProp are odd length (Keith Packard) */ /* */ if ( nprops & 3 ) { i = 4 - ( nprops & 3 ); FT_Stream_Skip( stream, i ); } if ( PCF_BYTE_ORDER( format ) == MSBFirst ) (void)FT_READ_ULONG( string_size ); else (void)FT_READ_ULONG_LE( string_size ); if ( error ) goto Bail; FT_TRACE4(( "get_prop: string_size = %ld\n", string_size )); if ( FT_NEW_ARRAY( strings, string_size ) ) goto Bail; error = FT_Stream_Read( stream, (FT_Byte*)strings, string_size ); if ( error ) goto Bail; if ( FT_NEW_ARRAY( properties, nprops ) ) goto Bail; for ( i = 0; i < nprops; i++ ) { /* XXX: make atom */ if ( FT_NEW_ARRAY( properties[i].name, ft_strlen( strings + props[i].name ) + 1 ) ) goto Bail; ft_strcpy( properties[i].name,strings + props[i].name ); properties[i].isString = props[i].isString; if ( props[i].isString ) { if ( FT_NEW_ARRAY( properties[i].value.atom, ft_strlen( strings + props[i].value ) + 1 ) ) goto Bail; ft_strcpy( properties[i].value.atom, strings + props[i].value ); } else properties[i].value.integer = props[i].value; } face->properties = properties; face->nprops = nprops; FT_FREE( props ); FT_FREE( strings ); return PCF_Err_Ok; Bail: FT_FREE( props ); FT_FREE( strings ); return error; }
/* synthesized into a TTC with one offset table. */ static FT_Error sfnt_open_font( FT_Stream stream, TT_Face face ) { FT_Memory memory = stream->memory; FT_Error error; FT_ULong tag, offset; static const FT_Frame_Field ttc_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TTC_HeaderRec FT_FRAME_START( 8 ), FT_FRAME_LONG( version ), FT_FRAME_LONG( count ), /* this is ULong in the specs */ FT_FRAME_END }; face->ttc_header.tag = 0; face->ttc_header.version = 0; face->ttc_header.count = 0; offset = FT_STREAM_POS(); if ( FT_READ_ULONG( tag ) ) return error; if ( tag != 0x00010000UL && tag != TTAG_ttcf && tag != TTAG_OTTO && tag != TTAG_true && tag != TTAG_typ1 && tag != 0x00020000UL ) { FT_TRACE2(( " not a font using the SFNT container format\n" )); return FT_THROW( Unknown_File_Format ); } face->ttc_header.tag = TTAG_ttcf; if ( tag == TTAG_ttcf ) { FT_Int n; FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) return error; if ( face->ttc_header.count == 0 ) return FT_THROW( Invalid_Table ); /* a rough size estimate: let's conservatively assume that there */ /* is just a single table info in each subfont header (12 + 16*1 = */ /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ /* size of the TTC header plus `28*count' bytes for all subfont */ /* headers */ if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ if ( FT_NEW_ARRAY( face->ttc_header.offsets, face->ttc_header.count ) ) return error; if ( FT_FRAME_ENTER( face->ttc_header.count * 4L ) ) return error; for ( n = 0; n < face->ttc_header.count; n++ ) face->ttc_header.offsets[n] = FT_GET_ULONG(); FT_FRAME_EXIT(); } else { FT_TRACE3(( "sfnt_open_font: synthesize TTC\n" )); face->ttc_header.version = 1 << 16; face->ttc_header.count = 1; if ( FT_NEW( face->ttc_header.offsets ) ) return error; face->ttc_header.offsets[0] = offset; } return error; }
static FT_Error check_table_dir( SFNT_Header sfnt, FT_Stream stream ) { FT_Error error; FT_UInt nn; FT_UInt has_head = 0, has_sing = 0, has_meta = 0; FT_ULong offset = sfnt->offset + 12; const FT_ULong glyx_tag = FT_MAKE_TAG( 'g', 'l', 'y', 'x' ); const FT_ULong locx_tag = FT_MAKE_TAG( 'l', 'o', 'c', 'x' ); static const FT_Frame_Field table_dir_entry_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_TableRec FT_FRAME_START( 16 ), FT_FRAME_ULONG( Tag ), FT_FRAME_ULONG( CheckSum ), FT_FRAME_ULONG( Offset ), FT_FRAME_ULONG( Length ), FT_FRAME_END }; if ( sfnt->num_tables == 0 || offset + sfnt->num_tables * 16 > stream->size ) return SFNT_Err_Unknown_File_Format; if ( FT_STREAM_SEEK( offset ) ) return error; for ( nn = 0; nn < sfnt->num_tables; nn++ ) { TT_TableRec table; if ( FT_STREAM_READ_FIELDS( table_dir_entry_fields, &table ) ) return error; if ( table.Offset + table.Length > stream->size && table.Tag != glyx_tag && table.Tag != locx_tag ) return SFNT_Err_Unknown_File_Format; if ( table.Tag == TTAG_head || table.Tag == TTAG_bhed ) { FT_UInt32 magic; #ifndef TT_CONFIG_OPTION_EMBEDDED_BITMAPS if ( table.Tag == TTAG_head ) #endif has_head = 1; /* * The table length should be 0x36, but certain font tools make it * 0x38, so we will just check that it is greater. * * Note that according to the specification, the table must be * padded to 32-bit lengths, but this doesn't apply to the value of * its `Length' field! * */ if ( table.Length < 0x36 ) return SFNT_Err_Unknown_File_Format; if ( FT_STREAM_SEEK( table.Offset + 12 ) || FT_READ_ULONG( magic ) ) return error; if ( magic != 0x5F0F3CF5UL ) return SFNT_Err_Unknown_File_Format; if ( FT_STREAM_SEEK( offset + ( nn + 1 ) * 16 ) ) return error; } else if ( table.Tag == TTAG_SING ) has_sing = 1; else if ( table.Tag == TTAG_META ) has_meta = 1; } /* if `sing' and `meta' tables are present, there is no `head' table */ if ( has_head || ( has_sing && has_meta ) ) return SFNT_Err_Ok; else return SFNT_Err_Unknown_File_Format; }
TT_CharMap_Load( TT_Face face, TT_CMapTable cmap, FT_Stream stream ) { FT_Error error; FT_Memory memory; FT_UShort num_SH, num_Seg, i; FT_ULong j, n; FT_UShort u, l; TT_CMap0 cmap0; TT_CMap2 cmap2; TT_CMap4 cmap4; TT_CMap6 cmap6; TT_CMap8_12 cmap8_12; TT_CMap10 cmap10; TT_CMap2SubHeader cmap2sub; TT_CMap4Segment segments; TT_CMapGroup groups; if ( cmap->loaded ) return SFNT_Err_Ok; memory = stream->memory; if ( FT_STREAM_SEEK( cmap->offset ) ) return error; switch ( cmap->format ) { case 0: cmap0 = &cmap->c.cmap0; if ( FT_READ_USHORT( cmap0->language ) || FT_ALLOC( cmap0->glyphIdArray, 256L ) || FT_STREAM_READ( cmap0->glyphIdArray, 256L ) ) goto Fail; cmap->get_index = code_to_index0; cmap->get_next_char = code_to_next0; break; case 2: num_SH = 0; cmap2 = &cmap->c.cmap2; /* allocate subheader keys */ if ( FT_NEW_ARRAY( cmap2->subHeaderKeys, 256 ) || FT_FRAME_ENTER( 2L + 512L ) ) goto Fail; cmap2->language = FT_GET_USHORT(); for ( i = 0; i < 256; i++ ) { u = (FT_UShort)( FT_GET_USHORT() / 8 ); cmap2->subHeaderKeys[i] = u; if ( num_SH < u ) num_SH = u; } FT_FRAME_EXIT(); /* load subheaders */ cmap2->numGlyphId = l = (FT_UShort)( ( ( cmap->length - 2L * ( 256 + 3 ) - num_SH * 8L ) & 0xFFFFU ) / 2 ); if ( FT_NEW_ARRAY( cmap2->subHeaders, num_SH + 1 ) || FT_FRAME_ENTER( ( num_SH + 1 ) * 8L ) ) { FT_FREE( cmap2->subHeaderKeys ); goto Fail; } cmap2sub = cmap2->subHeaders; for ( i = 0; i <= num_SH; i++ ) { cmap2sub->firstCode = FT_GET_USHORT(); cmap2sub->entryCount = FT_GET_USHORT(); cmap2sub->idDelta = FT_GET_SHORT(); /* we apply the location offset immediately */ cmap2sub->idRangeOffset = (FT_UShort)( FT_GET_USHORT() - ( num_SH - i ) * 8 - 2 ); cmap2sub++; } FT_FRAME_EXIT(); /* load glyph IDs */ if ( FT_NEW_ARRAY( cmap2->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap2->subHeaders ); FT_FREE( cmap2->subHeaderKeys ); goto Fail; } for ( i = 0; i < l; i++ ) cmap2->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index2; cmap->get_next_char = code_to_next2; break; case 4: cmap4 = &cmap->c.cmap4; /* load header */ if ( FT_FRAME_ENTER( 10L ) ) goto Fail; cmap4->language = FT_GET_USHORT(); cmap4->segCountX2 = FT_GET_USHORT(); cmap4->searchRange = FT_GET_USHORT(); cmap4->entrySelector = FT_GET_USHORT(); cmap4->rangeShift = FT_GET_USHORT(); num_Seg = (FT_UShort)( cmap4->segCountX2 / 2 ); FT_FRAME_EXIT(); /* load segments */ if ( FT_NEW_ARRAY( cmap4->segments, num_Seg ) || FT_FRAME_ENTER( ( num_Seg * 4 + 1 ) * 2L ) ) goto Fail; segments = cmap4->segments; for ( i = 0; i < num_Seg; i++ ) segments[i].endCount = FT_GET_USHORT(); (void)FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].startCount = FT_GET_USHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idDelta = FT_GET_SHORT(); for ( i = 0; i < num_Seg; i++ ) segments[i].idRangeOffset = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->numGlyphId = l = (FT_UShort)( ( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xFFFFU ) / 2 ); /* load IDs */ if ( FT_NEW_ARRAY( cmap4->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) { FT_FREE( cmap4->segments ); goto Fail; } for ( i = 0; i < l; i++ ) cmap4->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap4->last_segment = cmap4->segments; cmap->get_index = code_to_index4; cmap->get_next_char = code_to_next4; break; case 6: cmap6 = &cmap->c.cmap6; if ( FT_FRAME_ENTER( 6L ) ) goto Fail; cmap6->language = FT_GET_USHORT(); cmap6->firstCode = FT_GET_USHORT(); cmap6->entryCount = FT_GET_USHORT(); FT_FRAME_EXIT(); l = cmap6->entryCount; if ( FT_NEW_ARRAY( cmap6->glyphIdArray, l ) || FT_FRAME_ENTER( l * 2L ) ) goto Fail; for ( i = 0; i < l; i++ ) cmap6->glyphIdArray[i] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index6; cmap->get_next_char = code_to_next6; break; case 8: case 12: cmap8_12 = &cmap->c.cmap8_12; if ( FT_FRAME_ENTER( 8L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap8_12->language = FT_GET_ULONG(); FT_FRAME_EXIT(); if ( cmap->format == 8 ) if ( FT_STREAM_SKIP( 8192L ) ) goto Fail; if ( FT_READ_ULONG( cmap8_12->nGroups ) ) goto Fail; n = cmap8_12->nGroups; if ( FT_NEW_ARRAY( cmap8_12->groups, n ) || FT_FRAME_ENTER( n * 3 * 4L ) ) goto Fail; groups = cmap8_12->groups; for ( j = 0; j < n; j++ ) { groups[j].startCharCode = FT_GET_ULONG(); groups[j].endCharCode = FT_GET_ULONG(); groups[j].startGlyphID = FT_GET_ULONG(); } FT_FRAME_EXIT(); cmap8_12->last_group = cmap8_12->groups; cmap->get_index = code_to_index8_12; cmap->get_next_char = code_to_next8_12; break; case 10: cmap10 = &cmap->c.cmap10; if ( FT_FRAME_ENTER( 16L ) ) goto Fail; cmap->length = FT_GET_ULONG(); cmap10->language = FT_GET_ULONG(); cmap10->startCharCode = FT_GET_ULONG(); cmap10->numChars = FT_GET_ULONG(); FT_FRAME_EXIT(); n = cmap10->numChars; if ( FT_NEW_ARRAY( cmap10->glyphs, n ) || FT_FRAME_ENTER( n * 2L ) ) goto Fail; for ( j = 0; j < n; j++ ) cmap10->glyphs[j] = FT_GET_USHORT(); FT_FRAME_EXIT(); cmap->get_index = code_to_index10; cmap->get_next_char = code_to_next10; break; default: /* corrupt character mapping table */ return SFNT_Err_Invalid_CharMap_Format; } return SFNT_Err_Ok; Fail: TT_CharMap_Free( face, cmap ); return error; }