(root)/
freetype-2.13.2/
src/
otvalid/
otvgpos.c
       1  /****************************************************************************
       2   *
       3   * otvgpos.c
       4   *
       5   *   OpenType GPOS table validation (body).
       6   *
       7   * Copyright (C) 2002-2023 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 = %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 */