code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx.c                                                              */
/*                                                                         */
/*    TrueTypeGX/AAT morx table validation (body).                         */
/*                                                                         */
/*  Copyright 2005, 2008 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 "gxvmorx.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_gxvmorx

  static void
  gxv_morx_subtables_validate( FT_Bytes       table,
                               FT_Bytes       limit,
                               FT_UShort      nSubtables,
                               GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_Validate_Func fmt_funcs_table[] =
    {
      gxv_morx_subtable_type0_validate, /* 0 */
      gxv_morx_subtable_type1_validate, /* 1 */
      gxv_morx_subtable_type2_validate, /* 2 */
      NULL,                             /* 3 */
      gxv_morx_subtable_type4_validate, /* 4 */
      gxv_morx_subtable_type5_validate, /* 5 */

    };

    GXV_Validate_Func  func;

    FT_UShort  i;

    GXV_NAME_ENTER( "subtables in a chain" );

    for ( i = 0; i < nSubtables; i++ )
    {
      FT_ULong  length;
      FT_ULong  coverage;
      FT_ULong  subFeatureFlags;
      FT_ULong  type;
      FT_ULong  rest;

      GXV_LIMIT_CHECK( 4 + 4 + 4 );
      length          = FT_NEXT_ULONG( p );
      coverage        = FT_NEXT_ULONG( p );
      subFeatureFlags = FT_NEXT_ULONG( p );

      GXV_TRACE(( "validating chain subtable %d/%d (%d bytes)\n",
                  i + 1, nSubtables, length ));

      type = coverage & 0x0007;
      rest = length - ( 4 + 4 + 4 );
      GXV_LIMIT_CHECK( rest );

      /* morx coverage consists of mort_coverage & 16bit padding */
      gxv_mort_coverage_validate( (FT_UShort)( ( coverage >> 16 ) | coverage ),
                                  valid );
      if ( type > 5 )
        FT_INVALID_FORMAT;

      func = fmt_funcs_table[type];
      if ( func == NULL )
        GXV_TRACE(( "morx type %d is reserved\n", type ));

      func( p, p + rest, valid );

      p += rest;
    }

    valid->subtable_length = p - table;

    GXV_EXIT;
  }

  static void
  gxv_morx_chain_validate( FT_Bytes       table,
                           FT_Bytes       limit,
                           GXV_Validator  valid )
  {
    FT_Bytes  p = table;
    FT_ULong  defaultFlags;
    FT_ULong  chainLength;
    FT_ULong  nFeatureFlags;
    FT_ULong  nSubtables;

    GXV_NAME_ENTER( "morx chain header" );

    GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
    defaultFlags  = FT_NEXT_ULONG( p );
    chainLength   = FT_NEXT_ULONG( p );
    nFeatureFlags = FT_NEXT_ULONG( p );
    nSubtables    = FT_NEXT_ULONG( p );

    /* feature-array of morx is same with that of mort */
    gxv_mort_featurearray_validate( p, limit, nFeatureFlags, valid );
    p += valid->subtable_length;

    if ( nSubtables >= 0x10000L )
      FT_INVALID_DATA;

    gxv_morx_subtables_validate( p, table + chainLength,
                                 (FT_UShort)nSubtables, valid );

    valid->subtable_length = chainLength;

    GXV_EXIT;
  }

  FT_LOCAL_DEF( void )
  gxv_morx_validate( FT_Bytes      table,
                     FT_Face       face,
                     FT_Validator  ftvalid )
  {
    GXV_ValidatorRec  validrec;
    GXV_Validator     valid = &validrec;
    FT_Bytes          p     = table;
    FT_Bytes          limit = 0;
    FT_ULong          version;
    FT_ULong          nChains;
    FT_ULong          i;

    valid->root = ftvalid;
    valid->face = face;

    FT_TRACE3(( "validating `morx' table\n" ));
    GXV_INIT;

    GXV_LIMIT_CHECK( 4 + 4 );
    version = FT_NEXT_ULONG( p );
    nChains = FT_NEXT_ULONG( p );

    if ( version != 0x00020000UL )
      FT_INVALID_FORMAT;

    for ( i = 0; i < nChains; i++ )
    {
      GXV_TRACE(( "validating chain %d/%d\n", i + 1, nChains ));
      GXV_32BIT_ALIGNMENT_VALIDATE( p - table );
      gxv_morx_chain_validate( p, limit, valid );
      p += valid->subtable_length;
    }

    FT_TRACE4(( "\n" ));
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx.h                                                              */
/*                                                                         */
/*    TrueTypeGX/AAT common definition for morx table (specification).     */
/*                                                                         */
/*  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.                                           */
/*                                                                         */
/***************************************************************************/

#ifndef __GXVMORX_H__
#define __GXVMORX_H__

#include "gxvalid.h"
#include "gxvcommn.h"
#include "gxvmort.h"

#include FT_SFNT_NAMES_H

  FT_LOCAL( void )
  gxv_morx_subtable_type0_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid );

  FT_LOCAL( void )
  gxv_morx_subtable_type1_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid );

  FT_LOCAL( void )
  gxv_morx_subtable_type2_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid );

  FT_LOCAL( void )
  gxv_morx_subtable_type4_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid );

  FT_LOCAL( void )
  gxv_morx_subtable_type5_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid );

#endif /* __GXVMORX_H__ */

/* END */

license: mit


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx0.c                                                             */
/*                                                                         */
/*    TrueTypeGX/AAT morx table validation                                 */
/*    body for type0 (Indic Script Rearrangement) 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 "gxvmorx.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_gxvmorx

  static void
  gxv_morx_subtable_type0_entry_validate(
    FT_UShort                        state,
    FT_UShort                        flags,
    GXV_XStateTable_GlyphOffsetCPtr  glyphOffset_p,
    FT_Bytes                         table,
    FT_Bytes                         limit,
    GXV_Validator                    valid )
  {
    FT_UShort  markFirst;
    FT_UShort  dontAdvance;
    FT_UShort  markLast;
    FT_UShort  reserved;
    FT_UShort  verb;

    FT_UNUSED( state );
    FT_UNUSED( glyphOffset_p );
    FT_UNUSED( table );
    FT_UNUSED( limit );

    markFirst   = (FT_UShort)( ( flags >> 15 ) & 1 );
    dontAdvance = (FT_UShort)( ( flags >> 14 ) & 1 );
    markLast    = (FT_UShort)( ( flags >> 13 ) & 1 );

    reserved = (FT_UShort)( flags & 0x1FF0 );
    verb     = (FT_UShort)( flags & 0x000F );

    if ( 0 < reserved )
    {
      GXV_TRACE(( " non-zero bits found in reserved range\n" ));
      FT_INVALID_DATA;
    }
  }

  FT_LOCAL_DEF( void )
  gxv_morx_subtable_type0_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_NAME_ENTER(
      "morx chain subtable type0 (Indic-Script Rearrangement)" );

    GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE );

    valid->xstatetable.optdata               = NULL;
    valid->xstatetable.optdata_load_func     = NULL;
    valid->xstatetable.subtable_setup_func   = NULL;
    valid->xstatetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
    valid->xstatetable.entry_validate_func =
      gxv_morx_subtable_type0_entry_validate;

    gxv_XStateTable_validate( p, limit, valid );

    GXV_EXIT;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx1.c                                                             */
/*                                                                         */
/*    TrueTypeGX/AAT morx table validation                                 */
/*    body for type1 (Contextual Substitution) subtable.                   */
/*                                                                         */
/*  Copyright 2005, 2007 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 "gxvmorx.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_gxvmorx

  typedef struct  GXV_morx_subtable_type1_StateOptRec_
  {
    FT_ULong   substitutionTable;
    FT_ULong   substitutionTable_length;
    FT_UShort  substitutionTable_num_lookupTables;

  }  GXV_morx_subtable_type1_StateOptRec,
    *GXV_morx_subtable_type1_StateOptRecData;

#define GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE \
          ( GXV_STATETABLE_HEADER_SIZE + 2 )

  static void
  gxv_morx_subtable_type1_substitutionTable_load( FT_Bytes       table,
                                                  FT_Bytes       limit,
                                                  GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type1_StateOptRecData  optdata =
      (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata;

    GXV_LIMIT_CHECK( 2 );
    optdata->substitutionTable = FT_NEXT_USHORT( p );
  }

  static void
  gxv_morx_subtable_type1_subtable_setup( FT_ULong       table_size,
                                          FT_ULong       classTable,
                                          FT_ULong       stateArray,
                                          FT_ULong       entryTable,
                                          FT_ULong*      classTable_length_p,
                                          FT_ULong*      stateArray_length_p,
                                          FT_ULong*      entryTable_length_p,
                                          GXV_Validator  valid )
  {
    FT_ULong  o[4];
    FT_ULong  *l[4];
    FT_ULong  buff[5];

    GXV_morx_subtable_type1_StateOptRecData  optdata =
      (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata;

    o[0] = classTable;
    o[1] = stateArray;
    o[2] = entryTable;
    o[3] = optdata->substitutionTable;
    l[0] = classTable_length_p;
    l[1] = stateArray_length_p;
    l[2] = entryTable_length_p;
    l[3] = &(optdata->substitutionTable_length);

    gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid );
  }

  static void
  gxv_morx_subtable_type1_entry_validate(
    FT_UShort                       state,
    FT_UShort                       flags,
    GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
    FT_Bytes                        table,
    FT_Bytes                        limit,
    GXV_Validator                   valid )
  {
    FT_UShort  setMark;
    FT_UShort  dontAdvance;
    FT_UShort  reserved;
    FT_Short   markIndex;
    FT_Short   currentIndex;

    GXV_morx_subtable_type1_StateOptRecData  optdata =
      (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata;

    FT_UNUSED( state );
    FT_UNUSED( table );
    FT_UNUSED( limit );

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

    reserved = (FT_UShort)( flags & 0x3FFF );

    markIndex    = (FT_Short)( glyphOffset_p->ul >> 16 );
    currentIndex = (FT_Short)( glyphOffset_p->ul       );

    GXV_TRACE(( " setMark=%01d dontAdvance=%01d\n",
                setMark, dontAdvance ));

    if ( 0 < reserved )
    {
      GXV_TRACE(( " non-zero bits found in reserved range\n" ));
      if ( valid->root->level >= FT_VALIDATE_PARANOID )
        FT_INVALID_DATA;
    }

    GXV_TRACE(( "markIndex = %d, currentIndex = %d\n",
                markIndex, currentIndex ));

    if ( optdata->substitutionTable_num_lookupTables < markIndex + 1 )
      optdata->substitutionTable_num_lookupTables =
        (FT_Short)( markIndex + 1 );

    if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 )
      optdata->substitutionTable_num_lookupTables =
        (FT_Short)( currentIndex + 1 );
  }

  static void
  gxv_morx_subtable_type1_LookupValue_validate( FT_UShort            glyph,
                                                GXV_LookupValueCPtr  value_p,
                                                GXV_Validator        valid )
  {
    FT_UNUSED( glyph ); /* for the non-debugging case */

    GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value_p->u ));

    if ( value_p->u > valid->face->num_glyphs )
      FT_INVALID_GLYPH_ID;
  }

  static GXV_LookupValueDesc
  gxv_morx_subtable_type1_LookupFmt4_transit(
    FT_UShort            relative_gindex,
    GXV_LookupValueCPtr  base_value_p,
    FT_Bytes             lookuptbl_limit,
    GXV_Validator        valid )
  {
    FT_Bytes             p;
    FT_Bytes             limit;
    FT_UShort            offset;
    GXV_LookupValueDesc  value;

    /* XXX: check range? */
    offset = (FT_UShort)( base_value_p->u +
                          relative_gindex * sizeof ( FT_UShort ) );

    p     = valid->lookuptbl_head + offset;
    limit = lookuptbl_limit;

    GXV_LIMIT_CHECK ( 2 );
    value.u = FT_NEXT_USHORT( p );

    return value;
  }

  /*
   * TODO: length should be limit?
   **/
  static void
  gxv_morx_subtable_type1_substitutionTable_validate( FT_Bytes       table,
                                                      FT_Bytes       limit,
                                                      GXV_Validator  valid )
  {
    FT_Bytes   p = table;
    FT_UShort  i;

    GXV_morx_subtable_type1_StateOptRecData  optdata =
      (GXV_morx_subtable_type1_StateOptRecData)valid->xstatetable.optdata;

    /* TODO: calculate offset/length for each lookupTables */
    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
    valid->lookupval_func   = gxv_morx_subtable_type1_LookupValue_validate;
    valid->lookupfmt4_trans = gxv_morx_subtable_type1_LookupFmt4_transit;

    for ( i = 0; i < optdata->substitutionTable_num_lookupTables; i++ )
    {
      FT_ULong  offset;

      GXV_LIMIT_CHECK( 4 );
      offset = FT_NEXT_ULONG( p );

      gxv_LookupTable_validate( table + offset, limit, valid );
    }

    /* TODO: overlapping of lookupTables in substitutionTable */
  }

  /*
   * subtable for Contextual glyph substitution is a modified StateTable.
   * In addition to classTable, stateArray, entryTable, the field
   * `substitutionTable' is added.
   */
  FT_LOCAL_DEF( void )
  gxv_morx_subtable_type1_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type1_StateOptRec  st_rec;

    GXV_NAME_ENTER( "morx chain subtable type1 (Contextual Glyph Subst)" );

    GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE1_HEADER_SIZE );

    st_rec.substitutionTable_num_lookupTables = 0;

    valid->xstatetable.optdata =
      &st_rec;
    valid->xstatetable.optdata_load_func =
      gxv_morx_subtable_type1_substitutionTable_load;
    valid->xstatetable.subtable_setup_func =
      gxv_morx_subtable_type1_subtable_setup;
    valid->xstatetable.entry_glyphoffset_fmt =
      GXV_GLYPHOFFSET_ULONG;
    valid->xstatetable.entry_validate_func =
      gxv_morx_subtable_type1_entry_validate;

    gxv_XStateTable_validate( p, limit, valid );

    gxv_morx_subtable_type1_substitutionTable_validate(
      table + st_rec.substitutionTable,
      table + st_rec.substitutionTable + st_rec.substitutionTable_length,
      valid );

    GXV_EXIT;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx2.c                                                             */
