tt_face_load_gasp( TT_Face face, FT_Stream stream ) { FT_Error error; FT_Memory memory = stream->memory; FT_UInt j,num_ranges; TT_GaspRange gaspranges; /* the gasp table is optional */ error = face->goto_table( face, TTAG_gasp, stream, 0 ); if ( error ) goto Exit; if ( FT_FRAME_ENTER( 4L ) ) goto Exit; face->gasp.version = FT_GET_USHORT(); face->gasp.numRanges = FT_GET_USHORT(); FT_FRAME_EXIT(); /* only support versions 0 and 1 of the table */ if ( face->gasp.version >= 2 ) { face->gasp.numRanges = 0; error = SFNT_Err_Invalid_Table; goto Exit; } num_ranges = face->gasp.numRanges; FT_TRACE3(( "numRanges: %u\n", num_ranges )); if ( FT_QNEW_ARRAY( gaspranges, num_ranges ) || FT_FRAME_ENTER( num_ranges * 4L ) ) goto Exit; face->gasp.gaspRanges = gaspranges; for ( j = 0; j < num_ranges; j++ ) { gaspranges[j].maxPPEM = FT_GET_USHORT(); gaspranges[j].gaspFlag = FT_GET_USHORT(); FT_TRACE3(( "gaspRange %d: rangeMaxPPEM %5d, rangeGaspBehavior 0x%x\n", j, gaspranges[j].maxPPEM, gaspranges[j].gaspFlag )); } FT_FRAME_EXIT(); Exit: return error; }
/* parse a PFM file -- for now, only read the kerning pairs */ static FT_Error T1_Read_PFM( FT_Face t1_face, FT_Stream stream, AFM_FontInfo fi ) { FT_Error error = FT_Err_Ok; FT_Memory memory = stream->memory; FT_Byte* start; FT_Byte* limit; FT_Byte* p; AFM_KernPair kp; FT_Int width_table_length; FT_CharMap oldcharmap; FT_CharMap charmap; FT_Int n; start = (FT_Byte*)stream->cursor; limit = (FT_Byte*)stream->limit; p = start; /* Figure out how long the width table is. */ /* This info is a little-endian short at offset 99. */ p = start + 99; if ( p + 2 > limit ) { error = FT_THROW( Unknown_File_Format ); goto Exit; } width_table_length = FT_PEEK_USHORT_LE( p ); p += 18 + width_table_length; if ( p + 0x12 > limit || FT_PEEK_USHORT_LE( p ) < 0x12 ) /* extension table is probably optional */ goto Exit; /* Kerning offset is 14 bytes from start of extensions table. */ p += 14; p = start + FT_PEEK_ULONG_LE( p ); if ( p == start ) /* zero offset means no table */ goto Exit; if ( p + 2 > limit ) { error = FT_THROW( Unknown_File_Format ); goto Exit; } fi->NumKernPair = FT_PEEK_USHORT_LE( p ); p += 2; if ( p + 4 * fi->NumKernPair > limit ) { error = FT_THROW( Unknown_File_Format ); goto Exit; } /* Actually, kerning pairs are simply optional! */ if ( fi->NumKernPair == 0 ) goto Exit; /* allocate the pairs */ if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) goto Exit; /* now, read each kern pair */ kp = fi->KernPairs; limit = p + 4 * fi->NumKernPair; /* PFM kerning data are stored by encoding rather than glyph index, */ /* so find the PostScript charmap of this font and install it */ /* temporarily. If we find no PostScript charmap, then just use */ /* the default and hope it is the right one. */ oldcharmap = t1_face->charmap; charmap = NULL; for ( n = 0; n < t1_face->num_charmaps; n++ ) { charmap = t1_face->charmaps[n]; /* check against PostScript pseudo platform */ if ( charmap->platform_id == 7 ) { error = FT_Set_Charmap( t1_face, charmap ); if ( error ) goto Exit; break; } } /* Kerning info is stored as: */ /* */ /* encoding of first glyph (1 byte) */ /* encoding of second glyph (1 byte) */ /* offset (little-endian short) */ for ( ; p < limit ; p += 4 ) { kp->index1 = FT_Get_Char_Index( t1_face, p[0] ); kp->index2 = FT_Get_Char_Index( t1_face, p[1] ); kp->x = (FT_Int)FT_PEEK_SHORT_LE(p + 2); kp->y = 0; kp++; } if ( oldcharmap != NULL ) error = FT_Set_Charmap( t1_face, oldcharmap ); if ( error ) goto Exit; /* now, sort the kern pairs according to their glyph indices */ ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof ( AFM_KernPairRec ), compare_kern_pairs ); Exit: if ( error ) { FT_FREE( fi->KernPairs ); fi->NumKernPair = 0; } return error; }
tt_face_load_hmtx( TT_Face face, FT_Stream stream, FT_Bool vertical ) { FT_Error error; FT_Memory memory = stream->memory; FT_ULong table_len; FT_Long num_shorts, num_longs, num_shorts_checked; TT_LongMetrics* longs; TT_ShortMetrics** shorts; FT_Byte* p; if ( vertical ) { void* lm = &face->vertical.long_metrics; void** sm = &face->vertical.short_metrics; error = face->goto_table( face, TTAG_vmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->vertical.number_Of_VMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->vertical.number_Of_VMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } else { void* lm = &face->horizontal.long_metrics; void** sm = &face->horizontal.short_metrics; error = face->goto_table( face, TTAG_hmtx, stream, &table_len ); if ( error ) goto Fail; num_longs = face->horizontal.number_Of_HMetrics; if ( (FT_ULong)num_longs > table_len / 4 ) num_longs = (FT_Long)( table_len / 4 ); face->horizontal.number_Of_HMetrics = 0; longs = (TT_LongMetrics*)lm; shorts = (TT_ShortMetrics**)sm; } /* never trust derived values */ num_shorts = face->max_profile.numGlyphs - num_longs; num_shorts_checked = ( table_len - num_longs * 4L ) / 2; if ( num_shorts < 0 ) { FT_ERROR(( "%cmtx has more metrics than glyphs.\n" )); /* Adobe simply ignores this problem. So we shall do the same. */ #if 0 error = vertical ? SFNT_Err_Invalid_Vert_Metrics : SFNT_Err_Invalid_Horiz_Metrics; goto Exit; #else num_shorts = 0; #endif } if ( FT_QNEW_ARRAY( *longs, num_longs ) || FT_QNEW_ARRAY( *shorts, num_shorts ) ) goto Fail; if ( FT_FRAME_ENTER( table_len ) ) goto Fail; p = stream->cursor; { TT_LongMetrics cur = *longs; TT_LongMetrics limit = cur + num_longs; for ( ; cur < limit; cur++ ) { cur->advance = FT_NEXT_USHORT( p ); cur->bearing = FT_NEXT_SHORT( p ); } } /* do we have an inconsistent number of metric values? */ { TT_ShortMetrics* cur = *shorts; TT_ShortMetrics* limit = cur + FT_MIN( num_shorts, num_shorts_checked ); for ( ; cur < limit; cur++ ) *cur = FT_NEXT_SHORT( p ); /* We fill up the missing left side bearings with the */ /* last valid value. Since this will occur for buggy CJK */ /* fonts usually only, nothing serious will happen. */ if ( num_shorts > num_shorts_checked && num_shorts_checked > 0 ) { FT_Short val = (*shorts)[num_shorts_checked - 1]; limit = *shorts + num_shorts; for ( ; cur < limit; cur++ ) *cur = val; } } FT_FRAME_EXIT(); if ( vertical ) face->vertical.number_Of_VMetrics = (FT_UShort)num_longs; else face->horizontal.number_Of_HMetrics = (FT_UShort)num_longs; Fail: return error; }
static FT_Error afm_parse_kern_pairs( AFM_Parser parser ) { AFM_FontInfo fi = parser->FontInfo; AFM_KernPair kp; char* key; FT_Offset len; int n = -1; if ( afm_parser_read_int( parser, &fi->NumKernPair ) ) goto Fail; if ( fi->NumKernPair ) { FT_Memory memory = parser->memory; FT_Error error; if ( FT_QNEW_ARRAY( fi->KernPairs, fi->NumKernPair ) ) return error; } while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) { AFM_Token token = afm_tokenize( key, len ); switch ( token ) { case AFM_TOKEN_KP: case AFM_TOKEN_KPX: case AFM_TOKEN_KPY: { FT_Int r; AFM_ValueRec shared_vals[4]; n++; if ( n >= fi->NumKernPair ) goto Fail; kp = fi->KernPairs + n; shared_vals[0].type = AFM_VALUE_TYPE_INDEX; shared_vals[1].type = AFM_VALUE_TYPE_INDEX; shared_vals[2].type = AFM_VALUE_TYPE_INTEGER; shared_vals[3].type = AFM_VALUE_TYPE_INTEGER; r = afm_parser_read_vals( parser, shared_vals, 4 ); if ( r < 3 ) goto Fail; kp->index1 = shared_vals[0].u.i; kp->index2 = shared_vals[1].u.i; if ( token == AFM_TOKEN_KPY ) { kp->x = 0; kp->y = shared_vals[2].u.i; } else { kp->x = shared_vals[2].u.i; kp->y = ( token == AFM_TOKEN_KP && r == 4 ) ? shared_vals[3].u.i : 0; } } break; case AFM_TOKEN_ENDKERNPAIRS: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: fi->NumKernPair = n + 1; ft_qsort( fi->KernPairs, fi->NumKernPair, sizeof( AFM_KernPairRec ), afm_compare_kern_pairs ); return PSaux_Err_Ok; case AFM_TOKEN_UNKNOWN: break; default: goto Fail; } } Fail: return PSaux_Err_Syntax_Error; }
static FT_Error afm_parse_track_kern( AFM_Parser parser ) { AFM_FontInfo fi = parser->FontInfo; AFM_TrackKern tk; char* key; FT_Offset len; int n = -1; if ( afm_parser_read_int( parser, &fi->NumTrackKern ) ) goto Fail; if ( fi->NumTrackKern ) { FT_Memory memory = parser->memory; FT_Error error; if ( FT_QNEW_ARRAY( fi->TrackKerns, fi->NumTrackKern ) ) return error; } while ( ( key = afm_parser_next_key( parser, 1, &len ) ) != 0 ) { AFM_ValueRec shared_vals[5]; switch ( afm_tokenize( key, len ) ) { case AFM_TOKEN_TRACKKERN: n++; if ( n >= fi->NumTrackKern ) goto Fail; tk = fi->TrackKerns + n; shared_vals[0].type = AFM_VALUE_TYPE_INTEGER; shared_vals[1].type = AFM_VALUE_TYPE_FIXED; shared_vals[2].type = AFM_VALUE_TYPE_FIXED; shared_vals[3].type = AFM_VALUE_TYPE_FIXED; shared_vals[4].type = AFM_VALUE_TYPE_FIXED; if ( afm_parser_read_vals( parser, shared_vals, 5 ) != 5 ) goto Fail; tk->degree = shared_vals[0].u.i; tk->min_ptsize = shared_vals[1].u.f; tk->min_kern = shared_vals[2].u.f; tk->max_ptsize = shared_vals[3].u.f; tk->max_kern = shared_vals[4].u.f; /* is this correct? */ if ( tk->degree < 0 && tk->min_kern > 0 ) tk->min_kern = -tk->min_kern; break; case AFM_TOKEN_ENDTRACKKERN: case AFM_TOKEN_ENDKERNDATA: case AFM_TOKEN_ENDFONTMETRICS: fi->NumTrackKern = n + 1; return PSaux_Err_Ok; case AFM_TOKEN_UNKNOWN: break; default: goto Fail; } } Fail: return PSaux_Err_Syntax_Error; }
static FT_Error tt_face_get_name(TT_Face face, FT_UShort nameid, FT_String **name) { FT_Memory memory = face->root.memory; FT_Error error = SFNT_Err_Ok; FT_String *result = NULL; FT_UShort n; TT_NameEntryRec *rec; FT_Int found_apple = -1; FT_Int found_apple_roman = -1; FT_Int found_apple_english = -1; FT_Int found_win = -1; FT_Int found_unicode = -1; FT_Bool is_english = 0; TT_NameEntry_ConvertFunc convert; FT_ASSERT(name); rec = face->name_table.names; for (n = 0; n < face->num_names; n++, rec++) { /* According to the OpenType 1.3 specification, only Microsoft or */ /* Apple platform IDs might be used in the `name' table. The */ /* `Unicode' platform is reserved for the `cmap' table, and the */ /* `ISO' one is deprecated. */ /* */ /* However, the Apple TrueType specification doesn't say the same */ /* thing and goes to suggest that all Unicode `name' table entries */ /* should be coded in UTF-16 (in big-endian format I suppose). */ /* */ if (rec->nameID == nameid && rec->stringLength > 0) { switch (rec->platformID) { case TT_PLATFORM_APPLE_UNICODE: case TT_PLATFORM_ISO: /* there is `languageID' to check there. We should use this */ /* field only as a last solution when nothing else is */ /* available. */ /* */ found_unicode = n; break; case TT_PLATFORM_MACINTOSH: /* This is a bit special because some fonts will use either */ /* an English language id, or a Roman encoding id, to indicate */ /* the English version of its font name. */ /* */ if (rec->languageID == TT_MAC_LANGID_ENGLISH) found_apple_english = n; else if (rec->encodingID == TT_MAC_ID_ROMAN) found_apple_roman = n; break; case TT_PLATFORM_MICROSOFT: /* we only take a non-English name when there is nothing */ /* else available in the font */ /* */ if (found_win == -1 || (rec->languageID & 0x3FF) == 0x009) { switch (rec->encodingID) { case TT_MS_ID_SYMBOL_CS: case TT_MS_ID_UNICODE_CS: case TT_MS_ID_UCS_4: is_english = FT_BOOL((rec->languageID & 0x3FF) == 0x009); found_win = n; break; default: ; } } break; default: ; } } } found_apple = found_apple_roman; if (found_apple_english >= 0) found_apple = found_apple_english; /* some fonts contain invalid Unicode or Macintosh formatted entries; */ /* we will thus favor names encoded in Windows formats if available */ /* (provided it is an English name) */ /* */ convert = NULL; if (found_win >= 0 && !(found_apple >= 0 && !is_english)) { rec = face->name_table.names + found_win; switch (rec->encodingID) { /* all Unicode strings are encoded using UTF-16BE */ case TT_MS_ID_UNICODE_CS: case TT_MS_ID_SYMBOL_CS: convert = tt_name_entry_ascii_from_utf16; break; case TT_MS_ID_UCS_4: /* Apparently, if this value is found in a name table entry, it is */ /* documented as `full Unicode repertoire'. Experience with the */ /* MsGothic font shipped with Windows Vista shows that this really */ /* means UTF-16 encoded names (UCS-4 values are only used within */ /* charmaps). */ convert = tt_name_entry_ascii_from_utf16; break; default: ; } } else if (found_apple >= 0) { rec = face->name_table.names + found_apple; convert = tt_name_entry_ascii_from_other; } else if (found_unicode >= 0) { rec = face->name_table.names + found_unicode; convert = tt_name_entry_ascii_from_utf16; } if (rec && convert) { if (rec->string == NULL) { FT_Stream stream = face->name_table.stream; if (FT_QNEW_ARRAY (rec->string, rec->stringLength) || FT_STREAM_SEEK(rec->stringOffset) || FT_STREAM_READ(rec->string, rec->stringLength)) { FT_FREE(rec->string); rec->stringLength = 0; result = NULL; goto Exit; } } result = convert(rec, memory); } Exit: *name = result; 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_String* tt_face_get_name( TT_Face face, FT_UShort nameid ) { FT_Memory memory = face->root.memory; FT_String* result = NULL; FT_UShort n; TT_NameEntryRec* rec; FT_Int found_apple = -1; FT_Int found_win = -1; FT_Int found_unicode = -1; FT_Bool is_english = 0; TT_NameEntry_ConvertFunc convert; rec = face->name_table.names; for ( n = 0; n < face->num_names; n++, rec++ ) { /* According to the OpenType 1.3 specification, only Microsoft or */ /* Apple platform IDs might be used in the `name' table. The */ /* `Unicode' platform is reserved for the `cmap' table, and the */ /* `Iso' one is deprecated. */ /* */ /* However, the Apple TrueType specification doesn't say the same */ /* thing and goes to suggest that all Unicode `name' table entries */ /* should be coded in UTF-16 (in big-endian format I suppose). */ /* */ if ( rec->nameID == nameid && rec->stringLength > 0 ) { switch ( rec->platformID ) { case TT_PLATFORM_APPLE_UNICODE: case TT_PLATFORM_ISO: /* there is `languageID' to check there. We should use this */ /* field only as a last solution when nothing else is */ /* available. */ /* */ found_unicode = n; break; case TT_PLATFORM_MACINTOSH: if ( rec->languageID == TT_MAC_LANGID_ENGLISH ) found_apple = n; break; case TT_PLATFORM_MICROSOFT: /* we only take a non-English name when there is nothing */ /* else available in the font */ /* */ if ( found_win == -1 || ( rec->languageID & 0x3FF ) == 0x009 ) { switch ( rec->encodingID ) { case TT_MS_ID_SYMBOL_CS: case TT_MS_ID_UNICODE_CS: case TT_MS_ID_UCS_4: is_english = FT_BOOL( ( rec->languageID & 0x3FF ) == 0x009 ); found_win = n; break; default: ; } } break; default: ; } } } /* some fonts contain invalid Unicode or Macintosh formatted entries; */ /* we will thus favor names encoded in Windows formats if available */ /* (provided it is an English name) */ /* */ convert = NULL; if ( found_win >= 0 && !( found_apple >= 0 && !is_english ) ) { rec = face->name_table.names + found_win; switch ( rec->encodingID ) { case TT_MS_ID_UNICODE_CS: case TT_MS_ID_SYMBOL_CS: convert = tt_name_entry_ascii_from_utf16; break; case TT_MS_ID_UCS_4: convert = tt_name_entry_ascii_from_ucs4; break; default: ; } } else if ( found_apple >= 0 ) { rec = face->name_table.names + found_apple; convert = tt_name_entry_ascii_from_other; } else if ( found_unicode >= 0 ) { rec = face->name_table.names + found_unicode; convert = tt_name_entry_ascii_from_utf16; } if ( rec && convert ) { if ( rec->string == NULL ) { FT_Error error = SFNT_Err_Ok; FT_Stream stream = face->name_table.stream; FT_UNUSED( error ); if ( FT_QNEW_ARRAY ( rec->string, rec->stringLength ) || FT_STREAM_SEEK( rec->stringOffset ) || FT_STREAM_READ( rec->string, rec->stringLength ) ) { FT_FREE( rec->string ); rec->stringLength = 0; result = NULL; goto Exit; } } result = convert( rec, memory ); } Exit: return result; }
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; }