Home | History | Annotate | Download | only in src
      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-gpos-private.h"
     31 #include "harfbuzz-open-private.h"
     32 #include "harfbuzz-gdef-private.h"
     33 #include "harfbuzz-shaper.h"
     34 
     35 struct  GPOS_Instance_
     36 {
     37   HB_GPOSHeader*  gpos;
     38   HB_Font          font;
     39   HB_Bool          dvi;
     40   HB_UShort        load_flags;  /* how the glyph should be loaded */
     41   HB_Bool          r2l;
     42 
     43   HB_UShort        last;        /* the last valid glyph -- used
     44 				   with cursive positioning     */
     45   HB_Fixed           anchor_x;    /* the coordinates of the anchor point */
     46   HB_Fixed           anchor_y;    /* of the last valid glyph             */
     47 };
     48 
     49 typedef struct GPOS_Instance_  GPOS_Instance;
     50 
     51 
     52 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
     53 				       HB_UShort         lookup_index,
     54 				       HB_Buffer        buffer,
     55 				       HB_UShort         context_length,
     56 				       int               nesting_level );
     57 
     58 
     59 
     60 #ifdef HB_SUPPORT_MULTIPLE_MASTER
     61 /* the client application must replace this with something more
     62    meaningful if multiple master fonts are to be supported.     */
     63 
     64 static HB_Error  default_mmfunc( HB_Font      font,
     65 				 HB_UShort    metric_id,
     66 				 HB_Fixed*      metric_value,
     67 				 void*        data )
     68 {
     69   HB_UNUSED(font);
     70   HB_UNUSED(metric_id);
     71   HB_UNUSED(metric_value);
     72   HB_UNUSED(data);
     73   return ERR(HB_Err_Not_Covered); /* ERR() call intended */
     74 }
     75 #endif
     76 
     77 
     78 
     79 HB_Error  HB_Load_GPOS_Table( HB_Stream stream,
     80 			      HB_GPOSHeader** retptr,
     81 			      HB_GDEFHeader*  gdef,
     82 			      HB_Stream       gdefStream )
     83 {
     84   HB_UInt         cur_offset, new_offset, base_offset;
     85 
     86   HB_GPOSHeader*  gpos;
     87 
     88   HB_Error   error;
     89 
     90 
     91   if ( !retptr )
     92     return ERR(HB_Err_Invalid_Argument);
     93 
     94   if ( GOTO_Table( TTAG_GPOS ) )
     95     return error;
     96 
     97   base_offset = FILE_Pos();
     98 
     99   if ( ALLOC ( gpos, sizeof( *gpos ) ) )
    100     return error;
    101 
    102 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    103   gpos->mmfunc = default_mmfunc;
    104 #endif
    105 
    106   /* skip version */
    107 
    108   if ( FILE_Seek( base_offset + 4L ) ||
    109        ACCESS_Frame( 2L ) )
    110     goto Fail4;
    111 
    112   new_offset = GET_UShort() + base_offset;
    113 
    114   FORGET_Frame();
    115 
    116   cur_offset = FILE_Pos();
    117   if ( FILE_Seek( new_offset ) ||
    118        ( error = _HB_OPEN_Load_ScriptList( &gpos->ScriptList,
    119 				  stream ) ) != HB_Err_Ok )
    120     goto Fail4;
    121   (void)FILE_Seek( cur_offset );
    122 
    123   if ( ACCESS_Frame( 2L ) )
    124     goto Fail3;
    125 
    126   new_offset = GET_UShort() + base_offset;
    127 
    128   FORGET_Frame();
    129 
    130   cur_offset = FILE_Pos();
    131   if ( FILE_Seek( new_offset ) ||
    132        ( error = _HB_OPEN_Load_FeatureList( &gpos->FeatureList,
    133 				   stream ) ) != HB_Err_Ok )
    134     goto Fail3;
    135   (void)FILE_Seek( cur_offset );
    136 
    137   if ( ACCESS_Frame( 2L ) )
    138     goto Fail2;
    139 
    140   new_offset = GET_UShort() + base_offset;
    141 
    142   FORGET_Frame();
    143 
    144   cur_offset = FILE_Pos();
    145   if ( FILE_Seek( new_offset ) ||
    146        ( error = _HB_OPEN_Load_LookupList( &gpos->LookupList,
    147 				  stream, HB_Type_GPOS ) ) != HB_Err_Ok )
    148     goto Fail2;
    149 
    150   gpos->gdef = gdef;      /* can be NULL */
    151 
    152   if ( ( error =  _HB_GDEF_LoadMarkAttachClassDef_From_LookupFlags( gdef, gdefStream,
    153 								     gpos->LookupList.Lookup,
    154 								     gpos->LookupList.LookupCount ) ) )
    155     goto Fail1;
    156 
    157   *retptr = gpos;
    158 
    159   return HB_Err_Ok;
    160 
    161 Fail1:
    162   _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
    163 
    164 Fail2:
    165   _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
    166 
    167 Fail3:
    168   _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
    169 
    170 Fail4:
    171   FREE( gpos );
    172 
    173   return error;
    174 }
    175 
    176 
    177 HB_Error  HB_Done_GPOS_Table( HB_GPOSHeader* gpos )
    178 {
    179   _HB_OPEN_Free_LookupList( &gpos->LookupList, HB_Type_GPOS );
    180   _HB_OPEN_Free_FeatureList( &gpos->FeatureList );
    181   _HB_OPEN_Free_ScriptList( &gpos->ScriptList );
    182 
    183   FREE( gpos );
    184 
    185   return HB_Err_Ok;
    186 }
    187 
    188 
    189 /*****************************
    190  * SubTable related functions
    191  *****************************/
    192 
    193 /* shared tables */
    194 
    195 /* ValueRecord */
    196 
    197 /* There is a subtle difference in the specs between a `table' and a
    198    `record' -- offsets for device tables in ValueRecords are taken from
    199    the parent table and not the parent record.                          */
    200 
    201 static HB_Error  Load_ValueRecord( HB_ValueRecord*  vr,
    202 				   HB_UShort         format,
    203 				   HB_UInt          base_offset,
    204 				   HB_Stream         stream )
    205 {
    206   HB_Error  error;
    207 
    208   HB_UInt cur_offset, new_offset;
    209 
    210 
    211   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
    212   {
    213     if ( ACCESS_Frame( 2L ) )
    214       return error;
    215 
    216     vr->XPlacement = GET_Short();
    217 
    218     FORGET_Frame();
    219   }
    220   else
    221     vr->XPlacement = 0;
    222 
    223   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
    224   {
    225     if ( ACCESS_Frame( 2L ) )
    226       return error;
    227 
    228     vr->YPlacement = GET_Short();
    229 
    230     FORGET_Frame();
    231   }
    232   else
    233     vr->YPlacement = 0;
    234 
    235   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
    236   {
    237     if ( ACCESS_Frame( 2L ) )
    238       return error;
    239 
    240     vr->XAdvance = GET_Short();
    241 
    242     FORGET_Frame();
    243   }
    244   else
    245     vr->XAdvance = 0;
    246 
    247   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
    248   {
    249     if ( ACCESS_Frame( 2L ) )
    250       return error;
    251 
    252     vr->YAdvance = GET_Short();
    253 
    254     FORGET_Frame();
    255   }
    256   else
    257     vr->YAdvance = 0;
    258 
    259   if ( format & HB_GPOS_FORMAT_HAVE_DEVICE_TABLES )
    260   {
    261     if ( ALLOC_ARRAY( vr->DeviceTables, 4, HB_Device ) )
    262       return error;
    263     vr->DeviceTables[VR_X_ADVANCE_DEVICE] = 0;
    264     vr->DeviceTables[VR_Y_ADVANCE_DEVICE] = 0;
    265     vr->DeviceTables[VR_X_PLACEMENT_DEVICE] = 0;
    266     vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] = 0;
    267   }
    268   else
    269   {
    270     vr->DeviceTables = 0;
    271   }
    272 
    273   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    274   {
    275     if ( ACCESS_Frame( 2L ) )
    276       goto Fail4;
    277 
    278     new_offset = GET_UShort();
    279 
    280     FORGET_Frame();
    281 
    282     if ( new_offset )
    283     {
    284       new_offset += base_offset;
    285 
    286       cur_offset = FILE_Pos();
    287       if ( FILE_Seek( new_offset ) ||
    288 	   ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_PLACEMENT_DEVICE],
    289 				  stream ) ) != HB_Err_Ok )
    290        goto Fail4;
    291       (void)FILE_Seek( cur_offset );
    292     }
    293   }
    294 
    295   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    296   {
    297     if ( ACCESS_Frame( 2L ) )
    298       goto Fail3;
    299 
    300     new_offset = GET_UShort();
    301 
    302     FORGET_Frame();
    303 
    304     if ( new_offset )
    305     {
    306       new_offset += base_offset;
    307 
    308       cur_offset = FILE_Pos();
    309       if ( FILE_Seek( new_offset ) ||
    310 	   ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_PLACEMENT_DEVICE],
    311 				  stream ) ) != HB_Err_Ok )
    312 	goto Fail3;
    313       (void)FILE_Seek( cur_offset );
    314     }
    315   }
    316 
    317   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    318   {
    319     if ( ACCESS_Frame( 2L ) )
    320       goto Fail2;
    321 
    322     new_offset = GET_UShort();
    323 
    324     FORGET_Frame();
    325 
    326     if ( new_offset )
    327     {
    328       new_offset += base_offset;
    329 
    330       cur_offset = FILE_Pos();
    331       if ( FILE_Seek( new_offset ) ||
    332 	   ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_X_ADVANCE_DEVICE],
    333 				  stream ) ) != HB_Err_Ok )
    334 	goto Fail2;
    335       (void)FILE_Seek( cur_offset );
    336     }
    337   }
    338 
    339   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    340   {
    341     if ( ACCESS_Frame( 2L ) )
    342       goto Fail1;
    343 
    344     new_offset = GET_UShort();
    345 
    346     FORGET_Frame();
    347 
    348     if ( new_offset )
    349     {
    350       new_offset += base_offset;
    351 
    352       cur_offset = FILE_Pos();
    353       if ( FILE_Seek( new_offset ) ||
    354 	   ( error = _HB_OPEN_Load_Device( &vr->DeviceTables[VR_Y_ADVANCE_DEVICE],
    355 				  stream ) ) != HB_Err_Ok )
    356 	goto Fail1;
    357       (void)FILE_Seek( cur_offset );
    358     }
    359   }
    360 
    361   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
    362   {
    363     if ( ACCESS_Frame( 2L ) )
    364       goto Fail1;
    365 
    366 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    367     vr->XIdPlacement = GET_UShort();
    368 #else
    369     (void) GET_UShort();
    370 #endif
    371 
    372     FORGET_Frame();
    373   }
    374 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    375   else
    376     vr->XIdPlacement = 0;
    377 #endif
    378 
    379   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
    380   {
    381     if ( ACCESS_Frame( 2L ) )
    382       goto Fail1;
    383 
    384 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    385     vr->YIdPlacement = GET_UShort();
    386 #else
    387     (void) GET_UShort();
    388 #endif
    389 
    390     FORGET_Frame();
    391   }
    392 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    393   else
    394     vr->YIdPlacement = 0;
    395 #endif
    396 
    397   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
    398   {
    399     if ( ACCESS_Frame( 2L ) )
    400       goto Fail1;
    401 
    402 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    403     vr->XIdAdvance = GET_UShort();
    404 #else
    405     (void) GET_UShort();
    406 #endif
    407 
    408     FORGET_Frame();
    409   }
    410 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    411   else
    412     vr->XIdAdvance = 0;
    413 #endif
    414 
    415   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
    416   {
    417     if ( ACCESS_Frame( 2L ) )
    418       goto Fail1;
    419 
    420 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    421     vr->YIdAdvance = GET_UShort();
    422 #else
    423     (void) GET_UShort();
    424 #endif
    425 
    426     FORGET_Frame();
    427   }
    428 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    429   else
    430     vr->YIdAdvance = 0;
    431 #endif
    432 
    433   return HB_Err_Ok;
    434 
    435 Fail1:
    436   if ( vr->DeviceTables )
    437     _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] );
    438 
    439 Fail2:
    440   if ( vr->DeviceTables )
    441     _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] );
    442 
    443 Fail3:
    444   if ( vr->DeviceTables )
    445     _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] );
    446 
    447 Fail4:
    448   FREE( vr->DeviceTables );
    449   return error;
    450 }
    451 
    452 
    453 static void  Free_ValueRecord( HB_ValueRecord*  vr,
    454 			       HB_UShort         format )
    455 {
    456   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    457     _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE] );
    458   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    459     _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE] );
    460   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    461     _HB_OPEN_Free_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE] );
    462   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    463     _HB_OPEN_Free_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE] );
    464   FREE( vr->DeviceTables );
    465 }
    466 
    467 
    468 static HB_Error  Get_ValueRecord( GPOS_Instance*    gpi,
    469 				  HB_ValueRecord*  vr,
    470 				  HB_UShort         format,
    471 				  HB_Position      gd )
    472 {
    473   HB_Short         pixel_value;
    474   HB_Error         error = HB_Err_Ok;
    475 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    476   HB_GPOSHeader*  gpos = gpi->gpos;
    477   HB_Fixed           value;
    478 #endif
    479 
    480   HB_UShort  x_ppem, y_ppem;
    481   HB_16Dot16   x_scale, y_scale;
    482 
    483 
    484   if ( !format )
    485     return HB_Err_Ok;
    486 
    487   x_ppem  = gpi->font->x_ppem;
    488   y_ppem  = gpi->font->y_ppem;
    489   x_scale = gpi->font->x_scale;
    490   y_scale = gpi->font->y_scale;
    491 
    492   /* design units -> fractional pixel */
    493 
    494   if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT )
    495     gd->x_pos += x_scale * vr->XPlacement / 0x10000;
    496   if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT )
    497     gd->y_pos += y_scale * vr->YPlacement / 0x10000;
    498   if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE )
    499     gd->x_advance += x_scale * vr->XAdvance / 0x10000;
    500   if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE )
    501     gd->y_advance += y_scale * vr->YAdvance / 0x10000;
    502 
    503   if ( !gpi->dvi )
    504   {
    505     /* pixel -> fractional pixel */
    506 
    507     if ( format & HB_GPOS_FORMAT_HAVE_X_PLACEMENT_DEVICE )
    508     {
    509       _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_PLACEMENT_DEVICE], x_ppem, &pixel_value );
    510       gd->x_pos += pixel_value << 6;
    511     }
    512     if ( format & HB_GPOS_FORMAT_HAVE_Y_PLACEMENT_DEVICE )
    513     {
    514       _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_PLACEMENT_DEVICE], y_ppem, &pixel_value );
    515       gd->y_pos += pixel_value << 6;
    516     }
    517     if ( format & HB_GPOS_FORMAT_HAVE_X_ADVANCE_DEVICE )
    518     {
    519       _HB_OPEN_Get_Device( vr->DeviceTables[VR_X_ADVANCE_DEVICE], x_ppem, &pixel_value );
    520       gd->x_advance += pixel_value << 6;
    521     }
    522     if ( format & HB_GPOS_FORMAT_HAVE_Y_ADVANCE_DEVICE )
    523     {
    524       _HB_OPEN_Get_Device( vr->DeviceTables[VR_Y_ADVANCE_DEVICE], y_ppem, &pixel_value );
    525       gd->y_advance += pixel_value << 6;
    526     }
    527   }
    528 
    529 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    530   /* values returned from mmfunc() are already in fractional pixels */
    531 
    532   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_PLACEMENT )
    533   {
    534     error = (gpos->mmfunc)( gpi->font, vr->XIdPlacement,
    535 			    &value, gpos->data );
    536     if ( error )
    537       return error;
    538     gd->x_pos += value;
    539   }
    540   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_PLACEMENT )
    541   {
    542     error = (gpos->mmfunc)( gpi->font, vr->YIdPlacement,
    543 			    &value, gpos->data );
    544     if ( error )
    545       return error;
    546     gd->y_pos += value;
    547   }
    548   if ( format & HB_GPOS_FORMAT_HAVE_X_ID_ADVANCE )
    549   {
    550     error = (gpos->mmfunc)( gpi->font, vr->XIdAdvance,
    551 			    &value, gpos->data );
    552     if ( error )
    553       return error;
    554     gd->x_advance += value;
    555   }
    556   if ( format & HB_GPOS_FORMAT_HAVE_Y_ID_ADVANCE )
    557   {
    558     error = (gpos->mmfunc)( gpi->font, vr->YIdAdvance,
    559 			    &value, gpos->data );
    560     if ( error )
    561       return error;
    562     gd->y_advance += value;
    563   }
    564 #endif
    565 
    566   return error;
    567 }
    568 
    569 
    570 /* AnchorFormat1 */
    571 /* AnchorFormat2 */
    572 /* AnchorFormat3 */
    573 /* AnchorFormat4 */
    574 
    575 static HB_Error  Load_Anchor( HB_Anchor*  an,
    576 			      HB_Stream    stream )
    577 {
    578   HB_Error  error;
    579 
    580   HB_UInt cur_offset, new_offset, base_offset;
    581 
    582 
    583   base_offset = FILE_Pos();
    584 
    585   if ( ACCESS_Frame( 2L ) )
    586     return error;
    587 
    588   an->PosFormat = GET_UShort();
    589 
    590   FORGET_Frame();
    591 
    592   switch ( an->PosFormat )
    593   {
    594   case 1:
    595     if ( ACCESS_Frame( 4L ) )
    596       return error;
    597 
    598     an->af.af1.XCoordinate = GET_Short();
    599     an->af.af1.YCoordinate = GET_Short();
    600 
    601     FORGET_Frame();
    602     break;
    603 
    604   case 2:
    605     if ( ACCESS_Frame( 6L ) )
    606       return error;
    607 
    608     an->af.af2.XCoordinate = GET_Short();
    609     an->af.af2.YCoordinate = GET_Short();
    610     an->af.af2.AnchorPoint = GET_UShort();
    611 
    612     FORGET_Frame();
    613     break;
    614 
    615   case 3:
    616     if ( ACCESS_Frame( 6L ) )
    617       return error;
    618 
    619     an->af.af3.XCoordinate = GET_Short();
    620     an->af.af3.YCoordinate = GET_Short();
    621 
    622     new_offset = GET_UShort();
    623 
    624     FORGET_Frame();
    625 
    626     if ( new_offset )
    627     {
    628       if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
    629         return error;
    630 
    631       an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0;
    632       an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0;
    633 
    634       new_offset += base_offset;
    635 
    636       cur_offset = FILE_Pos();
    637       if ( FILE_Seek( new_offset ) ||
    638 	   ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE],
    639 				  stream ) ) != HB_Err_Ok )
    640 	goto Fail2;
    641       (void)FILE_Seek( cur_offset );
    642     }
    643 
    644     if ( ACCESS_Frame( 2L ) )
    645       goto Fail;
    646 
    647     new_offset = GET_UShort();
    648 
    649     FORGET_Frame();
    650 
    651     if ( new_offset )
    652     {
    653       if ( !an->af.af3.DeviceTables )
    654       {
    655         if ( ALLOC_ARRAY( an->af.af3.DeviceTables, 2, HB_Device ) )
    656           return error;
    657 
    658         an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] = 0;
    659         an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] = 0;
    660       }
    661 
    662       new_offset += base_offset;
    663 
    664       cur_offset = FILE_Pos();
    665       if ( FILE_Seek( new_offset ) ||
    666 	   ( error = _HB_OPEN_Load_Device( &an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE],
    667 				  stream ) ) != HB_Err_Ok )
    668 	goto Fail;
    669       (void)FILE_Seek( cur_offset );
    670     }
    671     break;
    672 
    673   case 4:
    674     if ( ACCESS_Frame( 4L ) )
    675       return error;
    676 
    677 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    678     an->af.af4.XIdAnchor = GET_UShort();
    679     an->af.af4.YIdAnchor = GET_UShort();
    680 #else
    681     (void) GET_UShort();
    682     (void) GET_UShort();
    683 #endif
    684 
    685     FORGET_Frame();
    686     break;
    687 
    688   default:
    689     return ERR(HB_Err_Invalid_SubTable_Format);
    690   }
    691 
    692   return HB_Err_Ok;
    693 
    694 Fail:
    695   if ( an->af.af3.DeviceTables )
    696     _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] );
    697 
    698 Fail2:
    699   FREE( an->af.af3.DeviceTables );
    700   return error;
    701 }
    702 
    703 
    704 static void  Free_Anchor( HB_Anchor*  an)
    705 {
    706   if ( an->PosFormat == 3 && an->af.af3.DeviceTables )
    707   {
    708     _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE] );
    709     _HB_OPEN_Free_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE] );
    710     FREE( an->af.af3.DeviceTables );
    711   }
    712 }
    713 
    714 
    715 static HB_Error  Get_Anchor( GPOS_Instance*   gpi,
    716 			     HB_Anchor*      an,
    717 			     HB_UShort        glyph_index,
    718 			     HB_Fixed*          x_value,
    719 			     HB_Fixed*          y_value )
    720 {
    721   HB_Error  error = HB_Err_Ok;
    722 
    723 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    724   HB_GPOSHeader*  gpos = gpi->gpos;
    725 #endif
    726   HB_UShort        ap;
    727 
    728   HB_Short         pixel_value;
    729 
    730   HB_UShort        x_ppem, y_ppem;
    731   HB_16Dot16         x_scale, y_scale;
    732 
    733 
    734   x_ppem  = gpi->font->x_ppem;
    735   y_ppem  = gpi->font->y_ppem;
    736   x_scale = gpi->font->x_scale;
    737   y_scale = gpi->font->y_scale;
    738 
    739   switch ( an->PosFormat )
    740   {
    741   case 0:
    742     /* The special case of an empty AnchorTable */
    743   default:
    744 
    745     return HB_Err_Not_Covered;
    746 
    747   case 1:
    748     *x_value = x_scale * an->af.af1.XCoordinate / 0x10000;
    749     *y_value = y_scale * an->af.af1.YCoordinate / 0x10000;
    750     break;
    751 
    752   case 2:
    753     if ( !gpi->dvi )
    754     {
    755       hb_uint32 n_points = 0;
    756       ap = an->af.af2.AnchorPoint;
    757       if (!gpi->font->klass->getPointInOutline)
    758           goto no_contour_point;
    759       error = gpi->font->klass->getPointInOutline(gpi->font, glyph_index, gpi->load_flags, ap, x_value, y_value, &n_points);
    760       if (error)
    761           return error;
    762       /* if n_points is set to zero, we use the design coordinate value pair.
    763        * This can happen e.g. for sbit glyphs. */
    764       if (!n_points)
    765           goto no_contour_point;
    766     }
    767     else
    768     {
    769     no_contour_point:
    770       *x_value = x_scale * an->af.af3.XCoordinate / 0x10000;
    771       *y_value = y_scale * an->af.af3.YCoordinate / 0x10000;
    772     }
    773     break;
    774 
    775   case 3:
    776     if ( !gpi->dvi )
    777     {
    778       _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_X_DEVICE_TABLE], x_ppem, &pixel_value );
    779       *x_value = pixel_value << 6;
    780       _HB_OPEN_Get_Device( an->af.af3.DeviceTables[AF3_Y_DEVICE_TABLE], y_ppem, &pixel_value );
    781       *y_value = pixel_value << 6;
    782     }
    783     else
    784       *x_value = *y_value = 0;
    785 
    786     *x_value += x_scale * an->af.af3.XCoordinate / 0x10000;
    787     *y_value += y_scale * an->af.af3.YCoordinate / 0x10000;
    788     break;
    789 
    790   case 4:
    791 #ifdef HB_SUPPORT_MULTIPLE_MASTER
    792     error = (gpos->mmfunc)( gpi->font, an->af.af4.XIdAnchor,
    793 			    x_value, gpos->data );
    794     if ( error )
    795       return error;
    796 
    797     error = (gpos->mmfunc)( gpi->font, an->af.af4.YIdAnchor,
    798 			    y_value, gpos->data );
    799     if ( error )
    800       return error;
    801     break;
    802 #else
    803     return ERR(HB_Err_Not_Covered);
    804 #endif
    805   }
    806 
    807   return error;
    808 }
    809 
    810 
    811 /* MarkArray */
    812 
    813 static HB_Error  Load_MarkArray ( HB_MarkArray*  ma,
    814 				  HB_Stream       stream )
    815 {
    816   HB_Error  error;
    817 
    818   HB_UShort        n, m, count;
    819   HB_UInt         cur_offset, new_offset, base_offset;
    820 
    821   HB_MarkRecord*  mr;
    822 
    823 
    824   base_offset = FILE_Pos();
    825 
    826   if ( ACCESS_Frame( 2L ) )
    827     return error;
    828 
    829   count = ma->MarkCount = GET_UShort();
    830 
    831   FORGET_Frame();
    832 
    833   ma->MarkRecord = NULL;
    834 
    835   if ( ALLOC_ARRAY( ma->MarkRecord, count, HB_MarkRecord ) )
    836     return error;
    837 
    838   mr = ma->MarkRecord;
    839 
    840   for ( n = 0; n < count; n++ )
    841   {
    842     if ( ACCESS_Frame( 4L ) )
    843       goto Fail;
    844 
    845     mr[n].Class = GET_UShort();
    846     new_offset  = GET_UShort() + base_offset;
    847 
    848     FORGET_Frame();
    849 
    850     cur_offset = FILE_Pos();
    851     if ( FILE_Seek( new_offset ) ||
    852 	 ( error = Load_Anchor( &mr[n].MarkAnchor, stream ) ) != HB_Err_Ok )
    853       goto Fail;
    854     (void)FILE_Seek( cur_offset );
    855   }
    856 
    857   return HB_Err_Ok;
    858 
    859 Fail:
    860   for ( m = 0; m < n; m++ )
    861     Free_Anchor( &mr[m].MarkAnchor );
    862 
    863   FREE( mr );
    864   return error;
    865 }
    866 
    867 
    868 static void  Free_MarkArray( HB_MarkArray*  ma )
    869 {
    870   HB_UShort        n, count;
    871 
    872   HB_MarkRecord*  mr;
    873 
    874 
    875   if ( ma->MarkRecord )
    876   {
    877     count = ma->MarkCount;
    878     mr    = ma->MarkRecord;
    879 
    880     for ( n = 0; n < count; n++ )
    881       Free_Anchor( &mr[n].MarkAnchor );
    882 
    883     FREE( mr );
    884   }
    885 }
    886 
    887 
    888 /* LookupType 1 */
    889 
    890 /* SinglePosFormat1 */
    891 /* SinglePosFormat2 */
    892 
    893 static HB_Error  Load_SinglePos( HB_GPOS_SubTable* st,
    894 				 HB_Stream       stream )
    895 {
    896   HB_Error  error;
    897   HB_SinglePos*   sp = &st->single;
    898 
    899   HB_UShort         n, m, count, format;
    900   HB_UInt          cur_offset, new_offset, base_offset;
    901 
    902   HB_ValueRecord*  vr;
    903 
    904 
    905   base_offset = FILE_Pos();
    906 
    907   if ( ACCESS_Frame( 6L ) )
    908     return error;
    909 
    910   sp->PosFormat = GET_UShort();
    911   new_offset    = GET_UShort() + base_offset;
    912 
    913   format = sp->ValueFormat = GET_UShort();
    914 
    915   FORGET_Frame();
    916 
    917   if ( !format )
    918     return ERR(HB_Err_Invalid_SubTable);
    919 
    920   cur_offset = FILE_Pos();
    921   if ( FILE_Seek( new_offset ) ||
    922        ( error = _HB_OPEN_Load_Coverage( &sp->Coverage, stream ) ) != HB_Err_Ok )
    923     return error;
    924   (void)FILE_Seek( cur_offset );
    925 
    926   switch ( sp->PosFormat )
    927   {
    928   case 1:
    929     error = Load_ValueRecord( &sp->spf.spf1.Value, format,
    930 			      base_offset, stream );
    931     if ( error )
    932       goto Fail2;
    933     break;
    934 
    935   case 2:
    936     if ( ACCESS_Frame( 2L ) )
    937       goto Fail2;
    938 
    939     count = sp->spf.spf2.ValueCount = GET_UShort();
    940 
    941     FORGET_Frame();
    942 
    943     sp->spf.spf2.Value = NULL;
    944 
    945     if ( ALLOC_ARRAY( sp->spf.spf2.Value, count, HB_ValueRecord ) )
    946       goto Fail2;
    947 
    948     vr = sp->spf.spf2.Value;
    949 
    950     for ( n = 0; n < count; n++ )
    951     {
    952       error = Load_ValueRecord( &vr[n], format, base_offset, stream );
    953       if ( error )
    954 	goto Fail1;
    955     }
    956     break;
    957 
    958   default:
    959     return ERR(HB_Err_Invalid_SubTable_Format);
    960   }
    961 
    962   return HB_Err_Ok;
    963 
    964 Fail1:
    965   for ( m = 0; m < n; m++ )
    966     Free_ValueRecord( &vr[m], format );
    967 
    968   FREE( vr );
    969 
    970 Fail2:
    971   _HB_OPEN_Free_Coverage( &sp->Coverage );
    972   return error;
    973 }
    974 
    975 
    976 static void  Free_SinglePos( HB_GPOS_SubTable* st )
    977 {
    978   HB_UShort         n, count, format;
    979   HB_SinglePos*   sp = &st->single;
    980 
    981   HB_ValueRecord*  v;
    982 
    983 
    984   format = sp->ValueFormat;
    985 
    986   switch ( sp->PosFormat )
    987   {
    988   case 1:
    989     Free_ValueRecord( &sp->spf.spf1.Value, format );
    990     break;
    991 
    992   case 2:
    993     if ( sp->spf.spf2.Value )
    994     {
    995       count = sp->spf.spf2.ValueCount;
    996       v     = sp->spf.spf2.Value;
    997 
    998       for ( n = 0; n < count; n++ )
    999 	Free_ValueRecord( &v[n], format );
   1000 
   1001       FREE( v );
   1002     }
   1003     break;
   1004   default:
   1005     break;
   1006   }
   1007 
   1008   _HB_OPEN_Free_Coverage( &sp->Coverage );
   1009 }
   1010 
   1011 static HB_Error  Lookup_SinglePos( GPOS_Instance*    gpi,
   1012 				   HB_GPOS_SubTable* st,
   1013 				   HB_Buffer        buffer,
   1014 				   HB_UShort         flags,
   1015 				   HB_UShort         context_length,
   1016 				   int               nesting_level )
   1017 {
   1018   HB_UShort        index, property;
   1019   HB_Error         error;
   1020   HB_GPOSHeader*  gpos = gpi->gpos;
   1021   HB_SinglePos*   sp = &st->single;
   1022 
   1023   HB_UNUSED(nesting_level);
   1024 
   1025   if ( context_length != 0xFFFF && context_length < 1 )
   1026     return HB_Err_Not_Covered;
   1027 
   1028   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   1029     return error;
   1030 
   1031   error = _HB_OPEN_Coverage_Index( &sp->Coverage, IN_CURGLYPH(), &index );
   1032   if ( error )
   1033     return error;
   1034 
   1035   switch ( sp->PosFormat )
   1036   {
   1037   case 1:
   1038     error = Get_ValueRecord( gpi, &sp->spf.spf1.Value,
   1039 			     sp->ValueFormat, POSITION( buffer->in_pos ) );
   1040     if ( error )
   1041       return error;
   1042     break;
   1043 
   1044   case 2:
   1045     if ( index >= sp->spf.spf2.ValueCount )
   1046       return ERR(HB_Err_Invalid_SubTable);
   1047     error = Get_ValueRecord( gpi, &sp->spf.spf2.Value[index],
   1048 			     sp->ValueFormat, POSITION( buffer->in_pos ) );
   1049     if ( error )
   1050       return error;
   1051     break;
   1052 
   1053   default:
   1054     return ERR(HB_Err_Invalid_SubTable);
   1055   }
   1056 
   1057   (buffer->in_pos)++;
   1058 
   1059   return HB_Err_Ok;
   1060 }
   1061 
   1062 
   1063 /* LookupType 2 */
   1064 
   1065 /* PairSet */
   1066 
   1067 static HB_Error  Load_PairSet ( HB_PairSet*  ps,
   1068 				HB_UShort     format1,
   1069 				HB_UShort     format2,
   1070 				HB_Stream     stream )
   1071 {
   1072   HB_Error  error;
   1073 
   1074   HB_UShort             n, m, count;
   1075   HB_UInt              base_offset;
   1076 
   1077   HB_PairValueRecord*  pvr;
   1078 
   1079 
   1080   base_offset = FILE_Pos();
   1081 
   1082   if ( ACCESS_Frame( 2L ) )
   1083     return error;
   1084 
   1085   count = ps->PairValueCount = GET_UShort();
   1086 
   1087   FORGET_Frame();
   1088 
   1089   ps->PairValueRecord = NULL;
   1090 
   1091   if ( ALLOC_ARRAY( ps->PairValueRecord, count, HB_PairValueRecord ) )
   1092     return error;
   1093 
   1094   pvr = ps->PairValueRecord;
   1095 
   1096   for ( n = 0; n < count; n++ )
   1097   {
   1098     if ( ACCESS_Frame( 2L ) )
   1099       goto Fail;
   1100 
   1101     pvr[n].SecondGlyph = GET_UShort();
   1102 
   1103     FORGET_Frame();
   1104 
   1105     if ( format1 )
   1106     {
   1107       error = Load_ValueRecord( &pvr[n].Value1, format1,
   1108 				base_offset, stream );
   1109       if ( error )
   1110 	goto Fail;
   1111     }
   1112     if ( format2 )
   1113     {
   1114       error = Load_ValueRecord( &pvr[n].Value2, format2,
   1115 				base_offset, stream );
   1116       if ( error )
   1117       {
   1118 	if ( format1 )
   1119 	  Free_ValueRecord( &pvr[n].Value1, format1 );
   1120 	goto Fail;
   1121       }
   1122     }
   1123   }
   1124 
   1125   return HB_Err_Ok;
   1126 
   1127 Fail:
   1128   for ( m = 0; m < n; m++ )
   1129   {
   1130     if ( format1 )
   1131       Free_ValueRecord( &pvr[m].Value1, format1 );
   1132     if ( format2 )
   1133       Free_ValueRecord( &pvr[m].Value2, format2 );
   1134   }
   1135 
   1136   FREE( pvr );
   1137   return error;
   1138 }
   1139 
   1140 
   1141 static void  Free_PairSet( HB_PairSet*  ps,
   1142 			   HB_UShort     format1,
   1143 			   HB_UShort     format2 )
   1144 {
   1145   HB_UShort             n, count;
   1146 
   1147   HB_PairValueRecord*  pvr;
   1148 
   1149 
   1150   if ( ps->PairValueRecord )
   1151   {
   1152     count = ps->PairValueCount;
   1153     pvr   = ps->PairValueRecord;
   1154 
   1155     for ( n = 0; n < count; n++ )
   1156     {
   1157       if ( format1 )
   1158 	Free_ValueRecord( &pvr[n].Value1, format1 );
   1159       if ( format2 )
   1160 	Free_ValueRecord( &pvr[n].Value2, format2 );
   1161     }
   1162 
   1163     FREE( pvr );
   1164   }
   1165 }
   1166 
   1167 
   1168 /* PairPosFormat1 */
   1169 
   1170 static HB_Error  Load_PairPos1( HB_PairPosFormat1*  ppf1,
   1171 				HB_UShort            format1,
   1172 				HB_UShort            format2,
   1173 				HB_Stream            stream )
   1174 {
   1175   HB_Error  error;
   1176 
   1177   HB_UShort     n, m, count;
   1178   HB_UInt      cur_offset, new_offset, base_offset;
   1179 
   1180   HB_PairSet*  ps;
   1181 
   1182 
   1183   base_offset = FILE_Pos() - 8L;
   1184 
   1185   if ( ACCESS_Frame( 2L ) )
   1186     return error;
   1187 
   1188   count = ppf1->PairSetCount = GET_UShort();
   1189 
   1190   FORGET_Frame();
   1191 
   1192   ppf1->PairSet = NULL;
   1193 
   1194   if ( ALLOC_ARRAY( ppf1->PairSet, count, HB_PairSet ) )
   1195     return error;
   1196 
   1197   ps = ppf1->PairSet;
   1198 
   1199   for ( n = 0; n < count; n++ )
   1200   {
   1201     if ( ACCESS_Frame( 2L ) )
   1202       goto Fail;
   1203 
   1204     new_offset = GET_UShort() + base_offset;
   1205 
   1206     FORGET_Frame();
   1207 
   1208     cur_offset = FILE_Pos();
   1209     if ( FILE_Seek( new_offset ) ||
   1210 	 ( error = Load_PairSet( &ps[n], format1,
   1211 				 format2, stream ) ) != HB_Err_Ok )
   1212       goto Fail;
   1213     (void)FILE_Seek( cur_offset );
   1214   }
   1215 
   1216   return HB_Err_Ok;
   1217 
   1218 Fail:
   1219   for ( m = 0; m < n; m++ )
   1220     Free_PairSet( &ps[m], format1, format2 );
   1221 
   1222   FREE( ps );
   1223   return error;
   1224 }
   1225 
   1226 
   1227 static void  Free_PairPos1( HB_PairPosFormat1*  ppf1,
   1228 			    HB_UShort            format1,
   1229 			    HB_UShort            format2 )
   1230 {
   1231   HB_UShort     n, count;
   1232 
   1233   HB_PairSet*  ps;
   1234 
   1235 
   1236   if ( ppf1->PairSet )
   1237   {
   1238     count = ppf1->PairSetCount;
   1239     ps    = ppf1->PairSet;
   1240 
   1241     for ( n = 0; n < count; n++ )
   1242       Free_PairSet( &ps[n], format1, format2 );
   1243 
   1244     FREE( ps );
   1245   }
   1246 }
   1247 
   1248 
   1249 /* PairPosFormat2 */
   1250 
   1251 static HB_Error  Load_PairPos2( HB_PairPosFormat2*  ppf2,
   1252 				HB_UShort            format1,
   1253 				HB_UShort            format2,
   1254 				HB_Stream            stream )
   1255 {
   1256   HB_Error  error;
   1257 
   1258   HB_UShort          m, n, k, count1, count2;
   1259   HB_UInt           cur_offset, new_offset1, new_offset2, base_offset;
   1260 
   1261   HB_Class1Record*  c1r;
   1262   HB_Class2Record*  c2r;
   1263 
   1264 
   1265   base_offset = FILE_Pos() - 8L;
   1266 
   1267   if ( ACCESS_Frame( 8L ) )
   1268     return error;
   1269 
   1270   new_offset1 = GET_UShort() + base_offset;
   1271   new_offset2 = GET_UShort() + base_offset;
   1272 
   1273   /* `Class1Count' and `Class2Count' are the upper limits for class
   1274      values, thus we read it now to make additional safety checks.  */
   1275 
   1276   count1 = ppf2->Class1Count = GET_UShort();
   1277   count2 = ppf2->Class2Count = GET_UShort();
   1278 
   1279   FORGET_Frame();
   1280 
   1281   cur_offset = FILE_Pos();
   1282   if ( FILE_Seek( new_offset1 ) ||
   1283        ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef1, count1,
   1284 				       stream ) ) != HB_Err_Ok )
   1285     return error;
   1286   if ( FILE_Seek( new_offset2 ) ||
   1287        ( error = _HB_OPEN_Load_ClassDefinition( &ppf2->ClassDef2, count2,
   1288 				       stream ) ) != HB_Err_Ok )
   1289     goto Fail3;
   1290   (void)FILE_Seek( cur_offset );
   1291 
   1292   ppf2->Class1Record = NULL;
   1293 
   1294   if ( ALLOC_ARRAY( ppf2->Class1Record, count1, HB_Class1Record ) )
   1295     goto Fail2;
   1296 
   1297   c1r = ppf2->Class1Record;
   1298 
   1299   for ( m = 0; m < count1; m++ )
   1300   {
   1301     c1r[m].Class2Record = NULL;
   1302 
   1303     if ( ALLOC_ARRAY( c1r[m].Class2Record, count2, HB_Class2Record ) )
   1304       goto Fail1;
   1305 
   1306     c2r = c1r[m].Class2Record;
   1307 
   1308     for ( n = 0; n < count2; n++ )
   1309     {
   1310       if ( format1 )
   1311       {
   1312 	error = Load_ValueRecord( &c2r[n].Value1, format1,
   1313 				  base_offset, stream );
   1314 	if ( error )
   1315 	  goto Fail0;
   1316       }
   1317       if ( format2 )
   1318       {
   1319 	error = Load_ValueRecord( &c2r[n].Value2, format2,
   1320 				  base_offset, stream );
   1321 	if ( error )
   1322 	{
   1323 	  if ( format1 )
   1324 	    Free_ValueRecord( &c2r[n].Value1, format1 );
   1325 	  goto Fail0;
   1326 	}
   1327       }
   1328     }
   1329 
   1330     continue;
   1331 
   1332   Fail0:
   1333     for ( k = 0; k < n; k++ )
   1334     {
   1335       if ( format1 )
   1336 	Free_ValueRecord( &c2r[k].Value1, format1 );
   1337       if ( format2 )
   1338 	Free_ValueRecord( &c2r[k].Value2, format2 );
   1339     }
   1340     goto Fail1;
   1341   }
   1342 
   1343   return HB_Err_Ok;
   1344 
   1345 Fail1:
   1346   for ( k = 0; k < m; k++ )
   1347   {
   1348     c2r = c1r[k].Class2Record;
   1349 
   1350     for ( n = 0; n < count2; n++ )
   1351     {
   1352       if ( format1 )
   1353 	Free_ValueRecord( &c2r[n].Value1, format1 );
   1354       if ( format2 )
   1355 	Free_ValueRecord( &c2r[n].Value2, format2 );
   1356     }
   1357 
   1358     FREE( c2r );
   1359   }
   1360 
   1361   FREE( c1r );
   1362 Fail2:
   1363 
   1364   _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
   1365 
   1366 Fail3:
   1367   _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
   1368   return error;
   1369 }
   1370 
   1371 
   1372 static void  Free_PairPos2( HB_PairPosFormat2*  ppf2,
   1373 			    HB_UShort            format1,
   1374 			    HB_UShort            format2)
   1375 {
   1376   HB_UShort          m, n, count1, count2;
   1377 
   1378   HB_Class1Record*  c1r;
   1379   HB_Class2Record*  c2r;
   1380 
   1381 
   1382   if ( ppf2->Class1Record )
   1383   {
   1384     c1r    = ppf2->Class1Record;
   1385     count1 = ppf2->Class1Count;
   1386     count2 = ppf2->Class2Count;
   1387 
   1388     for ( m = 0; m < count1; m++ )
   1389     {
   1390       c2r = c1r[m].Class2Record;
   1391 
   1392       for ( n = 0; n < count2; n++ )
   1393       {
   1394 	if ( format1 )
   1395 	  Free_ValueRecord( &c2r[n].Value1, format1 );
   1396 	if ( format2 )
   1397 	  Free_ValueRecord( &c2r[n].Value2, format2 );
   1398       }
   1399 
   1400       FREE( c2r );
   1401     }
   1402 
   1403     FREE( c1r );
   1404 
   1405     _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef2 );
   1406     _HB_OPEN_Free_ClassDefinition( &ppf2->ClassDef1 );
   1407   }
   1408 }
   1409 
   1410 
   1411 static HB_Error  Load_PairPos( HB_GPOS_SubTable* st,
   1412 			       HB_Stream     stream )
   1413 {
   1414   HB_Error  error;
   1415   HB_PairPos*     pp = &st->pair;
   1416 
   1417   HB_UShort         format1, format2;
   1418   HB_UInt          cur_offset, new_offset, base_offset;
   1419 
   1420 
   1421   base_offset = FILE_Pos();
   1422 
   1423   if ( ACCESS_Frame( 8L ) )
   1424     return error;
   1425 
   1426   pp->PosFormat = GET_UShort();
   1427   new_offset    = GET_UShort() + base_offset;
   1428 
   1429   format1 = pp->ValueFormat1 = GET_UShort();
   1430   format2 = pp->ValueFormat2 = GET_UShort();
   1431 
   1432   FORGET_Frame();
   1433 
   1434   cur_offset = FILE_Pos();
   1435   if ( FILE_Seek( new_offset ) ||
   1436        ( error = _HB_OPEN_Load_Coverage( &pp->Coverage, stream ) ) != HB_Err_Ok )
   1437     return error;
   1438   (void)FILE_Seek( cur_offset );
   1439 
   1440   switch ( pp->PosFormat )
   1441   {
   1442   case 1:
   1443     error = Load_PairPos1( &pp->ppf.ppf1, format1, format2, stream );
   1444     if ( error )
   1445       goto Fail;
   1446     break;
   1447 
   1448   case 2:
   1449     error = Load_PairPos2( &pp->ppf.ppf2, format1, format2, stream );
   1450     if ( error )
   1451       goto Fail;
   1452     break;
   1453 
   1454   default:
   1455     return ERR(HB_Err_Invalid_SubTable_Format);
   1456   }
   1457 
   1458   return HB_Err_Ok;
   1459 
   1460 Fail:
   1461   _HB_OPEN_Free_Coverage( &pp->Coverage );
   1462   return error;
   1463 }
   1464 
   1465 
   1466 static void  Free_PairPos( HB_GPOS_SubTable* st )
   1467 {
   1468   HB_UShort  format1, format2;
   1469   HB_PairPos*     pp = &st->pair;
   1470 
   1471 
   1472   format1 = pp->ValueFormat1;
   1473   format2 = pp->ValueFormat2;
   1474 
   1475   switch ( pp->PosFormat )
   1476   {
   1477   case 1:
   1478     Free_PairPos1( &pp->ppf.ppf1, format1, format2 );
   1479     break;
   1480 
   1481   case 2:
   1482     Free_PairPos2( &pp->ppf.ppf2, format1, format2 );
   1483     break;
   1484 
   1485   default:
   1486     break;
   1487   }
   1488 
   1489   _HB_OPEN_Free_Coverage( &pp->Coverage );
   1490 }
   1491 
   1492 
   1493 static HB_Error  Lookup_PairPos1( GPOS_Instance*       gpi,
   1494 				  HB_PairPosFormat1*  ppf1,
   1495 				  HB_Buffer           buffer,
   1496 				  HB_UInt              first_pos,
   1497 				  HB_UShort            index,
   1498 				  HB_UShort            format1,
   1499 				  HB_UShort            format2 )
   1500 {
   1501   HB_Error              error;
   1502   HB_UShort             numpvr, glyph2;
   1503 
   1504   HB_PairValueRecord*  pvr;
   1505 
   1506 
   1507   if ( index >= ppf1->PairSetCount )
   1508      return ERR(HB_Err_Invalid_SubTable);
   1509 
   1510   pvr = ppf1->PairSet[index].PairValueRecord;
   1511   if ( !pvr )
   1512     return ERR(HB_Err_Invalid_SubTable);
   1513 
   1514   glyph2 = IN_CURGLYPH();
   1515 
   1516   for ( numpvr = ppf1->PairSet[index].PairValueCount;
   1517 	numpvr;
   1518 	numpvr--, pvr++ )
   1519   {
   1520     if ( glyph2 == pvr->SecondGlyph )
   1521     {
   1522       error = Get_ValueRecord( gpi, &pvr->Value1, format1,
   1523 			       POSITION( first_pos ) );
   1524       if ( error )
   1525 	return error;
   1526       return Get_ValueRecord( gpi, &pvr->Value2, format2,
   1527 			      POSITION( buffer->in_pos ) );
   1528     }
   1529   }
   1530 
   1531   return HB_Err_Not_Covered;
   1532 }
   1533 
   1534 
   1535 static HB_Error  Lookup_PairPos2( GPOS_Instance*       gpi,
   1536 				  HB_PairPosFormat2*  ppf2,
   1537 				  HB_Buffer           buffer,
   1538 				  HB_UInt              first_pos,
   1539 				  HB_UShort            format1,
   1540 				  HB_UShort            format2 )
   1541 {
   1542   HB_Error           error;
   1543   HB_UShort          cl1 = 0, cl2 = 0; /* shut compiler up */
   1544 
   1545   HB_Class1Record*  c1r;
   1546   HB_Class2Record*  c2r;
   1547 
   1548 
   1549   error = _HB_OPEN_Get_Class( &ppf2->ClassDef1, IN_GLYPH( first_pos ),
   1550 		     &cl1, NULL );
   1551   if ( error && error != HB_Err_Not_Covered )
   1552     return error;
   1553   error = _HB_OPEN_Get_Class( &ppf2->ClassDef2, IN_CURGLYPH(),
   1554 		     &cl2, NULL );
   1555   if ( error && error != HB_Err_Not_Covered )
   1556     return error;
   1557 
   1558   c1r = &ppf2->Class1Record[cl1];
   1559   if ( !c1r )
   1560     return ERR(HB_Err_Invalid_SubTable);
   1561   c2r = &c1r->Class2Record[cl2];
   1562 
   1563   error = Get_ValueRecord( gpi, &c2r->Value1, format1, POSITION( first_pos ) );
   1564   if ( error )
   1565     return error;
   1566   return Get_ValueRecord( gpi, &c2r->Value2, format2, POSITION( buffer->in_pos ) );
   1567 }
   1568 
   1569 
   1570 static HB_Error  Lookup_PairPos( GPOS_Instance*    gpi,
   1571 				 HB_GPOS_SubTable* st,
   1572 				 HB_Buffer        buffer,
   1573 				 HB_UShort         flags,
   1574 				 HB_UShort         context_length,
   1575 				 int               nesting_level )
   1576 {
   1577   HB_Error         error;
   1578   HB_UShort        index, property;
   1579   HB_UInt          first_pos;
   1580   HB_GPOSHeader*  gpos = gpi->gpos;
   1581   HB_PairPos*     pp = &st->pair;
   1582 
   1583   HB_UNUSED(nesting_level);
   1584 
   1585   if ( buffer->in_pos >= buffer->in_length - 1 )
   1586     return HB_Err_Not_Covered;           /* Not enough glyphs in stream */
   1587 
   1588   if ( context_length != 0xFFFF && context_length < 2 )
   1589     return HB_Err_Not_Covered;
   1590 
   1591   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   1592     return error;
   1593 
   1594   error = _HB_OPEN_Coverage_Index( &pp->Coverage, IN_CURGLYPH(), &index );
   1595   if ( error )
   1596     return error;
   1597 
   1598   /* second glyph */
   1599 
   1600   first_pos = buffer->in_pos;
   1601   (buffer->in_pos)++;
   1602 
   1603   while ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   1604 			  flags, &property ) )
   1605   {
   1606     if ( error && error != HB_Err_Not_Covered )
   1607       return error;
   1608 
   1609     if ( buffer->in_pos == buffer->in_length )
   1610       {
   1611 	buffer->in_pos = first_pos;
   1612         return HB_Err_Not_Covered;
   1613       }
   1614     (buffer->in_pos)++;
   1615 
   1616   }
   1617 
   1618   switch ( pp->PosFormat )
   1619   {
   1620   case 1:
   1621     error = Lookup_PairPos1( gpi, &pp->ppf.ppf1, buffer,
   1622 			     first_pos, index,
   1623 			     pp->ValueFormat1, pp->ValueFormat2 );
   1624     break;
   1625 
   1626   case 2:
   1627     error = Lookup_PairPos2( gpi, &pp->ppf.ppf2, buffer, first_pos,
   1628 			     pp->ValueFormat1, pp->ValueFormat2 );
   1629     break;
   1630 
   1631   default:
   1632     return ERR(HB_Err_Invalid_SubTable_Format);
   1633   }
   1634 
   1635   /* if we don't have coverage for the second glyph don't skip it for
   1636      further lookups but reset in_pos back to the first_glyph and let
   1637      the caller in Do_String_Lookup increment in_pos */
   1638   if ( error == HB_Err_Not_Covered )
   1639       buffer->in_pos = first_pos;
   1640 
   1641   /* adjusting the `next' glyph */
   1642 
   1643   if ( pp->ValueFormat2 )
   1644     (buffer->in_pos)++;
   1645 
   1646   return error;
   1647 }
   1648 
   1649 
   1650 /* LookupType 3 */
   1651 
   1652 /* CursivePosFormat1 */
   1653 
   1654 static HB_Error  Load_CursivePos( HB_GPOS_SubTable* st,
   1655 				  HB_Stream        stream )
   1656 {
   1657   HB_Error  error;
   1658   HB_CursivePos*  cp = &st->cursive;
   1659 
   1660   HB_UShort             n, m, count;
   1661   HB_UInt              cur_offset, new_offset, base_offset;
   1662 
   1663   HB_EntryExitRecord*  eer;
   1664 
   1665 
   1666   base_offset = FILE_Pos();
   1667 
   1668   if ( ACCESS_Frame( 4L ) )
   1669     return error;
   1670 
   1671   cp->PosFormat = GET_UShort();
   1672   new_offset    = GET_UShort() + base_offset;
   1673 
   1674   FORGET_Frame();
   1675 
   1676   cur_offset = FILE_Pos();
   1677   if ( FILE_Seek( new_offset ) ||
   1678        ( error = _HB_OPEN_Load_Coverage( &cp->Coverage, stream ) ) != HB_Err_Ok )
   1679     return error;
   1680   (void)FILE_Seek( cur_offset );
   1681 
   1682   if ( ACCESS_Frame( 2L ) )
   1683     goto Fail2;
   1684 
   1685   count = cp->EntryExitCount = GET_UShort();
   1686 
   1687   FORGET_Frame();
   1688 
   1689   cp->EntryExitRecord = NULL;
   1690 
   1691   if ( ALLOC_ARRAY( cp->EntryExitRecord, count, HB_EntryExitRecord ) )
   1692     goto Fail2;
   1693 
   1694   eer = cp->EntryExitRecord;
   1695 
   1696   for ( n = 0; n < count; n++ )
   1697   {
   1698     HB_UInt entry_offset;
   1699 
   1700     if ( ACCESS_Frame( 2L ) )
   1701       return error;
   1702 
   1703     entry_offset = new_offset = GET_UShort();
   1704 
   1705     FORGET_Frame();
   1706 
   1707     if ( new_offset )
   1708     {
   1709       new_offset += base_offset;
   1710 
   1711       cur_offset = FILE_Pos();
   1712       if ( FILE_Seek( new_offset ) ||
   1713 	   ( error = Load_Anchor( &eer[n].EntryAnchor,
   1714 				  stream ) ) != HB_Err_Ok )
   1715 	goto Fail1;
   1716       (void)FILE_Seek( cur_offset );
   1717     }
   1718     else
   1719       eer[n].EntryAnchor.PosFormat   = 0;
   1720 
   1721     if ( ACCESS_Frame( 2L ) )
   1722       return error;
   1723 
   1724     new_offset = GET_UShort();
   1725 
   1726     FORGET_Frame();
   1727 
   1728     if ( new_offset )
   1729     {
   1730       new_offset += base_offset;
   1731 
   1732       cur_offset = FILE_Pos();
   1733       if ( FILE_Seek( new_offset ) ||
   1734 	   ( error = Load_Anchor( &eer[n].ExitAnchor,
   1735 				  stream ) ) != HB_Err_Ok )
   1736       {
   1737 	if ( entry_offset )
   1738 	  Free_Anchor( &eer[n].EntryAnchor );
   1739 	goto Fail1;
   1740       }
   1741       (void)FILE_Seek( cur_offset );
   1742     }
   1743     else
   1744       eer[n].ExitAnchor.PosFormat   = 0;
   1745   }
   1746 
   1747   return HB_Err_Ok;
   1748 
   1749 Fail1:
   1750   for ( m = 0; m < n; m++ )
   1751   {
   1752     Free_Anchor( &eer[m].EntryAnchor );
   1753     Free_Anchor( &eer[m].ExitAnchor );
   1754   }
   1755 
   1756   FREE( eer );
   1757 
   1758 Fail2:
   1759   _HB_OPEN_Free_Coverage( &cp->Coverage );
   1760   return error;
   1761 }
   1762 
   1763 
   1764 static void  Free_CursivePos( HB_GPOS_SubTable* st )
   1765 {
   1766   HB_UShort             n, count;
   1767   HB_CursivePos*  cp = &st->cursive;
   1768 
   1769   HB_EntryExitRecord*  eer;
   1770 
   1771 
   1772   if ( cp->EntryExitRecord )
   1773   {
   1774     count = cp->EntryExitCount;
   1775     eer   = cp->EntryExitRecord;
   1776 
   1777     for ( n = 0; n < count; n++ )
   1778     {
   1779       Free_Anchor( &eer[n].EntryAnchor );
   1780       Free_Anchor( &eer[n].ExitAnchor );
   1781     }
   1782 
   1783     FREE( eer );
   1784   }
   1785 
   1786   _HB_OPEN_Free_Coverage( &cp->Coverage );
   1787 }
   1788 
   1789 
   1790 static HB_Error  Lookup_CursivePos( GPOS_Instance*    gpi,
   1791 				    HB_GPOS_SubTable* st,
   1792 				    HB_Buffer        buffer,
   1793 				    HB_UShort         flags,
   1794 				    HB_UShort         context_length,
   1795 				    int               nesting_level )
   1796 {
   1797   HB_UShort        index, property;
   1798   HB_Error         error;
   1799   HB_GPOSHeader*  gpos = gpi->gpos;
   1800   HB_CursivePos*  cp = &st->cursive;
   1801 
   1802   HB_EntryExitRecord*  eer;
   1803   HB_Fixed                entry_x, entry_y;
   1804   HB_Fixed                exit_x, exit_y;
   1805 
   1806   HB_UNUSED(nesting_level);
   1807 
   1808   if ( context_length != 0xFFFF && context_length < 1 )
   1809   {
   1810     gpi->last = 0xFFFF;
   1811     return HB_Err_Not_Covered;
   1812   }
   1813 
   1814   /* Glyphs not having the right GDEF properties will be ignored, i.e.,
   1815      gpi->last won't be reset (contrary to user defined properties). */
   1816 
   1817   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   1818     return error;
   1819 
   1820   /* We don't handle mark glyphs here.  According to Andrei, this isn't
   1821      possible, but who knows...                                         */
   1822 
   1823   if ( property == HB_GDEF_MARK )
   1824   {
   1825     gpi->last = 0xFFFF;
   1826     return HB_Err_Not_Covered;
   1827   }
   1828 
   1829   error = _HB_OPEN_Coverage_Index( &cp->Coverage, IN_CURGLYPH(), &index );
   1830   if ( error )
   1831   {
   1832     gpi->last = 0xFFFF;
   1833     return error;
   1834   }
   1835 
   1836   if ( index >= cp->EntryExitCount )
   1837     return ERR(HB_Err_Invalid_SubTable);
   1838 
   1839   eer = &cp->EntryExitRecord[index];
   1840 
   1841   /* Now comes the messiest part of the whole OpenType
   1842      specification.  At first glance, cursive connections seem easy
   1843      to understand, but there are pitfalls!  The reason is that
   1844      the specs don't mention how to compute the advance values
   1845      resp. glyph offsets.  I was told it would be an omission, to
   1846      be fixed in the next OpenType version...  Again many thanks to
   1847      Andrei Burago <andreib (at) microsoft.com> for clarifications.
   1848 
   1849      Consider the following example:
   1850 
   1851 		      |  xadv1    |
   1852 		       +---------+
   1853 		       |         |
   1854 		 +-----+--+ 1    |
   1855 		 |     | .|      |
   1856 		 |    0+--+------+
   1857 		 |   2    |
   1858 		 |        |
   1859 		0+--------+
   1860 		|  xadv2   |
   1861 
   1862        glyph1: advance width = 12
   1863 	       anchor point = (3,1)
   1864 
   1865        glyph2: advance width = 11
   1866 	       anchor point = (9,4)
   1867 
   1868        LSB is 1 for both glyphs (so the boxes drawn above are glyph
   1869        bboxes).  Writing direction is R2L; `0' denotes the glyph's
   1870        coordinate origin.
   1871 
   1872      Now the surprising part: The advance width of the *left* glyph
   1873      (resp. of the *bottom* glyph) will be modified, no matter
   1874      whether the writing direction is L2R or R2L (resp. T2B or
   1875      B2T)!  This assymetry is caused by the fact that the glyph's
   1876      coordinate origin is always the lower left corner for all
   1877      writing directions.
   1878 
   1879      Continuing the above example, we can compute the new
   1880      (horizontal) advance width of glyph2 as
   1881 
   1882        9 - 3 = 6  ,
   1883 
   1884      and the new vertical offset of glyph2 as
   1885 
   1886        1 - 4 = -3  .
   1887 
   1888 
   1889      Vertical writing direction is far more complicated:
   1890 
   1891      a) Assuming that we recompute the advance height of the lower glyph:
   1892 
   1893 				  --
   1894 		       +---------+
   1895 	      --       |         |
   1896 		 +-----+--+ 1    | yadv1
   1897 		 |     | .|      |
   1898 	   yadv2 |    0+--+------+        -- BSB1  --
   1899 		 |   2    |       --      --        y_offset
   1900 		 |        |
   1901    BSB2 --      0+--------+                        --
   1902 	--    --
   1903 
   1904        glyph1: advance height = 6
   1905 	       anchor point = (3,1)
   1906 
   1907        glyph2: advance height = 7
   1908 	       anchor point = (9,4)
   1909 
   1910        TSB is 1 for both glyphs; writing direction is T2B.
   1911 
   1912 
   1913 	 BSB1     = yadv1 - (TSB1 + ymax1)
   1914 	 BSB2     = yadv2 - (TSB2 + ymax2)
   1915 	 y_offset = y2 - y1
   1916 
   1917        vertical advance width of glyph2
   1918 	 = y_offset + BSB2 - BSB1
   1919 	 = (y2 - y1) + (yadv2 - (TSB2 + ymax2)) - (yadv1 - (TSB1 + ymax1))
   1920 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - (yadv1 - TSB1 - ymax1)
   1921 	 = y2 - y1 + yadv2 - TSB2 - ymax2 - yadv1 + TSB1 + ymax1
   1922 
   1923 
   1924      b) Assuming that we recompute the advance height of the upper glyph:
   1925 
   1926 				  --      --
   1927 		       +---------+        -- TSB1
   1928 	--    --       |         |
   1929    TSB2 --       +-----+--+ 1    | yadv1   ymax1
   1930 		 |     | .|      |
   1931 	   yadv2 |    0+--+------+        --       --
   1932     ymax2        |   2    |       --                y_offset
   1933 		 |        |
   1934 	--      0+--------+                        --
   1935 	      --
   1936 
   1937        glyph1: advance height = 6
   1938 	       anchor point = (3,1)
   1939 
   1940        glyph2: advance height = 7
   1941 	       anchor point = (9,4)
   1942 
   1943        TSB is 1 for both glyphs; writing direction is T2B.
   1944 
   1945        y_offset = y2 - y1
   1946 
   1947        vertical advance width of glyph2
   1948 	 = TSB1 + ymax1 + y_offset - (TSB2 + ymax2)
   1949 	 = TSB1 + ymax1 + y2 - y1 - TSB2 - ymax2
   1950 
   1951 
   1952      Comparing a) with b) shows that b) is easier to compute.  I'll wait
   1953      for a reply from Andrei to see what should really be implemented...
   1954 
   1955      Since horizontal advance widths or vertical advance heights
   1956      can be used alone but not together, no ambiguity occurs.        */
   1957 
   1958   if ( gpi->last == 0xFFFF )
   1959     goto end;
   1960 
   1961   /* Get_Anchor() returns HB_Err_Not_Covered if there is no anchor
   1962      table.                                                         */
   1963 
   1964   error = Get_Anchor( gpi, &eer->EntryAnchor, IN_CURGLYPH(),
   1965 		      &entry_x, &entry_y );
   1966   if ( error == HB_Err_Not_Covered )
   1967     goto end;
   1968   if ( error )
   1969     return error;
   1970 
   1971   if ( gpi->r2l )
   1972   {
   1973     POSITION( buffer->in_pos )->x_advance   = entry_x - gpi->anchor_x;
   1974     POSITION( buffer->in_pos )->new_advance = TRUE;
   1975   }
   1976   else
   1977   {
   1978     POSITION( gpi->last )->x_advance   = gpi->anchor_x - entry_x;
   1979     POSITION( gpi->last )->new_advance = TRUE;
   1980   }
   1981 
   1982   if ( flags & HB_LOOKUP_FLAG_RIGHT_TO_LEFT )
   1983   {
   1984     POSITION( gpi->last )->cursive_chain = gpi->last - buffer->in_pos;
   1985     POSITION( gpi->last )->y_pos = entry_y - gpi->anchor_y;
   1986   }
   1987   else
   1988   {
   1989     POSITION( buffer->in_pos )->cursive_chain = buffer->in_pos - gpi->last;
   1990     POSITION( buffer->in_pos )->y_pos = gpi->anchor_y - entry_y;
   1991   }
   1992 
   1993 end:
   1994   error = Get_Anchor( gpi, &eer->ExitAnchor, IN_CURGLYPH(),
   1995 		      &exit_x, &exit_y );
   1996   if ( error == HB_Err_Not_Covered )
   1997     gpi->last = 0xFFFF;
   1998   else
   1999   {
   2000     gpi->last     = buffer->in_pos;
   2001     gpi->anchor_x = exit_x;
   2002     gpi->anchor_y = exit_y;
   2003   }
   2004   if ( error )
   2005     return error;
   2006 
   2007   (buffer->in_pos)++;
   2008 
   2009   return HB_Err_Ok;
   2010 }
   2011 
   2012 
   2013 /* LookupType 4 */
   2014 
   2015 /* BaseArray */
   2016 
   2017 static HB_Error  Load_BaseArray( HB_BaseArray*  ba,
   2018 				 HB_UShort       num_classes,
   2019 				 HB_Stream       stream )
   2020 {
   2021   HB_Error  error;
   2022 
   2023   HB_UShort       m, n, count;
   2024   HB_UInt         cur_offset, new_offset, base_offset;
   2025 
   2026   HB_BaseRecord  *br;
   2027   HB_Anchor      *ban, *bans;
   2028 
   2029 
   2030   base_offset = FILE_Pos();
   2031 
   2032   if ( ACCESS_Frame( 2L ) )
   2033     return error;
   2034 
   2035   count = ba->BaseCount = GET_UShort();
   2036 
   2037   FORGET_Frame();
   2038 
   2039   ba->BaseRecord = NULL;
   2040 
   2041   if ( ALLOC_ARRAY( ba->BaseRecord, count, HB_BaseRecord ) )
   2042     return error;
   2043 
   2044   br = ba->BaseRecord;
   2045 
   2046   bans = NULL;
   2047 
   2048   if ( ALLOC_ARRAY( bans, count * num_classes, HB_Anchor ) )
   2049     goto Fail;
   2050 
   2051   for ( m = 0; m < count; m++ )
   2052   {
   2053     br[m].BaseAnchor = NULL;
   2054 
   2055     ban = br[m].BaseAnchor = bans + m * num_classes;
   2056 
   2057     for ( n = 0; n < num_classes; n++ )
   2058     {
   2059       if ( ACCESS_Frame( 2L ) )
   2060 	goto Fail;
   2061 
   2062       new_offset = GET_UShort() + base_offset;
   2063 
   2064       FORGET_Frame();
   2065 
   2066       if (new_offset == base_offset) {
   2067 	/* XXX
   2068 	 * Doulos SIL Regular is buggy and has zero offsets here.
   2069 	 * Skip it
   2070 	 */
   2071 	ban[n].PosFormat = 0;
   2072 	continue;
   2073       }
   2074 
   2075       cur_offset = FILE_Pos();
   2076       if ( FILE_Seek( new_offset ) ||
   2077 	   ( error = Load_Anchor( &ban[n], stream ) ) != HB_Err_Ok )
   2078 	goto Fail;
   2079       (void)FILE_Seek( cur_offset );
   2080     }
   2081   }
   2082 
   2083   return HB_Err_Ok;
   2084 
   2085 Fail:
   2086   FREE( bans );
   2087   FREE( br );
   2088   return error;
   2089 }
   2090 
   2091 
   2092 static void  Free_BaseArray( HB_BaseArray*  ba,
   2093 			     HB_UShort       num_classes )
   2094 {
   2095   HB_BaseRecord  *br;
   2096   HB_Anchor      *bans;
   2097 
   2098   if ( ba->BaseRecord )
   2099   {
   2100     br    = ba->BaseRecord;
   2101 
   2102     if ( ba->BaseCount )
   2103     {
   2104       HB_UShort i, count;
   2105       count = num_classes * ba->BaseCount;
   2106       bans = br[0].BaseAnchor;
   2107       for (i = 0; i < count; i++)
   2108         Free_Anchor (&bans[i]);
   2109       FREE( bans );
   2110     }
   2111 
   2112     FREE( br );
   2113   }
   2114 }
   2115 
   2116 
   2117 /* MarkBasePosFormat1 */
   2118 
   2119 static HB_Error  Load_MarkBasePos( HB_GPOS_SubTable* st,
   2120 				   HB_Stream         stream )
   2121 {
   2122   HB_Error  error;
   2123   HB_MarkBasePos* mbp = &st->markbase;
   2124 
   2125   HB_UInt  cur_offset, new_offset, base_offset;
   2126 
   2127 
   2128   base_offset = FILE_Pos();
   2129 
   2130   if ( ACCESS_Frame( 4L ) )
   2131     return error;
   2132 
   2133   mbp->PosFormat = GET_UShort();
   2134   new_offset     = GET_UShort() + base_offset;
   2135 
   2136   FORGET_Frame();
   2137 
   2138   if (mbp->PosFormat != 1)
   2139     return ERR(HB_Err_Invalid_SubTable_Format);
   2140 
   2141   cur_offset = FILE_Pos();
   2142   if ( FILE_Seek( new_offset ) ||
   2143        ( error = _HB_OPEN_Load_Coverage( &mbp->MarkCoverage, stream ) ) != HB_Err_Ok )
   2144     return error;
   2145   (void)FILE_Seek( cur_offset );
   2146 
   2147   if ( ACCESS_Frame( 2L ) )
   2148     goto Fail3;
   2149 
   2150   new_offset = GET_UShort() + base_offset;
   2151 
   2152   FORGET_Frame();
   2153 
   2154   cur_offset = FILE_Pos();
   2155   if ( FILE_Seek( new_offset ) ||
   2156        ( error = _HB_OPEN_Load_Coverage( &mbp->BaseCoverage, stream ) ) != HB_Err_Ok )
   2157     goto Fail3;
   2158   (void)FILE_Seek( cur_offset );
   2159 
   2160   if ( ACCESS_Frame( 4L ) )
   2161     goto Fail2;
   2162 
   2163   mbp->ClassCount = GET_UShort();
   2164   new_offset      = GET_UShort() + base_offset;
   2165 
   2166   FORGET_Frame();
   2167 
   2168   cur_offset = FILE_Pos();
   2169   if ( FILE_Seek( new_offset ) ||
   2170        ( error = Load_MarkArray( &mbp->MarkArray, stream ) ) != HB_Err_Ok )
   2171     goto Fail2;
   2172   (void)FILE_Seek( cur_offset );
   2173 
   2174   if ( ACCESS_Frame( 2L ) )
   2175     goto Fail1;
   2176 
   2177   new_offset = GET_UShort() + base_offset;
   2178 
   2179   FORGET_Frame();
   2180 
   2181   cur_offset = FILE_Pos();
   2182   if ( FILE_Seek( new_offset ) ||
   2183        ( error = Load_BaseArray( &mbp->BaseArray, mbp->ClassCount,
   2184 				 stream ) ) != HB_Err_Ok )
   2185     goto Fail1;
   2186 
   2187   return HB_Err_Ok;
   2188 
   2189 Fail1:
   2190   Free_MarkArray( &mbp->MarkArray );
   2191 
   2192 Fail2:
   2193   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
   2194 
   2195 Fail3:
   2196   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
   2197   return error;
   2198 }
   2199 
   2200 
   2201 static void  Free_MarkBasePos( HB_GPOS_SubTable* st )
   2202 {
   2203   HB_MarkBasePos* mbp = &st->markbase;
   2204 
   2205   Free_BaseArray( &mbp->BaseArray, mbp->ClassCount );
   2206   Free_MarkArray( &mbp->MarkArray );
   2207   _HB_OPEN_Free_Coverage( &mbp->BaseCoverage );
   2208   _HB_OPEN_Free_Coverage( &mbp->MarkCoverage );
   2209 }
   2210 
   2211 
   2212 static HB_Error  Lookup_MarkBasePos( GPOS_Instance*    gpi,
   2213 				     HB_GPOS_SubTable* st,
   2214 				     HB_Buffer        buffer,
   2215 				     HB_UShort         flags,
   2216 				     HB_UShort         context_length,
   2217 				     int               nesting_level )
   2218 {
   2219   HB_UShort        i, j, mark_index, base_index, property, class;
   2220   HB_Fixed           x_mark_value, y_mark_value, x_base_value, y_base_value;
   2221   HB_Error         error;
   2222   HB_GPOSHeader*  gpos = gpi->gpos;
   2223   HB_MarkBasePos* mbp = &st->markbase;
   2224 
   2225   HB_MarkArray*   ma;
   2226   HB_BaseArray*   ba;
   2227   HB_BaseRecord*  br;
   2228   HB_Anchor*      mark_anchor;
   2229   HB_Anchor*      base_anchor;
   2230 
   2231   HB_Position     o;
   2232 
   2233   HB_UNUSED(nesting_level);
   2234 
   2235   if ( context_length != 0xFFFF && context_length < 1 )
   2236     return HB_Err_Not_Covered;
   2237 
   2238   if ( flags & HB_LOOKUP_FLAG_IGNORE_BASE_GLYPHS )
   2239     return HB_Err_Not_Covered;
   2240 
   2241   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   2242 		       flags, &property ) )
   2243     return error;
   2244 
   2245   error = _HB_OPEN_Coverage_Index( &mbp->MarkCoverage, IN_CURGLYPH(),
   2246 			  &mark_index );
   2247   if ( error )
   2248     return error;
   2249 
   2250   /* now we search backwards for a non-mark glyph */
   2251 
   2252   i = 1;
   2253   j = buffer->in_pos - 1;
   2254 
   2255   while ( i <= buffer->in_pos )
   2256   {
   2257     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2258 					&property );
   2259     if ( error )
   2260       return error;
   2261 
   2262     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   2263       break;
   2264 
   2265     i++;
   2266     j--;
   2267   }
   2268 
   2269   /* The following assertion is too strong -- at least for mangal.ttf. */
   2270 #if 0
   2271   if ( property != HB_GDEF_BASE_GLYPH )
   2272     return HB_Err_Not_Covered;
   2273 #endif
   2274 
   2275   if ( i > buffer->in_pos )
   2276     return HB_Err_Not_Covered;
   2277 
   2278   error = _HB_OPEN_Coverage_Index( &mbp->BaseCoverage, IN_GLYPH( j ),
   2279 			  &base_index );
   2280   if ( error )
   2281     return error;
   2282 
   2283   ma = &mbp->MarkArray;
   2284 
   2285   if ( mark_index >= ma->MarkCount )
   2286     return ERR(HB_Err_Invalid_SubTable);
   2287 
   2288   class       = ma->MarkRecord[mark_index].Class;
   2289   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
   2290 
   2291   if ( class >= mbp->ClassCount )
   2292     return ERR(HB_Err_Invalid_SubTable);
   2293 
   2294   ba = &mbp->BaseArray;
   2295 
   2296   if ( base_index >= ba->BaseCount )
   2297     return ERR(HB_Err_Invalid_SubTable);
   2298 
   2299   br          = &ba->BaseRecord[base_index];
   2300   base_anchor = &br->BaseAnchor[class];
   2301 
   2302   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
   2303 		      &x_mark_value, &y_mark_value );
   2304   if ( error )
   2305     return error;
   2306 
   2307   error = Get_Anchor( gpi, base_anchor, IN_GLYPH( j ),
   2308 		      &x_base_value, &y_base_value );
   2309   if ( error )
   2310     return error;
   2311 
   2312   /* anchor points are not cumulative */
   2313 
   2314   o = POSITION( buffer->in_pos );
   2315 
   2316   o->x_pos     = x_base_value - x_mark_value;
   2317   o->y_pos     = y_base_value - y_mark_value;
   2318   o->x_advance = 0;
   2319   o->y_advance = 0;
   2320   o->back      = i;
   2321 
   2322   (buffer->in_pos)++;
   2323 
   2324   return HB_Err_Ok;
   2325 }
   2326 
   2327 
   2328 /* LookupType 5 */
   2329 
   2330 /* LigatureAttach */
   2331 
   2332 static HB_Error  Load_LigatureAttach( HB_LigatureAttach*  lat,
   2333 				      HB_UShort            num_classes,
   2334 				      HB_Stream            stream )
   2335 {
   2336   HB_Error  error;
   2337 
   2338   HB_UShort             m, n, k, count;
   2339   HB_UInt              cur_offset, new_offset, base_offset;
   2340 
   2341   HB_ComponentRecord*  cr;
   2342   HB_Anchor*           lan;
   2343 
   2344 
   2345   base_offset = FILE_Pos();
   2346 
   2347   if ( ACCESS_Frame( 2L ) )
   2348     return error;
   2349 
   2350   count = lat->ComponentCount = GET_UShort();
   2351 
   2352   FORGET_Frame();
   2353 
   2354   lat->ComponentRecord = NULL;
   2355 
   2356   if ( ALLOC_ARRAY( lat->ComponentRecord, count, HB_ComponentRecord ) )
   2357     return error;
   2358 
   2359   cr = lat->ComponentRecord;
   2360 
   2361   for ( m = 0; m < count; m++ )
   2362   {
   2363     cr[m].LigatureAnchor = NULL;
   2364 
   2365     if ( ALLOC_ARRAY( cr[m].LigatureAnchor, num_classes, HB_Anchor ) )
   2366       goto Fail;
   2367 
   2368     lan = cr[m].LigatureAnchor;
   2369 
   2370     for ( n = 0; n < num_classes; n++ )
   2371     {
   2372       if ( ACCESS_Frame( 2L ) )
   2373 	goto Fail0;
   2374 
   2375       new_offset = GET_UShort();
   2376 
   2377       FORGET_Frame();
   2378 
   2379       if ( new_offset )
   2380       {
   2381 	new_offset += base_offset;
   2382 
   2383 	cur_offset = FILE_Pos();
   2384 	if ( FILE_Seek( new_offset ) ||
   2385 	     ( error = Load_Anchor( &lan[n], stream ) ) != HB_Err_Ok )
   2386 	  goto Fail0;
   2387 	(void)FILE_Seek( cur_offset );
   2388       }
   2389       else
   2390 	lan[n].PosFormat = 0;
   2391     }
   2392 
   2393     continue;
   2394   Fail0:
   2395     for ( k = 0; k < n; k++ )
   2396       Free_Anchor( &lan[k] );
   2397     goto Fail;
   2398   }
   2399 
   2400   return HB_Err_Ok;
   2401 
   2402 Fail:
   2403   for ( k = 0; k < m; k++ )
   2404   {
   2405     lan = cr[k].LigatureAnchor;
   2406 
   2407     for ( n = 0; n < num_classes; n++ )
   2408       Free_Anchor( &lan[n] );
   2409 
   2410     FREE( lan );
   2411   }
   2412 
   2413   FREE( cr );
   2414   return error;
   2415 }
   2416 
   2417 
   2418 static void  Free_LigatureAttach( HB_LigatureAttach*  lat,
   2419 				  HB_UShort            num_classes )
   2420 {
   2421   HB_UShort        m, n, count;
   2422 
   2423   HB_ComponentRecord*  cr;
   2424   HB_Anchor*           lan;
   2425 
   2426 
   2427   if ( lat->ComponentRecord )
   2428   {
   2429     count = lat->ComponentCount;
   2430     cr    = lat->ComponentRecord;
   2431 
   2432     for ( m = 0; m < count; m++ )
   2433     {
   2434       lan = cr[m].LigatureAnchor;
   2435 
   2436       for ( n = 0; n < num_classes; n++ )
   2437 	Free_Anchor( &lan[n] );
   2438 
   2439       FREE( lan );
   2440     }
   2441 
   2442     FREE( cr );
   2443   }
   2444 }
   2445 
   2446 
   2447 /* LigatureArray */
   2448 
   2449 static HB_Error  Load_LigatureArray( HB_LigatureArray*  la,
   2450 				     HB_UShort           num_classes,
   2451 				     HB_Stream           stream )
   2452 {
   2453   HB_Error  error;
   2454 
   2455   HB_UShort            n, m, count;
   2456   HB_UInt             cur_offset, new_offset, base_offset;
   2457 
   2458   HB_LigatureAttach*  lat;
   2459 
   2460 
   2461   base_offset = FILE_Pos();
   2462 
   2463   if ( ACCESS_Frame( 2L ) )
   2464     return error;
   2465 
   2466   count = la->LigatureCount = GET_UShort();
   2467 
   2468   FORGET_Frame();
   2469 
   2470   la->LigatureAttach = NULL;
   2471 
   2472   if ( ALLOC_ARRAY( la->LigatureAttach, count, HB_LigatureAttach ) )
   2473     return error;
   2474 
   2475   lat = la->LigatureAttach;
   2476 
   2477   for ( n = 0; n < count; n++ )
   2478   {
   2479     if ( ACCESS_Frame( 2L ) )
   2480       goto Fail;
   2481 
   2482     new_offset = GET_UShort() + base_offset;
   2483 
   2484     FORGET_Frame();
   2485 
   2486     cur_offset = FILE_Pos();
   2487     if ( FILE_Seek( new_offset ) ||
   2488 	 ( error = Load_LigatureAttach( &lat[n], num_classes,
   2489 					stream ) ) != HB_Err_Ok )
   2490       goto Fail;
   2491     (void)FILE_Seek( cur_offset );
   2492   }
   2493 
   2494   return HB_Err_Ok;
   2495 
   2496 Fail:
   2497   for ( m = 0; m < n; m++ )
   2498     Free_LigatureAttach( &lat[m], num_classes );
   2499 
   2500   FREE( lat );
   2501   return error;
   2502 }
   2503 
   2504 
   2505 static void  Free_LigatureArray( HB_LigatureArray*  la,
   2506 				 HB_UShort           num_classes )
   2507 {
   2508   HB_UShort            n, count;
   2509 
   2510   HB_LigatureAttach*  lat;
   2511 
   2512 
   2513   if ( la->LigatureAttach )
   2514   {
   2515     count = la->LigatureCount;
   2516     lat   = la->LigatureAttach;
   2517 
   2518     for ( n = 0; n < count; n++ )
   2519       Free_LigatureAttach( &lat[n], num_classes );
   2520 
   2521     FREE( lat );
   2522   }
   2523 }
   2524 
   2525 
   2526 /* MarkLigPosFormat1 */
   2527 
   2528 static HB_Error  Load_MarkLigPos( HB_GPOS_SubTable* st,
   2529 				  HB_Stream        stream )
   2530 {
   2531   HB_Error  error;
   2532   HB_MarkLigPos*  mlp = &st->marklig;
   2533 
   2534   HB_UInt  cur_offset, new_offset, base_offset;
   2535 
   2536 
   2537   base_offset = FILE_Pos();
   2538 
   2539   if ( ACCESS_Frame( 4L ) )
   2540     return error;
   2541 
   2542   mlp->PosFormat = GET_UShort();
   2543   new_offset     = GET_UShort() + base_offset;
   2544 
   2545   FORGET_Frame();
   2546 
   2547   cur_offset = FILE_Pos();
   2548   if ( FILE_Seek( new_offset ) ||
   2549        ( error = _HB_OPEN_Load_Coverage( &mlp->MarkCoverage, stream ) ) != HB_Err_Ok )
   2550     return error;
   2551   (void)FILE_Seek( cur_offset );
   2552 
   2553   if ( ACCESS_Frame( 2L ) )
   2554     goto Fail3;
   2555 
   2556   new_offset = GET_UShort() + base_offset;
   2557 
   2558   FORGET_Frame();
   2559 
   2560   cur_offset = FILE_Pos();
   2561   if ( FILE_Seek( new_offset ) ||
   2562        ( error = _HB_OPEN_Load_Coverage( &mlp->LigatureCoverage,
   2563 				stream ) ) != HB_Err_Ok )
   2564     goto Fail3;
   2565   (void)FILE_Seek( cur_offset );
   2566 
   2567   if ( ACCESS_Frame( 4L ) )
   2568     goto Fail2;
   2569 
   2570   mlp->ClassCount = GET_UShort();
   2571   new_offset      = GET_UShort() + base_offset;
   2572 
   2573   FORGET_Frame();
   2574 
   2575   cur_offset = FILE_Pos();
   2576   if ( FILE_Seek( new_offset ) ||
   2577        ( error = Load_MarkArray( &mlp->MarkArray, stream ) ) != HB_Err_Ok )
   2578     goto Fail2;
   2579   (void)FILE_Seek( cur_offset );
   2580 
   2581   if ( ACCESS_Frame( 2L ) )
   2582     goto Fail1;
   2583 
   2584   new_offset = GET_UShort() + base_offset;
   2585 
   2586   FORGET_Frame();
   2587 
   2588   cur_offset = FILE_Pos();
   2589   if ( FILE_Seek( new_offset ) ||
   2590        ( error = Load_LigatureArray( &mlp->LigatureArray, mlp->ClassCount,
   2591 				     stream ) ) != HB_Err_Ok )
   2592     goto Fail1;
   2593 
   2594   return HB_Err_Ok;
   2595 
   2596 Fail1:
   2597   Free_MarkArray( &mlp->MarkArray );
   2598 
   2599 Fail2:
   2600   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
   2601 
   2602 Fail3:
   2603   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
   2604   return error;
   2605 }
   2606 
   2607 
   2608 static void  Free_MarkLigPos( HB_GPOS_SubTable* st)
   2609 {
   2610   HB_MarkLigPos*  mlp = &st->marklig;
   2611 
   2612   Free_LigatureArray( &mlp->LigatureArray, mlp->ClassCount );
   2613   Free_MarkArray( &mlp->MarkArray );
   2614   _HB_OPEN_Free_Coverage( &mlp->LigatureCoverage );
   2615   _HB_OPEN_Free_Coverage( &mlp->MarkCoverage );
   2616 }
   2617 
   2618 
   2619 static HB_Error  Lookup_MarkLigPos( GPOS_Instance*    gpi,
   2620 				    HB_GPOS_SubTable* st,
   2621 				    HB_Buffer        buffer,
   2622 				    HB_UShort         flags,
   2623 				    HB_UShort         context_length,
   2624 				    int               nesting_level )
   2625 {
   2626   HB_UShort        i, j, mark_index, lig_index, property, class;
   2627   HB_UShort        mark_glyph;
   2628   HB_Fixed           x_mark_value, y_mark_value, x_lig_value, y_lig_value;
   2629   HB_Error         error;
   2630   HB_GPOSHeader*  gpos = gpi->gpos;
   2631   HB_MarkLigPos*  mlp = &st->marklig;
   2632 
   2633   HB_MarkArray*        ma;
   2634   HB_LigatureArray*    la;
   2635   HB_LigatureAttach*   lat;
   2636   HB_ComponentRecord*  cr;
   2637   HB_UShort             comp_index;
   2638   HB_Anchor*           mark_anchor;
   2639   HB_Anchor*           lig_anchor;
   2640 
   2641   HB_Position    o;
   2642 
   2643   HB_UNUSED(nesting_level);
   2644 
   2645   if ( context_length != 0xFFFF && context_length < 1 )
   2646     return HB_Err_Not_Covered;
   2647 
   2648   if ( flags & HB_LOOKUP_FLAG_IGNORE_LIGATURES )
   2649     return HB_Err_Not_Covered;
   2650 
   2651   mark_glyph = IN_CURGLYPH();
   2652 
   2653   if ( CHECK_Property( gpos->gdef, IN_CURITEM(), flags, &property ) )
   2654     return error;
   2655 
   2656   error = _HB_OPEN_Coverage_Index( &mlp->MarkCoverage, mark_glyph, &mark_index );
   2657   if ( error )
   2658     return error;
   2659 
   2660   /* now we search backwards for a non-mark glyph */
   2661 
   2662   i = 1;
   2663   j = buffer->in_pos - 1;
   2664 
   2665   while ( i <= buffer->in_pos )
   2666   {
   2667     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2668 					&property );
   2669     if ( error )
   2670       return error;
   2671 
   2672     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   2673       break;
   2674 
   2675     i++;
   2676     j--;
   2677   }
   2678 
   2679   /* Similar to Lookup_MarkBasePos(), I suspect that this assertion is
   2680      too strong, thus it is commented out.                             */
   2681 #if 0
   2682   if ( property != HB_GDEF_LIGATURE )
   2683     return HB_Err_Not_Covered;
   2684 #endif
   2685 
   2686   if ( i > buffer->in_pos )
   2687     return HB_Err_Not_Covered;
   2688 
   2689   error = _HB_OPEN_Coverage_Index( &mlp->LigatureCoverage, IN_GLYPH( j ),
   2690 			  &lig_index );
   2691   if ( error )
   2692     return error;
   2693 
   2694   ma = &mlp->MarkArray;
   2695 
   2696   if ( mark_index >= ma->MarkCount )
   2697     return ERR(HB_Err_Invalid_SubTable);
   2698 
   2699   class       = ma->MarkRecord[mark_index].Class;
   2700   mark_anchor = &ma->MarkRecord[mark_index].MarkAnchor;
   2701 
   2702   if ( class >= mlp->ClassCount )
   2703     return ERR(HB_Err_Invalid_SubTable);
   2704 
   2705   la = &mlp->LigatureArray;
   2706 
   2707   if ( lig_index >= la->LigatureCount )
   2708     return ERR(HB_Err_Invalid_SubTable);
   2709 
   2710   lat = &la->LigatureAttach[lig_index];
   2711 
   2712   /* We must now check whether the ligature ID of the current mark glyph
   2713      is identical to the ligature ID of the found ligature.  If yes, we
   2714      can directly use the component index.  If not, we attach the mark
   2715      glyph to the last component of the ligature.                        */
   2716 
   2717   if ( IN_LIGID( j ) == IN_LIGID( buffer->in_pos) )
   2718   {
   2719     comp_index = IN_COMPONENT( buffer->in_pos );
   2720     if ( comp_index >= lat->ComponentCount )
   2721       return HB_Err_Not_Covered;
   2722   }
   2723   else
   2724     comp_index = lat->ComponentCount - 1;
   2725 
   2726   cr         = &lat->ComponentRecord[comp_index];
   2727   lig_anchor = &cr->LigatureAnchor[class];
   2728 
   2729   error = Get_Anchor( gpi, mark_anchor, IN_CURGLYPH(),
   2730 		      &x_mark_value, &y_mark_value );
   2731   if ( error )
   2732     return error;
   2733   error = Get_Anchor( gpi, lig_anchor, IN_GLYPH( j ),
   2734 		      &x_lig_value, &y_lig_value );
   2735   if ( error )
   2736     return error;
   2737 
   2738   /* anchor points are not cumulative */
   2739 
   2740   o = POSITION( buffer->in_pos );
   2741 
   2742   o->x_pos     = x_lig_value - x_mark_value;
   2743   o->y_pos     = y_lig_value - y_mark_value;
   2744   o->x_advance = 0;
   2745   o->y_advance = 0;
   2746   o->back      = i;
   2747 
   2748   (buffer->in_pos)++;
   2749 
   2750   return HB_Err_Ok;
   2751 }
   2752 
   2753 
   2754 /* LookupType 6 */
   2755 
   2756 /* Mark2Array */
   2757 
   2758 static HB_Error  Load_Mark2Array( HB_Mark2Array*  m2a,
   2759 				  HB_UShort        num_classes,
   2760 				  HB_Stream        stream )
   2761 {
   2762   HB_Error  error;
   2763 
   2764   HB_UShort        m, n, count;
   2765   HB_UInt          cur_offset, new_offset, base_offset;
   2766 
   2767   HB_Mark2Record  *m2r;
   2768   HB_Anchor       *m2an, *m2ans;
   2769 
   2770 
   2771   base_offset = FILE_Pos();
   2772 
   2773   if ( ACCESS_Frame( 2L ) )
   2774     return error;
   2775 
   2776   count = m2a->Mark2Count = GET_UShort();
   2777 
   2778   FORGET_Frame();
   2779 
   2780   m2a->Mark2Record = NULL;
   2781 
   2782   if ( ALLOC_ARRAY( m2a->Mark2Record, count, HB_Mark2Record ) )
   2783     return error;
   2784 
   2785   m2r = m2a->Mark2Record;
   2786 
   2787   m2ans = NULL;
   2788 
   2789   if ( ALLOC_ARRAY( m2ans, count * num_classes, HB_Anchor ) )
   2790     goto Fail;
   2791 
   2792   for ( m = 0; m < count; m++ )
   2793   {
   2794     m2an = m2r[m].Mark2Anchor = m2ans + m * num_classes;
   2795 
   2796     for ( n = 0; n < num_classes; n++ )
   2797     {
   2798       if ( ACCESS_Frame( 2L ) )
   2799 	goto Fail;
   2800 
   2801       new_offset = GET_UShort() + base_offset;
   2802 
   2803       FORGET_Frame();
   2804 
   2805       if (new_offset == base_offset) {
   2806         /* Anchor table not provided.  Skip loading.
   2807 	 * Some versions of FreeSans hit this. */
   2808         m2an[n].PosFormat = 0;
   2809 	continue;
   2810       }
   2811 
   2812       cur_offset = FILE_Pos();
   2813       if ( FILE_Seek( new_offset ) ||
   2814 	   ( error = Load_Anchor( &m2an[n], stream ) ) != HB_Err_Ok )
   2815 	goto Fail;
   2816       (void)FILE_Seek( cur_offset );
   2817     }
   2818   }
   2819 
   2820   return HB_Err_Ok;
   2821 
   2822 Fail:
   2823   FREE( m2ans );
   2824   FREE( m2r );
   2825   return error;
   2826 }
   2827 
   2828 
   2829 static void  Free_Mark2Array( HB_Mark2Array*  m2a,
   2830 			      HB_UShort        num_classes )
   2831 {
   2832   HB_Mark2Record  *m2r;
   2833   HB_Anchor       *m2ans;
   2834 
   2835   HB_UNUSED(num_classes);
   2836 
   2837   if ( m2a->Mark2Record )
   2838   {
   2839     m2r   = m2a->Mark2Record;
   2840 
   2841     if ( m2a->Mark2Count )
   2842     {
   2843       m2ans = m2r[0].Mark2Anchor;
   2844       FREE( m2ans );
   2845     }
   2846 
   2847     FREE( m2r );
   2848   }
   2849 }
   2850 
   2851 
   2852 /* MarkMarkPosFormat1 */
   2853 
   2854 static HB_Error  Load_MarkMarkPos( HB_GPOS_SubTable* st,
   2855 				   HB_Stream         stream )
   2856 {
   2857   HB_Error  error;
   2858   HB_MarkMarkPos* mmp = &st->markmark;
   2859 
   2860   HB_UInt  cur_offset, new_offset, base_offset;
   2861 
   2862 
   2863   base_offset = FILE_Pos();
   2864 
   2865   if ( ACCESS_Frame( 4L ) )
   2866     return error;
   2867 
   2868   mmp->PosFormat = GET_UShort();
   2869   new_offset     = GET_UShort() + base_offset;
   2870 
   2871   FORGET_Frame();
   2872 
   2873   cur_offset = FILE_Pos();
   2874   if ( FILE_Seek( new_offset ) ||
   2875        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark1Coverage,
   2876 				stream ) ) != HB_Err_Ok )
   2877     return error;
   2878   (void)FILE_Seek( cur_offset );
   2879 
   2880   if ( ACCESS_Frame( 2L ) )
   2881     goto Fail3;
   2882 
   2883   new_offset = GET_UShort() + base_offset;
   2884 
   2885   FORGET_Frame();
   2886 
   2887   cur_offset = FILE_Pos();
   2888   if ( FILE_Seek( new_offset ) ||
   2889        ( error = _HB_OPEN_Load_Coverage( &mmp->Mark2Coverage,
   2890 				stream ) ) != HB_Err_Ok )
   2891     goto Fail3;
   2892   (void)FILE_Seek( cur_offset );
   2893 
   2894   if ( ACCESS_Frame( 4L ) )
   2895     goto Fail2;
   2896 
   2897   mmp->ClassCount = GET_UShort();
   2898   new_offset      = GET_UShort() + base_offset;
   2899 
   2900   FORGET_Frame();
   2901 
   2902   cur_offset = FILE_Pos();
   2903   if ( FILE_Seek( new_offset ) ||
   2904        ( error = Load_MarkArray( &mmp->Mark1Array, stream ) ) != HB_Err_Ok )
   2905     goto Fail2;
   2906   (void)FILE_Seek( cur_offset );
   2907 
   2908   if ( ACCESS_Frame( 2L ) )
   2909     goto Fail1;
   2910 
   2911   new_offset = GET_UShort() + base_offset;
   2912 
   2913   FORGET_Frame();
   2914 
   2915   cur_offset = FILE_Pos();
   2916   if ( FILE_Seek( new_offset ) ||
   2917        ( error = Load_Mark2Array( &mmp->Mark2Array, mmp->ClassCount,
   2918 				  stream ) ) != HB_Err_Ok )
   2919     goto Fail1;
   2920 
   2921   return HB_Err_Ok;
   2922 
   2923 Fail1:
   2924   Free_MarkArray( &mmp->Mark1Array );
   2925 
   2926 Fail2:
   2927   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
   2928 
   2929 Fail3:
   2930   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
   2931   return error;
   2932 }
   2933 
   2934 
   2935 static void  Free_MarkMarkPos( HB_GPOS_SubTable* st)
   2936 {
   2937   HB_MarkMarkPos* mmp = &st->markmark;
   2938 
   2939   Free_Mark2Array( &mmp->Mark2Array, mmp->ClassCount );
   2940   Free_MarkArray( &mmp->Mark1Array );
   2941   _HB_OPEN_Free_Coverage( &mmp->Mark2Coverage );
   2942   _HB_OPEN_Free_Coverage( &mmp->Mark1Coverage );
   2943 }
   2944 
   2945 
   2946 static HB_Error  Lookup_MarkMarkPos( GPOS_Instance*    gpi,
   2947 				     HB_GPOS_SubTable* st,
   2948 				     HB_Buffer        buffer,
   2949 				     HB_UShort         flags,
   2950 				     HB_UShort         context_length,
   2951 				     int               nesting_level )
   2952 {
   2953   HB_UShort        i, j, mark1_index, mark2_index, property, class;
   2954   HB_Fixed           x_mark1_value, y_mark1_value,
   2955 		   x_mark2_value, y_mark2_value;
   2956   HB_Error         error;
   2957   HB_GPOSHeader*  gpos = gpi->gpos;
   2958   HB_MarkMarkPos* mmp = &st->markmark;
   2959 
   2960   HB_MarkArray*    ma1;
   2961   HB_Mark2Array*   ma2;
   2962   HB_Mark2Record*  m2r;
   2963   HB_Anchor*       mark1_anchor;
   2964   HB_Anchor*       mark2_anchor;
   2965 
   2966   HB_Position    o;
   2967 
   2968   HB_UNUSED(nesting_level);
   2969 
   2970   if ( context_length != 0xFFFF && context_length < 1 )
   2971     return HB_Err_Not_Covered;
   2972 
   2973   if ( flags & HB_LOOKUP_FLAG_IGNORE_MARKS )
   2974     return HB_Err_Not_Covered;
   2975 
   2976   if ( CHECK_Property( gpos->gdef, IN_CURITEM(),
   2977 		       flags, &property ) )
   2978     return error;
   2979 
   2980   error = _HB_OPEN_Coverage_Index( &mmp->Mark1Coverage, IN_CURGLYPH(),
   2981 			  &mark1_index );
   2982   if ( error )
   2983     return error;
   2984 
   2985   /* now we search backwards for a suitable mark glyph until a non-mark
   2986      glyph                                                */
   2987 
   2988   if ( buffer->in_pos == 0 )
   2989     return HB_Err_Not_Covered;
   2990 
   2991   i = 1;
   2992   j = buffer->in_pos - 1;
   2993   while ( i <= buffer->in_pos )
   2994   {
   2995     error = HB_GDEF_Get_Glyph_Property( gpos->gdef, IN_GLYPH( j ),
   2996 					&property );
   2997     if ( error )
   2998       return error;
   2999 
   3000     if ( !( property == HB_GDEF_MARK || property & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS ) )
   3001       return HB_Err_Not_Covered;
   3002 
   3003     if ( flags & HB_LOOKUP_FLAG_IGNORE_SPECIAL_MARKS )
   3004     {
   3005       if ( property == (flags & 0xFF00) )
   3006         break;
   3007     }
   3008     else
   3009       break;
   3010 
   3011     i++;
   3012     j--;
   3013   }
   3014 
   3015   if ( i > buffer->in_pos )
   3016     return HB_Err_Not_Covered;
   3017 
   3018   error = _HB_OPEN_Coverage_Index( &mmp->Mark2Coverage, IN_GLYPH( j ),
   3019 			  &mark2_index );
   3020   if ( error )
   3021     return error;
   3022 
   3023   ma1 = &mmp->Mark1Array;
   3024 
   3025   if ( mark1_index >= ma1->MarkCount )
   3026     return ERR(HB_Err_Invalid_SubTable);
   3027 
   3028   class        = ma1->MarkRecord[mark1_index].Class;
   3029   mark1_anchor = &ma1->MarkRecord[mark1_index].MarkAnchor;
   3030 
   3031   if ( class >= mmp->ClassCount )
   3032     return ERR(HB_Err_Invalid_SubTable);
   3033 
   3034   ma2 = &mmp->Mark2Array;
   3035 
   3036   if ( mark2_index >= ma2->Mark2Count )
   3037     return ERR(HB_Err_Invalid_SubTable);
   3038 
   3039   m2r          = &ma2->Mark2Record[mark2_index];
   3040   mark2_anchor = &m2r->Mark2Anchor[class];
   3041 
   3042   error = Get_Anchor( gpi, mark1_anchor, IN_CURGLYPH(),
   3043 		      &x_mark1_value, &y_mark1_value );
   3044   if ( error )
   3045     return error;
   3046   error = Get_Anchor( gpi, mark2_anchor, IN_GLYPH( j ),
   3047 		      &x_mark2_value, &y_mark2_value );
   3048   if ( error )
   3049     return error;
   3050 
   3051   /* anchor points are not cumulative */
   3052 
   3053   o = POSITION( buffer->in_pos );
   3054 
   3055   o->x_pos     = x_mark2_value - x_mark1_value;
   3056   o->y_pos     = y_mark2_value - y_mark1_value;
   3057   o->x_advance = 0;
   3058   o->y_advance = 0;
   3059   o->back      = 1;
   3060 
   3061   (buffer->in_pos)++;
   3062 
   3063   return HB_Err_Ok;
   3064 }
   3065 
   3066 
   3067 /* Do the actual positioning for a context positioning (either format
   3068    7 or 8).  This is only called after we've determined that the stream
   3069    matches the subrule.                                                 */
   3070 
   3071 static HB_Error  Do_ContextPos( GPOS_Instance*        gpi,
   3072 				HB_UShort             GlyphCount,
   3073 				HB_UShort             PosCount,
   3074 				HB_PosLookupRecord*  pos,
   3075 				HB_Buffer            buffer,
   3076 				int                   nesting_level )
   3077 {
   3078   HB_Error  error;
   3079   HB_UInt   i, old_pos;
   3080 
   3081 
   3082   i = 0;
   3083 
   3084   while ( i < GlyphCount )
   3085   {
   3086     if ( PosCount && i == pos->SequenceIndex )
   3087     {
   3088       old_pos = buffer->in_pos;
   3089 
   3090       /* Do a positioning */
   3091 
   3092       error = GPOS_Do_Glyph_Lookup( gpi, pos->LookupListIndex, buffer,
   3093 				    GlyphCount, nesting_level );
   3094 
   3095       if ( error )
   3096 	return error;
   3097 
   3098       pos++;
   3099       PosCount--;
   3100       i += buffer->in_pos - old_pos;
   3101     }
   3102     else
   3103     {
   3104       i++;
   3105       (buffer->in_pos)++;
   3106     }
   3107   }
   3108 
   3109   return HB_Err_Ok;
   3110 }
   3111 
   3112 
   3113 /* LookupType 7 */
   3114 
   3115 /* PosRule */
   3116 
   3117 static HB_Error  Load_PosRule( HB_PosRule*  pr,
   3118 			       HB_Stream     stream )
   3119 {
   3120   HB_Error  error;
   3121 
   3122   HB_UShort             n, count;
   3123   HB_UShort*            i;
   3124 
   3125   HB_PosLookupRecord*  plr;
   3126 
   3127 
   3128   if ( ACCESS_Frame( 4L ) )
   3129     return error;
   3130 
   3131   pr->GlyphCount = GET_UShort();
   3132   pr->PosCount   = GET_UShort();
   3133 
   3134   FORGET_Frame();
   3135 
   3136   pr->Input = NULL;
   3137 
   3138   count = pr->GlyphCount - 1;         /* only GlyphCount - 1 elements */
   3139 
   3140   if ( ALLOC_ARRAY( pr->Input, count, HB_UShort ) )
   3141     return error;
   3142 
   3143   i = pr->Input;
   3144 
   3145   if ( ACCESS_Frame( count * 2L ) )
   3146     goto Fail2;
   3147 
   3148   for ( n = 0; n < count; n++ )
   3149     i[n] = GET_UShort();
   3150 
   3151   FORGET_Frame();
   3152 
   3153   pr->PosLookupRecord = NULL;
   3154 
   3155   count = pr->PosCount;
   3156 
   3157   if ( ALLOC_ARRAY( pr->PosLookupRecord, count, HB_PosLookupRecord ) )
   3158     goto Fail2;
   3159 
   3160   plr = pr->PosLookupRecord;
   3161 
   3162   if ( ACCESS_Frame( count * 4L ) )
   3163     goto Fail1;
   3164 
   3165   for ( n = 0; n < count; n++ )
   3166   {
   3167     plr[n].SequenceIndex   = GET_UShort();
   3168     plr[n].LookupListIndex = GET_UShort();
   3169   }
   3170 
   3171   FORGET_Frame();
   3172 
   3173   return HB_Err_Ok;
   3174 
   3175 Fail1:
   3176   FREE( plr );
   3177 
   3178 Fail2:
   3179   FREE( i );
   3180   return error;
   3181 }
   3182 
   3183 
   3184 static void  Free_PosRule( HB_PosRule*  pr )
   3185 {
   3186   FREE( pr->PosLookupRecord );
   3187   FREE( pr->Input );
   3188 }
   3189 
   3190 
   3191 /* PosRuleSet */
   3192 
   3193 static HB_Error  Load_PosRuleSet( HB_PosRuleSet*  prs,
   3194 				  HB_Stream        stream )
   3195 {
   3196   HB_Error  error;
   3197 
   3198   HB_UShort     n, m, count;
   3199   HB_UInt      cur_offset, new_offset, base_offset;
   3200 
   3201   HB_PosRule*  pr;
   3202 
   3203 
   3204   base_offset = FILE_Pos();
   3205 
   3206   if ( ACCESS_Frame( 2L ) )
   3207     return error;
   3208 
   3209   count = prs->PosRuleCount = GET_UShort();
   3210 
   3211   FORGET_Frame();
   3212 
   3213   prs->PosRule = NULL;
   3214 
   3215   if ( ALLOC_ARRAY( prs->PosRule, count, HB_PosRule ) )
   3216     return error;
   3217 
   3218   pr = prs->PosRule;
   3219 
   3220   for ( n = 0; n < count; n++ )
   3221   {
   3222     if ( ACCESS_Frame( 2L ) )
   3223       goto Fail;
   3224 
   3225     new_offset = GET_UShort() + base_offset;
   3226 
   3227     FORGET_Frame();
   3228 
   3229     cur_offset = FILE_Pos();
   3230     if ( FILE_Seek( new_offset ) ||
   3231 	 ( error = Load_PosRule( &pr[n], stream ) ) != HB_Err_Ok )
   3232       goto Fail;
   3233     (void)FILE_Seek( cur_offset );
   3234   }
   3235 
   3236   return HB_Err_Ok;
   3237 
   3238 Fail:
   3239   for ( m = 0; m < n; m++ )
   3240     Free_PosRule( &pr[m] );
   3241 
   3242   FREE( pr );
   3243   return error;
   3244 }
   3245 
   3246 
   3247 static void  Free_PosRuleSet( HB_PosRuleSet*  prs )
   3248 {
   3249   HB_UShort     n, count;
   3250 
   3251   HB_PosRule*  pr;
   3252 
   3253 
   3254   if ( prs->PosRule )
   3255   {
   3256     count = prs->PosRuleCount;
   3257     pr    = prs->PosRule;
   3258 
   3259     for ( n = 0; n < count; n++ )
   3260       Free_PosRule( &pr[n] );
   3261 
   3262     FREE( pr );
   3263   }
   3264 }
   3265 
   3266 
   3267 /* ContextPosFormat1 */
   3268 
   3269 static HB_Error  Load_ContextPos1( HB_ContextPosFormat1*  cpf1,
   3270 				   HB_Stream               stream )
   3271 {
   3272   HB_Error  error;
   3273 
   3274   HB_UShort        n, m, count;
   3275   HB_UInt         cur_offset, new_offset, base_offset;
   3276 
   3277   HB_PosRuleSet*  prs;
   3278 
   3279 
   3280   base_offset = FILE_Pos() - 2L;
   3281 
   3282   if ( ACCESS_Frame( 2L ) )
   3283     return error;
   3284 
   3285   new_offset = GET_UShort() + base_offset;
   3286 
   3287   FORGET_Frame();
   3288 
   3289   cur_offset = FILE_Pos();
   3290   if ( FILE_Seek( new_offset ) ||
   3291        ( error = _HB_OPEN_Load_Coverage( &cpf1->Coverage, stream ) ) != HB_Err_Ok )
   3292     return error;
   3293   (void)FILE_Seek( cur_offset );
   3294 
   3295   if ( ACCESS_Frame( 2L ) )
   3296     goto Fail2;
   3297 
   3298   count = cpf1->PosRuleSetCount = GET_UShort();
   3299 
   3300   FORGET_Frame();
   3301 
   3302   cpf1->PosRuleSet = NULL;
   3303 
   3304   if ( ALLOC_ARRAY( cpf1->PosRuleSet, count, HB_PosRuleSet ) )
   3305     goto Fail2;
   3306 
   3307   prs = cpf1->PosRuleSet;
   3308 
   3309   for ( n = 0; n < count; n++ )
   3310   {
   3311     if ( ACCESS_Frame( 2L ) )
   3312       goto Fail1;
   3313 
   3314     new_offset = GET_UShort() + base_offset;
   3315 
   3316     FORGET_Frame();
   3317 
   3318     cur_offset = FILE_Pos();
   3319     if ( FILE_Seek( new_offset ) ||
   3320 	 ( error = Load_PosRuleSet( &prs[n], stream ) ) != HB_Err_Ok )
   3321       goto Fail1;
   3322     (void)FILE_Seek( cur_offset );
   3323   }
   3324 
   3325   return HB_Err_Ok;
   3326 
   3327 Fail1:
   3328   for ( m = 0; m < n; m++ )
   3329     Free_PosRuleSet( &prs[m] );
   3330 
   3331   FREE( prs );
   3332 
   3333 Fail2:
   3334   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
   3335   return error;
   3336 }
   3337 
   3338 
   3339 static void  Free_ContextPos1( HB_ContextPosFormat1*  cpf1 )
   3340 {
   3341   HB_UShort        n, count;
   3342 
   3343   HB_PosRuleSet*  prs;
   3344 
   3345 
   3346   if ( cpf1->PosRuleSet )
   3347   {
   3348     count = cpf1->PosRuleSetCount;
   3349     prs   = cpf1->PosRuleSet;
   3350 
   3351     for ( n = 0; n < count; n++ )
   3352       Free_PosRuleSet( &prs[n] );
   3353 
   3354     FREE( prs );
   3355   }
   3356 
   3357   _HB_OPEN_Free_Coverage( &cpf1->Coverage );
   3358 }
   3359 
   3360 
   3361 /* PosClassRule */
   3362 
   3363 static HB_Error  Load_PosClassRule( HB_ContextPosFormat2*  cpf2,
   3364 				    HB_PosClassRule*       pcr,
   3365 				    HB_Stream               stream )
   3366 {
   3367   HB_Error  error;
   3368 
   3369   HB_UShort             n, count;
   3370 
   3371   HB_UShort*            c;
   3372   HB_PosLookupRecord*  plr;
   3373 
   3374 
   3375   if ( ACCESS_Frame( 4L ) )
   3376     return error;
   3377 
   3378   pcr->GlyphCount = GET_UShort();
   3379   pcr->PosCount   = GET_UShort();
   3380 
   3381   FORGET_Frame();
   3382 
   3383   if ( pcr->GlyphCount > cpf2->MaxContextLength )
   3384     cpf2->MaxContextLength = pcr->GlyphCount;
   3385 
   3386   pcr->Class = NULL;
   3387 
   3388   count = pcr->GlyphCount - 1;        /* only GlyphCount - 1 elements */
   3389 
   3390   if ( ALLOC_ARRAY( pcr->Class, count, HB_UShort ) )
   3391     return error;
   3392 
   3393   c = pcr->Class;
   3394 
   3395   if ( ACCESS_Frame( count * 2L ) )
   3396     goto Fail2;
   3397 
   3398   for ( n = 0; n < count; n++ )
   3399     c[n] = GET_UShort();
   3400 
   3401   FORGET_Frame();
   3402 
   3403   pcr->PosLookupRecord = NULL;
   3404 
   3405   count = pcr->PosCount;
   3406 
   3407   if ( ALLOC_ARRAY( pcr->PosLookupRecord, count, HB_PosLookupRecord ) )
   3408     goto Fail2;
   3409 
   3410   plr = pcr->PosLookupRecord;
   3411 
   3412   if ( ACCESS_Frame( count * 4L ) )
   3413     goto Fail1;
   3414 
   3415   for ( n = 0; n < count; n++ )
   3416   {
   3417     plr[n].SequenceIndex   = GET_UShort();
   3418     plr[n].LookupListIndex = GET_UShort();
   3419   }
   3420 
   3421   FORGET_Frame();
   3422 
   3423   return HB_Err_Ok;
   3424 
   3425 Fail1:
   3426   FREE( plr );
   3427 
   3428 Fail2:
   3429   FREE( c );
   3430   return error;
   3431 }
   3432 
   3433 
   3434 static void  Free_PosClassRule( HB_PosClassRule*  pcr )
   3435 {
   3436   FREE( pcr->PosLookupRecord );
   3437   FREE( pcr->Class );
   3438 }
   3439 
   3440 
   3441 /* PosClassSet */
   3442 
   3443 static HB_Error  Load_PosClassSet( HB_ContextPosFormat2*  cpf2,
   3444 				   HB_PosClassSet*        pcs,
   3445 				   HB_Stream               stream )
   3446 {
   3447   HB_Error  error;
   3448 
   3449   HB_UShort          n, m, count;
   3450   HB_UInt           cur_offset, new_offset, base_offset;
   3451 
   3452   HB_PosClassRule*  pcr;
   3453 
   3454 
   3455   base_offset = FILE_Pos();
   3456 
   3457   if ( ACCESS_Frame( 2L ) )
   3458     return error;
   3459 
   3460   count = pcs->PosClassRuleCount = GET_UShort();
   3461 
   3462   FORGET_Frame();
   3463 
   3464   pcs->PosClassRule = NULL;
   3465 
   3466   if ( ALLOC_ARRAY( pcs->PosClassRule, count, HB_PosClassRule ) )
   3467     return error;
   3468 
   3469   pcr = pcs->PosClassRule;
   3470 
   3471   for ( n = 0; n < count; n++ )
   3472   {
   3473     if ( ACCESS_Frame( 2L ) )
   3474       goto Fail;
   3475 
   3476     new_offset = GET_UShort() + base_offset;
   3477 
   3478     FORGET_Frame();
   3479 
   3480     cur_offset = FILE_Pos();
   3481     if ( FILE_Seek( new_offset ) ||
   3482 	 ( error = Load_PosClassRule( cpf2, &pcr[n],
   3483 				      stream ) ) != HB_Err_Ok )
   3484       goto Fail;
   3485     (void)FILE_Seek( cur_offset );
   3486   }
   3487 
   3488   return HB_Err_Ok;
   3489 
   3490 Fail:
   3491   for ( m = 0; m < n; m++ )
   3492     Free_PosClassRule( &pcr[m] );
   3493 
   3494   FREE( pcr );
   3495   return error;
   3496 }
   3497 
   3498 
   3499 static void  Free_PosClassSet( HB_PosClassSet*  pcs )
   3500 {
   3501   HB_UShort          n, count;
   3502 
   3503   HB_PosClassRule*  pcr;
   3504 
   3505 
   3506   if ( pcs->PosClassRule )
   3507   {
   3508     count = pcs->PosClassRuleCount;
   3509     pcr   = pcs->PosClassRule;
   3510 
   3511     for ( n = 0; n < count; n++ )
   3512       Free_PosClassRule( &pcr[n] );
   3513 
   3514     FREE( pcr );
   3515   }
   3516 }
   3517 
   3518 
   3519 /* ContextPosFormat2 */
   3520 
   3521 static HB_Error  Load_ContextPos2( HB_ContextPosFormat2*  cpf2,
   3522 				   HB_Stream               stream )
   3523 {
   3524   HB_Error  error;
   3525 
   3526   HB_UShort         n, m, count;
   3527   HB_UInt          cur_offset, new_offset, base_offset;
   3528 
   3529   HB_PosClassSet*  pcs;
   3530 
   3531 
   3532   base_offset = FILE_Pos() - 2;
   3533 
   3534   if ( ACCESS_Frame( 2L ) )
   3535     return error;
   3536 
   3537   new_offset = GET_UShort() + base_offset;
   3538 
   3539   FORGET_Frame();
   3540 
   3541   cur_offset = FILE_Pos();
   3542   if ( FILE_Seek( new_offset ) ||
   3543        ( error = _HB_OPEN_Load_Coverage( &cpf2->Coverage, stream ) ) != HB_Err_Ok )
   3544     return error;
   3545   (void)FILE_Seek( cur_offset );
   3546 
   3547   if ( ACCESS_Frame( 4L ) )
   3548     goto Fail3;
   3549 
   3550   new_offset = GET_UShort() + base_offset;
   3551 
   3552   /* `PosClassSetCount' is the upper limit for class values, thus we
   3553      read it now to make an additional safety check.                 */
   3554 
   3555   count = cpf2->PosClassSetCount = GET_UShort();
   3556 
   3557   FORGET_Frame();
   3558 
   3559   cur_offset = FILE_Pos();
   3560   if ( FILE_Seek( new_offset ) ||
   3561        ( error = _HB_OPEN_Load_ClassDefinition( &cpf2->ClassDef, count,
   3562 				       stream ) ) != HB_Err_Ok )
   3563     goto Fail3;
   3564   (void)FILE_Seek( cur_offset );
   3565 
   3566   cpf2->PosClassSet      = NULL;
   3567   cpf2->MaxContextLength = 0;
   3568 
   3569   if ( ALLOC_ARRAY( cpf2->PosClassSet, count, HB_PosClassSet ) )
   3570     goto Fail2;
   3571 
   3572   pcs = cpf2->PosClassSet;
   3573 
   3574   for ( n = 0; n < count; n++ )
   3575   {
   3576     if ( ACCESS_Frame( 2L ) )
   3577       goto Fail1;
   3578 
   3579     new_offset = GET_UShort() + base_offset;
   3580 
   3581     FORGET_Frame();
   3582 
   3583     if ( new_offset != base_offset )      /* not a NULL offset */
   3584     {
   3585       cur_offset = FILE_Pos();
   3586       if ( FILE_Seek( new_offset ) ||
   3587 	   ( error = Load_PosClassSet( cpf2, &pcs[n],
   3588 				       stream ) ) != HB_Err_Ok )
   3589 	goto Fail1;
   3590       (void)FILE_Seek( cur_offset );
   3591     }
   3592     else
   3593     {
   3594       /* we create a PosClassSet table with no entries */
   3595 
   3596       cpf2->PosClassSet[n].PosClassRuleCount = 0;
   3597       cpf2->PosClassSet[n].PosClassRule      = NULL;
   3598     }
   3599   }
   3600 
   3601   return HB_Err_Ok;
   3602 
   3603 Fail1:
   3604   for ( m = 0; m < n; n++ )
   3605     Free_PosClassSet( &pcs[m] );
   3606 
   3607   FREE( pcs );
   3608 
   3609 Fail2:
   3610   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
   3611 
   3612 Fail3:
   3613   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
   3614   return error;
   3615 }
   3616 
   3617 
   3618 static void  Free_ContextPos2( HB_ContextPosFormat2*  cpf2 )
   3619 {
   3620   HB_UShort         n, count;
   3621 
   3622   HB_PosClassSet*  pcs;
   3623 
   3624 
   3625   if ( cpf2->PosClassSet )
   3626   {
   3627     count = cpf2->PosClassSetCount;
   3628     pcs   = cpf2->PosClassSet;
   3629 
   3630     for ( n = 0; n < count; n++ )
   3631       Free_PosClassSet( &pcs[n] );
   3632 
   3633     FREE( pcs );
   3634   }
   3635 
   3636   _HB_OPEN_Free_ClassDefinition( &cpf2->ClassDef );
   3637   _HB_OPEN_Free_Coverage( &cpf2->Coverage );
   3638 }
   3639 
   3640 
   3641 /* ContextPosFormat3 */
   3642 
   3643 static HB_Error  Load_ContextPos3( HB_ContextPosFormat3*  cpf3,
   3644 				   HB_Stream               stream )
   3645 {
   3646   HB_Error  error;
   3647 
   3648   HB_UShort             n, count;
   3649   HB_UInt              cur_offset, new_offset, base_offset;
   3650 
   3651   HB_Coverage*         c;
   3652   HB_PosLookupRecord*  plr;
   3653 
   3654 
   3655   base_offset = FILE_Pos() - 2L;
   3656 
   3657   if ( ACCESS_Frame( 4L ) )
   3658     return error;
   3659 
   3660   cpf3->GlyphCount = GET_UShort();
   3661   cpf3->PosCount   = GET_UShort();
   3662 
   3663   FORGET_Frame();
   3664 
   3665   cpf3->Coverage = NULL;
   3666 
   3667   count = cpf3->GlyphCount;
   3668 
   3669   if ( ALLOC_ARRAY( cpf3->Coverage, count, HB_Coverage ) )
   3670     return error;
   3671 
   3672   c = cpf3->Coverage;
   3673 
   3674   for ( n = 0; n < count; n++ )
   3675   {
   3676     if ( ACCESS_Frame( 2L ) )
   3677       goto Fail2;
   3678 
   3679     new_offset = GET_UShort() + base_offset;
   3680 
   3681     FORGET_Frame();
   3682 
   3683     cur_offset = FILE_Pos();
   3684     if ( FILE_Seek( new_offset ) ||
   3685 	 ( error = _HB_OPEN_Load_Coverage( &c[n], stream ) ) != HB_Err_Ok )
   3686       goto Fail2;
   3687     (void)FILE_Seek( cur_offset );
   3688   }
   3689 
   3690   cpf3->PosLookupRecord = NULL;
   3691 
   3692   count = cpf3->PosCount;
   3693 
   3694   if ( ALLOC_ARRAY( cpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
   3695     goto Fail2;
   3696 
   3697   plr = cpf3->PosLookupRecord;
   3698 
   3699   if ( ACCESS_Frame( count * 4L ) )
   3700     goto Fail1;
   3701 
   3702   for ( n = 0; n < count; n++ )
   3703   {
   3704     plr[n].SequenceIndex   = GET_UShort();
   3705     plr[n].LookupListIndex = GET_UShort();
   3706   }
   3707 
   3708   FORGET_Frame();
   3709 
   3710   return HB_Err_Ok;
   3711 
   3712 Fail1:
   3713   FREE( plr );
   3714 
   3715 Fail2:
   3716   for ( n = 0; n < count; n++ )
   3717     _HB_OPEN_Free_Coverage( &c[n] );
   3718 
   3719   FREE( c );
   3720   return error;
   3721 }
   3722 
   3723 
   3724 static void  Free_ContextPos3( HB_ContextPosFormat3*  cpf3 )
   3725 {
   3726   HB_UShort      n, count;
   3727 
   3728   HB_Coverage*  c;
   3729 
   3730 
   3731   FREE( cpf3->PosLookupRecord );
   3732 
   3733   if ( cpf3->Coverage )
   3734   {
   3735     count = cpf3->GlyphCount;
   3736     c     = cpf3->Coverage;
   3737 
   3738     for ( n = 0; n < count; n++ )
   3739       _HB_OPEN_Free_Coverage( &c[n] );
   3740 
   3741     FREE( c );
   3742   }
   3743 }
   3744 
   3745 
   3746 /* ContextPos */
   3747 
   3748 static HB_Error  Load_ContextPos( HB_GPOS_SubTable* st,
   3749 				  HB_Stream        stream )
   3750 {
   3751   HB_Error  error;
   3752   HB_ContextPos*   cp = &st->context;
   3753 
   3754 
   3755   if ( ACCESS_Frame( 2L ) )
   3756     return error;
   3757 
   3758   cp->PosFormat = GET_UShort();
   3759 
   3760   FORGET_Frame();
   3761 
   3762   switch ( cp->PosFormat )
   3763   {
   3764   case 1:
   3765     return Load_ContextPos1( &cp->cpf.cpf1, stream );
   3766 
   3767   case 2:
   3768     return Load_ContextPos2( &cp->cpf.cpf2, stream );
   3769 
   3770   case 3:
   3771     return Load_ContextPos3( &cp->cpf.cpf3, stream );
   3772 
   3773   default:
   3774     return ERR(HB_Err_Invalid_SubTable_Format);
   3775   }
   3776 
   3777   return HB_Err_Ok;               /* never reached */
   3778 }
   3779 
   3780 
   3781 static void  Free_ContextPos( HB_GPOS_SubTable* st )
   3782 {
   3783   HB_ContextPos*   cp = &st->context;
   3784 
   3785   switch ( cp->PosFormat )
   3786   {
   3787   case 1:  Free_ContextPos1( &cp->cpf.cpf1 ); break;
   3788   case 2:  Free_ContextPos2( &cp->cpf.cpf2 ); break;
   3789   case 3:  Free_ContextPos3( &cp->cpf.cpf3 ); break;
   3790   default:					      break;
   3791   }
   3792 }
   3793 
   3794 
   3795 static HB_Error  Lookup_ContextPos1( GPOS_Instance*          gpi,
   3796 				     HB_ContextPosFormat1*  cpf1,
   3797 				     HB_Buffer              buffer,
   3798 				     HB_UShort               flags,
   3799 				     HB_UShort               context_length,
   3800 				     int                     nesting_level )
   3801 {
   3802   HB_UShort        index, property;
   3803   HB_UShort        i, j, k, numpr;
   3804   HB_Error         error;
   3805   HB_GPOSHeader*  gpos = gpi->gpos;
   3806 
   3807   HB_PosRule*     pr;
   3808   HB_GDEFHeader*  gdef;
   3809 
   3810 
   3811   gdef = gpos->gdef;
   3812 
   3813   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3814     return error;
   3815 
   3816   error = _HB_OPEN_Coverage_Index( &cpf1->Coverage, IN_CURGLYPH(), &index );
   3817   if ( error )
   3818     return error;
   3819 
   3820   pr    = cpf1->PosRuleSet[index].PosRule;
   3821   numpr = cpf1->PosRuleSet[index].PosRuleCount;
   3822 
   3823   for ( k = 0; k < numpr; k++ )
   3824   {
   3825     if ( context_length != 0xFFFF && context_length < pr[k].GlyphCount )
   3826       goto next_posrule;
   3827 
   3828     if ( buffer->in_pos + pr[k].GlyphCount > buffer->in_length )
   3829       goto next_posrule;                       /* context is too long */
   3830 
   3831     for ( i = 1, j = buffer->in_pos + 1; i < pr[k].GlyphCount; i++, j++ )
   3832     {
   3833       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3834       {
   3835 	if ( error && error != HB_Err_Not_Covered )
   3836 	  return error;
   3837 
   3838 	if ( j + pr[k].GlyphCount - i == (HB_Int)buffer->in_length )
   3839 	  goto next_posrule;
   3840 	j++;
   3841       }
   3842 
   3843       if ( IN_GLYPH( j ) != pr[k].Input[i - 1] )
   3844 	goto next_posrule;
   3845     }
   3846 
   3847     return Do_ContextPos( gpi, pr[k].GlyphCount,
   3848 			  pr[k].PosCount, pr[k].PosLookupRecord,
   3849 			  buffer,
   3850 			  nesting_level );
   3851 
   3852     next_posrule:
   3853       ;
   3854   }
   3855 
   3856   return HB_Err_Not_Covered;
   3857 }
   3858 
   3859 
   3860 static HB_Error  Lookup_ContextPos2( GPOS_Instance*          gpi,
   3861 				     HB_ContextPosFormat2*  cpf2,
   3862 				     HB_Buffer              buffer,
   3863 				     HB_UShort               flags,
   3864 				     HB_UShort               context_length,
   3865 				     int                     nesting_level )
   3866 {
   3867   HB_UShort          index, property;
   3868   HB_Error           error;
   3869   HB_UShort          i, j, k, known_classes;
   3870 
   3871   HB_UShort*         classes;
   3872   HB_UShort*         cl;
   3873   HB_GPOSHeader*    gpos = gpi->gpos;
   3874 
   3875   HB_PosClassSet*   pcs;
   3876   HB_PosClassRule*  pr;
   3877   HB_GDEFHeader*    gdef;
   3878 
   3879 
   3880   gdef = gpos->gdef;
   3881 
   3882   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3883     return error;
   3884 
   3885   /* Note: The coverage table in format 2 doesn't give an index into
   3886 	   anything.  It just lets us know whether or not we need to
   3887 	   do any lookup at all.                                     */
   3888 
   3889   error = _HB_OPEN_Coverage_Index( &cpf2->Coverage, IN_CURGLYPH(), &index );
   3890   if ( error )
   3891     return error;
   3892 
   3893   if (cpf2->MaxContextLength < 1)
   3894     return HB_Err_Not_Covered;
   3895 
   3896   if ( ALLOC_ARRAY( classes, cpf2->MaxContextLength, HB_UShort ) )
   3897     return error;
   3898 
   3899   error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_CURGLYPH(),
   3900 		     &classes[0], NULL );
   3901   if ( error && error != HB_Err_Not_Covered )
   3902     goto End;
   3903   known_classes = 0;
   3904 
   3905   pcs = &cpf2->PosClassSet[classes[0]];
   3906   if ( !pcs )
   3907   {
   3908     error = ERR(HB_Err_Invalid_SubTable);
   3909     goto End;
   3910   }
   3911 
   3912   for ( k = 0; k < pcs->PosClassRuleCount; k++ )
   3913   {
   3914     pr = &pcs->PosClassRule[k];
   3915 
   3916     if ( context_length != 0xFFFF && context_length < pr->GlyphCount )
   3917       goto next_posclassrule;
   3918 
   3919     if ( buffer->in_pos + pr->GlyphCount > buffer->in_length )
   3920       goto next_posclassrule;                /* context is too long */
   3921 
   3922     cl   = pr->Class;
   3923 
   3924     /* Start at 1 because [0] is implied */
   3925 
   3926     for ( i = 1, j = buffer->in_pos + 1; i < pr->GlyphCount; i++, j++ )
   3927     {
   3928       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   3929       {
   3930 	if ( error && error != HB_Err_Not_Covered )
   3931 	  goto End;
   3932 
   3933 	if ( j + pr->GlyphCount - i == (HB_Int)buffer->in_length )
   3934 	  goto next_posclassrule;
   3935 	j++;
   3936       }
   3937 
   3938       if ( i > known_classes )
   3939       {
   3940 	/* Keeps us from having to do this for each rule */
   3941 
   3942 	error = _HB_OPEN_Get_Class( &cpf2->ClassDef, IN_GLYPH( j ), &classes[i], NULL );
   3943 	if ( error && error != HB_Err_Not_Covered )
   3944 	  goto End;
   3945 	known_classes = i;
   3946       }
   3947 
   3948       if ( cl[i - 1] != classes[i] )
   3949 	goto next_posclassrule;
   3950     }
   3951 
   3952     error = Do_ContextPos( gpi, pr->GlyphCount,
   3953 			   pr->PosCount, pr->PosLookupRecord,
   3954 			   buffer,
   3955 			   nesting_level );
   3956     goto End;
   3957 
   3958   next_posclassrule:
   3959     ;
   3960   }
   3961 
   3962   error = HB_Err_Not_Covered;
   3963 
   3964 End:
   3965   FREE( classes );
   3966   return error;
   3967 }
   3968 
   3969 
   3970 static HB_Error  Lookup_ContextPos3( GPOS_Instance*          gpi,
   3971 				     HB_ContextPosFormat3*  cpf3,
   3972 				     HB_Buffer              buffer,
   3973 				     HB_UShort               flags,
   3974 				     HB_UShort               context_length,
   3975 				     int                     nesting_level )
   3976 {
   3977   HB_Error         error;
   3978   HB_UShort        index, i, j, property;
   3979   HB_GPOSHeader*  gpos = gpi->gpos;
   3980 
   3981   HB_Coverage*    c;
   3982   HB_GDEFHeader*  gdef;
   3983 
   3984 
   3985   gdef = gpos->gdef;
   3986 
   3987   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   3988     return error;
   3989 
   3990   if ( context_length != 0xFFFF && context_length < cpf3->GlyphCount )
   3991     return HB_Err_Not_Covered;
   3992 
   3993   if ( buffer->in_pos + cpf3->GlyphCount > buffer->in_length )
   3994     return HB_Err_Not_Covered;         /* context is too long */
   3995 
   3996   c    = cpf3->Coverage;
   3997 
   3998   for ( i = 1, j = 1; i < cpf3->GlyphCount; i++, j++ )
   3999   {
   4000     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   4001     {
   4002       if ( error && error != HB_Err_Not_Covered )
   4003 	return error;
   4004 
   4005       if ( j + cpf3->GlyphCount - i == (HB_Int)buffer->in_length )
   4006 	return HB_Err_Not_Covered;
   4007       j++;
   4008     }
   4009 
   4010     error = _HB_OPEN_Coverage_Index( &c[i], IN_GLYPH( j ), &index );
   4011     if ( error )
   4012       return error;
   4013   }
   4014 
   4015   return Do_ContextPos( gpi, cpf3->GlyphCount,
   4016 			cpf3->PosCount, cpf3->PosLookupRecord,
   4017 			buffer,
   4018 			nesting_level );
   4019 }
   4020 
   4021 
   4022 static HB_Error  Lookup_ContextPos( GPOS_Instance*    gpi,
   4023 				    HB_GPOS_SubTable* st,
   4024 				    HB_Buffer        buffer,
   4025 				    HB_UShort         flags,
   4026 				    HB_UShort         context_length,
   4027 				    int               nesting_level )
   4028 {
   4029   HB_ContextPos*   cp = &st->context;
   4030 
   4031   switch ( cp->PosFormat )
   4032   {
   4033   case 1:
   4034     return Lookup_ContextPos1( gpi, &cp->cpf.cpf1, buffer,
   4035 			       flags, context_length, nesting_level );
   4036 
   4037   case 2:
   4038     return Lookup_ContextPos2( gpi, &cp->cpf.cpf2, buffer,
   4039 			       flags, context_length, nesting_level );
   4040 
   4041   case 3:
   4042     return Lookup_ContextPos3( gpi, &cp->cpf.cpf3, buffer,
   4043 			       flags, context_length, nesting_level );
   4044 
   4045   default:
   4046     return ERR(HB_Err_Invalid_SubTable_Format);
   4047   }
   4048 
   4049   return HB_Err_Ok;               /* never reached */
   4050 }
   4051 
   4052 
   4053 /* LookupType 8 */
   4054 
   4055 /* ChainPosRule */
   4056 
   4057 static HB_Error  Load_ChainPosRule( HB_ChainPosRule*  cpr,
   4058 				    HB_Stream          stream )
   4059 {
   4060   HB_Error  error;
   4061 
   4062   HB_UShort             n, count;
   4063   HB_UShort*            b;
   4064   HB_UShort*            i;
   4065   HB_UShort*            l;
   4066 
   4067   HB_PosLookupRecord*  plr;
   4068 
   4069 
   4070   if ( ACCESS_Frame( 2L ) )
   4071     return error;
   4072 
   4073   cpr->BacktrackGlyphCount = GET_UShort();
   4074 
   4075   FORGET_Frame();
   4076 
   4077   cpr->Backtrack = NULL;
   4078 
   4079   count = cpr->BacktrackGlyphCount;
   4080 
   4081   if ( ALLOC_ARRAY( cpr->Backtrack, count, HB_UShort ) )
   4082     return error;
   4083 
   4084   b = cpr->Backtrack;
   4085 
   4086   if ( ACCESS_Frame( count * 2L ) )
   4087     goto Fail4;
   4088 
   4089   for ( n = 0; n < count; n++ )
   4090     b[n] = GET_UShort();
   4091 
   4092   FORGET_Frame();
   4093 
   4094   if ( ACCESS_Frame( 2L ) )
   4095     goto Fail4;
   4096 
   4097   cpr->InputGlyphCount = GET_UShort();
   4098 
   4099   FORGET_Frame();
   4100 
   4101   cpr->Input = NULL;
   4102 
   4103   count = cpr->InputGlyphCount - 1;  /* only InputGlyphCount - 1 elements */
   4104 
   4105   if ( ALLOC_ARRAY( cpr->Input, count, HB_UShort ) )
   4106     goto Fail4;
   4107 
   4108   i = cpr->Input;
   4109 
   4110   if ( ACCESS_Frame( count * 2L ) )
   4111     goto Fail3;
   4112 
   4113   for ( n = 0; n < count; n++ )
   4114     i[n] = GET_UShort();
   4115 
   4116   FORGET_Frame();
   4117 
   4118   if ( ACCESS_Frame( 2L ) )
   4119     goto Fail3;
   4120 
   4121   cpr->LookaheadGlyphCount = GET_UShort();
   4122 
   4123   FORGET_Frame();
   4124 
   4125   cpr->Lookahead = NULL;
   4126 
   4127   count = cpr->LookaheadGlyphCount;
   4128 
   4129   if ( ALLOC_ARRAY( cpr->Lookahead, count, HB_UShort ) )
   4130     goto Fail3;
   4131 
   4132   l = cpr->Lookahead;
   4133 
   4134   if ( ACCESS_Frame( count * 2L ) )
   4135     goto Fail2;
   4136 
   4137   for ( n = 0; n < count; n++ )
   4138     l[n] = GET_UShort();
   4139 
   4140   FORGET_Frame();
   4141 
   4142   if ( ACCESS_Frame( 2L ) )
   4143     goto Fail2;
   4144 
   4145   cpr->PosCount = GET_UShort();
   4146 
   4147   FORGET_Frame();
   4148 
   4149   cpr->PosLookupRecord = NULL;
   4150 
   4151   count = cpr->PosCount;
   4152 
   4153   if ( ALLOC_ARRAY( cpr->PosLookupRecord, count, HB_PosLookupRecord ) )
   4154     goto Fail2;
   4155 
   4156   plr = cpr->PosLookupRecord;
   4157 
   4158   if ( ACCESS_Frame( count * 4L ) )
   4159     goto Fail1;
   4160 
   4161   for ( n = 0; n < count; n++ )
   4162   {
   4163     plr[n].SequenceIndex   = GET_UShort();
   4164     plr[n].LookupListIndex = GET_UShort();
   4165   }
   4166 
   4167   FORGET_Frame();
   4168 
   4169   return HB_Err_Ok;
   4170 
   4171 Fail1:
   4172   FREE( plr );
   4173 
   4174 Fail2:
   4175   FREE( l );
   4176 
   4177 Fail3:
   4178   FREE( i );
   4179 
   4180 Fail4:
   4181   FREE( b );
   4182   return error;
   4183 }
   4184 
   4185 
   4186 static void  Free_ChainPosRule( HB_ChainPosRule*  cpr )
   4187 {
   4188   FREE( cpr->PosLookupRecord );
   4189   FREE( cpr->Lookahead );
   4190   FREE( cpr->Input );
   4191   FREE( cpr->Backtrack );
   4192 }
   4193 
   4194 
   4195 /* ChainPosRuleSet */
   4196 
   4197 static HB_Error  Load_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs,
   4198 				       HB_Stream             stream )
   4199 {
   4200   HB_Error  error;
   4201 
   4202   HB_UShort          n, m, count;
   4203   HB_UInt           cur_offset, new_offset, base_offset;
   4204 
   4205   HB_ChainPosRule*  cpr;
   4206 
   4207 
   4208   base_offset = FILE_Pos();
   4209 
   4210   if ( ACCESS_Frame( 2L ) )
   4211     return error;
   4212 
   4213   count = cprs->ChainPosRuleCount = GET_UShort();
   4214 
   4215   FORGET_Frame();
   4216 
   4217   cprs->ChainPosRule = NULL;
   4218 
   4219   if ( ALLOC_ARRAY( cprs->ChainPosRule, count, HB_ChainPosRule ) )
   4220     return error;
   4221 
   4222   cpr = cprs->ChainPosRule;
   4223 
   4224   for ( n = 0; n < count; n++ )
   4225   {
   4226     if ( ACCESS_Frame( 2L ) )
   4227       goto Fail;
   4228 
   4229     new_offset = GET_UShort() + base_offset;
   4230 
   4231     FORGET_Frame();
   4232 
   4233     cur_offset = FILE_Pos();
   4234     if ( FILE_Seek( new_offset ) ||
   4235 	 ( error = Load_ChainPosRule( &cpr[n], stream ) ) != HB_Err_Ok )
   4236       goto Fail;
   4237     (void)FILE_Seek( cur_offset );
   4238   }
   4239 
   4240   return HB_Err_Ok;
   4241 
   4242 Fail:
   4243   for ( m = 0; m < n; m++ )
   4244     Free_ChainPosRule( &cpr[m] );
   4245 
   4246   FREE( cpr );
   4247   return error;
   4248 }
   4249 
   4250 
   4251 static void  Free_ChainPosRuleSet( HB_ChainPosRuleSet*  cprs )
   4252 {
   4253   HB_UShort          n, count;
   4254 
   4255   HB_ChainPosRule*  cpr;
   4256 
   4257 
   4258   if ( cprs->ChainPosRule )
   4259   {
   4260     count = cprs->ChainPosRuleCount;
   4261     cpr   = cprs->ChainPosRule;
   4262 
   4263     for ( n = 0; n < count; n++ )
   4264       Free_ChainPosRule( &cpr[n] );
   4265 
   4266     FREE( cpr );
   4267   }
   4268 }
   4269 
   4270 
   4271 /* ChainContextPosFormat1 */
   4272 
   4273 static HB_Error  Load_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1,
   4274 					HB_Stream                    stream )
   4275 {
   4276   HB_Error  error;
   4277 
   4278   HB_UShort             n, m, count;
   4279   HB_UInt              cur_offset, new_offset, base_offset;
   4280 
   4281   HB_ChainPosRuleSet*  cprs;
   4282 
   4283 
   4284   base_offset = FILE_Pos() - 2L;
   4285 
   4286   if ( ACCESS_Frame( 2L ) )
   4287     return error;
   4288 
   4289   new_offset = GET_UShort() + base_offset;
   4290 
   4291   FORGET_Frame();
   4292 
   4293   cur_offset = FILE_Pos();
   4294   if ( FILE_Seek( new_offset ) ||
   4295        ( error = _HB_OPEN_Load_Coverage( &ccpf1->Coverage, stream ) ) != HB_Err_Ok )
   4296     return error;
   4297   (void)FILE_Seek( cur_offset );
   4298 
   4299   if ( ACCESS_Frame( 2L ) )
   4300     goto Fail2;
   4301 
   4302   count = ccpf1->ChainPosRuleSetCount = GET_UShort();
   4303 
   4304   FORGET_Frame();
   4305 
   4306   ccpf1->ChainPosRuleSet = NULL;
   4307 
   4308   if ( ALLOC_ARRAY( ccpf1->ChainPosRuleSet, count, HB_ChainPosRuleSet ) )
   4309     goto Fail2;
   4310 
   4311   cprs = ccpf1->ChainPosRuleSet;
   4312 
   4313   for ( n = 0; n < count; n++ )
   4314   {
   4315     if ( ACCESS_Frame( 2L ) )
   4316       goto Fail1;
   4317 
   4318     new_offset = GET_UShort() + base_offset;
   4319 
   4320     FORGET_Frame();
   4321 
   4322     cur_offset = FILE_Pos();
   4323     if ( FILE_Seek( new_offset ) ||
   4324 	 ( error = Load_ChainPosRuleSet( &cprs[n], stream ) ) != HB_Err_Ok )
   4325       goto Fail1;
   4326     (void)FILE_Seek( cur_offset );
   4327   }
   4328 
   4329   return HB_Err_Ok;
   4330 
   4331 Fail1:
   4332   for ( m = 0; m < n; m++ )
   4333     Free_ChainPosRuleSet( &cprs[m] );
   4334 
   4335   FREE( cprs );
   4336 
   4337 Fail2:
   4338   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
   4339   return error;
   4340 }
   4341 
   4342 
   4343 static void  Free_ChainContextPos1( HB_ChainContextPosFormat1*  ccpf1 )
   4344 {
   4345   HB_UShort             n, count;
   4346 
   4347   HB_ChainPosRuleSet*  cprs;
   4348 
   4349 
   4350   if ( ccpf1->ChainPosRuleSet )
   4351   {
   4352     count = ccpf1->ChainPosRuleSetCount;
   4353     cprs  = ccpf1->ChainPosRuleSet;
   4354 
   4355     for ( n = 0; n < count; n++ )
   4356       Free_ChainPosRuleSet( &cprs[n] );
   4357 
   4358     FREE( cprs );
   4359   }
   4360 
   4361   _HB_OPEN_Free_Coverage( &ccpf1->Coverage );
   4362 }
   4363 
   4364 
   4365 /* ChainPosClassRule */
   4366 
   4367 static HB_Error  Load_ChainPosClassRule(
   4368 		   HB_ChainContextPosFormat2*  ccpf2,
   4369 		   HB_ChainPosClassRule*       cpcr,
   4370 		   HB_Stream                    stream )
   4371 {
   4372   HB_Error  error;
   4373 
   4374   HB_UShort             n, count;
   4375 
   4376   HB_UShort*            b;
   4377   HB_UShort*            i;
   4378   HB_UShort*            l;
   4379   HB_PosLookupRecord*  plr;
   4380 
   4381 
   4382   if ( ACCESS_Frame( 2L ) )
   4383     return error;
   4384 
   4385   cpcr->BacktrackGlyphCount = GET_UShort();
   4386 
   4387   FORGET_Frame();
   4388 
   4389   if ( cpcr->BacktrackGlyphCount > ccpf2->MaxBacktrackLength )
   4390     ccpf2->MaxBacktrackLength = cpcr->BacktrackGlyphCount;
   4391 
   4392   cpcr->Backtrack = NULL;
   4393 
   4394   count = cpcr->BacktrackGlyphCount;
   4395 
   4396   if ( ALLOC_ARRAY( cpcr->Backtrack, count, HB_UShort ) )
   4397     return error;
   4398 
   4399   b = cpcr->Backtrack;
   4400 
   4401   if ( ACCESS_Frame( count * 2L ) )
   4402     goto Fail4;
   4403 
   4404   for ( n = 0; n < count; n++ )
   4405     b[n] = GET_UShort();
   4406 
   4407   FORGET_Frame();
   4408 
   4409   if ( ACCESS_Frame( 2L ) )
   4410     goto Fail4;
   4411 
   4412   cpcr->InputGlyphCount = GET_UShort();
   4413 
   4414   if ( cpcr->InputGlyphCount > ccpf2->MaxInputLength )
   4415     ccpf2->MaxInputLength = cpcr->InputGlyphCount;
   4416 
   4417   FORGET_Frame();
   4418 
   4419   cpcr->Input = NULL;
   4420 
   4421   count = cpcr->InputGlyphCount - 1; /* only InputGlyphCount - 1 elements */
   4422 
   4423   if ( ALLOC_ARRAY( cpcr->Input, count, HB_UShort ) )
   4424     goto Fail4;
   4425 
   4426   i = cpcr->Input;
   4427 
   4428   if ( ACCESS_Frame( count * 2L ) )
   4429     goto Fail3;
   4430 
   4431   for ( n = 0; n < count; n++ )
   4432     i[n] = GET_UShort();
   4433 
   4434   FORGET_Frame();
   4435 
   4436   if ( ACCESS_Frame( 2L ) )
   4437     goto Fail3;
   4438 
   4439   cpcr->LookaheadGlyphCount = GET_UShort();
   4440 
   4441   FORGET_Frame();
   4442 
   4443   if ( cpcr->LookaheadGlyphCount > ccpf2->MaxLookaheadLength )
   4444     ccpf2->MaxLookaheadLength = cpcr->LookaheadGlyphCount;
   4445 
   4446   cpcr->Lookahead = NULL;
   4447 
   4448   count = cpcr->LookaheadGlyphCount;
   4449 
   4450   if ( ALLOC_ARRAY( cpcr->Lookahead, count, HB_UShort ) )
   4451     goto Fail3;
   4452 
   4453   l = cpcr->Lookahead;
   4454 
   4455   if ( ACCESS_Frame( count * 2L ) )
   4456     goto Fail2;
   4457 
   4458   for ( n = 0; n < count; n++ )
   4459     l[n] = GET_UShort();
   4460 
   4461   FORGET_Frame();
   4462 
   4463   if ( ACCESS_Frame( 2L ) )
   4464     goto Fail2;
   4465 
   4466   cpcr->PosCount = GET_UShort();
   4467 
   4468   FORGET_Frame();
   4469 
   4470   cpcr->PosLookupRecord = NULL;
   4471 
   4472   count = cpcr->PosCount;
   4473 
   4474   if ( ALLOC_ARRAY( cpcr->PosLookupRecord, count, HB_PosLookupRecord ) )
   4475     goto Fail2;
   4476 
   4477   plr = cpcr->PosLookupRecord;
   4478 
   4479   if ( ACCESS_Frame( count * 4L ) )
   4480     goto Fail1;
   4481 
   4482   for ( n = 0; n < count; n++ )
   4483   {
   4484     plr[n].SequenceIndex   = GET_UShort();
   4485     plr[n].LookupListIndex = GET_UShort();
   4486   }
   4487 
   4488   FORGET_Frame();
   4489 
   4490   return HB_Err_Ok;
   4491 
   4492 Fail1:
   4493   FREE( plr );
   4494 
   4495 Fail2:
   4496   FREE( l );
   4497 
   4498 Fail3:
   4499   FREE( i );
   4500 
   4501 Fail4:
   4502   FREE( b );
   4503   return error;
   4504 }
   4505 
   4506 
   4507 static void  Free_ChainPosClassRule( HB_ChainPosClassRule*  cpcr )
   4508 {
   4509   FREE( cpcr->PosLookupRecord );
   4510   FREE( cpcr->Lookahead );
   4511   FREE( cpcr->Input );
   4512   FREE( cpcr->Backtrack );
   4513 }
   4514 
   4515 
   4516 /* PosClassSet */
   4517 
   4518 static HB_Error  Load_ChainPosClassSet(
   4519 		   HB_ChainContextPosFormat2*  ccpf2,
   4520 		   HB_ChainPosClassSet*        cpcs,
   4521 		   HB_Stream                    stream )
   4522 {
   4523   HB_Error  error;
   4524 
   4525   HB_UShort               n, m, count;
   4526   HB_UInt                cur_offset, new_offset, base_offset;
   4527 
   4528   HB_ChainPosClassRule*  cpcr;
   4529 
   4530 
   4531   base_offset = FILE_Pos();
   4532 
   4533   if ( ACCESS_Frame( 2L ) )
   4534     return error;
   4535 
   4536   count = cpcs->ChainPosClassRuleCount = GET_UShort();
   4537 
   4538   FORGET_Frame();
   4539 
   4540   cpcs->ChainPosClassRule = NULL;
   4541 
   4542   if ( ALLOC_ARRAY( cpcs->ChainPosClassRule, count,
   4543 		    HB_ChainPosClassRule ) )
   4544     return error;
   4545 
   4546   cpcr = cpcs->ChainPosClassRule;
   4547 
   4548   for ( n = 0; n < count; n++ )
   4549   {
   4550     if ( ACCESS_Frame( 2L ) )
   4551       goto Fail;
   4552 
   4553     new_offset = GET_UShort() + base_offset;
   4554 
   4555     FORGET_Frame();
   4556 
   4557     cur_offset = FILE_Pos();
   4558     if ( FILE_Seek( new_offset ) ||
   4559 	 ( error = Load_ChainPosClassRule( ccpf2, &cpcr[n],
   4560 					   stream ) ) != HB_Err_Ok )
   4561       goto Fail;
   4562     (void)FILE_Seek( cur_offset );
   4563   }
   4564 
   4565   return HB_Err_Ok;
   4566 
   4567 Fail:
   4568   for ( m = 0; m < n; m++ )
   4569     Free_ChainPosClassRule( &cpcr[m] );
   4570 
   4571   FREE( cpcr );
   4572   return error;
   4573 }
   4574 
   4575 
   4576 static void  Free_ChainPosClassSet( HB_ChainPosClassSet*  cpcs )
   4577 {
   4578   HB_UShort               n, count;
   4579 
   4580   HB_ChainPosClassRule*  cpcr;
   4581 
   4582 
   4583   if ( cpcs->ChainPosClassRule )
   4584   {
   4585     count = cpcs->ChainPosClassRuleCount;
   4586     cpcr  = cpcs->ChainPosClassRule;
   4587 
   4588     for ( n = 0; n < count; n++ )
   4589       Free_ChainPosClassRule( &cpcr[n] );
   4590 
   4591     FREE( cpcr );
   4592   }
   4593 }
   4594 
   4595 
   4596 /* ChainContextPosFormat2 */
   4597 
   4598 static HB_Error  Load_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2,
   4599 					HB_Stream                    stream )
   4600 {
   4601   HB_Error  error;
   4602 
   4603   HB_UShort              n, m, count;
   4604   HB_UInt               cur_offset, new_offset, base_offset;
   4605   HB_UInt               backtrack_offset, input_offset, lookahead_offset;
   4606 
   4607   HB_ChainPosClassSet*  cpcs;
   4608 
   4609 
   4610   base_offset = FILE_Pos() - 2;
   4611 
   4612   if ( ACCESS_Frame( 2L ) )
   4613     return error;
   4614 
   4615   new_offset = GET_UShort() + base_offset;
   4616 
   4617   FORGET_Frame();
   4618 
   4619   cur_offset = FILE_Pos();
   4620   if ( FILE_Seek( new_offset ) ||
   4621        ( error = _HB_OPEN_Load_Coverage( &ccpf2->Coverage, stream ) ) != HB_Err_Ok )
   4622     return error;
   4623   (void)FILE_Seek( cur_offset );
   4624 
   4625   if ( ACCESS_Frame( 8L ) )
   4626     goto Fail5;
   4627 
   4628   backtrack_offset = GET_UShort();
   4629   input_offset     = GET_UShort();
   4630   lookahead_offset = GET_UShort();
   4631 
   4632   /* `ChainPosClassSetCount' is the upper limit for input class values,
   4633      thus we read it now to make an additional safety check. No limit
   4634      is known or needed for the other two class definitions          */
   4635 
   4636   count = ccpf2->ChainPosClassSetCount = GET_UShort();
   4637 
   4638   FORGET_Frame();
   4639 
   4640   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->BacktrackClassDef, 65535,
   4641 						       backtrack_offset, base_offset,
   4642 						       stream ) ) != HB_Err_Ok )
   4643     goto Fail5;
   4644   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->InputClassDef, count,
   4645 						       input_offset, base_offset,
   4646 						       stream ) ) != HB_Err_Ok )
   4647     goto Fail4;
   4648   if ( ( error = _HB_OPEN_Load_EmptyOrClassDefinition( &ccpf2->LookaheadClassDef, 65535,
   4649 						       lookahead_offset, base_offset,
   4650 						       stream ) ) != HB_Err_Ok )
   4651     goto Fail3;
   4652 
   4653   ccpf2->ChainPosClassSet   = NULL;
   4654   ccpf2->MaxBacktrackLength = 0;
   4655   ccpf2->MaxInputLength     = 0;
   4656   ccpf2->MaxLookaheadLength = 0;
   4657 
   4658   if ( ALLOC_ARRAY( ccpf2->ChainPosClassSet, count, HB_ChainPosClassSet ) )
   4659     goto Fail2;
   4660 
   4661   cpcs = ccpf2->ChainPosClassSet;
   4662 
   4663   for ( n = 0; n < count; n++ )
   4664   {
   4665     if ( ACCESS_Frame( 2L ) )
   4666       goto Fail1;
   4667 
   4668     new_offset = GET_UShort() + base_offset;
   4669 
   4670     FORGET_Frame();
   4671 
   4672     if ( new_offset != base_offset )      /* not a NULL offset */
   4673     {
   4674       cur_offset = FILE_Pos();
   4675       if ( FILE_Seek( new_offset ) ||
   4676 	   ( error = Load_ChainPosClassSet( ccpf2, &cpcs[n],
   4677 					    stream ) ) != HB_Err_Ok )
   4678 	goto Fail1;
   4679       (void)FILE_Seek( cur_offset );
   4680     }
   4681     else
   4682     {
   4683       /* we create a ChainPosClassSet table with no entries */
   4684 
   4685       ccpf2->ChainPosClassSet[n].ChainPosClassRuleCount = 0;
   4686       ccpf2->ChainPosClassSet[n].ChainPosClassRule      = NULL;
   4687     }
   4688   }
   4689 
   4690   return HB_Err_Ok;
   4691 
   4692 Fail1:
   4693   for ( m = 0; m < n; m++ )
   4694     Free_ChainPosClassSet( &cpcs[m] );
   4695 
   4696   FREE( cpcs );
   4697 
   4698 Fail2:
   4699   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
   4700 
   4701 Fail3:
   4702   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
   4703 
   4704 Fail4:
   4705   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
   4706 
   4707 Fail5:
   4708   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
   4709   return error;
   4710 }
   4711 
   4712 
   4713 static void  Free_ChainContextPos2( HB_ChainContextPosFormat2*  ccpf2 )
   4714 {
   4715   HB_UShort              n, count;
   4716 
   4717   HB_ChainPosClassSet*  cpcs;
   4718 
   4719 
   4720   if ( ccpf2->ChainPosClassSet )
   4721   {
   4722     count = ccpf2->ChainPosClassSetCount;
   4723     cpcs  = ccpf2->ChainPosClassSet;
   4724 
   4725     for ( n = 0; n < count; n++ )
   4726       Free_ChainPosClassSet( &cpcs[n] );
   4727 
   4728     FREE( cpcs );
   4729   }
   4730 
   4731   _HB_OPEN_Free_ClassDefinition( &ccpf2->LookaheadClassDef );
   4732   _HB_OPEN_Free_ClassDefinition( &ccpf2->InputClassDef );
   4733   _HB_OPEN_Free_ClassDefinition( &ccpf2->BacktrackClassDef );
   4734 
   4735   _HB_OPEN_Free_Coverage( &ccpf2->Coverage );
   4736 }
   4737 
   4738 
   4739 /* ChainContextPosFormat3 */
   4740 
   4741 static HB_Error  Load_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3,
   4742 					HB_Stream                    stream )
   4743 {
   4744   HB_Error  error;
   4745 
   4746   HB_UShort             n, nb, ni, nl, m, count;
   4747   HB_UShort             backtrack_count, input_count, lookahead_count;
   4748   HB_UInt              cur_offset, new_offset, base_offset;
   4749 
   4750   HB_Coverage*         b;
   4751   HB_Coverage*         i;
   4752   HB_Coverage*         l;
   4753   HB_PosLookupRecord*  plr;
   4754 
   4755 
   4756   base_offset = FILE_Pos() - 2L;
   4757 
   4758   if ( ACCESS_Frame( 2L ) )
   4759     return error;
   4760 
   4761   ccpf3->BacktrackGlyphCount = GET_UShort();
   4762 
   4763   FORGET_Frame();
   4764 
   4765   ccpf3->BacktrackCoverage = NULL;
   4766 
   4767   backtrack_count = ccpf3->BacktrackGlyphCount;
   4768 
   4769   if ( ALLOC_ARRAY( ccpf3->BacktrackCoverage, backtrack_count,
   4770 		    HB_Coverage ) )
   4771     return error;
   4772 
   4773   b = ccpf3->BacktrackCoverage;
   4774 
   4775   for ( nb = 0; nb < backtrack_count; nb++ )
   4776   {
   4777     if ( ACCESS_Frame( 2L ) )
   4778       goto Fail4;
   4779 
   4780     new_offset = GET_UShort() + base_offset;
   4781 
   4782     FORGET_Frame();
   4783 
   4784     cur_offset = FILE_Pos();
   4785     if ( FILE_Seek( new_offset ) ||
   4786 	 ( error = _HB_OPEN_Load_Coverage( &b[nb], stream ) ) != HB_Err_Ok )
   4787       goto Fail4;
   4788     (void)FILE_Seek( cur_offset );
   4789   }
   4790 
   4791   if ( ACCESS_Frame( 2L ) )
   4792     goto Fail4;
   4793 
   4794   ccpf3->InputGlyphCount = GET_UShort();
   4795 
   4796   FORGET_Frame();
   4797 
   4798   ccpf3->InputCoverage = NULL;
   4799 
   4800   input_count = ccpf3->InputGlyphCount;
   4801 
   4802   if ( ALLOC_ARRAY( ccpf3->InputCoverage, input_count, HB_Coverage ) )
   4803     goto Fail4;
   4804 
   4805   i = ccpf3->InputCoverage;
   4806 
   4807   for ( ni = 0; ni < input_count; ni++ )
   4808   {
   4809     if ( ACCESS_Frame( 2L ) )
   4810       goto Fail3;
   4811 
   4812     new_offset = GET_UShort() + base_offset;
   4813 
   4814     FORGET_Frame();
   4815 
   4816     cur_offset = FILE_Pos();
   4817     if ( FILE_Seek( new_offset ) ||
   4818 	 ( error = _HB_OPEN_Load_Coverage( &i[ni], stream ) ) != HB_Err_Ok )
   4819       goto Fail3;
   4820     (void)FILE_Seek( cur_offset );
   4821   }
   4822 
   4823   if ( ACCESS_Frame( 2L ) )
   4824     goto Fail3;
   4825 
   4826   ccpf3->LookaheadGlyphCount = GET_UShort();
   4827 
   4828   FORGET_Frame();
   4829 
   4830   ccpf3->LookaheadCoverage = NULL;
   4831 
   4832   lookahead_count = ccpf3->LookaheadGlyphCount;
   4833 
   4834   if ( ALLOC_ARRAY( ccpf3->LookaheadCoverage, lookahead_count,
   4835 		    HB_Coverage ) )
   4836     goto Fail3;
   4837 
   4838   l = ccpf3->LookaheadCoverage;
   4839 
   4840   for ( nl = 0; nl < lookahead_count; nl++ )
   4841   {
   4842     if ( ACCESS_Frame( 2L ) )
   4843       goto Fail2;
   4844 
   4845     new_offset = GET_UShort() + base_offset;
   4846 
   4847     FORGET_Frame();
   4848 
   4849     cur_offset = FILE_Pos();
   4850     if ( FILE_Seek( new_offset ) ||
   4851 	 ( error = _HB_OPEN_Load_Coverage( &l[nl], stream ) ) != HB_Err_Ok )
   4852       goto Fail2;
   4853     (void)FILE_Seek( cur_offset );
   4854   }
   4855 
   4856   if ( ACCESS_Frame( 2L ) )
   4857     goto Fail2;
   4858 
   4859   ccpf3->PosCount = GET_UShort();
   4860 
   4861   FORGET_Frame();
   4862 
   4863   ccpf3->PosLookupRecord = NULL;
   4864 
   4865   count = ccpf3->PosCount;
   4866 
   4867   if ( ALLOC_ARRAY( ccpf3->PosLookupRecord, count, HB_PosLookupRecord ) )
   4868     goto Fail2;
   4869 
   4870   plr = ccpf3->PosLookupRecord;
   4871 
   4872   if ( ACCESS_Frame( count * 4L ) )
   4873     goto Fail1;
   4874 
   4875   for ( n = 0; n < count; n++ )
   4876   {
   4877     plr[n].SequenceIndex   = GET_UShort();
   4878     plr[n].LookupListIndex = GET_UShort();
   4879   }
   4880 
   4881   FORGET_Frame();
   4882 
   4883   return HB_Err_Ok;
   4884 
   4885 Fail1:
   4886   FREE( plr );
   4887 
   4888 Fail2:
   4889   for ( m = 0; m < nl; m++ )
   4890     _HB_OPEN_Free_Coverage( &l[m] );
   4891 
   4892   FREE( l );
   4893 
   4894 Fail3:
   4895   for ( m = 0; m < ni; m++ )
   4896     _HB_OPEN_Free_Coverage( &i[m] );
   4897 
   4898   FREE( i );
   4899 
   4900 Fail4:
   4901   for ( m = 0; m < nb; m++ )
   4902     _HB_OPEN_Free_Coverage( &b[m] );
   4903 
   4904   FREE( b );
   4905   return error;
   4906 }
   4907 
   4908 
   4909 static void  Free_ChainContextPos3( HB_ChainContextPosFormat3*  ccpf3 )
   4910 {
   4911   HB_UShort      n, count;
   4912 
   4913   HB_Coverage*  c;
   4914 
   4915 
   4916   FREE( ccpf3->PosLookupRecord );
   4917 
   4918   if ( ccpf3->LookaheadCoverage )
   4919   {
   4920     count = ccpf3->LookaheadGlyphCount;
   4921     c     = ccpf3->LookaheadCoverage;
   4922 
   4923     for ( n = 0; n < count; n++ )
   4924       _HB_OPEN_Free_Coverage( &c[n] );
   4925 
   4926     FREE( c );
   4927   }
   4928 
   4929   if ( ccpf3->InputCoverage )
   4930   {
   4931     count = ccpf3->InputGlyphCount;
   4932     c     = ccpf3->InputCoverage;
   4933 
   4934     for ( n = 0; n < count; n++ )
   4935       _HB_OPEN_Free_Coverage( &c[n] );
   4936 
   4937     FREE( c );
   4938   }
   4939 
   4940   if ( ccpf3->BacktrackCoverage )
   4941   {
   4942     count = ccpf3->BacktrackGlyphCount;
   4943     c     = ccpf3->BacktrackCoverage;
   4944 
   4945     for ( n = 0; n < count; n++ )
   4946       _HB_OPEN_Free_Coverage( &c[n] );
   4947 
   4948     FREE( c );
   4949   }
   4950 }
   4951 
   4952 
   4953 /* ChainContextPos */
   4954 
   4955 static HB_Error  Load_ChainContextPos( HB_GPOS_SubTable* st,
   4956 				       HB_Stream             stream )
   4957 {
   4958   HB_Error  error;
   4959   HB_ChainContextPos*  ccp = &st->chain;
   4960 
   4961 
   4962   if ( ACCESS_Frame( 2L ) )
   4963     return error;
   4964 
   4965   ccp->PosFormat = GET_UShort();
   4966 
   4967   FORGET_Frame();
   4968 
   4969   switch ( ccp->PosFormat )
   4970   {
   4971   case 1:
   4972     return Load_ChainContextPos1( &ccp->ccpf.ccpf1, stream );
   4973 
   4974   case 2:
   4975     return Load_ChainContextPos2( &ccp->ccpf.ccpf2, stream );
   4976 
   4977   case 3:
   4978     return Load_ChainContextPos3( &ccp->ccpf.ccpf3, stream );
   4979 
   4980   default:
   4981     return ERR(HB_Err_Invalid_SubTable_Format);
   4982   }
   4983 
   4984   return HB_Err_Ok;               /* never reached */
   4985 }
   4986 
   4987 
   4988 static void  Free_ChainContextPos( HB_GPOS_SubTable* st )
   4989 {
   4990   HB_ChainContextPos*  ccp = &st->chain;
   4991 
   4992   switch ( ccp->PosFormat )
   4993   {
   4994   case 1:  Free_ChainContextPos1( &ccp->ccpf.ccpf1 ); break;
   4995   case 2:  Free_ChainContextPos2( &ccp->ccpf.ccpf2 ); break;
   4996   case 3:  Free_ChainContextPos3( &ccp->ccpf.ccpf3 ); break;
   4997   default:						      break;
   4998   }
   4999 }
   5000 
   5001 
   5002 static HB_Error  Lookup_ChainContextPos1(
   5003 		   GPOS_Instance*               gpi,
   5004 		   HB_ChainContextPosFormat1*  ccpf1,
   5005 		   HB_Buffer                   buffer,
   5006 		   HB_UShort                    flags,
   5007 		   HB_UShort                    context_length,
   5008 		   int                          nesting_level )
   5009 {
   5010   HB_UShort          index, property;
   5011   HB_UShort          i, j, k, num_cpr;
   5012   HB_UShort          bgc, igc, lgc;
   5013   HB_Error           error;
   5014   HB_GPOSHeader*    gpos = gpi->gpos;
   5015 
   5016   HB_ChainPosRule*  cpr;
   5017   HB_ChainPosRule   curr_cpr;
   5018   HB_GDEFHeader*    gdef;
   5019 
   5020 
   5021   gdef = gpos->gdef;
   5022 
   5023   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   5024     return error;
   5025 
   5026   error = _HB_OPEN_Coverage_Index( &ccpf1->Coverage, IN_CURGLYPH(), &index );
   5027   if ( error )
   5028     return error;
   5029 
   5030   cpr     = ccpf1->ChainPosRuleSet[index].ChainPosRule;
   5031   num_cpr = ccpf1->ChainPosRuleSet[index].ChainPosRuleCount;
   5032 
   5033   for ( k = 0; k < num_cpr; k++ )
   5034   {
   5035     curr_cpr = cpr[k];
   5036     bgc      = curr_cpr.BacktrackGlyphCount;
   5037     igc      = curr_cpr.InputGlyphCount;
   5038     lgc      = curr_cpr.LookaheadGlyphCount;
   5039 
   5040     if ( context_length != 0xFFFF && context_length < igc )
   5041       goto next_chainposrule;
   5042 
   5043     /* check whether context is too long; it is a first guess only */
   5044 
   5045     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5046       goto next_chainposrule;
   5047 
   5048     if ( bgc )
   5049     {
   5050       /* Since we don't know in advance the number of glyphs to inspect,
   5051 	 we search backwards for matches in the backtrack glyph array    */
   5052 
   5053       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5054       {
   5055 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5056 	{
   5057 	  if ( error && error != HB_Err_Not_Covered )
   5058 	    return error;
   5059 
   5060 	  if ( j + 1 == bgc - i )
   5061 	    goto next_chainposrule;
   5062 	  j--;
   5063 	}
   5064 
   5065 	/* In OpenType 1.3, it is undefined whether the offsets of
   5066 	   backtrack glyphs is in logical order or not.  Version 1.4
   5067 	   will clarify this:
   5068 
   5069 	     Logical order -      a  b  c  d  e  f  g  h  i  j
   5070 					      i
   5071 	     Input offsets -                  0  1
   5072 	     Backtrack offsets -  3  2  1  0
   5073 	     Lookahead offsets -                    0  1  2  3           */
   5074 
   5075 	if ( IN_GLYPH( j ) != curr_cpr.Backtrack[i] )
   5076 	  goto next_chainposrule;
   5077       }
   5078     }
   5079 
   5080     /* Start at 1 because [0] is implied */
   5081 
   5082     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   5083     {
   5084       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5085       {
   5086 	if ( error && error != HB_Err_Not_Covered )
   5087 	  return error;
   5088 
   5089 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5090 	  goto next_chainposrule;
   5091 	j++;
   5092       }
   5093 
   5094       if ( IN_GLYPH( j ) != curr_cpr.Input[i - 1] )
   5095 	goto next_chainposrule;
   5096     }
   5097 
   5098     /* we are starting to check for lookahead glyphs right after the
   5099        last context glyph                                            */
   5100 
   5101     for ( i = 0; i < lgc; i++, j++ )
   5102     {
   5103       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5104       {
   5105 	if ( error && error != HB_Err_Not_Covered )
   5106 	  return error;
   5107 
   5108 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   5109 	  goto next_chainposrule;
   5110 	j++;
   5111       }
   5112 
   5113       if ( IN_GLYPH( j ) != curr_cpr.Lookahead[i] )
   5114 	goto next_chainposrule;
   5115     }
   5116 
   5117     return Do_ContextPos( gpi, igc,
   5118 			  curr_cpr.PosCount,
   5119 			  curr_cpr.PosLookupRecord,
   5120 			  buffer,
   5121 			  nesting_level );
   5122 
   5123   next_chainposrule:
   5124     ;
   5125   }
   5126 
   5127   return HB_Err_Not_Covered;
   5128 }
   5129 
   5130 
   5131 static HB_Error  Lookup_ChainContextPos2(
   5132 		   GPOS_Instance*               gpi,
   5133 		   HB_ChainContextPosFormat2*  ccpf2,
   5134 		   HB_Buffer                   buffer,
   5135 		   HB_UShort                    flags,
   5136 		   HB_UShort                    context_length,
   5137 		   int                          nesting_level )
   5138 {
   5139   HB_UShort              index, property;
   5140   HB_Error               error;
   5141   HB_UShort              i, j, k;
   5142   HB_UShort              bgc, igc, lgc;
   5143   HB_UShort              known_backtrack_classes,
   5144 			 known_input_classes,
   5145 			 known_lookahead_classes;
   5146 
   5147   HB_UShort*             backtrack_classes;
   5148   HB_UShort*             input_classes;
   5149   HB_UShort*             lookahead_classes;
   5150 
   5151   HB_UShort*             bc;
   5152   HB_UShort*             ic;
   5153   HB_UShort*             lc;
   5154   HB_GPOSHeader*        gpos = gpi->gpos;
   5155 
   5156   HB_ChainPosClassSet*  cpcs;
   5157   HB_ChainPosClassRule  cpcr;
   5158   HB_GDEFHeader*        gdef;
   5159 
   5160 
   5161   gdef = gpos->gdef;
   5162 
   5163   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   5164     return error;
   5165 
   5166   /* Note: The coverage table in format 2 doesn't give an index into
   5167 	   anything.  It just lets us know whether or not we need to
   5168 	   do any lookup at all.                                     */
   5169 
   5170   error = _HB_OPEN_Coverage_Index( &ccpf2->Coverage, IN_CURGLYPH(), &index );
   5171   if ( error )
   5172     return error;
   5173 
   5174   if (ccpf2->MaxInputLength < 1)
   5175     return HB_Err_Not_Covered;
   5176 
   5177   if ( ALLOC_ARRAY( backtrack_classes, ccpf2->MaxBacktrackLength, HB_UShort ) )
   5178     return error;
   5179   known_backtrack_classes = 0;
   5180 
   5181   if ( ALLOC_ARRAY( input_classes, ccpf2->MaxInputLength, HB_UShort ) )
   5182     goto End3;
   5183   known_input_classes = 1;
   5184 
   5185   if ( ALLOC_ARRAY( lookahead_classes, ccpf2->MaxLookaheadLength, HB_UShort ) )
   5186     goto End2;
   5187   known_lookahead_classes = 0;
   5188 
   5189   error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_CURGLYPH(),
   5190 		     &input_classes[0], NULL );
   5191   if ( error && error != HB_Err_Not_Covered )
   5192     goto End1;
   5193 
   5194   cpcs = &ccpf2->ChainPosClassSet[input_classes[0]];
   5195   if ( !cpcs )
   5196   {
   5197     error = ERR(HB_Err_Invalid_SubTable);
   5198     goto End1;
   5199   }
   5200 
   5201   for ( k = 0; k < cpcs->ChainPosClassRuleCount; k++ )
   5202   {
   5203     cpcr = cpcs->ChainPosClassRule[k];
   5204     bgc  = cpcr.BacktrackGlyphCount;
   5205     igc  = cpcr.InputGlyphCount;
   5206     lgc  = cpcr.LookaheadGlyphCount;
   5207 
   5208     if ( context_length != 0xFFFF && context_length < igc )
   5209       goto next_chainposclassrule;
   5210 
   5211     /* check whether context is too long; it is a first guess only */
   5212 
   5213     if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5214       goto next_chainposclassrule;
   5215 
   5216     if ( bgc )
   5217     {
   5218       /* Since we don't know in advance the number of glyphs to inspect,
   5219 	 we search backwards for matches in the backtrack glyph array.
   5220 	 Note that `known_backtrack_classes' starts at index 0.         */
   5221 
   5222       bc       = cpcr.Backtrack;
   5223 
   5224       for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5225       {
   5226 	while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5227 	{
   5228 	  if ( error && error != HB_Err_Not_Covered )
   5229 	    goto End1;
   5230 
   5231 	  if ( j + 1 == bgc - i )
   5232 	    goto next_chainposclassrule;
   5233 	  j++;
   5234 	}
   5235 
   5236 	if ( i >= known_backtrack_classes )
   5237 	{
   5238 	  /* Keeps us from having to do this for each rule */
   5239 
   5240 	  error = _HB_OPEN_Get_Class( &ccpf2->BacktrackClassDef, IN_GLYPH( j ),
   5241 			     &backtrack_classes[i], NULL );
   5242 	  if ( error && error != HB_Err_Not_Covered )
   5243 	    goto End1;
   5244 	  known_backtrack_classes = i;
   5245 	}
   5246 
   5247 	if ( bc[i] != backtrack_classes[i] )
   5248 	  goto next_chainposclassrule;
   5249       }
   5250     }
   5251 
   5252     ic       = cpcr.Input;
   5253 
   5254     /* Start at 1 because [0] is implied */
   5255 
   5256     for ( i = 1, j = buffer->in_pos + 1; i < igc; i++, j++ )
   5257     {
   5258       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5259       {
   5260 	if ( error && error != HB_Err_Not_Covered )
   5261 	  goto End1;
   5262 
   5263 	if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5264 	  goto next_chainposclassrule;
   5265 	j++;
   5266       }
   5267 
   5268       if ( i >= known_input_classes )
   5269       {
   5270 	error = _HB_OPEN_Get_Class( &ccpf2->InputClassDef, IN_GLYPH( j ),
   5271 			   &input_classes[i], NULL );
   5272 	if ( error && error != HB_Err_Not_Covered )
   5273 	  goto End1;
   5274 	known_input_classes = i;
   5275       }
   5276 
   5277       if ( ic[i - 1] != input_classes[i] )
   5278 	goto next_chainposclassrule;
   5279     }
   5280 
   5281     /* we are starting to check for lookahead glyphs right after the
   5282        last context glyph                                            */
   5283 
   5284     lc       = cpcr.Lookahead;
   5285 
   5286     for ( i = 0; i < lgc; i++, j++ )
   5287     {
   5288       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5289       {
   5290 	if ( error && error != HB_Err_Not_Covered )
   5291 	  goto End1;
   5292 
   5293 	if ( j + lgc - i == (HB_Int)buffer->in_length )
   5294 	  goto next_chainposclassrule;
   5295 	j++;
   5296       }
   5297 
   5298       if ( i >= known_lookahead_classes )
   5299       {
   5300 	error = _HB_OPEN_Get_Class( &ccpf2->LookaheadClassDef, IN_GLYPH( j ),
   5301 			   &lookahead_classes[i], NULL );
   5302 	if ( error && error != HB_Err_Not_Covered )
   5303 	  goto End1;
   5304 	known_lookahead_classes = i;
   5305       }
   5306 
   5307       if ( lc[i] != lookahead_classes[i] )
   5308 	goto next_chainposclassrule;
   5309     }
   5310 
   5311     error = Do_ContextPos( gpi, igc,
   5312 			   cpcr.PosCount,
   5313 			   cpcr.PosLookupRecord,
   5314 			   buffer,
   5315 			   nesting_level );
   5316     goto End1;
   5317 
   5318   next_chainposclassrule:
   5319     ;
   5320   }
   5321 
   5322   error = HB_Err_Not_Covered;
   5323 
   5324 End1:
   5325   FREE( lookahead_classes );
   5326 
   5327 End2:
   5328   FREE( input_classes );
   5329 
   5330 End3:
   5331   FREE( backtrack_classes );
   5332   return error;
   5333 }
   5334 
   5335 
   5336 static HB_Error  Lookup_ChainContextPos3(
   5337 		   GPOS_Instance*               gpi,
   5338 		   HB_ChainContextPosFormat3*  ccpf3,
   5339 		   HB_Buffer                   buffer,
   5340 		   HB_UShort                    flags,
   5341 		   HB_UShort                    context_length,
   5342 		   int                          nesting_level )
   5343 {
   5344   HB_UShort        index, i, j, property;
   5345   HB_UShort        bgc, igc, lgc;
   5346   HB_Error         error;
   5347   HB_GPOSHeader*  gpos = gpi->gpos;
   5348 
   5349   HB_Coverage*    bc;
   5350   HB_Coverage*    ic;
   5351   HB_Coverage*    lc;
   5352   HB_GDEFHeader*  gdef;
   5353 
   5354 
   5355   gdef = gpos->gdef;
   5356 
   5357   if ( CHECK_Property( gdef, IN_CURITEM(), flags, &property ) )
   5358     return error;
   5359 
   5360   bgc = ccpf3->BacktrackGlyphCount;
   5361   igc = ccpf3->InputGlyphCount;
   5362   lgc = ccpf3->LookaheadGlyphCount;
   5363 
   5364   if ( context_length != 0xFFFF && context_length < igc )
   5365     return HB_Err_Not_Covered;
   5366 
   5367   /* check whether context is too long; it is a first guess only */
   5368 
   5369   if ( bgc > buffer->in_pos || buffer->in_pos + igc + lgc > buffer->in_length )
   5370     return HB_Err_Not_Covered;
   5371 
   5372   if ( bgc )
   5373   {
   5374     /* Since we don't know in advance the number of glyphs to inspect,
   5375        we search backwards for matches in the backtrack glyph array    */
   5376 
   5377     bc       = ccpf3->BacktrackCoverage;
   5378 
   5379     for ( i = 0, j = buffer->in_pos - 1; i < bgc; i++, j-- )
   5380     {
   5381       while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5382       {
   5383 	if ( error && error != HB_Err_Not_Covered )
   5384 	  return error;
   5385 
   5386 	if ( j + 1 == bgc - i )
   5387 	  return HB_Err_Not_Covered;
   5388 	j--;
   5389       }
   5390 
   5391       error = _HB_OPEN_Coverage_Index( &bc[i], IN_GLYPH( j ), &index );
   5392       if ( error )
   5393 	return error;
   5394     }
   5395   }
   5396 
   5397   ic       = ccpf3->InputCoverage;
   5398 
   5399   for ( i = 0, j = buffer->in_pos; i < igc; i++, j++ )
   5400   {
   5401     /* We already called CHECK_Property for IN_GLYPH ( buffer->in_pos ) */
   5402     while ( j > buffer->in_pos && CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5403     {
   5404       if ( error && error != HB_Err_Not_Covered )
   5405 	return error;
   5406 
   5407       if ( j + igc - i + lgc == (HB_Int)buffer->in_length )
   5408 	return HB_Err_Not_Covered;
   5409       j++;
   5410     }
   5411 
   5412     error = _HB_OPEN_Coverage_Index( &ic[i], IN_GLYPH( j ), &index );
   5413     if ( error )
   5414       return error;
   5415   }
   5416 
   5417   /* we are starting to check for lookahead glyphs right after the
   5418      last context glyph                                            */
   5419 
   5420   lc       = ccpf3->LookaheadCoverage;
   5421 
   5422   for ( i = 0; i < lgc; i++, j++ )
   5423   {
   5424     while ( CHECK_Property( gdef, IN_ITEM( j ), flags, &property ) )
   5425     {
   5426       if ( error && error != HB_Err_Not_Covered )
   5427 	return error;
   5428 
   5429       if ( j + lgc - i == (HB_Int)buffer->in_length )
   5430 	return HB_Err_Not_Covered;
   5431       j++;
   5432     }
   5433 
   5434     error = _HB_OPEN_Coverage_Index( &lc[i], IN_GLYPH( j ), &index );
   5435     if ( error )
   5436       return error;
   5437   }
   5438 
   5439   return Do_ContextPos( gpi, igc,
   5440 			ccpf3->PosCount,
   5441 			ccpf3->PosLookupRecord,
   5442 			buffer,
   5443 			nesting_level );
   5444 }
   5445 
   5446 
   5447 static HB_Error  Lookup_ChainContextPos(
   5448 		   GPOS_Instance*        gpi,
   5449 		   HB_GPOS_SubTable* st,
   5450 		   HB_Buffer            buffer,
   5451 		   HB_UShort             flags,
   5452 		   HB_UShort             context_length,
   5453 		   int                   nesting_level )
   5454 {
   5455   HB_ChainContextPos*  ccp = &st->chain;
   5456 
   5457   switch ( ccp->PosFormat )
   5458   {
   5459   case 1:
   5460     return Lookup_ChainContextPos1( gpi, &ccp->ccpf.ccpf1, buffer,
   5461 				    flags, context_length,
   5462 				    nesting_level );
   5463 
   5464   case 2:
   5465     return Lookup_ChainContextPos2( gpi, &ccp->ccpf.ccpf2, buffer,
   5466 				    flags, context_length,
   5467 				    nesting_level );
   5468 
   5469   case 3:
   5470     return Lookup_ChainContextPos3( gpi, &ccp->ccpf.ccpf3, buffer,
   5471 				    flags, context_length,
   5472 				    nesting_level );
   5473 
   5474   default:
   5475     return ERR(HB_Err_Invalid_SubTable_Format);
   5476   }
   5477 
   5478   return HB_Err_Ok;               /* never reached */
   5479 }
   5480 
   5481 
   5482 
   5483 /***********
   5484  * GPOS API
   5485  ***********/
   5486 
   5487 
   5488 
   5489 HB_Error  HB_GPOS_Select_Script( HB_GPOSHeader*  gpos,
   5490 				 HB_UInt         script_tag,
   5491 				 HB_UShort*       script_index )
   5492 {
   5493   HB_UShort          n;
   5494 
   5495   HB_ScriptList*    sl;
   5496   HB_ScriptRecord*  sr;
   5497 
   5498 
   5499   if ( !gpos || !script_index )
   5500     return ERR(HB_Err_Invalid_Argument);
   5501 
   5502   sl = &gpos->ScriptList;
   5503   sr = sl->ScriptRecord;
   5504 
   5505   for ( n = 0; n < sl->ScriptCount; n++ )
   5506     if ( script_tag == sr[n].ScriptTag )
   5507     {
   5508       *script_index = n;
   5509 
   5510       return HB_Err_Ok;
   5511     }
   5512 
   5513   return HB_Err_Not_Covered;
   5514 }
   5515 
   5516 
   5517 
   5518 HB_Error  HB_GPOS_Select_Language( HB_GPOSHeader*  gpos,
   5519 				   HB_UInt         language_tag,
   5520 				   HB_UShort        script_index,
   5521 				   HB_UShort*       language_index,
   5522 				   HB_UShort*       req_feature_index )
   5523 {
   5524   HB_UShort           n;
   5525 
   5526   HB_ScriptList*     sl;
   5527   HB_ScriptRecord*   sr;
   5528   HB_ScriptTable*         s;
   5529   HB_LangSysRecord*  lsr;
   5530 
   5531 
   5532   if ( !gpos || !language_index || !req_feature_index )
   5533     return ERR(HB_Err_Invalid_Argument);
   5534 
   5535   sl = &gpos->ScriptList;
   5536   sr = sl->ScriptRecord;
   5537 
   5538   if ( script_index >= sl->ScriptCount )
   5539     return ERR(HB_Err_Invalid_Argument);
   5540 
   5541   s   = &sr[script_index].Script;
   5542   lsr = s->LangSysRecord;
   5543 
   5544   for ( n = 0; n < s->LangSysCount; n++ )
   5545     if ( language_tag == lsr[n].LangSysTag )
   5546     {
   5547       *language_index = n;
   5548       *req_feature_index = lsr[n].LangSys.ReqFeatureIndex;
   5549 
   5550       return HB_Err_Ok;
   5551     }
   5552 
   5553   return HB_Err_Not_Covered;
   5554 }
   5555 
   5556 
   5557 /* selecting 0xFFFF for language_index asks for the values of the
   5558    default language (DefaultLangSys)                              */
   5559 
   5560 
   5561 HB_Error  HB_GPOS_Select_Feature( HB_GPOSHeader*  gpos,
   5562 				  HB_UInt         feature_tag,
   5563 				  HB_UShort        script_index,
   5564 				  HB_UShort        language_index,
   5565 				  HB_UShort*       feature_index )
   5566 {
   5567   HB_UShort           n;
   5568 
   5569   HB_ScriptList*     sl;
   5570   HB_ScriptRecord*   sr;
   5571   HB_ScriptTable*         s;
   5572   HB_LangSysRecord*  lsr;
   5573   HB_LangSys*        ls;
   5574   HB_UShort*          fi;
   5575 
   5576   HB_FeatureList*    fl;
   5577   HB_FeatureRecord*  fr;
   5578 
   5579 
   5580   if ( !gpos || !feature_index )
   5581     return ERR(HB_Err_Invalid_Argument);
   5582 
   5583   sl = &gpos->ScriptList;
   5584   sr = sl->ScriptRecord;
   5585 
   5586   fl = &gpos->FeatureList;
   5587   fr = fl->FeatureRecord;
   5588 
   5589   if ( script_index >= sl->ScriptCount )
   5590     return ERR(HB_Err_Invalid_Argument);
   5591 
   5592   s   = &sr[script_index].Script;
   5593   lsr = s->LangSysRecord;
   5594 
   5595   if ( language_index == 0xFFFF )
   5596     ls = &s->DefaultLangSys;
   5597   else
   5598   {
   5599     if ( language_index >= s->LangSysCount )
   5600       return ERR(HB_Err_Invalid_Argument);
   5601 
   5602     ls = &lsr[language_index].LangSys;
   5603   }
   5604 
   5605   fi = ls->FeatureIndex;
   5606 
   5607   for ( n = 0; n < ls->FeatureCount; n++ )
   5608   {
   5609     if ( fi[n] >= fl->FeatureCount )
   5610       return ERR(HB_Err_Invalid_SubTable_Format);
   5611 
   5612     if ( feature_tag == fr[fi[n]].FeatureTag )
   5613     {
   5614       *feature_index = fi[n];
   5615 
   5616       return HB_Err_Ok;
   5617     }
   5618   }
   5619 
   5620   return HB_Err_Not_Covered;
   5621 }
   5622 
   5623 
   5624 /* The next three functions return a null-terminated list */
   5625 
   5626 
   5627 HB_Error  HB_GPOS_Query_Scripts( HB_GPOSHeader*  gpos,
   5628 				 HB_UInt**       script_tag_list )
   5629 {
   5630   HB_Error           error;
   5631   HB_UShort          n;
   5632   HB_UInt*          stl;
   5633 
   5634   HB_ScriptList*    sl;
   5635   HB_ScriptRecord*  sr;
   5636 
   5637 
   5638   if ( !gpos || !script_tag_list )
   5639     return ERR(HB_Err_Invalid_Argument);
   5640 
   5641   sl = &gpos->ScriptList;
   5642   sr = sl->ScriptRecord;
   5643 
   5644   if ( ALLOC_ARRAY( stl, sl->ScriptCount + 1, HB_UInt ) )
   5645     return error;
   5646 
   5647   for ( n = 0; n < sl->ScriptCount; n++ )
   5648     stl[n] = sr[n].ScriptTag;
   5649   stl[n] = 0;
   5650 
   5651   *script_tag_list = stl;
   5652 
   5653   return HB_Err_Ok;
   5654 }
   5655 
   5656 
   5657 
   5658 HB_Error  HB_GPOS_Query_Languages( HB_GPOSHeader*  gpos,
   5659 				   HB_UShort        script_index,
   5660 				   HB_UInt**       language_tag_list )
   5661 {
   5662   HB_Error            error;
   5663   HB_UShort           n;
   5664   HB_UInt*           ltl;
   5665 
   5666   HB_ScriptList*     sl;
   5667   HB_ScriptRecord*   sr;
   5668   HB_ScriptTable*    s;
   5669   HB_LangSysRecord*  lsr;
   5670 
   5671 
   5672   if ( !gpos || !language_tag_list )
   5673     return ERR(HB_Err_Invalid_Argument);
   5674 
   5675   sl = &gpos->ScriptList;
   5676   sr = sl->ScriptRecord;
   5677 
   5678   if ( script_index >= sl->ScriptCount )
   5679     return ERR(HB_Err_Invalid_Argument);
   5680 
   5681   s   = &sr[script_index].Script;
   5682   lsr = s->LangSysRecord;
   5683 
   5684   if ( ALLOC_ARRAY( ltl, s->LangSysCount + 1, HB_UInt ) )
   5685     return error;
   5686 
   5687   for ( n = 0; n < s->LangSysCount; n++ )
   5688     ltl[n] = lsr[n].LangSysTag;
   5689   ltl[n] = 0;
   5690 
   5691   *language_tag_list = ltl;
   5692 
   5693   return HB_Err_Ok;
   5694 }
   5695 
   5696 
   5697 /* selecting 0xFFFF for language_index asks for the values of the
   5698    default language (DefaultLangSys)                              */
   5699 
   5700 
   5701 HB_Error  HB_GPOS_Query_Features( HB_GPOSHeader*  gpos,
   5702 				  HB_UShort        script_index,
   5703 				  HB_UShort        language_index,
   5704 				  HB_UInt**       feature_tag_list )
   5705 {
   5706   HB_UShort           n;
   5707   HB_Error            error;
   5708   HB_UInt*           ftl;
   5709 
   5710   HB_ScriptList*     sl;
   5711   HB_ScriptRecord*   sr;
   5712   HB_ScriptTable*    s;
   5713   HB_LangSysRecord*  lsr;
   5714   HB_LangSys*        ls;
   5715   HB_UShort*          fi;
   5716 
   5717   HB_FeatureList*    fl;
   5718   HB_FeatureRecord*  fr;
   5719 
   5720 
   5721   if ( !gpos || !feature_tag_list )
   5722     return ERR(HB_Err_Invalid_Argument);
   5723 
   5724   sl = &gpos->ScriptList;
   5725   sr = sl->ScriptRecord;
   5726 
   5727   fl = &gpos->FeatureList;
   5728   fr = fl->FeatureRecord;
   5729 
   5730   if ( script_index >= sl->ScriptCount )
   5731     return ERR(HB_Err_Invalid_Argument);
   5732 
   5733   s   = &sr[script_index].Script;
   5734   lsr = s->LangSysRecord;
   5735 
   5736   if ( language_index == 0xFFFF )
   5737     ls = &s->DefaultLangSys;
   5738   else
   5739   {
   5740     if ( language_index >= s->LangSysCount )
   5741       return ERR(HB_Err_Invalid_Argument);
   5742 
   5743     ls = &lsr[language_index].LangSys;
   5744   }
   5745 
   5746   fi = ls->FeatureIndex;
   5747 
   5748   if ( ALLOC_ARRAY( ftl, ls->FeatureCount + 1, HB_UInt ) )
   5749     return error;
   5750 
   5751   for ( n = 0; n < ls->FeatureCount; n++ )
   5752   {
   5753     if ( fi[n] >= fl->FeatureCount )
   5754     {
   5755       FREE( ftl );
   5756       return ERR(HB_Err_Invalid_SubTable_Format);
   5757     }
   5758     ftl[n] = fr[fi[n]].FeatureTag;
   5759   }
   5760   ftl[n] = 0;
   5761 
   5762   *feature_tag_list = ftl;
   5763 
   5764   return HB_Err_Ok;
   5765 }
   5766 
   5767 
   5768 /* Do an individual subtable lookup.  Returns HB_Err_Ok if positioning
   5769    has been done, or HB_Err_Not_Covered if not.                        */
   5770 static HB_Error  GPOS_Do_Glyph_Lookup( GPOS_Instance*    gpi,
   5771 				       HB_UShort         lookup_index,
   5772 				       HB_Buffer        buffer,
   5773 				       HB_UShort         context_length,
   5774 				       int               nesting_level )
   5775 {
   5776   HB_Error             error = HB_Err_Not_Covered;
   5777   HB_UShort            i, flags, lookup_count;
   5778   HB_GPOSHeader*       gpos = gpi->gpos;
   5779   HB_Lookup*           lo;
   5780   int		       lookup_type;
   5781 
   5782 
   5783   nesting_level++;
   5784 
   5785   if ( nesting_level > HB_MAX_NESTING_LEVEL )
   5786     return ERR(HB_Err_Not_Covered); /* ERR() call intended */
   5787 
   5788   lookup_count = gpos->LookupList.LookupCount;
   5789   if (lookup_index >= lookup_count)
   5790     return error;
   5791 
   5792   lo    = &gpos->LookupList.Lookup[lookup_index];
   5793   flags = lo->LookupFlag;
   5794   lookup_type = lo->LookupType;
   5795 
   5796   for ( i = 0; i < lo->SubTableCount; i++ )
   5797   {
   5798     HB_GPOS_SubTable *st = &lo->SubTable[i].st.gpos;
   5799 
   5800     switch (lookup_type) {
   5801       case HB_GPOS_LOOKUP_SINGLE:
   5802         error = Lookup_SinglePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5803       case HB_GPOS_LOOKUP_PAIR:
   5804 	error = Lookup_PairPos		( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5805       case HB_GPOS_LOOKUP_CURSIVE:
   5806 	error = Lookup_CursivePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5807       case HB_GPOS_LOOKUP_MARKBASE:
   5808 	error = Lookup_MarkBasePos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5809       case HB_GPOS_LOOKUP_MARKLIG:
   5810 	error = Lookup_MarkLigPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5811       case HB_GPOS_LOOKUP_MARKMARK:
   5812 	error = Lookup_MarkMarkPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5813       case HB_GPOS_LOOKUP_CONTEXT:
   5814 	error = Lookup_ContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5815       case HB_GPOS_LOOKUP_CHAIN:
   5816 	error = Lookup_ChainContextPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;
   5817     /*case HB_GPOS_LOOKUP_EXTENSION:
   5818 	error = Lookup_ExtensionPos	( gpi, st, buffer, flags, context_length, nesting_level ); break;*/
   5819       default:
   5820 	error = HB_Err_Not_Covered;
   5821     }
   5822 
   5823     /* Check whether we have a successful positioning or an error other
   5824        than HB_Err_Not_Covered                                         */
   5825     if ( error != HB_Err_Not_Covered )
   5826       return error;
   5827   }
   5828 
   5829   return HB_Err_Not_Covered;
   5830 }
   5831 
   5832 
   5833 HB_INTERNAL HB_Error
   5834 _HB_GPOS_Load_SubTable( HB_GPOS_SubTable* st,
   5835 			HB_Stream         stream,
   5836 			HB_UShort         lookup_type )
   5837 {
   5838   switch ( lookup_type ) {
   5839     case HB_GPOS_LOOKUP_SINGLE:		return Load_SinglePos		( st, stream );
   5840     case HB_GPOS_LOOKUP_PAIR:		return Load_PairPos		( st, stream );
   5841     case HB_GPOS_LOOKUP_CURSIVE:	return Load_CursivePos		( st, stream );
   5842     case HB_GPOS_LOOKUP_MARKBASE:	return Load_MarkBasePos		( st, stream );
   5843     case HB_GPOS_LOOKUP_MARKLIG:	return Load_MarkLigPos		( st, stream );
   5844     case HB_GPOS_LOOKUP_MARKMARK:	return Load_MarkMarkPos		( st, stream );
   5845     case HB_GPOS_LOOKUP_CONTEXT:	return Load_ContextPos		( st, stream );
   5846     case HB_GPOS_LOOKUP_CHAIN:		return Load_ChainContextPos	( st, stream );
   5847   /*case HB_GPOS_LOOKUP_EXTENSION:	return Load_ExtensionPos	( st, stream );*/
   5848     default:				return ERR(HB_Err_Invalid_SubTable_Format);
   5849   }
   5850 }
   5851 
   5852 
   5853 HB_INTERNAL void
   5854 _HB_GPOS_Free_SubTable( HB_GPOS_SubTable* st,
   5855 			HB_UShort         lookup_type )
   5856 {
   5857   switch ( lookup_type ) {
   5858     case HB_GPOS_LOOKUP_SINGLE:		Free_SinglePos		( st ); return;
   5859     case HB_GPOS_LOOKUP_PAIR:		Free_PairPos		( st ); return;
   5860     case HB_GPOS_LOOKUP_CURSIVE:	Free_CursivePos		( st ); return;
   5861     case HB_GPOS_LOOKUP_MARKBASE:	Free_MarkBasePos	( st ); return;
   5862     case HB_GPOS_LOOKUP_MARKLIG:	Free_MarkLigPos		( st ); return;
   5863     case HB_GPOS_LOOKUP_MARKMARK:	Free_MarkMarkPos	( st ); return;
   5864     case HB_GPOS_LOOKUP_CONTEXT:	Free_ContextPos		( st ); return;
   5865     case HB_GPOS_LOOKUP_CHAIN:		Free_ChainContextPos	( st ); return;
   5866   /*case HB_GPOS_LOOKUP_EXTENSION:	Free_ExtensionPos	( st ); return;*/
   5867     default:									return;
   5868   }
   5869 }
   5870 
   5871 
   5872 /* apply one lookup to the input string object */
   5873 
   5874 static HB_Error  GPOS_Do_String_Lookup( GPOS_Instance*    gpi,
   5875 				   HB_UShort         lookup_index,
   5876 				   HB_Buffer        buffer )
   5877 {
   5878   HB_Error         error, retError = HB_Err_Not_Covered;
   5879   HB_GPOSHeader*  gpos = gpi->gpos;
   5880 
   5881   HB_UInt*  properties = gpos->LookupList.Properties;
   5882 
   5883   const int       nesting_level = 0;
   5884   /* 0xFFFF indicates that we don't have a context length yet */
   5885   const HB_UShort context_length = 0xFFFF;
   5886 
   5887 
   5888   gpi->last  = 0xFFFF;     /* no last valid glyph for cursive pos. */
   5889 
   5890   buffer->in_pos = 0;
   5891   while ( buffer->in_pos < buffer->in_length )
   5892   {
   5893     if ( ~IN_PROPERTIES( buffer->in_pos ) & properties[lookup_index] )
   5894     {
   5895       /* Note that the connection between mark and base glyphs hold
   5896 	 exactly one (string) lookup.  For example, it would be possible
   5897 	 that in the first lookup, mark glyph X is attached to base
   5898 	 glyph A, and in the next lookup it is attached to base glyph B.
   5899 	 It is up to the font designer to provide meaningful lookups and
   5900 	 lookup order.                                                   */
   5901 
   5902       error = GPOS_Do_Glyph_Lookup( gpi, lookup_index, buffer, context_length, nesting_level );
   5903       if ( error && error != HB_Err_Not_Covered )
   5904 	return error;
   5905     }
   5906     else
   5907     {
   5908       /* Contrary to properties defined in GDEF, user-defined properties
   5909 	 will always stop a possible cursive positioning.                */
   5910       gpi->last = 0xFFFF;
   5911 
   5912       error = HB_Err_Not_Covered;
   5913     }
   5914 
   5915     if ( error == HB_Err_Not_Covered )
   5916       (buffer->in_pos)++;
   5917     else
   5918       retError = error;
   5919   }
   5920 
   5921   return retError;
   5922 }
   5923 
   5924 
   5925 static HB_Error  Position_CursiveChain ( HB_Buffer     buffer )
   5926 {
   5927   HB_UInt   i, j;
   5928   HB_Position positions = buffer->positions;
   5929 
   5930   /* First handle all left-to-right connections */
   5931   for (j = 0; j < buffer->in_length; j++)
   5932   {
   5933     if (positions[j].cursive_chain > 0)
   5934       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
   5935   }
   5936 
   5937   /* Then handle all right-to-left connections */
   5938   for (i = buffer->in_length; i > 0; i--)
   5939   {
   5940     j = i - 1;
   5941 
   5942     if (positions[j].cursive_chain < 0)
   5943       positions[j].y_pos += positions[j - positions[j].cursive_chain].y_pos;
   5944   }
   5945 
   5946   return HB_Err_Ok;
   5947 }
   5948 
   5949 
   5950 HB_Error  HB_GPOS_Add_Feature( HB_GPOSHeader*  gpos,
   5951 			       HB_UShort        feature_index,
   5952 			       HB_UInt          property )
   5953 {
   5954   HB_UShort    i;
   5955 
   5956   HB_Feature  feature;
   5957   HB_UInt*     properties;
   5958   HB_UShort*   index;
   5959   HB_UShort    lookup_count;
   5960 
   5961   /* Each feature can only be added once */
   5962 
   5963   if ( !gpos ||
   5964        feature_index >= gpos->FeatureList.FeatureCount ||
   5965        gpos->FeatureList.ApplyCount == gpos->FeatureList.FeatureCount )
   5966     return ERR(HB_Err_Invalid_Argument);
   5967 
   5968   gpos->FeatureList.ApplyOrder[gpos->FeatureList.ApplyCount++] = feature_index;
   5969 
   5970   properties = gpos->LookupList.Properties;
   5971 
   5972   feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
   5973   index   = feature.LookupListIndex;
   5974   lookup_count = gpos->LookupList.LookupCount;
   5975 
   5976   for ( i = 0; i < feature.LookupListCount; i++ )
   5977   {
   5978     HB_UShort lookup_index = index[i];
   5979     if (lookup_index < lookup_count)
   5980       properties[lookup_index] |= property;
   5981   }
   5982 
   5983   return HB_Err_Ok;
   5984 }
   5985 
   5986 
   5987 
   5988 HB_Error  HB_GPOS_Clear_Features( HB_GPOSHeader*  gpos )
   5989 {
   5990   HB_UShort i;
   5991 
   5992   HB_UInt*  properties;
   5993 
   5994 
   5995   if ( !gpos )
   5996     return ERR(HB_Err_Invalid_Argument);
   5997 
   5998   gpos->FeatureList.ApplyCount = 0;
   5999 
   6000   properties = gpos->LookupList.Properties;
   6001 
   6002   for ( i = 0; i < gpos->LookupList.LookupCount; i++ )
   6003     properties[i] = 0;
   6004 
   6005   return HB_Err_Ok;
   6006 }
   6007 
   6008 #ifdef HB_SUPPORT_MULTIPLE_MASTER
   6009 HB_Error  HB_GPOS_Register_MM_Function( HB_GPOSHeader*  gpos,
   6010 					HB_MMFunction   mmfunc,
   6011 					void*            data )
   6012 {
   6013   if ( !gpos )
   6014     return ERR(HB_Err_Invalid_Argument);
   6015 
   6016   gpos->mmfunc = mmfunc;
   6017   gpos->data   = data;
   6018 
   6019   return HB_Err_Ok;
   6020 }
   6021 #endif
   6022 
   6023 /* If `dvi' is TRUE, glyph contour points for anchor points and device
   6024    tables are ignored -- you will get device independent values.         */
   6025 
   6026 
   6027 HB_Error  HB_GPOS_Apply_String( HB_Font            font,
   6028 				HB_GPOSHeader*    gpos,
   6029 				HB_UShort          load_flags,
   6030 				HB_Buffer         buffer,
   6031 				HB_Bool            dvi,
   6032 				HB_Bool            r2l )
   6033 {
   6034   HB_Error       error, retError = HB_Err_Not_Covered;
   6035   GPOS_Instance  gpi;
   6036   int            i, j, lookup_count, num_features;
   6037 
   6038   if ( !font || !gpos || !buffer )
   6039     return ERR(HB_Err_Invalid_Argument);
   6040 
   6041   if ( buffer->in_length == 0 )
   6042     return HB_Err_Not_Covered;
   6043 
   6044   gpi.font       = font;
   6045   gpi.gpos       = gpos;
   6046   gpi.load_flags = load_flags;
   6047   gpi.r2l        = r2l;
   6048   gpi.dvi        = dvi;
   6049 
   6050   lookup_count = gpos->LookupList.LookupCount;
   6051   num_features = gpos->FeatureList.ApplyCount;
   6052 
   6053   if ( num_features )
   6054     {
   6055       error = _hb_buffer_clear_positions( buffer );
   6056       if ( error )
   6057 	return error;
   6058     }
   6059 
   6060   for ( i = 0; i < num_features; i++ )
   6061   {
   6062     HB_UShort  feature_index = gpos->FeatureList.ApplyOrder[i];
   6063     HB_Feature feature = gpos->FeatureList.FeatureRecord[feature_index].Feature;
   6064 
   6065     for ( j = 0; j < feature.LookupListCount; j++ )
   6066     {
   6067       HB_UShort lookup_index = feature.LookupListIndex[j];
   6068 
   6069       /* Skip nonexistant lookups */
   6070       if (lookup_index >= lookup_count)
   6071        continue;
   6072 
   6073       error = GPOS_Do_String_Lookup( &gpi, lookup_index, buffer );
   6074       if ( error )
   6075       {
   6076 	if ( error != HB_Err_Not_Covered )
   6077 	  return error;
   6078       }
   6079       else
   6080 	retError = error;
   6081     }
   6082   }
   6083 
   6084   if ( num_features )
   6085     {
   6086   error = Position_CursiveChain ( buffer );
   6087   if ( error )
   6088     return error;
   6089     }
   6090 
   6091   return retError;
   6092 }
   6093 
   6094 /* END */
   6095