/*                                                                         */
/*    TrueTypeGX/AAT morx 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 "gxvmorx.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_gxvmorx

  typedef struct  GXV_morx_subtable_type2_StateOptRec_
  {
    FT_ULong  ligActionTable;
    FT_ULong  componentTable;
    FT_ULong  ligatureTable;
    FT_ULong  ligActionTable_length;
    FT_ULong  componentTable_length;
    FT_ULong  ligatureTable_length;

  }  GXV_morx_subtable_type2_StateOptRec,
    *GXV_morx_subtable_type2_StateOptRecData;

#define GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE \
          ( GXV_XSTATETABLE_HEADER_SIZE + 4 + 4 + 4 )

  static void
  gxv_morx_subtable_type2_opttable_load( FT_Bytes       table,
                                         FT_Bytes       limit,
                                         GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type2_StateOptRecData  optdata =
      (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata;

    GXV_LIMIT_CHECK( 4 + 4 + 4 );
    optdata->ligActionTable = FT_NEXT_ULONG( p );
    optdata->componentTable = FT_NEXT_ULONG( p );
    optdata->ligatureTable  = FT_NEXT_ULONG( p );

    GXV_TRACE(( "offset to ligActionTable=0x%08x\n",
                optdata->ligActionTable ));
    GXV_TRACE(( "offset to componentTable=0x%08x\n",
                optdata->componentTable ));
    GXV_TRACE(( "offset to ligatureTable=0x%08x\n",
                optdata->ligatureTable ));
  }

  static void
  gxv_morx_subtable_type2_subtable_setup( FT_ULong       table_size,
                                          FT_ULong       classTable,
                                          FT_ULong       stateArray,
                                          FT_ULong       entryTable,
                                          FT_ULong*      classTable_length_p,
                                          FT_ULong*      stateArray_length_p,
                                          FT_ULong*      entryTable_length_p,
                                          GXV_Validator  valid )
  {
    FT_ULong   o[6];
    FT_ULong*  l[6];
    FT_ULong   buff[7];

    GXV_morx_subtable_type2_StateOptRecData  optdata =
      (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.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_ulong_offset( o, l, buff, 6, table_size, valid );

    GXV_TRACE(( "classTable: offset=0x%08x length=0x%08x\n",
                classTable, *classTable_length_p ));
    GXV_TRACE(( "stateArray: offset=0x%08x length=0x%08x\n",
                stateArray, *stateArray_length_p ));
    GXV_TRACE(( "entryTable: offset=0x%08x length=0x%08x\n",
                entryTable, *entryTable_length_p ));
    GXV_TRACE(( "ligActionTable: offset=0x%08x length=0x%08x\n",
                optdata->ligActionTable,
                optdata->ligActionTable_length ));
    GXV_TRACE(( "componentTable: offset=0x%08x length=0x%08x\n",
                optdata->componentTable,
                optdata->componentTable_length ));
    GXV_TRACE(( "ligatureTable:  offset=0x%08x length=0x%08x\n",
                optdata->ligatureTable,
                optdata->ligatureTable_length ));

    GXV_EXIT;
  }

#define GXV_MORX_LIGACTION_ENTRY_SIZE  4

  static void
  gxv_morx_subtable_type2_ligActionIndex_validate(
    FT_Bytes       table,
    FT_UShort      ligActionIndex,
    GXV_Validator  valid )
  {
    /* access ligActionTable */
    GXV_morx_subtable_type2_StateOptRecData optdata =
      (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata;

    FT_Bytes lat_base  = table + optdata->ligActionTable;
    FT_Bytes p         = lat_base +
                         ligActionIndex * GXV_MORX_LIGACTION_ENTRY_SIZE;
    FT_Bytes lat_limit = lat_base + optdata->ligActionTable;

    if ( p < lat_base )
    {
      GXV_TRACE(( "p < lat_base (%d byte rewind)\n", lat_base - p ));
      FT_INVALID_OFFSET;
    }
    else if ( lat_limit < p )
    {
      GXV_TRACE(( "lat_limit < p (%d byte overrun)\n", p - lat_limit ));
      FT_INVALID_OFFSET;
    }

    {
      /* 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_morx_subtable_type2_entry_validate(
    FT_UShort                       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  performAction;
    FT_UShort  reserved;
    FT_UShort  ligActionIndex;

    FT_UNUSED( state );
    FT_UNUSED( limit );

    setComponent   = (FT_UShort)( ( flags >> 15 ) & 1 );
    dontAdvance    = (FT_UShort)( ( flags >> 14 ) & 1 );
    performAction  = (FT_UShort)( ( flags >> 13 ) & 1 );

    reserved       = (FT_UShort)( flags & 0x1FFF );
    ligActionIndex = glyphOffset_p->u;

    if ( reserved > 0 )
      GXV_TRACE(( "  reserved 14bit is non-zero\n" ));

    if ( 0 < ligActionIndex )
      gxv_morx_subtable_type2_ligActionIndex_validate(
        table, ligActionIndex, valid );
  }

  static void
  gxv_morx_subtable_type2_ligatureTable_validate( FT_Bytes       table,
                                                  GXV_Validator  valid )
  {
    GXV_morx_subtable_type2_StateOptRecData  optdata =
      (GXV_morx_subtable_type2_StateOptRecData)valid->xstatetable.optdata;

    FT_Bytes p     = table + optdata->ligatureTable;
    FT_Bytes limit = table + optdata->ligatureTable
                           + optdata->ligatureTable_length;

    GXV_NAME_ENTER( "morx 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_morx_subtable_type2_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type2_StateOptRec  lig_rec;

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

    GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE2_HEADER_SIZE );

    valid->xstatetable.optdata =
      &lig_rec;
    valid->xstatetable.optdata_load_func =
      gxv_morx_subtable_type2_opttable_load;
    valid->xstatetable.subtable_setup_func =
      gxv_morx_subtable_type2_subtable_setup;
    valid->xstatetable.entry_glyphoffset_fmt =
      GXV_GLYPHOFFSET_USHORT;
    valid->xstatetable.entry_validate_func =
      gxv_morx_subtable_type2_entry_validate;

    gxv_XStateTable_validate( p, limit, valid );

    p += valid->subtable_length;
    gxv_morx_subtable_type2_ligatureTable_validate( table, valid );

    GXV_EXIT;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx4.c                                                             */
/*                                                                         */
/*    TrueTypeGX/AAT morx table validation                                 */
/*    body for "morx" type4 (Non-Contextual Glyph 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 "gxvmorx.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_gxvmorx

  FT_LOCAL_DEF( void )
  gxv_morx_subtable_type4_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid )
  {
    GXV_NAME_ENTER( "morx chain subtable type4 "
                    "(Non-Contextual Glyph Substitution)" );

    gxv_mort_subtable_type4_validate( table, limit, valid );

    GXV_EXIT;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvmorx5.c                                                             */
/*                                                                         */
/*    TrueTypeGX/AAT morx table validation                                 */
/*    body for type5 (Contextual Glyph Insertion) subtable.                */
/*                                                                         */
/*  Copyright 2005, 2007 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 "gxvmorx.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_gxvmorx

  /*
   * `morx' subtable type5 (Contextual Glyph Insertion)
   * has format of a StateTable with insertion-glyph-list
   * without name.  However, the 32bit offset from the head
   * of subtable to the i-g-l is given after `entryTable',
   * without variable name specification (the existence of
   * this offset to the table is different from mort type5).
   */

  typedef struct  GXV_morx_subtable_type5_StateOptRec_
  {
    FT_ULong  insertionGlyphList;
    FT_ULong  insertionGlyphList_length;

  }  GXV_morx_subtable_type5_StateOptRec,
    *GXV_morx_subtable_type5_StateOptRecData;

#define GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE \
          ( GXV_STATETABLE_HEADER_SIZE + 4 )

  static void
  gxv_morx_subtable_type5_insertionGlyphList_load( FT_Bytes       table,
                                                   FT_Bytes       limit,
                                                   GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type5_StateOptRecData  optdata =
      (GXV_morx_subtable_type5_StateOptRecData)valid->xstatetable.optdata;

    GXV_LIMIT_CHECK( 4 );
    optdata->insertionGlyphList = FT_NEXT_ULONG( p );
  }

  static void
  gxv_morx_subtable_type5_subtable_setup( FT_ULong       table_size,
                                          FT_ULong       classTable,
                                          FT_ULong       stateArray,
                                          FT_ULong       entryTable,
                                          FT_ULong*      classTable_length_p,
                                          FT_ULong*      stateArray_length_p,
                                          FT_ULong*      entryTable_length_p,
                                          GXV_Validator  valid )
  {
    FT_ULong   o[4];
    FT_ULong*  l[4];
    FT_ULong   buff[5];

    GXV_morx_subtable_type5_StateOptRecData  optdata =
      (GXV_morx_subtable_type5_StateOptRecData)valid->xstatetable.optdata;

    o[0] = classTable;
    o[1] = stateArray;
    o[2] = entryTable;
    o[3] = optdata->insertionGlyphList;
    l[0] = classTable_length_p;
    l[1] = stateArray_length_p;
    l[2] = entryTable_length_p;
    l[3] = &(optdata->insertionGlyphList_length);

    gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid );
  }

  static void
  gxv_morx_subtable_type5_InsertList_validate( FT_UShort      table_index,
                                               FT_UShort      count,
                                               FT_Bytes       table,
                                               FT_Bytes       limit,
                                               GXV_Validator  valid )
  {
    FT_Bytes p = table + table_index * 2;

    while ( p < table + count * 2 + table_index * 2 )
    {
      FT_UShort  insert_glyphID;

      GXV_LIMIT_CHECK( 2 );
      insert_glyphID = FT_NEXT_USHORT( p );
      GXV_TRACE(( " 0x%04x", insert_glyphID ));
    }

    GXV_TRACE(( "\n" ));
  }

  static void
  gxv_morx_subtable_type5_entry_validate(
    FT_UShort                       state,
    FT_UShort                       flags,
    GXV_StateTable_GlyphOffsetCPtr  glyphOffset_p,
    FT_Bytes                        table,
    FT_Bytes                        limit,
    GXV_Validator                   valid )
  {
    FT_Bool    setMark;
    FT_Bool    dontAdvance;
    FT_Bool    currentIsKashidaLike;
    FT_Bool    markedIsKashidaLike;
    FT_Bool    currentInsertBefore;
    FT_Bool    markedInsertBefore;
    FT_Byte    currentInsertCount;
    FT_Byte    markedInsertCount;
    FT_Byte    currentInsertList;
    FT_UShort  markedInsertList;

    FT_UNUSED( state );

    setMark              = FT_BOOL( ( flags >> 15 ) & 1 );
    dontAdvance          = FT_BOOL( ( flags >> 14 ) & 1 );
    currentIsKashidaLike = FT_BOOL( ( flags >> 13 ) & 1 );
    markedIsKashidaLike  = FT_BOOL( ( flags >> 12 ) & 1 );
    currentInsertBefore  = FT_BOOL( ( flags >> 11 ) & 1 );
    markedInsertBefore   = FT_BOOL( ( flags >> 10 ) & 1 );

    currentInsertCount = (FT_Byte)( ( flags >> 5 ) & 0x1F   );
    markedInsertCount  = (FT_Byte)(   flags        & 0x001F );

    currentInsertList = (FT_Byte)  ( glyphOffset_p->ul >> 16 );
    markedInsertList  = (FT_UShort)( glyphOffset_p->ul       );

    if ( currentInsertList && 0 != currentInsertCount )
      gxv_morx_subtable_type5_InsertList_validate( currentInsertList,
                                                   currentInsertCount,
                                                   table, limit,
                                                   valid );

    if ( markedInsertList && 0 != markedInsertCount )
      gxv_morx_subtable_type5_InsertList_validate( markedInsertList,
                                                   markedInsertCount,
                                                   table, limit,
                                                   valid );
  }

  FT_LOCAL_DEF( void )
  gxv_morx_subtable_type5_validate( FT_Bytes       table,
                                    FT_Bytes       limit,
                                    GXV_Validator  valid )
  {
    FT_Bytes  p = table;

    GXV_morx_subtable_type5_StateOptRec      et_rec;
    GXV_morx_subtable_type5_StateOptRecData  et = &et_rec;

    GXV_NAME_ENTER( "morx chain subtable type5 (Glyph Insertion)" );

    GXV_LIMIT_CHECK( GXV_MORX_SUBTABLE_TYPE5_HEADER_SIZE );

    valid->xstatetable.optdata =
      et;
    valid->xstatetable.optdata_load_func =
      gxv_morx_subtable_type5_insertionGlyphList_load;
    valid->xstatetable.subtable_setup_func =
      gxv_morx_subtable_type5_subtable_setup;
    valid->xstatetable.entry_glyphoffset_fmt =
      GXV_GLYPHOFFSET_ULONG;
    valid->xstatetable.entry_validate_func =
      gxv_morx_subtable_type5_entry_validate;

    gxv_XStateTable_validate( p, limit, valid );

    GXV_EXIT;
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvopbd.c                                                              */
/*                                                                         */
/*    TrueTypeGX/AAT opbd table validation (body).                         */
/*                                                                         */
/*  Copyright 2004, 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 "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_gxvopbd

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      Data and Types                           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  typedef struct  GXV_opbd_DataRec_
  {
    FT_UShort  format;
    FT_UShort  valueOffset_min;

  } GXV_opbd_DataRec, *GXV_opbd_Data;

#define GXV_OPBD_DATA( FIELD )  GXV_TABLE_DATA( opbd, FIELD )

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      UTILITY FUNCTIONS                        *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  static void
  gxv_opbd_LookupValue_validate( FT_UShort            glyph,
                                 GXV_LookupValueCPtr  value_p,
                                 GXV_Validator        valid )
  {
    /* offset in LookupTable is measured from the head of opbd table */
    FT_Bytes   p     = valid->root->base + value_p->u;
    FT_Bytes   limit = valid->root->limit;
    FT_Short   delta_value;
    int        i;

    if ( value_p->u < GXV_OPBD_DATA( valueOffset_min ) )
      GXV_OPBD_DATA( valueOffset_min ) = value_p->u;

    for ( i = 0; i < 4; i++ )
    {
      GXV_LIMIT_CHECK( 2 );
      delta_value = FT_NEXT_SHORT( p );

      if ( GXV_OPBD_DATA( format ) )    /* format 1, value is ctrl pt. */
      {
        if ( delta_value == -1 )
          continue;

        gxv_ctlPoint_validate( glyph, delta_value, valid );
      }
      else                              /* format 0, value is distance */
        continue;
    }
  }

  /*
    opbd ---------------------+
                              |
    +===============+         |
    | lookup header |         |
    +===============+         |
    | BinSrchHeader |         |
    +===============+         |
    | lastGlyph[0]  |         |
    +---------------+         |
    | firstGlyph[0] |         |  head of opbd sfnt table
    +---------------+         |             +
    | offset[0]     |    ->   |          offset            [byte]
    +===============+         |             +
    | lastGlyph[1]  |         | (glyphID - firstGlyph) * 4 * sizeof(FT_Short) [byte]
    +---------------+         |
    | firstGlyph[1] |         |
    +---------------+         |
    | offset[1]     |         |
    +===============+         |
                              |
     ....                     |
                              |
    48bit value array         |
    +===============+         |
    |     value     | <-------+
    |               |
    |               |
    |               |
    +---------------+
    .... */

  static GXV_LookupValueDesc
  gxv_opbd_LookupFmt4_transit( FT_UShort            relative_gindex,
                               GXV_LookupValueCPtr  base_value_p,
                               FT_Bytes             lookuptbl_limit,
                               GXV_Validator        valid )
  {
    GXV_LookupValueDesc  value;

    FT_UNUSED( lookuptbl_limit );
    FT_UNUSED( valid );

    /* XXX: check range? */
    value.u = (FT_UShort)( base_value_p->u +
                           relative_gindex * 4 * sizeof ( FT_Short ) );

    return value;
  }

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                         opbd TABLE                            *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  FT_LOCAL_DEF( void )
  gxv_opbd_validate( FT_Bytes      table,
                     FT_Face       face,
                     FT_Validator  ftvalid )
  {
    GXV_ValidatorRec  validrec;
    GXV_Validator     valid = &validrec;
    GXV_opbd_DataRec  opbdrec;
    GXV_opbd_Data     opbd  = &opbdrec;
    FT_Bytes          p     = table;
    FT_Bytes          limit = 0;

    FT_ULong  version;

    valid->root       = ftvalid;
    valid->table_data = opbd;
    valid->face       = face;

    FT_TRACE3(( "validating `opbd' table\n" ));
    GXV_INIT;
    GXV_OPBD_DATA( valueOffset_min ) = 0xFFFFU;

    GXV_LIMIT_CHECK( 4 + 2 );
    version                 = FT_NEXT_ULONG( p );
    GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p );

    /* only 0x00010000 is defined (1996) */
    GXV_TRACE(( "(version=0x%08x)\n", version ));
    if ( 0x00010000UL != version )
      FT_INVALID_FORMAT;

    /* only values 0 and 1 are defined (1996) */
    GXV_TRACE(( "(format=0x%04x)\n", GXV_OPBD_DATA( format ) ));
    if ( 0x0001 < GXV_OPBD_DATA( format ) )
      FT_INVALID_FORMAT;

    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
    valid->lookupval_func   = gxv_opbd_LookupValue_validate;
    valid->lookupfmt4_trans = gxv_opbd_LookupFmt4_transit;

    gxv_LookupTable_validate( p, limit, valid );
    p += valid->subtable_length;

    if ( p > table + GXV_OPBD_DATA( valueOffset_min ) )
    {
      GXV_TRACE((
        "found overlap between LookupTable and opbd_value array\n" ));
      FT_INVALID_OFFSET;
    }

    FT_TRACE4(( "\n" ));
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvprop.c                                                              */
/*                                                                         */
/*    TrueTypeGX/AAT prop table validation (body).                         */
/*                                                                         */
/*  Copyright 2004, 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 "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_gxvprop

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      Data and Types                           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

#define GXV_PROP_HEADER_SIZE  ( 4 + 2 + 2 )
#define GXV_PROP_SIZE_MIN     GXV_PROP_HEADER_SIZE

  typedef struct  GXV_prop_DataRec_
  {
    FT_Fixed  version;

  } GXV_prop_DataRec, *GXV_prop_Data;

#define GXV_PROP_DATA( field )  GXV_TABLE_DATA( prop, field )

#define GXV_PROP_FLOATER                      0x8000U
#define GXV_PROP_USE_COMPLEMENTARY_BRACKET    0x1000U
#define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00U
#define GXV_PROP_ATTACHING_TO_RIGHT           0x0080U
#define GXV_PROP_RESERVED                     0x0060U
#define GXV_PROP_DIRECTIONALITY_CLASS         0x001FU

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      UTILITY FUNCTIONS                        *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  static void
  gxv_prop_zero_advance_validate( FT_UShort      gid,
                                  GXV_Validator  valid )
  {
    FT_Face       face;
    FT_Error      error;
    FT_GlyphSlot  glyph;

    GXV_NAME_ENTER( "zero advance" );

    face = valid->face;

    error = FT_Load_Glyph( face,
                           gid,
                           FT_LOAD_IGNORE_TRANSFORM );
    if ( error )
      FT_INVALID_GLYPH_ID;

    glyph = face->glyph;

    if ( glyph->advance.x != (FT_Pos)0 ||
         glyph->advance.y != (FT_Pos)0 )
      FT_INVALID_DATA;

    GXV_EXIT;
  }

  /* Pass 0 as GLYPH to check the default property */
  static void
  gxv_prop_property_validate( FT_UShort      property,
                              FT_UShort      glyph,
                              GXV_Validator  valid )
  {
    if ( glyph != 0 && ( property & GXV_PROP_FLOATER ) )
      gxv_prop_zero_advance_validate( glyph, valid );

    if ( property & GXV_PROP_USE_COMPLEMENTARY_BRACKET )
    {
      FT_UShort  offset;
      char       complement;

      offset = (FT_UShort)( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET );
      if ( offset == 0 )
        FT_INVALID_DATA;

      complement = (char)( offset >> 8 );
      if ( complement & 0x08 )
      {
        /* Top bit is set: negative */

        /* Calculate the absolute offset */
        complement = (char)( ( complement & 0x07 ) + 1 );

        /* The gid for complement must be greater than 0 */
        if ( glyph <= complement )
          FT_INVALID_DATA;
      }
      else
      {
        /* The gid for complement must be the face. */
        gxv_glyphid_validate( (FT_UShort)( glyph + complement ), valid );
      }
    }
    else
    {
      if ( property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET )
        GXV_TRACE(( "glyph %d cannot have complementary bracketing\n",
                    glyph ));
    }

    /* this is introduced in version 2.0 */
    if ( property & GXV_PROP_ATTACHING_TO_RIGHT )
    {
      if ( GXV_PROP_DATA( version ) == 0x00010000UL )
        FT_INVALID_DATA;
    }

    if ( property & GXV_PROP_RESERVED )
      FT_INVALID_DATA;

    if ( ( property & GXV_PROP_DIRECTIONALITY_CLASS ) > 11 )
    {
      /* TODO: Too restricted. Use the validation level. */
      if ( GXV_PROP_DATA( version ) == 0x00010000UL ||
           GXV_PROP_DATA( version ) == 0x00020000UL )
        FT_INVALID_DATA;
    }
  }

  static void
  gxv_prop_LookupValue_validate( FT_UShort            glyph,
                                 GXV_LookupValueCPtr  value_p,
                                 GXV_Validator        valid )
  {
    gxv_prop_property_validate( value_p->u, glyph, valid );
  }

  /*
    +===============+ --------+
    | lookup header |         |
    +===============+         |
    | BinSrchHeader |         |
    +===============+         |
    | lastGlyph[0]  |         |
    +---------------+         |
    | firstGlyph[0] |         |    head of lookup table
    +---------------+         |             +
    | offset[0]     |    ->   |          offset            [byte]
    +===============+         |             +
    | lastGlyph[1]  |         | (glyphID - firstGlyph) * 2 [byte]
    +---------------+         |
    | firstGlyph[1] |         |
    +---------------+         |
    | offset[1]     |         |
    +===============+         |
                              |
     ...                      |
                              |
    16bit value array         |
    +===============+         |
    |     value     | <-------+
    ...
  */

  static GXV_LookupValueDesc
  gxv_prop_LookupFmt4_transit( FT_UShort            relative_gindex,
                               GXV_LookupValueCPtr  base_value_p,
                               FT_Bytes             lookuptbl_limit,
                               GXV_Validator        valid )
  {
    FT_Bytes             p;
    FT_Bytes             limit;
    FT_UShort            offset;
    GXV_LookupValueDesc  value;

    /* XXX: check range? */
    offset = (FT_UShort)( base_value_p->u +
                          relative_gindex * sizeof( FT_UShort ) );
    p      = valid->lookuptbl_head + offset;
    limit  = lookuptbl_limit;

    GXV_LIMIT_CHECK ( 2 );
    value.u = FT_NEXT_USHORT( p );

    return value;
  }

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                         prop TABLE                            *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  FT_LOCAL_DEF( void )
  gxv_prop_validate( FT_Bytes      table,
                     FT_Face       face,
                     FT_Validator  ftvalid )
  {
    FT_Bytes          p     = table;
    FT_Bytes          limit = 0;
    GXV_ValidatorRec  validrec;
    GXV_Validator     valid = &validrec;

    GXV_prop_DataRec  proprec;
    GXV_prop_Data     prop = &proprec;

    FT_Fixed          version;
    FT_UShort         format;
    FT_UShort         defaultProp;

    valid->root       = ftvalid;
    valid->table_data = prop;
    valid->face       = face;

    FT_TRACE3(( "validating `prop' table\n" ));
    GXV_INIT;

    GXV_LIMIT_CHECK( 4 + 2 + 2 );
    version     = FT_NEXT_ULONG( p );
    format      = FT_NEXT_USHORT( p );
    defaultProp = FT_NEXT_USHORT( p );

    /* only versions 1.0, 2.0, 3.0 are defined (1996) */
    if ( version != 0x00010000UL &&
         version != 0x00020000UL &&
         version != 0x00030000UL )
      FT_INVALID_FORMAT;

    /* only formats 0x0000, 0x0001 are defined (1996) */
    if ( format > 1 )
      FT_INVALID_FORMAT;

    gxv_prop_property_validate( defaultProp, 0, valid );

    if ( format == 0 )
    {
      FT_TRACE3(( "(format 0, no per-glyph properties, "
                  "remaining %d bytes are skipped)", limit - p ));
      goto Exit;
    }

    /* format == 1 */
    GXV_PROP_DATA( version ) = version;

    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
    valid->lookupval_func   = gxv_prop_LookupValue_validate;
    valid->lookupfmt4_trans = gxv_prop_LookupFmt4_transit;

    gxv_LookupTable_validate( p, limit, valid );

  Exit:
    FT_TRACE4(( "\n" ));
  }

/* END */


code:
/***************************************************************************/
/*                                                                         */
/*  gxvtrak.c                                                              */
/*                                                                         */
/*    TrueTypeGX/AAT trak table validation (body).                         */
/*                                                                         */
/*  Copyright 2004, 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 "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_gxvtrak

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      Data and Types                           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

    /*
     * referred track table format specification:
     * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6trak.html
     * last update was 1996.
     * ----------------------------------------------
     * [MINIMUM HEADER]: GXV_TRAK_SIZE_MIN
     * version          (fixed:  32bit) = 0x00010000
     * format           (uint16: 16bit) = 0 is only defined (1996)
     * horizOffset      (uint16: 16bit)
     * vertOffset       (uint16: 16bit)
     * reserved         (uint16: 16bit) = 0
     * ----------------------------------------------
     * [VARIABLE BODY]:
     * horizData
     *   header         ( 2 + 2 + 4
     *   trackTable       + nTracks * ( 4 + 2 + 2 )
     *   sizeTable        + nSizes * 4 )
     * ----------------------------------------------
     * vertData
     *   header         ( 2 + 2 + 4
     *   trackTable       + nTracks * ( 4 + 2 + 2 )
     *   sizeTable        + nSizes * 4 )
     * ----------------------------------------------
     */
  typedef struct  GXV_trak_DataRec_
  {
    FT_UShort  trackValueOffset_min;
    FT_UShort  trackValueOffset_max;

  } GXV_trak_DataRec, *GXV_trak_Data;

#define GXV_TRAK_DATA( FIELD )  GXV_TABLE_DATA( trak, FIELD )

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                      UTILITY FUNCTIONS                        *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  static void
  gxv_trak_trackTable_validate( FT_Bytes       table,
                                FT_Bytes       limit,
                                FT_UShort      nTracks,
                                GXV_Validator  valid )
  {
    FT_Bytes   p = table;

    FT_Fixed   track;
    FT_UShort  nameIndex;
    FT_UShort  offset;
    FT_UShort  i;

    GXV_NAME_ENTER( "trackTable" );

    GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU;
    GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000;

    for ( i = 0; i < nTracks; i ++ )
    {
      GXV_LIMIT_CHECK( 4 + 2 + 2 );
      track     = FT_NEXT_LONG( p );
      nameIndex = FT_NEXT_USHORT( p );
      offset    = FT_NEXT_USHORT( p );

      if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) )
        GXV_TRAK_DATA( trackValueOffset_min ) = offset;
      if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) )
        GXV_TRAK_DATA( trackValueOffset_max ) = offset;

      gxv_sfntName_validate( nameIndex, 256, 32767, valid );
    }

    valid->subtable_length = p - table;
    GXV_EXIT;
  }

  static void
  gxv_trak_trackData_validate( FT_Bytes       table,
                               FT_Bytes       limit,
                               GXV_Validator  valid )
  {
    FT_Bytes   p = table;
    FT_UShort  nTracks;
    FT_UShort  nSizes;
    FT_ULong   sizeTableOffset;

    GXV_ODTECT( 4, odtect );

    GXV_ODTECT_INIT( odtect );
    GXV_NAME_ENTER( "trackData" );

    /* read the header of trackData */
    GXV_LIMIT_CHECK( 2 + 2 + 4 );
    nTracks         = FT_NEXT_USHORT( p );
    nSizes          = FT_NEXT_USHORT( p );
    sizeTableOffset = FT_NEXT_ULONG( p );

    gxv_odtect_add_range( table, p - table, "trackData header", odtect );

    /* validate trackTable */
    gxv_trak_trackTable_validate( p, limit, nTracks, valid );
    gxv_odtect_add_range( p, valid->subtable_length,
                          "trackTable", odtect );

    /* sizeTable is array of FT_Fixed, don't check contents */
    p = valid->root->base + sizeTableOffset;
    GXV_LIMIT_CHECK( nSizes * 4 );
    gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect );

    /* validate trackValueOffet */
    p = valid->root->base + GXV_TRAK_DATA( trackValueOffset_min );
    if ( limit - p < nTracks * nSizes * 2 )
      GXV_TRACE(( "too short trackValue array\n" ));

    p = valid->root->base + GXV_TRAK_DATA( trackValueOffset_max );
    GXV_LIMIT_CHECK( nSizes * 2 );

    gxv_odtect_add_range( valid->root->base
                            + GXV_TRAK_DATA( trackValueOffset_min ),
                          GXV_TRAK_DATA( trackValueOffset_max )
                            - GXV_TRAK_DATA( trackValueOffset_min )
                            + nSizes * 2,
                          "trackValue array", odtect );

    gxv_odtect_validate( odtect, valid );

    GXV_EXIT;
  }

  /*************************************************************************/
  /*************************************************************************/
  /*****                                                               *****/
  /*****                          trak TABLE                           *****/
  /*****                                                               *****/
  /*************************************************************************/
  /*************************************************************************/

  FT_LOCAL_DEF( void )
  gxv_trak_validate( FT_Bytes      table,
                     FT_Face       face,
                     FT_Validator  ftvalid )
  {
    FT_Bytes          p = table;
    FT_Bytes          limit = 0;
    FT_Offset         table_size;

    GXV_ValidatorRec  validrec;
    GXV_Validator     valid = &validrec;
    GXV_trak_DataRec  trakrec;
    GXV_trak_Data     trak = &trakrec;

    FT_ULong   version;
    FT_UShort  format;
    FT_UShort  horizOffset;
    FT_UShort  vertOffset;
    FT_UShort  reserved;

    GXV_ODTECT( 3, odtect );

    GXV_ODTECT_INIT( odtect );
    valid->root       = ftvalid;
    valid->table_data = trak;
    valid->face       = face;

    limit      = valid->root->limit;
    table_size = limit - table;

    FT_TRACE3(( "validating `trak' table\n" ));
    GXV_INIT;

    GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 );
    version     = FT_NEXT_ULONG( p );
    format      = FT_NEXT_USHORT( p );
    horizOffset = FT_NEXT_USHORT( p );
    vertOffset  = FT_NEXT_USHORT( p );
    reserved    = FT_NEXT_USHORT( p );

    GXV_TRACE(( " (version = 0x%08x)\n", version ));
    GXV_TRACE(( " (format = 0x%04x)\n", format ));
    GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset ));
    GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset ));
    GXV_TRACE(( " (reserved = 0x%04x)\n", reserved ));

    /* Version 1.0 (always:1996) */
    if ( version != 0x00010000UL )
      FT_INVALID_FORMAT;

    /* format 0 (always:1996) */
    if ( format != 0x0000 )
      FT_INVALID_FORMAT;

    GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset );
    GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset );

    /* Reserved Fixed Value (always) */
    if ( reserved != 0x0000 )
      FT_INVALID_DATA;

    /* validate trackData */
    if ( 0 < horizOffset )
    {
      gxv_trak_trackData_validate( table + horizOffset, limit, valid );
      gxv_odtect_add_range( table + horizOffset, valid->subtable_length,
                            "horizJustData", odtect );
    }

    if ( 0 < vertOffset )
    {
      gxv_trak_trackData_validate( table + vertOffset, limit, valid );
      gxv_odtect_add_range( table + vertOffset, valid->subtable_length,
                            "vertJustData", odtect );
    }

    gxv_odtect_validate( odtect, valid );

    FT_TRACE4(( "\n" ));
  }

