tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

otvgpos.c (29663B)


      1 /****************************************************************************
      2 *
      3 * otvgpos.c
      4 *
      5 *   OpenType GPOS table validation (body).
      6 *
      7 * Copyright (C) 2002-2025 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  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 = %u)\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 %u)\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 = %u)\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 %u)\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 = %u)\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 = %u)\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 %u)\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 = %u)\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 = %u)\n", ClassCount1 ));
    528        OTV_TRACE(( " (ClassCount2 = %u)\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 %u)\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 = %u)\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 %u)\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 %u)\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 %u)\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 %u)\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 %u)\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 %u)\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 */