Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  otvgpos.c                                                              */
  4. /*                                                                         */
  5. /*    OpenType GPOS table validation (body).                               */
  6. /*                                                                         */
  7. /*  Copyright 2002, 2004, 2005, 2006, 2007, 2008 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  valid )
  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 * valid->extra1 * 2 );
  75.  
  76.     table_size = Count * valid->extra1 * 2 + 2;
  77.  
  78.     for ( ; Count > 0; Count-- )
  79.       for ( count1 = valid->extra1; count1 > 0; count1-- )
  80.       {
  81.         OTV_OPTIONAL_TABLE( anchor_offset );
  82.  
  83.  
  84.         OTV_OPTIONAL_OFFSET( anchor_offset );
  85.  
  86.         if ( valid->extra2 )
  87.         {
  88.           OTV_SIZE_CHECK( anchor_offset );
  89.           if ( anchor_offset )
  90.             otv_Anchor_validate( table + anchor_offset, valid );
  91.         }
  92.         else
  93.           otv_Anchor_validate( table + anchor_offset, valid );
  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 valid->extra1 (class count) */
  105.  
  106.   static void
  107.   otv_u_O_O_u_O_O( FT_Bytes       table,
  108.                    OTV_Validator  valid )
  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, valid, -1 );
  128.     otv_Coverage_validate( table + Coverage2, valid, -1 );
  129.  
  130.     otv_MarkArray_validate( table + Array1, valid );
  131.  
  132.     valid->nesting_level++;
  133.     func          = valid->func[valid->nesting_level];
  134.     valid->extra1 = ClassCount;
  135.  
  136.     func( table + Array2, valid );
  137.  
  138.     valid->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 valid->extra3 (pointer to base table) */
  167.  
  168.   static void
  169.   otv_ValueRecord_validate( FT_Bytes       table,
  170.                             FT_UInt        format,
  171.                             OTV_Validator  valid )
  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.         /* XXX: this value is usually too small, especially if the current */
  222.         /* ValueRecord is part of an array -- getting the correct table    */
  223.         /* size is probably not worth the trouble                          */
  224.  
  225.         table_size = p - valid->extra3;
  226.  
  227.         OTV_SIZE_CHECK( device );
  228.         if ( device )
  229.           otv_Device_validate( valid->extra3 + device, valid );
  230.       }
  231.       format >>= 1;
  232.     }
  233.  
  234.     OTV_EXIT;
  235.   }
  236.  
  237.  
  238.   /*************************************************************************/
  239.   /*************************************************************************/
  240.   /*****                                                               *****/
  241.   /*****                           ANCHORS                             *****/
  242.   /*****                                                               *****/
  243.   /*************************************************************************/
  244.   /*************************************************************************/
  245.  
  246.   static void
  247.   otv_Anchor_validate( FT_Bytes       table,
  248.                        OTV_Validator  valid )
  249.   {
  250.     FT_Bytes  p = table;
  251.     FT_UInt   AnchorFormat;
  252.  
  253.  
  254.     OTV_NAME_ENTER( "Anchor");
  255.  
  256.     OTV_LIMIT_CHECK( 6 );
  257.     AnchorFormat = FT_NEXT_USHORT( p );
  258.  
  259.     OTV_TRACE(( " (format %d)\n", AnchorFormat ));
  260.  
  261.     p += 4;     /* skip XCoordinate and YCoordinate */
  262.  
  263.     switch ( AnchorFormat )
  264.     {
  265.     case 1:
  266.       break;
  267.  
  268.     case 2:
  269.       OTV_LIMIT_CHECK( 2 );  /* AnchorPoint */
  270.       break;
  271.  
  272.     case 3:
  273.       {
  274.         FT_UInt   table_size;
  275.  
  276.         OTV_OPTIONAL_TABLE( XDeviceTable );
  277.         OTV_OPTIONAL_TABLE( YDeviceTable );
  278.  
  279.  
  280.         OTV_LIMIT_CHECK( 4 );
  281.         OTV_OPTIONAL_OFFSET( XDeviceTable );
  282.         OTV_OPTIONAL_OFFSET( YDeviceTable );
  283.  
  284.         table_size = 6 + 4;
  285.  
  286.         OTV_SIZE_CHECK( XDeviceTable );
  287.         if ( XDeviceTable )
  288.           otv_Device_validate( table + XDeviceTable, valid );
  289.  
  290.         OTV_SIZE_CHECK( YDeviceTable );
  291.         if ( YDeviceTable )
  292.           otv_Device_validate( table + YDeviceTable, valid );
  293.       }
  294.       break;
  295.  
  296.     default:
  297.       FT_INVALID_FORMAT;
  298.     }
  299.  
  300.     OTV_EXIT;
  301.   }
  302.  
  303.  
  304.   /*************************************************************************/
  305.   /*************************************************************************/
  306.   /*****                                                               *****/
  307.   /*****                         MARK ARRAYS                           *****/
  308.   /*****                                                               *****/
  309.   /*************************************************************************/
  310.   /*************************************************************************/
  311.  
  312.   static void
  313.   otv_MarkArray_validate( FT_Bytes       table,
  314.                           OTV_Validator  valid )
  315.   {
  316.     FT_Bytes  p = table;
  317.     FT_UInt   MarkCount;
  318.  
  319.  
  320.     OTV_NAME_ENTER( "MarkArray" );
  321.  
  322.     OTV_LIMIT_CHECK( 2 );
  323.     MarkCount = FT_NEXT_USHORT( p );
  324.  
  325.     OTV_TRACE(( " (MarkCount = %d)\n", MarkCount ));
  326.  
  327.     OTV_LIMIT_CHECK( MarkCount * 4 );
  328.  
  329.     /* MarkRecord */
  330.     for ( ; MarkCount > 0; MarkCount-- )
  331.     {
  332.       p += 2;   /* skip Class */
  333.       /* MarkAnchor */
  334.       otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid );
  335.     }
  336.  
  337.     OTV_EXIT;
  338.   }
  339.  
  340.  
  341.   /*************************************************************************/
  342.   /*************************************************************************/
  343.   /*****                                                               *****/
  344.   /*****                     GPOS LOOKUP TYPE 1                        *****/
  345.   /*****                                                               *****/
  346.   /*************************************************************************/
  347.   /*************************************************************************/
  348.  
  349.   /* sets valid->extra3 (pointer to base table) */
  350.  
  351.   static void
  352.   otv_SinglePos_validate( FT_Bytes       table,
  353.                           OTV_Validator  valid )
  354.   {
  355.     FT_Bytes  p = table;
  356.     FT_UInt   PosFormat;
  357.  
  358.  
  359.     OTV_NAME_ENTER( "SinglePos" );
  360.  
  361.     OTV_LIMIT_CHECK( 2 );
  362.     PosFormat = FT_NEXT_USHORT( p );
  363.  
  364.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  365.  
  366.     valid->extra3 = table;
  367.  
  368.     switch ( PosFormat )
  369.     {
  370.     case 1:     /* SinglePosFormat1 */
  371.       {
  372.         FT_UInt  Coverage, ValueFormat;
  373.  
  374.  
  375.         OTV_LIMIT_CHECK( 4 );
  376.         Coverage    = FT_NEXT_USHORT( p );
  377.         ValueFormat = FT_NEXT_USHORT( p );
  378.  
  379.         otv_Coverage_validate( table + Coverage, valid, -1 );
  380.         otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */
  381.       }
  382.       break;
  383.  
  384.     case 2:     /* SinglePosFormat2 */
  385.       {
  386.         FT_UInt  Coverage, ValueFormat, ValueCount, len_value;
  387.  
  388.  
  389.         OTV_LIMIT_CHECK( 6 );
  390.         Coverage    = FT_NEXT_USHORT( p );
  391.         ValueFormat = FT_NEXT_USHORT( p );
  392.         ValueCount  = FT_NEXT_USHORT( p );
  393.  
  394.         OTV_TRACE(( " (ValueCount = %d)\n", ValueCount ));
  395.  
  396.         len_value = otv_value_length( ValueFormat );
  397.  
  398.         otv_Coverage_validate( table + Coverage, valid, ValueCount );
  399.  
  400.         OTV_LIMIT_CHECK( ValueCount * len_value );
  401.  
  402.         /* Value */
  403.         for ( ; ValueCount > 0; ValueCount-- )
  404.         {
  405.           otv_ValueRecord_validate( p, ValueFormat, valid );
  406.           p += len_value;
  407.         }
  408.       }
  409.       break;
  410.  
  411.     default:
  412.       FT_INVALID_FORMAT;
  413.     }
  414.  
  415.     OTV_EXIT;
  416.   }
  417.  
  418.  
  419.   /*************************************************************************/
  420.   /*************************************************************************/
  421.   /*****                                                               *****/
  422.   /*****                     GPOS LOOKUP TYPE 2                        *****/
  423.   /*****                                                               *****/
  424.   /*************************************************************************/
  425.   /*************************************************************************/
  426.  
  427.   static void
  428.   otv_PairSet_validate( FT_Bytes       table,
  429.                         FT_UInt        format1,
  430.                         FT_UInt        format2,
  431.                         OTV_Validator  valid )
  432.   {
  433.     FT_Bytes  p = table;
  434.     FT_UInt   value_len1, value_len2, PairValueCount;
  435.  
  436.  
  437.     OTV_NAME_ENTER( "PairSet" );
  438.  
  439.     OTV_LIMIT_CHECK( 2 );
  440.     PairValueCount = FT_NEXT_USHORT( p );
  441.  
  442.     OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount ));
  443.  
  444.     value_len1 = otv_value_length( format1 );
  445.     value_len2 = otv_value_length( format2 );
  446.  
  447.     OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) );
  448.  
  449.     /* PairValueRecord */
  450.     for ( ; PairValueCount > 0; PairValueCount-- )
  451.     {
  452.       p += 2;       /* skip SecondGlyph */
  453.  
  454.       if ( format1 )
  455.         otv_ValueRecord_validate( p, format1, valid ); /* Value1 */
  456.       p += value_len1;
  457.  
  458.       if ( format2 )
  459.         otv_ValueRecord_validate( p, format2, valid ); /* Value2 */
  460.       p += value_len2;
  461.     }
  462.  
  463.     OTV_EXIT;
  464.   }
  465.  
  466.  
  467.   /* sets valid->extra3 (pointer to base table) */
  468.  
  469.   static void
  470.   otv_PairPos_validate( FT_Bytes       table,
  471.                         OTV_Validator  valid )
  472.   {
  473.     FT_Bytes  p = table;
  474.     FT_UInt   PosFormat;
  475.  
  476.  
  477.     OTV_NAME_ENTER( "PairPos" );
  478.  
  479.     OTV_LIMIT_CHECK( 2 );
  480.     PosFormat = FT_NEXT_USHORT( p );
  481.  
  482.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  483.  
  484.     valid->extra3 = table;
  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, valid, -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, valid );
  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, valid, -1 );
  534.         otv_ClassDef_validate( table + ClassDef1, valid );
  535.         otv_ClassDef_validate( table + ClassDef2, valid );
  536.  
  537.         OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 *
  538.                      ( len_value1 + len_value2 ) );
  539.  
  540.         /* Class1Record */
  541.         for ( ; ClassCount1 > 0; ClassCount1-- )
  542.         {
  543.           /* Class2Record */
  544.           for ( count = ClassCount2; count > 0; count-- )
  545.           {
  546.             if ( ValueFormat1 )
  547.               /* Value1 */
  548.               otv_ValueRecord_validate( p, ValueFormat1, valid );
  549.             p += len_value1;
  550.  
  551.             if ( ValueFormat2 )
  552.               /* Value2 */
  553.               otv_ValueRecord_validate( p, ValueFormat2, valid );
  554.             p += len_value2;
  555.           }
  556.         }
  557.       }
  558.       break;
  559.  
  560.     default:
  561.       FT_INVALID_FORMAT;
  562.     }
  563.  
  564.     OTV_EXIT;
  565.   }
  566.  
  567.  
  568.   /*************************************************************************/
  569.   /*************************************************************************/
  570.   /*****                                                               *****/
  571.   /*****                     GPOS LOOKUP TYPE 3                        *****/
  572.   /*****                                                               *****/
  573.   /*************************************************************************/
  574.   /*************************************************************************/
  575.  
  576.   static void
  577.   otv_CursivePos_validate( FT_Bytes       table,
  578.                            OTV_Validator  valid )
  579.   {
  580.     FT_Bytes  p = table;
  581.     FT_UInt   PosFormat;
  582.  
  583.  
  584.     OTV_NAME_ENTER( "CursivePos" );
  585.  
  586.     OTV_LIMIT_CHECK( 2 );
  587.     PosFormat = FT_NEXT_USHORT( p );
  588.  
  589.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  590.  
  591.     switch ( PosFormat )
  592.     {
  593.     case 1:     /* CursivePosFormat1 */
  594.       {
  595.         FT_UInt   table_size;
  596.         FT_UInt   Coverage, EntryExitCount;
  597.  
  598.         OTV_OPTIONAL_TABLE( EntryAnchor );
  599.         OTV_OPTIONAL_TABLE( ExitAnchor  );
  600.  
  601.  
  602.         OTV_LIMIT_CHECK( 4 );
  603.         Coverage       = FT_NEXT_USHORT( p );
  604.         EntryExitCount = FT_NEXT_USHORT( p );
  605.  
  606.         OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount ));
  607.  
  608.         otv_Coverage_validate( table + Coverage, valid, EntryExitCount );
  609.  
  610.         OTV_LIMIT_CHECK( EntryExitCount * 4 );
  611.  
  612.         table_size = EntryExitCount * 4 + 4;
  613.  
  614.         /* EntryExitRecord */
  615.         for ( ; EntryExitCount > 0; EntryExitCount-- )
  616.         {
  617.           OTV_OPTIONAL_OFFSET( EntryAnchor );
  618.           OTV_OPTIONAL_OFFSET( ExitAnchor  );
  619.  
  620.           OTV_SIZE_CHECK( EntryAnchor );
  621.           if ( EntryAnchor )
  622.             otv_Anchor_validate( table + EntryAnchor, valid );
  623.  
  624.           OTV_SIZE_CHECK( ExitAnchor );
  625.           if ( ExitAnchor )
  626.             otv_Anchor_validate( table + ExitAnchor, valid );
  627.         }
  628.       }
  629.       break;
  630.  
  631.     default:
  632.       FT_INVALID_FORMAT;
  633.     }
  634.  
  635.     OTV_EXIT;
  636.   }
  637.  
  638.  
  639.   /*************************************************************************/
  640.   /*************************************************************************/
  641.   /*****                                                               *****/
  642.   /*****                     GPOS LOOKUP TYPE 4                        *****/
  643.   /*****                                                               *****/
  644.   /*************************************************************************/
  645.   /*************************************************************************/
  646.  
  647.   /* UNDOCUMENTED (in OpenType 1.5):              */
  648.   /* BaseRecord tables can contain NULL pointers. */
  649.  
  650.   /* sets valid->extra2 (1) */
  651.  
  652.   static void
  653.   otv_MarkBasePos_validate( FT_Bytes       table,
  654.                             OTV_Validator  valid )
  655.   {
  656.     FT_Bytes  p = table;
  657.     FT_UInt   PosFormat;
  658.  
  659.  
  660.     OTV_NAME_ENTER( "MarkBasePos" );
  661.  
  662.     OTV_LIMIT_CHECK( 2 );
  663.     PosFormat = FT_NEXT_USHORT( p );
  664.  
  665.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  666.  
  667.     switch ( PosFormat )
  668.     {
  669.     case 1:
  670.       valid->extra2 = 1;
  671.       OTV_NEST2( MarkBasePosFormat1, BaseArray );
  672.       OTV_RUN( table, valid );
  673.       break;
  674.  
  675.     default:
  676.       FT_INVALID_FORMAT;
  677.     }
  678.  
  679.     OTV_EXIT;
  680.   }
  681.  
  682.  
  683.   /*************************************************************************/
  684.   /*************************************************************************/
  685.   /*****                                                               *****/
  686.   /*****                     GPOS LOOKUP TYPE 5                        *****/
  687.   /*****                                                               *****/
  688.   /*************************************************************************/
  689.   /*************************************************************************/
  690.  
  691.   /* sets valid->extra2 (1) */
  692.  
  693.   static void
  694.   otv_MarkLigPos_validate( FT_Bytes       table,
  695.                            OTV_Validator  valid )
  696.   {
  697.     FT_Bytes  p = table;
  698.     FT_UInt   PosFormat;
  699.  
  700.  
  701.     OTV_NAME_ENTER( "MarkLigPos" );
  702.  
  703.     OTV_LIMIT_CHECK( 2 );
  704.     PosFormat = FT_NEXT_USHORT( p );
  705.  
  706.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  707.  
  708.     switch ( PosFormat )
  709.     {
  710.     case 1:
  711.       valid->extra2 = 1;
  712.       OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach );
  713.       OTV_RUN( table, valid );
  714.       break;
  715.  
  716.     default:
  717.       FT_INVALID_FORMAT;
  718.     }
  719.  
  720.     OTV_EXIT;
  721.   }
  722.  
  723.  
  724.   /*************************************************************************/
  725.   /*************************************************************************/
  726.   /*****                                                               *****/
  727.   /*****                     GPOS LOOKUP TYPE 6                        *****/
  728.   /*****                                                               *****/
  729.   /*************************************************************************/
  730.   /*************************************************************************/
  731.  
  732.   /* sets valid->extra2 (0) */
  733.  
  734.   static void
  735.   otv_MarkMarkPos_validate( FT_Bytes       table,
  736.                             OTV_Validator  valid )
  737.   {
  738.     FT_Bytes  p = table;
  739.     FT_UInt   PosFormat;
  740.  
  741.  
  742.     OTV_NAME_ENTER( "MarkMarkPos" );
  743.  
  744.     OTV_LIMIT_CHECK( 2 );
  745.     PosFormat = FT_NEXT_USHORT( p );
  746.  
  747.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  748.  
  749.     switch ( PosFormat )
  750.     {
  751.     case 1:
  752.       valid->extra2 = 0;
  753.       OTV_NEST2( MarkMarkPosFormat1, Mark2Array );
  754.       OTV_RUN( table, valid );
  755.       break;
  756.  
  757.     default:
  758.       FT_INVALID_FORMAT;
  759.     }
  760.  
  761.     OTV_EXIT;
  762.   }
  763.  
  764.  
  765.   /*************************************************************************/
  766.   /*************************************************************************/
  767.   /*****                                                               *****/
  768.   /*****                     GPOS LOOKUP TYPE 7                        *****/
  769.   /*****                                                               *****/
  770.   /*************************************************************************/
  771.   /*************************************************************************/
  772.  
  773.   /* sets valid->extra1 (lookup count) */
  774.  
  775.   static void
  776.   otv_ContextPos_validate( FT_Bytes       table,
  777.                            OTV_Validator  valid )
  778.   {
  779.     FT_Bytes  p = table;
  780.     FT_UInt   PosFormat;
  781.  
  782.  
  783.     OTV_NAME_ENTER( "ContextPos" );
  784.  
  785.     OTV_LIMIT_CHECK( 2 );
  786.     PosFormat = FT_NEXT_USHORT( p );
  787.  
  788.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  789.  
  790.     switch ( PosFormat )
  791.     {
  792.     case 1:
  793.       /* no need to check glyph indices/classes used as input for these */
  794.       /* context rules since even invalid glyph indices/classes return  */
  795.       /* meaningful results                                             */
  796.  
  797.       valid->extra1 = valid->lookup_count;
  798.       OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule );
  799.       OTV_RUN( table, valid );
  800.       break;
  801.  
  802.     case 2:
  803.       /* no need to check glyph indices/classes used as input for these */
  804.       /* context rules since even invalid glyph indices/classes return  */
  805.       /* meaningful results                                             */
  806.  
  807.       OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule );
  808.       OTV_RUN( table, valid );
  809.       break;
  810.  
  811.     case 3:
  812.       OTV_NEST1( ContextPosFormat3 );
  813.       OTV_RUN( table, valid );
  814.       break;
  815.  
  816.     default:
  817.       FT_INVALID_FORMAT;
  818.     }
  819.  
  820.     OTV_EXIT;
  821.   }
  822.  
  823.  
  824.   /*************************************************************************/
  825.   /*************************************************************************/
  826.   /*****                                                               *****/
  827.   /*****                     GPOS LOOKUP TYPE 8                        *****/
  828.   /*****                                                               *****/
  829.   /*************************************************************************/
  830.   /*************************************************************************/
  831.  
  832.   /* sets valid->extra1 (lookup count) */
  833.  
  834.   static void
  835.   otv_ChainContextPos_validate( FT_Bytes       table,
  836.                                 OTV_Validator  valid )
  837.   {
  838.     FT_Bytes  p = table;
  839.     FT_UInt   PosFormat;
  840.  
  841.  
  842.     OTV_NAME_ENTER( "ChainContextPos" );
  843.  
  844.     OTV_LIMIT_CHECK( 2 );
  845.     PosFormat = FT_NEXT_USHORT( p );
  846.  
  847.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  848.  
  849.     switch ( PosFormat )
  850.     {
  851.     case 1:
  852.       /* no need to check glyph indices/classes used as input for these */
  853.       /* context rules since even invalid glyph indices/classes return  */
  854.       /* meaningful results                                             */
  855.  
  856.       valid->extra1 = valid->lookup_count;
  857.       OTV_NEST3( ChainContextPosFormat1,
  858.                  ChainPosRuleSet, ChainPosRule );
  859.       OTV_RUN( table, valid );
  860.       break;
  861.  
  862.     case 2:
  863.       /* no need to check glyph indices/classes used as input for these */
  864.       /* context rules since even invalid glyph indices/classes return  */
  865.       /* meaningful results                                             */
  866.  
  867.       OTV_NEST3( ChainContextPosFormat2,
  868.                  ChainPosClassSet, ChainPosClassRule );
  869.       OTV_RUN( table, valid );
  870.       break;
  871.  
  872.     case 3:
  873.       OTV_NEST1( ChainContextPosFormat3 );
  874.       OTV_RUN( table, valid );
  875.       break;
  876.  
  877.     default:
  878.       FT_INVALID_FORMAT;
  879.     }
  880.  
  881.     OTV_EXIT;
  882.   }
  883.  
  884.  
  885.   /*************************************************************************/
  886.   /*************************************************************************/
  887.   /*****                                                               *****/
  888.   /*****                     GPOS LOOKUP TYPE 9                        *****/
  889.   /*****                                                               *****/
  890.   /*************************************************************************/
  891.   /*************************************************************************/
  892.  
  893.   /* uses valid->type_funcs */
  894.  
  895.   static void
  896.   otv_ExtensionPos_validate( FT_Bytes       table,
  897.                              OTV_Validator  valid )
  898.   {
  899.     FT_Bytes  p = table;
  900.     FT_UInt   PosFormat;
  901.  
  902.  
  903.     OTV_NAME_ENTER( "ExtensionPos" );
  904.  
  905.     OTV_LIMIT_CHECK( 2 );
  906.     PosFormat = FT_NEXT_USHORT( p );
  907.  
  908.     OTV_TRACE(( " (format %d)\n", PosFormat ));
  909.  
  910.     switch ( PosFormat )
  911.     {
  912.     case 1:     /* ExtensionPosFormat1 */
  913.       {
  914.         FT_UInt            ExtensionLookupType;
  915.         FT_ULong           ExtensionOffset;
  916.         OTV_Validate_Func  validate;
  917.  
  918.  
  919.         OTV_LIMIT_CHECK( 6 );
  920.         ExtensionLookupType = FT_NEXT_USHORT( p );
  921.         ExtensionOffset     = FT_NEXT_ULONG( p );
  922.  
  923.         if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 )
  924.           FT_INVALID_DATA;
  925.  
  926.         validate = valid->type_funcs[ExtensionLookupType - 1];
  927.         validate( table + ExtensionOffset, valid );
  928.       }
  929.       break;
  930.  
  931.     default:
  932.       FT_INVALID_FORMAT;
  933.     }
  934.  
  935.     OTV_EXIT;
  936.   }
  937.  
  938.  
  939.   static const OTV_Validate_Func  otv_gpos_validate_funcs[9] =
  940.   {
  941.     otv_SinglePos_validate,
  942.     otv_PairPos_validate,
  943.     otv_CursivePos_validate,
  944.     otv_MarkBasePos_validate,
  945.     otv_MarkLigPos_validate,
  946.     otv_MarkMarkPos_validate,
  947.     otv_ContextPos_validate,
  948.     otv_ChainContextPos_validate,
  949.     otv_ExtensionPos_validate
  950.   };
  951.  
  952.  
  953.   /* sets valid->type_count */
  954.   /* sets valid->type_funcs */
  955.  
  956.   FT_LOCAL_DEF( void )
  957.   otv_GPOS_subtable_validate( FT_Bytes       table,
  958.                               OTV_Validator  valid )
  959.   {
  960.     valid->type_count = 9;
  961.     valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs;
  962.  
  963.     otv_Lookup_validate( table, valid );
  964.   }
  965.  
  966.  
  967.   /*************************************************************************/
  968.   /*************************************************************************/
  969.   /*****                                                               *****/
  970.   /*****                          GPOS TABLE                           *****/
  971.   /*****                                                               *****/
  972.   /*************************************************************************/
  973.   /*************************************************************************/
  974.  
  975.   /* sets valid->glyph_count */
  976.  
  977.   FT_LOCAL_DEF( void )
  978.   otv_GPOS_validate( FT_Bytes      table,
  979.                      FT_UInt       glyph_count,
  980.                      FT_Validator  ftvalid )
  981.   {
  982.     OTV_ValidatorRec  validrec;
  983.     OTV_Validator     valid = &validrec;
  984.     FT_Bytes          p     = table;
  985.     FT_UInt           ScriptList, FeatureList, LookupList;
  986.  
  987.  
  988.     valid->root = ftvalid;
  989.  
  990.     FT_TRACE3(( "validating GPOS table\n" ));
  991.     OTV_INIT;
  992.  
  993.     OTV_LIMIT_CHECK( 10 );
  994.  
  995.     if ( FT_NEXT_ULONG( p ) != 0x10000UL )      /* Version */
  996.       FT_INVALID_FORMAT;
  997.  
  998.     ScriptList  = FT_NEXT_USHORT( p );
  999.     FeatureList = FT_NEXT_USHORT( p );
  1000.     LookupList  = FT_NEXT_USHORT( p );
  1001.  
  1002.     valid->type_count  = 9;
  1003.     valid->type_funcs  = (OTV_Validate_Func*)otv_gpos_validate_funcs;
  1004.     valid->glyph_count = glyph_count;
  1005.  
  1006.     otv_LookupList_validate( table + LookupList,
  1007.                              valid );
  1008.     otv_FeatureList_validate( table + FeatureList, table + LookupList,
  1009.                               valid );
  1010.     otv_ScriptList_validate( table + ScriptList, table + FeatureList,
  1011.                              valid );
  1012.  
  1013.     FT_TRACE4(( "\n" ));
  1014.   }
  1015.  
  1016.  
  1017. /* END */
  1018.