/***************************************************************************/

/*                                                                         */

/*  gxvmort2.c                                                             */

/*                                                                         */

/*    TrueTypeGX/AAT mort table validation                                 */

/*    body for type2 (Ligature Substitution) subtable.                     */

/*                                                                         */

/*  Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,       */

/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */

/*                                                                         */

/*  This file is part of the FreeType project, and may only be used,       */

/*  modified, and distributed under the terms of the FreeType project      */

/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */

/*  this file you indicate that you have read the license and              */

/*  understand and accept it fully.                                        */

/*                                                                         */

/***************************************************************************/



/***************************************************************************/

/*                                                                         */

/* gxvalid is derived from both gxlayout module and otvalid module.        */

/* Development of gxlayout is supported by the Information-technology      */

/* Promotion Agency(IPA), Japan.                                           */

/*                                                                         */

/***************************************************************************/





#include "gxvmort.h"





  /*************************************************************************/

  /*                                                                       */

  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */

  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */

  /* messages during execution.                                            */

  /*                                                                       */

#undef  FT_COMPONENT

#define FT_COMPONENT  trace_gxvmort





  typedef struct  GXV_mort_subtable_type2_StateOptRec_

  {

    FT_UShort  ligActionTable;

    FT_UShort  componentTable;

    FT_UShort  ligatureTable;

    FT_UShort  ligActionTable_length;

    FT_UShort  componentTable_length;

    FT_UShort  ligatureTable_length;



  }  GXV_mort_subtable_type2_StateOptRec,

    *GXV_mort_subtable_type2_StateOptRecData;



