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  *
      5  * This is part of HarfBuzz, an OpenType Layout engine library.
      6  *
      7  * Permission is hereby granted, without written agreement and without
      8  * license or royalty fees, to use, copy, modify, and distribute this
      9  * software and its documentation for any purpose, provided that the
     10  * above copyright notice and the following two paragraphs appear in
     11  * all copies of this software.
     12  *
     13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
     14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
     15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
     16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     17  * DAMAGE.
     18  *
     19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
     20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
     21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
     22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
     23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
     24  */
     25 
     26 #include "harfbuzz-impl.h"
     27 #include "harfbuzz-open-private.h"
     28 
     29 
     30 /***************************
     31  * Script related functions
     32  ***************************/
     33 
     34 
     35 /* LangSys */
     36 
     37 static HB_Error  Load_LangSys( HB_LangSys*  ls,
     38 			       HB_Stream     stream )
     39 {
     40   HB_Error   error;
     41   HB_UShort  n, count;
     42   HB_UShort* fi;
     43 
     44 
     45   if ( ACCESS_Frame( 6L ) )
     46     return error;
     47 
     48   ls->LookupOrderOffset    = GET_UShort();    /* should be 0 */
     49   ls->ReqFeatureIndex      = GET_UShort();
     50   count = ls->FeatureCount = GET_UShort();
     51 
     52   FORGET_Frame();
     53 
     54   ls->FeatureIndex = NULL;
     55 
     56   if ( ALLOC_ARRAY( ls->FeatureIndex, count, HB_UShort ) )
     57     return error;
     58 
     59   if ( ACCESS_Frame( count * 2L ) )
     60   {
     61     FREE( ls->FeatureIndex );
     62     return error;
     63   }
     64 
     65   fi = ls->FeatureIndex;
     66 
     67   for ( n = 0; n < count; n++ )
     68     fi[n] = GET_UShort();
     69 
     70   FORGET_Frame();
     71 
     72   return HB_Err_Ok;
     73 }
     74 
     75 
     76 static void  Free_LangSys( HB_LangSys*  ls )
     77 {
     78   FREE( ls->FeatureIndex );
     79 }
     80 
     81 
     82 /* Script */
     83 
     84 static HB_Error  Load_Script( HB_ScriptTable*  s,
     85 			      HB_Stream    stream )
     86 {
     87   HB_Error   error;
     88   HB_UShort  n, m, count;
     89   HB_UInt   cur_offset, new_offset, base_offset;
     90 
     91   HB_LangSysRecord*  lsr;
     92 
     93 
     94   base_offset = FILE_Pos();
     95 
     96   if ( ACCESS_Frame( 2L ) )
     97     return error;
     98 
     99   new_offset = GET_UShort() + base_offset;
    100 
    101   FORGET_Frame();
    102 
    103   if ( new_offset != base_offset )        /* not a NULL offset */
    104   {
    105     cur_offset = FILE_Pos();
    106     if ( FILE_Seek( new_offset ) ||
    107 	 ( error = Load_LangSys( &s->DefaultLangSys,
    108 				 stream ) ) != HB_Err_Ok )
    109       return error;
    110     (void)FILE_Seek( cur_offset );
    111   }
    112   else
    113   {
    114     /* we create a DefaultLangSys table with no entries */
    115 
    116     s->DefaultLangSys.LookupOrderOffset = 0;
    117     s->DefaultLangSys.ReqFeatureIndex   = 0xFFFF;
    118     s->DefaultLangSys.FeatureCount      = 0;
    119     s->DefaultLangSys.FeatureIndex      = NULL;
    120   }
    121 
    122   if ( ACCESS_Frame( 2L ) )
    123     goto Fail2;
    124 
    125   count = s->LangSysCount = GET_UShort();
    126 
    127   /* safety check; otherwise the official handling of TrueType Open
    128      fonts won't work */
    129 
    130   if ( s->LangSysCount == 0 && s->DefaultLangSys.FeatureCount == 0 )
    131   {
    132     error = HB_Err_Not_Covered;
    133     goto Fail2;
    134   }
    135 
    136   FORGET_Frame();
    137 
    138   s->LangSysRecord = NULL;
    139 
    140   if ( ALLOC_ARRAY( s->LangSysRecord, count, HB_LangSysRecord ) )
    141     goto Fail2;
    142 
    143   lsr = s->LangSysRecord;
    144 
    145   for ( n = 0; n < count; n++ )
    146   {
    147     if ( ACCESS_Frame( 6L ) )
    148       goto Fail1;
    149 
    150     lsr[n].LangSysTag = GET_ULong();
    151     new_offset = GET_UShort() + base_offset;
    152 
    153     FORGET_Frame();
    154 
    155     cur_offset = FILE_Pos();
    156     if ( FILE_Seek( new_offset ) ||
    157 	 ( error = Load_LangSys( &lsr[n].LangSys, stream ) ) != HB_Err_Ok )
    158       goto Fail1;
    159     (void)FILE_Seek( cur_offset );
    160   }
    161 
    162   return HB_Err_Ok;
    163 
    164 Fail1:
    165   for ( m = 0; m < n; m++ )
    166     Free_LangSys( &lsr[m].LangSys );
    167 
    168   FREE( s->LangSysRecord );
    169 
    170 Fail2:
    171   Free_LangSys( &s->DefaultLangSys );
    172   return error;
    173 }
    174 
    175 
    176 static void  Free_Script( HB_ScriptTable*  s )
    177 {
    178   HB_UShort           n, count;
    179 
    180   HB_LangSysRecord*  lsr;
    181 
    182 
    183   Free_LangSys( &s->DefaultLangSys );
    184 
    185   if ( s->LangSysRecord )
    186   {
    187     count = s->LangSysCount;
    188     lsr   = s->LangSysRecord;
    189 
    190     for ( n = 0; n < count; n++ )
    191       Free_LangSys( &lsr[n].LangSys );
    192 
    193     FREE( lsr );
    194   }
    195 }
    196 
    197 
    198 /* ScriptList */
    199 
    200 HB_INTERNAL HB_Error
    201 _HB_OPEN_Load_ScriptList( HB_ScriptList* sl,
    202 			   HB_Stream        stream )
    203 {
    204   HB_Error   error;
    205 
    206   HB_UShort          n, script_count;
    207   HB_UInt           cur_offset, new_offset, base_offset;
    208 
    209   HB_ScriptRecord*  sr;
    210 
    211 
    212   base_offset = FILE_Pos();
    213 
    214   if ( ACCESS_Frame( 2L ) )
    215     return error;
    216 
    217   script_count = GET_UShort();
    218 
    219   FORGET_Frame();
    220 
    221   sl->ScriptRecord = NULL;
    222 
    223   if ( ALLOC_ARRAY( sl->ScriptRecord, script_count, HB_ScriptRecord ) )
    224     return error;
    225 
    226   sr = sl->ScriptRecord;
    227 
    228   sl->ScriptCount= 0;
    229   for ( n = 0; n < script_count; n++ )
    230   {
    231     if ( ACCESS_Frame( 6L ) )
    232       goto Fail;
    233 
    234     sr[sl->ScriptCount].ScriptTag = GET_ULong();
    235     new_offset = GET_UShort() + base_offset;
    236 
    237     FORGET_Frame();
    238 
    239     cur_offset = FILE_Pos();
    240 
    241     if ( FILE_Seek( new_offset ) )
    242       goto Fail;
    243 
    244     error = Load_Script( &sr[sl->ScriptCount].Script, stream );
    245     if ( error == HB_Err_Ok )
    246       sl->ScriptCount += 1;
    247     else if ( error != HB_Err_Not_Covered )
    248       goto Fail;
    249 
    250     (void)FILE_Seek( cur_offset );
    251   }
    252 
    253   /* Empty tables are harmless and generated by fontforge.
    254    * See http://bugzilla.gnome.org/show_bug.cgi?id=347073
    255    */
    256 #if 0
    257   if ( sl->ScriptCount == 0 )
    258   {
    259     error = ERR(HB_Err_Invalid_SubTable);
    260     goto Fail;
    261   }
    262 #endif
    263 
    264   return HB_Err_Ok;
    265 
    266 Fail:
    267   for ( n = 0; n < sl->ScriptCount; n++ )
    268     Free_Script( &sr[n].Script );
    269 
    270   FREE( sl->ScriptRecord );
    271   return error;
    272 }
    273 
    274 
    275 HB_INTERNAL void
    276 _HB_OPEN_Free_ScriptList( HB_ScriptList* sl )
    277 {
    278   HB_UShort          n, count;
    279 
    280   HB_ScriptRecord*  sr;
    281 
    282 
    283   if ( sl->ScriptRecord )
    284   {
    285     count = sl->ScriptCount;
    286     sr    = sl->ScriptRecord;
    287 
    288     for ( n = 0; n < count; n++ )
    289       Free_Script( &sr[n].Script );
    290 
    291     FREE( sr );
    292   }
    293 }
    294 
    295 
    296 
    297 /*********************************
    298  * Feature List related functions
    299  *********************************/
    300 
    301 
    302 /* Feature */
    303 
    304 static HB_Error  Load_Feature( HB_Feature*  f,
    305 			       HB_Stream     stream )
    306 {
    307   HB_Error   error;
    308 
    309   HB_UShort   n, count;
    310 
    311   HB_UShort*  lli;
    312 
    313 
    314   if ( ACCESS_Frame( 4L ) )
    315     return error;
    316 
    317   f->FeatureParams           = GET_UShort();    /* should be 0 */
    318   count = f->LookupListCount = GET_UShort();
    319 
    320   FORGET_Frame();
    321 
    322   f->LookupListIndex = NULL;
    323 
    324   if ( ALLOC_ARRAY( f->LookupListIndex, count, HB_UShort ) )
    325     return error;
    326 
    327   lli = f->LookupListIndex;
    328 
    329   if ( ACCESS_Frame( count * 2L ) )
    330   {
    331     FREE( f->LookupListIndex );
    332     return error;
    333   }
    334 
    335   for ( n = 0; n < count; n++ )
    336     lli[n] = GET_UShort();
    337 
    338   FORGET_Frame();
    339 
    340   return HB_Err_Ok;
    341 }
    342 
    343 
    344 static void  Free_Feature( HB_Feature*  f )
    345 {
    346   FREE( f->LookupListIndex );
    347 }
    348 
    349 
    350 /* FeatureList */
    351 
    352 HB_INTERNAL HB_Error
    353 _HB_OPEN_Load_FeatureList( HB_FeatureList* fl,
    354 			    HB_Stream         stream )
    355 {
    356   HB_Error   error;
    357 
    358   HB_UShort           n, m, count;
    359   HB_UInt            cur_offset, new_offset, base_offset;
    360 
    361   HB_FeatureRecord*  fr;
    362 
    363 
    364   base_offset = FILE_Pos();
    365 
    366   if ( ACCESS_Frame( 2L ) )
    367     return error;
    368 
    369   count = fl->FeatureCount = GET_UShort();
    370 
    371   FORGET_Frame();
    372 
    373   fl->FeatureRecord = NULL;
    374 
    375   if ( ALLOC_ARRAY( fl->FeatureRecord, count, HB_FeatureRecord ) )
    376     return error;
    377   if ( ALLOC_ARRAY( fl->ApplyOrder, count, HB_UShort ) )
    378     goto Fail2;
    379 
    380   fl->ApplyCount = 0;
    381 
    382   fr = fl->FeatureRecord;
    383 
    384   for ( n = 0; n < count; n++ )
    385   {
    386     if ( ACCESS_Frame( 6L ) )
    387       goto Fail1;
    388 
    389     fr[n].FeatureTag = GET_ULong();
    390     new_offset = GET_UShort() + base_offset;
    391 
    392     FORGET_Frame();
    393 
    394     cur_offset = FILE_Pos();
    395     if ( FILE_Seek( new_offset ) ||
    396 	 ( error = Load_Feature( &fr[n].Feature, stream ) ) != HB_Err_Ok )
    397       goto Fail1;
    398     (void)FILE_Seek( cur_offset );
    399   }
    400 
    401   return HB_Err_Ok;
    402 
    403 Fail1:
    404   for ( m = 0; m < n; m++ )
    405     Free_Feature( &fr[m].Feature );
    406 
    407   FREE( fl->ApplyOrder );
    408 
    409 Fail2:
    410   FREE( fl->FeatureRecord );
    411 
    412   return error;
    413 }
    414 
    415 
    416 HB_INTERNAL void
    417 _HB_OPEN_Free_FeatureList( HB_FeatureList*  fl )
    418 {
    419   HB_UShort           n, count;
    420 
    421   HB_FeatureRecord*  fr;
    422 
    423 
    424   if ( fl->FeatureRecord )
    425   {
    426     count = fl->FeatureCount;
    427     fr    = fl->FeatureRecord;
    428 
    429     for ( n = 0; n < count; n++ )
    430       Free_Feature( &fr[n].Feature );
    431 
    432     FREE( fr );
    433   }
    434 
    435   FREE( fl->ApplyOrder );
    436 }
    437 
    438 
    439 
    440 /********************************
    441  * Lookup List related functions
    442  ********************************/
    443 
    444 /* the subroutines of the following two functions are defined in
    445    ftxgsub.c and ftxgpos.c respectively                          */
    446 
    447 
    448 /* SubTable */
    449 
    450 static HB_Error  Load_SubTable( HB_SubTable*  st,
    451 				HB_Stream     stream,
    452 				HB_Type       table_type,
    453 				HB_UShort     lookup_type )
    454 {
    455   if ( table_type == HB_Type_GSUB )
    456     return _HB_GSUB_Load_SubTable ( &st->st.gsub, stream, lookup_type );
    457   else
    458     return _HB_GPOS_Load_SubTable ( &st->st.gpos, stream, lookup_type );
    459 }
    460 
    461 
    462 static void  Free_SubTable( HB_SubTable*  st,
    463 			    HB_Type       table_type,
    464 			    HB_UShort      lookup_type )
    465 {
    466   if ( table_type == HB_Type_GSUB )
    467     _HB_GSUB_Free_SubTable ( &st->st.gsub, lookup_type );
    468   else
    469     _HB_GPOS_Free_SubTable ( &st->st.gpos, lookup_type );
    470 }
    471 
    472 
    473 /* Lookup */
    474 
    475 static HB_Error  Load_Lookup( HB_Lookup*   l,
    476 			      HB_Stream     stream,
    477 			      HB_Type      type )
    478 {
    479   HB_Error   error;
    480 
    481   HB_UShort      n, m, count;
    482   HB_UInt       cur_offset, new_offset, base_offset;
    483 
    484   HB_SubTable*  st;
    485 
    486   HB_Bool        is_extension = FALSE;
    487 
    488 
    489   base_offset = FILE_Pos();
    490 
    491   if ( ACCESS_Frame( 6L ) )
    492     return error;
    493 
    494   l->LookupType            = GET_UShort();
    495   l->LookupFlag            = GET_UShort();
    496   count = l->SubTableCount = GET_UShort();
    497 
    498   FORGET_Frame();
    499 
    500   l->SubTable = NULL;
    501 
    502   if ( ALLOC_ARRAY( l->SubTable, count, HB_SubTable ) )
    503     return error;
    504 
    505   st = l->SubTable;
    506 
    507   if ( ( type == HB_Type_GSUB && l->LookupType == HB_GSUB_LOOKUP_EXTENSION ) ||
    508        ( type == HB_Type_GPOS && l->LookupType == HB_GPOS_LOOKUP_EXTENSION ) )
    509     is_extension = TRUE;
    510 
    511   for ( n = 0; n < count; n++ )
    512   {
    513     if ( ACCESS_Frame( 2L ) )
    514       goto Fail;
    515 
    516     new_offset = GET_UShort() + base_offset;
    517 
    518     FORGET_Frame();
    519 
    520     cur_offset = FILE_Pos();
    521 
    522     if ( is_extension )
    523     {
    524       if ( FILE_Seek( new_offset ) || ACCESS_Frame( 8L ) )
    525 	goto Fail;
    526 
    527       if (GET_UShort() != 1) /* format should be 1 */
    528 	goto Fail;
    529 
    530       l->LookupType = GET_UShort();
    531       new_offset += GET_ULong();
    532 
    533       FORGET_Frame();
    534     }
    535 
    536     if ( FILE_Seek( new_offset ) ||
    537 	 ( error = Load_SubTable( &st[n], stream,
    538 				  type, l->LookupType ) ) != HB_Err_Ok )
    539       goto Fail;
    540     (void)FILE_Seek( cur_offset );
    541   }
    542 
    543   return HB_Err_Ok;
    544 
    545 Fail:
    546   for ( m = 0; m < n; m++ )
    547     Free_SubTable( &st[m], type, l->LookupType );
    548 
    549   FREE( l->SubTable );
    550   return error;
    551 }
    552 
    553 
    554 static void  Free_Lookup( HB_Lookup*   l,
    555 			  HB_Type      type)
    556 {
    557   HB_UShort      n, count;
    558 
    559   HB_SubTable*  st;
    560 
    561 
    562   if ( l->SubTable )
    563   {
    564     count = l->SubTableCount;
    565     st    = l->SubTable;
    566 
    567     for ( n = 0; n < count; n++ )
    568       Free_SubTable( &st[n], type, l->LookupType );
    569 
    570     FREE( st );
    571   }
    572 }
    573 
    574 
    575 /* LookupList */
    576 
    577 HB_INTERNAL HB_Error
    578 _HB_OPEN_Load_LookupList( HB_LookupList* ll,
    579 			   HB_Stream        stream,
    580 			   HB_Type         type )
    581 {
    582   HB_Error   error;
    583 
    584   HB_UShort    n, m, count;
    585   HB_UInt     cur_offset, new_offset, base_offset;
    586 
    587   HB_Lookup*  l;
    588 
    589 
    590   base_offset = FILE_Pos();
    591 
    592   if ( ACCESS_Frame( 2L ) )
    593     return error;
    594 
    595   count = ll->LookupCount = GET_UShort();
    596 
    597   FORGET_Frame();
    598 
    599   ll->Lookup = NULL;
    600 
    601   if ( ALLOC_ARRAY( ll->Lookup, count, HB_Lookup ) )
    602     return error;
    603   if ( ALLOC_ARRAY( ll->Properties, count, HB_UInt ) )
    604     goto Fail2;
    605 
    606   l = ll->Lookup;
    607 
    608   for ( n = 0; n < count; n++ )
    609   {
    610     if ( ACCESS_Frame( 2L ) )
    611       goto Fail1;
    612 
    613     new_offset = GET_UShort() + base_offset;
    614 
    615     FORGET_Frame();
    616 
    617     cur_offset = FILE_Pos();
    618     if ( FILE_Seek( new_offset ) ||
    619 	 ( error = Load_Lookup( &l[n], stream, type ) ) != HB_Err_Ok )
    620       goto Fail1;
    621     (void)FILE_Seek( cur_offset );
    622   }
    623 
    624   return HB_Err_Ok;
    625 
    626 Fail1:
    627   FREE( ll->Properties );
    628 
    629   for ( m = 0; m < n; m++ )
    630     Free_Lookup( &l[m], type );
    631 
    632 Fail2:
    633   FREE( ll->Lookup );
    634   return error;
    635 }
    636 
    637 
    638 HB_INTERNAL void
    639 _HB_OPEN_Free_LookupList( HB_LookupList* ll,
    640 		       HB_Type         type )
    641 {
    642   HB_UShort    n, count;
    643 
    644   HB_Lookup*  l;
    645 
    646 
    647   FREE( ll->Properties );
    648 
    649   if ( ll->Lookup )
    650   {
    651     count = ll->LookupCount;
    652     l     = ll->Lookup;
    653 
    654     for ( n = 0; n < count; n++ )
    655       Free_Lookup( &l[n], type );
    656 
    657     FREE( l );
    658   }
    659 }
    660 
    661 
    662 
    663 /*****************************
    664  * Coverage related functions
    665  *****************************/
    666 
    667 
    668 /* CoverageFormat1 */
    669 
    670 static HB_Error  Load_Coverage1( HB_CoverageFormat1*  cf1,
    671 				 HB_Stream             stream )
    672 {
    673   HB_Error   error;
    674 
    675   HB_UShort  n, count;
    676 
    677   HB_UShort* ga;
    678 
    679 
    680   if ( ACCESS_Frame( 2L ) )
    681     return error;
    682 
    683   count = cf1->GlyphCount = GET_UShort();
    684 
    685   FORGET_Frame();
    686 
    687   cf1->GlyphArray = NULL;
    688 
    689   if ( ALLOC_ARRAY( cf1->GlyphArray, count, HB_UShort ) )
    690     return error;
    691 
    692   ga = cf1->GlyphArray;
    693 
    694   if ( ACCESS_Frame( count * 2L ) )
    695   {
    696     FREE( cf1->GlyphArray );
    697     return error;
    698   }
    699 
    700   for ( n = 0; n < count; n++ )
    701     ga[n] = GET_UShort();
    702 
    703   FORGET_Frame();
    704 
    705   return HB_Err_Ok;
    706 }
    707 
    708 
    709 static void  Free_Coverage1( HB_CoverageFormat1*  cf1)
    710 {
    711   FREE( cf1->GlyphArray );
    712 }
    713 
    714 
    715 /* CoverageFormat2 */
    716 
    717 static HB_Error  Load_Coverage2( HB_CoverageFormat2*  cf2,
    718 				 HB_Stream             stream )
    719 {
    720   HB_Error   error;
    721 
    722   HB_UShort         n, count;
    723 
    724   HB_RangeRecord*  rr;
    725 
    726 
    727   if ( ACCESS_Frame( 2L ) )
    728     return error;
    729 
    730   count = cf2->RangeCount = GET_UShort();
    731 
    732   FORGET_Frame();
    733 
    734   cf2->RangeRecord = NULL;
    735 
    736   if ( ALLOC_ARRAY( cf2->RangeRecord, count, HB_RangeRecord ) )
    737     return error;
    738 
    739   rr = cf2->RangeRecord;
    740 
    741   if ( ACCESS_Frame( count * 6L ) )
    742     goto Fail;
    743 
    744   for ( n = 0; n < count; n++ )
    745   {
    746     rr[n].Start              = GET_UShort();
    747     rr[n].End                = GET_UShort();
    748     rr[n].StartCoverageIndex = GET_UShort();
    749 
    750     /* sanity check; we are limited to 16bit integers */
    751     if ( rr[n].Start > rr[n].End ||
    752 	 ( rr[n].End - rr[n].Start + (long)rr[n].StartCoverageIndex ) >=
    753 	   0x10000L )
    754     {
    755       error = ERR(HB_Err_Invalid_SubTable);
    756       goto Fail;
    757     }
    758   }
    759 
    760   FORGET_Frame();
    761 
    762   return HB_Err_Ok;
    763 
    764 Fail:
    765   FREE( cf2->RangeRecord );
    766   return error;
    767 }
    768 
    769 
    770 static void  Free_Coverage2( HB_CoverageFormat2*  cf2 )
    771 {
    772   FREE( cf2->RangeRecord );
    773 }
    774 
    775 
    776 HB_INTERNAL HB_Error
    777 _HB_OPEN_Load_Coverage( HB_Coverage* c,
    778 			 HB_Stream      stream )
    779 {
    780   HB_Error   error;
    781 
    782   if ( ACCESS_Frame( 2L ) )
    783     return error;
    784 
    785   c->CoverageFormat = GET_UShort();
    786 
    787   FORGET_Frame();
    788 
    789   switch ( c->CoverageFormat )
    790   {
    791   case 1:  return Load_Coverage1( &c->cf.cf1, stream );
    792   case 2:  return Load_Coverage2( &c->cf.cf2, stream );
    793   default: return ERR(HB_Err_Invalid_SubTable_Format);
    794   }
    795 
    796   return HB_Err_Ok;               /* never reached */
    797 }
    798 
    799 
    800 HB_INTERNAL void
    801 _HB_OPEN_Free_Coverage( HB_Coverage* c )
    802 {
    803   switch ( c->CoverageFormat )
    804   {
    805   case 1:  Free_Coverage1( &c->cf.cf1 ); break;
    806   case 2:  Free_Coverage2( &c->cf.cf2 ); break;
    807   default:					 break;
    808   }
    809 }
    810 
    811 
    812 static HB_Error  Coverage_Index1( HB_CoverageFormat1*  cf1,
    813 				  HB_UShort             glyphID,
    814 				  HB_UShort*            index )
    815 {
    816   HB_UShort min, max, new_min, new_max, middle;
    817 
    818   HB_UShort*  array = cf1->GlyphArray;
    819 
    820 
    821   /* binary search */
    822 
    823   if ( cf1->GlyphCount == 0 )
    824     return HB_Err_Not_Covered;
    825 
    826   new_min = 0;
    827   new_max = cf1->GlyphCount - 1;
    828 
    829   do
    830   {
    831     min = new_min;
    832     max = new_max;
    833 
    834     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
    835        overflow and rounding errors                             */
    836 
    837     middle = max - ( ( max - min ) >> 1 );
    838 
    839     if ( glyphID == array[middle] )
    840     {
    841       *index = middle;
    842       return HB_Err_Ok;
    843     }
    844     else if ( glyphID < array[middle] )
    845     {
    846       if ( middle == min )
    847 	break;
    848       new_max = middle - 1;
    849     }
    850     else
    851     {
    852       if ( middle == max )
    853 	break;
    854       new_min = middle + 1;
    855     }
    856   } while ( min < max );
    857 
    858   return HB_Err_Not_Covered;
    859 }
    860 
    861 
    862 static HB_Error  Coverage_Index2( HB_CoverageFormat2*  cf2,
    863 				  HB_UShort             glyphID,
    864 				  HB_UShort*            index )
    865 {
    866   HB_UShort         min, max, new_min, new_max, middle;
    867 
    868   HB_RangeRecord*  rr = cf2->RangeRecord;
    869 
    870 
    871   /* binary search */
    872 
    873   if ( cf2->RangeCount == 0 )
    874     return HB_Err_Not_Covered;
    875 
    876   new_min = 0;
    877   new_max = cf2->RangeCount - 1;
    878 
    879   do
    880   {
    881     min = new_min;
    882     max = new_max;
    883 
    884     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
    885        overflow and rounding errors                             */
    886 
    887     middle = max - ( ( max - min ) >> 1 );
    888 
    889     if ( glyphID >= rr[middle].Start && glyphID <= rr[middle].End )
    890     {
    891       *index = rr[middle].StartCoverageIndex + glyphID - rr[middle].Start;
    892       return HB_Err_Ok;
    893     }
    894     else if ( glyphID < rr[middle].Start )
    895     {
    896       if ( middle == min )
    897 	break;
    898       new_max = middle - 1;
    899     }
    900     else
    901     {
    902       if ( middle == max )
    903 	break;
    904       new_min = middle + 1;
    905     }
    906   } while ( min < max );
    907 
    908   return HB_Err_Not_Covered;
    909 }
    910 
    911 
    912 HB_INTERNAL HB_Error
    913 _HB_OPEN_Coverage_Index( HB_Coverage* c,
    914 			  HB_UShort      glyphID,
    915 			  HB_UShort*     index )
    916 {
    917   switch ( c->CoverageFormat )
    918   {
    919   case 1:  return Coverage_Index1( &c->cf.cf1, glyphID, index );
    920   case 2:  return Coverage_Index2( &c->cf.cf2, glyphID, index );
    921   default: return ERR(HB_Err_Invalid_SubTable_Format);
    922   }
    923 
    924   return HB_Err_Ok;               /* never reached */
    925 }
    926 
    927 
    928 
    929 /*************************************
    930  * Class Definition related functions
    931  *************************************/
    932 
    933 
    934 /* ClassDefFormat1 */
    935 
    936 static HB_Error  Load_ClassDef1( HB_ClassDefinition*  cd,
    937 				 HB_UShort             limit,
    938 				 HB_Stream             stream )
    939 {
    940   HB_Error   error;
    941 
    942   HB_UShort             n, count;
    943 
    944   HB_UShort*            cva;
    945 
    946   HB_ClassDefFormat1*  cdf1;
    947 
    948 
    949   cdf1 = &cd->cd.cd1;
    950 
    951   if ( ACCESS_Frame( 4L ) )
    952     return error;
    953 
    954   cdf1->StartGlyph         = GET_UShort();
    955   count = cdf1->GlyphCount = GET_UShort();
    956 
    957   FORGET_Frame();
    958 
    959   /* sanity check; we are limited to 16bit integers */
    960 
    961   if ( cdf1->StartGlyph + (long)count >= 0x10000L )
    962     return ERR(HB_Err_Invalid_SubTable);
    963 
    964   cdf1->ClassValueArray = NULL;
    965 
    966   if ( ALLOC_ARRAY( cdf1->ClassValueArray, count, HB_UShort ) )
    967     return error;
    968 
    969   cva = cdf1->ClassValueArray;
    970 
    971   if ( ACCESS_Frame( count * 2L ) )
    972     goto Fail;
    973 
    974   for ( n = 0; n < count; n++ )
    975   {
    976     cva[n] = GET_UShort();
    977     if ( cva[n] >= limit )
    978     {
    979       error = ERR(HB_Err_Invalid_SubTable);
    980       goto Fail;
    981     }
    982   }
    983 
    984   FORGET_Frame();
    985 
    986   return HB_Err_Ok;
    987 
    988 Fail:
    989   FREE( cva );
    990 
    991   return error;
    992 }
    993 
    994 
    995 static void  Free_ClassDef1( HB_ClassDefFormat1*  cdf1 )
    996 {
    997   FREE( cdf1->ClassValueArray );
    998 }
    999 
   1000 
   1001 /* ClassDefFormat2 */
   1002 
   1003 static HB_Error  Load_ClassDef2( HB_ClassDefinition*  cd,
   1004 				 HB_UShort             limit,
   1005 				 HB_Stream             stream )
   1006 {
   1007   HB_Error   error;
   1008 
   1009   HB_UShort              n, count;
   1010 
   1011   HB_ClassRangeRecord*  crr;
   1012 
   1013   HB_ClassDefFormat2*   cdf2;
   1014 
   1015 
   1016   cdf2 = &cd->cd.cd2;
   1017 
   1018   if ( ACCESS_Frame( 2L ) )
   1019     return error;
   1020 
   1021   count = GET_UShort();
   1022   cdf2->ClassRangeCount = 0; /* zero for now.  we fill with the number of good entries later */
   1023 
   1024   FORGET_Frame();
   1025 
   1026   cdf2->ClassRangeRecord = NULL;
   1027 
   1028   if ( ALLOC_ARRAY( cdf2->ClassRangeRecord, count, HB_ClassRangeRecord ) )
   1029     return error;
   1030 
   1031   crr = cdf2->ClassRangeRecord;
   1032 
   1033   if ( ACCESS_Frame( count * 6L ) )
   1034     goto Fail;
   1035 
   1036   for ( n = 0; n < count; n++ )
   1037   {
   1038     crr[n].Start = GET_UShort();
   1039     crr[n].End   = GET_UShort();
   1040     crr[n].Class = GET_UShort();
   1041 
   1042     /* sanity check */
   1043 
   1044     if ( crr[n].Start > crr[n].End ||
   1045 	 crr[n].Class >= limit )
   1046     {
   1047       /* XXX
   1048        * Corrupt entry.  Skip it.
   1049        * This is hit by Nafees Nastaliq font for example
   1050        */
   1051        n--;
   1052        count--;
   1053     }
   1054   }
   1055 
   1056   FORGET_Frame();
   1057 
   1058   cdf2->ClassRangeCount = count;
   1059 
   1060   return HB_Err_Ok;
   1061 
   1062 Fail:
   1063   FREE( crr );
   1064 
   1065   return error;
   1066 }
   1067 
   1068 
   1069 static void  Free_ClassDef2( HB_ClassDefFormat2*  cdf2 )
   1070 {
   1071   FREE( cdf2->ClassRangeRecord );
   1072 }
   1073 
   1074 
   1075 /* ClassDefinition */
   1076 
   1077 HB_INTERNAL HB_Error
   1078 _HB_OPEN_Load_ClassDefinition( HB_ClassDefinition* cd,
   1079 				HB_UShort             limit,
   1080 				HB_Stream             stream )
   1081 {
   1082   HB_Error   error;
   1083 
   1084   if ( ACCESS_Frame( 2L ) )
   1085     return error;
   1086 
   1087   cd->ClassFormat = GET_UShort();
   1088 
   1089   FORGET_Frame();
   1090 
   1091   switch ( cd->ClassFormat )
   1092   {
   1093   case 1:  error = Load_ClassDef1( cd, limit, stream ); break;
   1094   case 2:  error = Load_ClassDef2( cd, limit, stream ); break;
   1095   default: error = ERR(HB_Err_Invalid_SubTable_Format);	break;
   1096   }
   1097 
   1098   if ( error )
   1099     return error;
   1100 
   1101   cd->loaded = TRUE;
   1102 
   1103   return HB_Err_Ok;
   1104 }
   1105 
   1106 
   1107 static HB_Error
   1108 _HB_OPEN_Load_EmptyClassDefinition( HB_ClassDefinition*  cd )
   1109 {
   1110   HB_Error   error;
   1111 
   1112   cd->ClassFormat = 1; /* Meaningless */
   1113 
   1114   if ( ALLOC_ARRAY( cd->cd.cd1.ClassValueArray, 1, HB_UShort ) )
   1115     return error;
   1116 
   1117   cd->loaded = TRUE;
   1118 
   1119   return HB_Err_Ok;
   1120 }
   1121 
   1122 HB_INTERNAL HB_Error
   1123 _HB_OPEN_Load_EmptyOrClassDefinition( HB_ClassDefinition* cd,
   1124 					       HB_UShort             limit,
   1125 					       HB_UInt              class_offset,
   1126 					       HB_UInt              base_offset,
   1127 					       HB_Stream             stream )
   1128 {
   1129   HB_Error error;
   1130   HB_UInt               cur_offset;
   1131 
   1132   cur_offset = FILE_Pos();
   1133 
   1134   if ( class_offset )
   1135     {
   1136       if ( !FILE_Seek( class_offset + base_offset ) )
   1137 	error = _HB_OPEN_Load_ClassDefinition( cd, limit, stream );
   1138     }
   1139   else
   1140      error = _HB_OPEN_Load_EmptyClassDefinition ( cd );
   1141 
   1142   if (error == HB_Err_Ok)
   1143     (void)FILE_Seek( cur_offset ); /* Changes error as a side-effect */
   1144 
   1145   return error;
   1146 }
   1147 
   1148 HB_INTERNAL void
   1149 _HB_OPEN_Free_ClassDefinition( HB_ClassDefinition*  cd )
   1150 {
   1151   if ( !cd->loaded )
   1152     return;
   1153 
   1154   switch ( cd->ClassFormat )
   1155   {
   1156   case 1:  Free_ClassDef1( &cd->cd.cd1 ); break;
   1157   case 2:  Free_ClassDef2( &cd->cd.cd2 ); break;
   1158   default:				  break;
   1159   }
   1160 }
   1161 
   1162 
   1163 static HB_Error  Get_Class1( HB_ClassDefFormat1*  cdf1,
   1164 			     HB_UShort             glyphID,
   1165 			     HB_UShort*            klass,
   1166 			     HB_UShort*            index )
   1167 {
   1168   HB_UShort*  cva = cdf1->ClassValueArray;
   1169 
   1170 
   1171   if ( index )
   1172     *index = 0;
   1173 
   1174   if ( glyphID >= cdf1->StartGlyph &&
   1175        glyphID < cdf1->StartGlyph + cdf1->GlyphCount )
   1176   {
   1177     *klass = cva[glyphID - cdf1->StartGlyph];
   1178     return HB_Err_Ok;
   1179   }
   1180   else
   1181   {
   1182     *klass = 0;
   1183     return HB_Err_Not_Covered;
   1184   }
   1185 }
   1186 
   1187 
   1188 /* we need the index value of the last searched class range record
   1189    in case of failure for constructed GDEF tables                  */
   1190 
   1191 static HB_Error  Get_Class2( HB_ClassDefFormat2*  cdf2,
   1192 			     HB_UShort             glyphID,
   1193 			     HB_UShort*            klass,
   1194 			     HB_UShort*            index )
   1195 {
   1196   HB_Error               error = HB_Err_Ok;
   1197   HB_UShort              min, max, new_min, new_max, middle;
   1198 
   1199   HB_ClassRangeRecord*  crr = cdf2->ClassRangeRecord;
   1200 
   1201 
   1202   /* binary search */
   1203 
   1204   if ( cdf2->ClassRangeCount == 0 )
   1205     {
   1206       *klass = 0;
   1207       if ( index )
   1208 	*index = 0;
   1209 
   1210       return HB_Err_Not_Covered;
   1211     }
   1212 
   1213   new_min = 0;
   1214   new_max = cdf2->ClassRangeCount - 1;
   1215 
   1216   do
   1217   {
   1218     min = new_min;
   1219     max = new_max;
   1220 
   1221     /* we use (min + max) / 2 = max - (max - min) / 2  to avoid
   1222        overflow and rounding errors                             */
   1223 
   1224     middle = max - ( ( max - min ) >> 1 );
   1225 
   1226     if ( glyphID >= crr[middle].Start && glyphID <= crr[middle].End )
   1227     {
   1228       *klass = crr[middle].Class;
   1229       error  = HB_Err_Ok;
   1230       break;
   1231     }
   1232     else if ( glyphID < crr[middle].Start )
   1233     {
   1234       if ( middle == min )
   1235       {
   1236 	*klass = 0;
   1237 	error  = HB_Err_Not_Covered;
   1238 	break;
   1239       }
   1240       new_max = middle - 1;
   1241     }
   1242     else
   1243     {
   1244       if ( middle == max )
   1245       {
   1246 	*klass = 0;
   1247 	error  = HB_Err_Not_Covered;
   1248 	break;
   1249       }
   1250       new_min = middle + 1;
   1251     }
   1252   } while ( min < max );
   1253 
   1254   if ( index )
   1255     *index = middle;
   1256 
   1257   return error;
   1258 }
   1259 
   1260 
   1261 HB_INTERNAL HB_Error
   1262 _HB_OPEN_Get_Class( HB_ClassDefinition* cd,
   1263 		     HB_UShort             glyphID,
   1264 		    HB_UShort*          klass,
   1265 		     HB_UShort*            index )
   1266 {
   1267   switch ( cd->ClassFormat )
   1268   {
   1269   case 1:  return Get_Class1( &cd->cd.cd1, glyphID, klass, index );
   1270   case 2:  return Get_Class2( &cd->cd.cd2, glyphID, klass, index );
   1271   default: return ERR(HB_Err_Invalid_SubTable_Format);
   1272   }
   1273 
   1274   return HB_Err_Ok;               /* never reached */
   1275 }
   1276 
   1277 
   1278 
   1279 /***************************
   1280  * Device related functions
   1281  ***************************/
   1282 
   1283 
   1284 HB_INTERNAL HB_Error
   1285 _HB_OPEN_Load_Device( HB_Device** device,
   1286 		       HB_Stream    stream )
   1287 {
   1288   HB_Device*  d;
   1289   HB_Error   error;
   1290 
   1291   HB_UShort   n, count;
   1292 
   1293   HB_UShort*  dv;
   1294 
   1295 
   1296   if ( ACCESS_Frame( 6L ) )
   1297     return error;
   1298 
   1299   if ( ALLOC( *device, sizeof(HB_Device)) )
   1300   {
   1301     *device = 0;
   1302     return error;
   1303   }
   1304 
   1305   d = *device;
   1306 
   1307   d->StartSize   = GET_UShort();
   1308   d->EndSize     = GET_UShort();
   1309   d->DeltaFormat = GET_UShort();
   1310 
   1311   FORGET_Frame();
   1312 
   1313   d->DeltaValue = NULL;
   1314 
   1315   if ( d->StartSize > d->EndSize ||
   1316        d->DeltaFormat == 0 || d->DeltaFormat > 3 )
   1317     {
   1318       /* XXX
   1319        * I've seen fontforge generate DeltaFormat == 0.
   1320        * Just return Ok and let the NULL DeltaValue disable
   1321        * this table.
   1322        */
   1323       return HB_Err_Ok;
   1324     }
   1325 
   1326   count = ( ( d->EndSize - d->StartSize + 1 ) >>
   1327 	      ( 4 - d->DeltaFormat ) ) + 1;
   1328 
   1329   if ( ALLOC_ARRAY( d->DeltaValue, count, HB_UShort ) )
   1330   {
   1331     FREE( *device );
   1332     *device = 0;
   1333     return error;
   1334   }
   1335 
   1336   if ( ACCESS_Frame( count * 2L ) )
   1337   {
   1338     FREE( d->DeltaValue );
   1339     FREE( *device );
   1340     *device = 0;
   1341     return error;
   1342   }
   1343 
   1344   dv = d->DeltaValue;
   1345 
   1346   for ( n = 0; n < count; n++ )
   1347     dv[n] = GET_UShort();
   1348 
   1349   FORGET_Frame();
   1350 
   1351   return HB_Err_Ok;
   1352 }
   1353 
   1354 
   1355 HB_INTERNAL void
   1356 _HB_OPEN_Free_Device( HB_Device* d )
   1357 {
   1358   if ( d )
   1359   {
   1360     FREE( d->DeltaValue );
   1361     FREE( d );
   1362   }
   1363 }
   1364 
   1365 
   1366 /* Since we have the delta values stored in compressed form, we must
   1367    uncompress it now.  To simplify the interface, the function always
   1368    returns a meaningful value in `value'; the error is just for
   1369    information.
   1370 			       |                |
   1371    format = 1: 0011223344556677|8899101112131415|...
   1372 			       |                |
   1373 		    byte 1           byte 2
   1374 
   1375      00: (byte >> 14) & mask
   1376      11: (byte >> 12) & mask
   1377      ...
   1378 
   1379      mask = 0x0003
   1380 			       |                |
   1381    format = 2: 0000111122223333|4444555566667777|...
   1382 			       |                |
   1383 		    byte 1           byte 2
   1384 
   1385      0000: (byte >> 12) & mask
   1386      1111: (byte >>  8) & mask
   1387      ...
   1388 
   1389      mask = 0x000F
   1390 			       |                |
   1391    format = 3: 0000000011111111|2222222233333333|...
   1392 			       |                |
   1393 		    byte 1           byte 2
   1394 
   1395      00000000: (byte >> 8) & mask
   1396      11111111: (byte >> 0) & mask
   1397      ....
   1398 
   1399      mask = 0x00FF                                    */
   1400 
   1401 HB_INTERNAL HB_Error
   1402 _HB_OPEN_Get_Device( HB_Device* d,
   1403 		      HB_UShort    size,
   1404 		      HB_Short*    value )
   1405 {
   1406   HB_UShort  byte, bits, mask, s;
   1407 
   1408   if ( d && d->DeltaValue && size >= d->StartSize && size <= d->EndSize )
   1409   {
   1410     HB_UShort f = d->DeltaFormat;
   1411     s    = size - d->StartSize;
   1412     byte = d->DeltaValue[s >> ( 4 - f )];
   1413     bits = byte >> ( 16 - ( ( s % ( 1 << ( 4 - f ) ) + 1 ) << f ) );
   1414     mask = 0xFFFF >> ( 16 - ( 1 << f ) );
   1415 
   1416     *value = (HB_Short)( bits & mask );
   1417 
   1418     /* conversion to a signed value */
   1419 
   1420     if ( *value >= ( ( mask + 1 ) >> 1 ) )
   1421       *value -= mask + 1;
   1422 
   1423     return HB_Err_Ok;
   1424   }
   1425   else
   1426   {
   1427     *value = 0;
   1428     return HB_Err_Not_Covered;
   1429   }
   1430 }
   1431 
   1432 
   1433 /* END */
   1434