Home | History | Annotate | Download | only in otvalid
      1 /****************************************************************************
      2  *
      3  * otvgpos.c
      4  *
      5  *   OpenType GPOS table validation (body).
      6  *
      7  * Copyright 2002-2018 by
      8  * David Turner, Robert Wilhelm, and Werner Lemberg.
      9  *
     10  * This file is part of the FreeType project, and may only be used,
     11  * modified, and distributed under the terms of the FreeType project
     12  * license, LICENSE.TXT.  By continuing to use, modify, or distribute
     13  * this file you indicate that you have read the license and
     14  * understand and accept it fully.
     15  *
     16  */
     17 
     18 
     19 #include "otvalid.h"
     20 #include "otvcommn.h"
     21 #include "otvgpos.h"
     22 
     23 
     24   /**************************************************************************
     25    *
     26    * The macro FT_COMPONENT is used in trace mode.  It is an implicit
     27    * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
     28    * messages during execution.
     29    */
     30 #undef  FT_COMPONENT
     31 #define FT_COMPONENT  trace_otvgpos
     32 
     33 
     34   static void
     35   otv_Anchor_validate( FT_Bytes       table,
     36                        OTV_Validator  valid );
     37 
     38   static void
     39   otv_MarkArray_validate( FT_Bytes       table,
     40                           OTV_Validator  valid );
     41 
     42 
     43   /*************************************************************************/
     44   /*************************************************************************/
     45   /*****                                                               *****/
     46   /*****                      UTILITY FUNCTIONS                        *****/
     47   /*****                                                               *****/
     48   /*************************************************************************/
     49   /*************************************************************************/
     50 
     51 #define BaseArrayFunc       otv_x_sxy
     52 #define LigatureAttachFunc  otv_x_sxy
     53 #define Mark2ArrayFunc      otv_x_sxy
     54 
     55   /* uses valid->extra1 (counter)                             */
     56   /* uses valid->extra2 (boolean to handle NULL anchor field) */
     57 
     58   static void
     59   otv_x_sxy( FT_Bytes       table,
     60              OTV_Validator  otvalid )
     61   {
     62     FT_Bytes  p = table;
     63     FT_UInt   Count, count1, table_size;
     64 
     65 
     66     OTV_ENTER;
     67 
     68     OTV_LIMIT_CHECK( 2 );
     69 
     70     Count = FT_NEXT_USHORT( p );
     71 
     72     OTV_TRACE(( " (Count = %d)\n", Count ));
     73 
     74     OTV_LIMIT_CHECK( Count * otvalid->extra1 * 2 );
     75 
     76     table_size = Count * otvalid->extra1 * 2 + 2;
     77 
     78     for ( ; Count > 0; Count-- )
     79       for ( count1 = otvalid->extra1; count1 > 0; count1-- )
     80       {
     81         OTV_OPTIONAL_TABLE( anchor_offset );
     82 
     83 
     84         OTV_OPTIONAL_OFFSET( anchor_offset );
     85 
     86         if ( otvalid->extra2 )
     87         {
     88           OTV_SIZE_CHECK( anchor_offset );
     89           if ( anchor_offset )
     90             otv_Anchor_validate( table + anchor_offset, otvalid );
     91         }
     92         else
     93           otv_Anchor_validate( table + anchor_offset, otvalid );
     94       }
     95 
     96     OTV_EXIT;
     97   }
     98 
     99 
    100 #define MarkBasePosFormat1Func  otv_u_O_O_u_O_O
    101 #define MarkLigPosFormat1Func   otv_u_O_O_u_O_O
    102 #define MarkMarkPosFormat1Func  otv_u_O_O_u_O_O
    103 
    104   /* sets otvalid->extra1 (class count) */
    105 
    106   static void
    107   otv_u_O_O_u_O_O( FT_Bytes       table,
    108                    OTV_Validator  otvalid )
    109   {
    110     FT_Bytes           p = table;
    111     FT_UInt            Coverage1, Coverage2, ClassCount;
    112     FT_UInt            Array1, Array2;
    113     OTV_Validate_Func  func;
    114 
    115 
    116     OTV_ENTER;
    117 
    118     p += 2;     /* skip PosFormat */
    119 
    120     OTV_LIMIT_CHECK( 10 );
    121     Coverage1  = FT_NEXT_USHORT( p );
    122     Coverage2  = FT_NEXT_USHORT( p );
    123     ClassCount = FT_NEXT_USHORT( p );
    124     Array1     = FT_NEXT_USHORT( p );
    125     Array2     = FT_NEXT_USHORT( p );
    126 
    127     otv_Coverage_validate( table + Coverage1, otvalid, -1 );
    128     otv_Coverage_validate( table + Coverage2, otvalid, -1 );
    129 
    130     otv_MarkArray_validate( table + Array1, otvalid );
    131 
    132     otvalid->nesting_level++;
    133     func            = otvalid->func[otvalid->nesting_level];
    134     otvalid->extra1 = ClassCount;
    135 
    136     func( table + Array2, otvalid );
    137 
    138     otvalid->nesting_level--;
    139 
    140     OTV_EXIT;
    141   }
    142 
    143 
    144   /*************************************************************************/
    145   /*************************************************************************/
    146   /*****                                                               *****/
    147   /*****                        VALUE RECORDS                          *****/
    148   /*****                                                               *****/
    149   /*************************************************************************/
    150   /*************************************************************************/
    151 
    152   static FT_UInt
    153   otv_value_length( FT_UInt  format )
    154   {
    155     FT_UInt  count;
    156 
    157 
    158     count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 );
    159     count = ( ( count  & 0xCC ) >> 2 ) + ( count  & 0x33 );
    160     count = ( ( count  & 0xF0 ) >> 4 ) + ( count  & 0x0F );
    161 
    162     return count * 2;
    163   }
    164 
    165 
    166   /* uses otvalid->extra3 (pointer to base table) */
    167 
    168   static void
    169   otv_ValueRecord_validate( FT_Bytes       table,
    170                             FT_UInt        format,
    171                             OTV_Validator  otvalid )
    172   {
    173     FT_Bytes  p = table;
    174     FT_UInt   count;
    175 
    176 #ifdef FT_DEBUG_LEVEL_TRACE
    177     FT_Int    loop;
    178     FT_ULong  res = 0;
    179 
    180 
    181     OTV_NAME_ENTER( "ValueRecord" );
    182 
    183     /* display `format' in dual representation */
    184     for ( loop = 7; loop >= 0; loop-- )
    185     {
    186       res <<= 4;
    187       res  += ( format >> loop ) & 1;
    188     }
    189 
    190     OTV_TRACE(( " (format 0b%08lx)\n", res ));
    191 #endif
    192 
    193     if ( format >= 0x100 )
    194       FT_INVALID_FORMAT;
    195 
    196     for ( count = 4; count > 0; count-- )
    197     {
    198       if ( format & 1 )
    199       {
    200         /* XPlacement, YPlacement, XAdvance, YAdvance */
    201         OTV_LIMIT_CHECK( 2 );
    202         p += 2;
    203       }
    204 
    205       format >>= 1;
    206     }
    207 
    208     for ( count = 4; count > 0; count-- )
    209     {
    210       if ( format & 1 )
    211       {
    212         FT_PtrDist  table_size;
    213 
    214         OTV_OPTIONAL_TABLE( device );
    215 
    216 
    217         /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */
    218         OTV_LIMIT_CHECK( 2 );
    219         OTV_OPTIONAL_OFFSET( device );
    220 
    221         table_size = p - otvalid->extra3;
    222 
    223         OTV_SIZE_CHECK( device );
    224         if ( device )
    225           otv_Device_validate( otvalid->extra3 + device, otvalid );
    226       }
    227       format >>= 1;
    228     }
    229 
    230     OTV_EXIT;
    231   }
    232 
    233 
    234   /*************************************************************************/
    235   /*************************************************************************/
    236   /*****                                                               *****/
    237   /*****                           ANCHORS                             *****/
    238   /*****                                                               *****/
    239   /*************************************************************************/
    240   /*************************************************************************/
    241 
    242   static void
    243   otv_Anchor_validate( FT_Bytes       table,
    244                        OTV_Validator  otvalid )
    245   {
    246     FT_Bytes  p = table;
    247     FT_UInt   AnchorFormat;
    248 
    249 
    250     OTV_NAME_ENTER( "Anchor");
    251 
    252     OTV_LIMIT_CHECK( 6 );
    253     AnchorFormat = FT_NEXT_USHORT( p );
    254 
    255     OTV_TRACE(( " (format %d)\n", AnchorFormat ));
    256 
    257     p += 4;     /* skip XCoordinate and YCoordinate */
    258 
    259     switch ( AnchorFormat )
    260     {
    261     case 1:
    262       break;
    263 
    264     case 2:
    265       OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
    266       break;
    267 
    268     case 3:
    269       {
    270         FT_UInt  table_size;
    271 
    272         OTV_OPTIONAL_TABLE( XDeviceTable );
    273         OTV_OPTIONAL_TABLE( YDeviceTable );
    274 
    275 
    276         OTV_LIMIT_CHECK( 4 );
    277         OTV_OPTIONAL_OFFSET( XDeviceTable );
    278         OTV_OPTIONAL_OFFSET( YDeviceTable );
    279 
    280         table_size = 6 + 4;
    281 
    282         OTV_SIZE_CHECK( XDeviceTable );
    283         if ( XDeviceTable )
    284           otv_Device_validate( table + XDeviceTable, otvalid );
    285 
    286         OTV_SIZE_CHECK( YDeviceTable );
    287         if ( YDeviceTable )
    288           otv_Device_validate( table + YDeviceTable, otvalid );
    289       }
    290       break;
    291 
    292     default:
    293       FT_INVALID_FORMAT;
    294     }
    295 
    296     OTV_EXIT;
    297   }
    298 
    299 
    300   /*************************************************************************/
    301   /*************************************************************************/
    302   /*****                                                               *****/
    303   /*****                         MARK ARRAYS                           *****/
    304   /*****                                                               *****/
    305   /*************************************************************************/
    306   /*************************************************************************/
    307 
    308   static void
    309   otv_MarkArray_validate( FT_Bytes       table,
    310                           OTV_Validator  otvalid )
    311   {
    312     FT_Bytes  p = table;
    313     FT_UInt   MarkCount;
    314 
    315 
    316     OTV_NAME_ENTER( "MarkArray" );
    317 
    318     OTV_LIMIT_CHECK( 2 );
    319     MarkCount = FT_NEXT_USHORT( p );
    320 
    321     OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
    322 
    323     OTV_LIMIT_CHECK( MarkCount * 4 );
    324 
    325     /* MarkRecord */
    326     for ( ; MarkCount > 0; MarkCount-- )
    327     {
    328       p += 2;   /* skip Class */
    329       /* MarkAnchor */
    330       otv_Anchor_validate( table + FT_NEXT_USHORT( p ), otvalid );
    331     }
    332 
    333     OTV_EXIT;
    334   }
    335 
    336 
    337   /*************************************************************************/
    338   /*************************************************************************/
    339   /*****                                                               *****/
    340   /*****                     GPOS LOOKUP TYPE 1                        *****/
    341   /*****                                                               *****/
    342   /*************************************************************************/
    343   /*************************************************************************/
    344 
    345   /* sets otvalid->extra3 (pointer to base table) */
    346 
    347   static void
    348   otv_SinglePos_validate( FT_Bytes       table,
    349                           OTV_Validator  otvalid )
    350   {
    351     FT_Bytes  p = table;
    352     FT_UInt   PosFormat;
    353 
    354 
    355     OTV_NAME_ENTER( "SinglePos" );
    356 
    357     OTV_LIMIT_CHECK( 2 );
    358     PosFormat = FT_NEXT_USHORT( p );
    359 
    360     OTV_TRACE(( " (format %d)\n", PosFormat ));
    361 
    362     otvalid->extra3 = table;
    363 
    364     switch ( PosFormat )
    365     {
    366     case 1:     /* SinglePosFormat1 */
    367       {
    368         FT_UInt  Coverage, ValueFormat;
    369 
    370 
    371         OTV_LIMIT_CHECK( 4 );
    372         Coverage    = FT_NEXT_USHORT( p );
    373         ValueFormat = FT_NEXT_USHORT( p );
    374 
    375         otv_Coverage_validate( table + Coverage, otvalid, -1 );
    376         otv_ValueRecord_validate( p, ValueFormat, otvalid ); /* Value */
    377       }
    378       break;
    379 
    380     case 2:     /* SinglePosFormat2 */
    381       {
    382         FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
    383 
    384 
    385         OTV_LIMIT_CHECK( 6 );
    386         Coverage    = FT_NEXT_USHORT( p );
    387         ValueFormat = FT_NEXT_USHORT( p );
    388         ValueCount  = FT_NEXT_USHORT( p );
    389 
    390         OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
    391 
    392         len_value = otv_value_length( ValueFormat );
    393 
    394         otv_Coverage_validate( table + Coverage,
    395                                otvalid,
    396                                (FT_Int)ValueCount );
    397 
    398         OTV_LIMIT_CHECK( ValueCount * len_value );
    399 
    400         /* Value */
    401         for ( ; ValueCount > 0; ValueCount-- )
    402         {
    403           otv_ValueRecord_validate( p, ValueFormat, otvalid );
    404           p += len_value;
    405         }
    406       }
    407       break;
    408 
    409     default:
    410       FT_INVALID_FORMAT;
    411     }
    412 
    413     OTV_EXIT;
    414   }
    415 
    416 
    417   /*************************************************************************/
    418   /*************************************************************************/
    419   /*****                                                               *****/
    420   /*****                     GPOS LOOKUP TYPE 2                        *****/
    421   /*****                                                               *****/
    422   /*************************************************************************/
    423   /*************************************************************************/
    424 
    425   /* sets otvalid->extra3 (pointer to base table) */
    426 
    427   static void
    428   otv_PairSet_validate( FT_Bytes       table,
    429                         FT_UInt        format1,
    430                         FT_UInt        format2,
    431                         OTV_Validator  otvalid )
    432   {
    433     FT_Bytes  p = table;
    434     FT_UInt   value_len1, value_len2, PairValueCount;
    435 
    436 
    437     OTV_NAME_ENTER( "PairSet" );
    438 
    439     otvalid->extra3 = table;
    440 
    441     OTV_LIMIT_CHECK( 2 );
    442     PairValueCount = FT_NEXT_USHORT( p );
    443 
    444     OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
    445 
    446     value_len1 = otv_value_length( format1 );
    447     value_len2 = otv_value_length( format2 );
    448 
    449     OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
    450 
    451     /* PairValueRecord */
    452     for ( ; PairValueCount > 0; PairValueCount-- )
    453     {
    454       p += 2;       /* skip SecondGlyph */
    455 
    456       if ( format1 )
    457         otv_ValueRecord_validate( p, format1, otvalid ); /* Value1 */
    458       p += value_len1;
    459 
    460       if ( format2 )
    461         otv_ValueRecord_validate( p, format2, otvalid ); /* Value2 */
    462       p += value_len2;
    463     }
    464 
    465     OTV_EXIT;
    466   }
    467 
    468 
    469   /* sets otvalid->extra3 (pointer to base table) */
    470 
    471   static void
    472   otv_PairPos_validate( FT_Bytes       table,
    473                         OTV_Validator  otvalid )
    474   {
    475     FT_Bytes  p = table;
    476     FT_UInt   PosFormat;
    477 
    478 
    479     OTV_NAME_ENTER( "PairPos" );
    480 
    481     OTV_LIMIT_CHECK( 2 );
    482     PosFormat = FT_NEXT_USHORT( p );
    483 
    484     OTV_TRACE(( " (format %d)\n", PosFormat ));
    485 
    486     switch ( PosFormat )
    487     {
    488     case 1:     /* PairPosFormat1 */
    489       {
    490         FT_UInt  Coverage, ValueFormat1, ValueFormat2, PairSetCount;
    491 
    492 
    493         OTV_LIMIT_CHECK( 8 );
    494         Coverage     = FT_NEXT_USHORT( p );
    495         ValueFormat1 = FT_NEXT_USHORT( p );
    496         ValueFormat2 = FT_NEXT_USHORT( p );
    497         PairSetCount = FT_NEXT_USHORT( p );
    498 
    499         OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount ));
    500 
    501         otv_Coverage_validate( table + Coverage, otvalid, -1 );
    502 
    503         OTV_LIMIT_CHECK( PairSetCount * 2 );
    504 
    505         /* PairSetOffset */
    506         for ( ; PairSetCount > 0; PairSetCount-- )
    507           otv_PairSet_validate( table + FT_NEXT_USHORT( p ),
    508                                 ValueFormat1, ValueFormat2, otvalid );
    509       }
    510       break;
    511 
    512     case 2:     /* PairPosFormat2 */
    513       {
    514         FT_UInt  Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2;
    515         FT_UInt  ClassCount1, ClassCount2, len_value1, len_value2, count;
    516 
    517 
    518         OTV_LIMIT_CHECK( 14 );
    519         Coverage     = FT_NEXT_USHORT( p );
    520         ValueFormat1 = FT_NEXT_USHORT( p );
    521         ValueFormat2 = FT_NEXT_USHORT( p );
    522         ClassDef1    = FT_NEXT_USHORT( p );
    523         ClassDef2    = FT_NEXT_USHORT( p );
    524         ClassCount1  = FT_NEXT_USHORT( p );
    525         ClassCount2  = FT_NEXT_USHORT( p );
    526 
    527         OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 ));
    528         OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 ));
    529 
    530         len_value1 = otv_value_length( ValueFormat1 );
    531         len_value2 = otv_value_length( ValueFormat2 );
    532 
    533         otv_Coverage_validate( table + Coverage, otvalid, -1 );
    534         otv_ClassDef_validate( table + ClassDef1, otvalid );
    535         otv_ClassDef_validate( table + ClassDef2, otvalid );
    536 
    537         OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
    538                          ( len_value1 + len_value2 ) );
    539 
    540         otvalid->extra3 = table;
    541 
    542         /* Class1Record */
    543         for ( ; ClassCount1 > 0; ClassCount1-- )
    544         {
    545           /* Class2Record */
    546           for ( count = ClassCount2; count > 0; count-- )
    547           {
    548             if ( ValueFormat1 )
    549               /* Value1 */
    550               otv_ValueRecord_validate( p, ValueFormat1, otvalid );
    551             p += len_value1;
    552 
    553             if ( ValueFormat2 )
    554               /* Value2 */
    555               otv_ValueRecord_validate( p, ValueFormat2, otvalid );
    556             p += len_value2;
    557           }
    558         }
    559       }
    560       break;
    561 
    562     default:
    563       FT_INVALID_FORMAT;
    564     }
    565 
    566     OTV_EXIT;
    567   }
    568 
    569 
    570   /*************************************************************************/
    571   /*************************************************************************/
    572   /*****                                                               *****/
    573   /*****                     GPOS LOOKUP TYPE 3                        *****/
    574   /*****                                                               *****/
    575   /*************************************************************************/
    576   /*************************************************************************/
    577 
    578   static void
    579   otv_CursivePos_validate( FT_Bytes       table,
    580                            OTV_Validator  otvalid )
    581   {
    582     FT_Bytes  p = table;
    583     FT_UInt   PosFormat;
    584 
    585 
    586     OTV_NAME_ENTER( "CursivePos" );
    587 
    588     OTV_LIMIT_CHECK( 2 );
    589     PosFormat = FT_NEXT_USHORT( p );
    590 
    591     OTV_TRACE(( " (format %d)\n", PosFormat ));
    592 
    593     switch ( PosFormat )
    594     {
    595     case 1:     /* CursivePosFormat1 */
    596       {
    597         FT_UInt   table_size;
    598         FT_UInt   Coverage, EntryExitCount;
    599 
    600         OTV_OPTIONAL_TABLE( EntryAnchor );
    601         OTV_OPTIONAL_TABLE( ExitAnchor  );
    602 
    603 
    604         OTV_LIMIT_CHECK( 4 );
    605         Coverage       = FT_NEXT_USHORT( p );
    606         EntryExitCount = FT_NEXT_USHORT( p );
    607 
    608         OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
    609 
    610         otv_Coverage_validate( table + Coverage,
    611                                otvalid,
    612                                (FT_Int)EntryExitCount );
    613 
    614         OTV_LIMIT_CHECK( EntryExitCount * 4 );
    615 
    616         table_size = EntryExitCount * 4 + 4;
    617 
    618         /* EntryExitRecord */
    619         for ( ; EntryExitCount > 0; EntryExitCount-- )
    620         {
    621           OTV_OPTIONAL_OFFSET( EntryAnchor );
    622           OTV_OPTIONAL_OFFSET( ExitAnchor  );
    623 
    624           OTV_SIZE_CHECK( EntryAnchor );
    625           if ( EntryAnchor )
    626             otv_Anchor_validate( table + EntryAnchor, otvalid );
    627 
    628           OTV_SIZE_CHECK( ExitAnchor );
    629           if ( ExitAnchor )
    630             otv_Anchor_validate( table + ExitAnchor, otvalid );
    631         }
    632       }
    633       break;
    634 
    635     default:
    636       FT_INVALID_FORMAT;
    637     }
    638 
    639     OTV_EXIT;
    640   }
    641 
    642 
    643   /*************************************************************************/
    644   /*************************************************************************/
    645   /*****                                                               *****/
    646   /*****                     GPOS LOOKUP TYPE 4                        *****/
    647   /*****                                                               *****/
    648   /*************************************************************************/
    649   /*************************************************************************/
    650 
    651   /* UNDOCUMENTED (in OpenType 1.5):              */
    652   /* BaseRecord tables can contain NULL pointers. */
    653 
    654   /* sets otvalid->extra2 (1) */
    655 
    656   static void
    657   otv_MarkBasePos_validate( FT_Bytes       table,
    658                             OTV_Validator  otvalid )
    659   {
    660     FT_Bytes  p = table;
    661     FT_UInt   PosFormat;
    662 
    663 
    664     OTV_NAME_ENTER( "MarkBasePos" );
    665 
    666     OTV_LIMIT_CHECK( 2 );
    667     PosFormat = FT_NEXT_USHORT( p );
    668 
    669     OTV_TRACE(( " (format %d)\n", PosFormat ));
    670 
    671     switch ( PosFormat )
    672     {
    673     case 1:
    674       otvalid->extra2 = 1;
    675       OTV_NEST2( MarkBasePosFormat1, BaseArray );
    676       OTV_RUN( table, otvalid );
    677       break;
    678 
    679     default:
    680       FT_INVALID_FORMAT;
    681     }
    682 
    683     OTV_EXIT;
    684   }
    685 
    686 
    687   /*************************************************************************/
    688   /*************************************************************************/
    689   /*****                                                               *****/
    690   /*****                     GPOS LOOKUP TYPE 5                        *****/
    691   /*****                                                               *****/
    692   /*************************************************************************/
    693   /*************************************************************************/
    694 
    695   /* sets otvalid->extra2 (1) */
    696 
    697   static void
    698   otv_MarkLigPos_validate( FT_Bytes       table,
    699                            OTV_Validator  otvalid )
    700   {
    701     FT_Bytes  p = table;
    702     FT_UInt   PosFormat;
    703 
    704 
    705     OTV_NAME_ENTER( "MarkLigPos" );
    706 
    707     OTV_LIMIT_CHECK( 2 );
    708     PosFormat = FT_NEXT_USHORT( p );
    709 
    710     OTV_TRACE(( " (format %d)\n", PosFormat ));
    711 
    712     switch ( PosFormat )
    713     {
    714     case 1:
    715       otvalid->extra2 = 1;
    716       OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
    717       OTV_RUN( table, otvalid );
    718       break;
    719 
    720     default:
    721       FT_INVALID_FORMAT;
    722     }
    723 
    724     OTV_EXIT;
    725   }
    726 
    727 
    728   /*************************************************************************/
    729   /*************************************************************************/
    730   /*****                                                               *****/
    731   /*****                     GPOS LOOKUP TYPE 6                        *****/
    732   /*****                                                               *****/
    733   /*************************************************************************/
    734   /*************************************************************************/
    735 
    736   /* sets otvalid->extra2 (0) */
    737 
    738   static void
    739   otv_MarkMarkPos_validate( FT_Bytes       table,
    740                             OTV_Validator  otvalid )
    741   {
    742     FT_Bytes  p = table;
    743     FT_UInt   PosFormat;
    744 
    745 
    746     OTV_NAME_ENTER( "MarkMarkPos" );
    747 
    748     OTV_LIMIT_CHECK( 2 );
    749     PosFormat = FT_NEXT_USHORT( p );
    750 
    751     OTV_TRACE(( " (format %d)\n", PosFormat ));
    752 
    753     switch ( PosFormat )
    754     {
    755     case 1:
    756       otvalid->extra2 = 0;
    757       OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
    758       OTV_RUN( table, otvalid );
    759       break;
    760 
    761     default:
    762       FT_INVALID_FORMAT;
    763     }
    764 
    765     OTV_EXIT;
    766   }
    767 
    768 
    769   /*************************************************************************/
    770   /*************************************************************************/
    771   /*****                                                               *****/
    772   /*****                     GPOS LOOKUP TYPE 7                        *****/
    773   /*****                                                               *****/
    774   /*************************************************************************/
    775   /*************************************************************************/
    776 
    777   /* sets otvalid->extra1 (lookup count) */
    778 
    779   static void
    780   otv_ContextPos_validate( FT_Bytes       table,
    781                            OTV_Validator  otvalid )
    782   {
    783     FT_Bytes  p = table;
    784     FT_UInt   PosFormat;
    785 
    786 
    787     OTV_NAME_ENTER( "ContextPos" );
    788 
    789     OTV_LIMIT_CHECK( 2 );
    790     PosFormat = FT_NEXT_USHORT( p );
    791 
    792     OTV_TRACE(( " (format %d)\n", PosFormat ));
    793 
    794     switch ( PosFormat )
    795     {
    796     case 1:
    797       /* no need to check glyph indices/classes used as input for these */
    798       /* context rules since even invalid glyph indices/classes return  */
    799       /* meaningful results                                             */
    800 
    801       otvalid->extra1 = otvalid->lookup_count;
    802       OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
    803       OTV_RUN( table, otvalid );
    804       break;
    805 
    806     case 2:
    807       /* no need to check glyph indices/classes used as input for these */
    808       /* context rules since even invalid glyph indices/classes return  */
    809       /* meaningful results                                             */
    810 
    811       OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
    812       OTV_RUN( table, otvalid );
    813       break;
    814 
    815     case 3:
    816       OTV_NEST1( ContextPosFormat3 );
    817       OTV_RUN( table, otvalid );
    818       break;
    819 
    820     default:
    821       FT_INVALID_FORMAT;
    822     }
    823 
    824     OTV_EXIT;
    825   }
    826 
    827 
    828   /*************************************************************************/
    829   /*************************************************************************/
    830   /*****                                                               *****/
    831   /*****                     GPOS LOOKUP TYPE 8                        *****/
    832   /*****                                                               *****/
    833   /*************************************************************************/
    834   /*************************************************************************/
    835 
    836   /* sets otvalid->extra1 (lookup count) */
    837 
    838   static void
    839   otv_ChainContextPos_validate( FT_Bytes       table,
    840                                 OTV_Validator  otvalid )
    841   {
    842     FT_Bytes  p = table;
    843     FT_UInt   PosFormat;
    844 
    845 
    846     OTV_NAME_ENTER( "ChainContextPos" );
    847 
    848     OTV_LIMIT_CHECK( 2 );
    849     PosFormat = FT_NEXT_USHORT( p );
    850 
    851     OTV_TRACE(( " (format %d)\n", PosFormat ));
    852 
    853     switch ( PosFormat )
    854     {
    855     case 1:
    856       /* no need to check glyph indices/classes used as input for these */
    857       /* context rules since even invalid glyph indices/classes return  */
    858       /* meaningful results                                             */
    859 
    860       otvalid->extra1 = otvalid->lookup_count;
    861       OTV_NEST3( ChainContextPosFormat1,
    862                  ChainPosRuleSet, ChainPosRule );
    863       OTV_RUN( table, otvalid );
    864       break;
    865 
    866     case 2:
    867       /* no need to check glyph indices/classes used as input for these */
    868       /* context rules since even invalid glyph indices/classes return  */
    869       /* meaningful results                                             */
    870 
    871       OTV_NEST3( ChainContextPosFormat2,
    872                  ChainPosClassSet, ChainPosClassRule );
    873       OTV_RUN( table, otvalid );
    874       break;
    875 
    876     case 3:
    877       OTV_NEST1( ChainContextPosFormat3 );
    878       OTV_RUN( table, otvalid );
    879       break;
    880 
    881     default:
    882       FT_INVALID_FORMAT;
    883     }
    884 
    885     OTV_EXIT;
    886   }
    887 
    888 
    889   /*************************************************************************/
    890   /*************************************************************************/
    891   /*****                                                               *****/
    892   /*****                     GPOS LOOKUP TYPE 9                        *****/
    893   /*****                                                               *****/
    894   /*************************************************************************/
    895   /*************************************************************************/
    896 
    897   /* uses otvalid->type_funcs */
    898 
    899   static void
    900   otv_ExtensionPos_validate( FT_Bytes       table,
    901                              OTV_Validator  otvalid )
    902   {
    903     FT_Bytes  p = table;
    904     FT_UInt   PosFormat;
    905 
    906 
    907     OTV_NAME_ENTER( "ExtensionPos" );
    908 
    909     OTV_LIMIT_CHECK( 2 );
    910     PosFormat = FT_NEXT_USHORT( p );
    911 
    912     OTV_TRACE(( " (format %d)\n", PosFormat ));
    913 
    914     switch ( PosFormat )
    915     {
    916     case 1:     /* ExtensionPosFormat1 */
    917       {
    918         FT_UInt            ExtensionLookupType;
    919         FT_ULong           ExtensionOffset;
    920         OTV_Validate_Func  validate;
    921 
    922 
    923         OTV_LIMIT_CHECK( 6 );
    924         ExtensionLookupType = FT_NEXT_USHORT( p );
    925         ExtensionOffset     = FT_NEXT_ULONG( p );
    926 
    927         if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
    928           FT_INVALID_DATA;
    929 
    930         validate = otvalid->type_funcs[ExtensionLookupType - 1];
    931         validate( table + ExtensionOffset, otvalid );
    932       }
    933       break;
    934 
    935     default:
    936       FT_INVALID_FORMAT;
    937     }
    938 
    939     OTV_EXIT;
    940   }
    941 
    942 
    943   static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
    944   {
    945     otv_SinglePos_validate,
    946     otv_PairPos_validate,
    947     otv_CursivePos_validate,
    948     otv_MarkBasePos_validate,
    949     otv_MarkLigPos_validate,
    950     otv_MarkMarkPos_validate,
    951     otv_ContextPos_validate,
    952     otv_ChainContextPos_validate,
    953     otv_ExtensionPos_validate
    954   };
    955 
    956 
    957   /* sets otvalid->type_count */
    958   /* sets otvalid->type_funcs */
    959 
    960   FT_LOCAL_DEF( void )
    961   otv_GPOS_subtable_validate( FT_Bytes       table,
    962                               OTV_Validator  otvalid )
    963   {
    964     otvalid->type_count = 9;
    965     otvalid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
    966 
    967     otv_Lookup_validate( table, otvalid );
    968   }
    969 
    970 
    971   /*************************************************************************/
    972   /*************************************************************************/
    973   /*****                                                               *****/
    974   /*****                          GPOS TABLE                           *****/
    975   /*****                                                               *****/
    976   /*************************************************************************/
    977   /*************************************************************************/
    978 
    979   /* sets otvalid->glyph_count */
    980 
    981   FT_LOCAL_DEF( void )
    982   otv_GPOS_validate( FT_Bytes      table,
    983                      FT_UInt       glyph_count,
    984                      FT_Validator  ftvalid )
    985   {
    986     OTV_ValidatorRec  validrec;
    987     OTV_Validator     otvalid = &validrec;
    988     FT_Bytes          p       = table;
    989     FT_UInt           table_size;
    990     FT_UShort         version;
    991     FT_UInt           ScriptList, FeatureList, LookupList;
    992 
    993     OTV_OPTIONAL_TABLE32( featureVariations );
    994 
    995 
    996     otvalid->root = ftvalid;
    997 
    998     FT_TRACE3(( "validating GPOS table\n" ));
    999     OTV_INIT;
   1000 
   1001     OTV_LIMIT_CHECK( 4 );
   1002 
   1003     if ( FT_NEXT_USHORT( p ) != 1 )  /* majorVersion */
   1004       FT_INVALID_FORMAT;
   1005 
   1006     version = FT_NEXT_USHORT( p );   /* minorVersion */
   1007 
   1008     table_size = 10;
   1009     switch ( version )
   1010     {
   1011     case 0:
   1012       OTV_LIMIT_CHECK( 6 );
   1013       break;
   1014 
   1015     case 1:
   1016       OTV_LIMIT_CHECK( 10 );
   1017       table_size += 4;
   1018       break;
   1019 
   1020     default:
   1021       FT_INVALID_FORMAT;
   1022     }
   1023 
   1024     ScriptList  = FT_NEXT_USHORT( p );
   1025     FeatureList = FT_NEXT_USHORT( p );
   1026     LookupList  = FT_NEXT_USHORT( p );
   1027 
   1028     otvalid->type_count  = 9;
   1029     otvalid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
   1030     otvalid->glyph_count = glyph_count;
   1031 
   1032     otv_LookupList_validate( table + LookupList,
   1033                              otvalid );
   1034     otv_FeatureList_validate( table + FeatureList, table + LookupList,
   1035                               otvalid );
   1036     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
   1037                              otvalid );
   1038 
   1039     if ( version > 0 )
   1040     {
   1041       OTV_OPTIONAL_OFFSET32( featureVariations );
   1042       OTV_SIZE_CHECK32( featureVariations );
   1043       if ( featureVariations )
   1044         OTV_TRACE(( "  [omitting featureVariations validation]\n" )); /* XXX */
   1045     }
   1046 
   1047     FT_TRACE4(( "\n" ));
   1048   }
   1049 
   1050 
   1051 /* END */
   1052