#define GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE \

          ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 )





  static void

  gxv_mort_subtable_type2_opttable_load( FT_Bytes       table,

                                         FT_Bytes       limit,

                                         GXV_Validator  valid )

  {

    FT_Bytes p = table;

    GXV_mort_subtable_type2_StateOptRecData  optdata =

      (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata;





    GXV_LIMIT_CHECK( 2 + 2 + 2 );

    optdata->ligActionTable = FT_NEXT_USHORT( p );

    optdata->componentTable = FT_NEXT_USHORT( p );

    optdata->ligatureTable  = FT_NEXT_USHORT( p );



    GXV_TRACE(( "offset to ligActionTable=0x%04x\n",

                optdata->ligActionTable ));

    GXV_TRACE(( "offset to componentTable=0x%04x\n",

                optdata->componentTable ));

    GXV_TRACE(( "offset to ligatureTable=0x%04x\n",

                optdata->ligatureTable ));

  }





  static void

  gxv_mort_subtable_type2_subtable_setup( FT_UShort      table_size,

                                          FT_UShort      classTable,

                                          FT_UShort      stateArray,

                                          FT_UShort      entryTable,

                                          FT_UShort      *classTable_length_p,

                                          FT_UShort      *stateArray_length_p,

                                          FT_UShort      *entryTable_length_p,

                                          GXV_Validator  valid )

  {

    FT_UShort  o[6];

    FT_UShort  *l[6];

    FT_UShort  buff[7];



    GXV_mort_subtable_type2_StateOptRecData  optdata =

      (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata;





    GXV_NAME_ENTER( "subtable boundaries setup" );



    o[0] = classTable;

    o[1] = stateArray;

    o[2] = entryTable;

    o[3] = optdata->ligActionTable;

    o[4] = optdata->componentTable;

    o[5] = optdata->ligatureTable;

    l[0] = classTable_length_p;

    l[1] = stateArray_length_p;

    l[2] = entryTable_length_p;

    l[3] = &(optdata->ligActionTable_length);

    l[4] = &(optdata->componentTable_length);

    l[5] = &(optdata->ligatureTable_length);



    gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, valid );



    GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n",

                classTable, *classTable_length_p ));

    GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n",

                stateArray, *stateArray_length_p ));

    GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n",

                entryTable, *entryTable_length_p ));

    GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n",

                optdata->ligActionTable,

                optdata->ligActionTable_length ));

    GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n",

                optdata->componentTable,

                optdata->componentTable_length ));

    GXV_TRACE(( "ligatureTable:  offset=0x%04x length=0x%04x\n",

                optdata->ligatureTable,

                optdata->ligatureTable_length ));



    GXV_EXIT;

  }





  static void

  gxv_mort_subtable_type2_ligActionOffset_validate(

    FT_Bytes       table,

    FT_UShort      ligActionOffset,

    GXV_Validator  valid )

  {

    /* access ligActionTable */

    GXV_mort_subtable_type2_StateOptRecData  optdata =

      (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata;



    FT_Bytes lat_base  = table + optdata->ligActionTable;

    FT_Bytes p         = table + ligActionOffset;

    FT_Bytes lat_limit = lat_base + optdata->ligActionTable;





    GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset );

    if ( p < lat_base )

    {

      GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n",

                  ligActionOffset, lat_base - p ));



      /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */

      if ( valid->root->level >= FT_VALIDATE_PARANOID )

        FT_INVALID_OFFSET;

    }

    else if ( lat_limit < p )

    {

      GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n",

                  ligActionOffset, p - lat_limit ));



      /* FontValidator, ftxvalidator, ftxdumperfuser warn but continue */

      if ( valid->root->level >= FT_VALIDATE_PARANOID )

        FT_INVALID_OFFSET;

    }

    else

    {

      /* validate entry in ligActionTable */

      FT_ULong   lig_action;

      FT_UShort  last;

      FT_UShort  store;

      FT_ULong   offset;





      lig_action = FT_NEXT_ULONG( p );

      last   = (FT_UShort)( ( lig_action >> 31 ) & 1 );

      store  = (FT_UShort)( ( lig_action >> 30 ) & 1 );



      offset = lig_action & 0x3FFFFFFFUL;

    }

  }





  static void

  gxv_mort_subtable_type2_entry_validate(

    FT_Byte                         state,

    FT_UShort                       flags,

    GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,

    FT_Bytes                        table,

    FT_Bytes                        limit,

    GXV_Validator                   valid )

  {

    FT_UShort setComponent;

    FT_UShort dontAdvance;

    FT_UShort offset;



    FT_UNUSED( state );

    FT_UNUSED( glyphOffset_p );

    FT_UNUSED( limit );





    setComponent = (FT_UShort)( ( flags >> 15 ) & 1 );

    dontAdvance  = (FT_UShort)( ( flags >> 14 ) & 1 );



    offset = (FT_UShort)( flags & 0x3FFFU );



    if ( 0 < offset )

      gxv_mort_subtable_type2_ligActionOffset_validate( table, offset,

                                                        valid );

  }





  static void

  gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes       table,

                                                  GXV_Validator  valid )

  {

    GXV_mort_subtable_type2_StateOptRecData  optdata =

      (GXV_mort_subtable_type2_StateOptRecData)valid->statetable.optdata;



    FT_Bytes p     = table + optdata->ligatureTable;

    FT_Bytes limit = table + optdata->ligatureTable

                           + optdata->ligatureTable_length;





    GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" );

    if ( 0 != optdata->ligatureTable )

    {

      /* Apple does not give specification of ligatureTable format */

      while ( p < limit )

      {

        FT_UShort  lig_gid;





        GXV_LIMIT_CHECK( 2 );

        lig_gid = FT_NEXT_USHORT( p );

      }

    }

    GXV_EXIT;

  }





  FT_LOCAL_DEF( void )

  gxv_mort_subtable_type2_validate( FT_Bytes       table,

                                    FT_Bytes       limit,

                                    GXV_Validator  valid )

  {

    FT_Bytes  p = table;



    GXV_mort_subtable_type2_StateOptRec  lig_rec;





    GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" );



    GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE );



    valid->statetable.optdata =

      &lig_rec;

    valid->statetable.optdata_load_func =

      gxv_mort_subtable_type2_opttable_load;

    valid->statetable.subtable_setup_func =

      gxv_mort_subtable_type2_subtable_setup;

    valid->statetable.entry_glyphoffset_fmt =

      GXV_GLYPHOFFSET_NONE;

    valid->statetable.entry_validate_func =

      gxv_mort_subtable_type2_entry_validate;



    gxv_StateTable_validate( p, limit, valid );



    p += valid->subtable_length;

    gxv_mort_subtable_type2_ligatureTable_validate( table, valid );



    valid->subtable_length = p - table;



    GXV_EXIT;

  }





/* END */

