Home | History | Annotate | Download | only in hb-old
      1 /*
      2  * Copyright (C) 1998-2004  David Turner and Werner Lemberg
      3  * Copyright (C) 2006  Behdad Esfahbod
      4  * Copyright (C) 2007  Red Hat, Inc.
      5  *
      6  * This is part of HarfBuzz, an OpenType Layout engine library.
      7  *
      8  * Permission is hereby granted, without written agreement and without
      9  * license or royalty fees, to use, copy, modify, and distribute this
     10  * software and its documentation for any purpose, provided that the
     11  * above copyright notice and the following two paragraphs appear in
     12  * all copies of this software.
     13  *
     14  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     15  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     16  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     17  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     18  * DAMAGE.
     19  *
     20  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     21  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     22  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     23  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     24  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     25  *
     26  * Red Hat Author(s): Behdad Esfahbod
     27  */
     28 
     29 #include "harfbuzz-impl.h"
     30 #include "harfbuzz-gsub-private.h"
     31 #include "harfbuzz-open-private.h"
     32 #include "harfbuzz-gdef-private.h"
     33 
     34 static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader*   gsub,
     35 				       HB_UShort         lookup_index,
     36 				       HB_Buffer        buffer,
     37 				       HB_UShort         context_length,
     38 				       int               nesting_level );
     39 
     40 
     41 
     42 /**********************
     43  * Auxiliary functions
     44  **********************/
     45 
     46 
     47 
     48 HB_Error  HB_Load_GSUB_Table( HB_Stream stream,
     49 			      HB_GSUBHeader** retptr,
     50 			      HB_GDEFHeader*  gdef,
     51                               HB_Stream       gdefStream )
     52 {
     53   HB_Error         error;
     54   HB_UInt         cur_offset, new_offset, base_offset;
     55 
     56   HB_GSUBHeader*  gsub;
     57 
     58   if ( !retptr )
     59     return ERR(HB_Err_Invalid_Argument);
     60 
     61   if ( GOTO_Table( TTAG_GSUB ) )
     62     return error;
     63 
     64   base_offset = FILE_Pos();
     65 
     66   if ( ALLOC ( gsub, sizeof( *gsub ) ) )
     67       return error;
     68 
     69 
     70   /* skip version */
     71 
     72   if ( FILE_Seek( base_offset + 4L ) ||
     73        ACCESS_Frame( 2L ) )
     74     goto Fail4;
     75 
     76   new_offset = GET_UShort() + base_offset;
     77 
     78   FORGET_Frame();
     79 
     80   cur_offset = FILE_Pos();
     81   if ( FILE_Seek( new_offset ) ||
     82        ( error = _HB_OPEN_Load_ScriptList( &gsub->ScriptList,
     83 				  stream ) ) != HB_Err_Ok )
     84     goto Fail4;
     85   (void)FILE_Seek( cur_offset );
     86 
     87   if ( ACCESS_Frame( 2L ) )
     88     goto Fail3;
     89 
     90   new_offset = GET_UShort() + base_offset;
     91 
     92   FORGET_Frame();
     93 
     94   cur_offset = FILE_Pos();
     95   if ( FILE_Seek( new_offset ) ||
     96        ( error = _HB_OPEN_Load_FeatureList( &gsub->FeatureList,
     97 				   stream ) ) != HB_Err_Ok )
     98     goto Fail3;
     99   (void)FILE_Seek( cur_offset );
    100 
    101   if ( ACCESS_Frame( 2L ) )
    102     goto Fail2;
    103 
    104   new_offset = GET_UShort() + base_offset;
    105 
    106   FORGET_Frame();
    107 
    108   cur_offset = FILE_Pos();
    109   if ( FILE_Seek( new_offset ) ||
    110        ( error = _HB_OPEN_Load_LookupList( &gsub->LookupList,
    111 				  stream, HB_Type_GSUB ) ) != HB_Err_Ok )
    112     goto Fail2;
    113 
    114   gsub->gdef = gdef;      /* can be NULL */
    115 
    116   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
    117 								     gsub->LookupList.Lookup,
    118 								     gsub->LookupList.LookupCount ) ) )
    119     goto Fail1;
    120 
    121   *retptr = gsub;
    122 
    123   return HB_Err_Ok;
    124 
    125 Fail1:
    126   _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
    127 
    128 Fail2:
    129   _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
    130 
    131 Fail3:
    132   _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
    133 
    134 Fail4:
    135   FREE ( gsub );
    136 
    137 
    138   return error;
    139 }
    140 
    141 
    142 HB_Error   HB_Done_GSUB_Table( HB_GSUBHeader* gsub )
    143 {
    144   _HB_OPEN_Free_LookupList( &gsub->LookupList, HB_Type_GSUB );
    145   _HB_OPEN_Free_FeatureList( &gsub->FeatureList );
    146   _HB_OPEN_Free_ScriptList( &gsub->ScriptList );
    147 
    148   FREE( gsub );
    149 
    150   return HB_Err_Ok;
    151 }
    152 
    153 /*****************************
    154  * SubTable related functions
    155  *****************************/
    156 
    157 
    158 /* LookupType 1 */
    159 
    160 /* SingleSubstFormat1 */
    161 /* SingleSubstFormat2 */
    162 
    163 static HB_Error  Load_SingleSubst( HB_GSUB_SubTable* st,
    164 				   HB_Stream         stream )
    165 {
    166   HB_Error error;
    167   HB_SingleSubst*  ss = &st->single;
    168 
    169   HB_UShort n, count;
    170   HB_UInt cur_offset, new_offset, base_offset;
    171 
    172   HB_UShort*  s;
    173 
    174 
    175   base_offset = FILE_Pos();
    176 
    177   if ( ACCESS_Frame( 4L ) )
    178     return error;
    179 
    180   ss->SubstFormat = GET_UShort();
    181   new_offset      = GET_UShort() + base_offset;
    182 
    183   FORGET_Frame();
    184 
    185   cur_offset = FILE_Pos();
    186   if ( FILE_Seek( new_offset ) ||
    187        ( error = _HB_OPEN_Load_Coverage( &ss->Coverage, stream ) ) != HB_Err_Ok )
    188     return error;
    189   (void)FILE_Seek( cur_offset );
    190 
    191   switch ( ss->SubstFormat )
    192   {
    193   case 1:
    194     if ( ACCESS_Frame( 2L ) )
    195       goto Fail2;
    196 
    197     ss->ssf.ssf1.DeltaGlyphID = GET_UShort();
    198 
    199     FORGET_Frame();
    200 
    201     break;
    202 
    203   case 2:
    204     if ( ACCESS_Frame( 2L ) )
    205       goto Fail2;
    206 
    207     count = ss->ssf.ssf2.GlyphCount = GET_UShort();
    208 
    209     FORGET_Frame();
    210 
    211     ss->ssf.ssf2.Substitute = NULL;
    212 
    213     if ( ALLOC_ARRAY( ss->ssf.ssf2.Substitute, count, HB_UShort ) )
    214       goto Fail2;
    215 
    216     s = ss->ssf.ssf2.Substitute;
    217 
    218     if ( ACCESS_Frame( count * 2L ) )
    219       goto Fail1;
    220 
    221     for ( n = 0; n < count; n++ )
    222       s[n] = GET_UShort();
    223 
    224     FORGET_Frame();
    225 
    226     break;
    227 
    228   default:
    229     return ERR(HB_Err_Invalid_SubTable_Format);
    230   }
    231 
    232   return HB_Err_Ok;
    233 
    234 Fail1:
    235   FREE( s );
    236 
    237 Fail2:
    238   _HB_OPEN_Free_Coverage( &ss->Coverage );
    239   return error;
    240 }
    241 
    242 
    243 static void  Free_SingleSubst( HB_GSUB_SubTable* st )
    244 {
    245   HB_SingleSubst*  ss = &st->single;
    246 
    247   switch ( ss->SubstFormat )
    248   {
    249   case 1:
    250     break;
    251 
    252   case 2:
    253     FREE( ss->ssf.ssf2.Substitute );
    254     break;
    255 
    256   default:
    257     break;
    258   }
    259 
    260   _HB_OPEN_Free_Coverage( &ss->Coverage );
    261 }
    262 
    263 
    264 static HB_Error  Lookup_SingleSubst( HB_GSUBHeader*   gsub,
    265 				     HB_GSUB_SubTable* st,
    266 				     HB_Buffer        buffer,
    267 				     HB_UShort         flags,
    268 				     HB_UShort         context_length,
    269 				     int               nesting_level )
    270 {
    271   HB_UShort index, value, property;
    272   HB_Error  error;
    273   HB_SingleSubst*  ss = &st->single;
    274   HB_GDEFHeader*   gdef = gsub->gdef;
    275 
    276   HB_UNUSED(nesting_level);
    277 
    278   if ( context_length != 0xFFFF && context_length < 1 )
    279     return HB_Err_Not_Covered;
    280 
    281   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
    282     return error;
    283 
    284   error = _HB_OPEN_Coverage_Index( &ss->Coverage, IN_CURGLYPH(), &index );
    285   if ( error )
    286     return error;
    287 
    288   switch ( ss->SubstFormat )
    289   {
    290   case 1:
    291     value = ( IN_CURGLYPH() + ss->ssf.ssf1.DeltaGlyphID ) & 0xFFFF;
    292     if ( REPLACE_Glyph( buffer, value, nesting_level ) )
    293       return error;
    294     break;
    295 
    296   case 2:
    297     if ( index >= ss->ssf.ssf2.GlyphCount )
    298       return ERR(HB_Err_Invalid_SubTable);
    299     value = ss->ssf.ssf2.Substitute[index];
    300     if ( REPLACE_Glyph( buffer, value, nesting_level ) )
    301       return error;
    302     break;
    303 
    304   default:
    305     return ERR(HB_Err_Invalid_SubTable);
    306   }
    307 
    308   if ( gdef && gdef->NewGlyphClasses )
    309   {
    310     /* we inherit the old glyph class to the substituted glyph */
    311 
    312     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
    313     if ( error && error != HB_Err_Not_Covered )
    314       return error;
    315   }
    316 
    317   return HB_Err_Ok;
    318 }
    319 
    320 
    321 /* LookupType 2 */
    322 
    323 /* Sequence */
    324 
    325 static HB_Error  Load_Sequence( HB_Sequence*  s,
    326 				HB_Stream      stream )
    327 {
    328   HB_Error error;
    329 
    330   HB_UShort n, count;
    331   HB_UShort*  sub;
    332 
    333 
    334   if ( ACCESS_Frame( 2L ) )
    335     return error;
    336 
    337   count = s->GlyphCount = GET_UShort();
    338 
    339   FORGET_Frame();
    340 
    341   s->Substitute = NULL;
    342 
    343   if ( count )
    344   {
    345     if ( ALLOC_ARRAY( s->Substitute, count, HB_UShort ) )
    346       return error;
    347 
    348     sub = s->Substitute;
    349 
    350     if ( ACCESS_Frame( count * 2L ) )
    351     {
    352       FREE( sub );
    353       return error;
    354     }
    355 
    356     for ( n = 0; n < count; n++ )
    357       sub[n] = GET_UShort();
    358 
    359     FORGET_Frame();
    360   }
    361 
    362   return HB_Err_Ok;
    363 }
    364 
    365 
    366 static void  Free_Sequence( HB_Sequence*  s )
    367 {
    368   FREE( s->Substitute );
    369 }
    370 
    371 
    372 /* MultipleSubstFormat1 */
    373 
    374 static HB_Error  Load_MultipleSubst( HB_GSUB_SubTable* st,
    375 				     HB_Stream         stream )
    376 {
    377   HB_Error error;
    378   HB_MultipleSubst*  ms = &st->multiple;
    379 
    380   HB_UShort      n = 0, m, count;
    381   HB_UInt       cur_offset, new_offset, base_offset;
    382 
    383   HB_Sequence*  s;
    384 
    385 
    386   base_offset = FILE_Pos();
    387 
    388   if ( ACCESS_Frame( 4L ) )
    389     return error;
    390 
    391   ms->SubstFormat = GET_UShort();             /* should be 1 */
    392   new_offset      = GET_UShort() + base_offset;
    393 
    394   FORGET_Frame();
    395 
    396   cur_offset = FILE_Pos();
    397   if ( FILE_Seek( new_offset ) ||
    398        ( error = _HB_OPEN_Load_Coverage( &ms->Coverage, stream ) ) != HB_Err_Ok )
    399     return error;
    400   (void)FILE_Seek( cur_offset );
    401 
    402   if ( ACCESS_Frame( 2L ) )
    403     goto Fail2;
    404 
    405   count = ms->SequenceCount = GET_UShort();
    406 
    407   FORGET_Frame();
    408 
    409   ms->Sequence = NULL;
    410 
    411   if ( ALLOC_ARRAY( ms->Sequence, count, HB_Sequence ) )
    412     goto Fail2;
    413 
    414   s = ms->Sequence;
    415 
    416   for ( n = 0; n < count; n++ )
    417   {
    418     if ( ACCESS_Frame( 2L ) )
    419       goto Fail1;
    420 
    421     new_offset = GET_UShort() + base_offset;
    422 
    423     FORGET_Frame();
    424 
    425     cur_offset = FILE_Pos();
    426     if ( FILE_Seek( new_offset ) ||
    427 	 ( error = Load_Sequence( &s[n], stream ) ) != HB_Err_Ok )
    428       goto Fail1;
    429     (void)FILE_Seek( cur_offset );
    430   }
    431 
    432   return HB_Err_Ok;
    433 
    434 Fail1:
    435   for ( m = 0; m < n; m++ )
    436     Free_Sequence( &s[m] );
    437 
    438   FREE( s );
    439 
    440 Fail2:
    441   _HB_OPEN_Free_Coverage( &ms->Coverage );
    442   return error;
    443 }
    444 
    445 
    446 static void  Free_MultipleSubst( HB_GSUB_SubTable* st )
    447 {
    448   HB_UShort      n, count;
    449   HB_MultipleSubst*  ms = &st->multiple;
    450 
    451   HB_Sequence*  s;
    452 
    453 
    454   if ( ms->Sequence )
    455   {
    456     count = ms->SequenceCount;
    457     s     = ms->Sequence;
    458 
    459     for ( n = 0; n < count; n++ )
    460       Free_Sequence( &s[n] );
    461 
    462     FREE( s );
    463   }
    464 
    465   _HB_OPEN_Free_Coverage( &ms->Coverage );
    466 }
    467 
    468 
    469 static HB_Error  Lookup_MultipleSubst( HB_GSUBHeader*    gsub,
    470 				       HB_GSUB_SubTable* st,
    471 				       HB_Buffer         buffer,
    472 				       HB_UShort          flags,
    473 				       HB_UShort          context_length,
    474 				       int                nesting_level )
    475 {
    476   HB_Error  error;
    477   HB_UShort index, property, n, count;
    478   HB_UShort*s;
    479   HB_MultipleSubst*  ms = &st->multiple;
    480   HB_GDEFHeader*     gdef = gsub->gdef;
    481 
    482   HB_UNUSED(nesting_level);
    483 
    484   if ( context_length != 0xFFFF && context_length < 1 )
    485     return HB_Err_Not_Covered;
    486 
    487   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
    488     return error;
    489 
    490   error = _HB_OPEN_Coverage_Index( &ms->Coverage, IN_CURGLYPH(), &index );
    491   if ( error )
    492     return error;
    493 
    494   if ( index >= ms->SequenceCount )
    495     return ERR(HB_Err_Invalid_SubTable);
    496 
    497   count = ms->Sequence[index].GlyphCount;
    498   s     = ms->Sequence[index].Substitute;
    499 
    500   if ( ADD_String( buffer, 1, count, s, 0xFFFF, 0xFFFF ) )
    501     return error;
    502 
    503   if ( gdef && gdef->NewGlyphClasses )
    504   {
    505     /* this is a guess only ... */
    506 
    507     if ( property == HB_GDEF_LIGATURE )
    508       property = HB_GDEF_BASE_GLYPH;
    509 
    510     for ( n = 0; n < count; n++ )
    511     {
    512       error = _HB_GDEF_Add_Glyph_Property( gdef, s[n], property );
    513       if ( error && error != HB_Err_Not_Covered )
    514 	return error;
    515     }
    516   }
    517 
    518   return HB_Err_Ok;
    519 }
    520 
    521 
    522 /* LookupType 3 */
    523 
    524 /* AlternateSet */
    525 
    526 static HB_Error  Load_AlternateSet( HB_AlternateSet*  as,
    527 				    HB_Stream          stream )
    528 {
    529   HB_Error error;
    530 
    531   HB_UShort n, count;
    532   HB_UShort*  a;
    533 
    534 
    535   if ( ACCESS_Frame( 2L ) )
    536     return error;
    537 
    538   count = as->GlyphCount = GET_UShort();
    539 
    540   FORGET_Frame();
    541 
    542   as->Alternate = NULL;
    543 
    544   if ( ALLOC_ARRAY( as->Alternate, count, HB_UShort ) )
    545     return error;
    546 
    547   a = as->Alternate;
    548 
    549   if ( ACCESS_Frame( count * 2L ) )
    550   {
    551     FREE( a );
    552     return error;
    553   }
    554 
    555   for ( n = 0; n < count; n++ )
    556     a[n] = GET_UShort();
    557 
    558   FORGET_Frame();
    559 
    560   return HB_Err_Ok;
    561 }
    562 
    563 
    564 static void  Free_AlternateSet( HB_AlternateSet*  as )
    565 {
    566   FREE( as->Alternate );
    567 }
    568 
    569 
    570 /* AlternateSubstFormat1 */
    571 
    572 static HB_Error  Load_AlternateSubst( HB_GSUB_SubTable* st,
    573 				      HB_Stream         stream )
    574 {
    575   HB_Error error;
    576   HB_AlternateSubst* as = &st->alternate;
    577 
    578   HB_UShort          n = 0, m, count;
    579   HB_UInt           cur_offset, new_offset, base_offset;
    580 
    581   HB_AlternateSet*  aset;
    582 
    583 
    584   base_offset = FILE_Pos();
    585 
    586   if ( ACCESS_Frame( 4L ) )
    587     return error;
    588 
    589   as->SubstFormat = GET_UShort();             /* should be 1 */
    590   new_offset      = GET_UShort() + base_offset;
    591 
    592   FORGET_Frame();
    593 
    594   cur_offset = FILE_Pos();
    595   if ( FILE_Seek( new_offset ) ||
    596        ( error = _HB_OPEN_Load_Coverage( &as->Coverage, stream ) ) != HB_Err_Ok )
    597     return error;
    598   (void)FILE_Seek( cur_offset );
    599 
    600   if ( ACCESS_Frame( 2L ) )
    601     goto Fail2;
    602 
    603   count = as->AlternateSetCount = GET_UShort();
    604 
    605   FORGET_Frame();
    606 
    607   as->AlternateSet = NULL;
    608 
    609   if ( ALLOC_ARRAY( as->AlternateSet, count, HB_AlternateSet ) )
    610     goto Fail2;
    611 
    612   aset = as->AlternateSet;
    613 
    614   for ( n = 0; n < count; n++ )
    615   {
    616     if ( ACCESS_Frame( 2L ) )
    617       goto Fail1;
    618 
    619     new_offset = GET_UShort() + base_offset;
    620 
    621     FORGET_Frame();
    622 
    623     cur_offset = FILE_Pos();
    624     if ( FILE_Seek( new_offset ) ||
    625 	 ( error = Load_AlternateSet( &aset[n], stream ) ) != HB_Err_Ok )
    626       goto Fail1;
    627     (void)FILE_Seek( cur_offset );
    628   }
    629 
    630   return HB_Err_Ok;
    631 
    632 Fail1:
    633   for ( m = 0; m < n; m++ )
    634     Free_AlternateSet( &aset[m] );
    635 
    636   FREE( aset );
    637 
    638 Fail2:
    639   _HB_OPEN_Free_Coverage( &as->Coverage );
    640   return error;
    641 }
    642 
    643 
    644 static void  Free_AlternateSubst( HB_GSUB_SubTable* st )
    645 {
    646   HB_UShort          n, count;
    647   HB_AlternateSubst* as = &st->alternate;
    648 
    649   HB_AlternateSet*  aset;
    650 
    651 
    652   if ( as->AlternateSet )
    653   {
    654     count = as->AlternateSetCount;
    655     aset  = as->AlternateSet;
    656 
    657     for ( n = 0; n < count; n++ )
    658       Free_AlternateSet( &aset[n] );
    659 
    660     FREE( aset );
    661   }
    662 
    663   _HB_OPEN_Free_Coverage( &as->Coverage );
    664 }
    665 
    666 
    667 static HB_Error  Lookup_AlternateSubst( HB_GSUBHeader*    gsub,
    668 					HB_GSUB_SubTable* st,
    669 					HB_Buffer         buffer,
    670 					HB_UShort          flags,
    671 					HB_UShort          context_length,
    672 					int                nesting_level )
    673 {
    674   HB_Error          error;
    675   HB_UShort         index, value, alt_index, property;
    676   HB_AlternateSubst* as = &st->alternate;
    677   HB_GDEFHeader*     gdef = gsub->gdef;
    678   HB_AlternateSet  aset;
    679 
    680   HB_UNUSED(nesting_level);
    681 
    682   if ( context_length != 0xFFFF && context_length < 1 )
    683     return HB_Err_Not_Covered;
    684 
    685   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
    686     return error;
    687 
    688   error = _HB_OPEN_Coverage_Index( &as->Coverage, IN_CURGLYPH(), &index );
    689   if ( error )
    690     return error;
    691 
    692   aset = as->AlternateSet[index];
    693 
    694   /* we use a user-defined callback function to get the alternate index */
    695 
    696   if ( gsub->altfunc )
    697     alt_index = (gsub->altfunc)( buffer->out_pos, IN_CURGLYPH(),
    698 				 aset.GlyphCount, aset.Alternate,
    699 				 gsub->data );
    700   else
    701     alt_index = 0;
    702 
    703   value = aset.Alternate[alt_index];
    704   if ( REPLACE_Glyph( buffer, value, nesting_level ) )
    705     return error;
    706 
    707   if ( gdef && gdef->NewGlyphClasses )
    708   {
    709     /* we inherit the old glyph class to the substituted glyph */
    710 
    711     error = _HB_GDEF_Add_Glyph_Property( gdef, value, property );
    712     if ( error && error != HB_Err_Not_Covered )
    713       return error;
    714   }
    715 
    716   return HB_Err_Ok;
    717 }
    718 
    719 
    720 /* LookupType 4 */
    721 
    722 /* Ligature */
    723 
    724 static HB_Error  Load_Ligature( HB_Ligature*  l,
    725 				HB_Stream      stream )
    726 {
    727   HB_Error error;
    728 
    729   HB_UShort n, count;
    730   HB_UShort*  c;
    731 
    732 
    733   if ( ACCESS_Frame( 4L ) )
    734     return error;
    735 
    736   l->LigGlyph       = GET_UShort();
    737   l->ComponentCount = GET_UShort();
    738 
    739   FORGET_Frame();
    740 
    741   l->Component = NULL;
    742 
    743   count = l->ComponentCount - 1;      /* only ComponentCount - 1 elements */
    744 
    745   if ( ALLOC_ARRAY( l->Component, count, HB_UShort ) )
    746     return error;
    747 
    748   c = l->Component;
    749 
    750   if ( ACCESS_Frame( count * 2L ) )
    751   {
    752     FREE( c );
    753     return error;
    754   }
    755 
    756   for ( n = 0; n < count; n++ )
    757     c[n] = GET_UShort();
    758 
    759   FORGET_Frame();
    760 
    761   return HB_Err_Ok;
    762 }
    763 
    764 
    765 static void  Free_Ligature( HB_Ligature*  l )
    766 {
    767   FREE( l->Component );
    768 }
    769 
    770 
    771 /* LigatureSet */
    772 
    773 static HB_Error  Load_LigatureSet( HB_LigatureSet*  ls,
    774 				   HB_Stream         stream )
    775 {
    776   HB_Error error;
    777 
    778   HB_UShort      n = 0, m, count;
    779   HB_UInt       cur_offset, new_offset, base_offset;
    780 
    781   HB_Ligature*  l;
    782 
    783 
    784   base_offset = FILE_Pos();
    785 
    786   if ( ACCESS_Frame( 2L ) )
    787     return error;
    788 
    789   count = ls->LigatureCount = GET_UShort();
    790 
    791   FORGET_Frame();
    792 
    793   ls->Ligature = NULL;
    794 
    795   if ( ALLOC_ARRAY( ls->Ligature, count, HB_Ligature ) )
    796     return error;
    797 
    798   l = ls->Ligature;
    799 
    800   for ( n = 0; n < count; n++ )
    801   {
    802     if ( ACCESS_Frame( 2L ) )
    803       goto Fail;
    804 
    805     new_offset = GET_UShort() + base_offset;
    806 
    807     FORGET_Frame();
    808 
    809     cur_offset = FILE_Pos();
    810     if ( FILE_Seek( new_offset ) ||
    811 	 ( error = Load_Ligature( &l[n], stream ) ) != HB_Err_Ok )
    812       goto Fail;
    813     (void)FILE_Seek( cur_offset );
    814   }
    815 
    816   return HB_Err_Ok;
    817 
    818 Fail:
    819   for ( m = 0; m < n; m++ )
    820     Free_Ligature( &l[m] );
    821 
    822   FREE( l );
    823   return error;
    824 }
    825 
    826 
    827 static void  Free_LigatureSet( HB_LigatureSet*  ls )
    828 {
    829   HB_UShort      n, count;
    830 
    831   HB_Ligature*  l;
    832 
    833 
    834   if ( ls->Ligature )
    835   {
    836     count = ls->LigatureCount;
    837     l     = ls->Ligature;
    838 
    839     for ( n = 0; n < count; n++ )
    840       Free_Ligature( &l[n] );
    841 
    842     FREE( l );
    843   }
    844 }
    845 
    846 
    847 /* LigatureSubstFormat1 */
    848 
    849 static HB_Error  Load_LigatureSubst( HB_GSUB_SubTable* st,
    850 				     HB_Stream         stream )
    851 {
    852   HB_Error error;
    853   HB_LigatureSubst*  ls = &st->ligature;
    854 
    855   HB_UShort         n = 0, m, count;
    856   HB_UInt          cur_offset, new_offset, base_offset;
    857 
    858   HB_LigatureSet*  lset;
    859 
    860 
    861   base_offset = FILE_Pos();
    862 
    863   if ( ACCESS_Frame( 4L ) )
    864     return error;
    865 
    866   ls->SubstFormat = GET_UShort();             /* should be 1 */
    867   new_offset      = GET_UShort() + base_offset;
    868 
    869   FORGET_Frame();
    870 
    871   cur_offset = FILE_Pos();
    872   if ( FILE_Seek( new_offset ) ||
    873        ( error = _HB_OPEN_Load_Coverage( &ls->Coverage, stream ) ) != HB_Err_Ok )
    874     return error;
    875   (void)FILE_Seek( cur_offset );
    876 
    877   if ( ACCESS_Frame( 2L ) )
    878     goto Fail2;
    879 
    880   count = ls->LigatureSetCount = GET_UShort();
    881 
    882   FORGET_Frame();
    883 
    884   ls->LigatureSet = NULL;
    885 
    886   if ( ALLOC_ARRAY( ls->LigatureSet, count, HB_LigatureSet ) )
    887     goto Fail2;
    888 
    889   lset = ls->LigatureSet;
    890 
    891   for ( n = 0; n < count; n++ )
    892   {
    893     if ( ACCESS_Frame( 2L ) )
    894       goto Fail1;
    895 
    896     new_offset = GET_UShort() + base_offset;
    897 
    898     FORGET_Frame();
    899 
    900     cur_offset = FILE_Pos();
    901     if ( FILE_Seek( new_offset ) ||
    902 	 ( error = Load_LigatureSet( &lset[n], stream ) ) != HB_Err_Ok )
    903       goto Fail1;
    904     (void)FILE_Seek( cur_offset );
    905   }
    906 
    907   return HB_Err_Ok;
    908 
    909 Fail1:
    910   for ( m = 0; m < n; m++ )
    911     Free_LigatureSet( &lset[m] );
    912 
    913   FREE( lset );
    914 
    915 Fail2:
    916   _HB_OPEN_Free_Coverage( &ls->Coverage );
    917   return error;
    918 }
    919 
    920 
    921 static void  Free_LigatureSubst( HB_GSUB_SubTable* st )
    922 {
    923   HB_UShort         n, count;
    924   HB_LigatureSubst*  ls = &st->ligature;
    925 
    926   HB_LigatureSet*  lset;
    927 
    928 
    929   if ( ls->LigatureSet )
    930   {
    931     count = ls->LigatureSetCount;
    932     lset  = ls->LigatureSet;
    933 
    934     for ( n = 0; n < count; n++ )
    935       Free_LigatureSet( &lset[n] );
    936 
    937     FREE( lset );
    938   }
    939 
    940   _HB_OPEN_Free_Coverage( &ls->Coverage );
    941 }
    942 
    943 
    944 static HB_Error  Lookup_LigatureSubst( HB_GSUBHeader*    gsub,
    945 				       HB_GSUB_SubTable* st,
    946 				       HB_Buffer         buffer,
    947 				       HB_UShort          flags,
    948 				       HB_UShort          context_length,
    949 				       int                nesting_level )
    950 {
    951   HB_UShort      index, property;
    952   HB_Error       error;
    953   HB_UShort      numlig, i, j, is_mark, first_is_mark = FALSE;
    954   HB_UShort*     c;
    955   HB_LigatureSubst*  ls = &st->ligature;
    956   HB_GDEFHeader*     gdef = gsub->gdef;
    957 
    958   HB_Ligature*  lig;
    959 
    960   HB_UNUSED(nesting_level);
    961 
    962   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
    963     return error;
    964 
    965   if ( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
    966     first_is_mark = TRUE;
    967 
    968   error = _HB_OPEN_Coverage_Index( &ls->Coverage, IN_CURGLYPH(), &index );
    969   if ( error )
    970     return error;
    971 
    972   if ( index >= ls->LigatureSetCount )
    973      return ERR(HB_Err_Invalid_SubTable);
    974 
    975   lig = ls->LigatureSet[index].Ligature;
    976 
    977   for ( numlig = ls->LigatureSet[index].LigatureCount;
    978 	numlig;
    979 	numlig--, lig++ )
    980   {
    981     if ( buffer->in_pos + lig->ComponentCount > buffer->in_length )
    982       goto next_ligature;               /* Not enough glyphs in input */
    983 
    984     c    = lig->Component;
    985 
    986     is_mark = first_is_mark;
    987 
    988     if ( context_length != 0xFFFF && context_length < lig->ComponentCount )
    989       break;
    990 
    991     for ( i = 1, j = buffer->in_pos + 1; i < lig->ComponentCount; i++, j++ )
    992     {
    993       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
    994       {
    995 	if ( error && error != HB_Err_Not_Covered )
    996 	  return error;
    997 
    998 	if ( j + lig->ComponentCount - i == (HB_Int)buffer->in_length )
    999 	  goto next_ligature;
   1000 	j++;
   1001       }
   1002 
   1003       if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   1004 	is_mark = FALSE;
   1005 
   1006       if ( IN_GLYPH( j ) != c[i - 1] )
   1007 	goto next_ligature;
   1008     }
   1009 
   1010     if ( gdef && gdef->NewGlyphClasses )
   1011     {
   1012       /* this is just a guess ... */
   1013 
   1014       error = _HB_GDEF_Add_Glyph_Property( gdef, lig->LigGlyph,
   1015 				  is_mark ? HB_GDEF_MARK : HB_GDEF_LIGATURE );
   1016       if ( error && error != HB_Err_Not_Covered )
   1017 	return error;
   1018     }
   1019 
   1020     if ( j == buffer->in_pos + i ) /* No input glyphs skipped */
   1021     {
   1022       /* We don't use a new ligature ID if there are no skipped
   1023 	 glyphs and the ligature already has an ID.             */
   1024 
   1025       if ( IN_LIGID( buffer->in_pos ) )
   1026       {
   1027 	if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
   1028 			0xFFFF, 0xFFFF ) )
   1029 	  return error;
   1030       }
   1031       else
   1032       {
   1033 	HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
   1034 	if ( ADD_String( buffer, i, 1, &lig->LigGlyph,
   1035 			0xFFFF, ligID ) )
   1036 	  return error;
   1037       }
   1038     }
   1039     else
   1040     {
   1041       HB_UShort ligID = _hb_buffer_allocate_ligid( buffer );
   1042       if ( ADD_Glyph( buffer, lig->LigGlyph, 0xFFFF, ligID ) )
   1043 	return error;
   1044 
   1045       /* Now we must do a second loop to copy the skipped glyphs to
   1046 	 `out' and assign component values to it.  We start with the
   1047 	 glyph after the first component.  Glyphs between component
   1048 	 i and i+1 belong to component i.  Together with the ligID
   1049 	 value it is later possible to check whether a specific
   1050 	 component value really belongs to a given ligature.         */
   1051 
   1052       for ( i = 0; i < lig->ComponentCount - 1; i++ )
   1053       {
   1054 	while ( CHECK_Property( gdef, IN_CURITEM(),
   1055 				flags, &property ) )
   1056 	  if ( ADD_Glyph( buffer, IN_CURGLYPH(), i, ligID ) )
   1057 	    return error;
   1058 
   1059 	(buffer->in_pos)++;
   1060       }
   1061     }
   1062 
   1063     return HB_Err_Ok;
   1064 
   1065   next_ligature:
   1066     ;
   1067   }
   1068 
   1069   return HB_Err_Not_Covered;
   1070 }
   1071 
   1072 
   1073 /* Do the actual substitution for a context substitution (either format
   1074    5 or 6).  This is only called after we've determined that the input
   1075    matches the subrule.                                                 */
   1076 
   1077 static HB_Error  Do_ContextSubst( HB_GSUBHeader*        gsub,
   1078 				  HB_UShort              GlyphCount,
   1079 				  HB_UShort              SubstCount,
   1080 				  HB_SubstLookupRecord* subst,
   1081 				  HB_Buffer             buffer,
   1082 				  int                    nesting_level )
   1083 {
   1084   HB_Error  error;
   1085   HB_UInt   i, old_pos;
   1086 
   1087 
   1088   i = 0;
   1089 
   1090   while ( i < GlyphCount )
   1091   {
   1092     if ( SubstCount && i == subst->SequenceIndex )
   1093     {
   1094       old_pos = buffer->in_pos;
   1095 
   1096       /* Do a substitution */
   1097 
   1098       error = GSUB_Do_Glyph_Lookup( gsub, subst->LookupListIndex, buffer,
   1099 				    GlyphCount, nesting_level );
   1100 
   1101       subst++;
   1102       SubstCount--;
   1103       i += buffer->in_pos - old_pos;
   1104 
   1105       if ( error == HB_Err_Not_Covered )
   1106       {
   1107 	if ( COPY_Glyph( buffer ) )
   1108 	  return error;
   1109 	i++;
   1110       }
   1111       else if ( error )
   1112 	return error;
   1113     }
   1114     else
   1115     {
   1116       /* No substitution for this index */
   1117 
   1118       if ( COPY_Glyph( buffer ) )
   1119 	return error;
   1120       i++;
   1121     }
   1122   }
   1123 
   1124   return HB_Err_Ok;
   1125 }
   1126 
   1127 
   1128 /* LookupType 5 */
   1129 
   1130 /* SubRule */
   1131 
   1132 static HB_Error  Load_SubRule( HB_SubRule*  sr,
   1133 			       HB_Stream     stream )
   1134 {
   1135   HB_Error error;
   1136 
   1137   HB_UShort               n, count;
   1138   HB_UShort*              i;
   1139 
   1140   HB_SubstLookupRecord*  slr;
   1141 
   1142 
   1143   if ( ACCESS_Frame( 4L ) )
   1144     return error;
   1145 
   1146   sr->GlyphCount = GET_UShort();
   1147   sr->SubstCount = GET_UShort();
   1148 
   1149   FORGET_Frame();
   1150 
   1151   sr->Input = NULL;
   1152 
   1153   count = sr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
   1154 
   1155   if ( ALLOC_ARRAY( sr->Input, count, HB_UShort ) )
   1156     return error;
   1157 
   1158   i = sr->Input;
   1159 
   1160   if ( ACCESS_Frame( count * 2L ) )
   1161     goto Fail2;
   1162 
   1163   for ( n = 0; n < count; n++ )
   1164     i[n] = GET_UShort();
   1165 
   1166   FORGET_Frame();
   1167 
   1168   sr->SubstLookupRecord = NULL;
   1169 
   1170   count = sr->SubstCount;
   1171 
   1172   if ( ALLOC_ARRAY( sr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
   1173     goto Fail2;
   1174 
   1175   slr = sr->SubstLookupRecord;
   1176 
   1177   if ( ACCESS_Frame( count * 4L ) )
   1178     goto Fail1;
   1179 
   1180   for ( n = 0; n < count; n++ )
   1181   {
   1182     slr[n].SequenceIndex   = GET_UShort();
   1183     slr[n].LookupListIndex = GET_UShort();
   1184   }
   1185 
   1186   FORGET_Frame();
   1187 
   1188   return HB_Err_Ok;
   1189 
   1190 Fail1:
   1191   FREE( slr );
   1192 
   1193 Fail2:
   1194   FREE( i );
   1195   return error;
   1196 }
   1197 
   1198 
   1199 static void  Free_SubRule( HB_SubRule*  sr )
   1200 {
   1201   FREE( sr->SubstLookupRecord );
   1202   FREE( sr->Input );
   1203 }
   1204 
   1205 
   1206 /* SubRuleSet */
   1207 
   1208 static HB_Error  Load_SubRuleSet( HB_SubRuleSet*  srs,
   1209 				  HB_Stream        stream )
   1210 {
   1211   HB_Error error;
   1212 
   1213   HB_UShort     n = 0, m, count;
   1214   HB_UInt      cur_offset, new_offset, base_offset;
   1215 
   1216   HB_SubRule*  sr;
   1217 
   1218 
   1219   base_offset = FILE_Pos();
   1220 
   1221   if ( ACCESS_Frame( 2L ) )
   1222     return error;
   1223 
   1224   count = srs->SubRuleCount = GET_UShort();
   1225 
   1226   FORGET_Frame();
   1227 
   1228   srs->SubRule = NULL;
   1229 
   1230   if ( ALLOC_ARRAY( srs->SubRule, count, HB_SubRule ) )
   1231     return error;
   1232 
   1233   sr = srs->SubRule;
   1234 
   1235   for ( n = 0; n < count; n++ )
   1236   {
   1237     if ( ACCESS_Frame( 2L ) )
   1238       goto Fail;
   1239 
   1240     new_offset = GET_UShort() + base_offset;
   1241 
   1242     FORGET_Frame();
   1243 
   1244     cur_offset = FILE_Pos();
   1245     if ( FILE_Seek( new_offset ) ||
   1246 	 ( error = Load_SubRule( &sr[n], stream ) ) != HB_Err_Ok )
   1247       goto Fail;
   1248     (void)FILE_Seek( cur_offset );
   1249   }
   1250 
   1251   return HB_Err_Ok;
   1252 
   1253 Fail:
   1254   for ( m = 0; m < n; m++ )
   1255     Free_SubRule( &sr[m] );
   1256 
   1257   FREE( sr );
   1258   return error;
   1259 }
   1260 
   1261 
   1262 static void  Free_SubRuleSet( HB_SubRuleSet*  srs )
   1263 {
   1264   HB_UShort     n, count;
   1265 
   1266   HB_SubRule*  sr;
   1267 
   1268 
   1269   if ( srs->SubRule )
   1270   {
   1271     count = srs->SubRuleCount;
   1272     sr    = srs->SubRule;
   1273 
   1274     for ( n = 0; n < count; n++ )
   1275       Free_SubRule( &sr[n] );
   1276 
   1277     FREE( sr );
   1278   }
   1279 }
   1280 
   1281 
   1282 /* ContextSubstFormat1 */
   1283 
   1284 static HB_Error  Load_ContextSubst1( HB_ContextSubstFormat1*  csf1,
   1285 				     HB_Stream                 stream )
   1286 {
   1287   HB_Error error;
   1288 
   1289   HB_UShort        n = 0, m, count;
   1290   HB_UInt         cur_offset, new_offset, base_offset;
   1291 
   1292   HB_SubRuleSet*  srs;
   1293 
   1294 
   1295   base_offset = FILE_Pos() - 2L;
   1296 
   1297   if ( ACCESS_Frame( 2L ) )
   1298     return error;
   1299 
   1300   new_offset = GET_UShort() + base_offset;
   1301 
   1302   FORGET_Frame();
   1303 
   1304   cur_offset = FILE_Pos();
   1305   if ( FILE_Seek( new_offset ) ||
   1306        ( error = _HB_OPEN_Load_Coverage( &csf1->Coverage, stream ) ) != HB_Err_Ok )
   1307     return error;
   1308   (void)FILE_Seek( cur_offset );
   1309 
   1310   if ( ACCESS_Frame( 2L ) )
   1311     goto Fail2;
   1312 
   1313   count = csf1->SubRuleSetCount = GET_UShort();
   1314 
   1315   FORGET_Frame();
   1316 
   1317   csf1->SubRuleSet = NULL;
   1318 
   1319   if ( ALLOC_ARRAY( csf1->SubRuleSet, count, HB_SubRuleSet ) )
   1320     goto Fail2;
   1321 
   1322   srs = csf1->SubRuleSet;
   1323 
   1324   for ( n = 0; n < count; n++ )
   1325   {
   1326     if ( ACCESS_Frame( 2L ) )
   1327       goto Fail1;
   1328 
   1329     new_offset = GET_UShort() + base_offset;
   1330 
   1331     FORGET_Frame();
   1332 
   1333     cur_offset = FILE_Pos();
   1334     if ( FILE_Seek( new_offset ) ||
   1335 	 ( error = Load_SubRuleSet( &srs[n], stream ) ) != HB_Err_Ok )
   1336       goto Fail1;
   1337     (void)FILE_Seek( cur_offset );
   1338   }
   1339 
   1340   return HB_Err_Ok;
   1341 
   1342 Fail1:
   1343   for ( m = 0; m < n; m++ )
   1344     Free_SubRuleSet( &srs[m] );
   1345 
   1346   FREE( srs );
   1347 
   1348 Fail2:
   1349   _HB_OPEN_Free_Coverage( &csf1->Coverage );
   1350   return error;
   1351 }
   1352 
   1353 
   1354 static void  Free_ContextSubst1( HB_ContextSubstFormat1* csf1 )
   1355 {
   1356   HB_UShort        n, count;
   1357 
   1358   HB_SubRuleSet*  srs;
   1359 
   1360 
   1361   if ( csf1->SubRuleSet )
   1362   {
   1363     count = csf1->SubRuleSetCount;
   1364     srs   = csf1->SubRuleSet;
   1365 
   1366     for ( n = 0; n < count; n++ )
   1367       Free_SubRuleSet( &srs[n] );
   1368 
   1369     FREE( srs );
   1370   }
   1371 
   1372   _HB_OPEN_Free_Coverage( &csf1->Coverage );
   1373 }
   1374 
   1375 
   1376 /* SubClassRule */
   1377 
   1378 static HB_Error  Load_SubClassRule( HB_ContextSubstFormat2*  csf2,
   1379 				    HB_SubClassRule*         scr,
   1380 				    HB_Stream                 stream )
   1381 {
   1382   HB_Error error;
   1383 
   1384   HB_UShort               n, count;
   1385 
   1386   HB_UShort*              c;
   1387   HB_SubstLookupRecord*  slr;
   1388 
   1389 
   1390   if ( ACCESS_Frame( 4L ) )
   1391     return error;
   1392 
   1393   scr->GlyphCount = GET_UShort();
   1394   scr->SubstCount = GET_UShort();
   1395 
   1396   if ( scr->GlyphCount > csf2->MaxContextLength )
   1397     csf2->MaxContextLength = scr->GlyphCount;
   1398 
   1399   FORGET_Frame();
   1400 
   1401   scr->Class = NULL;
   1402 
   1403   count = scr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
   1404 
   1405   if ( ALLOC_ARRAY( scr->Class, count, HB_UShort ) )
   1406     return error;
   1407 
   1408   c = scr->Class;
   1409 
   1410   if ( ACCESS_Frame( count * 2L ) )
   1411     goto Fail2;
   1412 
   1413   for ( n = 0; n < count; n++ )
   1414     c[n] = GET_UShort();
   1415 
   1416   FORGET_Frame();
   1417 
   1418   scr->SubstLookupRecord = NULL;
   1419 
   1420   count = scr->SubstCount;
   1421 
   1422   if ( ALLOC_ARRAY( scr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
   1423     goto Fail2;
   1424 
   1425   slr = scr->SubstLookupRecord;
   1426 
   1427   if ( ACCESS_Frame( count * 4L ) )
   1428     goto Fail1;
   1429 
   1430   for ( n = 0; n < count; n++ )
   1431   {
   1432     slr[n].SequenceIndex   = GET_UShort();
   1433     slr[n].LookupListIndex = GET_UShort();
   1434   }
   1435 
   1436   FORGET_Frame();
   1437 
   1438   return HB_Err_Ok;
   1439 
   1440 Fail1:
   1441   FREE( slr );
   1442 
   1443 Fail2:
   1444   FREE( c );
   1445   return error;
   1446 }
   1447 
   1448 
   1449 static void  Free_SubClassRule( HB_SubClassRule*  scr )
   1450 {
   1451   FREE( scr->SubstLookupRecord );
   1452   FREE( scr->Class );
   1453 }
   1454 
   1455 
   1456 /* SubClassSet */
   1457 
   1458 static HB_Error  Load_SubClassSet( HB_ContextSubstFormat2*  csf2,
   1459 				   HB_SubClassSet*          scs,
   1460 				   HB_Stream                 stream )
   1461 {
   1462   HB_Error error;
   1463 
   1464   HB_UShort          n = 0, m, count;
   1465   HB_UInt           cur_offset, new_offset, base_offset;
   1466 
   1467   HB_SubClassRule*  scr;
   1468 
   1469 
   1470   base_offset = FILE_Pos();
   1471 
   1472   if ( ACCESS_Frame( 2L ) )
   1473     return error;
   1474 
   1475   count = scs->SubClassRuleCount = GET_UShort();
   1476 
   1477   FORGET_Frame();
   1478 
   1479   scs->SubClassRule = NULL;
   1480 
   1481   if ( ALLOC_ARRAY( scs->SubClassRule, count, HB_SubClassRule ) )
   1482     return error;
   1483 
   1484   scr = scs->SubClassRule;
   1485 
   1486   for ( n = 0; n < count; n++ )
   1487   {
   1488     if ( ACCESS_Frame( 2L ) )
   1489       goto Fail;
   1490 
   1491     new_offset = GET_UShort() + base_offset;
   1492 
   1493     FORGET_Frame();
   1494 
   1495     cur_offset = FILE_Pos();
   1496     if ( FILE_Seek( new_offset ) ||
   1497 	 ( error = Load_SubClassRule( csf2, &scr[n],
   1498 				      stream ) ) != HB_Err_Ok )
   1499       goto Fail;
   1500     (void)FILE_Seek( cur_offset );
   1501   }
   1502 
   1503   return HB_Err_Ok;
   1504 
   1505 Fail:
   1506   for ( m = 0; m < n; m++ )
   1507     Free_SubClassRule( &scr[m] );
   1508 
   1509   FREE( scr );
   1510   return error;
   1511 }
   1512 
   1513 
   1514 static void  Free_SubClassSet( HB_SubClassSet*  scs )
   1515 {
   1516   HB_UShort          n, count;
   1517 
   1518   HB_SubClassRule*  scr;
   1519 
   1520 
   1521   if ( scs->SubClassRule )
   1522   {
   1523     count = scs->SubClassRuleCount;
   1524     scr   = scs->SubClassRule;
   1525 
   1526     for ( n = 0; n < count; n++ )
   1527       Free_SubClassRule( &scr[n] );
   1528 
   1529     FREE( scr );
   1530   }
   1531 }
   1532 
   1533 
   1534 /* ContextSubstFormat2 */
   1535 
   1536 static HB_Error  Load_ContextSubst2( HB_ContextSubstFormat2*  csf2,
   1537 				     HB_Stream                 stream )
   1538 {
   1539   HB_Error error;
   1540 
   1541   HB_UShort         n = 0, m, count;
   1542   HB_UInt          cur_offset, new_offset, base_offset;
   1543 
   1544   HB_SubClassSet*  scs;
   1545 
   1546 
   1547   base_offset = FILE_Pos() - 2;
   1548 
   1549   if ( ACCESS_Frame( 2L ) )
   1550     return error;
   1551 
   1552   new_offset = GET_UShort() + base_offset;
   1553 
   1554   FORGET_Frame();
   1555 
   1556   cur_offset = FILE_Pos();
   1557   if ( FILE_Seek( new_offset ) ||
   1558        ( error = _HB_OPEN_Load_Coverage( &csf2->Coverage, stream ) ) != HB_Err_Ok )
   1559     return error;
   1560   (void)FILE_Seek( cur_offset );
   1561 
   1562   if ( ACCESS_Frame( 4L ) )
   1563     goto Fail3;
   1564 
   1565   new_offset = GET_UShort() + base_offset;
   1566 
   1567   /* `SubClassSetCount' is the upper limit for class values, thus we
   1568      read it now to make an additional safety check.                 */
   1569 
   1570   count = csf2->SubClassSetCount = GET_UShort();
   1571 
   1572   FORGET_Frame();
   1573 
   1574   cur_offset = FILE_Pos();
   1575   if ( FILE_Seek( new_offset ) ||
   1576        ( error = _HB_OPEN_Load_ClassDefinition( &csf2->ClassDef, count,
   1577 				       stream ) ) != HB_Err_Ok )
   1578     goto Fail3;
   1579   (void)FILE_Seek( cur_offset );
   1580 
   1581   csf2->SubClassSet      = NULL;
   1582   csf2->MaxContextLength = 0;
   1583 
   1584   if ( ALLOC_ARRAY( csf2->SubClassSet, count, HB_SubClassSet ) )
   1585     goto Fail2;
   1586 
   1587   scs = csf2->SubClassSet;
   1588 
   1589   for ( n = 0; n < count; n++ )
   1590   {
   1591     if ( ACCESS_Frame( 2L ) )
   1592       goto Fail1;
   1593 
   1594     new_offset = GET_UShort() + base_offset;
   1595 
   1596     FORGET_Frame();
   1597 
   1598     if ( new_offset != base_offset )      /* not a NULL offset */
   1599     {
   1600       cur_offset = FILE_Pos();
   1601       if ( FILE_Seek( new_offset ) ||
   1602 	   ( error = Load_SubClassSet( csf2, &scs[n],
   1603 				       stream ) ) != HB_Err_Ok )
   1604 	goto Fail1;
   1605       (void)FILE_Seek( cur_offset );
   1606     }
   1607     else
   1608     {
   1609       /* we create a SubClassSet table with no entries */
   1610 
   1611       csf2->SubClassSet[n].SubClassRuleCount = 0;
   1612       csf2->SubClassSet[n].SubClassRule      = NULL;
   1613     }
   1614   }
   1615 
   1616   return HB_Err_Ok;
   1617 
   1618 Fail1:
   1619   for ( m = 0; m < n; m++ )
   1620     Free_SubClassSet( &scs[m] );
   1621 
   1622   FREE( scs );
   1623 
   1624 Fail2:
   1625   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
   1626 
   1627 Fail3:
   1628   _HB_OPEN_Free_Coverage( &csf2->Coverage );
   1629   return error;
   1630 }
   1631 
   1632 
   1633 static void  Free_ContextSubst2( HB_ContextSubstFormat2*  csf2 )
   1634 {
   1635   HB_UShort         n, count;
   1636 
   1637   HB_SubClassSet*  scs;
   1638 
   1639 
   1640   if ( csf2->SubClassSet )
   1641   {
   1642     count = csf2->SubClassSetCount;
   1643     scs   = csf2->SubClassSet;
   1644 
   1645     for ( n = 0; n < count; n++ )
   1646       Free_SubClassSet( &scs[n] );
   1647 
   1648     FREE( scs );
   1649   }
   1650 
   1651   _HB_OPEN_Free_ClassDefinition( &csf2->ClassDef );
   1652   _HB_OPEN_Free_Coverage( &csf2->Coverage );
   1653 }
   1654 
   1655 
   1656 /* ContextSubstFormat3 */
   1657 
   1658 static HB_Error  Load_ContextSubst3( HB_ContextSubstFormat3*  csf3,
   1659 				     HB_Stream                 stream )
   1660 {
   1661   HB_Error error;
   1662 
   1663   HB_UShort               n = 0, m, count;
   1664   HB_UInt                cur_offset, new_offset, base_offset;
   1665 
   1666   HB_Coverage*           c;
   1667   HB_SubstLookupRecord*  slr;
   1668 
   1669 
   1670   base_offset = FILE_Pos() - 2L;
   1671 
   1672   if ( ACCESS_Frame( 4L ) )
   1673     return error;
   1674 
   1675   csf3->GlyphCount = GET_UShort();
   1676   csf3->SubstCount = GET_UShort();
   1677 
   1678   FORGET_Frame();
   1679 
   1680   csf3->Coverage = NULL;
   1681 
   1682   count = csf3->GlyphCount;
   1683 
   1684   if ( ALLOC_ARRAY( csf3->Coverage, count, HB_Coverage ) )
   1685     return error;
   1686 
   1687   c = csf3->Coverage;
   1688 
   1689   for ( n = 0; n < count; n++ )
   1690   {
   1691     if ( ACCESS_Frame( 2L ) )
   1692       goto Fail2;
   1693 
   1694     new_offset = GET_UShort() + base_offset;
   1695 
   1696     FORGET_Frame();
   1697 
   1698     cur_offset = FILE_Pos();
   1699     if ( FILE_Seek( new_offset ) ||
   1700 	 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
   1701       goto Fail2;
   1702     (void)FILE_Seek( cur_offset );
   1703   }
   1704 
   1705   csf3->SubstLookupRecord = NULL;
   1706 
   1707   count = csf3->SubstCount;
   1708 
   1709   if ( ALLOC_ARRAY( csf3->SubstLookupRecord, count,
   1710 		    HB_SubstLookupRecord ) )
   1711     goto Fail2;
   1712 
   1713   slr = csf3->SubstLookupRecord;
   1714 
   1715   if ( ACCESS_Frame( count * 4L ) )
   1716     goto Fail1;
   1717 
   1718   for ( n = 0; n < count; n++ )
   1719   {
   1720     slr[n].SequenceIndex   = GET_UShort();
   1721     slr[n].LookupListIndex = GET_UShort();
   1722   }
   1723 
   1724   FORGET_Frame();
   1725 
   1726   return HB_Err_Ok;
   1727 
   1728 Fail1:
   1729   FREE( slr );
   1730 
   1731 Fail2:
   1732   for ( m = 0; m < n; m++ )
   1733     _HB_OPEN_Free_Coverage( &c[m] );
   1734 
   1735   FREE( c );
   1736   return error;
   1737 }
   1738 
   1739 
   1740 static void  Free_ContextSubst3( HB_ContextSubstFormat3*  csf3 )
   1741 {
   1742   HB_UShort      n, count;
   1743 
   1744   HB_Coverage*  c;
   1745 
   1746 
   1747   FREE( csf3->SubstLookupRecord );
   1748 
   1749   if ( csf3->Coverage )
   1750   {
   1751     count = csf3->GlyphCount;
   1752     c     = csf3->Coverage;
   1753 
   1754     for ( n = 0; n < count; n++ )
   1755       _HB_OPEN_Free_Coverage( &c[n] );
   1756 
   1757     FREE( c );
   1758   }
   1759 }
   1760 
   1761 
   1762 /* ContextSubst */
   1763 
   1764 static HB_Error  Load_ContextSubst( HB_GSUB_SubTable* st,
   1765 				    HB_Stream         stream )
   1766 {
   1767   HB_Error error;
   1768   HB_ContextSubst*  cs = &st->context;
   1769 
   1770 
   1771   if ( ACCESS_Frame( 2L ) )
   1772     return error;
   1773 
   1774   cs->SubstFormat = GET_UShort();
   1775 
   1776   FORGET_Frame();
   1777 
   1778   switch ( cs->SubstFormat )
   1779   {
   1780   case 1:  return Load_ContextSubst1( &cs->csf.csf1, stream );
   1781   case 2:  return Load_ContextSubst2( &cs->csf.csf2, stream );
   1782   case 3:  return Load_ContextSubst3( &cs->csf.csf3, stream );
   1783   default: return ERR(HB_Err_Invalid_SubTable_Format);
   1784   }
   1785 
   1786   return HB_Err_Ok;               /* never reached */
   1787 }
   1788 
   1789 
   1790 static void  Free_ContextSubst( HB_GSUB_SubTable* st )
   1791 {
   1792   HB_ContextSubst*  cs = &st->context;
   1793 
   1794   switch ( cs->SubstFormat )
   1795   {
   1796   case 1:  Free_ContextSubst1( &cs->csf.csf1 ); break;
   1797   case 2:  Free_ContextSubst2( &cs->csf.csf2 ); break;
   1798   case 3:  Free_ContextSubst3( &cs->csf.csf3 ); break;
   1799   default:						break;
   1800   }
   1801 }
   1802 
   1803 
   1804 static HB_Error  Lookup_ContextSubst1( HB_GSUBHeader*          gsub,
   1805 				       HB_ContextSubstFormat1* csf1,
   1806 				       HB_Buffer               buffer,
   1807 				       HB_UShort                flags,
   1808 				       HB_UShort                context_length,
   1809 				       int                      nesting_level )
   1810 {
   1811   HB_UShort        index, property;
   1812   HB_UShort        i, j, k, numsr;
   1813   HB_Error         error;
   1814 
   1815   HB_SubRule*     sr;
   1816   HB_GDEFHeader*  gdef;
   1817 
   1818 
   1819   gdef = gsub->gdef;
   1820 
   1821   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   1822     return error;
   1823 
   1824   error = _HB_OPEN_Coverage_Index( &csf1->Coverage, IN_CURGLYPH(), &index );
   1825   if ( error )
   1826     return error;
   1827 
   1828   sr    = csf1->SubRuleSet[index].SubRule;
   1829   numsr = csf1->SubRuleSet[index].SubRuleCount;
   1830 
   1831   for ( k = 0; k < numsr; k++ )
   1832   {
   1833     if ( context_length != 0xFFFF && context_length < sr[k].GlyphCount )
   1834       goto next_subrule;
   1835 
   1836     if ( buffer->in_pos + sr[k].GlyphCount > buffer->in_length )
   1837       goto next_subrule;                        /* context is too long */
   1838 
   1839     for ( i = 1, j = buffer->in_pos + 1; i < sr[k].GlyphCount; i++, j++ )
   1840     {
   1841       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   1842       {
   1843 	if ( error && error != HB_Err_Not_Covered )
   1844 	  return error;
   1845 
   1846 	if ( j + sr[k].GlyphCount - i == (HB_Int)buffer->in_length )
   1847 	  goto next_subrule;
   1848 	j++;
   1849       }
   1850 
   1851       if ( IN_GLYPH( j ) != sr[k].Input[i - 1] )
   1852 	goto next_subrule;
   1853     }
   1854 
   1855     return Do_ContextSubst( gsub, sr[k].GlyphCount,
   1856 			    sr[k].SubstCount, sr[k].SubstLookupRecord,
   1857 			    buffer,
   1858 			    nesting_level );
   1859   next_subrule:
   1860     ;
   1861   }
   1862 
   1863   return HB_Err_Not_Covered;
   1864 }
   1865 
   1866 
   1867 static HB_Error  Lookup_ContextSubst2( HB_GSUBHeader*          gsub,
   1868 				       HB_ContextSubstFormat2* csf2,
   1869 				       HB_Buffer               buffer,
   1870 				       HB_UShort                flags,
   1871 				       HB_UShort                context_length,
   1872 				       int                      nesting_level )
   1873 {
   1874   HB_UShort          index, property;
   1875   HB_Error           error;
   1876   HB_UShort          i, j, k, known_classes;
   1877 
   1878   HB_UShort*         classes;
   1879   HB_UShort*         cl;
   1880 
   1881   HB_SubClassSet*   scs;
   1882   HB_SubClassRule*  sr;
   1883   HB_GDEFHeader*    gdef;
   1884 
   1885 
   1886   gdef = gsub->gdef;
   1887 
   1888   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   1889     return error;
   1890 
   1891   /* Note: The coverage table in format 2 doesn't give an index into
   1892 	   anything.  It just lets us know whether or not we need to
   1893 	   do any lookup at all.                                     */
   1894 
   1895   error = _HB_OPEN_Coverage_Index( &csf2->Coverage, IN_CURGLYPH(), &index );
   1896   if ( error )
   1897     return error;
   1898 
   1899   if (csf2->MaxContextLength < 1)
   1900     return HB_Err_Not_Covered;
   1901 
   1902   if ( ALLOC_ARRAY( classes, csf2->MaxContextLength, HB_UShort ) )
   1903     return error;
   1904 
   1905   error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_CURGLYPH(),
   1906 		     &classes[0], NULL );
   1907   if ( error && error != HB_Err_Not_Covered )
   1908     goto End;
   1909   known_classes = 0;
   1910 
   1911   scs = &csf2->SubClassSet[classes[0]];
   1912   if ( !scs )
   1913   {
   1914     error = ERR(HB_Err_Invalid_SubTable);
   1915     goto End;
   1916   }
   1917 
   1918   for ( k = 0; k < scs->SubClassRuleCount; k++ )
   1919   {
   1920     sr  = &scs->SubClassRule[k];
   1921 
   1922     if ( context_length != 0xFFFF && context_length < sr->GlyphCount )
   1923       goto next_subclassrule;
   1924 
   1925     if ( buffer->in_pos + sr->GlyphCount > buffer->in_length )
   1926       goto next_subclassrule;                      /* context is too long */
   1927 
   1928     cl   = sr->Class;
   1929 
   1930     /* Start at 1 because [0] is implied */
   1931 
   1932     for ( i = 1, j = buffer->in_pos + 1; i < sr->GlyphCount; i++, j++ )
   1933     {
   1934       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   1935       {
   1936 	if ( error && error != HB_Err_Not_Covered )
   1937 	  goto End;
   1938 
   1939 	if ( j + sr->GlyphCount - i < (HB_Int)buffer->in_length )
   1940 	  goto next_subclassrule;
   1941 	j++;
   1942       }
   1943 
   1944       if ( i > known_classes )
   1945       {
   1946 	/* Keeps us from having to do this for each rule */
   1947 
   1948 	error = _HB_OPEN_Get_Class( &csf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
   1949 	if ( error && error != HB_Err_Not_Covered )
   1950 	  goto End;
   1951 	known_classes = i;
   1952       }
   1953 
   1954       if ( cl[i - 1] != classes[i] )
   1955 	goto next_subclassrule;
   1956     }
   1957 
   1958     error = Do_ContextSubst( gsub, sr->GlyphCount,
   1959 			     sr->SubstCount, sr->SubstLookupRecord,
   1960 			     buffer,
   1961 			     nesting_level );
   1962     goto End;
   1963 
   1964   next_subclassrule:
   1965     ;
   1966   }
   1967 
   1968   error = HB_Err_Not_Covered;
   1969 
   1970 End:
   1971   FREE( classes );
   1972   return error;
   1973 }
   1974 
   1975 
   1976 static HB_Error  Lookup_ContextSubst3( HB_GSUBHeader*          gsub,
   1977 				       HB_ContextSubstFormat3* csf3,
   1978 				       HB_Buffer               buffer,
   1979 				       HB_UShort                flags,
   1980 				       HB_UShort                context_length,
   1981 				       int                      nesting_level )
   1982 {
   1983   HB_Error         error;
   1984   HB_UShort        index, i, j, property;
   1985 
   1986   HB_Coverage*    c;
   1987   HB_GDEFHeader*  gdef;
   1988 
   1989 
   1990   gdef = gsub->gdef;
   1991 
   1992   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   1993     return error;
   1994 
   1995   if ( context_length != 0xFFFF && context_length < csf3->GlyphCount )
   1996     return HB_Err_Not_Covered;
   1997 
   1998   if ( buffer->in_pos + csf3->GlyphCount > buffer->in_length )
   1999     return HB_Err_Not_Covered;         /* context is too long */
   2000 
   2001   c    = csf3->Coverage;
   2002 
   2003   for ( i = 1, j = buffer->in_pos + 1; i < csf3->GlyphCount; i++, j++ )
   2004   {
   2005     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   2006     {
   2007       if ( error && error != HB_Err_Not_Covered )
   2008 	return error;
   2009 
   2010       if ( j + csf3->GlyphCount - i == (HB_Int)buffer->in_length )
   2011 	return HB_Err_Not_Covered;
   2012       j++;
   2013     }
   2014 
   2015     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
   2016     if ( error )
   2017       return error;
   2018   }
   2019 
   2020   return Do_ContextSubst( gsub, csf3->GlyphCount,
   2021 			  csf3->SubstCount, csf3->SubstLookupRecord,
   2022 			  buffer,
   2023 			  nesting_level );
   2024 }
   2025 
   2026 
   2027 static HB_Error  Lookup_ContextSubst( HB_GSUBHeader*    gsub,
   2028 				      HB_GSUB_SubTable* st,
   2029 				      HB_Buffer         buffer,
   2030 				      HB_UShort          flags,
   2031 				      HB_UShort          context_length,
   2032 				      int                nesting_level )
   2033 {
   2034   HB_ContextSubst*  cs = &st->context;
   2035 
   2036   switch ( cs->SubstFormat )
   2037   {
   2038   case 1:  return Lookup_ContextSubst1( gsub, &cs->csf.csf1, buffer, flags, context_length, nesting_level );
   2039   case 2:  return Lookup_ContextSubst2( gsub, &cs->csf.csf2, buffer, flags, context_length, nesting_level );
   2040   case 3:  return Lookup_ContextSubst3( gsub, &cs->csf.csf3, buffer, flags, context_length, nesting_level );
   2041   default: return ERR(HB_Err_Invalid_SubTable_Format);
   2042   }
   2043 
   2044   return HB_Err_Ok;               /* never reached */
   2045 }
   2046 
   2047 
   2048 /* LookupType 6 */
   2049 
   2050 /* ChainSubRule */
   2051 
   2052 static HB_Error  Load_ChainSubRule( HB_ChainSubRule*  csr,
   2053 				    HB_Stream          stream )
   2054 {
   2055   HB_Error error;
   2056 
   2057   HB_UShort               n, count;
   2058   HB_UShort*              b;
   2059   HB_UShort*              i;
   2060   HB_UShort*              l;
   2061 
   2062   HB_SubstLookupRecord*  slr;
   2063 
   2064 
   2065   if ( ACCESS_Frame( 2L ) )
   2066     return error;
   2067 
   2068   csr->BacktrackGlyphCount = GET_UShort();
   2069 
   2070   FORGET_Frame();
   2071 
   2072   csr->Backtrack = NULL;
   2073 
   2074   count = csr->BacktrackGlyphCount;
   2075 
   2076   if ( ALLOC_ARRAY( csr->Backtrack, count, HB_UShort ) )
   2077     return error;
   2078 
   2079   b = csr->Backtrack;
   2080 
   2081   if ( ACCESS_Frame( count * 2L ) )
   2082     goto Fail4;
   2083 
   2084   for ( n = 0; n < count; n++ )
   2085     b[n] = GET_UShort();
   2086 
   2087   FORGET_Frame();
   2088 
   2089   if ( ACCESS_Frame( 2L ) )
   2090     goto Fail4;
   2091 
   2092   csr->InputGlyphCount = GET_UShort();
   2093 
   2094   FORGET_Frame();
   2095 
   2096   csr->Input = NULL;
   2097 
   2098   count = csr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
   2099 
   2100   if ( ALLOC_ARRAY( csr->Input, count, HB_UShort ) )
   2101     goto Fail4;
   2102 
   2103   i = csr->Input;
   2104 
   2105   if ( ACCESS_Frame( count * 2L ) )
   2106     goto Fail3;
   2107 
   2108   for ( n = 0; n < count; n++ )
   2109     i[n] = GET_UShort();
   2110 
   2111   FORGET_Frame();
   2112 
   2113   if ( ACCESS_Frame( 2L ) )
   2114     goto Fail3;
   2115 
   2116   csr->LookaheadGlyphCount = GET_UShort();
   2117 
   2118   FORGET_Frame();
   2119 
   2120   csr->Lookahead = NULL;
   2121 
   2122   count = csr->LookaheadGlyphCount;
   2123 
   2124   if ( ALLOC_ARRAY( csr->Lookahead, count, HB_UShort ) )
   2125     goto Fail3;
   2126 
   2127   l = csr->Lookahead;
   2128 
   2129   if ( ACCESS_Frame( count * 2L ) )
   2130     goto Fail2;
   2131 
   2132   for ( n = 0; n < count; n++ )
   2133     l[n] = GET_UShort();
   2134 
   2135   FORGET_Frame();
   2136 
   2137   if ( ACCESS_Frame( 2L ) )
   2138     goto Fail2;
   2139 
   2140   csr->SubstCount = GET_UShort();
   2141 
   2142   FORGET_Frame();
   2143 
   2144   csr->SubstLookupRecord = NULL;
   2145 
   2146   count = csr->SubstCount;
   2147 
   2148   if ( ALLOC_ARRAY( csr->SubstLookupRecord, count, HB_SubstLookupRecord ) )
   2149     goto Fail2;
   2150 
   2151   slr = csr->SubstLookupRecord;
   2152 
   2153   if ( ACCESS_Frame( count * 4L ) )
   2154     goto Fail1;
   2155 
   2156   for ( n = 0; n < count; n++ )
   2157   {
   2158     slr[n].SequenceIndex   = GET_UShort();
   2159     slr[n].LookupListIndex = GET_UShort();
   2160   }
   2161 
   2162   FORGET_Frame();
   2163 
   2164   return HB_Err_Ok;
   2165 
   2166 Fail1:
   2167   FREE( slr );
   2168 
   2169 Fail2:
   2170   FREE( l );
   2171 
   2172 Fail3:
   2173   FREE( i );
   2174 
   2175 Fail4:
   2176   FREE( b );
   2177   return error;
   2178 }
   2179 
   2180 
   2181 static void  Free_ChainSubRule( HB_ChainSubRule*  csr )
   2182 {
   2183   FREE( csr->SubstLookupRecord );
   2184   FREE( csr->Lookahead );
   2185   FREE( csr->Input );
   2186   FREE( csr->Backtrack );
   2187 }
   2188 
   2189 
   2190 /* ChainSubRuleSet */
   2191 
   2192 static HB_Error  Load_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs,
   2193 				       HB_Stream             stream )
   2194 {
   2195   HB_Error error;
   2196 
   2197   HB_UShort          n = 0, m, count;
   2198   HB_UInt           cur_offset, new_offset, base_offset;
   2199 
   2200   HB_ChainSubRule*  csr;
   2201 
   2202 
   2203   base_offset = FILE_Pos();
   2204 
   2205   if ( ACCESS_Frame( 2L ) )
   2206     return error;
   2207 
   2208   count = csrs->ChainSubRuleCount = GET_UShort();
   2209 
   2210   FORGET_Frame();
   2211 
   2212   csrs->ChainSubRule = NULL;
   2213 
   2214   if ( ALLOC_ARRAY( csrs->ChainSubRule, count, HB_ChainSubRule ) )
   2215     return error;
   2216 
   2217   csr = csrs->ChainSubRule;
   2218 
   2219   for ( n = 0; n < count; n++ )
   2220   {
   2221     if ( ACCESS_Frame( 2L ) )
   2222       goto Fail;
   2223 
   2224     new_offset = GET_UShort() + base_offset;
   2225 
   2226     FORGET_Frame();
   2227 
   2228     cur_offset = FILE_Pos();
   2229     if ( FILE_Seek( new_offset ) ||
   2230 	 ( error = Load_ChainSubRule( &csr[n], stream ) ) != HB_Err_Ok )
   2231       goto Fail;
   2232     (void)FILE_Seek( cur_offset );
   2233   }
   2234 
   2235   return HB_Err_Ok;
   2236 
   2237 Fail:
   2238   for ( m = 0; m < n; m++ )
   2239     Free_ChainSubRule( &csr[m] );
   2240 
   2241   FREE( csr );
   2242   return error;
   2243 }
   2244 
   2245 
   2246 static void  Free_ChainSubRuleSet( HB_ChainSubRuleSet*  csrs )
   2247 {
   2248   HB_UShort          n, count;
   2249 
   2250   HB_ChainSubRule*  csr;
   2251 
   2252 
   2253   if ( csrs->ChainSubRule )
   2254   {
   2255     count = csrs->ChainSubRuleCount;
   2256     csr   = csrs->ChainSubRule;
   2257 
   2258     for ( n = 0; n < count; n++ )
   2259       Free_ChainSubRule( &csr[n] );
   2260 
   2261     FREE( csr );
   2262   }
   2263 }
   2264 
   2265 
   2266 /* ChainContextSubstFormat1 */
   2267 
   2268 static HB_Error  Load_ChainContextSubst1(
   2269 		   HB_ChainContextSubstFormat1*  ccsf1,
   2270 		   HB_Stream                      stream )
   2271 {
   2272   HB_Error error;
   2273 
   2274   HB_UShort             n = 0, m, count;
   2275   HB_UInt              cur_offset, new_offset, base_offset;
   2276 
   2277   HB_ChainSubRuleSet*  csrs;
   2278 
   2279 
   2280   base_offset = FILE_Pos() - 2L;
   2281 
   2282   if ( ACCESS_Frame( 2L ) )
   2283     return error;
   2284 
   2285   new_offset = GET_UShort() + base_offset;
   2286 
   2287   FORGET_Frame();
   2288 
   2289   cur_offset = FILE_Pos();
   2290   if ( FILE_Seek( new_offset ) ||
   2291        ( error = _HB_OPEN_Load_Coverage( &ccsf1->Coverage, stream ) ) != HB_Err_Ok )
   2292     return error;
   2293   (void)FILE_Seek( cur_offset );
   2294 
   2295   if ( ACCESS_Frame( 2L ) )
   2296     goto Fail2;
   2297 
   2298   count = ccsf1->ChainSubRuleSetCount = GET_UShort();
   2299 
   2300   FORGET_Frame();
   2301 
   2302   ccsf1->ChainSubRuleSet = NULL;
   2303 
   2304   if ( ALLOC_ARRAY( ccsf1->ChainSubRuleSet, count, HB_ChainSubRuleSet ) )
   2305     goto Fail2;
   2306 
   2307   csrs = ccsf1->ChainSubRuleSet;
   2308 
   2309   for ( n = 0; n < count; n++ )
   2310   {
   2311     if ( ACCESS_Frame( 2L ) )
   2312       goto Fail1;
   2313 
   2314     new_offset = GET_UShort() + base_offset;
   2315 
   2316     FORGET_Frame();
   2317 
   2318     cur_offset = FILE_Pos();
   2319     if ( FILE_Seek( new_offset ) ||
   2320 	 ( error = Load_ChainSubRuleSet( &csrs[n], stream ) ) != HB_Err_Ok )
   2321       goto Fail1;
   2322     (void)FILE_Seek( cur_offset );
   2323   }
   2324 
   2325   return HB_Err_Ok;
   2326 
   2327 Fail1:
   2328   for ( m = 0; m < n; m++ )
   2329     Free_ChainSubRuleSet( &csrs[m] );
   2330 
   2331   FREE( csrs );
   2332 
   2333 Fail2:
   2334   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
   2335   return error;
   2336 }
   2337 
   2338 
   2339 static void  Free_ChainContextSubst1( HB_ChainContextSubstFormat1*  ccsf1 )
   2340 {
   2341   HB_UShort             n, count;
   2342 
   2343   HB_ChainSubRuleSet*  csrs;
   2344 
   2345 
   2346   if ( ccsf1->ChainSubRuleSet )
   2347   {
   2348     count = ccsf1->ChainSubRuleSetCount;
   2349     csrs  = ccsf1->ChainSubRuleSet;
   2350 
   2351     for ( n = 0; n < count; n++ )
   2352       Free_ChainSubRuleSet( &csrs[n] );
   2353 
   2354     FREE( csrs );
   2355   }
   2356 
   2357   _HB_OPEN_Free_Coverage( &ccsf1->Coverage );
   2358 }
   2359 
   2360 
   2361 /* ChainSubClassRule */
   2362 
   2363 static HB_Error  Load_ChainSubClassRule(
   2364 		   HB_ChainContextSubstFormat2*  ccsf2,
   2365 		   HB_ChainSubClassRule*         cscr,
   2366 		   HB_Stream                      stream )
   2367 {
   2368   HB_Error error;
   2369 
   2370   HB_UShort               n, count;
   2371 
   2372   HB_UShort*              b;
   2373   HB_UShort*              i;
   2374   HB_UShort*              l;
   2375   HB_SubstLookupRecord*  slr;
   2376 
   2377 
   2378   if ( ACCESS_Frame( 2L ) )
   2379     return error;
   2380 
   2381   cscr->BacktrackGlyphCount = GET_UShort();
   2382 
   2383   FORGET_Frame();
   2384 
   2385   if ( cscr->BacktrackGlyphCount > ccsf2->MaxBacktrackLength )
   2386     ccsf2->MaxBacktrackLength = cscr->BacktrackGlyphCount;
   2387 
   2388   cscr->Backtrack = NULL;
   2389 
   2390   count = cscr->BacktrackGlyphCount;
   2391 
   2392   if ( ALLOC_ARRAY( cscr->Backtrack, count, HB_UShort ) )
   2393     return error;
   2394 
   2395   b = cscr->Backtrack;
   2396 
   2397   if ( ACCESS_Frame( count * 2L ) )
   2398     goto Fail4;
   2399 
   2400   for ( n = 0; n < count; n++ )
   2401     b[n] = GET_UShort();
   2402 
   2403   FORGET_Frame();
   2404 
   2405   if ( ACCESS_Frame( 2L ) )
   2406     goto Fail4;
   2407 
   2408   cscr->InputGlyphCount = GET_UShort();
   2409 
   2410   FORGET_Frame();
   2411 
   2412   if ( cscr->InputGlyphCount > ccsf2->MaxInputLength )
   2413     ccsf2->MaxInputLength = cscr->InputGlyphCount;
   2414 
   2415   cscr->Input = NULL;
   2416 
   2417   count = cscr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
   2418 
   2419   if ( ALLOC_ARRAY( cscr->Input, count, HB_UShort ) )
   2420     goto Fail4;
   2421 
   2422   i = cscr->Input;
   2423 
   2424   if ( ACCESS_Frame( count * 2L ) )
   2425     goto Fail3;
   2426 
   2427   for ( n = 0; n < count; n++ )
   2428     i[n] = GET_UShort();
   2429 
   2430   FORGET_Frame();
   2431 
   2432   if ( ACCESS_Frame( 2L ) )
   2433     goto Fail3;
   2434 
   2435   cscr->LookaheadGlyphCount = GET_UShort();
   2436 
   2437   FORGET_Frame();
   2438 
   2439   if ( cscr->LookaheadGlyphCount > ccsf2->MaxLookaheadLength )
   2440     ccsf2->MaxLookaheadLength = cscr->LookaheadGlyphCount;
   2441 
   2442   cscr->Lookahead = NULL;
   2443 
   2444   count = cscr->LookaheadGlyphCount;
   2445 
   2446   if ( ALLOC_ARRAY( cscr->Lookahead, count, HB_UShort ) )
   2447     goto Fail3;
   2448 
   2449   l = cscr->Lookahead;
   2450 
   2451   if ( ACCESS_Frame( count * 2L ) )
   2452     goto Fail2;
   2453 
   2454   for ( n = 0; n < count; n++ )
   2455     l[n] = GET_UShort();
   2456 
   2457   FORGET_Frame();
   2458 
   2459   if ( ACCESS_Frame( 2L ) )
   2460     goto Fail2;
   2461 
   2462   cscr->SubstCount = GET_UShort();
   2463 
   2464   FORGET_Frame();
   2465 
   2466   cscr->SubstLookupRecord = NULL;
   2467 
   2468   count = cscr->SubstCount;
   2469 
   2470   if ( ALLOC_ARRAY( cscr->SubstLookupRecord, count,
   2471 		    HB_SubstLookupRecord ) )
   2472     goto Fail2;
   2473 
   2474   slr = cscr->SubstLookupRecord;
   2475 
   2476   if ( ACCESS_Frame( count * 4L ) )
   2477     goto Fail1;
   2478 
   2479   for ( n = 0; n < count; n++ )
   2480   {
   2481     slr[n].SequenceIndex   = GET_UShort();
   2482     slr[n].LookupListIndex = GET_UShort();
   2483   }
   2484 
   2485   FORGET_Frame();
   2486 
   2487   return HB_Err_Ok;
   2488 
   2489 Fail1:
   2490   FREE( slr );
   2491 
   2492 Fail2:
   2493   FREE( l );
   2494 
   2495 Fail3:
   2496   FREE( i );
   2497 
   2498 Fail4:
   2499   FREE( b );
   2500   return error;
   2501 }
   2502 
   2503 
   2504 static void  Free_ChainSubClassRule( HB_ChainSubClassRule*  cscr )
   2505 {
   2506   FREE( cscr->SubstLookupRecord );
   2507   FREE( cscr->Lookahead );
   2508   FREE( cscr->Input );
   2509   FREE( cscr->Backtrack );
   2510 }
   2511 
   2512 
   2513 /* SubClassSet */
   2514 
   2515 static HB_Error  Load_ChainSubClassSet(
   2516 		   HB_ChainContextSubstFormat2*  ccsf2,
   2517 		   HB_ChainSubClassSet*          cscs,
   2518 		   HB_Stream                      stream )
   2519 {
   2520   HB_Error error;
   2521 
   2522   HB_UShort               n = 0, m, count;
   2523   HB_UInt                cur_offset, new_offset, base_offset;
   2524 
   2525   HB_ChainSubClassRule*  cscr;
   2526 
   2527 
   2528   base_offset = FILE_Pos();
   2529 
   2530   if ( ACCESS_Frame( 2L ) )
   2531     return error;
   2532 
   2533   count = cscs->ChainSubClassRuleCount = GET_UShort();
   2534 
   2535   FORGET_Frame();
   2536 
   2537   cscs->ChainSubClassRule = NULL;
   2538 
   2539   if ( ALLOC_ARRAY( cscs->ChainSubClassRule, count,
   2540 		    HB_ChainSubClassRule ) )
   2541     return error;
   2542 
   2543   cscr = cscs->ChainSubClassRule;
   2544 
   2545   for ( n = 0; n < count; n++ )
   2546   {
   2547     if ( ACCESS_Frame( 2L ) )
   2548       goto Fail;
   2549 
   2550     new_offset = GET_UShort() + base_offset;
   2551 
   2552     FORGET_Frame();
   2553 
   2554     cur_offset = FILE_Pos();
   2555     if ( FILE_Seek( new_offset ) ||
   2556 	 ( error = Load_ChainSubClassRule( ccsf2, &cscr[n],
   2557 					   stream ) ) != HB_Err_Ok )
   2558       goto Fail;
   2559     (void)FILE_Seek( cur_offset );
   2560   }
   2561 
   2562   return HB_Err_Ok;
   2563 
   2564 Fail:
   2565   for ( m = 0; m < n; m++ )
   2566     Free_ChainSubClassRule( &cscr[m] );
   2567 
   2568   FREE( cscr );
   2569   return error;
   2570 }
   2571 
   2572 
   2573 static void  Free_ChainSubClassSet( HB_ChainSubClassSet*  cscs )
   2574 {
   2575   HB_UShort               n, count;
   2576 
   2577   HB_ChainSubClassRule*  cscr;
   2578 
   2579 
   2580   if ( cscs->ChainSubClassRule )
   2581   {
   2582     count = cscs->ChainSubClassRuleCount;
   2583     cscr  = cscs->ChainSubClassRule;
   2584 
   2585     for ( n = 0; n < count; n++ )
   2586       Free_ChainSubClassRule( &cscr[n] );
   2587 
   2588     FREE( cscr );
   2589   }
   2590 }
   2591 
   2592 
   2593 /* ChainContextSubstFormat2 */
   2594 
   2595 static HB_Error  Load_ChainContextSubst2(
   2596 		   HB_ChainContextSubstFormat2*  ccsf2,
   2597 		   HB_Stream                      stream )
   2598 {
   2599   HB_Error error;
   2600 
   2601   HB_UShort              n = 0, m, count;
   2602   HB_UInt               cur_offset, new_offset, base_offset;
   2603   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
   2604 
   2605   HB_ChainSubClassSet*  cscs;
   2606 
   2607 
   2608   base_offset = FILE_Pos() - 2;
   2609 
   2610   if ( ACCESS_Frame( 2L ) )
   2611     return error;
   2612 
   2613   new_offset = GET_UShort() + base_offset;
   2614 
   2615   FORGET_Frame();
   2616 
   2617   cur_offset = FILE_Pos();
   2618   if ( FILE_Seek( new_offset ) ||
   2619        ( error = _HB_OPEN_Load_Coverage( &ccsf2->Coverage, stream ) ) != HB_Err_Ok )
   2620     return error;
   2621   (void)FILE_Seek( cur_offset );
   2622 
   2623   if ( ACCESS_Frame( 8L ) )
   2624     goto Fail5;
   2625 
   2626   backtrack_offset = GET_UShort();
   2627   input_offset     = GET_UShort();
   2628   lookahead_offset = GET_UShort();
   2629 
   2630   /* `ChainSubClassSetCount' is the upper limit for input class values,
   2631      thus we read it now to make an additional safety check. No limit
   2632      is known or needed for the other two class definitions          */
   2633 
   2634   count = ccsf2->ChainSubClassSetCount = GET_UShort();
   2635 
   2636   FORGET_Frame();
   2637 
   2638   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->BacktrackClassDef, 65535,
   2639 						       backtrack_offset, base_offset,
   2640 						       stream ) ) != HB_Err_Ok )
   2641       goto Fail5;
   2642 
   2643   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->InputClassDef, count,
   2644 						       input_offset, base_offset,
   2645 						       stream ) ) != HB_Err_Ok )
   2646       goto Fail4;
   2647   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccsf2->LookaheadClassDef, 65535,
   2648 						       lookahead_offset, base_offset,
   2649 						       stream ) ) != HB_Err_Ok )
   2650     goto Fail3;
   2651 
   2652   ccsf2->ChainSubClassSet   = NULL;
   2653   ccsf2->MaxBacktrackLength = 0;
   2654   ccsf2->MaxInputLength     = 0;
   2655   ccsf2->MaxLookaheadLength = 0;
   2656 
   2657   if ( ALLOC_ARRAY( ccsf2->ChainSubClassSet, count, HB_ChainSubClassSet ) )
   2658     goto Fail2;
   2659 
   2660   cscs = ccsf2->ChainSubClassSet;
   2661 
   2662   for ( n = 0; n < count; n++ )
   2663   {
   2664     if ( ACCESS_Frame( 2L ) )
   2665       goto Fail1;
   2666 
   2667     new_offset = GET_UShort() + base_offset;
   2668 
   2669     FORGET_Frame();
   2670 
   2671     if ( new_offset != base_offset )      /* not a NULL offset */
   2672     {
   2673       cur_offset = FILE_Pos();
   2674       if ( FILE_Seek( new_offset ) ||
   2675 	   ( error = Load_ChainSubClassSet( ccsf2, &cscs[n],
   2676 					    stream ) ) != HB_Err_Ok )
   2677 	goto Fail1;
   2678       (void)FILE_Seek( cur_offset );
   2679     }
   2680     else
   2681     {
   2682       /* we create a ChainSubClassSet table with no entries */
   2683 
   2684       ccsf2->ChainSubClassSet[n].ChainSubClassRuleCount = 0;
   2685       ccsf2->ChainSubClassSet[n].ChainSubClassRule      = NULL;
   2686     }
   2687   }
   2688 
   2689   return HB_Err_Ok;
   2690 
   2691 Fail1:
   2692   for ( m = 0; m < n; m++ )
   2693     Free_ChainSubClassSet( &cscs[m] );
   2694 
   2695   FREE( cscs );
   2696 
   2697 Fail2:
   2698   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
   2699 
   2700 Fail3:
   2701   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
   2702 
   2703 Fail4:
   2704   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
   2705 
   2706 Fail5:
   2707   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
   2708   return error;
   2709 }
   2710 
   2711 
   2712 static void  Free_ChainContextSubst2( HB_ChainContextSubstFormat2*  ccsf2 )
   2713 {
   2714   HB_UShort              n, count;
   2715 
   2716   HB_ChainSubClassSet*  cscs;
   2717 
   2718 
   2719   if ( ccsf2->ChainSubClassSet )
   2720   {
   2721     count = ccsf2->ChainSubClassSetCount;
   2722     cscs  = ccsf2->ChainSubClassSet;
   2723 
   2724     for ( n = 0; n < count; n++ )
   2725       Free_ChainSubClassSet( &cscs[n] );
   2726 
   2727     FREE( cscs );
   2728   }
   2729 
   2730   _HB_OPEN_Free_ClassDefinition( &ccsf2->LookaheadClassDef );
   2731   _HB_OPEN_Free_ClassDefinition( &ccsf2->InputClassDef );
   2732   _HB_OPEN_Free_ClassDefinition( &ccsf2->BacktrackClassDef );
   2733 
   2734   _HB_OPEN_Free_Coverage( &ccsf2->Coverage );
   2735 }
   2736 
   2737 
   2738 /* ChainContextSubstFormat3 */
   2739 
   2740 static HB_Error  Load_ChainContextSubst3(
   2741 		   HB_ChainContextSubstFormat3*  ccsf3,
   2742 		   HB_Stream                      stream )
   2743 {
   2744   HB_Error error;
   2745 
   2746   HB_UShort               n, nb = 0, ni =0, nl = 0, m, count;
   2747   HB_UShort               backtrack_count, input_count, lookahead_count;
   2748   HB_UInt                cur_offset, new_offset, base_offset;
   2749 
   2750   HB_Coverage*           b;
   2751   HB_Coverage*           i;
   2752   HB_Coverage*           l;
   2753   HB_SubstLookupRecord*  slr;
   2754 
   2755 
   2756   base_offset = FILE_Pos() - 2L;
   2757 
   2758   if ( ACCESS_Frame( 2L ) )
   2759     return error;
   2760 
   2761   ccsf3->BacktrackGlyphCount = GET_UShort();
   2762 
   2763   FORGET_Frame();
   2764 
   2765   ccsf3->BacktrackCoverage = NULL;
   2766 
   2767   backtrack_count = ccsf3->BacktrackGlyphCount;
   2768 
   2769   if ( ALLOC_ARRAY( ccsf3->BacktrackCoverage, backtrack_count,
   2770 		    HB_Coverage ) )
   2771     return error;
   2772 
   2773   b = ccsf3->BacktrackCoverage;
   2774 
   2775   for ( nb = 0; nb < backtrack_count; nb++ )
   2776   {
   2777     if ( ACCESS_Frame( 2L ) )
   2778       goto Fail4;
   2779 
   2780     new_offset = GET_UShort() + base_offset;
   2781 
   2782     FORGET_Frame();
   2783 
   2784     cur_offset = FILE_Pos();
   2785     if ( FILE_Seek( new_offset ) ||
   2786 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
   2787       goto Fail4;
   2788     (void)FILE_Seek( cur_offset );
   2789   }
   2790 
   2791   if ( ACCESS_Frame( 2L ) )
   2792     goto Fail4;
   2793 
   2794   ccsf3->InputGlyphCount = GET_UShort();
   2795 
   2796   FORGET_Frame();
   2797 
   2798   ccsf3->InputCoverage = NULL;
   2799 
   2800   input_count = ccsf3->InputGlyphCount;
   2801 
   2802   if ( ALLOC_ARRAY( ccsf3->InputCoverage, input_count, HB_Coverage ) )
   2803     goto Fail4;
   2804 
   2805   i = ccsf3->InputCoverage;
   2806 
   2807   for ( ni = 0; ni < input_count; ni++ )
   2808   {
   2809     if ( ACCESS_Frame( 2L ) )
   2810       goto Fail3;
   2811 
   2812     new_offset = GET_UShort() + base_offset;
   2813 
   2814     FORGET_Frame();
   2815 
   2816     cur_offset = FILE_Pos();
   2817     if ( FILE_Seek( new_offset ) ||
   2818 	 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
   2819       goto Fail3;
   2820     (void)FILE_Seek( cur_offset );
   2821   }
   2822 
   2823   if ( ACCESS_Frame( 2L ) )
   2824     goto Fail3;
   2825 
   2826   ccsf3->LookaheadGlyphCount = GET_UShort();
   2827 
   2828   FORGET_Frame();
   2829 
   2830   ccsf3->LookaheadCoverage = NULL;
   2831 
   2832   lookahead_count = ccsf3->LookaheadGlyphCount;
   2833 
   2834   if ( ALLOC_ARRAY( ccsf3->LookaheadCoverage, lookahead_count,
   2835 		    HB_Coverage ) )
   2836     goto Fail3;
   2837 
   2838   l = ccsf3->LookaheadCoverage;
   2839 
   2840   for ( nl = 0; nl < lookahead_count; nl++ )
   2841   {
   2842     if ( ACCESS_Frame( 2L ) )
   2843       goto Fail2;
   2844 
   2845     new_offset = GET_UShort() + base_offset;
   2846 
   2847     FORGET_Frame();
   2848 
   2849     cur_offset = FILE_Pos();
   2850     if ( FILE_Seek( new_offset ) ||
   2851 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
   2852       goto Fail2;
   2853     (void)FILE_Seek( cur_offset );
   2854   }
   2855 
   2856   if ( ACCESS_Frame( 2L ) )
   2857     goto Fail2;
   2858 
   2859   ccsf3->SubstCount = GET_UShort();
   2860 
   2861   FORGET_Frame();
   2862 
   2863   ccsf3->SubstLookupRecord = NULL;
   2864 
   2865   count = ccsf3->SubstCount;
   2866 
   2867   if ( ALLOC_ARRAY( ccsf3->SubstLookupRecord, count,
   2868 		    HB_SubstLookupRecord ) )
   2869     goto Fail2;
   2870 
   2871   slr = ccsf3->SubstLookupRecord;
   2872 
   2873   if ( ACCESS_Frame( count * 4L ) )
   2874     goto Fail1;
   2875 
   2876   for ( n = 0; n < count; n++ )
   2877   {
   2878     slr[n].SequenceIndex   = GET_UShort();
   2879     slr[n].LookupListIndex = GET_UShort();
   2880   }
   2881 
   2882   FORGET_Frame();
   2883 
   2884   return HB_Err_Ok;
   2885 
   2886 Fail1:
   2887   FREE( slr );
   2888 
   2889 Fail2:
   2890   for ( m = 0; m < nl; m++ )
   2891     _HB_OPEN_Free_Coverage( &l[m] );
   2892 
   2893   FREE( l );
   2894 
   2895 Fail3:
   2896   for ( m = 0; m < ni; m++ )
   2897     _HB_OPEN_Free_Coverage( &i[m] );
   2898 
   2899   FREE( i );
   2900 
   2901 Fail4:
   2902   for ( m = 0; m < nb; m++ )
   2903     _HB_OPEN_Free_Coverage( &b[m] );
   2904 
   2905   FREE( b );
   2906   return error;
   2907 }
   2908 
   2909 
   2910 static void  Free_ChainContextSubst3( HB_ChainContextSubstFormat3*  ccsf3 )
   2911 {
   2912   HB_UShort      n, count;
   2913 
   2914   HB_Coverage*  c;
   2915 
   2916 
   2917   FREE( ccsf3->SubstLookupRecord );
   2918 
   2919   if ( ccsf3->LookaheadCoverage )
   2920   {
   2921     count = ccsf3->LookaheadGlyphCount;
   2922     c     = ccsf3->LookaheadCoverage;
   2923 
   2924     for ( n = 0; n < count; n++ )
   2925       _HB_OPEN_Free_Coverage( &c[n] );
   2926 
   2927     FREE( c );
   2928   }
   2929 
   2930   if ( ccsf3->InputCoverage )
   2931   {
   2932     count = ccsf3->InputGlyphCount;
   2933     c     = ccsf3->InputCoverage;
   2934 
   2935     for ( n = 0; n < count; n++ )
   2936       _HB_OPEN_Free_Coverage( &c[n] );
   2937 
   2938     FREE( c );
   2939   }
   2940 
   2941   if ( ccsf3->BacktrackCoverage )
   2942   {
   2943     count = ccsf3->BacktrackGlyphCount;
   2944     c     = ccsf3->BacktrackCoverage;
   2945 
   2946     for ( n = 0; n < count; n++ )
   2947       _HB_OPEN_Free_Coverage( &c[n] );
   2948 
   2949     FREE( c );
   2950   }
   2951 }
   2952 
   2953 
   2954 /* ChainContextSubst */
   2955 
   2956 static HB_Error  Load_ChainContextSubst( HB_GSUB_SubTable* st,
   2957 					 HB_Stream         stream )
   2958 {
   2959   HB_Error error;
   2960   HB_ChainContextSubst*  ccs = &st->chain;
   2961 
   2962   if ( ACCESS_Frame( 2L ) )
   2963     return error;
   2964 
   2965   ccs->SubstFormat = GET_UShort();
   2966 
   2967   FORGET_Frame();
   2968 
   2969   switch ( ccs->SubstFormat ) {
   2970     case 1:  return Load_ChainContextSubst1( &ccs->ccsf.ccsf1, stream );
   2971     case 2:  return Load_ChainContextSubst2( &ccs->ccsf.ccsf2, stream );
   2972     case 3:  return Load_ChainContextSubst3( &ccs->ccsf.ccsf3, stream );
   2973     default: return ERR(HB_Err_Invalid_SubTable_Format);
   2974   }
   2975 
   2976   return HB_Err_Ok;               /* never reached */
   2977 }
   2978 
   2979 
   2980 static void  Free_ChainContextSubst( HB_GSUB_SubTable* st )
   2981 {
   2982   HB_ChainContextSubst*  ccs = &st->chain;
   2983 
   2984   switch ( ccs->SubstFormat ) {
   2985     case 1:  Free_ChainContextSubst1( &ccs->ccsf.ccsf1 ); break;
   2986     case 2:  Free_ChainContextSubst2( &ccs->ccsf.ccsf2 ); break;
   2987     case 3:  Free_ChainContextSubst3( &ccs->ccsf.ccsf3 ); break;
   2988     default:							  break;
   2989   }
   2990 }
   2991 
   2992 
   2993 static HB_Error  Lookup_ChainContextSubst1( HB_GSUBHeader*               gsub,
   2994 					    HB_ChainContextSubstFormat1* ccsf1,
   2995 					    HB_Buffer                    buffer,
   2996 					    HB_UShort                     flags,
   2997 					    HB_UShort                     context_length,
   2998 					    int                           nesting_level )
   2999 {
   3000   HB_UShort          index, property;
   3001   HB_UShort          i, j, k, num_csr;
   3002   HB_UShort          bgc, igc, lgc;
   3003   HB_Error           error;
   3004 
   3005   HB_ChainSubRule*  csr;
   3006   HB_ChainSubRule   curr_csr;
   3007   HB_GDEFHeader*    gdef;
   3008 
   3009 
   3010   gdef = gsub->gdef;
   3011 
   3012   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3013     return error;
   3014 
   3015   error = _HB_OPEN_Coverage_Index( &ccsf1->Coverage, IN_CURGLYPH(), &index );
   3016   if ( error )
   3017     return error;
   3018 
   3019   csr     = ccsf1->ChainSubRuleSet[index].ChainSubRule;
   3020   num_csr = ccsf1->ChainSubRuleSet[index].ChainSubRuleCount;
   3021 
   3022   for ( k = 0; k < num_csr; k++ )
   3023   {
   3024     curr_csr = csr[k];
   3025     bgc      = curr_csr.BacktrackGlyphCount;
   3026     igc      = curr_csr.InputGlyphCount;
   3027     lgc      = curr_csr.LookaheadGlyphCount;
   3028 
   3029     if ( context_length != 0xFFFF && context_length < igc )
   3030       goto next_chainsubrule;
   3031 
   3032     /* check whether context is too long; it is a first guess only */
   3033 
   3034     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   3035       goto next_chainsubrule;
   3036 
   3037     if ( bgc )
   3038     {
   3039       /* since we don't know in advance the number of glyphs to inspect,
   3040 	 we search backwards for matches in the backtrack glyph array    */
   3041 
   3042       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
   3043       {
   3044 	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
   3045 	{
   3046 	  if ( error && error != HB_Err_Not_Covered )
   3047 	    return error;
   3048 
   3049 	  if ( j + 1 == bgc - i )
   3050 	    goto next_chainsubrule;
   3051 	  j--;
   3052 	}
   3053 
   3054 	/* In OpenType 1.3, it is undefined whether the offsets of
   3055 	   backtrack glyphs is in logical order or not.  Version 1.4
   3056 	   will clarify this:
   3057 
   3058 	     Logical order -      a  b  c  d  e  f  g  h  i  j
   3059 					      i
   3060 	     Input offsets -                  0  1
   3061 	     Backtrack offsets -  3  2  1  0
   3062 	     Lookahead offsets -                    0  1  2  3           */
   3063 
   3064 	if ( OUT_GLYPH( j ) != curr_csr.Backtrack[i] )
   3065 	  goto next_chainsubrule;
   3066       }
   3067     }
   3068 
   3069     /* Start at 1 because [0] is implied */
   3070 
   3071     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   3072     {
   3073       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3074       {
   3075 	if ( error && error != HB_Err_Not_Covered )
   3076 	  return error;
   3077 
   3078 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   3079 	  goto next_chainsubrule;
   3080 	j++;
   3081       }
   3082 
   3083       if ( IN_GLYPH( j ) != curr_csr.Input[i - 1] )
   3084 	  goto next_chainsubrule;
   3085     }
   3086 
   3087     /* we are starting to check for lookahead glyphs right after the
   3088        last context glyph                                            */
   3089 
   3090     for ( i = 0; i < lgc; i++, j++ )
   3091     {
   3092       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3093       {
   3094 	if ( error && error != HB_Err_Not_Covered )
   3095 	  return error;
   3096 
   3097 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   3098 	  goto next_chainsubrule;
   3099 	j++;
   3100       }
   3101 
   3102       if ( IN_GLYPH( j ) != curr_csr.Lookahead[i] )
   3103 	goto next_chainsubrule;
   3104     }
   3105 
   3106     return Do_ContextSubst( gsub, igc,
   3107 			    curr_csr.SubstCount,
   3108 			    curr_csr.SubstLookupRecord,
   3109 			    buffer,
   3110 			    nesting_level );
   3111 
   3112   next_chainsubrule:
   3113     ;
   3114   }
   3115 
   3116   return HB_Err_Not_Covered;
   3117 }
   3118 
   3119 
   3120 static HB_Error  Lookup_ChainContextSubst2( HB_GSUBHeader*               gsub,
   3121 					    HB_ChainContextSubstFormat2* ccsf2,
   3122 					    HB_Buffer                    buffer,
   3123 					    HB_UShort                     flags,
   3124 					    HB_UShort                     context_length,
   3125 					    int                           nesting_level )
   3126 {
   3127   HB_UShort              index, property;
   3128   HB_Error               error;
   3129   HB_UShort              i, j, k;
   3130   HB_UShort              bgc, igc, lgc;
   3131   HB_UShort              known_backtrack_classes,
   3132 			 known_input_classes,
   3133 			 known_lookahead_classes;
   3134 
   3135   HB_UShort*             backtrack_classes;
   3136   HB_UShort*             input_classes;
   3137   HB_UShort*             lookahead_classes;
   3138 
   3139   HB_UShort*             bc;
   3140   HB_UShort*             ic;
   3141   HB_UShort*             lc;
   3142 
   3143   HB_ChainSubClassSet*  cscs;
   3144   HB_ChainSubClassRule  ccsr;
   3145   HB_GDEFHeader*        gdef;
   3146 
   3147 
   3148   gdef = gsub->gdef;
   3149 
   3150   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3151     return error;
   3152 
   3153   /* Note: The coverage table in format 2 doesn't give an index into
   3154 	   anything.  It just lets us know whether or not we need to
   3155 	   do any lookup at all.                                     */
   3156 
   3157   error = _HB_OPEN_Coverage_Index( &ccsf2->Coverage, IN_CURGLYPH(), &index );
   3158   if ( error )
   3159     return error;
   3160 
   3161   if (ccsf2->MaxInputLength < 1)
   3162     return HB_Err_Not_Covered;
   3163 
   3164   if ( ALLOC_ARRAY( backtrack_classes, ccsf2->MaxBacktrackLength, HB_UShort ) )
   3165     return error;
   3166   known_backtrack_classes = 0;
   3167 
   3168   if ( ALLOC_ARRAY( input_classes, ccsf2->MaxInputLength, HB_UShort ) )
   3169     goto End3;
   3170   known_input_classes = 1;
   3171 
   3172   if ( ALLOC_ARRAY( lookahead_classes, ccsf2->MaxLookaheadLength, HB_UShort ) )
   3173     goto End2;
   3174   known_lookahead_classes = 0;
   3175 
   3176   error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_CURGLYPH(),
   3177 		     &input_classes[0], NULL );
   3178   if ( error && error != HB_Err_Not_Covered )
   3179     goto End1;
   3180 
   3181   cscs = &ccsf2->ChainSubClassSet[input_classes[0]];
   3182   if ( !cscs )
   3183   {
   3184     error = ERR(HB_Err_Invalid_SubTable);
   3185     goto End1;
   3186   }
   3187 
   3188   for ( k = 0; k < cscs->ChainSubClassRuleCount; k++ )
   3189   {
   3190     ccsr = cscs->ChainSubClassRule[k];
   3191     bgc  = ccsr.BacktrackGlyphCount;
   3192     igc  = ccsr.InputGlyphCount;
   3193     lgc  = ccsr.LookaheadGlyphCount;
   3194 
   3195     if ( context_length != 0xFFFF && context_length < igc )
   3196       goto next_chainsubclassrule;
   3197 
   3198     /* check whether context is too long; it is a first guess only */
   3199 
   3200     if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   3201       goto next_chainsubclassrule;
   3202 
   3203     if ( bgc )
   3204     {
   3205       /* Since we don't know in advance the number of glyphs to inspect,
   3206 	 we search backwards for matches in the backtrack glyph array.
   3207 	 Note that `known_backtrack_classes' starts at index 0.         */
   3208 
   3209       bc       = ccsr.Backtrack;
   3210 
   3211       for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
   3212       {
   3213 	while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
   3214 	{
   3215 	  if ( error && error != HB_Err_Not_Covered )
   3216 	    goto End1;
   3217 
   3218 	  if ( j + 1 == bgc - i )
   3219 	    goto next_chainsubclassrule;
   3220 	  j--;
   3221 	}
   3222 
   3223 	if ( i >= known_backtrack_classes )
   3224 	{
   3225 	  /* Keeps us from having to do this for each rule */
   3226 
   3227 	  error = _HB_OPEN_Get_Class( &ccsf2->BacktrackClassDef, OUT_GLYPH( j ),
   3228 			     &backtrack_classes[i], NULL );
   3229 	  if ( error && error != HB_Err_Not_Covered )
   3230 	    goto End1;
   3231 	  known_backtrack_classes = i;
   3232 	}
   3233 
   3234 	if ( bc[i] != backtrack_classes[i] )
   3235 	  goto next_chainsubclassrule;
   3236       }
   3237     }
   3238 
   3239     ic       = ccsr.Input;
   3240 
   3241     /* Start at 1 because [0] is implied */
   3242 
   3243     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   3244     {
   3245       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3246       {
   3247 	if ( error && error != HB_Err_Not_Covered )
   3248 	  goto End1;
   3249 
   3250 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   3251 	  goto next_chainsubclassrule;
   3252 	j++;
   3253       }
   3254 
   3255       if ( i >= known_input_classes )
   3256       {
   3257 	error = _HB_OPEN_Get_Class( &ccsf2->InputClassDef, IN_GLYPH( j ),
   3258 			   &input_classes[i], NULL );
   3259 	if ( error && error != HB_Err_Not_Covered )
   3260 	  goto End1;
   3261 	known_input_classes = i;
   3262       }
   3263 
   3264       if ( ic[i - 1] != input_classes[i] )
   3265 	goto next_chainsubclassrule;
   3266     }
   3267 
   3268     /* we are starting to check for lookahead glyphs right after the
   3269        last context glyph                                            */
   3270 
   3271     lc       = ccsr.Lookahead;
   3272 
   3273     for ( i = 0; i < lgc; i++, j++ )
   3274     {
   3275       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3276       {
   3277 	if ( error && error != HB_Err_Not_Covered )
   3278 	  goto End1;
   3279 
   3280 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   3281 	  goto next_chainsubclassrule;
   3282 	j++;
   3283       }
   3284 
   3285       if ( i >= known_lookahead_classes )
   3286       {
   3287 	error = _HB_OPEN_Get_Class( &ccsf2->LookaheadClassDef, IN_GLYPH( j ),
   3288 			   &lookahead_classes[i], NULL );
   3289 	if ( error && error != HB_Err_Not_Covered )
   3290 	  goto End1;
   3291 	known_lookahead_classes = i;
   3292       }
   3293 
   3294       if ( lc[i] != lookahead_classes[i] )
   3295 	goto next_chainsubclassrule;
   3296     }
   3297 
   3298     error = Do_ContextSubst( gsub, igc,
   3299 			     ccsr.SubstCount,
   3300 			     ccsr.SubstLookupRecord,
   3301 			     buffer,
   3302 			     nesting_level );
   3303     goto End1;
   3304 
   3305   next_chainsubclassrule:
   3306     ;
   3307   }
   3308 
   3309   error = HB_Err_Not_Covered;
   3310 
   3311 End1:
   3312   FREE( lookahead_classes );
   3313 
   3314 End2:
   3315   FREE( input_classes );
   3316 
   3317 End3:
   3318   FREE( backtrack_classes );
   3319   return error;
   3320 }
   3321 
   3322 
   3323 static HB_Error  Lookup_ChainContextSubst3( HB_GSUBHeader*               gsub,
   3324 					    HB_ChainContextSubstFormat3* ccsf3,
   3325 					    HB_Buffer                    buffer,
   3326 					    HB_UShort                     flags,
   3327 					    HB_UShort                     context_length,
   3328 					    int                           nesting_level )
   3329 {
   3330   HB_UShort        index, i, j, property;
   3331   HB_UShort        bgc, igc, lgc;
   3332   HB_Error         error;
   3333 
   3334   HB_Coverage*    bc;
   3335   HB_Coverage*    ic;
   3336   HB_Coverage*    lc;
   3337   HB_GDEFHeader*  gdef;
   3338 
   3339 
   3340   gdef = gsub->gdef;
   3341 
   3342   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3343     return error;
   3344 
   3345   bgc = ccsf3->BacktrackGlyphCount;
   3346   igc = ccsf3->InputGlyphCount;
   3347   lgc = ccsf3->LookaheadGlyphCount;
   3348 
   3349   if ( context_length != 0xFFFF && context_length < igc )
   3350     return HB_Err_Not_Covered;
   3351 
   3352   /* check whether context is too long; it is a first guess only */
   3353 
   3354   if ( bgc > buffer->out_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   3355     return HB_Err_Not_Covered;
   3356 
   3357   if ( bgc )
   3358   {
   3359     /* Since we don't know in advance the number of glyphs to inspect,
   3360        we search backwards for matches in the backtrack glyph array    */
   3361 
   3362     bc       = ccsf3->BacktrackCoverage;
   3363 
   3364     for ( i = 0, j = buffer->out_pos - 1; i < bgc; i++, j-- )
   3365     {
   3366       while ( CHECK_Property( gdef, OUT_ITEM( j ), flags, &property ) )
   3367       {
   3368 	if ( error && error != HB_Err_Not_Covered )
   3369 	  return error;
   3370 
   3371 	if ( j + 1 == bgc - i )
   3372 	  return HB_Err_Not_Covered;
   3373 	j--;
   3374       }
   3375 
   3376       error = _HB_OPEN_Coverage_Index( &bc[i], OUT_GLYPH( j ), &index );
   3377       if ( error )
   3378 	return error;
   3379     }
   3380   }
   3381 
   3382   ic       = ccsf3->InputCoverage;
   3383 
   3384   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
   3385   {
   3386     /* We already called CHECK_Property for IN_GLYPH( buffer->in_pos ) */
   3387     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3388     {
   3389       if ( error && error != HB_Err_Not_Covered )
   3390 	return error;
   3391 
   3392       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   3393 	return HB_Err_Not_Covered;
   3394       j++;
   3395     }
   3396 
   3397     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
   3398     if ( error )
   3399       return error;
   3400   }
   3401 
   3402   /* we are starting for lookahead glyphs right after the last context
   3403      glyph                                                             */
   3404 
   3405   lc       = ccsf3->LookaheadCoverage;
   3406 
   3407   for ( i = 0; i < lgc; i++, j++ )
   3408   {
   3409     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3410     {
   3411       if ( error && error != HB_Err_Not_Covered )
   3412 	return error;
   3413 
   3414       if ( j + lgc - i == (HB_Int)buffer->in_length )
   3415 	return HB_Err_Not_Covered;
   3416       j++;
   3417     }
   3418 
   3419     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
   3420     if ( error )
   3421       return error;
   3422   }
   3423 
   3424   return Do_ContextSubst( gsub, igc,
   3425 			  ccsf3->SubstCount,
   3426 			  ccsf3->SubstLookupRecord,
   3427 			  buffer,
   3428 			  nesting_level );
   3429 }
   3430 
   3431 
   3432 static HB_Error  Lookup_ChainContextSubst( HB_GSUBHeader*    gsub,
   3433 					   HB_GSUB_SubTable* st,
   3434 					   HB_Buffer         buffer,
   3435 					   HB_UShort          flags,
   3436 					   HB_UShort          context_length,
   3437 					   int                nesting_level )
   3438 {
   3439   HB_ChainContextSubst*  ccs = &st->chain;
   3440 
   3441   switch ( ccs->SubstFormat ) {
   3442     case 1:  return Lookup_ChainContextSubst1( gsub, &ccs->ccsf.ccsf1, buffer, flags, context_length, nesting_level );
   3443     case 2:  return Lookup_ChainContextSubst2( gsub, &ccs->ccsf.ccsf2, buffer, flags, context_length, nesting_level );
   3444     case 3:  return Lookup_ChainContextSubst3( gsub, &ccs->ccsf.ccsf3, buffer, flags, context_length, nesting_level );
   3445     default: return ERR(HB_Err_Invalid_SubTable_Format);
   3446   }
   3447 }
   3448 
   3449 
   3450 static HB_Error  Load_ReverseChainContextSubst( HB_GSUB_SubTable* st,
   3451 					        HB_Stream         stream )
   3452 {
   3453   HB_Error error;
   3454   HB_ReverseChainContextSubst*  rccs = &st->reverse;
   3455 
   3456   HB_UShort               m, count;
   3457 
   3458   HB_UShort               nb = 0, nl = 0, n;
   3459   HB_UShort               backtrack_count, lookahead_count;
   3460   HB_UInt                cur_offset, new_offset, base_offset;
   3461 
   3462   HB_Coverage*           b;
   3463   HB_Coverage*           l;
   3464   HB_UShort*              sub;
   3465 
   3466   base_offset = FILE_Pos();
   3467 
   3468   if ( ACCESS_Frame( 2L ) )
   3469     return error;
   3470 
   3471   rccs->SubstFormat = GET_UShort();
   3472 
   3473   if ( rccs->SubstFormat != 1 )
   3474     return ERR(HB_Err_Invalid_SubTable_Format);
   3475 
   3476   FORGET_Frame();
   3477 
   3478   if ( ACCESS_Frame( 2L ) )
   3479     return error;
   3480 
   3481   new_offset = GET_UShort() + base_offset;
   3482 
   3483   FORGET_Frame();
   3484 
   3485   cur_offset = FILE_Pos();
   3486   if ( FILE_Seek( new_offset ) ||
   3487        ( error = _HB_OPEN_Load_Coverage( &rccs->Coverage, stream ) ) != HB_Err_Ok )
   3488     return error;
   3489   (void)FILE_Seek( cur_offset );
   3490 
   3491 
   3492   if ( ACCESS_Frame( 2L ) )
   3493     goto Fail4;
   3494 
   3495   rccs->BacktrackGlyphCount = GET_UShort();
   3496 
   3497   FORGET_Frame();
   3498 
   3499   rccs->BacktrackCoverage = NULL;
   3500 
   3501   backtrack_count = rccs->BacktrackGlyphCount;
   3502 
   3503   if ( ALLOC_ARRAY( rccs->BacktrackCoverage, backtrack_count,
   3504 		    HB_Coverage ) )
   3505     goto Fail4;
   3506 
   3507   b = rccs->BacktrackCoverage;
   3508 
   3509   for ( nb = 0; nb < backtrack_count; nb++ )
   3510   {
   3511     if ( ACCESS_Frame( 2L ) )
   3512       goto Fail3;
   3513 
   3514     new_offset = GET_UShort() + base_offset;
   3515 
   3516     FORGET_Frame();
   3517 
   3518     cur_offset = FILE_Pos();
   3519     if ( FILE_Seek( new_offset ) ||
   3520 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
   3521       goto Fail3;
   3522     (void)FILE_Seek( cur_offset );
   3523   }
   3524 
   3525 
   3526   if ( ACCESS_Frame( 2L ) )
   3527     goto Fail3;
   3528 
   3529   rccs->LookaheadGlyphCount = GET_UShort();
   3530 
   3531   FORGET_Frame();
   3532 
   3533   rccs->LookaheadCoverage = NULL;
   3534 
   3535   lookahead_count = rccs->LookaheadGlyphCount;
   3536 
   3537   if ( ALLOC_ARRAY( rccs->LookaheadCoverage, lookahead_count,
   3538 		    HB_Coverage ) )
   3539     goto Fail3;
   3540 
   3541   l = rccs->LookaheadCoverage;
   3542 
   3543   for ( nl = 0; nl < lookahead_count; nl++ )
   3544   {
   3545     if ( ACCESS_Frame( 2L ) )
   3546       goto Fail2;
   3547 
   3548     new_offset = GET_UShort() + base_offset;
   3549 
   3550     FORGET_Frame();
   3551 
   3552     cur_offset = FILE_Pos();
   3553     if ( FILE_Seek( new_offset ) ||
   3554 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
   3555       goto Fail2;
   3556     (void)FILE_Seek( cur_offset );
   3557   }
   3558 
   3559   if ( ACCESS_Frame( 2L ) )
   3560     goto Fail2;
   3561 
   3562   rccs->GlyphCount = GET_UShort();
   3563 
   3564   FORGET_Frame();
   3565 
   3566   rccs->Substitute = NULL;
   3567 
   3568   count = rccs->GlyphCount;
   3569 
   3570   if ( ALLOC_ARRAY( rccs->Substitute, count,
   3571 		    HB_UShort ) )
   3572     goto Fail2;
   3573 
   3574   sub = rccs->Substitute;
   3575 
   3576   if ( ACCESS_Frame( count * 2L ) )
   3577     goto Fail1;
   3578 
   3579   for ( n = 0; n < count; n++ )
   3580     sub[n] = GET_UShort();
   3581 
   3582   FORGET_Frame();
   3583 
   3584   return HB_Err_Ok;
   3585 
   3586 Fail1:
   3587   FREE( sub );
   3588 
   3589 Fail2:
   3590   for ( m = 0; m < nl; m++ )
   3591     _HB_OPEN_Free_Coverage( &l[m] );
   3592 
   3593   FREE( l );
   3594 
   3595 Fail3:
   3596   for ( m = 0; m < nb; m++ )
   3597     _HB_OPEN_Free_Coverage( &b[m] );
   3598 
   3599   FREE( b );
   3600 
   3601 Fail4:
   3602   _HB_OPEN_Free_Coverage( &rccs->Coverage );
   3603   return error;
   3604 }
   3605 
   3606 
   3607 static void  Free_ReverseChainContextSubst( HB_GSUB_SubTable* st )
   3608 {
   3609   HB_UShort      n, count;
   3610   HB_ReverseChainContextSubst*  rccs = &st->reverse;
   3611 
   3612   HB_Coverage*  c;
   3613 
   3614   _HB_OPEN_Free_Coverage( &rccs->Coverage );
   3615 
   3616   if ( rccs->LookaheadCoverage )
   3617   {
   3618     count = rccs->LookaheadGlyphCount;
   3619     c     = rccs->LookaheadCoverage;
   3620 
   3621     for ( n = 0; n < count; n++ )
   3622       _HB_OPEN_Free_Coverage( &c[n] );
   3623 
   3624     FREE( c );
   3625   }
   3626 
   3627   if ( rccs->BacktrackCoverage )
   3628   {
   3629     count = rccs->BacktrackGlyphCount;
   3630     c     = rccs->BacktrackCoverage;
   3631 
   3632     for ( n = 0; n < count; n++ )
   3633       _HB_OPEN_Free_Coverage( &c[n] );
   3634 
   3635     FREE( c );
   3636   }
   3637 
   3638   FREE ( rccs->Substitute );
   3639 }
   3640 
   3641 
   3642 static HB_Error  Lookup_ReverseChainContextSubst( HB_GSUBHeader*    gsub,
   3643 						  HB_GSUB_SubTable* st,
   3644 						  HB_Buffer         buffer,
   3645 						  HB_UShort          flags,
   3646 						  HB_UShort         context_length,
   3647 						  int               nesting_level )
   3648 {
   3649   HB_UShort        index, input_index, i, j, property;
   3650   HB_UShort        bgc, lgc;
   3651   HB_Error         error;
   3652 
   3653   HB_ReverseChainContextSubst*  rccs = &st->reverse;
   3654   HB_Coverage*    bc;
   3655   HB_Coverage*    lc;
   3656   HB_GDEFHeader*  gdef;
   3657 
   3658   if ( nesting_level != 1 || context_length != 0xFFFF )
   3659     return HB_Err_Not_Covered;
   3660 
   3661   gdef = gsub->gdef;
   3662 
   3663   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3664     return error;
   3665 
   3666   bgc = rccs->BacktrackGlyphCount;
   3667   lgc = rccs->LookaheadGlyphCount;
   3668 
   3669   /* check whether context is too long; it is a first guess only */
   3670 
   3671   if ( bgc > buffer->in_pos || buffer->in_pos + 1 + lgc > buffer->in_length )
   3672     return HB_Err_Not_Covered;
   3673 
   3674   if ( bgc )
   3675   {
   3676     /* Since we don't know in advance the number of glyphs to inspect,
   3677        we search backwards for matches in the backtrack glyph array    */
   3678 
   3679     bc       = rccs->BacktrackCoverage;
   3680 
   3681     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   3682     {
   3683       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3684       {
   3685 	if ( error && error != HB_Err_Not_Covered )
   3686 	  return error;
   3687 
   3688 	if ( j + 1 == bgc - i )
   3689 	  return HB_Err_Not_Covered;
   3690 	j--;
   3691       }
   3692 
   3693       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
   3694       if ( error )
   3695 	return error;
   3696     }
   3697   }
   3698 
   3699   j = buffer->in_pos;
   3700 
   3701   error = _HB_OPEN_Coverage_Index( &rccs->Coverage, IN_GLYPH( j ), &input_index );
   3702   if ( error )
   3703       return error;
   3704 
   3705   lc       = rccs->LookaheadCoverage;
   3706 
   3707   for ( i = 0, j = buffer->in_pos + 1; i < lgc; i++, j++ )
   3708   {
   3709     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3710     {
   3711       if ( error && error != HB_Err_Not_Covered )
   3712 	return error;
   3713 
   3714       if ( j + lgc - i == (HB_Int)buffer->in_length )
   3715 	return HB_Err_Not_Covered;
   3716       j++;
   3717     }
   3718 
   3719     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
   3720     if ( error )
   3721       return error;
   3722   }
   3723 
   3724   IN_CURGLYPH() = rccs->Substitute[input_index];
   3725   buffer->in_pos--; /* Reverse! */
   3726 
   3727   return error;
   3728 }
   3729 
   3730 
   3731 
   3732 /***********
   3733  * GSUB API
   3734  ***********/
   3735 
   3736 
   3737 
   3738 HB_Error  HB_GSUB_Select_Script( HB_GSUBHeader*  gsub,
   3739 				 HB_UInt         script_tag,
   3740 				 HB_UShort*       script_index )
   3741 {
   3742   HB_UShort          n;
   3743 
   3744   HB_ScriptList*    sl;
   3745   HB_ScriptRecord*  sr;
   3746 
   3747 
   3748   if ( !gsub || !script_index )
   3749     return ERR(HB_Err_Invalid_Argument);
   3750 
   3751   sl = &gsub->ScriptList;
   3752   sr = sl->ScriptRecord;
   3753 
   3754   for ( n = 0; n < sl->ScriptCount; n++ )
   3755     if ( script_tag == sr[n].ScriptTag )
   3756     {
   3757       *script_index = n;
   3758 
   3759       return HB_Err_Ok;
   3760     }
   3761 
   3762   return HB_Err_Not_Covered;
   3763 }
   3764 
   3765 
   3766 
   3767 HB_Error  HB_GSUB_Select_Language( HB_GSUBHeader*  gsub,
   3768 				   HB_UInt         language_tag,
   3769 				   HB_UShort        script_index,
   3770 				   HB_UShort*       language_index,
   3771 				   HB_UShort*       req_feature_index )
   3772 {
   3773   HB_UShort           n;
   3774 
   3775   HB_ScriptList*     sl;
   3776   HB_ScriptRecord*   sr;
   3777   HB_ScriptTable*    s;
   3778   HB_LangSysRecord*  lsr;
   3779 
   3780 
   3781   if ( !gsub || !language_index || !req_feature_index )
   3782     return ERR(HB_Err_Invalid_Argument);
   3783 
   3784   sl = &gsub->ScriptList;
   3785   sr = sl->ScriptRecord;
   3786 
   3787   if ( script_index >= sl->ScriptCount )
   3788     return ERR(HB_Err_Invalid_Argument);
   3789 
   3790   s   = &sr[script_index].Script;
   3791   lsr = s->LangSysRecord;
   3792 
   3793   for ( n = 0; n < s->LangSysCount; n++ )
   3794     if ( language_tag == lsr[n].LangSysTag )
   3795     {
   3796       *language_index = n;
   3797       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
   3798 
   3799       return HB_Err_Ok;
   3800     }
   3801 
   3802   return HB_Err_Not_Covered;
   3803 }
   3804 
   3805 
   3806 /* selecting 0xFFFF for language_index asks for the values of the
   3807    default language (DefaultLangSys)                              */
   3808 
   3809 
   3810 HB_Error  HB_GSUB_Select_Feature( HB_GSUBHeader*  gsub,
   3811 				  HB_UInt         feature_tag,
   3812 				  HB_UShort        script_index,
   3813 				  HB_UShort        language_index,
   3814 				  HB_UShort*       feature_index )
   3815 {
   3816   HB_UShort           n;
   3817 
   3818   HB_ScriptList*     sl;
   3819   HB_ScriptRecord*   sr;
   3820   HB_ScriptTable*    s;
   3821   HB_LangSysRecord*  lsr;
   3822   HB_LangSys*        ls;
   3823   HB_UShort*          fi;
   3824 
   3825   HB_FeatureList*    fl;
   3826   HB_FeatureRecord*  fr;
   3827 
   3828 
   3829   if ( !gsub || !feature_index )
   3830     return ERR(HB_Err_Invalid_Argument);
   3831 
   3832   sl = &gsub->ScriptList;
   3833   sr = sl->ScriptRecord;
   3834 
   3835   fl = &gsub->FeatureList;
   3836   fr = fl->FeatureRecord;
   3837 
   3838   if ( script_index >= sl->ScriptCount )
   3839     return ERR(HB_Err_Invalid_Argument);
   3840 
   3841   s   = &sr[script_index].Script;
   3842   lsr = s->LangSysRecord;
   3843 
   3844   if ( language_index == 0xFFFF )
   3845     ls = &s->DefaultLangSys;
   3846   else
   3847   {
   3848     if ( language_index >= s->LangSysCount )
   3849       return ERR(HB_Err_Invalid_Argument);
   3850 
   3851     ls = &lsr[language_index].LangSys;
   3852   }
   3853 
   3854   fi = ls->FeatureIndex;
   3855 
   3856   for ( n = 0; n < ls->FeatureCount; n++ )
   3857   {
   3858     if ( fi[n] >= fl->FeatureCount )
   3859       return ERR(HB_Err_Invalid_SubTable_Format);
   3860 
   3861     if ( feature_tag == fr[fi[n]].FeatureTag )
   3862     {
   3863       *feature_index = fi[n];
   3864 
   3865       return HB_Err_Ok;
   3866     }
   3867   }
   3868 
   3869   return HB_Err_Not_Covered;
   3870 }
   3871 
   3872 
   3873 /* The next three functions return a null-terminated list */
   3874 
   3875 
   3876 HB_Error  HB_GSUB_Query_Scripts( HB_GSUBHeader*  gsub,
   3877 				 HB_UInt**       script_tag_list )
   3878 {
   3879   HB_UShort          n;
   3880   HB_Error           error;
   3881   HB_UInt*          stl;
   3882 
   3883   HB_ScriptList*    sl;
   3884   HB_ScriptRecord*  sr;
   3885 
   3886 
   3887   if ( !gsub || !script_tag_list )
   3888     return ERR(HB_Err_Invalid_Argument);
   3889 
   3890   sl = &gsub->ScriptList;
   3891   sr = sl->ScriptRecord;
   3892 
   3893   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
   3894     return error;
   3895 
   3896   for ( n = 0; n < sl->ScriptCount; n++ )
   3897     stl[n] = sr[n].ScriptTag;
   3898   stl[n] = 0;
   3899 
   3900   *script_tag_list = stl;
   3901 
   3902   return HB_Err_Ok;
   3903 }
   3904 
   3905 
   3906 
   3907 HB_Error  HB_GSUB_Query_Languages( HB_GSUBHeader*  gsub,
   3908 				   HB_UShort        script_index,
   3909 				   HB_UInt**       language_tag_list )
   3910 {
   3911   HB_UShort           n;
   3912   HB_Error            error;
   3913   HB_UInt*           ltl;
   3914 
   3915   HB_ScriptList*     sl;
   3916   HB_ScriptRecord*   sr;
   3917   HB_ScriptTable*    s;
   3918   HB_LangSysRecord*  lsr;
   3919 
   3920 
   3921   if ( !gsub || !language_tag_list )
   3922     return ERR(HB_Err_Invalid_Argument);
   3923 
   3924   sl = &gsub->ScriptList;
   3925   sr = sl->ScriptRecord;
   3926 
   3927   if ( script_index >= sl->ScriptCount )
   3928     return ERR(HB_Err_Invalid_Argument);
   3929 
   3930   s   = &sr[script_index].Script;
   3931   lsr = s->LangSysRecord;
   3932 
   3933   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
   3934     return error;
   3935 
   3936   for ( n = 0; n < s->LangSysCount; n++ )
   3937     ltl[n] = lsr[n].LangSysTag;
   3938   ltl[n] = 0;
   3939 
   3940   *language_tag_list = ltl;
   3941 
   3942   return HB_Err_Ok;
   3943 }
   3944 
   3945 
   3946 /* selecting 0xFFFF for language_index asks for the values of the
   3947    default language (DefaultLangSys)                              */
   3948 
   3949 
   3950 HB_Error  HB_GSUB_Query_Features( HB_GSUBHeader*  gsub,
   3951 				  HB_UShort        script_index,
   3952 				  HB_UShort        language_index,
   3953 				  HB_UInt**       feature_tag_list )
   3954 {
   3955   HB_UShort           n;
   3956   HB_Error            error;
   3957   HB_UInt*           ftl;
   3958 
   3959   HB_ScriptList*     sl;
   3960   HB_ScriptRecord*   sr;
   3961   HB_ScriptTable*    s;
   3962   HB_LangSysRecord*  lsr;
   3963   HB_LangSys*        ls;
   3964   HB_UShort*          fi;
   3965 
   3966   HB_FeatureList*    fl;
   3967   HB_FeatureRecord*  fr;
   3968 
   3969 
   3970   if ( !gsub || !feature_tag_list )
   3971     return ERR(HB_Err_Invalid_Argument);
   3972 
   3973   sl = &gsub->ScriptList;
   3974   sr = sl->ScriptRecord;
   3975 
   3976   fl = &gsub->FeatureList;
   3977   fr = fl->FeatureRecord;
   3978 
   3979   if ( script_index >= sl->ScriptCount )
   3980     return ERR(HB_Err_Invalid_Argument);
   3981 
   3982   s   = &sr[script_index].Script;
   3983   lsr = s->LangSysRecord;
   3984 
   3985   if ( language_index == 0xFFFF )
   3986     ls = &s->DefaultLangSys;
   3987   else
   3988   {
   3989     if ( language_index >= s->LangSysCount )
   3990       return ERR(HB_Err_Invalid_Argument);
   3991 
   3992     ls = &lsr[language_index].LangSys;
   3993   }
   3994 
   3995   fi = ls->FeatureIndex;
   3996 
   3997   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
   3998     return error;
   3999 
   4000   for ( n = 0; n < ls->FeatureCount; n++ )
   4001   {
   4002     if ( fi[n] >= fl->FeatureCount )
   4003     {
   4004       FREE( ftl );
   4005       return ERR(HB_Err_Invalid_SubTable_Format);
   4006     }
   4007     ftl[n] = fr[fi[n]].FeatureTag;
   4008   }
   4009   ftl[n] = 0;
   4010 
   4011   *feature_tag_list = ftl;
   4012 
   4013   return HB_Err_Ok;
   4014 }
   4015 
   4016 
   4017 /* Do an individual subtable lookup.  Returns HB_Err_Ok if substitution
   4018    has been done, or HB_Err_Not_Covered if not.                        */
   4019 static HB_Error  GSUB_Do_Glyph_Lookup( HB_GSUBHeader* gsub,
   4020 				       HB_UShort       lookup_index,
   4021 				       HB_Buffer      buffer,
   4022 				       HB_UShort       context_length,
   4023 				       int             nesting_level )
   4024 {
   4025   HB_Error               error = HB_Err_Not_Covered;
   4026   HB_UShort              i, flags, lookup_count;
   4027   HB_Lookup*             lo;
   4028   int                    lookup_type;
   4029 
   4030   nesting_level++;
   4031 
   4032   if ( nesting_level > HB_MAX_NESTING_LEVEL )
   4033     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
   4034 
   4035   lookup_count = gsub->LookupList.LookupCount;
   4036   if (lookup_index >= lookup_count)
   4037     return error;
   4038 
   4039   lo    = &gsub->LookupList.Lookup[lookup_index];
   4040   flags = lo->LookupFlag;
   4041   lookup_type = lo->LookupType;
   4042 
   4043   for ( i = 0; i < lo->SubTableCount; i++ )
   4044   {
   4045     HB_GSUB_SubTable *st = &lo->SubTable[i].st.gsub;
   4046 
   4047     switch (lookup_type) {
   4048       case HB_GSUB_LOOKUP_SINGLE:
   4049 	error = Lookup_SingleSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4050       case HB_GSUB_LOOKUP_MULTIPLE:
   4051 	error = Lookup_MultipleSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4052       case HB_GSUB_LOOKUP_ALTERNATE:
   4053 	error = Lookup_AlternateSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4054       case HB_GSUB_LOOKUP_LIGATURE:
   4055 	error = Lookup_LigatureSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4056       case HB_GSUB_LOOKUP_CONTEXT:
   4057 	error = Lookup_ContextSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4058       case HB_GSUB_LOOKUP_CHAIN:
   4059 	error = Lookup_ChainContextSubst	( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4060     /*case HB_GSUB_LOOKUP_EXTENSION:
   4061 	error = Lookup_ExtensionSubst		( gsub, st, buffer, flags, context_length, nesting_level ); break;*/
   4062       case HB_GSUB_LOOKUP_REVERSE_CHAIN:
   4063 	error = Lookup_ReverseChainContextSubst	( gsub, st, buffer, flags, context_length, nesting_level ); break;
   4064       default:
   4065 	error = HB_Err_Not_Covered;
   4066     };
   4067 
   4068     /* Check whether we have a successful substitution or an error other
   4069        than HB_Err_Not_Covered                                          */
   4070     if ( error != HB_Err_Not_Covered )
   4071       return error;
   4072   }
   4073 
   4074   return HB_Err_Not_Covered;
   4075 }
   4076 
   4077 
   4078 HB_INTERNAL HB_Error
   4079 _HB_GSUB_Load_SubTable( HB_GSUB_SubTable* st,
   4080 			HB_Stream         stream,
   4081 			HB_UShort         lookup_type )
   4082 {
   4083   switch (lookup_type) {
   4084     case HB_GSUB_LOOKUP_SINGLE:		return Load_SingleSubst			( st, stream );
   4085     case HB_GSUB_LOOKUP_MULTIPLE:	return Load_MultipleSubst		( st, stream );
   4086     case HB_GSUB_LOOKUP_ALTERNATE:	return Load_AlternateSubst		( st, stream );
   4087     case HB_GSUB_LOOKUP_LIGATURE:	return Load_LigatureSubst		( st, stream );
   4088     case HB_GSUB_LOOKUP_CONTEXT:	return Load_ContextSubst		( st, stream );
   4089     case HB_GSUB_LOOKUP_CHAIN:		return Load_ChainContextSubst		( st, stream );
   4090   /*case HB_GSUB_LOOKUP_EXTENSION:	return Load_ExtensionSubst		( st, stream );*/
   4091     case HB_GSUB_LOOKUP_REVERSE_CHAIN:	return Load_ReverseChainContextSubst	( st, stream );
   4092     default:				return ERR(HB_Err_Invalid_SubTable_Format);
   4093   };
   4094 }
   4095 
   4096 
   4097 HB_INTERNAL void
   4098 _HB_GSUB_Free_SubTable( HB_GSUB_SubTable* st,
   4099 			HB_UShort         lookup_type )
   4100 {
   4101   switch ( lookup_type ) {
   4102     case HB_GSUB_LOOKUP_SINGLE:		Free_SingleSubst		( st ); return;
   4103     case HB_GSUB_LOOKUP_MULTIPLE:	Free_MultipleSubst		( st ); return;
   4104     case HB_GSUB_LOOKUP_ALTERNATE:	Free_AlternateSubst		( st ); return;
   4105     case HB_GSUB_LOOKUP_LIGATURE:	Free_LigatureSubst		( st ); return;
   4106     case HB_GSUB_LOOKUP_CONTEXT:	Free_ContextSubst		( st ); return;
   4107     case HB_GSUB_LOOKUP_CHAIN:		Free_ChainContextSubst		( st ); return;
   4108   /*case HB_GSUB_LOOKUP_EXTENSION:	Free_ExtensionSubst		( st ); return;*/
   4109     case HB_GSUB_LOOKUP_REVERSE_CHAIN:	Free_ReverseChainContextSubst	( st ); return;
   4110     default:									return;
   4111   };
   4112 }
   4113 
   4114 
   4115 
   4116 /* apply one lookup to the input string object */
   4117 
   4118 static HB_Error  GSUB_Do_String_Lookup( HB_GSUBHeader*   gsub,
   4119 				   HB_UShort         lookup_index,
   4120 				   HB_Buffer        buffer )
   4121 {
   4122   HB_Error  error, retError = HB_Err_Not_Covered;
   4123 
   4124   HB_UInt*  properties = gsub->LookupList.Properties;
   4125   int       lookup_type = gsub->LookupList.Lookup[lookup_index].LookupType;
   4126 
   4127   const int       nesting_level = 0;
   4128   /* 0xFFFF indicates that we don't have a context length yet */
   4129   const HB_UShort context_length = 0xFFFF;
   4130 
   4131   switch (lookup_type) {
   4132 
   4133     case HB_GSUB_LOOKUP_SINGLE:
   4134     case HB_GSUB_LOOKUP_MULTIPLE:
   4135     case HB_GSUB_LOOKUP_ALTERNATE:
   4136     case HB_GSUB_LOOKUP_LIGATURE:
   4137     case HB_GSUB_LOOKUP_CONTEXT:
   4138     case HB_GSUB_LOOKUP_CHAIN:
   4139       /* in/out forward substitution (implemented lazy) */
   4140 
   4141       _hb_buffer_clear_output ( buffer );
   4142       buffer->in_pos = 0;
   4143   while ( buffer->in_pos < buffer->in_length )
   4144   {
   4145     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
   4146     {
   4147 	  error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
   4148       if ( error )
   4149       {
   4150 	if ( error != HB_Err_Not_Covered )
   4151 	  return error;
   4152       }
   4153       else
   4154 	retError = error;
   4155     }
   4156     else
   4157       error = HB_Err_Not_Covered;
   4158 
   4159     if ( error == HB_Err_Not_Covered )
   4160 	  if ( COPY_Glyph ( buffer ) )
   4161 	return error;
   4162   }
   4163       /* we shouldn't swap if error occurred.
   4164        *
   4165        * also don't swap if nothing changed (ie HB_Err_Not_Covered).
   4166        * shouldn't matter in that case though.
   4167        */
   4168       if ( retError == HB_Err_Ok )
   4169 	_hb_buffer_swap( buffer );
   4170 
   4171   return retError;
   4172 
   4173     case HB_GSUB_LOOKUP_REVERSE_CHAIN:
   4174       /* in-place backward substitution */
   4175 
   4176       buffer->in_pos = buffer->in_length - 1;
   4177     do
   4178     {
   4179       if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
   4180 	{
   4181 	  error = GSUB_Do_Glyph_Lookup( gsub, lookup_index, buffer, context_length, nesting_level );
   4182 	  if ( error )
   4183 	    {
   4184 	      if ( error != HB_Err_Not_Covered )
   4185 		return error;
   4186 	    }
   4187 	  else
   4188 	    retError = error;
   4189 	}
   4190 	else
   4191 	  error = HB_Err_Not_Covered;
   4192 
   4193 	if ( error == HB_Err_Not_Covered )
   4194 	  buffer->in_pos--;
   4195       }
   4196       while ((HB_Int) buffer->in_pos >= 0);
   4197 
   4198       return retError;
   4199 
   4200   /*case HB_GSUB_LOOKUP_EXTENSION:*/
   4201     default:
   4202   return retError;
   4203   };
   4204 }
   4205 
   4206 
   4207 HB_Error  HB_GSUB_Add_Feature( HB_GSUBHeader*  gsub,
   4208 			       HB_UShort        feature_index,
   4209 			       HB_UInt          property )
   4210 {
   4211   HB_UShort    i;
   4212 
   4213   HB_Feature  feature;
   4214   HB_UInt*     properties;
   4215   HB_UShort*   index;
   4216   HB_UShort    lookup_count;
   4217 
   4218   /* Each feature can only be added once */
   4219 
   4220   if ( !gsub ||
   4221        feature_index >= gsub->FeatureList.FeatureCount ||
   4222        gsub->FeatureList.ApplyCount == gsub->FeatureList.FeatureCount )
   4223     return ERR(HB_Err_Invalid_Argument);
   4224 
   4225   gsub->FeatureList.ApplyOrder[gsub->FeatureList.ApplyCount++] = feature_index;
   4226 
   4227   properties = gsub->LookupList.Properties;
   4228 
   4229   feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
   4230   index   = feature.LookupListIndex;
   4231   lookup_count = gsub->LookupList.LookupCount;
   4232 
   4233   for ( i = 0; i < feature.LookupListCount; i++ )
   4234   {
   4235     HB_UShort lookup_index = index[i];
   4236     if (lookup_index < lookup_count)
   4237       properties[lookup_index] |= property;
   4238   }
   4239 
   4240   return HB_Err_Ok;
   4241 }
   4242 
   4243 
   4244 
   4245 HB_Error  HB_GSUB_Clear_Features( HB_GSUBHeader*  gsub )
   4246 {
   4247   HB_UShort i;
   4248 
   4249   HB_UInt*  properties;
   4250 
   4251 
   4252   if ( !gsub )
   4253     return ERR(HB_Err_Invalid_Argument);
   4254 
   4255   gsub->FeatureList.ApplyCount = 0;
   4256 
   4257   properties = gsub->LookupList.Properties;
   4258 
   4259   for ( i = 0; i < gsub->LookupList.LookupCount; i++ )
   4260     properties[i] = 0;
   4261 
   4262   return HB_Err_Ok;
   4263 }
   4264 
   4265 
   4266 
   4267 HB_Error  HB_GSUB_Register_Alternate_Function( HB_GSUBHeader*  gsub,
   4268 					       HB_AltFunction  altfunc,
   4269 					       void*            data )
   4270 {
   4271   if ( !gsub )
   4272     return ERR(HB_Err_Invalid_Argument);
   4273 
   4274   gsub->altfunc = altfunc;
   4275   gsub->data    = data;
   4276 
   4277   return HB_Err_Ok;
   4278 }
   4279 
   4280 /* returns error if one happened, otherwise returns HB_Err_Not_Covered if no
   4281  * feature were applied, or HB_Err_Ok otherwise.
   4282  */
   4283 HB_Error  HB_GSUB_Apply_String( HB_GSUBHeader*   gsub,
   4284 				HB_Buffer        buffer )
   4285 {
   4286   HB_Error          error, retError = HB_Err_Not_Covered;
   4287   int               i, j, lookup_count, num_features;
   4288 
   4289   if ( !gsub ||
   4290        !buffer)
   4291     return ERR(HB_Err_Invalid_Argument);
   4292 
   4293   if ( buffer->in_length == 0 )
   4294     return retError;
   4295 
   4296   lookup_count = gsub->LookupList.LookupCount;
   4297   num_features = gsub->FeatureList.ApplyCount;
   4298 
   4299   for ( i = 0; i < num_features; i++)
   4300   {
   4301     HB_UShort  feature_index = gsub->FeatureList.ApplyOrder[i];
   4302     HB_Feature feature = gsub->FeatureList.FeatureRecord[feature_index].Feature;
   4303 
   4304     for ( j = 0; j < feature.LookupListCount; j++ )
   4305     {
   4306       HB_UShort         lookup_index = feature.LookupListIndex[j];
   4307 
   4308       /* Skip nonexistant lookups */
   4309       if (lookup_index >= lookup_count)
   4310        continue;
   4311 
   4312 	error = GSUB_Do_String_Lookup( gsub, lookup_index, buffer );
   4313       if ( error )
   4314       {
   4315 	if ( error != HB_Err_Not_Covered )
   4316 	  return error;
   4317       }
   4318       else
   4319 	retError = error;
   4320     }
   4321   }
   4322 
   4323   error = retError;
   4324 
   4325   return error;
   4326 }
   4327 
   4328 
   4329 /* END */
   4330