/* END */


code:
#
# FreeType 2 gxvalid module definition
#

# 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.

FTMODULE_H_COMMANDS += GXVALID_MODULE

define GXVALID_MODULE
$(OPEN_DRIVER) FT_Module_Class, gxv_module_class $(CLOSE_DRIVER)
$(ECHO_DRIVER)gxvalid   $(ECHO_DRIVER_DESC)TrueTypeGX/AAT validation module$(ECHO_DRIVER_DONE)
endef

# EOF


code:
#
# FreeType 2 TrueTypeGX/AAT validation driver configuration rules
#

# Copyright 2004, 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.

# GXV driver directory
#
GXV_DIR := $(SRC_DIR)/gxvalid

# compilation flags for the driver
#
GXV_COMPILE := $(FT_COMPILE) $I$(subst /,$(COMPILER_SEP),$(GXV_DIR))

# GXV driver sources (i.e., C files)
#
GXV_DRV_SRC := $(GXV_DIR)/gxvcommn.c \
               $(GXV_DIR)/gxvfeat.c  \
               $(GXV_DIR)/gxvbsln.c  \
               $(GXV_DIR)/gxvtrak.c  \
               $(GXV_DIR)/gxvopbd.c  \
               $(GXV_DIR)/gxvprop.c  \
               $(GXV_DIR)/gxvjust.c  \
               $(GXV_DIR)/gxvmort.c  \
               $(GXV_DIR)/gxvmort0.c \
               $(GXV_DIR)/gxvmort1.c \
               $(GXV_DIR)/gxvmort2.c \
               $(GXV_DIR)/gxvmort4.c \
               $(GXV_DIR)/gxvmort5.c \
               $(GXV_DIR)/gxvmorx.c  \
               $(GXV_DIR)/gxvmorx0.c \
               $(GXV_DIR)/gxvmorx1.c \
               $(GXV_DIR)/gxvmorx2.c \
               $(GXV_DIR)/gxvmorx4.c \
               $(GXV_DIR)/gxvmorx5.c \
               $(GXV_DIR)/gxvlcar.c  \
               $(GXV_DIR)/gxvkern.c  \
               $(GXV_DIR)/gxvmod.c

