📄 ftxgsub.c
字号:
if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &csf2->Coverage, input ) ) != TT_Err_Ok ) return error; (void)FILE_Seek( cur_offset ); if ( ACCESS_Frame( 4L ) ) goto Fail3; new_offset = GET_UShort() + base_offset; /* `SubClassSetCount' is the upper limit for class values, thus we read it now to make an additional safety check. */ count = csf2->SubClassSetCount = GET_UShort(); FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_ClassDefinition( &csf2->ClassDef, count, input ) ) != TT_Err_Ok ) goto Fail3; (void)FILE_Seek( cur_offset ); csf2->SubClassSet = NULL; csf2->MaxContextLength = 0; if ( ALLOC_ARRAY( csf2->SubClassSet, count, TTO_SubClassSet ) ) goto Fail2; scs = csf2->SubClassSet; for ( n = 0; n < count; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail1; new_offset = GET_UShort() + base_offset; FORGET_Frame(); if ( new_offset != base_offset ) /* not a NULL offset */ { cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_SubClassSet( csf2, &scs[n], input ) ) != TT_Err_Ok ) goto Fail1; (void)FILE_Seek( cur_offset ); } else { /* we create a SubClassSet table with no entries */ csf2->SubClassSet[n].SubClassRuleCount = 0; csf2->SubClassSet[n].SubClassRule = NULL; } } return TT_Err_Ok; Fail1: for ( n = 0; n < count; n++ ) Free_SubClassSet( &scs[n] ); FREE( scs ); Fail2: Free_ClassDefinition( &csf2->ClassDef ); Fail3: Free_Coverage( &csf2->Coverage ); return error; } static void Free_Context2( TTO_ContextSubstFormat2* csf2 ) { UShort n, count; TTO_SubClassSet* scs; if ( csf2->SubClassSet ) { count = csf2->SubClassSetCount; scs = csf2->SubClassSet; for ( n = 0; n < count; n++ ) Free_SubClassSet( &scs[n] ); FREE( scs ); } Free_ClassDefinition( &csf2->ClassDef ); Free_Coverage( &csf2->Coverage ); } /* ContextSubstFormat3 */ static TT_Error Load_ContextSubst3( TTO_ContextSubstFormat3* csf3, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; ULong cur_offset, new_offset, base_offset; TTO_Coverage* c; TTO_SubstLookupRecord* slr; base_offset = FILE_Pos() - 2L; if ( ACCESS_Frame( 4L ) ) return error; csf3->GlyphCount = GET_UShort(); csf3->SubstCount = GET_UShort(); FORGET_Frame(); csf3->Coverage = NULL; count = csf3->GlyphCount; if ( ALLOC_ARRAY( csf3->Coverage, count, TTO_Coverage ) ) return error; c = csf3->Coverage; for ( n = 0; n < count; n++ ) { if ( ACCESS_Frame( 2L ) ) goto Fail2; new_offset = GET_UShort() + base_offset; FORGET_Frame(); cur_offset = FILE_Pos(); if ( FILE_Seek( new_offset ) || ( error = Load_Coverage( &c[n], input ) ) != TT_Err_Ok ) goto Fail2; (void)FILE_Seek( cur_offset ); } csf3->SubstLookupRecord = NULL; count = csf3->SubstCount; if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count, TTO_SubstLookupRecord ) ) goto Fail2; slr = csf3->SubstLookupRecord; if ( ACCESS_Frame( count * 4L ) ) goto Fail1; for ( n = 0; n < count; n++ ) { slr[n].SequenceIndex = GET_UShort(); slr[n].LookupListIndex = GET_UShort(); } FORGET_Frame(); return TT_Err_Ok; Fail1: FREE( slr ); Fail2: for ( n = 0; n < count; n++ ) Free_Coverage( &c[n] ); FREE( c ); return error; } static void Free_Context3( TTO_ContextSubstFormat3* csf3 ) { UShort n, count; TTO_Coverage* c; FREE( csf3->SubstLookupRecord ); if ( csf3->Coverage ) { count = csf3->GlyphCount; c = csf3->Coverage; for ( n = 0; n < count; n++ ) Free_Coverage( &c[n] ); FREE( c ); } } /* ContextSubst */ TT_Error Load_ContextSubst( TTO_ContextSubst* cs, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); if ( ACCESS_Frame( 2L ) ) return error; cs->SubstFormat = GET_UShort(); FORGET_Frame(); switch ( cs->SubstFormat ) { case 1: return Load_ContextSubst1( &cs->csf.csf1, input ); case 2: return Load_ContextSubst2( &cs->csf.csf2, input ); case 3: return Load_ContextSubst3( &cs->csf.csf3, input ); default: return TTO_Err_Invalid_GSUB_SubTable_Format; } return TT_Err_Ok; /* never reached */ } void Free_ContextSubst( TTO_ContextSubst* cs ) { switch ( cs->SubstFormat ) { case 1: Free_Context1( &cs->csf.csf1 ); break; case 2: Free_Context2( &cs->csf.csf2 ); break; case 3: Free_Context3( &cs->csf.csf3 ); break; } } static TT_Error Lookup_ContextSubst1( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat1* csf1, TTO_GSUB_String* in, TTO_GSUB_String* out, UShort flags, UShort context_length, int nesting_level ) { UShort index, property; UShort i, j, k, numsr; TT_Error error; UShort* s_in; TTO_SubRule* sr; TTO_GDEFHeader* gdef; gdef = gsub->gdef; if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) return error; error = Coverage_Index( &csf1->Coverage, in->string[in->pos], &index ); if ( error ) return error; sr = csf1->SubRuleSet[index].SubRule; numsr = csf1->SubRuleSet[index].SubRuleCount; for ( k = 0; k < numsr; k++ ) { if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount ) continue; if ( in->pos + sr[k].GlyphCount > in->length ) continue; /* context is too long */ s_in = &in->string[in->pos]; for ( i = 1, j = 1; i < sr[k].GlyphCount; i++, j++ ) { while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( in->pos + j < in->length ) j++; else break; } if ( s_in[j] != sr[k].Input[i - 1] ) break; } if ( i == sr[k].GlyphCount ) return Do_ContextSubst( gsub, sr[k].GlyphCount, sr[k].SubstCount, sr[k].SubstLookupRecord, in, out, nesting_level ); } return TTO_Err_Not_Covered; } static TT_Error Lookup_ContextSubst2( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat2* csf2, TTO_GSUB_String* in, TTO_GSUB_String* out, UShort flags, UShort context_length, int nesting_level ) { UShort index, property; TT_Error error; UShort i, j, k, known_classes; UShort* classes; UShort* s_in; UShort* cl; TTO_SubClassSet* scs; TTO_SubClassRule* sr; TTO_GDEFHeader* gdef; gdef = gsub->gdef; if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, UShort ) ) return error; if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) return error; /* Note: The coverage table in format 2 doesn't give an index into anything. It just lets us know whether or not we need to do any lookup at all. */ error = Coverage_Index( &csf2->Coverage, in->string[in->pos], &index ); if ( error ) goto End; error = Get_Class( &csf2->ClassDef, in->string[in->pos], &classes[0], NULL ); if ( error ) goto End; known_classes = 0; scs = &csf2->SubClassSet[classes[0]]; if ( !scs ) { error = TTO_Err_Invalid_GSUB_SubTable; goto End; } for ( k = 0; k < scs->SubClassRuleCount; k++ ) { sr = &scs->SubClassRule[k]; if ( context_length != 0xFFFF && context_length < sr->GlyphCount ) continue; if ( in->pos + sr->GlyphCount > in->length ) continue; /* context is too long */ s_in = &in->string[in->pos]; cl = sr->Class; /* Start at 1 because [0] is implied */ for ( i = 1, j = 1; i < sr->GlyphCount; i++, j++ ) { while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( in->pos + j < in->length ) j++; else break; } if ( i > known_classes ) { /* Keeps us from having to do this for each rule */ error = Get_Class( &csf2->ClassDef, s_in[j], &classes[i], NULL ); if ( error && error != TTO_Err_Not_Covered ) return error; known_classes = i; } if ( cl[i - 1] != classes[i] ) break; } if ( i == sr->GlyphCount ) { error = Do_ContextSubst( gsub, sr->GlyphCount, sr->SubstCount, sr->SubstLookupRecord, in, out, nesting_level ); goto End; } } error = TTO_Err_Not_Covered; End: FREE( classes ); return error; } static TT_Error Lookup_ContextSubst3( TTO_GSUBHeader* gsub, TTO_ContextSubstFormat3* csf3, TTO_GSUB_String* in, TTO_GSUB_String* out, UShort flags, UShort context_length, int nesting_level ) { TT_Error error; UShort index, i, j, property; UShort* s_in; TTO_Coverage* c; TTO_GDEFHeader* gdef; gdef = gsub->gdef; if ( CHECK_Property( gdef, in->string[in->pos], flags, &property ) ) return error; if ( context_length != 0xFFFF && context_length < csf3->GlyphCount ) return TTO_Err_Not_Covered; if ( in->pos + csf3->GlyphCount > in->length ) return TTO_Err_Not_Covered; /* context is too long */ s_in = &in->string[in->pos]; c = csf3->Coverage; for ( i = 1, j = 1; i < csf3->GlyphCount; i++, j++ ) { while ( CHECK_Property( gdef, s_in[j], flags, &property ) ) { if ( error && error != TTO_Err_Not_Covered ) return error; if ( in->pos + j < in->length ) j++; else return TTO_Err_Not_Covered; } error = Coverage_Index( &c[i], s_in[j], &index ); if ( error ) return error; } return Do_ContextSubst( gsub, csf3->GlyphCount, csf3->SubstCount, csf3->SubstLookupRecord, in, out, nesting_level ); } static TT_Error Lookup_ContextSubst( TTO_GSUBHeader* gsub, TTO_ContextSubst* cs, TTO_GSUB_String* in, TTO_GSUB_String* out, UShort flags, UShort context_length, int nesting_level ) { switch ( cs->SubstFormat ) { case 1: return Lookup_ContextSubst1( gsub, &cs->csf.csf1, in, out, flags, context_length, nesting_level ); case 2: return Lookup_ContextSubst2( gsub, &cs->csf.csf2, in, out, flags, context_length, nesting_level ); case 3: return Lookup_ContextSubst3( gsub, &cs->csf.csf3, in, out, flags, context_length, nesting_level ); default: return TTO_Err_Invalid_GSUB_SubTable_Format; } return TT_Err_Ok; /* never reached */ } /* LookupType 6 */ /* ChainSubRule */ static TT_Error Load_ChainSubRule( TTO_ChainSubRule* csr, PFace input ) { DEFINE_LOAD_LOCALS( input->stream ); UShort n, count; UShort* b; UShort* i; UShort* l; TTO_SubstLookupRecord* slr; if ( ACCESS_Frame( 2L ) ) return error; csr->BacktrackGlyphCount = GET_UShort(); FORGET_Frame(); csr->Backtrack = NULL; count = csr->BacktrackGlyphCount; if ( ALLOC_ARRAY( csr->Backtrack, count, UShort ) ) return error; b = csr->Backtrack; if ( ACCESS_Frame( count * 2L ) ) goto Fail4; for ( n = 0; n < count; n++ ) b[n] = GET_UShort(); FORGET_Frame(); if ( ACCESS_Frame( 2L ) ) goto Fail4; csr->InputGlyphCount = GET_UShort(); FORGET_Frame(); csr->Input = NULL; count = csr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */ if ( ALLOC_ARRAY( csr->Input, count, UShort ) ) goto Fail4; i = csr->Input;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -