Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /***************************************************************************/
  2. /*                                                                         */
  3. /*  gxvjust.c                                                              */
  4. /*                                                                         */
  5. /*    TrueTypeGX/AAT just table validation (body).                         */
  6. /*                                                                         */
  7. /*  Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,       */
  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. /*                                                                         */
  20. /* gxvalid is derived from both gxlayout module and otvalid module.        */
  21. /* Development of gxlayout is supported by the Information-technology      */
  22. /* Promotion Agency(IPA), Japan.                                           */
  23. /*                                                                         */
  24. /***************************************************************************/
  25.  
  26.  
  27. #include "gxvalid.h"
  28. #include "gxvcommn.h"
  29.  
  30. #include FT_SFNT_NAMES_H
  31.  
  32.  
  33.   /*************************************************************************/
  34.   /*                                                                       */
  35.   /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
  36.   /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
  37.   /* messages during execution.                                            */
  38.   /*                                                                       */
  39. #undef  FT_COMPONENT
  40. #define FT_COMPONENT  trace_gxvjust
  41.  
  42.   /*
  43.    * referred `just' table format specification:
  44.    * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6just.html
  45.    * last updated 2000.
  46.    * ----------------------------------------------
  47.    * [JUST HEADER]: GXV_JUST_HEADER_SIZE
  48.    * version     (fixed:  32bit) = 0x00010000
  49.    * format      (uint16: 16bit) = 0 is only defined (2000)
  50.    * horizOffset (uint16: 16bit)
  51.    * vertOffset  (uint16: 16bit)
  52.    * ----------------------------------------------
  53.    */
  54.  
  55.   typedef struct  GXV_just_DataRec_
  56.   {
  57.     FT_UShort  wdc_offset_max;
  58.     FT_UShort  wdc_offset_min;
  59.     FT_UShort  pc_offset_max;
  60.     FT_UShort  pc_offset_min;
  61.  
  62.   } GXV_just_DataRec, *GXV_just_Data;
  63.  
  64.  
  65. #define  GXV_JUST_DATA( a )  GXV_TABLE_DATA( just, a )
  66.  
  67.  
  68.   /* GX just table does not define their subset of GID */
  69.   static void
  70.   gxv_just_check_max_gid( FT_UShort         gid,
  71.                           const FT_String*  msg_tag,
  72.                           GXV_Validator     valid )
  73.   {
  74.     if ( gid < valid->face->num_glyphs )
  75.       return;
  76.  
  77.     GXV_TRACE(( "just table includes too large %s"
  78.                 " GID=%d > %d (in maxp)\n",
  79.                 msg_tag, gid, valid->face->num_glyphs ));
  80.     GXV_SET_ERR_IF_PARANOID( FT_INVALID_GLYPH_ID );
  81.   }
  82.  
  83.  
  84.   static void
  85.   gxv_just_wdp_entry_validate( FT_Bytes       table,
  86.                                FT_Bytes       limit,
  87.                                GXV_Validator  valid )
  88.   {
  89.     FT_Bytes   p = table;
  90.     FT_ULong   justClass;
  91. #ifdef GXV_LOAD_UNUSED_VARS
  92.     FT_Fixed   beforeGrowLimit;
  93.     FT_Fixed   beforeShrinkGrowLimit;
  94.     FT_Fixed   afterGrowLimit;
  95.     FT_Fixed   afterShrinkGrowLimit;
  96.     FT_UShort  growFlags;
  97.     FT_UShort  shrinkFlags;
  98. #endif
  99.  
  100.  
  101.     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 );
  102.     justClass             = FT_NEXT_ULONG( p );
  103. #ifndef GXV_LOAD_UNUSED_VARS
  104.     p += 4 + 4 + 4 + 4 + 2 + 2;
  105. #else
  106.     beforeGrowLimit       = FT_NEXT_ULONG( p );
  107.     beforeShrinkGrowLimit = FT_NEXT_ULONG( p );
  108.     afterGrowLimit        = FT_NEXT_ULONG( p );
  109.     afterShrinkGrowLimit  = FT_NEXT_ULONG( p );
  110.     growFlags             = FT_NEXT_USHORT( p );
  111.     shrinkFlags           = FT_NEXT_USHORT( p );
  112. #endif
  113.  
  114.     /* According to Apple spec, only 7bits in justClass is used */
  115.     if ( ( justClass & 0xFFFFFF80 ) != 0 )
  116.     {
  117.       GXV_TRACE(( "just table includes non-zero value"
  118.                   " in unused justClass higher bits"
  119.                   " of WidthDeltaPair" ));
  120.       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
  121.     }
  122.  
  123.     valid->subtable_length = p - table;
  124.   }
  125.  
  126.  
  127.   static void
  128.   gxv_just_wdc_entry_validate( FT_Bytes       table,
  129.                                FT_Bytes       limit,
  130.                                GXV_Validator  valid )
  131.   {
  132.     FT_Bytes  p = table;
  133.     FT_ULong  count, i;
  134.  
  135.  
  136.     GXV_LIMIT_CHECK( 4 );
  137.     count = FT_NEXT_ULONG( p );
  138.     for ( i = 0; i < count; i++ )
  139.     {
  140.       GXV_TRACE(( "validating wdc pair %d/%d\n", i + 1, count ));
  141.       gxv_just_wdp_entry_validate( p, limit, valid );
  142.       p += valid->subtable_length;
  143.     }
  144.  
  145.     valid->subtable_length = p - table;
  146.   }
  147.  
  148.  
  149.   static void
  150.   gxv_just_widthDeltaClusters_validate( FT_Bytes       table,
  151.                                         FT_Bytes       limit,
  152.                                         GXV_Validator  valid )
  153.   {
  154.     FT_Bytes  p         = table ;
  155.     FT_Bytes  wdc_end   = table + GXV_JUST_DATA( wdc_offset_max );
  156.     FT_UInt   i;
  157.  
  158.  
  159.     GXV_NAME_ENTER( "just justDeltaClusters" );
  160.  
  161.     if ( limit <= wdc_end )
  162.       FT_INVALID_OFFSET;
  163.  
  164.     for ( i = 0; p <= wdc_end; i++ )
  165.     {
  166.       gxv_just_wdc_entry_validate( p, limit, valid );
  167.       p += valid->subtable_length;
  168.     }
  169.  
  170.     valid->subtable_length = p - table;
  171.  
  172.     GXV_EXIT;
  173.   }
  174.  
  175.  
  176.   static void
  177.   gxv_just_actSubrecord_type0_validate( FT_Bytes       table,
  178.                                         FT_Bytes       limit,
  179.                                         GXV_Validator  valid )
  180.   {
  181.     FT_Bytes   p = table;
  182.  
  183.     FT_Fixed   lowerLimit;
  184.     FT_Fixed   upperLimit;
  185. #ifdef GXV_LOAD_UNUSED_VARS
  186.     FT_UShort  order;
  187. #endif
  188.     FT_UShort  decomposedCount;
  189.  
  190.     FT_UInt    i;
  191.  
  192.  
  193.     GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
  194.     lowerLimit      = FT_NEXT_ULONG( p );
  195.     upperLimit      = FT_NEXT_ULONG( p );
  196. #ifdef GXV_LOAD_UNUSED_VARS
  197.     order           = FT_NEXT_USHORT( p );
  198. #else
  199.     p += 2;
  200. #endif
  201.     decomposedCount = FT_NEXT_USHORT( p );
  202.  
  203.     if ( lowerLimit >= upperLimit )
  204.     {
  205.       GXV_TRACE(( "just table includes invalid range spec:"
  206.                   " lowerLimit(%d) > upperLimit(%d)\n"     ));
  207.       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
  208.     }
  209.  
  210.     for ( i = 0; i < decomposedCount; i++ )
  211.     {
  212.       FT_UShort glyphs;
  213.  
  214.  
  215.       GXV_LIMIT_CHECK( 2 );
  216.       glyphs = FT_NEXT_USHORT( p );
  217.       gxv_just_check_max_gid( glyphs, "type0:glyphs", valid );
  218.     }
  219.  
  220.     valid->subtable_length = p - table;
  221.   }
  222.  
  223.  
  224.   static void
  225.   gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
  226.                                         FT_Bytes       limit,
  227.                                         GXV_Validator  valid )
  228.   {
  229.     FT_Bytes   p = table;
  230.     FT_UShort  addGlyph;
  231.  
  232.  
  233.     GXV_LIMIT_CHECK( 2 );
  234.     addGlyph = FT_NEXT_USHORT( p );
  235.  
  236.     gxv_just_check_max_gid( addGlyph, "type1:addGlyph", valid );
  237.  
  238.     valid->subtable_length = p - table;
  239.   }
  240.  
  241.  
  242.   static void
  243.   gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
  244.                                         FT_Bytes       limit,
  245.                                         GXV_Validator  valid )
  246.   {
  247.     FT_Bytes   p = table;
  248. #ifdef GXV_LOAD_UNUSED_VARS
  249.     FT_Fixed   substThreshhold; /* Apple misspelled "Threshhold" */
  250. #endif
  251.     FT_UShort  addGlyph;
  252.     FT_UShort  substGlyph;
  253.  
  254.  
  255.     GXV_LIMIT_CHECK( 4 + 2 + 2 );
  256. #ifdef GXV_LOAD_UNUSED_VARS
  257.     substThreshhold = FT_NEXT_ULONG( p );
  258. #else
  259.     p += 4;
  260. #endif
  261.     addGlyph        = FT_NEXT_USHORT( p );
  262.     substGlyph      = FT_NEXT_USHORT( p );
  263.  
  264.     if ( addGlyph != 0xFFFF )
  265.       gxv_just_check_max_gid( addGlyph, "type2:addGlyph", valid );
  266.  
  267.     gxv_just_check_max_gid( substGlyph, "type2:substGlyph", valid );
  268.  
  269.     valid->subtable_length = p - table;
  270.   }
  271.  
  272.  
  273.   static void
  274.   gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
  275.                                         FT_Bytes       limit,
  276.                                         GXV_Validator  valid )
  277.   {
  278.     FT_Bytes  p = table;
  279.     FT_ULong  variantsAxis;
  280.     FT_Fixed  minimumLimit;
  281.     FT_Fixed  noStretchValue;
  282.     FT_Fixed  maximumLimit;
  283.  
  284.  
  285.     GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
  286.     variantsAxis   = FT_NEXT_ULONG( p );
  287.     minimumLimit   = FT_NEXT_ULONG( p );
  288.     noStretchValue = FT_NEXT_ULONG( p );
  289.     maximumLimit   = FT_NEXT_ULONG( p );
  290.  
  291.     valid->subtable_length = p - table;
  292.  
  293.     if ( variantsAxis != 0x64756374 ) /* 'duct' */
  294.       GXV_TRACE(( "variantsAxis 0x%08x is non default value",
  295.                    variantsAxis ));
  296.  
  297.     if ( minimumLimit > noStretchValue )
  298.       GXV_TRACE(( "type4:minimumLimit 0x%08x > noStretchValue 0x%08x\n",
  299.                   minimumLimit, noStretchValue ));
  300.     else if ( noStretchValue > maximumLimit )
  301.       GXV_TRACE(( "type4:noStretchValue 0x%08x > maximumLimit 0x%08x\n",
  302.                   noStretchValue, maximumLimit ));
  303.     else if ( !IS_PARANOID_VALIDATION )
  304.       return;
  305.  
  306.     FT_INVALID_DATA;
  307.   }
  308.  
  309.  
  310.   static void
  311.   gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
  312.                                         FT_Bytes       limit,
  313.                                         GXV_Validator  valid )
  314.   {
  315.     FT_Bytes   p = table;
  316.     FT_UShort  flags;
  317.     FT_UShort  glyph;
  318.  
  319.  
  320.     GXV_LIMIT_CHECK( 2 + 2 );
  321.     flags = FT_NEXT_USHORT( p );
  322.     glyph = FT_NEXT_USHORT( p );
  323.  
  324.     if ( flags )
  325.       GXV_TRACE(( "type5: nonzero value 0x%04x in unused flags\n",
  326.                    flags ));
  327.     gxv_just_check_max_gid( glyph, "type5:glyph", valid );
  328.  
  329.     valid->subtable_length = p - table;
  330.   }
  331.  
  332.  
  333.   /* parse single actSubrecord */
  334.   static void
  335.   gxv_just_actSubrecord_validate( FT_Bytes       table,
  336.                                   FT_Bytes       limit,
  337.                                   GXV_Validator  valid )
  338.   {
  339.     FT_Bytes   p = table;
  340.     FT_UShort  actionClass;
  341.     FT_UShort  actionType;
  342.     FT_ULong   actionLength;
  343.  
  344.  
  345.     GXV_NAME_ENTER( "just actSubrecord" );
  346.  
  347.     GXV_LIMIT_CHECK( 2 + 2 + 4 );
  348.     actionClass  = FT_NEXT_USHORT( p );
  349.     actionType   = FT_NEXT_USHORT( p );
  350.     actionLength = FT_NEXT_ULONG( p );
  351.  
  352.     /* actionClass is related with justClass using 7bit only */
  353.     if ( ( actionClass & 0xFF80 ) != 0 )
  354.       GXV_SET_ERR_IF_PARANOID( FT_INVALID_DATA );
  355.  
  356.     if ( actionType == 0 )
  357.       gxv_just_actSubrecord_type0_validate( p, limit, valid );
  358.     else if ( actionType == 1 )
  359.       gxv_just_actSubrecord_type1_validate( p, limit, valid );
  360.     else if ( actionType == 2 )
  361.       gxv_just_actSubrecord_type2_validate( p, limit, valid );
  362.     else if ( actionType == 3 )
  363.       ;                         /* Stretch glyph action: no actionData */
  364.     else if ( actionType == 4 )
  365.       gxv_just_actSubrecord_type4_validate( p, limit, valid );
  366.     else if ( actionType == 5 )
  367.       gxv_just_actSubrecord_type5_validate( p, limit, valid );
  368.     else
  369.       FT_INVALID_DATA;
  370.  
  371.     valid->subtable_length = actionLength;
  372.  
  373.     GXV_EXIT;
  374.   }
  375.  
  376.  
  377.   static void
  378.   gxv_just_pcActionRecord_validate( FT_Bytes       table,
  379.                                     FT_Bytes       limit,
  380.                                     GXV_Validator  valid )
  381.   {
  382.     FT_Bytes  p = table;
  383.     FT_ULong  actionCount;
  384.     FT_ULong  i;
  385.  
  386.  
  387.     GXV_LIMIT_CHECK( 4 );
  388.     actionCount = FT_NEXT_ULONG( p );
  389.     GXV_TRACE(( "actionCount = %d\n", actionCount ));
  390.  
  391.     for ( i = 0; i < actionCount; i++ )
  392.     {
  393.       gxv_just_actSubrecord_validate( p, limit, valid );
  394.       p += valid->subtable_length;
  395.     }
  396.  
  397.     valid->subtable_length = p - table;
  398.  
  399.     GXV_EXIT;
  400.   }
  401.  
  402.  
  403.   static void
  404.   gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
  405.                                                GXV_LookupValueCPtr  value_p,
  406.                                                GXV_Validator        valid )
  407.   {
  408.     FT_UNUSED( glyph );
  409.  
  410.     if ( value_p->u > GXV_JUST_DATA( pc_offset_max ) )
  411.       GXV_JUST_DATA( pc_offset_max ) = value_p->u;
  412.     if ( value_p->u < GXV_JUST_DATA( pc_offset_max ) )
  413.       GXV_JUST_DATA( pc_offset_min ) = value_p->u;
  414.   }
  415.  
  416.  
  417.   static void
  418.   gxv_just_pcLookupTable_validate( FT_Bytes       table,
  419.                                    FT_Bytes       limit,
  420.                                    GXV_Validator  valid )
  421.   {
  422.     FT_Bytes p = table;
  423.  
  424.  
  425.     GXV_NAME_ENTER( "just pcLookupTable" );
  426.     GXV_JUST_DATA( pc_offset_max ) = 0x0000;
  427.     GXV_JUST_DATA( pc_offset_min ) = 0xFFFFU;
  428.  
  429.     valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
  430.     valid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
  431.  
  432.     gxv_LookupTable_validate( p, limit, valid );
  433.  
  434.     /* subtable_length is set by gxv_LookupTable_validate() */
  435.  
  436.     GXV_EXIT;
  437.   }
  438.  
  439.  
  440.   static void
  441.   gxv_just_postcompTable_validate( FT_Bytes       table,
  442.                                    FT_Bytes       limit,
  443.                                    GXV_Validator  valid )
  444.   {
  445.     FT_Bytes  p = table;
  446.  
  447.  
  448.     GXV_NAME_ENTER( "just postcompTable" );
  449.  
  450.     gxv_just_pcLookupTable_validate( p, limit, valid );
  451.     p += valid->subtable_length;
  452.  
  453.     gxv_just_pcActionRecord_validate( p, limit, valid );
  454.     p += valid->subtable_length;
  455.  
  456.     valid->subtable_length = p - table;
  457.  
  458.     GXV_EXIT;
  459.   }
  460.  
  461.  
  462.   static void
  463.   gxv_just_classTable_entry_validate(
  464.     FT_Byte                         state,
  465.     FT_UShort                       flags,
  466.     GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
  467.     FT_Bytes                        table,
  468.     FT_Bytes                        limit,
  469.     GXV_Validator                   valid )
  470.   {
  471. #ifdef GXV_LOAD_UNUSED_VARS
  472.     /* TODO: validate markClass & currentClass */
  473.     FT_UShort  setMark;
  474.     FT_UShort  dontAdvance;
  475.     FT_UShort  markClass;
  476.     FT_UShort  currentClass;
  477. #endif
  478.  
  479.     FT_UNUSED( state );
  480.     FT_UNUSED( glyphOffset_p );
  481.     FT_UNUSED( table );
  482.     FT_UNUSED( limit );
  483.     FT_UNUSED( valid );
  484.  
  485. #ifndef GXV_LOAD_UNUSED_VARS
  486.     FT_UNUSED( flags );
  487. #else
  488.     setMark      = (FT_UShort)( ( flags >> 15 ) & 1    );
  489.     dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1    );
  490.     markClass    = (FT_UShort)( ( flags >> 7  ) & 0x7F );
  491.     currentClass = (FT_UShort)(   flags         & 0x7F );
  492. #endif
  493.   }
  494.  
  495.  
  496.   static void
  497.   gxv_just_justClassTable_validate ( FT_Bytes       table,
  498.                                      FT_Bytes       limit,
  499.                                      GXV_Validator  valid )
  500.   {
  501.     FT_Bytes   p = table;
  502.     FT_UShort  length;
  503.     FT_UShort  coverage;
  504.     FT_ULong   subFeatureFlags;
  505.  
  506.  
  507.     GXV_NAME_ENTER( "just justClassTable" );
  508.  
  509.     GXV_LIMIT_CHECK( 2 + 2 + 4 );
  510.     length          = FT_NEXT_USHORT( p );
  511.     coverage        = FT_NEXT_USHORT( p );
  512.     subFeatureFlags = FT_NEXT_ULONG( p );
  513.  
  514.     GXV_TRACE(( "  justClassTable: coverage = 0x%04x (%s) ", coverage ));
  515.     if ( ( coverage & 0x4000 ) == 0  )
  516.       GXV_TRACE(( "ascending\n" ));
  517.     else
  518.       GXV_TRACE(( "descending\n" ));
  519.  
  520.     if ( subFeatureFlags )
  521.       GXV_TRACE(( "  justClassTable: nonzero value (0x%08x)"
  522.                   " in unused subFeatureFlags\n", subFeatureFlags ));
  523.  
  524.     valid->statetable.optdata               = NULL;
  525.     valid->statetable.optdata_load_func     = NULL;
  526.     valid->statetable.subtable_setup_func   = NULL;
  527.     valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
  528.     valid->statetable.entry_validate_func   =
  529.       gxv_just_classTable_entry_validate;
  530.  
  531.     gxv_StateTable_validate( p, table + length, valid );
  532.  
  533.     /* subtable_length is set by gxv_LookupTable_validate() */
  534.  
  535.     GXV_EXIT;
  536.   }
  537.  
  538.  
  539.   static void
  540.   gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
  541.                                           GXV_LookupValueCPtr  value_p,
  542.                                           GXV_Validator        valid )
  543.   {
  544.     FT_UNUSED( glyph );
  545.  
  546.     if ( value_p->u > GXV_JUST_DATA( wdc_offset_max ) )
  547.       GXV_JUST_DATA( wdc_offset_max ) = value_p->u;
  548.     if ( value_p->u < GXV_JUST_DATA( wdc_offset_min ) )
  549.       GXV_JUST_DATA( wdc_offset_min ) = value_p->u;
  550.   }
  551.  
  552.  
  553.   static void
  554.   gxv_just_justData_lookuptable_validate( FT_Bytes       table,
  555.                                           FT_Bytes       limit,
  556.                                           GXV_Validator  valid )
  557.   {
  558.     FT_Bytes  p = table;
  559.  
  560.  
  561.     GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
  562.     GXV_JUST_DATA( wdc_offset_min ) = 0xFFFFU;
  563.  
  564.     valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
  565.     valid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
  566.  
  567.     gxv_LookupTable_validate( p, limit, valid );
  568.  
  569.     /* subtable_length is set by gxv_LookupTable_validate() */
  570.  
  571.     GXV_EXIT;
  572.   }
  573.  
  574.  
  575.   /*
  576.    * gxv_just_justData_validate() parses and validates horizData, vertData.
  577.    */
  578.   static void
  579.   gxv_just_justData_validate( FT_Bytes       table,
  580.                               FT_Bytes       limit,
  581.                               GXV_Validator  valid )
  582.   {
  583.     /*
  584.      * following 3 offsets are measured from the start of `just'
  585.      * (which table points to), not justData
  586.      */
  587.     FT_UShort  justClassTableOffset;
  588.     FT_UShort  wdcTableOffset;
  589.     FT_UShort  pcTableOffset;
  590.     FT_Bytes   p = table;
  591.  
  592.     GXV_ODTECT( 4, odtect );
  593.  
  594.  
  595.     GXV_NAME_ENTER( "just justData" );
  596.  
  597.     GXV_ODTECT_INIT( odtect );
  598.     GXV_LIMIT_CHECK( 2 + 2 + 2 );
  599.     justClassTableOffset = FT_NEXT_USHORT( p );
  600.     wdcTableOffset       = FT_NEXT_USHORT( p );
  601.     pcTableOffset        = FT_NEXT_USHORT( p );
  602.  
  603.     GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
  604.     GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
  605.     GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
  606.  
  607.     gxv_just_justData_lookuptable_validate( p, limit, valid );
  608.     gxv_odtect_add_range( p, valid->subtable_length,
  609.                           "just_LookupTable", odtect );
  610.  
  611.     if ( wdcTableOffset )
  612.     {
  613.       gxv_just_widthDeltaClusters_validate(
  614.         valid->root->base + wdcTableOffset, limit, valid );
  615.       gxv_odtect_add_range( valid->root->base + wdcTableOffset,
  616.                             valid->subtable_length, "just_wdcTable", odtect );
  617.     }
  618.  
  619.     if ( pcTableOffset )
  620.     {
  621.       gxv_just_postcompTable_validate( valid->root->base + pcTableOffset,
  622.                                        limit, valid );
  623.       gxv_odtect_add_range( valid->root->base + pcTableOffset,
  624.                             valid->subtable_length, "just_pcTable", odtect );
  625.     }
  626.  
  627.     if ( justClassTableOffset )
  628.     {
  629.       gxv_just_justClassTable_validate(
  630.         valid->root->base + justClassTableOffset, limit, valid );
  631.       gxv_odtect_add_range( valid->root->base + justClassTableOffset,
  632.                             valid->subtable_length, "just_justClassTable",
  633.                             odtect );
  634.     }
  635.  
  636.     gxv_odtect_validate( odtect, valid );
  637.  
  638.     GXV_EXIT;
  639.   }
  640.  
  641.  
  642.   FT_LOCAL_DEF( void )
  643.   gxv_just_validate( FT_Bytes      table,
  644.                      FT_Face       face,
  645.                      FT_Validator  ftvalid )
  646.   {
  647.     FT_Bytes           p     = table;
  648.     FT_Bytes           limit = 0;
  649.  
  650.     GXV_ValidatorRec   validrec;
  651.     GXV_Validator      valid = &validrec;
  652.     GXV_just_DataRec   justrec;
  653.     GXV_just_Data      just = &justrec;
  654.  
  655.     FT_ULong           version;
  656.     FT_UShort          format;
  657.     FT_UShort          horizOffset;
  658.     FT_UShort          vertOffset;
  659.  
  660.     GXV_ODTECT( 3, odtect );
  661.  
  662.  
  663.     GXV_ODTECT_INIT( odtect );
  664.  
  665.     valid->root       = ftvalid;
  666.     valid->table_data = just;
  667.     valid->face       = face;
  668.  
  669.     FT_TRACE3(( "validating `just' table\n" ));
  670.     GXV_INIT;
  671.  
  672.     limit      = valid->root->limit;
  673.  
  674.     GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
  675.     version     = FT_NEXT_ULONG( p );
  676.     format      = FT_NEXT_USHORT( p );
  677.     horizOffset = FT_NEXT_USHORT( p );
  678.     vertOffset  = FT_NEXT_USHORT( p );
  679.     gxv_odtect_add_range( table, p - table, "just header", odtect );
  680.  
  681.  
  682.     /* Version 1.0 (always:2000) */
  683.     GXV_TRACE(( " (version = 0x%08x)\n", version ));
  684.     if ( version != 0x00010000UL )
  685.       FT_INVALID_FORMAT;
  686.  
  687.     /* format 0 (always:2000) */
  688.     GXV_TRACE(( " (format = 0x%04x)\n", format ));
  689.     if ( format != 0x0000 )
  690.         FT_INVALID_FORMAT;
  691.  
  692.     GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
  693.     GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
  694.  
  695.  
  696.     /* validate justData */
  697.     if ( 0 < horizOffset )
  698.     {
  699.       gxv_just_justData_validate( table + horizOffset, limit, valid );
  700.       gxv_odtect_add_range( table + horizOffset, valid->subtable_length,
  701.                             "horizJustData", odtect );
  702.     }
  703.  
  704.     if ( 0 < vertOffset )
  705.     {
  706.       gxv_just_justData_validate( table + vertOffset, limit, valid );
  707.       gxv_odtect_add_range( table + vertOffset, valid->subtable_length,
  708.                             "vertJustData", odtect );
  709.     }
  710.  
  711.     gxv_odtect_validate( odtect, valid );
  712.  
  713.     FT_TRACE4(( "\n" ));
  714.   }
  715.  
  716.  
  717. /* END */
  718.