# GXV driver headers
#
GXV_DRV_H := $(GXV_DIR)/gxvalid.h  \
             $(GXV_DIR)/gxverror.h \
             $(GXV_DIR)/gxvcommn.h \
             $(GXV_DIR)/gxvfeat.h  \
             $(GXV_DIR)/gxvmod.h   \
             $(GXV_DIR)/gxvmort.h  \
             $(GXV_DIR)/gxvmorx.h

# GXV driver object(s)
#
#   GXV_DRV_OBJ_M is used during `multi' builds.
#   GXV_DRV_OBJ_S is used during `single' builds.
#
GXV_DRV_OBJ_M := $(GXV_DRV_SRC:$(GXV_DIR)/%.c=$(OBJ_DIR)/%.$O)
GXV_DRV_OBJ_S := $(OBJ_DIR)/gxvalid.$O

# GXV driver source file for single build
#
GXV_DRV_SRC_S := $(GXV_DIR)/gxvalid.c

# GXV driver - single object
#
$(GXV_DRV_OBJ_S): $(GXV_DRV_SRC_S) $(GXV_DRV_SRC) \
                   $(FREETYPE_H) $(GXV_DRV_H)
	$(GXV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $(GXV_DRV_SRC_S))

# GXV driver - multiple objects
#
$(OBJ_DIR)/%.$O: $(GXV_DIR)/%.c $(FREETYPE_H) $(GXV_DRV_H)
	$(GXV_COMPILE) $T$(subst /,$(COMPILER_SEP),$@ $<)

