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

/*                                                                         */

/*  gxvmod.c                                                               */

/*                                                                         */

/*    FreeType's TrueTypeGX/AAT validation module implementation (body).   */

/*                                                                         */

/*  Copyright 2004, 2005, 2006                                             */

/*  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 <ft2build.h>

#include FT_TRUETYPE_TABLES_H

#include FT_TRUETYPE_TAGS_H

#include FT_GX_VALIDATE_H

#include FT_INTERNAL_OBJECTS_H

#include FT_SERVICE_GX_VALIDATE_H



#include "gxvmod.h"

#include "gxvalid.h"

#include "gxvcommn.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_gxvmodule





  static FT_Error

  gxv_load_table( FT_Face             face,

                  FT_Tag              tag,

                  FT_Byte* volatile*  table,

                  FT_ULong*           table_len )

  {

    FT_Error   error;

    FT_Memory  memory = FT_FACE_MEMORY( face );





    error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len );

    if ( error == GXV_Err_Table_Missing )

      return GXV_Err_Ok;

    if ( error )

      goto Exit;



    if ( FT_ALLOC( *table, *table_len ) )

      goto Exit;



    error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len );



  Exit:

    return error;

  }





#define GXV_TABLE_DECL( _sfnt )                     \

          FT_Byte* volatile  _sfnt          = NULL; \

          FT_ULong            len_ ## _sfnt = 0



#define GXV_TABLE_LOAD( _sfnt )                                     \

          if ( ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) && \

               ( gx_flags & FT_VALIDATE_ ## _sfnt )            )    \

          {                                                         \

            error = gxv_load_table( face, TTAG_ ## _sfnt,           \

                                    &_sfnt, &len_ ## _sfnt );       \

            if ( error )                                            \

              goto Exit;                                            \

          }



#define GXV_TABLE_VALIDATE( _sfnt )                                  \

          if ( _sfnt )                                               \

          {                                                          \

            ft_validator_init( &valid, _sfnt, _sfnt + len_ ## _sfnt, \

                               FT_VALIDATE_DEFAULT );                \

            if ( ft_setjmp( valid.jump_buffer ) == 0 )               \

              gxv_ ## _sfnt ## _validate( _sfnt, face, &valid );     \

            error = valid.error;                                     \

            if ( error )                                             \

              goto Exit;                                             \

          }



#define GXV_TABLE_SET( _sfnt )                                        \

          if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count )        \

            tables[FT_VALIDATE_ ## _sfnt ## _INDEX] = (FT_Bytes)_sfnt





  static FT_Error

  gxv_validate( FT_Face   face,

                FT_UInt   gx_flags,

                FT_Bytes  tables[FT_VALIDATE_GX_LENGTH],

                FT_UInt   table_count )

  {

    FT_Memory volatile        memory = FT_FACE_MEMORY( face );



    FT_Error                  error = GXV_Err_Ok;

    FT_ValidatorRec volatile  valid;



    FT_UInt  i;





    GXV_TABLE_DECL( feat );

    GXV_TABLE_DECL( bsln );

    GXV_TABLE_DECL( trak );

    GXV_TABLE_DECL( just );

    GXV_TABLE_DECL( mort );

    GXV_TABLE_DECL( morx );

    GXV_TABLE_DECL( kern );

    GXV_TABLE_DECL( opbd );

    GXV_TABLE_DECL( prop );

    GXV_TABLE_DECL( lcar );



    for ( i = 0; i < table_count; i++ )

      tables[i] = 0;



    /* load tables */

    GXV_TABLE_LOAD( feat );

    GXV_TABLE_LOAD( bsln );

    GXV_TABLE_LOAD( trak );

    GXV_TABLE_LOAD( just );

    GXV_TABLE_LOAD( mort );

    GXV_TABLE_LOAD( morx );

    GXV_TABLE_LOAD( kern );

    GXV_TABLE_LOAD( opbd );

    GXV_TABLE_LOAD( prop );

    GXV_TABLE_LOAD( lcar );



    /* validate tables */

    GXV_TABLE_VALIDATE( feat );

    GXV_TABLE_VALIDATE( bsln );

    GXV_TABLE_VALIDATE( trak );

    GXV_TABLE_VALIDATE( just );

    GXV_TABLE_VALIDATE( mort );

    GXV_TABLE_VALIDATE( morx );

    GXV_TABLE_VALIDATE( kern );

    GXV_TABLE_VALIDATE( opbd );

    GXV_TABLE_VALIDATE( prop );

    GXV_TABLE_VALIDATE( lcar );



    /* Set results */

    GXV_TABLE_SET( feat );

    GXV_TABLE_SET( mort );

    GXV_TABLE_SET( morx );

    GXV_TABLE_SET( bsln );

    GXV_TABLE_SET( just );

    GXV_TABLE_SET( kern );

    GXV_TABLE_SET( opbd );

    GXV_TABLE_SET( trak );

    GXV_TABLE_SET( prop );

    GXV_TABLE_SET( lcar );



  Exit:

    if ( error )

    {

      FT_FREE( feat );

      FT_FREE( bsln );

      FT_FREE( trak );

      FT_FREE( just );

      FT_FREE( mort );

      FT_FREE( morx );

      FT_FREE( kern );

      FT_FREE( opbd );

      FT_FREE( prop );

      FT_FREE( lcar );

    }



    return error;

  }





  static FT_Error

  classic_kern_validate( FT_Face    face,

                         FT_UInt    ckern_flags,

                         FT_Bytes*  ckern_table )

  {

    FT_Memory volatile        memory = FT_FACE_MEMORY( face );



    FT_Byte* volatile         ckern     = NULL;

    FT_ULong                  len_ckern = 0;



    /* without volatile on `error' GCC 4.1.1. emits:                         */

    /*  warning: variable 'error' might be clobbered by 'longjmp' or 'vfork' */

    /* this warning seems spurious but ---                                   */

    FT_Error volatile         error = GXV_Err_Ok;

    FT_ValidatorRec volatile  valid;





    *ckern_table = NULL;



    error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern );

    if ( error )

      goto Exit;



    if ( ckern )

    {

      ft_validator_init( &valid, ckern, ckern + len_ckern,

                         FT_VALIDATE_DEFAULT );

      if ( ft_setjmp( valid.jump_buffer ) == 0 )

        gxv_kern_validate_classic( ckern, face,

                                   ckern_flags & FT_VALIDATE_CKERN, &valid );

      error = valid.error;

      if ( error )

        goto Exit;

    }



    *ckern_table = ckern;



  Exit:

    if ( error )

      FT_FREE( ckern );



    return error;

  }





  static

  const FT_Service_GXvalidateRec  gxvalid_interface =

  {

    gxv_validate

  };





  static

  const FT_Service_CKERNvalidateRec  ckernvalid_interface =

  {

    classic_kern_validate

  };





  static

  const FT_ServiceDescRec  gxvalid_services[] =

  {

    { FT_SERVICE_ID_GX_VALIDATE,          &gxvalid_interface },

    { FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface },

    { NULL, NULL }

  };





  static FT_Pointer

  gxvalid_get_service( FT_Module    module,

                       const char*  service_id )

  {

    FT_UNUSED( module );



    return ft_service_list_lookup( gxvalid_services, service_id );

  }





  FT_CALLBACK_TABLE_DEF

  const FT_Module_Class  gxv_module_class =

  {

    0,

    sizeof( FT_ModuleRec ),

    "gxvalid",

    0x10000L,

    0x20000L,



    0,              /* module-specific interface */



    (FT_Module_Constructor)0,

    (FT_Module_Destructor) 0,

    (FT_Module_Requester)  gxvalid_get_service

  };





/* END */