# update main driver object lists
#
DRV_OBJS_S += $(GXV_DRV_OBJ_S)
DRV_OBJS_M += $(GXV_DRV_OBJ_M)

# EOF


code:
# FreeType 2 src/gzip Jamfile
#
# Copyright 2001 by
# 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.

SubDir  FT2_TOP $(FT2_SRC_DIR) gzip ;

Library  $(FT2_LIB) : ftgzip.c ;

# end of src/pcf Jamfile


code:
/* adler32.c -- compute the Adler-32 checksum of a data stream
 * Copyright (C) 1995-2002 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 */

/* @(#) $Id$ */

#include "zlib.h"

#define BASE 65521L /* largest prime smaller than 65536 */
#define NMAX 5552
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */

#define DO1(buf,i)  {s1 += buf[i]; s2 += s1;}
#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
#define DO16(buf)   DO8(buf,0); DO8(buf,8);

/* ========================================================================= */
ZEXPORT(uLong) adler32( /* adler, buf, len) */
    uLong adler,
    const Bytef *buf,
    uInt len )
{
    unsigned long s1 = adler & 0xffff;
    unsigned long s2 = (adler >> 16) & 0xffff;
    int k;

    if (buf == Z_NULL) return 1L;

    while (len > 0) {
        k = len < NMAX ? len : NMAX;
        len -= k;
        while (k >= 16) {
            DO16(buf);
            buf += 16;
            k -= 16;
        }
        if (k != 0) do {
            s1 += *buf++;
            s2 += s1;
        } while (--k);
        s1 %= BASE;
        s2 %= BASE;
    }
    return (s2 << 16) | s1;
}


code:
/***************************************************************************/
/*                                                                         */
/*  ftgzip.c                                                               */
/*                                                                         */
/*    FreeType support for .gz compressed files.                           */
/*                                                                         */
/*  This optional component relies on zlib.  It should mainly be used to   */
/*  parse compressed PCF fonts, as found with many X11 server              */
/*  distributions.                                                         */
/*                                                                         */
/*  Copyright 2002, 2003, 2004, 2005, 2006, 2009, 2010 by                  */
/*  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.                                        */
/*                                                                         */
/***************************************************************************/

#include <ft2build.h>
#include FT_INTERNAL_MEMORY_H
#include FT_INTERNAL_STREAM_H
#include FT_INTERNAL_DEBUG_H
#include FT_GZIP_H
#include FT_CONFIG_STANDARD_LIBRARY_H

#include FT_MODULE_ERRORS_H

#undef __FTERRORS_H__

#define FT_ERR_PREFIX  Gzip_Err_
#define FT_ERR_BASE    FT_Mod_Err_Gzip

#include FT_ERRORS_H

#ifdef FT_CONFIG_OPTION_USE_ZLIB

#ifdef FT_CONFIG_OPTION_PIC
#error "gzip code does not support PIC yet"
#endif

#ifdef FT_CONFIG_OPTION_SYSTEM_ZLIB

#include <zlib.h>

#else /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */

 /* In this case, we include our own modified sources of the ZLib    */
 /* within the "ftgzip" component.  The modifications were necessary */
 /* to #include all files without conflicts, as well as preventing   */
 /* the definition of "extern" functions that may cause linking      */
 /* conflicts when a program is linked with both FreeType and the    */
 /* original ZLib.                                                   */

#define NO_DUMMY_DECL
#ifndef USE_ZLIB_ZCALLOC
#define MY_ZCALLOC /* prevent all zcalloc() & zfree() in zutils.c */
#endif

#include "zlib.h"

#undef  SLOW
#define SLOW  1  /* we can't use asm-optimized sources here! */

  /* Urgh.  `inflate_mask' must not be declared twice -- C++ doesn't like
     this.  We temporarily disable it and load all necessary header files. */
#define NO_INFLATE_MASK
#include "zutil.h"
#include "inftrees.h"
#include "infblock.h"
#include "infcodes.h"
#include "infutil.h"
#undef  NO_INFLATE_MASK

  /* infutil.c must be included before infcodes.c */
#include "zutil.c"
#include "inftrees.c"
#include "infutil.c"
#include "infcodes.c"
#include "infblock.c"
#include "inflate.c"
#include "adler32.c"

#endif /* !FT_CONFIG_OPTION_SYSTEM_ZLIB */

/***************************************************************************/
/***************************************************************************/
/*****                                                                 *****/
/*****            Z L I B   M E M O R Y   M A N A G E M E N T          *****/
/*****                                                                 *****/
/***************************************************************************/
/***************************************************************************/

  /* it is better to use FreeType memory routines instead of raw
     'malloc/free' */

  static voidpf
  ft_gzip_alloc( FT_Memory  memory,
                 uInt       items,
                 uInt       size )
  {
    FT_ULong    sz = (FT_ULong)size * items;
    FT_Error    error;
    FT_Pointer  p  = NULL;

    (void)FT_ALLOC( p, sz );
    return p;
  }

  static void
  ft_gzip_free( FT_Memory  memory,
                voidpf     address )
  {
    FT_MEM_FREE( address );
  }

#if !defined( FT_CONFIG_OPTION_SYSTEM_ZLIB ) && !defined( USE_ZLIB_ZCALLOC )

  local voidpf
  zcalloc ( voidpf    opaque,
            unsigned  items,
            unsigned  size )
  {
    return ft_gzip_alloc( (FT_Memory)opaque, items, size );
  }

  local void
  zcfree( voidpf  opaque,
          voidpf  ptr )
  {
    ft_gzip_free( (FT_Memory)opaque, ptr );
  }

#endif /* !SYSTEM_ZLIB && !USE_ZLIB_ZCALLOC */

/***************************************************************************/
/***************************************************************************/
/*****                                                                 *****/
/*****               Z L I B   F I L E   D E S C R I P T O R           *****/
/*****                                                                 *****/
/***************************************************************************/
/***************************************************************************/

#define FT_GZIP_BUFFER_SIZE  4096

  typedef struct  FT_GZipFileRec_
  {
    FT_Stream  source;         /* parent/source stream        */
    FT_Stream  stream;         /* embedding stream            */
    FT_Memory  memory;         /* memory allocator            */
    z_stream   zstream;        /* zlib input stream           */

    FT_ULong   start;          /* starting position, after .gz header */
    FT_Byte    input[FT_GZIP_BUFFER_SIZE];   /* input read buffer  */

    FT_Byte    buffer[FT_GZIP_BUFFER_SIZE];  /* output buffer      */
    FT_ULong   pos;                          /* position in output */
    FT_Byte*   cursor;
    FT_Byte*   limit;

  } FT_GZipFileRec, *FT_GZipFile;

  /* gzip flag byte */
#define FT_GZIP_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
#define FT_GZIP_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
#define FT_GZIP_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
#define FT_GZIP_ORIG_NAME    0x08 /* bit 3 set: original file name present */
#define FT_GZIP_COMMENT      0x10 /* bit 4 set: file comment present */
#define FT_GZIP_RESERVED     0xE0 /* bits 5..7: reserved */

  /* check and skip .gz header - we don't support `transparent' compression */
  static FT_Error
  ft_gzip_check_header( FT_Stream  stream )
  {
    FT_Error  error;
    FT_Byte   head[4];

    if ( FT_STREAM_SEEK( 0 )       ||
         FT_STREAM_READ( head, 4 ) )
      goto Exit;

    /* head[0] && head[1] are the magic numbers;    */
    /* head[2] is the method, and head[3] the flags */
    if ( head[0] != 0x1f              ||
         head[1] != 0x8b              ||
         head[2] != Z_DEFLATED        ||
        (head[3] & FT_GZIP_RESERVED)  )
    {
      error = Gzip_Err_Invalid_File_Format;
      goto Exit;
    }

    /* skip time, xflags and os code */
    (void)FT_STREAM_SKIP( 6 );

    /* skip the extra field */
    if ( head[3] & FT_GZIP_EXTRA_FIELD )
    {
      FT_UInt  len;

      if ( FT_READ_USHORT_LE( len ) ||
           FT_STREAM_SKIP( len )    )
        goto Exit;
    }

    /* skip original file name */
    if ( head[3] & FT_GZIP_ORIG_NAME )
      for (;;)
      {
        FT_UInt  c;

        if ( FT_READ_BYTE( c ) )
          goto Exit;

        if ( c == 0 )
          break;
      }

    /* skip .gz comment */
    if ( head[3] & FT_GZIP_COMMENT )
      for (;;)
      {
        FT_UInt  c;

        if ( FT_READ_BYTE( c ) )
          goto Exit;

        if ( c == 0 )
          break;
      }

    /* skip CRC */
    if ( head[3] & FT_GZIP_HEAD_CRC )
      if ( FT_STREAM_SKIP( 2 ) )
        goto Exit;

  Exit:
    return error;
  }

  static FT_Error
  ft_gzip_file_init( FT_GZipFile  zip,
                     FT_Stream    stream,
                     FT_Stream    source )
  {
    z_stream*  zstream = &zip->zstream;
    FT_Error   error   = Gzip_Err_Ok;

    zip->stream = stream;
    zip->source = source;
    zip->memory = stream->memory;

    zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
    zip->cursor = zip->limit;
    zip->pos    = 0;

    /* check and skip .gz header */
    {
      stream = source;

      error = ft_gzip_check_header( stream );
      if ( error )
        goto Exit;

      zip->start = FT_STREAM_POS();
    }

    /* initialize zlib -- there is no zlib header in the compressed stream */
    zstream->zalloc = (alloc_func)ft_gzip_alloc;
    zstream->zfree  = (free_func) ft_gzip_free;
    zstream->opaque = (voidpf)stream->memory;

    zstream->avail_in = 0;
    zstream->next_in  = zip->buffer;

    if ( inflateInit2( zstream, -MAX_WBITS ) != Z_OK ||
         zstream->next_in == NULL                     )
      error = Gzip_Err_Invalid_File_Format;

  Exit:
    return error;
  }

  static void
  ft_gzip_file_done( FT_GZipFile  zip )
  {
    z_stream*  zstream = &zip->zstream;

    inflateEnd( zstream );

    /* clear the rest */
    zstream->zalloc    = NULL;
    zstream->zfree     = NULL;
    zstream->opaque    = NULL;
    zstream->next_in   = NULL;
    zstream->next_out  = NULL;
    zstream->avail_in  = 0;
    zstream->avail_out = 0;

    zip->memory = NULL;
    zip->source = NULL;
    zip->stream = NULL;
  }

  static FT_Error
  ft_gzip_file_reset( FT_GZipFile  zip )
  {
    FT_Stream  stream = zip->source;
    FT_Error   error;

    if ( !FT_STREAM_SEEK( zip->start ) )
    {
      z_stream*  zstream = &zip->zstream;

      inflateReset( zstream );

      zstream->avail_in  = 0;
      zstream->next_in   = zip->input;
      zstream->avail_out = 0;
      zstream->next_out  = zip->buffer;

      zip->limit  = zip->buffer + FT_GZIP_BUFFER_SIZE;
      zip->cursor = zip->limit;
      zip->pos    = 0;
    }

    return error;
  }

  static FT_Error
  ft_gzip_file_fill_input( FT_GZipFile  zip )
  {
    z_stream*  zstream = &zip->zstream;
    FT_Stream  stream  = zip->source;
    FT_ULong   size;

    if ( stream->read )
    {
      size = stream->read( stream, stream->pos, zip->input,
                           FT_GZIP_BUFFER_SIZE );
      if ( size == 0 )
        return Gzip_Err_Invalid_Stream_Operation;
    }
    else
    {
      size = stream->size - stream->pos;
      if ( size > FT_GZIP_BUFFER_SIZE )
        size = FT_GZIP_BUFFER_SIZE;

      if ( size == 0 )
        return Gzip_Err_Invalid_Stream_Operation;

      FT_MEM_COPY( zip->input, stream->base + stream->pos, size );
    }
    stream->pos += size;

    zstream->next_in  = zip->input;
    zstream->avail_in = size;

    return Gzip_Err_Ok;
  }

  static FT_Error
  ft_gzip_file_fill_output( FT_GZipFile  zip )
  {
    z_stream*  zstream = &zip->zstream;
    FT_Error   error   = Gzip_Err_Ok;

    zip->cursor        = zip->buffer;
    zstream->next_out  = zip->cursor;
    zstream->avail_out = FT_GZIP_BUFFER_SIZE;

    while ( zstream->avail_out > 0 )
    {
      int  err;

      if ( zstream->avail_in == 0 )
      {
        error = ft_gzip_file_fill_input( zip );
        if ( error )
          break;
      }

      err = inflate( zstream, Z_NO_FLUSH );

      if ( err == Z_STREAM_END )
      {
        zip->limit = zstream->next_out;
        if ( zip->limit == zip->cursor )
          error = Gzip_Err_Invalid_Stream_Operation;
        break;
      }
      else if ( err != Z_OK )
      {
        error = Gzip_Err_Invalid_Stream_Operation;
        break;
      }
    }

    return error;
  }

  /* fill output buffer; `count' must be <= FT_GZIP_BUFFER_SIZE */
  static FT_Error
  ft_gzip_file_skip_output( FT_GZipFile  zip,
                            FT_ULong     count )
  {
    FT_Error  error = Gzip_Err_Ok;
    FT_ULong  delta;

    for (;;)
    {
      delta = (FT_ULong)( zip->limit - zip->cursor );
      if ( delta >= count )
        delta = count;

      zip->cursor += delta;
      zip->pos    += delta;

      count -= delta;
      if ( count == 0 )
        break;

      error = ft_gzip_file_fill_output( zip );
      if ( error )
        break;
    }

    return error;
  }

  static FT_ULong
  ft_gzip_file_io( FT_GZipFile  zip,
                   FT_ULong     pos,
                   FT_Byte*     buffer,
                   FT_ULong     count )
  {
    FT_ULong  result = 0;
    FT_Error  error;

    /* Reset inflate stream if we're seeking backwards.        */
    /* Yes, that is not too efficient, but it saves memory :-) */
    if ( pos < zip->pos )
    {
      error = ft_gzip_file_reset( zip );
      if ( error )
        goto Exit;
    }

    /* skip unwanted bytes */
    if ( pos > zip->pos )
    {
      error = ft_gzip_file_skip_output( zip, (FT_ULong)( pos - zip->pos ) );
      if ( error )
        goto Exit;
    }

    if ( count == 0 )
      goto Exit;

    /* now read the data */
    for (;;)
    {
      FT_ULong  delta;

      delta = (FT_ULong)( zip->limit - zip->cursor );
      if ( delta >= count )
        delta = count;

      FT_MEM_COPY( buffer, zip->cursor, delta );
      buffer      += delta;
      result      += delta;
      zip->cursor += delta;
      zip->pos    += delta;

      count -= delta;
      if ( count == 0 )
        break;

      error = ft_gzip_file_fill_output( zip );
      if ( error )
        break;
    }

  Exit:
    return result;
  }

/***************************************************************************/
/***************************************************************************/
/*****                                                                 *****/
/*****               G Z   E M B E D D I N G   S T R E A M             *****/
/*****                                                                 *****/
/***************************************************************************/
/***************************************************************************/

  static void
  ft_gzip_stream_close( FT_Stream  stream )
  {
    FT_GZipFile  zip    = (FT_GZipFile)stream->descriptor.pointer;
    FT_Memory    memory = stream->memory;

    if ( zip )
    {
      /* finalize gzip file descriptor */
      ft_gzip_file_done( zip );

      FT_FREE( zip );

      stream->descriptor.pointer = NULL;
    }
  }

  static FT_ULong
  ft_gzip_stream_io( FT_Stream  stream,
                     FT_ULong   pos,
                     FT_Byte*   buffer,
                     FT_ULong   count )
  {
    FT_GZipFile  zip = (FT_GZipFile)stream->descriptor.pointer;

    return ft_gzip_file_io( zip, pos, buffer, count );
  }

  static FT_ULong
  ft_gzip_get_uncompressed_size( FT_Stream  stream )
  {
    FT_Error  error;
    FT_ULong  old_pos;
    FT_ULong  result = 0;

    old_pos = stream->pos;
    if ( !FT_Stream_Seek( stream, stream->size - 4 ) )
    {
      result = (FT_ULong)FT_Stream_ReadLong( stream, &error );
      if ( error )
        result = 0;

      (void)FT_Stream_Seek( stream, old_pos );
    }

    return result;
  }

  FT_EXPORT_DEF( FT_Error )
  FT_Stream_OpenGzip( FT_Stream  stream,
                      FT_Stream  source )
  {
    FT_Error     error;
    FT_Memory    memory = source->memory;
    FT_GZipFile  zip;

    /*
     *  check the header right now; this prevents allocating un-necessary
     *  objects when we don't need them
     */
    error = ft_gzip_check_header( source );
    if ( error )
      goto Exit;

    FT_ZERO( stream );
    stream->memory = memory;

    if ( !FT_QNEW( zip ) )
    {
      error = ft_gzip_file_init( zip, stream, source );
      if ( error )
      {
        FT_FREE( zip );
        goto Exit;
      }

      stream->descriptor.pointer = zip;
    }

    /*
     *  We use the following trick to try to dramatically improve the
     *  performance while dealing with small files.  If the original stream
     *  size is less than a certain threshold, we try to load the whole font
     *  file into memory.  This saves us from using the 32KB buffer needed
     *  to inflate the file, plus the two 4KB intermediate input/output
     *  buffers used in the `FT_GZipFile' structure.
     */
    {
      FT_ULong  zip_size = ft_gzip_get_uncompressed_size( source );

      if ( zip_size != 0 && zip_size < 40 * 1024 )
      {
        FT_Byte*  zip_buff;

        if ( !FT_ALLOC( zip_buff, zip_size ) )
        {
          FT_ULong  count;

          count = ft_gzip_file_io( zip, 0, zip_buff, zip_size );
          if ( count == zip_size )
          {
            ft_gzip_file_done( zip );
            FT_FREE( zip );

            stream->descriptor.pointer = NULL;

            stream->size  = zip_size;
            stream->pos   = 0;
            stream->base  = zip_buff;
            stream->read  = NULL;
            stream->close = ft_gzip_stream_close;

            goto Exit;
          }

          ft_gzip_file_io( zip, 0, NULL, 0 );
          FT_FREE( zip_buff );
        }
        error = Gzip_Err_Ok;
      }
    }

    stream->size  = 0x7FFFFFFFL;  /* don't know the real size! */
    stream->pos   = 0;
    stream->base  = 0;
    stream->read  = ft_gzip_stream_io;
    stream->close = ft_gzip_stream_close;

  Exit:
    return error;
  }

#else  /* !FT_CONFIG_OPTION_USE_ZLIB */

  FT_EXPORT_DEF( FT_Error )
  FT_Stream_OpenGzip( FT_Stream  stream,
                      FT_Stream  source )
  {
    FT_UNUSED( stream );
    FT_UNUSED( source );

    return Gzip_Err_Unimplemented_Feature;
  }

#endif /* !FT_CONFIG_OPTION_USE_ZLIB */

/* END */