shithub: freetype+ttf2subf

Download patch

ref: a438621451bf126b4819d263c4df8c19db9fd9e2
parent: 2752bd1a462710d0b5f8ec76d973849b8780737a
author: Suzuki, Toshiya (鈴木俊哉) <[email protected]>
date: Wed Aug 24 00:31:31 EDT 2005

Add gxvalid module to validate TrueType GX/AAT tables.

	Modifications on existing files:

	* Jamfile: Register gxvalid module.
	* src/base/Jamfile: Register ftgxval.c.
	* src/base/rule.mk: Register ftgxval.c.
	* docs/INSTALL.ANY: Register gxvalid/gxvalid.c.

	* include/freetype/config/ftheader.h: Add macro to include gxvalid
	header file, FT_GX_VALIDATE_H.
	* include/freetype/config/ftmodule.h: Register gxv_module_class.

	* include/freetype/ftchapters.h: Add comment about gx_validation.
	* include/freetype/ftotval.h: Change keyword FT_VALIDATE_XXX
	to FT_VALIDATE_OTXXX to co-exist gxvalid.
	* include/freetype/tttags.h: Add tag for TrueType GX/AAT tables.

	* include/freetype/internal/ftserv.h: Add macro to use gxvalid
	service, FT_SERVICE_GX_VALIDATE_H
	* include/freetype/internal/fttrace.h: Add trace facilities
	for gxvalid.

	New files on existing directories:

	* include/freetype/internal/services/svgxval.h: Registration of
	validation service for TrueType GX/AAT and classic kern table.
	* include/freetype/ftgxval.h: Public API definition to use gxvalid.
	* src/base/ftgxval.c: Public API of gxvalid.

	New files under src/gxvalid/:

	* src/gxvalid/Jamfile src/gxvalid/README src/gxvalid/module.mk
	src/gxvalid/rules.mk src/gxvalid/gxvalid.c src/gxvalid/gxvalid.h
	src/gxvalid/gxvbsln.c src/gxvalid/gxvcommn.c src/gxvalid/gxvcommn.h
	src/gxvalid/gxverror.h src/gxvalid/gxvfeat.c src/gxvalid/gxvfgen.c
	src/gxvalid/gxvjust.c src/gxvalid/gxvkern.c src/gxvalid/gxvlcar.c
	src/gxvalid/gxvmod.c src/gxvalid/gxvmod.h src/gxvalid/gxvmort.c
	src/gxvalid/gxvmort.h src/gxvalid/gxvmort0.c src/gxvalid/gxvmort1.c
	src/gxvalid/gxvmort2.c src/gxvalid/gxvmort4.c src/gxvalid/gxvmort5.c
	src/gxvalid/gxvmorx.c src/gxvalid/gxvmorx.h src/gxvalid/gxvmorx0.c
	src/gxvalid/gxvmorx1.c src/gxvalid/gxvmorx2.c src/gxvalid/gxvmorx4.c
	src/gxvalid/gxvmorx5.c src/gxvalid/gxvopbd.c src/gxvalid/gxvprop.c
	src/gxvalid/gxvtrak.c: New files, gxvalid body.

git/fs: mount .git/fs: mount/attach disallowed
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,50 @@
+2005-08-23  suzuki toshiya <[email protected]>
+
+	Add gxvalid module to validate TrueType GX/AAT tables.
+
+	Modifications on existing files:
+
+	* Jamfile: Register gxvalid module.
+	* src/base/Jamfile: Register ftgxval.c.
+	* src/base/rule.mk: Register ftgxval.c.
+	* docs/INSTALL.ANY: Register gxvalid/gxvalid.c.
+
+	* include/freetype/config/ftheader.h: Add macro to include gxvalid
+	header file, FT_GX_VALIDATE_H.
+	* include/freetype/config/ftmodule.h: Register gxv_module_class.
+
+	* include/freetype/ftchapters.h: Add comment about gx_validation.
+	* include/freetype/ftotval.h: Change keyword FT_VALIDATE_XXX
+	to FT_VALIDATE_OTXXX to co-exist gxvalid.
+	* include/freetype/tttags.h: Add tag for TrueType GX/AAT tables.
+
+	* include/freetype/internal/ftserv.h: Add macro to use gxvalid
+	service, FT_SERVICE_GX_VALIDATE_H
+	* include/freetype/internal/fttrace.h: Add trace facilities
+	for gxvalid.
+
+	New files on existing directories:
+
+	* include/freetype/internal/services/svgxval.h: Registration of
+	validation service for TrueType GX/AAT and classic kern table.
+	* include/freetype/ftgxval.h: Public API definition to use gxvalid.
+	* src/base/ftgxval.c: Public API of gxvalid.
+
+	New files under src/gxvalid/:
+
+	* src/gxvalid/Jamfile src/gxvalid/README src/gxvalid/module.mk
+	src/gxvalid/rules.mk src/gxvalid/gxvalid.c src/gxvalid/gxvalid.h
+	src/gxvalid/gxvbsln.c src/gxvalid/gxvcommn.c src/gxvalid/gxvcommn.h
+	src/gxvalid/gxverror.h src/gxvalid/gxvfeat.c src/gxvalid/gxvfgen.c
+	src/gxvalid/gxvjust.c src/gxvalid/gxvkern.c src/gxvalid/gxvlcar.c
+	src/gxvalid/gxvmod.c src/gxvalid/gxvmod.h src/gxvalid/gxvmort.c
+	src/gxvalid/gxvmort.h src/gxvalid/gxvmort0.c src/gxvalid/gxvmort1.c
+	src/gxvalid/gxvmort2.c src/gxvalid/gxvmort4.c src/gxvalid/gxvmort5.c
+	src/gxvalid/gxvmorx.c src/gxvalid/gxvmorx.h src/gxvalid/gxvmorx0.c
+	src/gxvalid/gxvmorx1.c src/gxvalid/gxvmorx2.c src/gxvalid/gxvmorx4.c
+	src/gxvalid/gxvmorx5.c src/gxvalid/gxvopbd.c src/gxvalid/gxvprop.c
+	src/gxvalid/gxvtrak.c: New files, gxvalid body.
+
 2005-08-21  Werner Lemberg  <[email protected]>
 
 	* src/truetype/ttgload.c (TT_Load_Glyph): Only translate outline
--- a/Jamfile
+++ b/Jamfile
@@ -76,6 +76,7 @@
                   cache      # cache sub-system
                   cff        # CFF/CEF font driver
                   cid        # PostScript CID-keyed font driver
+                  gxvalid    # validation of TrueTypeGX/AAT tables
                   gzip       # support for gzip-compressed files
                   lzw        # support for LZW-compressed files
                   otvalid    # validation of OpenType tables
--- a/docs/INSTALL.ANY
+++ b/docs/INSTALL.ANY
@@ -69,6 +69,7 @@
       src/cache/ftcache.c     -- cache sub-system (in beta)
       src/gzip/ftgzip.c       -- support for compressed fonts (.gz)
       src/lzw/ftlzw.c         -- support for compressed fonts (.Z)
+      src/gxvalid/gxvalid.c   -- TrueTypeGX/AAT table validation
       src/otvalid/otvalid.c   -- OpenType table validation
       src/psaux/psaux.c       -- PostScript Type 1 parsing
       src/pshinter/pshinter.c -- PS hinting module
--- a/include/freetype/config/ftheader.h
+++ b/include/freetype/config/ftheader.h
@@ -557,6 +557,18 @@
   /*                                                                       */
 #define FT_OPENTYPE_VALIDATE_H  <freetype/ftotval.h>
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* @macro:                                                               */
+  /*    FT_GX_VALIDATE_H                                                   */
+  /*                                                                       */
+  /* @description:                                                         */
+  /*    A macro used in #include statements to name the file containing    */
+  /*    the optional FreeType 2 API used to validate TrueTypeGX/AAT tables */
+  /*    (feat, mort, morx, bsln, just, kern, opbd, trak, prop).            */
+  /*                                                                       */
+#define FT_GX_VALIDATE_H  <freetype/ftgxval.h>
+
 
   /* */
 
--- a/include/freetype/config/ftmodule.h
+++ b/include/freetype/config/ftmodule.h
@@ -17,3 +17,4 @@
 FT_USE_MODULE(ft_smooth_lcdv_renderer_class)
 FT_USE_MODULE(otv_module_class)
 FT_USE_MODULE(bdf_driver_class)
+FT_USE_MODULE(gxv_module_class)
--- a/include/freetype/ftchapters.h
+++ b/include/freetype/ftchapters.h
@@ -41,6 +41,7 @@
 /*    pfr_fonts                                                            */
 /*    winfnt_fonts                                                         */
 /*    ot_validation                                                        */
+/*    gx_validation                                                        */
 /*                                                                         */
 /***************************************************************************/
 
--- /dev/null
+++ b/include/freetype/ftgxval.h
@@ -1,0 +1,302 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgxval.h                                                              */
+/*                                                                         */
+/*    FreeType API for validating TrueTypeGX/AAT tables (specification).   */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  Masatake YAMATO, Redhat 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 support of Information-technology Promotion  */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#ifndef __FTGXVAL_H__
+#define __FTGXVAL_H__
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#ifdef FREETYPE_H
+#error "freetype.h of FreeType 1 has been loaded!"
+#error "Please fix the directory search order for header files"
+#error "so that freetype.h of FreeType 2 is found first."
+#endif
+
+
+FT_BEGIN_HEADER
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Section>                                                             */
+  /*    gx_validation                                                      */
+  /*                                                                       */
+  /* <Title>                                                               */
+  /*    TrueTypeGX/AAT Validation                                          */
+  /*                                                                       */
+  /* <Abstract>                                                            */
+  /*    An API to validate TrueTypeGX/AAT tables.                          */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This section contains the declaration of functions to validate     */
+  /*    some TrueTypeGX tables (feat, mort, morx, bsln, just, kern, opbd,  */
+  /*    trak, prop, lcar).                                                 */
+  /*                                                                       */
+  /*************************************************************************/
+
+/***************************************************************************/
+/*                                                                         */
+/*                                                                         */
+/* Warnings: Use FT_VALIDATE_XXX to validate a table.                      */
+/*           Following definitions are for gxvalid developers.             */
+/*                                                                         */
+/*                                                                         */
+/***************************************************************************/
+#define FT_VALIDATE_feat_INDEX     0
+#define FT_VALIDATE_mort_INDEX     1
+#define FT_VALIDATE_morx_INDEX     2
+#define FT_VALIDATE_bsln_INDEX     3
+#define FT_VALIDATE_just_INDEX     4
+#define FT_VALIDATE_kern_INDEX     5
+#define FT_VALIDATE_opbd_INDEX     6
+#define FT_VALIDATE_trak_INDEX     7
+#define FT_VALIDATE_prop_INDEX     8
+#define FT_VALIDATE_lcar_INDEX     9
+#define FT_VALIDATE_GX_LAST_INDEX  FT_VALIDATE_lcar_INDEX
+#define FT_VALIDATE_GX_LENGTH     (FT_VALIDATE_GX_LAST_INDEX + 1)
+
+ /* Up to 0x1000 is used by otvalid.
+    Ox2000 is reserved for feature ot extension. */
+#define FT_VALIDATE_GX_START 0x4000
+#define FT_VALIDATE_GX_BITFIELD(tag)  \
+  (FT_VALIDATE_GX_START << FT_VALIDATE_##tag##_INDEX)
+
+
+ /**********************************************************************
+  *
+  * @enum:
+  *    FT_VALIDATE_GXXXX
+  *
+  * @description:
+  *    A list of bit-field constants used with @FT_TrueTypeGX_Validate to
+  *    indicate which TrueTypeGX/AAT Type tables should be validated.
+  *
+  * @values:
+  *    FT_VALIDATE_feat ::
+  *      Validate feat table.
+  *
+  * @values:
+  *    FT_VALIDATE_mort ::
+  *      Validate mort table.
+  *
+  * @values:
+  *    FT_VALIDATE_morx ::
+  *      Validate morx table.
+  *
+  * @values:
+  *    FT_VALIDATE_bsln ::
+  *      Validate bsln table.
+  *
+  * @values:
+  *    FT_VALIDATE_just ::
+  *      Validate just table.
+  *
+  * @values:
+  *    FT_VALIDATE_kern ::
+  *      Validate kern table.
+  *
+  * @values:
+  *    FT_VALIDATE_opbd ::
+  *      Validate opbd table.
+  *
+  * @values:
+  *    FT_VALIDATE_trak ::
+  *      Validate trak table.
+  *
+  * @values:
+  *    FT_VALIDATE_prop ::
+  *      Validate prop table.
+  *
+  * @values:
+  *    FT_VALIDATE_lcar ::
+  *      Validate lcar table.
+  *
+  * @values:
+  *    FT_VALIDATE_GX ::
+  *      Validate all TrueTypeGX tables (feat, mort, morx, bsln, just, kern,
+  *      opbd, trak, prop and lcar).
+  *
+  */
+
+#define FT_VALIDATE_feat  FT_VALIDATE_GX_BITFIELD(feat)
+#define FT_VALIDATE_mort  FT_VALIDATE_GX_BITFIELD(mort)
+#define FT_VALIDATE_morx  FT_VALIDATE_GX_BITFIELD(morx)
+#define FT_VALIDATE_bsln  FT_VALIDATE_GX_BITFIELD(bsln)
+#define FT_VALIDATE_just  FT_VALIDATE_GX_BITFIELD(just)
+#define FT_VALIDATE_kern  FT_VALIDATE_GX_BITFIELD(kern)
+#define FT_VALIDATE_opbd  FT_VALIDATE_GX_BITFIELD(opbd)
+#define FT_VALIDATE_trak  FT_VALIDATE_GX_BITFIELD(trak)
+#define FT_VALIDATE_prop  FT_VALIDATE_GX_BITFIELD(prop)
+#define FT_VALIDATE_lcar  FT_VALIDATE_GX_BITFIELD(lcar)
+
+#define FT_VALIDATE_GX  ( FT_VALIDATE_feat |     \
+                          FT_VALIDATE_mort |     \
+                          FT_VALIDATE_morx |     \
+                          FT_VALIDATE_bsln |     \
+                          FT_VALIDATE_just |     \
+                          FT_VALIDATE_kern |     \
+                          FT_VALIDATE_opbd |     \
+                          FT_VALIDATE_trak |     \
+                          FT_VALIDATE_prop |     \
+                          FT_VALIDATE_lcar )
+
+
+  /* */
+
+ /**********************************************************************
+  *
+  * @function:
+  *    FT_TrueTypeGX_Validate
+  *
+  * @description:
+  *    Validate various TrueTypeGX tables to assure that all offsets and
+  *    indices are valid.  The idea is that a higher-level library which
+  *    actually does the text layout can access those tables without
+  *    error checking (which can be quite time consuming).
+  *
+  * @input:
+  *    face ::
+  *       A handle to the input face.
+  *
+  *    validation_flags ::
+  *       A bit field which specifies the tables to be validated.  See
+  *       @FT_VALIDATE_GXXXX for possible values.
+  *
+  *    table_length ::
+  *       The length of tables. Generally FT_VALIDATE_GX_LENGTH should
+  *       be passed.
+  *
+  * @output
+  *    tables ::
+  *       The array where each validated sfnt tables are stored to.
+  *       The array itself must be allocated by a client.
+  *
+  * @return:
+  *   FreeType error code.  0 means success.
+  *
+  * @note:
+  *   This function only works with TrueTypeGX fonts, returning an error
+  *   otherwise.
+  *
+  *   After use, the application should deallocate the buffers pointed by each
+  *   tables' element.  A NULL value indicates that the table either
+  *   doesn't exist in the font, the application hasn't asked for validation, or
+  *   the validator doesn't have ability to validate the sfnt table.
+  */
+  FT_EXPORT( FT_Error )
+  FT_TrueTypeGX_Validate( FT_Face    face,
+                          FT_UInt    validation_flags,
+                          FT_Bytes   tables[FT_VALIDATE_GX_LENGTH],
+                          FT_UInt    table_length );
+
+
+
+  /* */
+
+ /**********************************************************************
+  *
+  * @enum:
+  *    FT_VALIDATE_CKERNXXX
+  *
+  * @description:
+  *    A list of bit-field constants used with @FT_ClassicKern_Validate
+  *    to indicate (a) classic kern dialect(s).
+  *
+  * @values:
+  *    FT_VALIDATE_MS ::
+  *      Validate the kern table as it has classic Microsoft kern dialect.
+  *      If @FT_ClassicKern_Validate detects the table has the other
+  *      dialect, it regards the table invalid.
+  *
+  * @values:
+  *    FT_VALIDATE_APPLE ::
+  *      Validate the kern table as it has classic Apple kern dialect.
+  *      If @FT_ClassicKern_Validate detects the table has the other
+  *      dialect, it regards the table invalid.
+  *
+  * @values:
+  *    FT_VALIDATE_CKERN ::
+  *      Validate the kern table as it has classic Apple kern dialect or
+  *      Microsoft kern dialect.
+  */
+#define FT_VALIDATE_MS     (FT_VALIDATE_GX_START << 0)
+#define FT_VALIDATE_APPLE  (FT_VALIDATE_GX_START << 1)
+
+#define FT_VALIDATE_CKERN  ( FT_VALIDATE_MS | FT_VALIDATE_APPLE )
+
+
+  /* */
+
+ /**********************************************************************
+  *
+  * @function:
+  *    FT_ClassicKern_Validate
+  *
+  * @description:
+  *    Validate classic(16bit format) kern table to assure that the offsets
+  *    and indices are valid.  The idea is that a higher-level library
+  *    which actually does the text layout can access those tables without
+  *    error checking (which can be quite time consuming).
+  *
+  *    Kern table validator in @FT_TrueTypeGX_Validate deals both
+  *    new 32 bit format and classic 16 bit format. In other hand
+  *    this function supports only the classic 16 bit format.
+  *
+  * @input:
+  *    face ::
+  *       A handle to the input face.
+  *
+  *    validation_flags ::
+  *       A bit field which specifies the dialect to be validated.  See
+  *       @FT_VALIDATE_CKERNXXX for possible values.
+  *
+  * @output
+  *    ckern_table ::
+  *       A pointer to the kern table.
+  *
+  * @return:
+  *   FreeType error code.  0 means success.
+  *
+  * @note:
+  *   After use, the application should deallocate the buffers pointed by
+  *   ckern_table.  A NULL value indicates that the table either
+  *   doesn't exist in the font.
+  */
+  FT_EXPORT( FT_Error )
+  FT_ClassicKern_Validate( FT_Face   face,
+                           FT_UInt   validation_flags,
+                           FT_Bytes *ckern_table );
+
+
+ /* */
+
+
+FT_END_HEADER
+
+#endif /* __FTGXVAL_H__ */
+
+
+/* END */
--- a/include/freetype/ftotval.h
+++ b/include/freetype/ftotval.h
@@ -64,7 +64,7 @@
  /**********************************************************************
   *
   * @enum:
-  *    FT_VALIDATE_XXX
+  *    FT_VALIDATE_OTXXX
   *
   * @description:
   *    A list of bit-field constants used with @FT_OpenType_Validate to
@@ -121,7 +121,7 @@
   *
   *    validation_flags ::
   *       A bit field which specifies the tables to be validated.  See
-  *       @FT_VALIDATE_XXX for possible values.
+  *       @FT_VALIDATE_OTXXX for possible values.
   *
   * @output:
   *    BASE_table ::
--- a/include/freetype/internal/ftserv.h
+++ b/include/freetype/internal/ftserv.h
@@ -309,6 +309,7 @@
 #define FT_SERVICE_POSTSCRIPT_INFO_H    <freetype/internal/services/svpsinfo.h>
 #define FT_SERVICE_POSTSCRIPT_NAME_H    <freetype/internal/services/svpostnm.h>
 #define FT_SERVICE_SFNT_H               <freetype/internal/services/svsfnt.h>
+#define FT_SERVICE_GX_VALIDATE_H        <freetype/internal/services/svgxval.h>
 #define FT_SERVICE_TT_CMAP_H            <freetype/internal/services/svttcmap.h>
 #define FT_SERVICE_WINFNT_H             <freetype/internal/services/svwinfnt.h>
 #define FT_SERVICE_XFREE86_NAME_H       <freetype/internal/services/svxf86nm.h>
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -114,5 +114,19 @@
 FT_TRACE_DEF( otvgsub )
 FT_TRACE_DEF( otvjstf )
 
+  /* TrueTypeGX/AAT validation components */
+FT_TRACE_DEF( gxvmodule )
+FT_TRACE_DEF( gxvcommon )
+FT_TRACE_DEF( gxvfeat )
+FT_TRACE_DEF( gxvmort )
+FT_TRACE_DEF( gxvmorx )
+FT_TRACE_DEF( gxvbsln )
+FT_TRACE_DEF( gxvjust )
+FT_TRACE_DEF( gxvkern )
+FT_TRACE_DEF( gxvopbd )
+FT_TRACE_DEF( gxvtrak )
+FT_TRACE_DEF( gxvprop )
+FT_TRACE_DEF( gxvlcar )
+
 
 /* END */
--- /dev/null
+++ b/include/freetype/internal/services/svgxval.h
@@ -1,0 +1,69 @@
+/***************************************************************************/
+/*                                                                         */
+/*  svgxval.h                                                              */
+/*                                                                         */
+/*    FreeType API for validating TrueTypeGX/AAT tables (specification).   */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#ifndef __SVGXVAL_H__
+#define __SVGXVAL_H__
+
+#include FT_GX_VALIDATE_H
+#include FT_INTERNAL_VALIDATE_H
+
+FT_BEGIN_HEADER
+
+
+#define FT_SERVICE_ID_GX_VALIDATE           "truetypegx-validate"
+#define FT_SERVICE_ID_CLASSICKERN_VALIDATE  "classickern-validate"
+
+  typedef FT_Error
+  (*gxv_validate_func)( FT_Face    face,
+                        FT_UInt    gx_flags,
+                        FT_Bytes   tables[FT_VALIDATE_GX_LENGTH],
+                        FT_UInt    table_length );
+
+
+  typedef FT_Error
+  (*ckern_validate_func) ( FT_Face   face,
+                           FT_UInt   ckern_flags,
+                           FT_Bytes  *ckern_table );
+
+
+  FT_DEFINE_SERVICE( GXvalidate )
+  {
+    gxv_validate_func  validate;
+  };
+
+  FT_DEFINE_SERVICE( CKERNvalidate )
+  {
+    ckern_validate_func  validate;
+  };
+
+  /* */
+
+
+FT_END_HEADER
+
+
+#endif /* __SVGXVAL_H__ */
+
+
+/* END */
--- a/include/freetype/tttags.h
+++ b/include/freetype/tttags.h
@@ -38,6 +38,7 @@
 #define TTAG_bdat  FT_MAKE_TAG( 'b', 'd', 'a', 't' )
 #define TTAG_bhed  FT_MAKE_TAG( 'b', 'h', 'e', 'd' )
 #define TTAG_bloc  FT_MAKE_TAG( 'b', 'l', 'o', 'c' )
+#define TTAG_bsln  FT_MAKE_TAG( 'b', 's', 'l', 'n' )
 #define TTAG_CFF   FT_MAKE_TAG( 'C', 'F', 'F', ' ' )
 #define TTAG_cmap  FT_MAKE_TAG( 'c', 'm', 'a', 'p' )
 #define TTAG_cvar  FT_MAKE_TAG( 'c', 'v', 'a', 'r' )
@@ -46,6 +47,7 @@
 #define TTAG_EBDT  FT_MAKE_TAG( 'E', 'B', 'D', 'T' )
 #define TTAG_EBLC  FT_MAKE_TAG( 'E', 'B', 'L', 'C' )
 #define TTAG_EBSC  FT_MAKE_TAG( 'E', 'B', 'S', 'C' )
+#define TTAG_feat  FT_MAKE_TAG( 'f', 'e', 'a', 't' )
 #define TTAG_fpgm  FT_MAKE_TAG( 'f', 'p', 'g', 'm' )
 #define TTAG_fvar  FT_MAKE_TAG( 'f', 'v', 'a', 'r' )
 #define TTAG_gasp  FT_MAKE_TAG( 'g', 'a', 's', 'p' )
@@ -59,19 +61,26 @@
 #define TTAG_hhea  FT_MAKE_TAG( 'h', 'h', 'e', 'a' )
 #define TTAG_hmtx  FT_MAKE_TAG( 'h', 'm', 't', 'x' )
 #define TTAG_JSTF  FT_MAKE_TAG( 'J', 'S', 'T', 'F' )
+#define TTAG_just  FT_MAKE_TAG( 'j', 'u', 's', 't' )
 #define TTAG_kern  FT_MAKE_TAG( 'k', 'e', 'r', 'n' )
+#define TTAG_lcar  FT_MAKE_TAG( 'l', 'c', 'a', 'r' )
 #define TTAG_loca  FT_MAKE_TAG( 'l', 'o', 'c', 'a' )
 #define TTAG_LTSH  FT_MAKE_TAG( 'L', 'T', 'S', 'H' )
 #define TTAG_maxp  FT_MAKE_TAG( 'm', 'a', 'x', 'p' )
 #define TTAG_MMFX  FT_MAKE_TAG( 'M', 'M', 'F', 'X' )
 #define TTAG_MMSD  FT_MAKE_TAG( 'M', 'M', 'S', 'D' )
+#define TTAG_mort  FT_MAKE_TAG( 'm', 'o', 'r', 't' )
+#define TTAG_morx  FT_MAKE_TAG( 'm', 'o', 'r', 'x' )
 #define TTAG_name  FT_MAKE_TAG( 'n', 'a', 'm', 'e' )
+#define TTAG_opbd  FT_MAKE_TAG( 'o', 'p', 'b', 'd' )
 #define TTAG_OS2   FT_MAKE_TAG( 'O', 'S', '/', '2' )
 #define TTAG_OTTO  FT_MAKE_TAG( 'O', 'T', 'T', 'O' )
 #define TTAG_PCLT  FT_MAKE_TAG( 'P', 'C', 'L', 'T' )
 #define TTAG_post  FT_MAKE_TAG( 'p', 'o', 's', 't' )
 #define TTAG_prep  FT_MAKE_TAG( 'p', 'r', 'e', 'p' )
+#define TTAG_prop  FT_MAKE_TAG( 'p', 'r', 'o', 'p' )
 #define TTAG_true  FT_MAKE_TAG( 't', 'r', 'u', 'e' )
+#define TTAG_trak  FT_MAKE_TAG( 't', 'r', 'a', 'k' )
 #define TTAG_ttc   FT_MAKE_TAG( 't', 't', 'c', ' ' )
 #define TTAG_ttcf  FT_MAKE_TAG( 't', 't', 'c', 'f' )
 #define TTAG_VDMX  FT_MAKE_TAG( 'V', 'D', 'M', 'X' )
--- a/src/base/Jamfile
+++ b/src/base/Jamfile
@@ -32,7 +32,7 @@
 #
 Library  $(FT2_LIB) : ftsystem.c   ftinit.c    ftglyph.c  ftmm.c     ftbdf.c
                       ftbbox.c     ftdebug.c   ftxf86.c   fttype1.c  ftpfr.c
-                      ftstroke.c   ftwinfnt.c  ftotval.c  ftbitmap.c ;
+                      ftstroke.c   ftwinfnt.c  ftotval.c  ftgxval.c  ftbitmap.c ;
 
 # Add Macintosh-specific file to the library when necessary.
 #
--- /dev/null
+++ b/src/base/ftgxval.c
@@ -1,0 +1,103 @@
+/***************************************************************************/
+/*                                                                         */
+/*  ftgxval.c                                                              */
+/*                                                                         */
+/*    FreeType API for validating TrueTyepGX/AAT tables (body).            */
+/*                                                                         */
+/*  Copyright 2004 by                                                      */
+/*  Masatake YAMATO, Redhat 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_GX_VALIDATE_H
+
+  /* documentation is in ftgxval.h */
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_TrueTypeGX_Validate( FT_Face    face,
+                          FT_UInt    validation_flags,
+                          FT_Bytes   tables[FT_VALIDATE_GX_LENGTH],
+                          FT_UInt    table_length )
+  {
+    FT_Service_GXvalidate  service;
+    FT_Error               error;
+
+
+    if ( !face )
+    {
+      error = FT_Err_Invalid_Face_Handle;
+      goto Exit;
+    }
+
+    if ( tables == NULL )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, GX_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 tables,
+                                 table_length );
+    else
+      error = FT_Err_Invalid_Argument;
+
+  Exit:
+    return error;
+  }
+
+
+  FT_EXPORT_DEF( FT_Error )
+  FT_ClassicKern_Validate( FT_Face   face,
+                           FT_UInt   validation_flags,
+                           FT_Bytes *ckern_table )
+  {
+    FT_Service_CKERNvalidate  service;
+    FT_Error                  error;
+
+
+    if ( !face )
+    {
+      error = FT_Err_Invalid_Face_Handle;
+      goto Exit;
+    }
+
+    if ( ckern_table == NULL )
+    {
+      error = FT_Err_Invalid_Argument;
+      goto Exit;
+    }
+
+    FT_FACE_FIND_GLOBAL_SERVICE( face, service, CLASSICKERN_VALIDATE );
+
+    if ( service )
+      error = service->validate( face,
+                                 validation_flags,
+                                 ckern_table );
+    else
+      error = FT_Err_Invalid_Argument;
+
+  Exit:
+    return error;
+  }
+
+
+/* END */
--- a/src/base/rules.mk
+++ b/src/base/rules.mk
@@ -54,6 +54,7 @@
                 $(BASE_DIR)/ftbbox.c   \
                 $(BASE_DIR)/ftbdf.c    \
                 $(BASE_DIR)/ftglyph.c  \
+                $(BASE_DIR)/ftgxval.c  \
                 $(BASE_DIR)/ftmm.c     \
                 $(BASE_DIR)/ftotval.c  \
                 $(BASE_DIR)/ftpfr.c    \
--- /dev/null
+++ b/src/gxvalid/Jamfile
@@ -1,0 +1,21 @@
+# FreeType 2 src/gxvalid Jamfile (c) 2005 suzuki toshiya, Masatake YAMATO and Red Hat K.K.
+#
+
+SubDir  FT2_TOP $(FT2_SRC_DIR) gxvalid ;
+
+{
+  local  _sources ;
+
+  if $(FT2_MULTI)
+  {
+    _sources = gxvcommn gxvfeat gxvbsln gxvtrak gxvopbd gxvprop gxvjust gxvmort gxvmort0 gxvmort1 gxvmort2 gxvmort4 gxvmort5 gxvmorx gxvmorx0 gxvmorx1 gxvmorx2 gxvmorx4 gxvmorx5 gxvlcar gxvkern gxvmod ;
+  }
+  else
+  {
+    _sources = gxvalid ;
+  }
+
+  Library  $(FT2_LIB) : $(_sources).c ;
+}
+
+# end of src/gxvalid Jamfile
--- /dev/null
+++ b/src/gxvalid/README
@@ -1,0 +1,447 @@
+  gxvalid: TrueType GX validator
+  ==============================
+
+  1. What is this
+  ---------------
+  "gxvalid" is a module to validate TrueType GX tables:  a collection of
+  additional  tables  in  TrueType font which is used  by  "QuickDraw GX
+  Text",  Apple  Advanced Typography  (AAT).  In addition,  gxvalid  can
+  validates "kern" table which had been extended for AAT. Like otvalid,
+  gxvalid uses Freetype2's validator framework(ftvalid).
+
+  You can link gxvalid with your program; before running your own layout
+  engine,  gxvalid validates a font file.  As the result, you can reduce
+  error-checking code  from the layout engine.  You can use gxvalid as a
+  stand-alone font validator;  ftvalid command included in ft2demo calls
+  gxvalid internally.  Stand-alone font validator may be useful for font
+  developers.
+
+  This documents contains following informations:
+  - supported TrueType GX tables
+  - validation limitation in principle
+  - permissive error handling of broken GX tables
+  - "kern" table issue.
+
+
+  2. Supported tables
+  -------------------
+  Following GX tables are currently supported.
+    bsln feat just kern(*) lcar mort morx opbd prop trak
+
+  Following GX tables are currently unsupported.
+    cvar fdsc fmtx fvar gvar Zapf
+
+  Following GX tables won't be supported.
+    acnt(**) hsty(***)
+
+  Undocumented tables in TrueType fonts designed for Apple platform.
+    CVTM TPNM addg umif
+
+  *)   "kern" validator includes both of classic kern  (format supported
+       by both of Microsoft and Apple platforms) and new kern  (a format
+       supported by Apple platform only).
+
+  **)  "acnt" tables is not supported  by currently available Apple font
+       tools.
+
+  ***) There is one more Apple extension "hsty" but it is for Newton-OS,
+       not GX  (Newton-OS  is a platform by Apple,  but it can use sfnt-
+       housed bitmap fonts only.   Therefore, it should be excluded from
+       "Apple platform" in the context of TrueType.   gxvalid ignores it
+       as Apple font tools do so.
+
+  We have checked 183 fonts bundled to MacOS 9.1, MacOS 9.2, MacOS 10.0,
+  MacOS X 10.1, MSIE for MacOS and AppleWorks 6.0.  In addition, we have
+  checked  67 Dynalab fonts  (designed  for  MacOS) and  189 Ricoh fonts
+  (designed for  Windows and MacOS dual platforms).  The number of fonts
+  including TrueType GX tables are listed in following:
+    bsln:  76
+    feat: 191
+    just:  84
+    kern:  59
+    lcar:   4
+    mort: 326
+    morx:  19
+    opbd:   4
+    prop: 114
+    trak:  16
+  Dynalab and Ricoh fonts didn't have GX tables except of feat and mort.
+
+  3. Validation limitations in principle
+  --------------------------------------
+  TrueType GX provides  layout information to font-rasterize/text-layout
+  libraries.  gxvalid can check whether layout information is  stored as
+  TrueType GX  format specified by  Apple.  But gxvalid cannot check how
+  QuickDraw GX/AAT renderer uses the stored information.
+
+    3-1. Validation of State Machine activity
+    -----------------------------------------
+    QuickDraw GX/AAT  has  "State Machine"  to provide "stateful" layout
+    features,  and TrueType GX  stores  the  state transition diagram of
+    "State Machine" in "StateTable" data structure.  While State Machine
+    receives  a series of glyph ID,  State Machine starts from "start of
+    text" state,  walks  around  various  states and  generates  various
+    layout  informations  to renderer,  and  finally  reaches to "end of
+    text".
+
+    gxvalid can check essential errors like:
+      - possibility of state transition to undefined states
+      - existence  of  glyph ID that State Machine  doesn't know  how to
+        handle it
+      - State Machine cannot  compute the layout information  from given
+        diagram
+    these errors  can be checked within finite steps,  and without State
+    Machine itself,  because  these are  errors of "expression" of state
+    transition diagram.
+
+    There's no limitation about how long State Machine walks around,  so
+    validation of the algorithm in the state transition diagram requires
+    infinite steps, even if we have State Machine in gxvalid. Therefore,
+    following "errors" cannot be checked.
+      - existence of states which State Machine never transits to.
+      - possibility that State Machine never reaches to "end of text".
+      - possibility of stack underflow/overflow in State Machine
+        (in  ligature  and  contextual glyph substitution, State Machine
+         can store 16 glyphs onto its stack)
+
+    In addition,  gxvalid doesn't check  "temporal glyph ID" used in the
+    chained State Machines (in "mort" and "morx" tables).  When a layout
+    feature is implemented by  single State Machine,  glyph ID converted
+    by State Machine is passed to the glyph renderer, thus it should not
+    point to undefined glyph ID.  But if a layout feature is implemented
+    by chained State Machines, the component State Machine (if it is not
+    final one) is permitted to generate  undefined glyph ID for temporal
+    use, because it is handled  by next component State Machine, instead
+    of the glyph renderer.  To validate such temporal glyph ID,  gxvalid
+    must stack  all undefined glyph IDs  which is possible in the output
+    of previous State Machine and search them in "ClassTable" of current
+    State Machine.  It is too complexed work to  list all possible glyph
+    IDs from StateTable, especially from ligature substitution table.
+
+    3-2. Validation of relationship among multiple layout features
+    --------------------------------------------------------------
+    gxvalid  does not  validate  the relationship  among multiple layout
+    features at all.
+
+    If  multiple layout features are defined in  TrueType GX tables, the
+    interactivity,  overriding,  and conflict  among layout features are
+    defined in the font too.  For example,  there are several predefined
+    spacing control features:
+      - Text Spacing          (Proportional/Monospace/Half-width/Normal)
+      - Number Spacing        (Monospaced-numbers/Proportional-numbers)
+      - Kana Spacing          (Full-width/Proportional)
+      - Ideographic Spacing   (Full-width/Proportional)
+      - CJK Roman Spacing     (Half-width/Proportional/Default-roman
+                               /Full-width-roman/Proportional)
+    If  all layout features  are  independently  managed,  we can set an
+    inconsistent  typographic rule, as like "Text Spacing=Monospace" and
+    "Ideographic Spacing=Proportional", at the same time.
+
+    The combination  of each layout feature  is managed by 32bit integer
+    (1 bit for 1 selector setting),  so we can define relationship among
+    features  up  to  32 settings,  theoretically.  But  if  setting  of
+    a feature affects setting of another features,  typographic priority
+    of  each  layout  feature  is required to validate the relationship.
+    TrueType GX format specification does not give such information even
+    for predefined features.
+
+  4. Permissive error handling of broken GX tables
+  ------------------------------------------------
+  When Apple's font rendering system finds  an inconsistency,  violation
+  of specification  or unspecified value in TrueType GX tables,  they do
+  not always return error. In most case, they silently ignore such wrong
+  values or  whole  of  table.  In fact,  MacOS  is  shipped  with fonts
+  including  broken  GX/AAT  tables,  but  no  harmful  effects  due  to
+  officially broken fonts are observed by end-users.
+
+  gxvalid  is designed to continue its validation  as long as possible.
+  When gxvalid find wrong value,  gxvalid warns it at least,  and take a
+  fallback procedure if possible.  The fallback procedure depends on the
+  debug level.
+
+  We used following 3 tools to refer Apple's error handling.
+    - FontValidator  (for MacOS 8.5 - 9.2)  resource fork font
+    - ftxvalidator   (for MacOS X 10.1 -)   dfont or naked-sfnt
+    - ftxdumperfuser (for MacOS X 10.1 -)   dfont or naked-sfnt
+  However,  all tests are on PowerPC based Macintosh, we have not tested
+  on m68k-based Macintosh at all, at present.
+
+  We  checked  183 fonts  bundled to  MacOS 9.1,  MacOS 9.2, MacOS 10.0,
+  MacOS X 10.1,  MSIE for MacOS  and  AppleWorks 6.0.  These  fonts  are
+  distributed  officially,  but many  broken GX/AAT tables  are found by
+  Apple's font tools. In following, we list typical violation against GX
+  specification, in Apple official fonts.  At least, gxvalid warns them,
+  and fallback method to continue
+
+    4-1. broken BinSrchHeader ( 19/183)
+    -----------------------------------
+    BinSrchHeader is a header of data array, for m68k platform to access
+    memory effectively. Although independent parameters for real use are
+    only  2  (unitSize  and  nUnits),  BinSrchHeader  has  3  additional
+    parameters which can be  calculated  from  unitSize and  nUnits, for
+    fast setup.  Apple font tools ignore them silently, so gxvalid warns
+    inconsistency  and  always  continues  validation.   The  additional
+    parameters are ignored regardless of the consistency.
+
+    19 fonts include  inconsistent with calculated values
+       all breaks are in BinSrchHeader of "kern" table.
+
+    4-2. too-short LookupTable ( 5/183)
+    -----------------------------------
+    LookupTable  format 0 is simple array to get a value from given GID,
+    the  index  of  array  is  GID.  Therefore,  the  length of array is
+    expected to be same with max GID defined in "maxp" table,  but there
+    is  some fonts  whose LookupTable format 0 is too short to cover all
+    GID.  FontValidator ignores  this error  silently,  ftxvalidator and
+    ftxdumperfuser  warns  and continues.  Similar  shortage is found in
+    format 3 subtable of "kern".
+    gxvalid warns always and abort at FT_VALIDATE_PARANOID.
+
+      5 fonts include  too-short kern format 0 subtables.
+      1 font  includes too-short kern format 3 subtable.
+
+
+    4-3. broken LookupTable format 2 ( 1/183)
+    -----------------------------------------
+    LookupTable format 2, 4 covers GID  space  by collection of segments
+    which  specified  by  firstGlyph  and  lastGlyph.  Some fonts stores
+    firstGlyph and lastGlyph in reverse order,  so segment specification
+    is broken.  Apple  font tools ignores this  error  silently,  broken
+    segment is  ignored  as if it  did  not  exist.  gxvalid  warns  and
+    normalize the segment at FT_VALIDATE_DEFAULT,  or ignore the segment
+    at FT_VALIDATE_TIGHT, or abort at FT_VALIDATE_PARANOID.
+
+      1 font includes  broken LookupTable format 2, in "just" table.
+
+    *) It seems that  all fonts manufactured by  ITC for AppleWorks have
+       this error.
+
+
+    4-4. bad bracketing in glyph property ( 14/183)
+    -----------------------------------------------
+    GX/AAT defines bracketing property of the glyphs by "prop" table, to
+    control layout functionalities for string closed in brackets and out
+    of brackets.  Some fonts  give  inappropriate bracket properties  to
+    glyphs.  Apple font tools warn this error.  gxvalid warns always and
+    abort at FT_VALIDATE_PARANOID.
+
+     14 fonts include  wrong bracket properties.
+
+
+    4-5. invalid feature number (117/183)
+    -------------------------------------
+    GX/AAT extension can include 255 different features for layout,  but
+    popular layout features are predefined
+    (see http://developer.apple.com/fonts/Registry/index.html).
+    Some  fonts  include  feature  number  which  is  incompatible  with
+    predefined feature registry.
+
+    In our survey, there are 140 fonts including "feat" table.
+    a)  67 fonts uses feature number which should not be used.
+    b) 117 fonts set wrong feature range (nSetting).
+           this infraction is found in mort/morx.
+
+    Apple font tools gives no warning,  although  they  cannot recognize
+    what  the  feature  is.  At  FT_VALIDATE_DEFAULT,  gxvalid warns but
+    continues in both cases (a, b).  At FT_VALIDATE_TIGHT, gxvalid warns
+    and aborts for (a), but continues for (b).  At FT_VALIDATE_PARANOID,
+    gxvalid warns and aborts in both cases (a, b).
+
+    4-6. invalid prop version ( 10/183)
+    -----------------------------------
+    As  most  TrueType  GX  tables,  prop  table  must  start with 32bit
+    version: 0x00010000, 0x00020000 or 0x00030000.  But some fonts store
+    nonsense binary data  in it.  When Apple font tools find them,  they
+    abort  the processing at once,  and following  data  are  unhandled.
+    gxvalid does same always.
+
+      10 fonts include  broken prop version.
+
+    All  of  these  fonts  are  classic  TrueType  for  Japanese script,
+    manufactured by Apple.
+
+    4-7. unknown resource name (  2/183)
+    ------------------------------------
+    NOTE: THIS IS NOT TRUETYPE GX ERROR
+    When  TrueType font  is  stored  in  resource  fork or dfont format,
+    the data must be tagged as "sfnt" in resource fork index,  to invoke
+    TrueType font handler  for the data.  But  the TrueType font data in
+    "Keyboard.dfont" is tagged as "kbd", and that in  "LastResort.dfont"
+    is  tagged  as "lst".  Apple  font  tools  can detect the data is of
+    TrueType and successfully validate them.  Possibly this because they
+    are known  to be dfont.  Current  implementation  of  resource  fork
+    driver of FreeType cannot do that, thus gxvalid cannot validate them.
+
+       2 fonts use unknown tag for TrueType font resource.
+
+  5. "kern" table issue
+  ---------------------
+  In common terminology of TrueType,  "kern"  is classified to basic and
+  platform-independent  table.  But there are  Apple extensions of kern,
+  and  there  is  an  extension  which  requires  GX  state  machine for
+  contextual kerning.  Therefore,  gxvalid includes  validator for kern.
+  Unfortunately, there is no exact algorithm to check Apple's extension,
+  so gxvalid  includes pragmatic detector of  data format and  validator
+  for  all possible  data formats,  including data format for Microsoft.
+  By calling  classic_kern_validate() instead of gxv_validate(), you can
+  specify available "kern" format explicitly. However, current FreeType2
+  uses Microsoft "kern" format only, others are ignored.
+
+    5-1. History
+    ------------
+    Original 16bit version of "kern"  had been designed by Apple in pre-
+    GX era, and it was also approved by Microsoft. Afterwards, Apple has
+    designed new 32bit version "kern". Apple has noted as the difference
+    between  16bit and  32bit version  is only  the size of variables in
+    "kern" header.  In following,  we call the original 16bit version as
+    "classic", and 32bit version as "new".
+
+    5-2. Versions and dialects which should be discriminated
+    --------------------------------------------------------
+    The "kern" table consists of the table header and several subtables.
+    The version  "classic" or  "new" is explicitly written in  the table
+    header, but there are undocumented difference of font parser between
+    Microsoft and Apple. It is called as "dialect" in following.
+    There are 3 cases which should be discriminated:  new Apple-dialect,
+    classic Apple-dialect,  and classic Microsoft-dialect.  Analysis and
+    auto detection algorithm of gxvalid is described in following.
+
+      5-2-1. Version detection: classic and new kern
+      ----------------------------------------------
+      According   to   Apple  TrueType  specification,   the   clarified
+      difference between classic and new version are only 2:
+        - "kern" table header starts with the version number.
+          The classic version starts with 0x0000 (16bit),
+          the new version starts with 0x00010000 (32bit).
+        - In the "kern" table header, the number of subtables follows to
+          the version number.
+          In the classic version, it is stored in 16bit variable.
+          In the new version, it is stored in 32bit variable.
+
+      From Apple font tool's output (DumpKERN is also tested in addition
+      to 3 Apple font tools  in above),  there  is  another undocumented
+      difference.   In new version, the subtable header includes a 16bit
+      variable named  "tupleIndex"  which does not exist  in the classic
+      version.
+
+      New version can store all subtable formats (0,  1,  2 and  3), but
+      Apple  TrueType  specification  does not  mention  about  subtable
+      formats available in classic version.
+
+
+      5-2-2. Avaibale subtable format in classic version
+      --------------------------------------------------
+      Although  Apple  TrueType  specification recommends to use classic
+      version  in the case if the font is designed for both of Apple and
+      Microsoft platforms, it does not note about the available subtable
+      formats in classic version.
+
+      According to Microsoft TrueType specification, the subtable format
+      assured for Windows & OS/2 support is only subtable format 0. Also
+      Microsoft TrueType specification  describes the subtable format 2,
+      but  does not  mention  about  which  platforms support it.  About
+      subtable format 1,  3  and later  are noted as reserved for future
+      use.  Therefore,  the classic version can store subtable formats 0
+      and 2, at least.  ttfdump.exe,  a font tool provided  by Microsoft
+      ignores  the subtable format  written in the subtable header,  and
+      parse as if all subtables are in format 0.
+
+      kern subtable format 1 uses StateTable,  so  it cannot be utilized
+      without  GX State Machine.  Therefore,  it is reasonable to assume
+      format 1 (and 3) is introduced after  Apple have introduced GX and
+      moved to new 32bit version.
+
+      5-2-3. Apple and Microsoft dialects
+      -----------------------------------
+      The  kern  subtable  has  16bit  "coverage"  to  describe  kerning
+      attributions,  but bit-interpretations by  Apple and Microsoft are
+      reverse ordered:
+      e.g. Apple-dialect writes subtable format from 0x000F bit range,
+       Microsoft-dialect writes subtable format from 0x0F00 bit range).
+
+      In  addition,  from  the  outputs  of  DumpKERN and FontValidator,
+      Apple's bit-interpretations of coverage in classic and new version
+      are incompatible. In summary, there are 3 dialects: classic Apple-
+      dialect, classic Microsoft-dialect, and new Apple-dialect.
+      The classic Microsoft-dialect and new Apple-dialect are documented
+      by each vendors' TrueType font specification, but the document for
+      classic Apple-dialect had been lost.
+      
+      For example, in new Apple-dialect, the bit 0x8000 is documented as
+      "set to 1 when  the kerning is  vertical".  On the other hand,  in
+      classic Microsoft-dialect, the bit 0x0001 is documented as "set to
+      1 when the kerning is  horizontal".  From  the outputs of DumpKERN
+      and FontValidator, classic Apple-dialect recognizes the bit 0x8000
+      as "set to 1 when the kerning is horizontal".  From the results of
+      similar experiments, classic Apple-dialect is ein ndian-reverse of
+      classic Microsoft-dialect.
+
+      It must be noted:  no font tool can sense classic Apple-dialect or
+      classic-Microsoft dialect automatically.
+
+      5-2-4. gxvalid auto dialect detection algorithm
+      -----------------------------------------------
+      The  first  16bit  of kern table is enough to sense the version:
+        - if first 16bit is 0x0000,
+          kern table is in classic Apple-dialect
+                        or classic Microsoft-dialect,
+        - if first 16bit is 0x0001, and next 16bit is 0x0000,
+          kern table is in new Apple-dialect. 
+      If kern table is classic version, 16bit coverage is checked for in
+      next. For first,  the coverage is decoded by classic Apple-dialect
+      as following  (it is based on DumpKERN output):
+        0x8000: 1=horizontal, 0=vertical
+        0x4000: not used
+        0x2000: 1=cross-stream, 0=normal
+        0x1FF0: reserved
+        0x000F: subtable format
+      If   any   of   reserved  bits  are  set  or  subtable  format  is
+      interpreted  as 1 or 3,  we  take it  as  "impossible in classic
+      Apple-dialect", and retry by classic Microsoft-dialect.
+        The most popular coverage in new Apple-dialect:         0x8000,
+        The most popular coverage in classic Apple-dialect:     0x0000,
+        The most popular coverage in classic Microsoft dialect: 0x0001.
+
+    5-3. Tested fonts
+    -----------------
+    We  checked  59  fonts  bundled  to  MacOS  which includes kern, and
+    38 fonts bundled to Windows which includes kern.
+      - fonts bundled to MacOS
+        * new Apple-dialect
+          format 0: 18
+          format 2:  1
+          format 3:  1
+        * classic Apple-dialect
+          format 0: 14
+        * classic Microsoft-dialect
+          format 0: 15
+      - fonts bundled to Windows
+        * classic Microsoft-dialect
+          format 0: 38
+    It looks strange that classic Microsoft-dialect fonts are bundled to
+    MacOS: they come from MSIE for MacOS, except of MarkerFelt.dfont.
+
+
+  ACKNOWLEDGEMENT
+  ---------------
+  Some part of gxvalid is derived from both gxlayout module and otvalid
+  module. Development of gxlayout was support of Information-technology
+  Promotion Agency(IPA), Japan.
+
+  The detailed analysis of undefined glyph ID utilization in mort, morx
+  is provided by George Williams.
+
+------------------------------------------------------------------------
+
+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.
+
+
+--- end of README ---
--- /dev/null
+++ b/src/gxvalid/gxvalid.c
@@ -1,0 +1,46 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvalid.c                                                              */
+/*                                                                         */
+/*    FreeType validator for TrueTypeGX/AAT tables (body only).            */
+/*                                                                         */
+/*  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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+
+#include "gxvfeat.c"
+#include "gxvcommn.c"
+#include "gxvbsln.c"
+#include "gxvtrak.c"
+#include "gxvjust.c"
+#include "gxvmort.c"
+#include "gxvmort0.c"
+#include "gxvmort1.c"
+#include "gxvmort2.c"
+#include "gxvmort4.c"
+#include "gxvmort5.c"
+#include "gxvmorx.c"
+#include "gxvmorx0.c"
+#include "gxvmorx1.c"
+#include "gxvmorx2.c"
+#include "gxvmorx4.c"
+#include "gxvmorx5.c"
+#include "gxvkern.c"
+#include "gxvopbd.c"
+#include "gxvprop.c"
+#include "gxvlcar.c"
+#include "gxvmod.c"
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvalid.h
@@ -1,0 +1,106 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvalid.h                                                              */
+/*                                                                         */
+/*    TrueTyeeGX/AAT table validation (specification only).                */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#ifndef __GXVALID_H__
+#define __GXVALID_H__
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+#include "gxverror.h"          /* must come before FT_INTERNAL_VALIDATE_H */
+
+#include FT_INTERNAL_VALIDATE_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_LOCAL( void )
+  gxv_feat_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+
+  FT_LOCAL( void )
+  gxv_bsln_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+
+  FT_LOCAL( void )
+  gxv_trak_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_just_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_morx_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_kern_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_kern_validate_classic
+                   ( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Int        dialect_flags,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_opbd_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_prop_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_lcar_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  valid );
+
+
+FT_END_HEADER
+
+
+#endif /* __GXVALID_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvbsln.c
@@ -1,0 +1,326 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvbsln.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT bsln 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 was support of 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_gxvbsln
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      Data and Types                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define GXV_BSLN_VALUE_COUNT 32
+#define GXV_BSLN_VALUE_EMPTY 0xFFFF
+
+  typedef struct  GXV_bsln_DataRec_
+  {
+    FT_Bytes   ctlPoints_p;
+    FT_UShort  defaultBaseline;
+
+  } GXV_bsln_DataRec, *GXV_bsln_Data;
+#define GXV_BSLN_DATA(field)  GXV_TABLE_DATA( bsln, field )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  gxv_bsln_LookupValue_validate( FT_UShort            glyph,
+                                 GXV_LookupValueDesc  value,
+                                 GXV_Validator        valid )
+  {
+    FT_UShort   v  = value.u;
+    FT_UShort*  ctlPoints;
+
+
+    GXV_NAME_ENTER( " lookup value" );
+
+    if ( v >= GXV_BSLN_VALUE_COUNT )
+      FT_INVALID_DATA;
+
+
+    ctlPoints = (FT_UShort*)GXV_BSLN_DATA( ctlPoints_p );
+    if ( ctlPoints && ctlPoints[v] == GXV_BSLN_VALUE_EMPTY )
+      FT_INVALID_DATA;
+
+    GXV_EXIT;
+  }
+
+
+  /*
+    +===============+ --------+
+    | 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_bsln_LookupFmt4_transit( FT_UShort            relative_gindex,
+                               GXV_LookupValueDesc  base_value,
+                               FT_Bytes             lookuptbl_limit,
+                               GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+    offset = base_value.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;
+  }
+
+  static void
+  gxv_bsln_parts_fmt0_validate( FT_Bytes       tables,
+                                FT_Bytes       limit,
+                                GXV_Validator  valid )
+  {
+    FT_Bytes  p = tables;
+
+
+    GXV_NAME_ENTER( "parts format 0" );
+
+    /* deltas */
+    GXV_LIMIT_CHECK( 2 * GXV_BSLN_VALUE_COUNT );
+
+    valid->table_data = NULL;      /* No ctlPoints here. */
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_bsln_parts_fmt1_validate( FT_Bytes       tables,
+                                FT_Bytes       limit,
+                                GXV_Validator  valid )
+  {
+    FT_Bytes  p = tables;
+
+    GXV_NAME_ENTER( " parts format 1" );
+
+    /* deltas */
+    gxv_bsln_parts_fmt0_validate( p, limit, valid );
+
+    /* mappingData */
+    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func   = gxv_bsln_LookupValue_validate;
+    valid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit;
+    gxv_LookupTable_validate( p + 2 * GXV_BSLN_VALUE_COUNT,
+                              limit,
+                              valid );
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_bsln_parts_fmt2_validate( FT_Bytes       tables,
+                                FT_Bytes       limit,
+                                GXV_Validator  valid )
+  {
+    FT_Bytes      p = tables;
+
+    FT_UShort     stdGlyph;
+    FT_UShort     ctlPoint;
+    FT_Int        i;
+
+    FT_UShort     defaultBaseline = GXV_BSLN_DATA( defaultBaseline );
+
+
+    GXV_NAME_ENTER( "parts format 2" );
+
+    GXV_LIMIT_CHECK( 2 + ( 2 * GXV_BSLN_VALUE_COUNT ) );
+
+    /* stdGlyph */
+    stdGlyph = FT_NEXT_USHORT( p );
+    GXV_TRACE(( " (stdGlyph = %u)\n", stdGlyph ));
+
+    gxv_glyphid_validate( stdGlyph, valid );
+
+    /* Record the position of ctlPoints */
+    GXV_BSLN_DATA( ctlPoints_p) = p;
+
+    /* ctlPoints */
+    for ( i = 0; i < GXV_BSLN_VALUE_COUNT; i++ )
+    {
+      ctlPoint = FT_NEXT_USHORT( p );
+      if ( ctlPoint == GXV_BSLN_VALUE_EMPTY )
+      {
+        if ( i == defaultBaseline )
+          FT_INVALID_DATA;
+      }
+      else
+      {
+        gxv_ctlPoint_validate( stdGlyph, (FT_Short)ctlPoint, valid );
+      }
+    }
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_bsln_parts_fmt3_validate( FT_Bytes       tables,
+                                FT_Bytes       limit,
+                                GXV_Validator  valid)
+  {
+    FT_Bytes  p = tables;
+
+
+    GXV_NAME_ENTER( "parts format 3" );
+
+    /* stdGlyph + ctlPoints */
+    gxv_bsln_parts_fmt2_validate( p, limit, valid );
+
+    /* mappingData */
+    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func   = gxv_bsln_LookupValue_validate;
+    valid->lookupfmt4_trans = gxv_bsln_LookupFmt4_transit;
+    gxv_LookupTable_validate( p + ( 2 + 2 * GXV_BSLN_VALUE_COUNT ),
+                              limit,
+                              valid );
+
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         bsln TABLE                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  gxv_bsln_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  ftvalid )
+  {
+    GXV_ValidatorRec   validrec;
+    GXV_Validator      valid = &validrec;
+
+    GXV_bsln_DataRec   bslnrec;
+    GXV_bsln_Data      bsln = &bslnrec;
+
+    FT_Bytes  p = table;
+    FT_Bytes  limit = 0;
+
+    FT_ULong   version;
+    FT_UShort  format;
+    FT_UShort  defaultBaseline;
+
+    GXV_Validate_Func  fmt_funcs_table [] =
+    {
+      gxv_bsln_parts_fmt0_validate,
+      gxv_bsln_parts_fmt1_validate,
+      gxv_bsln_parts_fmt2_validate,
+      gxv_bsln_parts_fmt3_validate,
+    };
+
+
+    valid->root       = ftvalid;
+    valid->table_data = bsln;
+    valid->face       = face;
+
+    FT_TRACE3(( "validation bsln table\n" ));
+    GXV_INIT;
+
+
+    GXV_LIMIT_CHECK( 4 + 2 + 2 );
+    version         = FT_NEXT_ULONG( p );
+    format          = FT_NEXT_USHORT( p );
+    defaultBaseline = FT_NEXT_USHORT( p );
+
+    /* version 1.0 is only defined (1996) */
+    if ( version != 0x00010000UL )
+      FT_INVALID_FORMAT;
+
+    /* format 1, 2, 3 are only defined (1996) */
+    GXV_TRACE(( " (format = %d)\n", format ));
+    if ( format > 3 )
+      FT_INVALID_FORMAT;
+
+    if ( defaultBaseline > 31 )
+      FT_INVALID_FORMAT;
+
+
+    bsln->defaultBaseline = defaultBaseline;
+
+    fmt_funcs_table[format]( p, limit, valid );
+
+    FT_TRACE4(( "\n" ));
+  }
+
+/* arch-tag: ebe81143-fdaa-4c68-a4d1-b57227daa3bc
+   (do not change this comment) */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvcommn.c
@@ -1,0 +1,1735 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvcommn.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT common tables 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#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_gxvcommon
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       16bit offset sorter                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static int
+  gxv_compare_ushort_offset( FT_UShort*  a,
+                             FT_UShort*  b )
+  {
+    if ( *a < *b )
+      return ( -1 );
+    else if ( *a > *b )
+      return ( 1 );
+    else
+      return ( 0 );
+  }
+
+
+  static void
+  gxv_set_length_by_ushort_offset( FT_UShort*     offset,
+                                   FT_UShort**    length,
+                                   FT_UShort*     buff,
+                                   FT_UInt        nmemb,
+                                   FT_UShort      limit,
+                                   GXV_Validator  valid)
+  {
+    FT_UInt    i;
+
+
+    for ( i = 0; i < nmemb; i++ )
+      *(length[i]) = 0;
+
+    for ( i = 0; i < nmemb; i++ )
+      buff[i] = offset[i];
+    buff[nmemb] = limit;
+
+    ft_qsort( buff, ( nmemb + 1 ), sizeof(FT_UShort),
+              ( int(*)(const void*, const void*) )gxv_compare_ushort_offset );
+
+    if ( buff[nmemb] > limit )
+      FT_INVALID_OFFSET;
+
+    for ( i = 0; i < nmemb; i++ )
+    {
+      FT_UInt j;
+
+
+      for ( j = 0; j < nmemb; j++ )
+        if ( buff[j] == offset[i] )
+          break;
+
+      if (j == nmemb)
+        FT_INVALID_OFFSET;
+
+      *(length[i]) = buff[j + 1] - buff[j];
+
+      if ( 0 != offset[i] && 0 == *(length[i]) )
+        FT_INVALID_OFFSET;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       32bit offset sorter                     *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static int
+  gxv_compare_ulong_offset( FT_ULong*  a,
+                            FT_ULong*  b )
+  {
+    if ( *a < *b )
+      return ( -1 );
+    else if ( *a > *b )
+      return ( 1 );
+    else
+      return ( 0 );
+  }
+
+
+  static void
+  gxv_set_length_by_ulong_offset( FT_ULong*      offset,
+                                  FT_ULong**     length,
+                                  FT_ULong*      buff,
+                                  FT_UInt        nmemb,
+                                  FT_ULong       limit,
+                                  GXV_Validator  valid)
+  {
+    FT_UInt    i;
+
+
+    for ( i = 0; i < nmemb; i++ )
+      *(length[i]) = 0;
+
+    for ( i = 0; i < nmemb; i++ )
+      buff[i] = offset[i];
+    buff[nmemb] = limit;
+
+    ft_qsort( buff, ( nmemb + 1 ), sizeof(FT_ULong),
+              ( int(*)(const void*, const void*) )gxv_compare_ulong_offset );
+
+    if ( buff[nmemb] > limit )
+      FT_INVALID_OFFSET;
+
+    for ( i = 0; i < nmemb; i++ )
+    {
+      FT_UInt j;
+
+
+      for ( j = 0; j < nmemb; j++ )
+        if ( buff[j] == offset[i] )
+          break;
+
+      if (j == nmemb)
+        FT_INVALID_OFFSET;
+
+      *(length[i]) = buff[j + 1] - buff[j];
+
+      if ( 0 != offset[i] && 0 == *(length[i]) )
+        FT_INVALID_OFFSET;
+    }
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****               scan value array and get min & max              *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static void
+  gxv_array_getlimits_byte( FT_Bytes       table,
+                            FT_Bytes       limit,
+                            FT_Byte*       min,
+                            FT_Byte*       max,
+                            GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    *min = 0xFF;
+    *max = 0x00;
+
+    while ( p < limit )
+    {
+      FT_Byte  val;
+
+      GXV_LIMIT_CHECK( 1 );
+      val = FT_NEXT_BYTE( p );
+
+      *min = FT_MIN( *min, val );
+      *max = FT_MAX( *max, val );
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  static void
+  gxv_array_getlimits_ushort( FT_Bytes       table,
+                              FT_Bytes       limit,
+                              FT_UShort*     min,
+                              FT_UShort*     max,
+                              GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    *min = 0xFFFF;
+    *max = 0x0000;
+
+    while ( p < limit )
+    {
+      FT_UShort  val;
+
+      GXV_LIMIT_CHECK( 2 );
+      val = FT_NEXT_USHORT( p );
+
+      *min = FT_MIN( *min, val );
+      *max = FT_MAX( *max, val );
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                       BINSEARCHHEADER                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct GXV_BinSrchHeader_
+  {
+    FT_UShort unitSize;
+    FT_UShort nUnits;
+    FT_UShort searchRange;
+    FT_UShort entrySelector;
+    FT_UShort rangeShift;
+
+  } GXV_BinSrchHeader;
+
+
+  static void
+  gxv_BinSrchHeader_check_consistency( GXV_BinSrchHeader*  binSrchHeader,
+                                       GXV_Validator       valid )
+  {
+    FT_UShort searchRange;
+    FT_UShort entrySelector;
+    FT_UShort rangeShift;
+
+
+    if ( binSrchHeader->unitSize == 0 )
+      FT_INVALID_DATA;
+
+    if ( binSrchHeader->nUnits == 0 )
+    {
+      if ( binSrchHeader->searchRange   == 0 &&
+           binSrchHeader->entrySelector == 0 &&
+           binSrchHeader->rangeShift    == 0 )
+      {
+        return;
+      }
+      else
+      {
+        FT_INVALID_DATA;
+      }
+    }
+
+    for ( searchRange = 1, entrySelector = 1;
+          ( searchRange * 2 ) <= binSrchHeader->nUnits && searchRange < 0x8000;
+          searchRange *= 2, entrySelector++ )
+      ;
+
+    entrySelector --;
+    searchRange *= ( binSrchHeader->unitSize );
+    rangeShift   = ( binSrchHeader->nUnits ) * ( binSrchHeader->unitSize )
+                   - searchRange;
+
+
+    if ( searchRange   != binSrchHeader->searchRange   ||
+         entrySelector != binSrchHeader->entrySelector ||
+         rangeShift    != binSrchHeader->rangeShift    )
+    {
+      GXV_TRACE(( "Inconsistency found in BinSrchHeader\n" ));
+      GXV_TRACE(( "originally: unitSize=%d, nUnits=%d, "
+                  "searchRange=%d, entrySelector=%d, "
+                  "rangeShift=%d\n",
+                  binSrchHeader->unitSize, binSrchHeader->nUnits,
+                  binSrchHeader->searchRange, binSrchHeader->entrySelector,
+                  binSrchHeader->rangeShift ));
+      GXV_TRACE(( "calculated: unitSize=%d, nUnits=%d, "
+                  "searchRange=%d, entrySelector=%d, "
+                  "rangeShift=%d\n",
+                  binSrchHeader->unitSize, binSrchHeader->nUnits,
+                  searchRange, entrySelector, rangeShift ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+    }
+  }
+
+
+  /*
+   * parser & validator of BinSrchHeader
+   * which is used in LookupTable format 2, 4, 6.
+   *
+   * Essential parameters (unitSize, nUnits) are returned by
+   * given pointer, others (searchRange, entrySelector, rangeShift)
+   * can be calculated essential parameters, so they are just
+   * validated and discarded.
+   *
+   * However, wrong values in searchRange, entrySelector, rangeShift
+   * won't cause fatal errors, because these parameters might be
+   * only used in old m68k font driver in MacOS.
+   *   -- suzuki toshiya <[email protected]>
+   */
+
+
+  FT_LOCAL_DEF( void )
+  gxv_BinSrchHeader_validate( FT_Bytes       table,
+                              FT_Bytes       limit,
+                              FT_UShort*     unitSize_p,
+                              FT_UShort*     nUnits_p,
+                              GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    GXV_BinSrchHeader  binSrchHeader;
+
+
+    GXV_NAME_ENTER( "BinSrchHeader validate" );
+
+    if ( *unitSize_p == 0 )
+    {
+      GXV_LIMIT_CHECK( 2 );
+      binSrchHeader.unitSize =  FT_NEXT_USHORT( p );
+    }
+    else
+      binSrchHeader.unitSize = *unitSize_p;
+
+    if ( *nUnits_p == 0)
+    {
+      GXV_LIMIT_CHECK( 2 );
+      binSrchHeader.nUnits = FT_NEXT_USHORT( p );
+    }
+    else
+      binSrchHeader.nUnits = *nUnits_p;
+
+    GXV_LIMIT_CHECK( 2 + 2 + 2 );
+    binSrchHeader.searchRange   = FT_NEXT_USHORT( p );
+    binSrchHeader.entrySelector = FT_NEXT_USHORT( p );
+    binSrchHeader.rangeShift    = FT_NEXT_USHORT( p );
+    GXV_TRACE(( "nUnits %d\n", binSrchHeader.nUnits ));
+
+    gxv_BinSrchHeader_check_consistency( &binSrchHeader, valid );
+
+    if ( *unitSize_p == 0 )
+      *unitSize_p = binSrchHeader.unitSize;
+
+    if ( *nUnits_p == 0 )
+      *nUnits_p   = binSrchHeader.nUnits;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         LOOKUP TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define GXV_LOOKUP_VALUE_LOAD(P, SIGNSPEC) \
+  ( P += 2, gxv_lookup_value_load( P - 2, SIGNSPEC ) )
+
+  static GXV_LookupValueDesc
+  gxv_lookup_value_load( FT_Bytes  p,
+                         int       signspec )
+  {
+    GXV_LookupValueDesc v;
+
+
+    if ( signspec == GXV_LOOKUPVALUE_UNSIGNED )
+      v.u = FT_NEXT_USHORT( p );
+    else
+      v.s = FT_NEXT_SHORT( p );
+
+    return v;
+  }
+
+#define GXV_UNITSIZE_VALIDATE( FORMAT, UNITSIZE, NUNITS, CORRECTSIZE ) \
+          FT_BEGIN_STMNT                                     \
+            if ( UNITSIZE != CORRECTSIZE )                   \
+            {                                                \
+              FT_ERROR(( "unitSize=%d differs from"          \
+                         "expected unitSize=%d"              \
+                         "in LookupTable %s",                \
+                          UNITSIZE, CORRECTSIZE, FORMAT ));  \
+              if ( UNITSIZE != 0 && NUNITS != 0 )            \
+              {                                              \
+                FT_ERROR(( " cannot validate anymore\n" ));  \
+                FT_INVALID_FORMAT;                           \
+              }                                              \
+              else                                           \
+                FT_ERROR(( " forcibly continues\n" ));       \
+            }                                                \
+          FT_END_STMNT
+
+
+  /* ================= Simple Array Format 0 Lookup Table ================= */
+  static void
+  gxv_LookupTable_fmt0_validate( FT_Bytes       table,
+                                 FT_Bytes       limit,
+                                 GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  i;
+
+    GXV_LookupValueDesc  value;
+
+
+    GXV_NAME_ENTER( " LookupTable format 0" );
+
+    GXV_LIMIT_CHECK( 2 * valid->face->num_glyphs );
+
+    for ( i = 0; i < valid->face->num_glyphs; i++ )
+    {
+      GXV_LIMIT_CHECK( 2 );
+      if ( p + 2 >= limit ) /* some fonts has too-short fmt0 array */
+      {
+        GXV_TRACE(( "too-short, glyph %d - %d are missing\n",
+                     i, valid->face->num_glyphs ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+        break;
+      }
+      value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
+      valid->lookupval_func( i, value, valid );
+    }
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  /* ================= Segment Single Format 2 Loolup Table =============== */
+  /*
+   * Apple spec says: To guarantee that a binary search terminates,
+   *   you must include one or more special "end of search table" values
+   *   at the end of the data to be searched. The number of termination
+   *   values that need to be included is table-specific. The value
+   *   that indicates binary search termination is 0xFFFF.
+   * The problem is that nUnits does not include this end-marker.
+   * It's quite difficult to discriminate following 0xFFFF comes from
+   * the end-marker or some next data.
+   *   -- suzuki toshiya <[email protected]>
+   */
+  static void
+  gxv_LookupTable_fmt2_skip_endmarkers( FT_Bytes       table,
+                                        FT_UShort      unitSize,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    while ( ( p + 4 ) < valid->root->limit )
+    {
+      if ( p[0] != 0xFF || p[1] != 0xFF || /* lastGlyph */
+           p[2] != 0xFF || p[3] != 0xFF )  /* firstGlyph */
+      {
+        break;
+      }
+      p += unitSize;
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+  static void
+  gxv_LookupTable_fmt2_validate( FT_Bytes       table,
+                                 FT_Bytes       limit,
+                                 GXV_Validator  valid )
+  {
+    FT_Bytes             p = table;
+    FT_UShort            gid;
+
+    FT_UShort            unitSize;
+    FT_UShort            nUnits;
+    FT_UShort            unit;
+    FT_UShort            lastGlyph;
+    FT_UShort            firstGlyph;
+    GXV_LookupValueDesc  value;
+
+
+    GXV_NAME_ENTER( " LookupTable format 2" );
+
+    unitSize = nUnits = 0;
+    gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
+    p += valid->subtable_length;
+
+    GXV_UNITSIZE_VALIDATE( "format2", unitSize, nUnits, 6 );
+
+
+    for ( unit = 0, gid = 0; unit < nUnits; unit++ )
+    {
+      GXV_LIMIT_CHECK( 2 + 2 + 2 );
+      lastGlyph  = FT_NEXT_USHORT( p );
+      firstGlyph = FT_NEXT_USHORT( p );
+      value      = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
+
+      gxv_glyphid_validate( firstGlyph, valid );
+      gxv_glyphid_validate( lastGlyph, valid );
+
+
+      if ( lastGlyph < gid )
+      {
+        GXV_TRACE(( "reverse ordered segment specification:"
+                    " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
+                     unit, lastGlyph, unit - 1 , gid ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+      }
+
+
+      if ( lastGlyph < firstGlyph )
+      {
+        GXV_TRACE(( "reverse ordered range specification at unit %d:",
+                    " lastGlyph %d < firstGlyph %d ",
+                      unit, lastGlyph, firstGlyph ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+
+        if ( valid->root->level == FT_VALIDATE_TIGHT )
+          continue; /* ftxvalidator silently skips such entry */
+
+        FT_TRACE4(( "continue with exchange\n" ));
+        gid        = firstGlyph;
+        firstGlyph = lastGlyph;
+        lastGlyph  = gid;
+      }
+
+
+      for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
+        valid->lookupval_func( gid, value, valid );
+    }
+
+    gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
+    p += valid->subtable_length;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  /* ================= Segment Array Format 4 Lookup Table ================ */
+  static void
+  gxv_LookupTable_fmt4_validate( FT_Bytes       table,
+                                 FT_Bytes       limit,
+                                 GXV_Validator  valid )
+  {
+    FT_Bytes             p = table;
+    FT_UShort            unit;
+    FT_UShort            gid;
+
+    FT_UShort            unitSize;
+    FT_UShort            nUnits;
+    FT_UShort            lastGlyph;
+    FT_UShort            firstGlyph;
+    GXV_LookupValueDesc  base_value;
+    GXV_LookupValueDesc  value;
+
+
+    GXV_NAME_ENTER( " LookupTable format 4" );
+
+    unitSize = nUnits = 0;
+    gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
+    p += valid->subtable_length;
+
+    GXV_UNITSIZE_VALIDATE( "format4", unitSize, nUnits, 6 );
+
+    for ( unit = 0, gid = 0; unit < nUnits; unit++ )
+    {
+      GXV_LIMIT_CHECK( 2 + 2 );
+      lastGlyph  = FT_NEXT_USHORT( p );
+      firstGlyph = FT_NEXT_USHORT( p );
+
+      gxv_glyphid_validate( firstGlyph, valid );
+      gxv_glyphid_validate( lastGlyph, valid );
+
+
+      if ( lastGlyph < gid )
+      {
+        GXV_TRACE(( "reverse ordered segment specification:"
+                    " lastGlyph[%d]=%d < lastGlyph[%d]=%d\n",
+                     unit, lastGlyph, unit - 1 , gid ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+      }
+
+
+      if ( lastGlyph < firstGlyph )
+      {
+        GXV_TRACE(( "reverse ordered range specification at unit %d:",
+                    " lastGlyph %d < firstGlyph %d ",
+                      unit, lastGlyph, firstGlyph ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+
+        if ( valid->root->level == FT_VALIDATE_TIGHT )
+          continue; /* ftxvalidator silently skips such entry */
+
+        FT_TRACE4(( "continue with exchange\n" ));
+        gid        = firstGlyph;
+        firstGlyph = lastGlyph;
+        lastGlyph  = gid;
+      }
+
+
+      GXV_LIMIT_CHECK( 2 );
+      base_value = GXV_LOOKUP_VALUE_LOAD( p, GXV_LOOKUPVALUE_UNSIGNED );
+
+      for ( gid = firstGlyph; gid <= lastGlyph; gid++ )
+      {
+        value = valid->lookupfmt4_trans( gid - firstGlyph, base_value,
+                                         limit, valid );
+        valid->lookupval_func( gid, value, valid );
+      }
+    }
+
+    gxv_LookupTable_fmt2_skip_endmarkers( p, unitSize, valid );
+    p += valid->subtable_length;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  /* ================= Segment Table Format 6 Lookup Table ================ */
+  static void
+  gxv_LookupTable_fmt6_skip_endmarkers( FT_Bytes       table,
+                                        FT_UShort      unitSize,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    while ( p < valid->root->limit )
+    {
+      if ( p[0] != 0xFF || p[1] != 0xFF )
+        break;
+      p += unitSize;
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+  static void
+  gxv_LookupTable_fmt6_validate( FT_Bytes       table,
+                                 FT_Bytes       limit,
+                                 GXV_Validator  valid )
+  {
+    FT_Bytes             p = table;
+    FT_UShort            unit;
+    FT_UShort            prev_glyph;
+
+    FT_UShort            unitSize;
+    FT_UShort            nUnits;
+    FT_UShort            glyph;
+    GXV_LookupValueDesc  value;
+
+
+    GXV_NAME_ENTER( " LookupTable format 6" );
+
+    unitSize = nUnits = 0;
+    gxv_BinSrchHeader_validate( p, limit, &unitSize, &nUnits, valid );
+    p += valid->subtable_length;
+
+    GXV_UNITSIZE_VALIDATE( "format6", unitSize, nUnits, 4 );
+
+    for ( unit = 0, prev_glyph = 0; unit < nUnits; unit++ )
+    {
+      GXV_LIMIT_CHECK( 2 + 2 );
+      glyph = FT_NEXT_USHORT( p );
+      value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
+
+
+      if ( gxv_glyphid_validate( glyph, valid ) )
+        GXV_TRACE(( " endmarker found within defined range"
+                    " (entry %d < nUnits=%d)\n",
+                    unit, nUnits ));
+
+      if ( prev_glyph > glyph )
+      {
+        GXV_TRACE(( "current gid 0x%04x < previous gid 0x%04x\n",
+                     glyph, prev_glyph ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+      }
+      prev_glyph = glyph;
+
+
+      valid->lookupval_func( glyph, value, valid );
+    }
+
+    gxv_LookupTable_fmt6_skip_endmarkers( p, unitSize, valid );
+    p += valid->subtable_length;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  /* ================= Trimmed Array Format 8 Lookup Table ================ */
+  static void
+  gxv_LookupTable_fmt8_validate( FT_Bytes       table,
+                                 FT_Bytes       limit,
+                                 GXV_Validator  valid )
+  {
+    FT_Bytes              p = table;
+    FT_UShort             i;
+
+    GXV_LookupValueDesc   value;
+    FT_UShort             firstGlyph;
+    FT_UShort             glyphCount;
+
+
+    GXV_NAME_ENTER( " LookupTable format 8" );
+
+    /* firstGlyph + glyphCount */
+    GXV_LIMIT_CHECK( 2 + 2 );
+    firstGlyph = FT_NEXT_USHORT( p );
+    glyphCount = FT_NEXT_USHORT( p );
+
+    gxv_glyphid_validate( firstGlyph, valid );
+    gxv_glyphid_validate( firstGlyph + glyphCount, valid );
+
+    /* valueArray */
+    for ( i = 0; i < glyphCount; i++ )
+    {
+      GXV_LIMIT_CHECK( 2 );
+      value = GXV_LOOKUP_VALUE_LOAD( p, valid->lookupval_sign );
+      valid->lookupval_func( firstGlyph + i, value, valid );
+    }
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  gxv_LookupTable_validate( FT_Bytes       table,
+                            FT_Bytes       limit,
+                            GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UShort format;
+
+    GXV_Validate_Func fmt_funcs_table [] =
+    {
+      gxv_LookupTable_fmt0_validate, /* 0 */
+      NULL,                          /* 1 */
+      gxv_LookupTable_fmt2_validate, /* 2 */
+      NULL,                          /* 3 */
+      gxv_LookupTable_fmt4_validate, /* 4 */
+      NULL,                          /* 5 */
+      gxv_LookupTable_fmt6_validate, /* 6 */
+      NULL,                          /* 7 */
+      gxv_LookupTable_fmt8_validate, /* 8 */
+    };
+    GXV_Validate_Func func;
+
+
+    GXV_NAME_ENTER(" LookupTable" );
+
+    /* lookuptbl_head may be used in fmt4 transit function. */
+    valid->lookuptbl_head = table;
+
+    /* format */
+    GXV_LIMIT_CHECK( 2 );
+    format = FT_NEXT_USHORT( p );
+    GXV_TRACE(( " (format %d)\n", format ));
+
+    if ( format > 8 )
+      FT_INVALID_FORMAT;
+
+    func = fmt_funcs_table[format];
+    if ( func == NULL )
+      FT_INVALID_FORMAT;
+
+    func( p, limit, valid );
+    p += valid->subtable_length;
+
+    valid->subtable_length = ( p - table );
+
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          Glyph ID                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( FT_Int )
+  gxv_glyphid_validate( FT_UShort      gid,
+                        GXV_Validator  valid )
+  {
+    FT_Face       face;
+
+
+    if ( gid == 0xFFFF )
+    {
+      GXV_EXIT;
+      return 1;
+    }
+
+    face = valid->face;
+    if ( face->num_glyphs < gid )
+    {
+      GXV_TRACE(( " gxv_glyphid_check() gid overflow: num_glyphs %d < %d\n",
+                   face->num_glyphs, gid ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_GLYPH_ID;
+    }
+
+    return 0;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        CONTROL POINT                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  gxv_ctlPoint_validate( FT_UShort      gid,
+                         FT_Short       ctl_point,
+                         GXV_Validator  valid )
+  {
+    FT_Face       face;
+    FT_Error      error;
+
+    FT_GlyphSlot  glyph;
+    FT_Outline    outline;
+    short         n_points;
+
+
+    face = valid->face;
+
+    error = FT_Load_Glyph( face,
+                           gid,
+                           FT_LOAD_NO_BITMAP|FT_LOAD_IGNORE_TRANSFORM );
+    if ( error )
+      FT_INVALID_GLYPH_ID;
+
+    glyph    = face->glyph;
+    outline  = glyph->outline;
+    n_points = outline.n_points;
+
+
+    if ( !( ctl_point < n_points ) )
+      FT_INVALID_DATA;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          SFNT NAME                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  gxv_sfntName_validate( FT_UShort      name_index,
+                         FT_UShort      min_index,
+                         FT_UShort      max_index,
+                         GXV_Validator  valid )
+  {
+    FT_SfntName  name;
+    FT_Int       i;
+    FT_UInt      nnames;
+
+
+    GXV_NAME_ENTER( "sfntName" );
+
+    if ( name_index < min_index || max_index < name_index )
+      FT_INVALID_FORMAT;
+
+    nnames = FT_Get_Sfnt_Name_Count (valid->face);
+    for ( i = 0; i < nnames; i++ )
+    {
+      if ( FT_Get_Sfnt_Name( valid->face, i, &name ) != FT_Err_Ok )
+        continue ;
+
+      if ( name.name_id == name_index )
+        goto Out;
+    }
+
+    GXV_TRACE(( "  nameIndex = %d (UNTITLED)\n", name_index ));
+    FT_INVALID_DATA;
+
+  Out:
+    FT_TRACE1(( "  nameIndex = %d (", name_index ));
+    GXV_TRACE_HEXDUMP_SFNTNAME( name );
+    FT_TRACE1(( ")\n" ));
+
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          STATE TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* -------------------------- Class Table --------------------------- */
+
+  /*
+   * highestClass is used to notice how many class are defined in this
+   * Class Subtable. Apple spec does not mention about whether undefined
+   * hole in the class (e.g.: 0-3 are predefined, 4 is unused, 5 is used)
+   * is permitted. At present, hole in defined class is not checked.
+   *   -- suzuki toshiya <[email protected]>
+   */
+
+  static void
+  gxv_ClassTable_validate( FT_Bytes       table,
+                           FT_UShort*     length_p,
+                           FT_UShort      stateSize,
+                           FT_Byte*       maxClassID_p,
+                           GXV_Validator  valid )
+  {
+    FT_Bytes  p     = table;
+    FT_Bytes  limit = table + *length_p;
+    FT_UShort firstGlyph;
+    FT_UShort nGlyphs;
+
+
+    GXV_NAME_ENTER( "ClassTable" );
+
+    *maxClassID_p = 3;  /* Class 0,2,3 are predefined */
+
+    GXV_LIMIT_CHECK( 2 + 2 );
+    firstGlyph = FT_NEXT_USHORT( p );
+    nGlyphs    = FT_NEXT_USHORT( p );
+
+    GXV_TRACE(( " (firstGlyph = %d, nGlyphs = %d)\n", firstGlyph, nGlyphs ));
+
+    if ( !nGlyphs )
+      goto Out;
+
+    gxv_glyphid_validate( firstGlyph + nGlyphs, valid );
+
+    {
+      FT_Byte    nGlyphInClass[256];
+      FT_Byte    classID;
+      FT_UShort  i;
+
+
+      ft_memset( nGlyphInClass, 0, 256 );
+
+
+      for ( i = 0; i < nGlyphs; i++ )
+      {
+        GXV_LIMIT_CHECK( 1 );
+        classID = FT_NEXT_BYTE( p );
+        switch ( classID )
+        {
+          /* following class should not be appear in class array */
+          case 0:  /* end of text */
+          case 2:  /* out of bounds */
+          case 3:  /* end of line */
+            FT_INVALID_DATA;
+            break;
+
+          case 1:  /* out of bounds */
+          default: /* user-defined: 4 - ( stateSize - 1 ) */
+            if ( classID >= stateSize )
+              FT_INVALID_DATA;   /* assign glyph to undefined state */
+            nGlyphInClass[classID]++;
+            break;
+        }
+      }
+      *length_p = ( p - table );
+
+
+      /* scan max ClassID in use */
+      for ( i = 0; i < stateSize; i++ )
+        if ((3 < i) && (nGlyphInClass[i] > 0))
+          *maxClassID_p = i;
+    }
+
+Out:
+    GXV_TRACE(( "Declared stateSize=0x%02x, Used maxClassID=0x%02x\n", stateSize, *maxClassID_p ));
+    GXV_EXIT;
+  }
+
+  /* --------------------------- State Array ----------------------------- */
+
+  static void
+  gxv_StateArray_validate( FT_Bytes       table,
+                           FT_UShort*     length_p,
+                           FT_Byte        maxClassID,
+                           FT_UShort      stateSize,
+                           FT_Byte*       maxState_p,
+                           FT_Byte*       maxEntry_p,
+                           GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_Bytes  limit = table + *length_p;
+    FT_Byte   class;
+    FT_Byte   entry;
+
+
+    GXV_NAME_ENTER( "StateArray" );
+
+    GXV_TRACE(( "parse %d bytes by stateSize=%d maxClassID=%d\n",
+                       (int)(*length_p), stateSize, (int)(maxClassID) ));
+
+    /*
+     * 2 states are predefined and must be described in StateArray
+     * state 0 (start of text), 1 (start of line)
+     */
+    GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 );
+
+    *maxState_p = 0;
+    *maxEntry_p = 0;
+
+    /* read if enough to read another state */
+    while ( p + ( 1 + maxClassID ) <= limit )
+    {
+      (*maxState_p) ++;
+      for ( class = 0; class <= maxClassID; class++ )
+      {
+        entry = FT_NEXT_BYTE( p );
+        *maxEntry_p = FT_MAX( *maxEntry_p, entry );
+      }
+    }
+    GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
+                         *maxState_p, *maxEntry_p ));
+
+    *length_p = ( p - table );
+
+    GXV_EXIT;
+  }
+
+  /* --------------------------- Entry Table ----------------------------- */
+
+  static void
+  gxv_EntryTable_validate( FT_Bytes       table,
+                           FT_UShort*     length_p,
+                           FT_Byte        maxEntry,
+                           FT_UShort      stateArray,
+                           FT_UShort      stateArray_length,
+                           FT_Byte        maxClassID,
+                           FT_Bytes       statetable_table,
+                           FT_Bytes       statetable_limit,
+                           GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_Bytes  limit = table + *length_p;
+    FT_Byte   entry;
+    FT_Byte   state;
+    FT_Int    entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( statetable );
+    GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
+
+
+    GXV_NAME_ENTER( "EntryTable" );
+
+    GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
+
+    if ( ( maxEntry + 1 ) * entrySize > *length_p )
+    {
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_TOO_SHORT;
+
+      /* ftxvalidator, FontValidator warns and continues */
+      maxEntry = ( *length_p / entrySize ) - 1;
+      GXV_TRACE(( "too large maxEntry, shrink to %d fit EntryTable length\n",
+                   maxEntry ));
+    }
+
+
+    for ( entry = 0; entry <= maxEntry; entry++ )
+    {
+      FT_UShort  newState;
+      FT_UShort  flags;
+
+
+      GXV_LIMIT_CHECK( 2 + 2 );
+      newState = FT_NEXT_USHORT( p );
+      flags    = FT_NEXT_USHORT( p );
+
+
+      if ( newState < stateArray || stateArray + stateArray_length < newState )
+      {
+        GXV_TRACE(( " newState offset 0x%04x is out of stateArray\n", newState ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_OFFSET;
+        continue;
+      }
+
+
+      if ( 0 != (( newState - stateArray ) % ( 1 + maxClassID )) )
+      {
+        GXV_TRACE(( " newState offset 0x%04x is not aligned to %d-classes\n",
+                                      newState,  1 + maxClassID ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_OFFSET;
+        continue;
+      }
+
+
+      state =  ( newState - stateArray ) / ( 1 + maxClassID );
+
+
+      switch ( GXV_GLYPHOFFSET_FMT( statetable ) )
+      {
+        case GXV_GLYPHOFFSET_NONE:
+          break;
+
+        case GXV_GLYPHOFFSET_UCHAR:
+          glyphOffset.uc = FT_NEXT_BYTE( p );
+          break;
+
+        case GXV_GLYPHOFFSET_CHAR:
+          glyphOffset.c = FT_NEXT_CHAR( p );
+          break;
+
+        case GXV_GLYPHOFFSET_USHORT:
+          glyphOffset.u = FT_NEXT_USHORT( p );
+          break;
+
+        case GXV_GLYPHOFFSET_SHORT:
+          glyphOffset.s = FT_NEXT_SHORT( p );
+          break;
+
+        case GXV_GLYPHOFFSET_ULONG:
+          glyphOffset.ul = FT_NEXT_ULONG( p );
+          break;
+
+        case GXV_GLYPHOFFSET_LONG:
+          glyphOffset.l = FT_NEXT_LONG( p );
+          break;
+
+        default:
+          if ( valid->root->level >= FT_VALIDATE_PARANOID )
+            FT_INVALID_FORMAT;
+      }
+
+      if ( NULL != valid->statetable.entry_validate_func )
+        valid->statetable.entry_validate_func( state,
+                                               flags,
+                                               glyphOffset,
+                                               statetable_table,
+                                               statetable_limit,
+                                               valid );
+    }
+    *length_p = ( p - table );
+
+    GXV_EXIT;
+  }
+
+  /* =========================== State Table ============================= */
+
+  FT_LOCAL_DEF( void )
+  gxv_StateTable_subtable_setup( FT_UShort      table_size,
+                                 FT_UShort      classTable,
+                                 FT_UShort      stateArray,
+                                 FT_UShort      entryTable,
+                                 FT_UShort*     classTable_length_p,
+                                 FT_UShort*     stateArray_length_p,
+                                 FT_UShort*     entryTable_length_p,
+                                 GXV_Validator  valid )
+  {
+    FT_UShort   o[3];
+    FT_UShort*  l[3];
+    FT_UShort   buff[4];
+
+    o[0] = classTable;
+    o[1] = stateArray;
+    o[2] = entryTable;
+    l[0] = classTable_length_p;
+    l[1] = stateArray_length_p;
+    l[2] = entryTable_length_p;
+
+    gxv_set_length_by_ushort_offset( o, l, buff, 3, table_size, valid );
+  }
+
+  FT_LOCAL_DEF( void )
+  gxv_StateTable_validate( FT_Bytes       table,
+                           FT_Bytes       limit,
+                           GXV_Validator  valid )
+  {
+    FT_UShort   stateSize;
+    FT_UShort   classTable;  /* offset to Class(Sub)Table */
+    FT_UShort   stateArray;  /* offset to StateArray */
+    FT_UShort   entryTable;  /* offset to EntryTable */
+#define GXV_STATETABLE_HEADER_SIZE ( 2 + 2 + 2 + 2 )
+#define GXV_STATEHEADER_SIZE GXV_STATETABLE_HEADER_SIZE
+    FT_UShort   classTable_length;
+    FT_UShort   stateArray_length;
+    FT_UShort   entryTable_length;
+    FT_Byte     maxClassID;
+    FT_Byte     maxState;
+    FT_Byte     maxEntry;
+
+    GXV_StateTable_Subtable_Setup_Func  setup_func;
+
+    FT_Bytes    p = table;
+
+
+    GXV_NAME_ENTER( "StateTable" );
+
+    GXV_TRACE(( "StateTable header\n" ));
+
+    GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
+    stateSize  = FT_NEXT_USHORT( p );
+    classTable = FT_NEXT_USHORT( p );
+    stateArray = FT_NEXT_USHORT( p );
+    entryTable = FT_NEXT_USHORT( p );
+
+    GXV_TRACE(( "stateSize=0x%04x\n", stateSize ));
+    GXV_TRACE(( "offset to classTable=0x%04x\n", classTable ));
+    GXV_TRACE(( "offset to stateArray=0x%04x\n", stateArray ));
+    GXV_TRACE(( "offset to entryTable=0x%04x\n", entryTable ));
+
+    if (stateSize > 0xFF)
+      FT_INVALID_DATA;
+
+    if ( valid->statetable.optdata_load_func != NULL )
+      valid->statetable.optdata_load_func( p, limit, valid );
+
+
+    if ( valid->statetable.subtable_setup_func != NULL)
+      setup_func = valid->statetable.subtable_setup_func;
+    else
+      setup_func = gxv_StateTable_subtable_setup;
+
+    setup_func( limit - table,
+                classTable,
+                stateArray,
+                entryTable,
+                &classTable_length,
+                &stateArray_length,
+                &entryTable_length,
+                valid );
+
+
+    GXV_TRACE(( "StateTable Subtables\n" ));
+
+    if (classTable != 0)
+      gxv_ClassTable_validate( table + classTable,
+                               &classTable_length,
+                               stateSize,
+                               &maxClassID,
+                               valid );
+    else
+      maxClassID = stateSize - 1;
+
+    if (stateArray != 0)
+      gxv_StateArray_validate( table + stateArray,
+                               &stateArray_length,
+                               maxClassID,
+                               stateSize,
+                               &maxState,
+                               &maxEntry,
+                               valid );
+    else
+    {
+      maxState = 1; /* 0:start of text, 1:start of line are predefined */
+      maxEntry = 0;
+    }
+
+    if (maxEntry > 0 && entryTable == 0)
+      FT_INVALID_OFFSET;
+
+    if (entryTable != 0)
+      gxv_EntryTable_validate( table + entryTable,
+                               &entryTable_length,
+                               maxEntry,
+                               stateArray,
+                               stateArray_length,
+                               maxClassID,
+                               table,
+                               limit,
+                               valid );
+
+    GXV_EXIT;
+  }
+
+  /* ================ eXtended State Table (for morx) =================== */
+
+  FT_LOCAL_DEF( void )
+  gxv_XStateTable_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[3];
+    FT_ULong*  l[3];
+    FT_ULong   buff[4];
+
+    o[0] = classTable;
+    o[1] = stateArray;
+    o[2] = entryTable;
+    l[0] = classTable_length_p;
+    l[1] = stateArray_length_p;
+    l[2] = entryTable_length_p;
+
+    gxv_set_length_by_ulong_offset( o, l, buff, 4, table_size, valid );
+  }
+
+
+  static void
+  gxv_XClassTable_lookupval_validate( FT_UShort            glyph,
+                                      GXV_LookupValueDesc  value,
+                                      GXV_Validator        valid )
+  {
+    if ( value.u >= valid->xstatetable.nClasses )
+      FT_INVALID_DATA;
+    if ( value.u > valid->xstatetable.maxClassID )
+      valid->xstatetable.maxClassID = value.u;
+  }
+
+
+  /*
+    +===============+ --------+
+    | 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_XClassTable_lookupfmt4_transit( FT_UShort            relative_gindex,
+                                      GXV_LookupValueDesc  base_value,
+                                      FT_Bytes             lookuptbl_limit,
+                                      GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+    offset = base_value.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;
+  }
+
+
+  static void
+  gxv_XStateArray_validate( FT_Bytes       table,
+                            FT_ULong*      length_p,
+                            FT_UShort      maxClassID,
+                            FT_ULong       stateSize,
+                            FT_UShort*     maxState_p,
+                            FT_UShort*     maxEntry_p,
+                            GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_Bytes   limit = table + *length_p;
+    FT_UShort  class;
+    FT_UShort  entry;
+
+
+    GXV_NAME_ENTER( "XStateArray" );
+
+    GXV_TRACE(( "parse % 3d bytes by stateSize=% 3d maxClassID=% 3d\n",
+                       (int)(*length_p), stateSize, (int)(maxClassID) ));
+
+    /*
+     * 2 states are predefined and must be described
+     * state 0 (start of text), 1 (start of line)
+     */
+    GXV_LIMIT_CHECK( ( 1 + maxClassID ) * 2 * 2 );
+
+    *maxState_p = 0;
+    *maxEntry_p = 0;
+
+    /* read if enough to read another state */
+    while ( p + ( ( 1 + maxClassID ) * 2 ) <= limit )
+    {
+      (*maxState_p) ++;
+      for ( class = 0; class <= maxClassID; class++ )
+      {
+        entry = FT_NEXT_USHORT( p );
+        *maxEntry_p = FT_MAX( *maxEntry_p, entry );
+      }
+    }
+    GXV_TRACE(( "parsed: maxState=%d, maxEntry=%d\n",
+                         *maxState_p, *maxEntry_p ));
+
+    *length_p = ( p - table );
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_XEntryTable_validate( FT_Bytes       table,
+                            FT_ULong*      length_p,
+                            FT_UShort      maxEntry,
+                            FT_ULong       stateArray,
+                            FT_ULong       stateArray_length,
+                            FT_UShort      maxClassID,
+                            FT_Bytes       xstatetable_table,
+                            FT_Bytes       xstatetable_limit,
+                            GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_Bytes   limit = table + *length_p;
+    FT_UShort  entry;
+    FT_UShort  state;
+    FT_Int     entrySize = 2 + 2 + GXV_GLYPHOFFSET_SIZE( xstatetable );
+
+
+    GXV_NAME_ENTER( "XEntryTable" );
+    GXV_TRACE(( "maxEntry=%d entrySize=%d\n", maxEntry, entrySize ));
+
+    if ( ( p + ( maxEntry + 1 ) * entrySize ) > limit )
+      FT_INVALID_TOO_SHORT;
+
+    for (entry = 0; entry <= maxEntry ; entry++ )
+    {
+      FT_UShort  newState_idx;
+      FT_UShort  flags;
+      GXV_XStateTable_GlyphOffsetDesc  glyphOffset;
+
+
+      GXV_LIMIT_CHECK( 2 + 2 );
+      newState_idx = FT_NEXT_USHORT( p );
+      flags        = FT_NEXT_USHORT( p );
+
+      if ( stateArray_length < ( newState_idx * 2 ) )
+      {
+        GXV_TRACE(( "  newState index 0x%04x points out of stateArray\n", newState_idx ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_OFFSET;
+      }
+
+      state =  newState_idx / ( 1 + maxClassID );
+      if ( 0 != ( newState_idx % ( 1 + maxClassID ) ) )
+      {
+        FT_TRACE4(( "-> new state = %d (supposed) but newState index 0x%04x is not aligned to %d-classes\n",
+                                      state, newState_idx,  1 + maxClassID ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_OFFSET;
+      }
+
+
+      switch ( GXV_GLYPHOFFSET_FMT( xstatetable ) )
+      {
+        case GXV_GLYPHOFFSET_NONE:
+          break;
+
+        case GXV_GLYPHOFFSET_UCHAR:
+          glyphOffset.uc = FT_NEXT_BYTE( p );
+          break;
+
+        case GXV_GLYPHOFFSET_CHAR:
+          glyphOffset.c = FT_NEXT_CHAR( p );
+          break;
+
+        case GXV_GLYPHOFFSET_USHORT:
+          glyphOffset.u = FT_NEXT_USHORT( p );
+          break;
+
+        case GXV_GLYPHOFFSET_SHORT:
+          glyphOffset.s = FT_NEXT_SHORT( p );
+          break;
+
+        case GXV_GLYPHOFFSET_ULONG:
+          glyphOffset.ul = FT_NEXT_ULONG( p );
+          break;
+
+        case GXV_GLYPHOFFSET_LONG:
+          glyphOffset.l = FT_NEXT_LONG( p );
+          break;
+
+        default:
+          if ( valid->root->level >= FT_VALIDATE_PARANOID )
+            FT_INVALID_FORMAT;
+      }
+
+      if ( NULL != valid->xstatetable.entry_validate_func )
+        valid->xstatetable.entry_validate_func( state,
+                                                flags,
+                                                glyphOffset,
+                                                xstatetable_table,
+                                                xstatetable_limit,
+                                                valid );
+    }
+
+    *length_p = ( p - table );
+
+    GXV_EXIT;
+  }
+
+  FT_LOCAL_DEF( void )
+  gxv_XStateTable_validate( FT_Bytes       table,
+                            FT_Bytes       limit,
+                            GXV_Validator  valid )
+  {
+    /* StateHeader members */
+    FT_ULong    classTable;  /* offset to Class(Sub)Table */
+    FT_ULong    stateArray;  /* offset to StateArray */
+    FT_ULong    entryTable;  /* offset to EntryTable */
+#define GXV_XSTATETABLE_HEADER_SIZE ( 4 + 4 + 4 + 4 )
+#define GXV_XSTATEHEADER_SIZE GXV_XSTATETABLE_HEADER_SIZE
+    FT_ULong    classTable_length;
+    FT_ULong    stateArray_length;
+    FT_ULong    entryTable_length;
+    FT_UShort   maxState;
+    FT_UShort   maxEntry;
+
+    GXV_XStateTable_Subtable_Setup_Func  setup_func;
+
+    FT_Bytes    p = table;
+
+    GXV_NAME_ENTER( "XStateTable" );
+
+    GXV_TRACE(( "XStateTable header\n" ));
+
+    GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
+    valid->xstatetable.nClasses  = FT_NEXT_ULONG( p );
+    classTable = FT_NEXT_ULONG( p );
+    stateArray = FT_NEXT_ULONG( p );
+    entryTable = FT_NEXT_ULONG( p );
+
+    GXV_TRACE(( "nClasses =0x%08x\n", valid->xstatetable.nClasses ));
+    GXV_TRACE(( "offset to classTable=0x%08x\n", classTable ));
+    GXV_TRACE(( "offset to stateArray=0x%08x\n", stateArray ));
+    GXV_TRACE(( "offset to entryTable=0x%08x\n", entryTable ));
+
+    if ( valid->xstatetable.nClasses > 0xFFFF )
+      FT_INVALID_DATA;
+
+    GXV_TRACE(( "StateTable Subtables\n" ));
+
+    if ( valid->xstatetable.optdata_load_func != NULL )
+      valid->xstatetable.optdata_load_func( p, limit, valid );
+
+
+    if ( valid->xstatetable.subtable_setup_func != NULL)
+      setup_func = valid->xstatetable.subtable_setup_func;
+    else
+      setup_func = gxv_XStateTable_subtable_setup;
+
+    setup_func( limit - table,
+                classTable,
+                stateArray,
+                entryTable,
+                &classTable_length,
+                &stateArray_length,
+                &entryTable_length,
+                valid );
+
+
+    if (classTable != 0)
+    {
+      valid->xstatetable.maxClassID = 0;
+      valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
+      valid->lookupval_func   = gxv_XClassTable_lookupval_validate;
+      valid->lookupfmt4_trans = gxv_XClassTable_lookupfmt4_transit;
+      gxv_LookupTable_validate( table + classTable,
+                                table + classTable + classTable_length,
+                                valid );
+      if ( valid->subtable_length < classTable_length )
+        classTable_length = valid->subtable_length;
+    }
+    else
+      valid->xstatetable.maxClassID = valid->xstatetable.nClasses - 1;
+
+
+    if (stateArray != 0)
+    {
+      gxv_XStateArray_validate( table + stateArray,
+                                &stateArray_length,
+                                valid->xstatetable.maxClassID,
+                                valid->xstatetable.nClasses,
+                                &maxState,
+                                &maxEntry,
+                                valid );
+    }
+    else
+    {
+      maxState = 1; /* 0:start of text, 1:start of line are predefined */
+      maxEntry = 0;
+    }
+
+    if (maxEntry > 0 && entryTable == 0)
+      FT_INVALID_OFFSET;
+
+    if (entryTable != 0)
+    {
+      gxv_XEntryTable_validate( table + entryTable,
+                                &entryTable_length,
+                                maxEntry,
+                                stateArray,
+                                stateArray_length,
+                                valid->xstatetable.maxClassID,
+                                table,
+                                limit,
+                                valid );
+    }
+
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        Table overlapping                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( int )
+  gxv_compare_ranges( FT_Bytes       table1_start,
+                      FT_ULong       table1_length,
+                      FT_Bytes       table2_start,
+                      FT_ULong       table2_length,
+                      GXV_Validator  valid )
+  {
+    if ( table1_start == table2_start )
+    {
+      if ( ( table1_length == 0 || table2_length == 0 ) )
+        goto Out;
+    }
+    else if ( table1_start < table2_start )
+    {
+      if ( ( table1_start + table1_length ) <= table2_start )
+        goto Out;
+    }
+    else if ( table1_start > table2_start )
+    {
+      if ( ( table1_start >= table2_start + table2_length ) )
+        goto Out;
+    }
+    return 1;
+
+  Out:
+    return 0;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  gxv_odtect_add_range( FT_Bytes          start,
+                        FT_ULong          length,
+                        FT_String*        name,
+                        GXV_odtect_Range  odtect )
+  {
+    odtect->range[ odtect->nRanges ].start  = start;
+    odtect->range[ odtect->nRanges ].length = length;
+    odtect->range[ odtect->nRanges ].name   = name;
+    odtect->nRanges ++;
+  }
+
+  FT_LOCAL_DEF( void )
+  gxv_odtect_validate( GXV_odtect_Range  odtect,
+                       GXV_Validator     valid   )
+  {
+    FT_UInt  i, j;
+
+
+    GXV_NAME_ENTER( "check overlap among multi ranges" );
+
+    for ( i = 0; i < odtect->nRanges; i ++ )
+      for ( j = 0; j < i; j ++ )
+        if ( 0 != gxv_compare_ranges( odtect->range[i].start,
+                                      odtect->range[i].length,
+                                      odtect->range[j].start,
+                                      odtect->range[j].length,
+                                      valid )                      )
+        {
+          if ( odtect->range[i].name || odtect->range[j].name )
+            GXV_TRACE(( "found overlap between range-%d and range-%d\n",
+                         i, j ));
+          else
+            GXV_TRACE(( "found overlap between \"%s\" and \"%s\"\n",
+                         odtect->range[i].name,
+                         odtect->range[j].name ));
+          FT_INVALID_OFFSET;
+        }
+
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvcommn.h
@@ -1,0 +1,452 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvcommn.h                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT common tables validation (specification).             */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+/*
+ * keywords in variable naming
+ * ---------------------------
+ *  table: FT_Bytes typed, pointing the start of this table/subtable.
+ *  limit: FT_Bytes typed, pointing the end of this table/subtable
+ *         including padding for alignment.
+ *  offset: FT_UInt typed, the number of octets from the start to target.
+ *  length: FT_UInt typed, the number of octets from the start to the end.
+ *          in this table/subtable, including padding for alignment.
+ *
+ *  _MIN, _MAX: should be added to the tail of macros, as INT_MIN etc.
+ */
+
+#ifndef __GXVCOMMN_H__
+#define __GXVCOMMN_H__
+
+
+#include <ft2build.h>
+#include "gxvalid.h"
+#include FT_INTERNAL_DEBUG_H
+#include FT_SFNT_NAMES_H
+
+FT_BEGIN_HEADER
+
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         VALIDATION                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct GXV_ValidatorRec_*         GXV_Validator;
+
+#define DUMMY_LIMIT 0
+  typedef void  (*GXV_Validate_Func)( FT_Bytes      table,
+                                      FT_Bytes      limit,
+                                      GXV_Validator valid );
+
+  /* ====================== LookupTable Validator ======================== */
+
+  typedef union GXV_LookupValueDesc_
+  {
+    FT_UShort u;
+    FT_Short  s;
+
+  } GXV_LookupValueDesc;
+
+  typedef enum  GXV_LookupValue_SignSpec_
+  {
+    GXV_LOOKUPVALUE_UNSIGNED = 0,
+    GXV_LOOKUPVALUE_SIGNED
+
+  } GXV_LookupValue_SignSpec;
+
+  typedef void  (*GXV_Lookup_Value_Validate_Func)( FT_UShort           glyph,
+                                                   GXV_LookupValueDesc value,
+                                                   GXV_Validator       valid );
+
+  typedef GXV_LookupValueDesc (*GXV_Lookup_Fmt4_Transit_Func)
+  ( FT_UShort            relative_gindex,
+    GXV_LookupValueDesc  base_value,
+    FT_Bytes             lookuptbl_limit,
+    GXV_Validator        valid );
+
+
+  /* ====================== StateTable Validator ========================= */
+
+  typedef enum  GXV_GlyphOffset_Format_
+  {
+    GXV_GLYPHOFFSET_NONE   = -1,
+    GXV_GLYPHOFFSET_UCHAR  = 2,
+    GXV_GLYPHOFFSET_CHAR,
+    GXV_GLYPHOFFSET_USHORT = 4,
+    GXV_GLYPHOFFSET_SHORT,
+    GXV_GLYPHOFFSET_ULONG  = 8,
+    GXV_GLYPHOFFSET_LONG
+
+  } GXV_GlyphOffset_Format;
+
+
+#define GXV_GLYPHOFFSET_FMT( table ) \
+        ( valid-> table . entry_glyphoffset_fmt )
+
+#define GXV_GLYPHOFFSET_SIZE( table ) \
+        ( ( valid-> table . entry_glyphoffset_fmt ) / 2 )
+
+  /* ----------------------- 16bit StateTable ---------------------------- */
+
+  typedef union  GXV_StateTable_GlyphOffsetDesc_
+  {
+    FT_Byte   uc;
+    FT_UShort u;   /* same with GXV_LookupValueDesc */
+    FT_ULong  ul;
+    FT_Char   c;
+    FT_Short  s;   /* same with GXV_LookupValueDesc */
+    FT_Long   l;
+
+  } GXV_StateTable_GlyphOffsetDesc;
+
+  typedef void  (*GXV_StateTable_Subtable_Setup_Func)( FT_UShort      table_size,
+                                                       FT_UShort      classTable,
+                                                       FT_UShort      stateArray,
+                                                       FT_UShort      entryTable,
+                                                       FT_UShort*     classTable_length_p,
+                                                       FT_UShort*     stateArray_length_p,
+                                                       FT_UShort*     entryTable_length_p,
+                                                       GXV_Validator  valid );
+
+  typedef void  (*GXV_StateTable_Entry_Validate_Func)( FT_Byte                         state,
+                                                       FT_UShort                       flags,
+                                                       GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                                       FT_Bytes                        statetable_table,
+                                                       FT_Bytes                        statetable_limit,
+                                                       GXV_Validator                   valid );
+
+  typedef void  (*GXV_StateTable_OptData_Load_Func)( FT_Bytes       table,
+                                                     FT_Bytes       limit,
+                                                     GXV_Validator  valid );
+
+  typedef struct GXV_StateTable_ValidatorRec_
+  {
+    GXV_GlyphOffset_Format  entry_glyphoffset_fmt;
+    void*                   optdata;
+    GXV_StateTable_Subtable_Setup_Func
+                            subtable_setup_func;
+    GXV_StateTable_Entry_Validate_Func
+                            entry_validate_func;
+    GXV_StateTable_OptData_Load_Func
+                            optdata_load_func;
+
+  } GXV_StateTable_ValidatorRec, *GXV_StateTable_ValidatorRecData;
+
+
+  /* ---------------------- 32bit XStateTable ---------------------------- */
+
+  typedef GXV_StateTable_GlyphOffsetDesc GXV_XStateTable_GlyphOffsetDesc;
+
+  typedef void  (*GXV_XStateTable_Subtable_Setup_Func)( 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 );
+
+  typedef void  (*GXV_XStateTable_Entry_Validate_Func)( FT_UShort      state,
+                                                        FT_UShort      flags,
+                                                        GXV_StateTable_GlyphOffsetDesc
+                                                                       glyphOffset,
+                                                        FT_Bytes       xstatetable_table,
+                                                        FT_Bytes       xstatetable_limit,
+                                                        GXV_Validator  valid );
+
+  typedef GXV_StateTable_OptData_Load_Func GXV_XStateTable_OptData_Load_Func;
+
+  typedef struct GXV_XStateTable_ValidatorRec_
+  {
+    int        entry_glyphoffset_fmt;
+    void*      optdata;
+    GXV_XStateTable_Subtable_Setup_Func
+               subtable_setup_func;
+    GXV_XStateTable_Entry_Validate_Func
+               entry_validate_func;
+    GXV_XStateTable_OptData_Load_Func
+               optdata_load_func;
+    FT_ULong   nClasses;
+    FT_UShort  maxClassID;
+
+  } GXV_XStateTable_ValidatorRec, *GXV_XStateTable_ValidatorRecData;
+
+  /* ===================================================================== */
+
+  typedef struct GXV_ValidatorRec_
+  {
+    FT_Validator  root;
+
+    FT_Face       face;
+    void*         table_data;
+
+    FT_ULong      subtable_length;
+
+    GXV_LookupValue_SignSpec        lookupval_sign;
+    GXV_Lookup_Value_Validate_Func  lookupval_func;
+    GXV_Lookup_Fmt4_Transit_Func    lookupfmt4_trans;
+    FT_Bytes                        lookuptbl_head;
+
+    GXV_StateTable_ValidatorRec     statetable;
+    GXV_XStateTable_ValidatorRec    xstatetable;
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+    FT_UInt             debug_indent;
+    const FT_String*    debug_function_name[3];
+#endif
+
+  } GXV_ValidatorRec;
+
+#define GXV_TABLE_DATA( tag, field ) \
+        ( ( (GXV_ ## tag ## _Data)valid->table_data )->field )
+
+#undef  FT_INVALID_
+#define FT_INVALID_( _prefix, _error )                         \
+          ft_validator_error( valid->root, _prefix ## _error )
+
+#define GXV_LIMIT_CHECK( _count )                                      \
+          FT_BEGIN_STMNT                                               \
+            if ( p + _count > ( limit? limit : valid->root->limit ) )  \
+                FT_INVALID_TOO_SHORT;                                  \
+          FT_END_STMNT
+
+#ifdef FT_DEBUG_LEVEL_TRACE
+#define GXV_INIT  valid->debug_indent = 0
+
+#define GXV_NAME_ENTER( name )                             \
+          FT_BEGIN_STMNT                                   \
+            valid->debug_indent += 2;                      \
+            FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \
+            FT_TRACE4(( "%s table\n", name ));             \
+          FT_END_STMNT
+
+#define GXV_EXIT  valid->debug_indent -= 2
+
+#define GXV_TRACE( s )                                     \
+          FT_BEGIN_STMNT                                   \
+            FT_TRACE4(( "%*.s", valid->debug_indent, 0 )); \
+            FT_TRACE4( s );                                \
+          FT_END_STMNT
+
+#else   /* !FT_DEBUG_LEVEL_TRACE */
+#define GXV_INIT                do ; while ( 0 )
+#define GXV_NAME_ENTER( name )  do ; while ( 0 )
+#define GXV_EXIT                do ; while ( 0 )
+
+#define GXV_TRACE( s )          do ; while ( 0 )
+
+#endif  /* !FT_DEBUG_LEVEL_TRACE */
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    32bit alignment checking                   *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define GXV_32BIT_ALIGNMENT_VALIDATE( a )               \
+        FT_BEGIN_STMNT                                  \
+          {                                             \
+            if ( 0 != ( (a) % 4 ) ) FT_INVALID_OFFSET ; \
+          }                                             \
+        FT_END_STMNT
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                    Dumping Binary Data                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define  GXV_TRACE_HEXDUMP( p, len )                 \
+         FT_BEGIN_STMNT                              \
+           {                                         \
+             FT_Bytes b;                             \
+             for (b = p; b < (FT_Bytes)p + len; b++) \
+               FT_TRACE1(("\\x%02x", *b)) ;          \
+           }                                         \
+         FT_END_STMNT
+
+#define  GXV_TRACE_HEXDUMP_C( p, len )               \
+         FT_BEGIN_STMNT                              \
+           {                                         \
+             FT_Bytes b;                             \
+             for (b = p; b < (FT_Bytes)p + len; b++) \
+               if (0x40 < *b && *b < 0x7e)           \
+                 FT_TRACE1(("%c", *b)) ;             \
+               else                                  \
+                 FT_TRACE1(("\\x%02x", *b)) ;        \
+           }                                         \
+         FT_END_STMNT
+
+#define  GXV_TRACE_HEXDUMP_SFNTNAME( n )   GXV_TRACE_HEXDUMP( n.string, n.string_len )
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         LOOKUP TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  gxv_BinSrchHeader_validate( FT_Bytes       p,
+                              FT_Bytes       limit,
+                              FT_UShort*     unitSize_p,
+                              FT_UShort*     nUnits_p,
+                              GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_LookupTable_validate( FT_Bytes       table,
+                            FT_Bytes       limit,
+                            GXV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          Glyph ID                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( FT_Int )
+  gxv_glyphid_validate( FT_UShort      gid,
+                        GXV_Validator  valid );
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        CONTROL POINT                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  gxv_ctlPoint_validate( FT_UShort      gid,
+                         FT_Short       ctl_point,
+                         GXV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          SFNT NAME                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  gxv_sfntName_validate( FT_UShort      name_index,
+                         FT_UShort      min_index,
+                         FT_UShort      max_index,
+                         GXV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          STATE TABLE                          *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL( void )
+  gxv_StateTable_validate( FT_Bytes       table,
+                           FT_Bytes       limit,
+                           GXV_Validator  valid );
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         UTILITY MACRO                         *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+#define GXV_SUBTABLE_OFFSET_CHECK( _offset )        \
+         FT_BEGIN_STMNT                             \
+          if ( (_offset) > valid->subtable_length ) \
+            FT_INVALID_OFFSET;                      \
+         FT_END_STMNT
+
+#define GXV_SUBTABLE_LIMIT_CHECK( _count ) \
+         FT_BEGIN_STMNT                    \
+          if ( ( p + (_count) - valid->subtable_start ) > valid->subtable_length ) \
+            FT_INVALID_TOO_SHORT;          \
+         FT_END_STMNT
+
+#define GXV_USHORT_TO_SHORT( _us ) \
+         ( ( 0x8000 < ( _us ) ) ? ( ( _us ) - 0x8000 ) : ( _us ) )
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                        Table overlapping                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct GXV_odtect_DataRec_
+  {
+    FT_Bytes    start;
+    FT_ULong    length;
+    FT_String*  name;
+
+  } GXV_odtect_DataRec,  *GXV_odtect_Data;
+
+  typedef struct GXV_odtect_RangeRec_
+  {
+    FT_UInt          nRanges;
+    GXV_odtect_Data  range;
+
+  } GXV_odtect_RangeRec, *GXV_odtect_Range;
+
+#define GXV_ODTECT( n, odtect )                       \
+  GXV_odtect_DataRec   odtect ## _range[ n ];         \
+  GXV_odtect_RangeRec  odtect ## _rec = { 0, NULL };  \
+  GXV_odtect_Range     odtect = NULL
+
+#define GXV_ODTECT_INIT( odtect )                     \
+        FT_BEGIN_STMNT                                \
+          odtect ## _rec.nRanges = 0;                 \
+          odtect ## _rec.range   = odtect ## _range;  \
+          odtect                 = & odtect ## _rec;  \
+        FT_END_STMNT
+
+ /* */
+
+FT_END_HEADER
+
+#endif /* Not def: __GXVCOMMN_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxverror.h
@@ -1,0 +1,48 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxverror.h                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT validation module error codes (specification only).   */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the OpenType validation module error      */
+  /* enumeration constants.                                                */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __GXVERROR_H__
+#define __GXVERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  GXV_Err_
+#define FT_ERR_BASE    FT_Mod_Err_GXV
+
+#define FT_KEEP_ERR_PREFIX
+
+#include FT_ERRORS_H
+
+#endif /* __GXVERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvfeat.c
@@ -1,0 +1,464 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvfeat.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT feat 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 was support of 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_gxvfeat
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                Registry predefined by Apple                   *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  /* TODO: More compact format */
+  typedef struct  GXV_Feature_RegistryRec_
+  {
+    FT_Bool  existence;
+    FT_Bool  apple_reserved;
+    FT_Bool  exclusive;
+    FT_Byte  nSettings;
+
+  } GX_Feature_RegistryRec;
+#define gxv_feat_registry_length ( sizeof ( gxv_feat_registry ) / sizeof ( GX_Feature_RegistryRec ) )
+
+  static GX_Feature_RegistryRec  gxv_feat_registry [] =
+  {
+    /* Generated from gxvfgen.c */
+    {1, 0, 0,  1},   /* All Typographic Features */
+    {1, 0, 0,  8},   /* Ligatures */
+    {1, 0, 1,  3},   /* Cursive Connection */
+    {1, 0, 1,  6},   /* Letter Case */
+    {1, 0, 0,  1},   /* Vertical Substitution */
+    {1, 0, 0,  1},   /* Linguistic Rearrangement */
+    {1, 0, 1,  2},   /* Number Spacing */
+    {1, 1, 0,  0},   /* Apple Reserved 1 */
+    {1, 0, 0,  5},   /* Smart Swashes */
+    {1, 0, 1,  3},   /* Diacritics */
+    {1, 0, 1,  4},   /* Vertical Position */
+    {1, 0, 1,  3},   /* Fractions */
+    {1, 1, 0,  0},   /* Apple Reserved 2 */
+    {1, 0, 0,  1},   /* Overlapping Characters */
+    {1, 0, 0,  6},   /* Typographic Extras */
+    {1, 0, 0,  5},   /* Mathematical Extras */
+    {1, 0, 1,  7},   /* Ornament Sets */
+    {1, 0, 1,  1},   /* Character Alternatives */
+    {1, 0, 1,  5},   /* Design Complexity */
+    {1, 0, 1,  6},   /* Style Options */
+    {1, 0, 1, 11},   /* Character Shape */
+    {1, 0, 1,  2},   /* Number Case */
+    {1, 0, 1,  4},   /* Text Spacing */
+    {1, 0, 1, 10},   /* Transliteration */
+    {1, 0, 1,  9},   /* Annotation */
+    {1, 0, 1,  2},   /* Kana Spacing */
+    {1, 0, 1,  2},   /* Ideographic Spacing */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {0, 0, 0,  0},   /* __EMPTY__ */
+    {1, 0, 1,  4},   /* Text Spacing */
+    {1, 0, 1,  2},   /* Kana Spacing */
+    {1, 0, 1,  2},   /* Ideographic Spacing */
+    {1, 0, 1,  4},   /* CJK Roman Spacing */
+  };
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      Data and Types                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  typedef struct  GXV_feat_DataRec_
+  {
+    FT_UInt    reserved_size;
+    FT_UShort  feature;
+    FT_UShort  setting;
+
+  } GXV_feat_DataRec, *GXV_feat_Data;
+#define GXV_FEAT_DATA(field)  GXV_TABLE_DATA( feat, field )
+
+  typedef enum
+  {
+    GXV_FEAT_MASK_EXCLUSIVE_SETTINGS = 0x8000,
+    GXV_FEAT_MASK_DYNAMIC_DEFAULT    = 0x4000,
+    GXV_FEAT_MASK_UNUSED             = 0x3F00,
+    GXV_FEAT_MASK_DEFAULT_SETTING    = 0x00FF
+
+  } GXV_FeatureFlagsMask ;
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  gxv_feat_registry_validate( FT_UShort      feature,
+                              FT_UShort      nSettings,
+                              FT_Bool        exclusive,
+                              GXV_Validator  valid )
+  {
+    GXV_NAME_ENTER( "feature in registry" );
+
+    GXV_TRACE(( " (feature = %u)\n", feature ));
+
+    if ( feature >= gxv_feat_registry_length )
+    {
+      GXV_TRACE(( "feature number %d is out of range %d\n",
+                   feature, gxv_feat_registry_length ));
+      if ( valid->root->level == FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+      goto Exit;
+    }
+
+    if ( gxv_feat_registry[feature].existence == 0 )
+    {
+      GXV_TRACE(( "feature number %d is in define range but inexistent\n",
+                   feature ));
+      if ( valid->root->level == FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+      goto Exit;
+    }
+
+    if ( gxv_feat_registry[feature].apple_reserved )
+    {
+      /* Don't use here. Apple is reserved. */
+      GXV_TRACE(( "feature number %d is reserved by Apple\n",
+                   feature ));
+      if ( valid->root->level >= FT_VALIDATE_TIGHT )
+        FT_INVALID_DATA;
+    }
+
+    if ( nSettings != gxv_feat_registry[feature].nSettings )
+    {
+      GXV_TRACE(( "feature %d: nSettings %d != defined nSettings %d\n",
+                   feature, nSettings, gxv_feat_registry[feature].nSettings ));
+      if ( valid->root->level >= FT_VALIDATE_TIGHT )
+        FT_INVALID_DATA;
+    }
+
+    if ( exclusive != gxv_feat_registry[feature].exclusive )
+    {
+      GXV_TRACE(( "exclusive flag %d differs from predefined value\n",
+                   exclusive ));
+      if ( valid->root->level >= FT_VALIDATE_TIGHT )
+        FT_INVALID_DATA;
+    }
+
+  Exit:
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_feat_name_index_validate( FT_Bytes       table,
+                                FT_Bytes       limit,
+                                GXV_Validator  valid )
+  {
+    FT_Bytes     p = table;
+
+    FT_Short     nameIndex;
+
+
+    GXV_NAME_ENTER( "nameIndex" );
+
+    GXV_LIMIT_CHECK( 2 );
+    nameIndex = FT_NEXT_SHORT ( p );
+    GXV_TRACE(( " (nameIndex = %d)\n", nameIndex ));
+
+    gxv_sfntName_validate( (FT_UShort)nameIndex,
+                           255,
+                           32768,
+                           valid );
+
+    GXV_EXIT;
+  }
+
+  static void
+  gxv_feat_setting_validate( FT_Bytes       table,
+                             FT_Bytes       limit,
+                             FT_Bool        exclusive,
+                             GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  setting;
+
+    GXV_NAME_ENTER( "setting" );
+
+    GXV_LIMIT_CHECK( 2 );
+
+    setting = FT_NEXT_USHORT( p );
+
+    /* If exclusive setting,  setting should be odd. */
+    if ( exclusive && ( ( setting % 2 ) == 0 ) )
+      FT_INVALID_DATA;
+
+    gxv_feat_name_index_validate( p, limit, valid );
+
+    GXV_FEAT_DATA( setting ) = setting;
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_feat_name_validate( FT_Bytes       table,
+                          FT_Bytes       limit,
+                          GXV_Validator  valid )
+  {
+    FT_Bytes   p             = table;
+    FT_UInt    reserved_size = GXV_FEAT_DATA( reserved_size );
+
+    FT_UShort  feature;
+    FT_UShort  nSettings;
+    FT_UInt    settingTable;
+    FT_UShort  featureFlags;
+
+    FT_Bool    exclusive;
+    FT_Int     last_setting;
+    FT_Int     i;
+
+
+    GXV_NAME_ENTER( "name" );
+
+    /* feature + nSettings + settingTable + featureFlags */
+    GXV_LIMIT_CHECK( 2 + 2 + 4 + 2 );
+
+    feature = FT_NEXT_USHORT( p );
+    GXV_FEAT_DATA( feature ) = feature;
+
+    nSettings    = FT_NEXT_USHORT( p );
+    settingTable = FT_NEXT_ULONG ( p );
+    featureFlags = FT_NEXT_USHORT( p );
+
+    if ( settingTable < reserved_size )
+      FT_INVALID_OFFSET;
+
+    if ( valid->root->level == FT_VALIDATE_PARANOID &&
+         (featureFlags & GXV_FEAT_MASK_UNUSED) == 0 )
+      FT_INVALID_DATA;
+
+    exclusive    = featureFlags & GXV_FEAT_MASK_EXCLUSIVE_SETTINGS;
+    if ( exclusive )
+    {
+      FT_Byte   dynamic_default;
+
+
+      if (featureFlags & GXV_FEAT_MASK_DYNAMIC_DEFAULT)
+        dynamic_default = featureFlags & GXV_FEAT_MASK_DEFAULT_SETTING;
+      else
+        dynamic_default = 0;
+
+      /* If exclusive, check whether default setting is in the range. */
+      if ( !( dynamic_default < nSettings ) )
+        FT_INVALID_FORMAT;
+    }
+
+    gxv_feat_registry_validate( feature, nSettings, exclusive, valid );
+
+    gxv_feat_name_index_validate( p, limit, valid );
+
+    p = valid->root->base + settingTable;
+    for ( last_setting = -1, i = 0; i < nSettings; i++ )
+    {
+      gxv_feat_setting_validate( p, limit, exclusive, valid );
+
+      if ( valid->root->level == FT_VALIDATE_PARANOID &&
+           (FT_Int)GXV_FEAT_DATA( setting ) <= last_setting )
+        FT_INVALID_FORMAT;
+
+      last_setting = (FT_Int)GXV_FEAT_DATA( setting );
+      /* setting + nameIndex */
+      p += ( 2 + 2 );
+    }
+
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         feat TABLE                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  gxv_feat_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  ftvalid )
+  {
+    GXV_ValidatorRec  validrec;
+    GXV_Validator     valid = &validrec;
+
+    GXV_feat_DataRec  featrec;
+    GXV_feat_Data     feat = &featrec;
+
+    FT_Bytes          p     = table;
+    FT_Bytes          limit = 0;
+
+    FT_UInt           featureNameCount;
+
+    FT_Int            i;
+    FT_Int            last_feature;
+
+
+    valid->root       = ftvalid;
+    valid->table_data = feat;
+    valid->face       = face;
+
+    FT_TRACE3(( "validation feat table\n" ));
+    GXV_INIT;
+
+    feat->reserved_size = 0;
+
+    /* version + featureNameCount + none_0 + none_1  */
+    GXV_LIMIT_CHECK( 4 + 2 + 2 + 4 );
+    feat->reserved_size += 4 + 2 + 2 + 4;
+
+    if ( FT_NEXT_ULONG( p ) != 0x00010000UL ) /* Version */
+      FT_INVALID_FORMAT;
+
+    featureNameCount = FT_NEXT_USHORT( p );
+    GXV_TRACE(( " (featureNameCount = %d)\n", featureNameCount ));
+
+    if ( valid->root->level != FT_VALIDATE_PARANOID )
+      p += 6;                   /* skip (none) and (none) */
+    else
+    {
+      if ( FT_NEXT_USHORT( p ) != 0 )
+        FT_INVALID_DATA;
+
+      if ( FT_NEXT_ULONG( p )  != 0 )
+        FT_INVALID_DATA;
+    }
+
+    feat->reserved_size += ( featureNameCount * ( 2 + 2 + 4 + 2 + 2 ) );
+    for( last_feature = -1, i = 0; i < featureNameCount; i++ )
+    {
+      gxv_feat_name_validate( p, limit, valid );
+
+      if ( valid->root->level == FT_VALIDATE_PARANOID &&
+           (FT_Int)GXV_FEAT_DATA( feature ) <= last_feature      )
+        FT_INVALID_FORMAT;
+
+      last_feature = GXV_FEAT_DATA( feature );
+      p += ( 2 + 2 + 4 + 2 + 2 );
+    }
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvfgen.c
@@ -1,0 +1,471 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxfgen.c                                                               */
+/*                                                                         */
+/*    Generate feature registry infomations for gxv feat validator.        */
+/*    This program is derived from gxfeatreg.c in gxlayout.                */
+/*                                                                         */
+/*  Copyright 2004, 2005 by Masatake YAMATO and Redhat K.K.                */
+/*                                                                         */
+/*  This file 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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+/***************************************************************************/
+/*                                                                         */
+/*  gxfeatreg.c                                                            */
+/*                                                                         */
+/*    Database of font features pre-defined by Apple Computer, Inc.        */
+/*    http://developer.apple.com/fonts/Registry/                           */
+/*    (body).                                                              */
+/*                                                                         */
+/*  Copyright 2003 by                                                      */
+/*  Masatake YAMATO and Redhat K.K.                                        */
+/*                                                                         */
+/*  This file 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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+/***************************************************************************/
+/* Development of gxfeatreg.c is support of                                */
+/* Information-technology Promotion Agency, Japan.                         */
+/***************************************************************************/
+
+/***************************************************************************/
+/*                                                                         */
+/* This file is compiled to a standalone executable.                       */
+/* This file is never compiled into `libfreetype2'.                        */
+/* The output of this file is used in `gxvfeat.c'.                         */
+/* ----------------------------------------------------------------------- */
+/* Compile: gcc `pkg-config --cflags freetype2` gxvfgen.c -o gxvfgen       */
+/* Run: ./gxvfgen > tmp.c                                                  */
+/*                                                                         */
+/***************************************************************************/
+
+  /***************************************************************************/
+  /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
+  /***************************************************************************/
+  /*
+   * If you add a new setting to a feature, check the number of setting
+   * in the feature. If the number is greater than value defined as
+   * FEATREG_MAX_SETTING, update the value.
+   */
+#define FEATREG_MAX_SETTING    12
+  /***************************************************************************/
+  /* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING */
+  /***************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      Data and Types                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+#define APPLE_RESERVED         "Apple Reserved"
+#define APPLE_RESERVED_LENGTH  14
+
+  typedef struct  GX_Feature_RegistryRec_
+  {
+    const char*  feat_name;
+    char         exclusive;
+    char*        setting_name [FEATREG_MAX_SETTING];
+
+  } GX_Feature_RegistryRec;
+
+#define EMPTYFEAT {0, 0, {NULL}}
+  static GX_Feature_RegistryRec featreg_table [] = {
+    {                                   /* 0 */
+      "All Typographic Features",
+      0,
+      {
+        "All Type Features",
+        NULL
+      }
+    }, {                                    /* 1 */
+      "Ligatures",
+      0,
+      {
+        "Required Ligatures",
+        "Common Ligatures",
+        "Rare Ligatures",
+        "Logos",
+        "Rebus Pictures",
+        "Diphthong Ligatures",
+        "Squared Ligatures",
+        "Squared Ligatures, Abbreviated",
+        NULL
+      }
+    }, {                                    /* 2 */
+      "Cursive Connection",
+      1,
+      {
+        "Unconnected",
+        "Partially Connected",
+        "Cursive",
+        NULL
+      }
+    }, {                                    /* 3 */
+      "Letter Case",
+      1,
+      {
+        "Upper & Lower Case",
+        "All Caps",
+        "All Lower Case",
+        "Small Caps",
+        "Initial Caps",
+        "Initial Caps & Small Caps",
+        NULL
+      }
+    }, {                                    /* 4 */
+      "Vertical Substitution",
+      0,
+      {
+        /* "Substitute Vertical Forms", */
+        "Turns on the feature",
+        NULL
+      }
+    }, {                                    /* 5 */
+      "Linguistic Rearrangement",
+      0,
+      {
+        /* "Linguistic Rearrangement", */
+        "Turns on the feature",
+        NULL
+      }
+    }, {                                    /* 6 */
+      "Number Spacing",
+      1,
+      {
+        "Monospaced Numbers",
+        "Proportional Numbers",
+        NULL
+      }
+    }, {                                    /* 7 */
+      APPLE_RESERVED " 1",
+      0,
+      {NULL}
+    }, {                                    /* 8 */
+      "Smart Swashes",
+      0,
+      {
+        "Word Initial Swashes",
+        "Word Final Swashes",
+        "Line Initial Swashes",
+        "Line Final Swashes",
+        "Non-Final Swashes",
+        NULL
+      }
+    }, {                                    /* 9 */
+      "Diacritics",
+      1,
+      {
+        "Show Diacritics",
+        "Hide Diacritics",
+        "Decompose Diacritics",
+        NULL
+      }
+    }, {                                    /* 10 */
+      "Vertical Position",
+      1,
+      {
+        /* "Normal Position", */
+        "No Vertical Position",
+        "Superiors",
+        "Inferiors",
+        "Ordinals",
+        NULL
+      }
+    }, {                                    /* 11 */
+      "Fractions",
+      1,
+      {
+        "No Fractions",
+        "Vertical Fractions",
+        "Diagonal Fractions",
+        NULL
+      }
+    }, {                                    /* 12 */
+      APPLE_RESERVED " 2",
+      0,
+      {NULL}
+    }, {                                    /* 13 */
+      "Overlapping Characters",
+      0,
+      {
+        /* "Prevent Overlap", */
+        "Turns on the feature",
+        NULL
+      }
+    }, {                                    /* 14 */
+      "Typographic Extras",
+      0,
+      {
+        "Hyphens to Em Dash",
+        "Hyphens to En Dash",
+        "Unslashed Zero",
+        "Form Interrobang",
+        "Smart Quotes",
+        "Periods to Ellipsis",
+        NULL
+      }
+    }, {                                    /* 15 */
+      "Mathematical Extras",
+      0,
+      {
+        "Hyphens to Minus",
+        "Asterisk to Multiply",
+        "Slash to Divide",
+        "Inequality Ligatures",
+        "Exponents",
+        NULL
+      }
+    }, {                                    /* 16 */
+      "Ornament Sets",
+      1,
+      {
+        "No Ornaments",
+        "Dingbats",
+        "Pi Characters",
+        "Fleurons",
+        "Decorative Borders",
+        "International Symbols",
+        "Math Symbols",
+        NULL
+      }
+    }, {                                    /* 17 */
+      "Character Alternatives",
+      1,
+      {
+        "No Alternates",
+        /* TODO */
+        NULL
+      }
+    }, {                                    /* 18 */
+      "Design Complexity",
+      1,
+      {
+        "Design Level 1",
+        "Design Level 2",
+        "Design Level 3",
+        "Design Level 4",
+        "Design Level 5",
+        /* TODO */
+        NULL
+      }
+    }, {                                    /* 19 */
+      "Style Options",
+      1,
+      {
+        "No Style Options",
+        "Display Text",
+        "Engraved Text",
+        "Illuminated Caps",
+        "Tilling Caps",
+        "Tall Caps",
+        NULL
+      }
+    }, {                                    /* 20 */
+      "Character Shape",
+      1,
+      {
+        "Traditional Characters",
+        "Simplified Characters",
+        "JIS 1978 Characters",
+        "JIS 1983 Characters",
+        "JIS 1990 Characters",
+        "Traditional Characters, Alternative Set 1",
+        "Traditional Characters, Alternative Set 2",
+        "Traditional Characters, Alternative Set 3",
+        "Traditional Characters, Alternative Set 4",
+        "Traditional Characters, Alternative Set 5",
+        "Expert Characters",
+        NULL                           /* count=>12 */
+      }
+    }, {                                    /* 21 */
+      "Number Case",
+      1,
+      {
+        "Lower Case Numbers",
+        "Upper Case Numbers",
+        NULL
+      }
+    }, {                                    /* 22 */
+      "Text Spacing",
+      1,
+      {
+        "Proportional",
+        "Monospaced",
+        "Half-width",
+        "Normal",
+        NULL
+      }
+    }, /* Here after Newer */  { /* 23 */
+      "Transliteration",
+      1,
+      {
+        "No Transliteration",
+        "Hanja To Hangul",
+        "Hiragana to Katakana",
+        "Katakana to Hiragana",
+        "Kana to Romanization",
+        "Romanization to Hiragana",
+        "Romanization to Katakana",
+        "Hanja to Hangul, Alternative Set 1",
+        "Hanja to Hangul, Alternative Set 2",
+        "Hanja to Hangul, Alternative Set 3",
+        NULL
+      }
+    }, {                                    /* 24 */
+      "Annotation",
+      1,
+      {
+        "No Annotation",
+        "Box Annotation",
+        "Rounded Box Annotation",
+        "Circle Annotation",
+        "Inverted Circle Annotation",
+        "Parenthesis Annotation",
+        "Period Annotation",
+        "Roman Numeral Annotation",
+        "Diamond Annotation",
+        NULL
+      }
+    }, {                                    /* 25 */
+      "Kana Spacing",
+      1,
+      {
+        "Full Width",
+        "Proportional",
+        NULL
+      }
+    }, {                                    /* 26 */
+      "Ideographic Spacing",
+      1,
+      {
+        "Full Width",
+        "Proportional",
+        NULL
+      }
+    }, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 27-30 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 31-35 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 36-40 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 40-45 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 46-50 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 51-55 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 56-60 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 61-65 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 66-70 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 71-75 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 76-80 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 81-85 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 86-90 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 91-95 */
+    EMPTYFEAT, EMPTYFEAT, EMPTYFEAT, /* 96-98 */
+    EMPTYFEAT, /* 99 */ { /* 100 => 22*/
+      "Text Spacing",
+      1,
+      {
+        "Proportional",
+        "Monospaced",
+        "Half-width",
+        "Normal",
+        NULL
+      }
+    }, {                                    /* 101 => 25 */
+      "Kana Spacing",
+      1,
+      {
+        "Full Width",
+        "Proportional",
+        NULL
+      }
+    }, {                                    /* 102 => 26 */
+      "Ideographic Spacing",
+      1,
+      {
+        "Full Width",
+        "Proportional",
+        NULL
+      }
+    }, {                                    /* 103 */
+      "CJK Roman Spacing",
+      1,
+      {
+        "Half-width",
+        "Proportional",
+        "Default Roman",
+        "Full-width Roman",
+        NULL
+      }
+    }, {                                    /* 104 => 1 */
+      "All Typographic Features",
+      0,
+      {
+        "All Type Features",
+        NULL
+      }
+    }
+  };
+
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         Generator                             *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  int
+  main( void )
+  {
+    int  i;
+
+
+    printf( "  {\n" );
+    printf( "   /* Generated from %s */\n", __FILE__ );
+
+    for ( i = 0;
+          i < sizeof ( featreg_table ) / sizeof ( GX_Feature_RegistryRec );
+          i++ )
+    {
+      const char*  feat_name;
+      int          nSettings;
+
+      feat_name =  featreg_table[i].feat_name;
+      for ( nSettings = 0;
+            featreg_table[i].setting_name[nSettings];
+            nSettings++)
+        0;                           /* Do nothing */
+
+      printf( "    {%1d, %1d, %1d, %2d},   /* %s */\n",
+              feat_name ? 1 : 0,
+              ( feat_name &&
+                ( strncmp( feat_name, APPLE_RESERVED, APPLE_RESERVED_LENGTH ) == 0 )
+              ) ? 1 : 0,
+              featreg_table[i].exclusive ? 1 : 0,
+              nSettings,
+              feat_name ? feat_name : "__EMPTY__" );
+    }
+
+    printf( "  };\n" );
+
+    return 0;
+  }
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvjust.c
@@ -1,0 +1,588 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvjust.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT just table validation (body).                         */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvalid.h"
+#include "gxvcommn.h"
+
+#include FT_SFNT_NAMES_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_gxvjust
+
+    /*
+     * refered just table format specification:
+     * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6just.html
+     * last update is 2000.
+     * ----------------------------------------------
+     * [JUST HEADER]: GXV_JUST_HEADER_SIZE
+     * version     (fixed:  32bit) = 0x00010000
+     * format      (uint16: 16bit) = 0 is only defined (2000)
+     * horizOffset (uint16: 16bit)
+     * vertOffset  (uint16: 16bit)
+     * ----------------------------------------------
+     */
+  typedef struct  GXV_just_DataRec_
+  {
+    FT_UShort  wdc_offset_max;
+    FT_UShort  wdc_offset_min;
+    FT_UShort  pc_offset_max;
+    FT_UShort  pc_offset_min;
+
+  } GXV_just_DataRec, *GXV_just_Data;
+
+#define  GXV_JUST_DATA( a )  GXV_TABLE_DATA( just, a )
+
+  static void
+  gxv_just_wdp_entry_validate( FT_Bytes       table,
+                               FT_Bytes       limit,
+                               GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_ULong   justClass;
+    FT_Fixed   beforeGrowLimit;
+    FT_Fixed   beforeShrinkGrowLimit;
+    FT_Fixed   afterGrowLimit;
+    FT_Fixed   afterShrinkGrowLimit;
+    FT_UShort  growFlags;
+    FT_UShort  shrinkFlags;
+
+
+    GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 + 4 + 2 + 2 );
+    justClass             = FT_NEXT_ULONG( p );
+    beforeGrowLimit       = FT_NEXT_ULONG( p );
+    beforeShrinkGrowLimit = FT_NEXT_ULONG( p );
+    afterGrowLimit        = FT_NEXT_ULONG( p );
+    afterShrinkGrowLimit  = FT_NEXT_ULONG( p );
+    growFlags             = FT_NEXT_USHORT( p );
+    shrinkFlags           = FT_NEXT_USHORT( p );
+
+    /* TODO: decode flags for human readabilty */
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  static void
+  gxv_just_wdc_entry_validate( FT_Bytes       table,
+                               FT_Bytes       limit,
+                               GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_ULong  count, i;
+
+
+    GXV_LIMIT_CHECK( 4 );
+    count = FT_NEXT_ULONG( p );
+    for ( i = 0; i < count; i++ )
+    {
+      GXV_TRACE(( "validate wdc pair %d/%d\n", i + 1, count ));
+      gxv_just_wdp_entry_validate( p, limit, valid );
+      p += valid->subtable_length;
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+  static void
+  gxv_just_widthDeltaClusters_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes   p         = table ;
+    FT_Bytes   wdc_end   = table + GXV_JUST_DATA( wdc_offset_max );
+    FT_UInt    i;
+
+
+    GXV_NAME_ENTER( "just justDeltaClusters" );
+
+    if ( limit <= wdc_end )
+      FT_INVALID_OFFSET;
+    for ( i = 0; p <= wdc_end; i++ )
+    {
+      gxv_just_wdc_entry_validate( p, limit, valid );
+      p += valid->subtable_length;
+    }
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_just_actSubrecord_type0_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes p = table;
+    FT_Fixed lowerLimit;
+    FT_Fixed upperLimit;
+    FT_UShort order;
+    FT_UShort decomposedCount;
+    FT_UInt i;
+
+
+    GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
+    lowerLimit      = FT_NEXT_ULONG( p );
+    upperLimit      = FT_NEXT_ULONG( p );
+    order           = FT_NEXT_USHORT( p );
+    decomposedCount = FT_NEXT_USHORT( p );
+
+    for ( i = 0; i < decomposedCount; i++ )
+    {
+      FT_UShort glyphs;
+
+
+      GXV_LIMIT_CHECK( 2 );
+      glyphs = FT_NEXT_USHORT( p );
+    }
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  static void
+  gxv_just_actSubrecord_type1_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UShort addGlyph;
+
+
+    GXV_LIMIT_CHECK( 2 );
+    addGlyph = FT_NEXT_USHORT( p );
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  static void
+  gxv_just_actSubrecord_type2_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_Fixed   substThreshhold; /* Apple misspelled "Threshhold" */
+    FT_UShort  addGlyph;
+    FT_UShort  substGlyph;
+
+
+    GXV_LIMIT_CHECK( 4 + 2 + 2 );
+    substThreshhold = FT_NEXT_ULONG( p );
+    addGlyph        = FT_NEXT_USHORT( p );
+    substGlyph      = FT_NEXT_USHORT( p );
+
+    valid->subtable_length = ( p - table );
+  }
+
+  static void
+  gxv_just_actSubrecord_type4_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_ULong  variantsAxis;
+    FT_Fixed  minimumLimit;
+    FT_Fixed  noStretchValue;
+    FT_Fixed  maximumLimit;
+
+
+    GXV_LIMIT_CHECK( 4 + 4 + 4 + 4 );
+    variantsAxis   = FT_NEXT_ULONG( p );
+    minimumLimit   = FT_NEXT_ULONG( p );
+    noStretchValue = FT_NEXT_ULONG( p );
+    maximumLimit   = FT_NEXT_ULONG( p );
+
+    valid->subtable_length = ( p - table );
+  }
+
+  static void
+  gxv_just_actSubrecord_type5_validate( FT_Bytes       table,
+                                        FT_Bytes       limit,
+                                        GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  flags;
+    FT_UShort  glyph;
+
+
+    GXV_LIMIT_CHECK( 2 + 2 );
+    flags = FT_NEXT_USHORT( p );
+    glyph = FT_NEXT_USHORT( p );
+
+    valid->subtable_length = ( p - table );
+  }
+
+
+  /* parse single actSubrecord */
+  static void
+  gxv_just_actSubrecord_validate( FT_Bytes      table,
+                                  FT_Bytes      limit,
+                                  GXV_Validator valid )
+  {
+    FT_Bytes  p = table;
+    FT_UShort actionClass;
+    FT_UShort actionType;
+    FT_ULong  actionLength;
+
+
+    GXV_NAME_ENTER( "just actSubrecord" );
+
+    GXV_LIMIT_CHECK( 2 + 2 + 4 );
+    actionClass  = FT_NEXT_USHORT( p );
+    actionType   = FT_NEXT_USHORT( p );
+    actionLength = FT_NEXT_ULONG( p );
+
+    if ( actionType == 0 )
+      gxv_just_actSubrecord_type0_validate( p, limit, valid );
+    else if ( actionType == 1 )
+      gxv_just_actSubrecord_type1_validate( p, limit, valid );
+    else if ( actionType == 2 )
+      gxv_just_actSubrecord_type2_validate( p, limit, valid );
+    else if ( actionType == 3 )
+      ; /* Stretch glyph action: no actionData */
+    else if ( actionType == 4 )
+      gxv_just_actSubrecord_type4_validate( p, limit, valid );
+    else if ( actionType == 5 )
+      gxv_just_actSubrecord_type5_validate( p, limit, valid );
+    else
+      FT_INVALID_DATA;
+
+    valid->subtable_length = actionLength;
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_just_pcActionRecord_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_ULong  actionCount;
+    FT_ULong  i;
+
+
+    GXV_LIMIT_CHECK( 4 );
+    actionCount = FT_NEXT_ULONG( p );
+    GXV_TRACE(( "actionCount = %d\n", actionCount ));
+
+    for ( i = 0; i < actionCount; i++ )
+    {
+      gxv_just_actSubrecord_validate( p, limit, valid );
+      p += valid->subtable_length;
+    }
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_just_pcTable_LookupValue_entry_validate( FT_UShort            glyph,
+                                               GXV_LookupValueDesc  value,
+                                               GXV_Validator        valid )
+  {
+    if ( value.u > GXV_JUST_DATA( pc_offset_max ) )
+      GXV_JUST_DATA( pc_offset_max ) = value.u;
+    if ( value.u < GXV_JUST_DATA( pc_offset_max ) )
+      GXV_JUST_DATA( pc_offset_min ) = value.u;
+  }
+
+
+  static void
+  gxv_just_pcLookupTable_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    FT_Bytes p = table;
+
+    GXV_NAME_ENTER( "just pcLookupTable" );
+    GXV_JUST_DATA( pc_offset_max ) = 0x0000;
+    GXV_JUST_DATA( pc_offset_min ) = 0xFFFF;
+
+    valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func = gxv_just_pcTable_LookupValue_entry_validate;
+    gxv_LookupTable_validate( p, limit, valid );
+    /* subtable_length is set by gxv_LookupTable_validate() */
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_just_postcompTable_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    FT_Bytes p = table;
+
+
+    GXV_NAME_ENTER( "just postcompTable" );
+
+    gxv_just_pcLookupTable_validate( p, limit, valid );
+    p += valid->subtable_length;
+    gxv_just_pcActionRecord_validate( p, limit, valid );
+    p += valid->subtable_length;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_just_classTable_entry_validate( FT_Byte                         state,
+                                      FT_UShort                       flags,
+                                      GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                      FT_Bytes                        table,
+                                      FT_Bytes                        limit,
+                                      GXV_Validator                   valid )
+  {
+    FT_UShort  setMark;
+    FT_UShort  dontAdvance;
+    FT_UShort  markClass;
+    FT_UShort  currentClass;
+
+
+    setMark      = ( 0x8000 & flags ) / 0x8000;
+    dontAdvance  = ( 0x4000 & flags ) / 0x4000;
+    markClass    = ( 0x3F80 & flags ) / 0x0080;
+    currentClass =   0x007F & flags ;
+    /* TODO: validate markClass & currentClass */
+  }
+
+
+  static void
+  gxv_just_justClassTable_validate ( FT_Bytes       table,
+                                     FT_Bytes       limit,
+                                     GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  length;
+    FT_UShort  coverage;
+    FT_ULong   subFeatureFlags;
+
+
+    GXV_NAME_ENTER( "just justClassTable" );
+
+    GXV_LIMIT_CHECK( 2 + 2 + 4 );
+    length          = FT_NEXT_USHORT( p );
+    coverage        = FT_NEXT_USHORT( p );
+    subFeatureFlags = FT_NEXT_ULONG( p );
+
+    GXV_TRACE(( "  justClassTable: coverage = 0x%04x (%s)", coverage,
+                 (0x4000 & coverage) == 0 ? "ascending" : "descending"
+             ));
+
+    valid->statetable.optdata               = NULL;
+    valid->statetable.optdata_load_func     = NULL;
+    valid->statetable.subtable_setup_func   = NULL;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
+    valid->statetable.entry_validate_func   = gxv_just_classTable_entry_validate;
+    gxv_StateTable_validate( p, table + length, valid );
+    /* subtable_length is set by gxv_LookupTable_validate() */
+    GXV_EXIT;
+
+  }
+
+
+  static void
+  gxv_just_wdcTable_LookupValue_validate( FT_UShort            glyph,
+                                          GXV_LookupValueDesc  value,
+                                          GXV_Validator        valid )
+  {
+    if ( value.u > GXV_JUST_DATA( wdc_offset_max ) )
+      GXV_JUST_DATA( wdc_offset_max ) = value.u;
+    if ( value.u < GXV_JUST_DATA( wdc_offset_min ) )
+      GXV_JUST_DATA( wdc_offset_min ) = value.u;
+  }
+
+
+  static void
+  gxv_just_justData_lookuptable_validate( FT_Bytes       table,
+                                          FT_Bytes       limit,
+                                          GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+
+
+    GXV_JUST_DATA( wdc_offset_max ) = 0x0000;
+    GXV_JUST_DATA( wdc_offset_min ) = 0xFFFF;
+    valid->lookupval_sign = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func = gxv_just_wdcTable_LookupValue_validate;
+    gxv_LookupTable_validate( p, limit, valid );
+    /* subtable_length is set by gxv_LookupTable_validate() */
+    GXV_EXIT;
+  }
+
+
+  /*
+   * gxv_just_justData_validate() parses and validates horizData, vertData.
+   */
+  static void
+  gxv_just_justData_validate ( FT_Bytes       table,
+                               FT_Bytes       limit,
+                               GXV_Validator  valid )
+  {
+    /* following 3 offsets are measured from the start of just
+     * which table points to), not justData
+     */
+    FT_UShort  justClassTableOffset;
+    FT_UShort  wdcTableOffset;
+    FT_UShort  pcTableOffset;
+    FT_Bytes   p = table;
+    GXV_ODTECT( 4, odtect );
+
+
+    GXV_NAME_ENTER( "just justData" );
+
+    GXV_ODTECT_INIT( odtect );
+    GXV_LIMIT_CHECK( 2 + 2 + 2 );
+    justClassTableOffset = FT_NEXT_USHORT( p );
+    wdcTableOffset       = FT_NEXT_USHORT( p );
+    pcTableOffset        = FT_NEXT_USHORT( p );
+
+    GXV_TRACE(( " (justClassTableOffset = 0x%04x)\n", justClassTableOffset ));
+    GXV_TRACE(( " (wdcTableOffset = 0x%04x)\n", wdcTableOffset ));
+    GXV_TRACE(( " (pcTableOffset = 0x%04x)\n", pcTableOffset ));
+
+
+    gxv_just_justData_lookuptable_validate( p, limit, valid );
+    gxv_odtect_add_range( p, valid->subtable_length, "just_LookupTable", odtect );
+
+    if ( wdcTableOffset )
+    {
+      gxv_just_widthDeltaClusters_validate( valid->root->base + wdcTableOffset,
+                                            limit, valid );
+      gxv_odtect_add_range( valid->root->base + wdcTableOffset,
+                            valid->subtable_length, "just_wdcTable", odtect );
+    }
+
+    if ( pcTableOffset )
+    {
+      gxv_just_postcompTable_validate( valid->root->base + pcTableOffset,
+                                       limit, valid );
+      gxv_odtect_add_range( valid->root->base + pcTableOffset,
+                            valid->subtable_length, "just_pcTable", odtect );
+    }
+
+    if ( justClassTableOffset )
+    {
+      gxv_just_justClassTable_validate( valid->root->base + justClassTableOffset,
+                                        limit, valid );
+      gxv_odtect_add_range( valid->root->base + justClassTableOffset,
+                            valid->subtable_length, "just_justClassTable", odtect );
+    }
+
+    gxv_odtect_validate( odtect, valid );
+
+    GXV_EXIT;
+  }
+
+
+  FT_LOCAL_DEF( void )
+  gxv_just_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  ftvalid )
+  {
+    FT_Bytes           p     = table;
+    FT_Bytes           limit = 0;
+    FT_UInt            table_size;
+
+    GXV_ValidatorRec   validrec;
+    GXV_Validator      valid = &validrec;
+    GXV_just_DataRec   justrec;
+    GXV_just_Data      just = &justrec;
+
+    FT_ULong           version;
+    FT_UShort          format;
+    FT_UShort          horizOffset;
+    FT_UShort          vertOffset;
+
+    GXV_ODTECT( 3, odtect );
+
+
+    GXV_ODTECT_INIT( odtect );
+
+    valid->root       = ftvalid;
+    valid->table_data = just;
+    valid->face       = face;
+
+    FT_TRACE3(( "validation just table\n" ));
+    GXV_INIT;
+
+    limit      = valid->root->limit;
+    table_size = limit - table;
+    GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 );
+    version     = FT_NEXT_ULONG( p );
+    format      = FT_NEXT_USHORT( p );
+    horizOffset = FT_NEXT_USHORT( p );
+    vertOffset  = FT_NEXT_USHORT( p );
+    gxv_odtect_add_range( table, p - table, "just header", odtect );
+
+
+    /* Version 1.0 (always:2000) */
+    GXV_TRACE(( " (version = 0x%08x)\n", version ));
+    if ( version != 0x00010000UL )
+      FT_INVALID_FORMAT;
+
+    /* format 0 (always:2000) */
+    GXV_TRACE(( " (format = 0x%04x)\n", format ));
+    if ( format != 0x0000 )
+        FT_INVALID_FORMAT;
+
+    GXV_TRACE(( " (horizOffset = %d)\n", horizOffset  ));
+    GXV_TRACE(( " (vertOffset = %d)\n", vertOffset  ));
+
+
+    /* validate justData */
+    if ( 0 < horizOffset )
+    {
+      gxv_just_justData_validate( table + horizOffset, limit, valid );
+      gxv_odtect_add_range( table + horizOffset, valid->subtable_length,
+                            "horizJustData", odtect );
+    }
+
+    if ( 0 < vertOffset )
+    {
+      gxv_just_justData_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 */
--- /dev/null
+++ b/src/gxvalid/gxvkern.c
@@ -1,0 +1,801 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvkern.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT kern 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#include "gxvalid.h"
+#include "gxvcommn.h"
+
+#include FT_SFNT_NAMES_H
+#include FT_SERVICE_GX_VALIDATE_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_gxvkern
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      Data and Types                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef enum GXV_kern_Version_
+  {
+    KERN_VERSION_CLASSIC = 0x0000,
+    KERN_VERSION_NEW     = 0x0001
+
+  } GXV_kern_Version;
+
+  typedef enum GXV_kern_Dialect_
+  {
+    KERN_DIALECT_MS      = FT_VALIDATE_MS,
+    KERN_DIALECT_APPLE   = FT_VALIDATE_APPLE,
+    KERN_DIALECT_ANY     = FT_VALIDATE_CKERN
+
+  } GXV_kern_Dialect;
+
+  typedef struct  GXV_kern_DataRec_
+  {
+    GXV_kern_Version  version;
+    void             *subtable_data;
+    GXV_kern_Dialect  dialect_request;
+
+  } GXV_kern_DataRec, *GXV_kern_Data;
+
+#define GXV_KERN_DATA( field )    GXV_TABLE_DATA( kern, field )
+
+#define KERN_IS_CLASSIC( valid )  ( KERN_VERSION_CLASSIC == GXV_KERN_DATA( version ) )
+#define KERN_IS_NEW( valid )      ( KERN_VERSION_NEW     == GXV_KERN_DATA( version ) )
+
+#define KERN_DIALECT( valid )        GXV_KERN_DATA( dialect_request )
+#define KERN_ALLOWS_MS( valid )      ( KERN_DIALECT( valid ) & KERN_DIALECT_MS )
+#define KERN_ALLOWS_APPLE( valid )   ( KERN_DIALECT( valid ) & KERN_DIALECT_APPLE )
+
+#define GXV_KERN_HEADER_SIZE      ( KERN_IS_NEW( valid ) ? 8 : 4 )
+#define GXV_KERN_SUBTABLE_HEADER_SIZE  ( KERN_IS_NEW( valid ) ? 8 : 6 )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      SUBTABLE VALIDATORS                      *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  /* ============================= format 0 ============================== */
+
+
+  static void
+  gxv_kern_subtable_fmt0_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
+
+    FT_UShort  nPairs;
+    FT_UShort  unitSize;
+    FT_UShort  i;
+
+
+    GXV_NAME_ENTER("kern subtable format0");
+
+    unitSize = ( 2 + 2 + 2 );
+    nPairs   = 0;
+
+    /* nPairs, searchRange, entrySelector, rangeShift */
+    GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
+    gxv_BinSrchHeader_validate( p, limit, &unitSize, &nPairs, valid );
+    p += 2 + 2 + 2 + 2;
+
+    for ( i = 0; i < nPairs; i++ )
+    {
+      FT_UShort  gid_left;
+      FT_UShort  gid_right;
+      FT_Short   kernValue;
+      /* TODO: should be checked pairs are unique. */
+
+      /* left */
+      gid_left  = FT_NEXT_USHORT( p );
+      gxv_glyphid_validate( gid_left, valid );
+
+      /* right */
+      gid_right = FT_NEXT_USHORT( p );
+      gxv_glyphid_validate( gid_right, valid );
+
+      /* skip the kern value */
+      kernValue = FT_NEXT_SHORT( p );
+    }
+
+    GXV_EXIT;
+  }
+
+
+  /* ============================= format 1 ============================== */
+
+
+  typedef struct  GXV_kern_fmt1_StateOptRec_
+  {
+    FT_UShort  valueTable;
+    FT_UShort  valueTable_length;
+
+  } GXV_kern_fmt1_StateOptRec, *GXV_kern_fmt1_StateOptRecData;
+
+
+  static void
+  gxv_kern_subtable_fmt1_valueTable_load( FT_Bytes       table,
+                                          FT_Bytes       limit,
+                                          GXV_Validator  valid )
+  {
+    FT_Bytes                       p = table;
+    GXV_kern_fmt1_StateOptRecData  optdata = valid->statetable.optdata;
+
+    GXV_LIMIT_CHECK( 2 );
+    optdata->valueTable = FT_NEXT_USHORT( p );
+  }
+
+
+  /*
+   * passed tables_size covers whole StateTable, including kern fmt1 header
+   */
+  static void
+  gxv_kern_subtable_fmt1_subtable_setup( FT_UShort      table_size,
+                                         FT_UShort      classTable,
+                                         FT_UShort      stateArray,
+                                         FT_UShort      entryTable,
+                                         FT_UShort*     classTable_length_p,
+                                         FT_UShort*     stateArray_length_p,
+                                         FT_UShort*     entryTable_length_p,
+                                         GXV_Validator  valid )
+  {
+    FT_UShort  o[4];
+    FT_UShort  *l[4];
+    FT_UShort  buff[5];
+    GXV_kern_fmt1_StateOptRecData  optdata = valid->statetable.optdata;
+
+
+    o[0] = classTable;
+    o[1] = stateArray;
+    o[2] = entryTable;
+    o[3] = optdata->valueTable;
+    l[0] = classTable_length_p;
+    l[1] = stateArray_length_p;
+    l[2] = entryTable_length_p;
+    l[3] = &(optdata->valueTable_length);
+
+    gxv_set_length_by_ushort_offset( o, l, buff, 4, table_size, valid );
+  }
+
+
+  /*
+   * passed table & limit are of whole of StateTable, not included subtables.
+   */
+  static void
+  gxv_kern_subtable_fmt1_entry_validate( FT_Byte                         state,
+                                         FT_UShort                       flags,
+                                         GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                         FT_Bytes                        table,
+                                         FT_Bytes                        limit,
+                                         GXV_Validator                   valid )
+  {
+    FT_UShort push;
+    FT_UShort dontAdvance;
+    FT_UShort valueOffset;
+    FT_UShort kernAction;
+    FT_UShort kernValue;
+
+    push        =   flags / 0x8000;
+    dontAdvance = ( flags & 0x4000 ) / 0x4000;
+    valueOffset =   flags & 0x3FFF;
+
+    {
+      GXV_kern_fmt1_StateOptRecData vt_rec = valid->statetable.optdata;
+      FT_Bytes  p;
+
+      if ( valueOffset < vt_rec->valueTable )
+        FT_INVALID_OFFSET;
+
+      p     = table + valueOffset;
+      limit = table + vt_rec->valueTable + vt_rec->valueTable_length;
+
+      GXV_LIMIT_CHECK( 2 + 2 );
+      kernAction = FT_NEXT_USHORT( p );
+      kernValue  = FT_NEXT_USHORT( p );
+    }
+  }
+
+
+  static void
+  gxv_kern_subtable_fmt1_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    FT_Bytes p = table;
+    GXV_kern_fmt1_StateOptRec        vt_rec;
+
+    GXV_NAME_ENTER("kern subtable format1");
+
+    valid->statetable.optdata               = &vt_rec;
+    valid->statetable.optdata_load_func     = gxv_kern_subtable_fmt1_valueTable_load;
+    valid->statetable.subtable_setup_func   = gxv_kern_subtable_fmt1_subtable_setup;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
+    valid->statetable.entry_validate_func   = gxv_kern_subtable_fmt1_entry_validate;
+    gxv_StateTable_validate( p, limit, valid );
+
+    GXV_EXIT;
+  }
+
+  /* ================ Data for Class-Based Subtables 2, 3 ================ */
+
+
+  typedef enum GXV_kern_ClassSpec_
+  {
+    GXV_KERN_CLS_L = 0,
+    GXV_KERN_CLS_R
+  } GXV_kern_ClassSpec;
+
+
+  /* ============================= format 2 ============================== */
+
+  /* ---------------------- format 2 specific data ----------------------- */
+
+  typedef struct  GXV_kern_subtable_fmt2_DataRec_
+  {
+    FT_UShort   rowWidth;
+    FT_UShort   array;
+    FT_UShort   offset_min[2];
+    FT_UShort   offset_max[2];
+    FT_String*  class_tag[2];
+    GXV_odtect_Range  odtect;
+
+  } GXV_kern_subtable_fmt2_DataRec, *GXV_kern_subtable_fmt2_Data;
+
+#define GXV_KERN_FMT2_DATA( field ) \
+  (((GXV_kern_subtable_fmt2_DataRec *)(GXV_KERN_DATA( subtable_data )))-> field )
+
+  /* -------------------------- utility functions ----------------------- */
+
+
+  static void
+  gxv_kern_subtable_fmt2_clstbl_validate( FT_Bytes            table,
+                                          FT_Bytes            limit,
+                                          GXV_kern_ClassSpec  spec,
+                                          GXV_Validator       valid )
+  {
+    FT_String*        tag    = GXV_KERN_FMT2_DATA( class_tag[spec] );
+    GXV_odtect_Range  odtect = GXV_KERN_FMT2_DATA( odtect );
+
+    FT_Bytes   p = table;
+    FT_UShort  firstGlyph;
+    FT_UShort  nGlyphs;
+
+
+    GXV_NAME_ENTER(( "kern format 2 classTable" ));
+
+
+    GXV_LIMIT_CHECK( 2 + 2 );
+    firstGlyph = FT_NEXT_USHORT( p );
+    nGlyphs    = FT_NEXT_USHORT( p );
+    GXV_TRACE(( " %s firstGlyph=%d, nGlyphs=%d\n", tag, firstGlyph, nGlyphs ));
+
+
+    gxv_glyphid_validate( firstGlyph, valid );
+    gxv_glyphid_validate( firstGlyph + nGlyphs - 1, valid );
+
+
+    gxv_array_getlimits_ushort( p, p + ( 2 * nGlyphs ),
+                                &( GXV_KERN_FMT2_DATA( offset_min[spec] ) ),
+                                &( GXV_KERN_FMT2_DATA( offset_max[spec] ) ),
+                                valid );
+
+
+    gxv_odtect_add_range( table, ( 2 * nGlyphs ), tag, odtect );
+
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_kern_subtable_fmt2_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    GXV_ODTECT( 3, odtect );
+    GXV_kern_subtable_fmt2_DataRec  fmt2_rec =
+      { 0, 0, { 0, 0 }, { 0, 0 }, { "leftClass", "rightClass" }, NULL };
+
+    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
+    FT_UShort  leftOffsetTable;
+    FT_UShort  rightOffsetTable;
+
+
+    GXV_NAME_ENTER("kern subtable format2");
+
+    GXV_ODTECT_INIT( odtect );
+    fmt2_rec.odtect = odtect;
+    GXV_KERN_DATA( subtable_data ) = &fmt2_rec;
+
+    GXV_LIMIT_CHECK( 2 + 2 + 2 + 2 );
+    GXV_KERN_FMT2_DATA( rowWidth ) = FT_NEXT_USHORT( p );
+    leftOffsetTable                = FT_NEXT_USHORT( p );
+    rightOffsetTable               = FT_NEXT_USHORT( p );
+    GXV_KERN_FMT2_DATA( array )    = FT_NEXT_USHORT( p );
+
+    GXV_TRACE(( "rowWidth = %d\n", GXV_KERN_FMT2_DATA( rowWidth ) ));
+
+
+    GXV_LIMIT_CHECK( leftOffsetTable );
+    GXV_LIMIT_CHECK( rightOffsetTable );
+    GXV_LIMIT_CHECK( GXV_KERN_FMT2_DATA( array ) );
+
+
+    gxv_kern_subtable_fmt2_clstbl_validate( table + leftOffsetTable, limit,
+                                            GXV_KERN_CLS_L, valid );
+
+
+    gxv_kern_subtable_fmt2_clstbl_validate( table + rightOffsetTable, limit,
+                                            GXV_KERN_CLS_R, valid );
+
+    if ( GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_L] )
+         + GXV_KERN_FMT2_DATA( offset_min[GXV_KERN_CLS_R] )
+         < GXV_KERN_FMT2_DATA( array ) )
+      FT_INVALID_OFFSET;
+
+
+    gxv_odtect_add_range( table + GXV_KERN_FMT2_DATA( array ),
+                          GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_L] )
+                            + GXV_KERN_FMT2_DATA( offset_max[GXV_KERN_CLS_R] )
+                            - GXV_KERN_FMT2_DATA( array ),
+                          "array", odtect );
+
+    gxv_odtect_validate( odtect, valid );
+
+    GXV_EXIT;
+  }
+
+
+  /* ============================= format 3 ============================== */
+
+
+  static void
+  gxv_kern_subtable_fmt3_validate( FT_Bytes       table,
+                                   FT_Bytes       limit,
+                                   GXV_Validator  valid )
+  {
+    FT_Bytes   p = table + GXV_KERN_SUBTABLE_HEADER_SIZE;
+    FT_UShort  glyphCount;
+    FT_Byte    kernValueCount;
+    FT_Byte    leftClassCount;
+    FT_Byte    rightClassCount;
+    FT_Byte    flags;
+
+
+    GXV_NAME_ENTER("kern subtable format3");
+
+    GXV_LIMIT_CHECK( 2 + 1 + 1 + 1 + 1 );
+    glyphCount      = FT_NEXT_USHORT( p );
+    kernValueCount  = FT_NEXT_BYTE( p );
+    leftClassCount  = FT_NEXT_BYTE( p );
+    rightClassCount = FT_NEXT_BYTE( p );
+    flags           = FT_NEXT_BYTE( p );
+
+
+    if ( valid->face->num_glyphs != glyphCount )
+    {
+      GXV_TRACE(( "maxGID=%d, but glyphCount=%d\n", valid->face->num_glyphs, glyphCount ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_GLYPH_ID;
+    }
+
+
+    /*
+     * Just skip kernValue[kernValueCount]
+     */
+    GXV_LIMIT_CHECK( 2 * kernValueCount );
+    p += ( 2 * kernValueCount );
+
+
+    /*
+     * check leftClass[gid] < leftClassCount
+     */
+    {
+      FT_Byte  min, max;
+
+      GXV_LIMIT_CHECK( glyphCount );
+      gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
+      p += valid->subtable_length;
+
+      if ( leftClassCount < max )
+        FT_INVALID_DATA;
+    }
+
+
+    /*
+     * check rightClass[gid] < rightClassCount
+     */
+    {
+      FT_Byte  min, max;
+
+      GXV_LIMIT_CHECK( glyphCount );
+      gxv_array_getlimits_byte( p, p + glyphCount, &min, &max, valid );
+      p += valid->subtable_length;
+
+      if ( rightClassCount < max )
+        FT_INVALID_DATA;
+    }
+
+
+    /*
+     * check kernIndex[i, j] < kernValueCount
+     */
+    {
+      FT_UShort  i, j;
+      for ( i = 0; i < leftClassCount; i ++ )
+      {
+        for ( j = 0; j < rightClassCount; j ++ )
+        {
+          GXV_LIMIT_CHECK( 1 );
+          if ( kernValueCount < FT_NEXT_BYTE( p ) )
+            FT_INVALID_OFFSET;
+        }
+      }
+    }
+
+    valid->subtable_length = ( p - table );
+
+    GXV_EXIT;
+  }
+
+
+  static FT_Bool
+  gxv_kern_coverage_new_apple_validate( FT_UShort      coverage,
+                                        FT_UShort*     format,
+                                        GXV_Validator  valid )
+  {
+    /* new Apple-dialect */
+    FT_Bool  kernVertical;
+    FT_Bool  kernCrossStream;
+    FT_Bool  kernVariation;
+
+
+    /* reserved bits = 0 */
+    if ( coverage & 0x1FFC )
+      return FALSE;
+
+
+    kernVertical    = ( coverage >> 15 ) & 1;
+    kernCrossStream = ( coverage >> 14 ) & 1;
+    kernVariation   = ( coverage >> 13 ) & 1;
+    *format         =   coverage & 0x0003;
+
+    GXV_TRACE(( "new Apple-dialect: "
+                "horizontal=%d, cross-stream=%d, variation=%d, format=%d\n",
+                 !kernVertical, kernCrossStream, kernVariation, *format ));
+
+    GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
+    return TRUE;
+  }
+
+
+  static FT_Bool
+  gxv_kern_coverage_classic_apple_validate( FT_UShort      coverage,
+                                            FT_UShort*     format,
+                                            GXV_Validator  valid )
+  {
+    /* classic Apple-dialect */
+    FT_Bool  horizontal;
+    FT_Bool  cross_stream;
+
+
+    /* expected flags but don't check if MS-dialect is impossible */
+    if ( !( coverage & 0xFD00 ) && KERN_ALLOWS_MS( valid ) )
+      return FALSE;
+
+    /* reserved bits = 0 */
+    if ( coverage & 0x02FC )
+      return FALSE;
+
+
+    horizontal   = ( coverage >> 15 ) & 1;
+    cross_stream = ( coverage >> 13 ) & 1;
+    *format      =   coverage & 0x0003;
+
+    GXV_TRACE(( "classic Apple-dialect: "
+                "horizontal=%d, cross-stream=%d, format=%d\n",
+                 horizontal, cross_stream, *format ));
+
+    /* format1 requires GX State Machine, too new for classic */
+    if ( *format == 1 )
+      return FALSE;
+
+    GXV_TRACE(( "kerning values in Apple format subtable are ignored\n" ));
+    return TRUE;
+  }
+
+
+  static FT_Bool
+  gxv_kern_coverage_classic_microsoft_validate( FT_UShort      coverage,
+                                                FT_UShort*     format,
+                                                GXV_Validator  valid )
+  {
+    /* classic Microsoft-dialect */
+    FT_Bool  horizontal;
+    FT_Bool  minimum;
+    FT_Bool  cross_stream;
+    FT_Bool  override;
+
+    /* reserved bits = 0 */
+    if ( coverage & 0xFDF0 )
+      return FALSE;
+
+    horizontal   =   coverage & 1;
+    minimum      = ( coverage >> 1 ) & 1;
+    cross_stream = ( coverage >> 2 ) & 1;
+    override     = ( coverage >> 3 ) & 1;
+    *format      = ( coverage >> 8 ) & 0x0003;
+
+    GXV_TRACE(( "classic Microsoft-dialect: "
+                "horizontal=%d, minimum=%d, cross-stream=%d, override=%d, format=%d\n",
+                 horizontal, minimum, cross_stream, override, *format ));
+
+    if ( *format == 2 )
+      GXV_TRACE(( "kerning values in Microsoft format 2 subtable are ignored\n" ));
+
+    return TRUE;
+  }
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                            MAIN                               *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+
+  static GXV_kern_Dialect
+  gxv_kern_coverage_validate ( FT_UShort      coverage,
+                               FT_UShort*     format,
+                               GXV_Validator  valid )
+  {
+    FT_Int result = 0;
+
+
+    GXV_NAME_ENTER(( "validate coverage" ));
+
+    GXV_TRACE(( "interprete coverage 0x%04x by Apple style\n", coverage ));
+
+    if ( KERN_IS_NEW( valid ) )
+    {
+      if ( gxv_kern_coverage_new_apple_validate( coverage,
+                                                 format,
+                                                 valid ) )
+      {
+        result = KERN_DIALECT_APPLE;
+        goto Exit;
+      }
+    }
+
+    if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_APPLE( valid ) )
+    {
+      if ( gxv_kern_coverage_classic_apple_validate( coverage,
+                                                     format,
+                                                     valid ) )
+      {
+        result = KERN_DIALECT_APPLE;
+        goto Exit;
+      }
+    }
+
+    if ( KERN_IS_CLASSIC( valid ) && KERN_ALLOWS_MS( valid ) )
+    {
+      if ( gxv_kern_coverage_classic_microsoft_validate( coverage,
+                                                         format,
+                                                         valid ) )
+      {
+        result = KERN_DIALECT_MS;
+        goto Exit;
+      }
+    }
+
+    GXV_TRACE(( "cannot interprete coverage, broken kern subtable\n" ));
+
+  Exit:
+    GXV_EXIT;
+    return result;
+  }
+
+  static void
+  gxv_kern_subtable_validate( FT_Bytes       table,
+                              FT_Bytes       limit,
+                              GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  version = 0;    /* MS only: subtable version, unused */
+    FT_ULong   length;         /* MS: 16bit, Apple: 32bit*/
+    FT_UShort  coverage;
+    FT_UShort  tupleIndex = 0; /* Apple only */
+    FT_UShort  u16[2];
+    FT_UShort  format = 255;   /* subtable format */
+
+
+    GXV_NAME_ENTER("kern subtable");
+
+    GXV_LIMIT_CHECK( 2 + 2 + 2 );
+    u16[0]   = FT_NEXT_USHORT( p ); /* Apple: length_hi MS: version */
+    u16[1]   = FT_NEXT_USHORT( p ); /* Apple: length_lo MS: length */
+    coverage = FT_NEXT_USHORT( p );
+
+    switch ( gxv_kern_coverage_validate( coverage, &format, valid ) )
+    {
+      case KERN_DIALECT_MS:
+        version    = u16[0];
+        length     = u16[1];
+        tupleIndex = 0;
+        GXV_TRACE(( "Subtable version = %d\n", version ));
+        GXV_TRACE(( "Subtable length = %d\n", length ));
+        break;
+      case KERN_DIALECT_APPLE:
+        version    = 0;
+        length     = ( u16[0] << 16 ) + u16[1];
+        tupleIndex = 0;
+        GXV_TRACE(( "Subtable length = %d\n", length ));
+
+        if ( KERN_IS_NEW( valid ))
+        {
+          GXV_LIMIT_CHECK( 2 );
+          tupleIndex = FT_NEXT_USHORT( p );
+          GXV_TRACE(( "Subtable tupleIndex = %d\n", tupleIndex ));
+        }
+        break;
+      default:
+        length = u16[1];
+        GXV_TRACE(( "cannot detect subtable dialect, "
+                    "just skip %d byte\n", length ));
+        goto Exit;
+    }
+
+    /* fmt1, 2, 3 requires the position of the start of this subtable */
+    if ( format == 0 )
+      gxv_kern_subtable_fmt0_validate( table, table + length, valid );
+    else if ( format == 1 )
+      gxv_kern_subtable_fmt1_validate( table, table + length, valid );
+    else if ( format == 2 )
+      gxv_kern_subtable_fmt2_validate( table, table + length, valid );
+    else if ( format == 3 )
+      gxv_kern_subtable_fmt3_validate( table, table + length, valid );
+    else
+      FT_INVALID_DATA;
+
+  Exit:
+    valid->subtable_length = length;
+    GXV_EXIT;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                         kern TABLE                            *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  gxv_kern_validate_generic( FT_Bytes          table,
+                             FT_Face           face,
+                             FT_Bool           classic_only,
+                             GXV_kern_Dialect  dialect_request,
+                             FT_Validator      ftvalid )
+  {
+    GXV_ValidatorRec   validrec;
+    GXV_Validator      valid = &validrec;
+
+    GXV_kern_DataRec   kernrec;
+    GXV_kern_Data      kern = &kernrec;
+
+    FT_Bytes           p     = table;
+    FT_Bytes           limit = 0;
+
+    FT_ULong           nTables = 0;
+    FT_UInt            i;
+
+
+    valid->root       = ftvalid;
+    valid->table_data = kern;
+    valid->face       = face;
+
+    FT_TRACE3(( "validation kern table\n" ));
+    GXV_INIT;
+    KERN_DIALECT( valid ) = dialect_request;
+
+    GXV_LIMIT_CHECK( 2 );
+    GXV_KERN_DATA( version ) = FT_NEXT_USHORT( p );
+    GXV_TRACE(( "version 0x%04x (higher 16bit)\n", GXV_KERN_DATA( version ) ));
+
+    if ( 0x0001 < GXV_KERN_DATA( version ) )
+      FT_INVALID_FORMAT;
+    else if ( KERN_IS_CLASSIC( valid ) )
+    {
+      GXV_LIMIT_CHECK( 2 );
+      nTables = FT_NEXT_USHORT( p );
+    }
+    else if ( KERN_IS_NEW( valid ) )
+    {
+      if ( classic_only )
+        FT_INVALID_FORMAT;
+
+      if ( 0x0000 != FT_NEXT_USHORT( p ) )
+        FT_INVALID_FORMAT;
+
+      GXV_LIMIT_CHECK( 4 );
+      nTables = FT_NEXT_ULONG( p );
+    }
+
+
+    for ( i = 0; i < nTables; i++ )
+    {
+      GXV_TRACE(( "validate subtable %d/%d\n", i, nTables ));
+      /* p should be 32bit-aligned? */
+      gxv_kern_subtable_validate( p, 0, valid );
+      p += valid->subtable_length;
+    }
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+  FT_LOCAL_DEF( void )
+  gxv_kern_validate( FT_Bytes      table,
+                     FT_Face       face,
+                     FT_Validator  ftvalid )
+  {
+    gxv_kern_validate_generic( table, face, 0, KERN_DIALECT_ANY, ftvalid );
+  }
+
+
+  FT_LOCAL_DEF( void )
+  gxv_kern_validate_classic( FT_Bytes      table,
+                             FT_Face       face,
+                             FT_Int        dialect_flags,
+                             FT_Validator  ftvalid )
+  {
+    GXV_kern_Dialect dialect_request;
+
+
+    dialect_request = dialect_flags;
+    gxv_kern_validate_generic( table, face, 1, dialect_request, ftvalid );
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvlcar.c
@@ -1,0 +1,217 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvlcar.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT lcar table validation (body).                         */
+/*                                                                         */
+/*  Copyright 2004 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 was support of 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_gxvlcar
+
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      Data and Types                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  typedef struct  GXV_lcar_DataRec_
+  {
+    FT_UShort  format;
+
+  } GXV_lcar_DataRec, *GXV_lcar_Data;
+
+#define  GXV_LCAR_DATA(FIELD)  GXV_TABLE_DATA( lcar, FIELD )
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      UTILITY FUNCTIONS                        *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  static void
+  gxv_lcar_partial_validate( FT_UShort      partial,
+                             FT_UShort      glyph,
+                             GXV_Validator  valid )
+  {
+    GXV_NAME_ENTER( "partial" );
+
+    if ( GXV_LCAR_DATA( format ) != 1 )
+      goto Exit;
+
+    gxv_ctlPoint_validate( glyph, partial, valid );
+
+  Exit:
+    GXV_EXIT;
+  }
+
+
+  static void
+  gxv_lcar_LookupValue_validate( FT_UShort            glyph,
+                                 GXV_LookupValueDesc  value,
+                                 GXV_Validator        valid )
+  {
+    FT_Bytes      p     = valid->root->base + value.u;
+    FT_Bytes      limit = valid->root->limit;
+    FT_UShort     count;
+    FT_Short      partial;
+    unsigned int  i;
+
+
+    GXV_NAME_ENTER( "element in lookupTable" );
+
+
+    GXV_LIMIT_CHECK( 2 );
+    count = FT_NEXT_USHORT( p );
+
+    GXV_LIMIT_CHECK( 2 * count );
+    for ( i = 0; i < count; i++ )
+    {
+      partial = FT_NEXT_SHORT( p );
+      gxv_lcar_partial_validate( partial, glyph, valid );
+    }
+
+    GXV_EXIT;
+  }
+
+  /*
+    +------ lcar --------------------+
+    |                                |
+    |      +===============+         |
+    |      | looup header  |         |
+    |      +===============+         |
+    |      | BinSrchHeader |         |
+    |      +===============+         |
+    |      | lastGlyph[0]  |         |
+    |      +---------------+         |
+    |      | firstGlyph[0] |         |  head of lcar sfnt table
+    |      +---------------+         |             +
+    |      | offset[0]     |    ->   |          offset            [byte]
+    |      +===============+         |             +
+    |      | lastGlyph[1]  |         | (glyphID - firstGlyph) * 2 [byte]
+    |      +---------------+         |
+    |      | firstGlyph[1] |         |
+    |      +---------------+         |
+    |      | offset[1]     |         |
+    |      +===============+         |
+    |                                |
+    |       ....                     |
+    |                                |
+    |      16bit value array         |
+    |      +===============+         |
+    +------|     value     | <-------+
+    |       ....
+    |
+    |
+    |
+    |
+    |
+    +---->  lcar values...handled by lcar callback function */
+
+  static GXV_LookupValueDesc
+  gxv_lcar_LookupFmt4_transit( FT_UShort            relative_gindex,
+                               GXV_LookupValueDesc  base_value,
+                               FT_Bytes             lookuptbl_limit,
+                               GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+
+    offset = base_value.u + ( relative_gindex * sizeof ( FT_UShort ) );
+    p      = valid->root->base + offset;
+    limit  = valid->root->limit;
+
+    GXV_LIMIT_CHECK ( 2 );
+    value.u = FT_NEXT_USHORT( p );
+
+    return value;
+  }
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                          lcar TABLE                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+  FT_LOCAL_DEF( void )
+  gxv_lcar_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_lcar_DataRec  lcarrec;
+    GXV_lcar_Data     lcar = &lcarrec;
+
+    FT_Fixed          version;
+
+
+    valid->root       = ftvalid;
+    valid->table_data = lcar;
+    valid->face       = face;
+
+    FT_TRACE3(( "validation lcar table\n" ));
+    GXV_INIT;
+
+    GXV_LIMIT_CHECK( 4 + 2 );
+    version = FT_NEXT_ULONG( p );
+    GXV_LCAR_DATA( format ) = FT_NEXT_USHORT( p );
+
+    if ( version != 0x00010000)
+      FT_INVALID_FORMAT;
+
+    if ( GXV_LCAR_DATA( format ) > 1 )
+      FT_INVALID_FORMAT;
+
+
+    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func   = gxv_lcar_LookupValue_validate;
+    valid->lookupfmt4_trans = gxv_lcar_LookupFmt4_transit;
+    gxv_LookupTable_validate( p, limit, valid );
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmod.c
@@ -1,0 +1,274 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmod.c                                                               */
+/*                                                                         */
+/*    FreeType's TrueTypeGX/AAT validation module implementation (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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#include <ft2build.h>
+#include FT_TRUETYPE_TABLES_H
+#include FT_TRUETYPE_TAGS_H
+#include FT_GX_VALIDATE_H
+#include FT_INTERNAL_OBJECTS_H
+#include FT_SERVICE_GX_VALIDATE_H
+
+#include "gxvmod.h"
+#include "gxvalid.h"
+#include "gxvcommn.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmodule
+
+
+  static FT_Error
+  gxv_load_table( FT_Face    face,
+                  FT_Tag     tag,
+                  FT_Byte**  table,
+                  FT_ULong*  table_len )
+  {
+    FT_Error   error;
+    FT_Memory  memory = FT_FACE_MEMORY( face );
+
+
+    error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len );
+    if ( error == GXV_Err_Table_Missing )
+      return GXV_Err_Ok;
+    if ( error )
+      goto Exit;
+
+    if ( FT_ALLOC( *table, *table_len ) )
+      goto Exit;
+
+    error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len );
+
+  Exit:
+    return error;
+  }
+
+#define GXV_TABLE_DECL( _sfnt )                 \
+        FT_Byte * _sfnt      = NULL;            \
+        FT_ULong  len_##_sfnt = 0
+
+#define GXV_TABLE_LOAD( _sfnt )                                         \
+        if ( ( FT_VALIDATE_##_sfnt##_INDEX < table_count ) &&           \
+             ( gx_flags & FT_VALIDATE_##_sfnt              )  )         \
+        {                                                               \
+          error = gxv_load_table( face, TTAG_##_sfnt, &_sfnt, &len_##_sfnt ); \
+          if ( error )                                                  \
+            goto Exit;                                                  \
+        }
+
+#define GXV_TABLE_VALIDATE( _sfnt )                                     \
+        if ( _sfnt )                                                    \
+        {                                                               \
+          ft_validator_init( &valid, _sfnt, _sfnt + len_##_sfnt, FT_VALIDATE_DEFAULT ); \
+          if ( ft_validator_run( &valid ) == 0 )                    \
+            gxv_##_sfnt##_validate( _sfnt, face, &valid );              \
+          error = valid.error;                                          \
+          if ( error )                                                  \
+            goto Exit;                                                  \
+        }
+
+#define GXV_TABLE_SET( _sfnt )                                     \
+        if ( FT_VALIDATE_##_sfnt##_INDEX < table_count )           \
+          tables[FT_VALIDATE_##_sfnt##_INDEX] = (FT_Bytes)_sfnt
+
+  static FT_Error
+  gxv_validate( FT_Face    face,
+                FT_UInt    gx_flags,
+                FT_Bytes   tables[FT_VALIDATE_GX_LENGTH],
+                FT_UInt    table_count )
+  {
+    FT_Memory        memory = FT_FACE_MEMORY( face );
+
+    FT_Error         error = GXV_Err_Ok;
+    FT_ValidatorRec  valid;
+
+    int i;
+
+
+    GXV_TABLE_DECL( feat );
+    GXV_TABLE_DECL( bsln );
+    GXV_TABLE_DECL( trak );
+    GXV_TABLE_DECL( just );
+    GXV_TABLE_DECL( mort );
+    GXV_TABLE_DECL( morx );
+    GXV_TABLE_DECL( kern );
+    GXV_TABLE_DECL( opbd );
+    GXV_TABLE_DECL( prop );
+    GXV_TABLE_DECL( lcar );
+
+
+    for ( i = 0; i < table_count; i++ )
+      tables[i] = 0;
+
+    /* load tables */
+    GXV_TABLE_LOAD( feat );
+    GXV_TABLE_LOAD( bsln );
+    GXV_TABLE_LOAD( trak );
+    GXV_TABLE_LOAD( just );
+    GXV_TABLE_LOAD( mort );
+    GXV_TABLE_LOAD( morx );
+    GXV_TABLE_LOAD( kern );
+    GXV_TABLE_LOAD( opbd );
+    GXV_TABLE_LOAD( prop );
+    GXV_TABLE_LOAD( lcar );
+
+
+    /* validate tables */
+    GXV_TABLE_VALIDATE( feat );
+    GXV_TABLE_VALIDATE( bsln );
+    GXV_TABLE_VALIDATE( trak );
+    GXV_TABLE_VALIDATE( just );
+    GXV_TABLE_VALIDATE( mort );
+    GXV_TABLE_VALIDATE( morx );
+    GXV_TABLE_VALIDATE( kern );
+    GXV_TABLE_VALIDATE( opbd );
+    GXV_TABLE_VALIDATE( prop );
+    GXV_TABLE_VALIDATE( lcar );
+
+    /* Set results */
+    GXV_TABLE_SET( feat );
+    GXV_TABLE_SET( mort );
+    GXV_TABLE_SET( morx );
+    GXV_TABLE_SET( bsln );
+    GXV_TABLE_SET( just );
+    GXV_TABLE_SET( kern );
+    GXV_TABLE_SET( opbd );
+    GXV_TABLE_SET( trak );
+    GXV_TABLE_SET( prop );
+    GXV_TABLE_SET( lcar );
+
+  Exit:
+    if ( error )
+    {
+      FT_FREE( feat );
+      FT_FREE( bsln );
+      FT_FREE( trak );
+      FT_FREE( just );
+      FT_FREE( mort );
+      FT_FREE( morx );
+      FT_FREE( kern );
+      FT_FREE( opbd );
+      FT_FREE( prop );
+      FT_FREE( lcar );
+    }
+    return error;
+  }
+
+
+  static FT_Error
+  classic_kern_validate( FT_Face    face,
+                         FT_UInt    ckern_flags,
+                         FT_Bytes*  ckern_table )
+  {
+    FT_Memory        memory = FT_FACE_MEMORY( face );
+
+    FT_Byte*         ckern     = NULL;
+    FT_ULong         len_ckern = 0;
+
+    FT_Error         error = GXV_Err_Ok;
+    FT_ValidatorRec  valid;
+
+
+    *ckern_table = NULL;
+
+    error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern );
+    if ( error )
+      goto Exit;
+
+    if ( ckern )
+    {
+      ft_validator_init( &valid, ckern, ckern + len_ckern, FT_VALIDATE_DEFAULT );
+      if ( ft_validator_run( &valid ) == 0 )
+        gxv_kern_validate_classic( ckern, face,
+                                   ckern_flags & FT_VALIDATE_CKERN, &valid );
+      error = valid.error;
+      if ( error )
+        goto Exit;
+    }
+
+    *ckern_table = ckern;
+
+  Exit:
+    if ( error )
+      FT_FREE( ckern );
+
+    return error;
+  }
+
+  static
+  const FT_Service_GXvalidateRec  gxvalid_interface =
+  {
+    gxv_validate
+  };
+
+
+  static
+  const FT_Service_CKERNvalidateRec  ckernvalid_interface =
+  {
+    classic_kern_validate
+  };
+
+
+  static
+  const FT_ServiceDescRec  gxvalid_services[] =
+  {
+    { FT_SERVICE_ID_GX_VALIDATE,  &gxvalid_interface },
+    { FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface },
+    { NULL, NULL }
+  };
+
+
+  static FT_Pointer
+  gxvalid_get_service( FT_Module    module,
+                       const char*  service_id )
+  {
+    FT_UNUSED( module );
+
+    return ft_service_list_lookup( gxvalid_services, service_id );
+  }
+
+
+  FT_CALLBACK_TABLE_DEF
+  const FT_Module_Class  gxv_module_class =
+  {
+    0,
+    sizeof( FT_ModuleRec ),
+    "gxvalid",
+    0x10000L,
+    0x20000L,
+
+    0,              /* module-specific interface */
+
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  gxvalid_get_service
+  };
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmod.h
@@ -1,0 +1,45 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmod.h                                                               */
+/*                                                                         */
+/*    FreeType's TrueTypeGX/AAT validation module implementation           */
+/*    (specification).                                                     */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#ifndef __GXVMOD_H__
+#define __GXVMOD_H__
+
+
+#include <ft2build.h>
+#include FT_MODULE_H
+
+
+FT_BEGIN_HEADER
+
+
+  FT_EXPORT_VAR( const FT_Module_Class )  gxv_module_class;
+
+
+FT_END_HEADER
+
+#endif /* Not def: __GXVMOD_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort.c
@@ -1,0 +1,267 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort table validation (body).                         */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+
+#include "gxvmort.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+  static void
+  gxv_mort_feature_validate( GXV_mort_feature  f,
+                             GXV_Validator     valid )
+  {
+    if ( f->featureType > gxv_feat_registry_length )
+    {
+      GXV_TRACE(( "featureType %d is out of registered range, "
+                  "setting %d is unchecked\n",
+                   f->featureType, f->featureSetting ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+    }
+    else if ( !gxv_feat_registry[f->featureType].existence )
+    {
+      GXV_TRACE(( "featureType %d is within registered area "
+                  "but undefined, setting %d is unchecked\n",
+                   f->featureType, f->featureSetting ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+    }
+    else
+    {
+      FT_Byte  nSettings_max;
+
+      /* nSettings in gxvfeat.c is halved for exclusive on/off settings */
+      if ( gxv_feat_registry[f->featureType].exclusive )
+        nSettings_max = 2 * gxv_feat_registry[f->featureType].nSettings;
+      else
+        nSettings_max = gxv_feat_registry[f->featureType].nSettings;
+
+      GXV_TRACE(( "featureType %d is registered", f->featureType ));
+      GXV_TRACE(( "setting %d", f->featureSetting ));
+      if ( f->featureSetting > nSettings_max )
+      {
+        GXV_TRACE(( "out of defined range %d", nSettings_max ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_DATA;
+      }
+      GXV_TRACE(( "\n" ));
+    }
+
+    /* TODO: enableFlags must be unique value in specified chain?  */
+  }
+
+  /*
+   * nFeatureFlags is typed to FT_UInt to accept that in
+   * mort (typed FT_UShort) and morx (typed FT_ULong).
+   */
+  static void
+  gxv_mort_featurearray_validate( FT_Bytes       table,
+                                  FT_Bytes       limit,
+                                  FT_UInt        nFeatureFlags,
+                                  GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    FT_UInt   i;
+    GXV_mort_featureRec  f = GXV_MORT_FEATURE_OFF;
+
+
+    GXV_NAME_ENTER( "mort feature list" );
+    for ( i = 0; i < nFeatureFlags; i++ )
+    {
+      GXV_LIMIT_CHECK( 2 + 2 + 4 + 4 );
+      f.featureType    = FT_NEXT_USHORT( p );
+      f.featureSetting = FT_NEXT_USHORT( p );
+      f.enableFlags    = FT_NEXT_ULONG( p );
+      f.disableFlags   = FT_NEXT_ULONG( p );
+
+      gxv_mort_feature_validate( &f, valid );
+    }
+
+    if ( !IS_GXV_MORT_FEATURE_OFF(f) )
+      FT_INVALID_DATA;
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+  static void
+  gxv_mort_coverage_validate( FT_UShort      coverage,
+                              GXV_Validator  valid )
+  {
+    if ( coverage & 0x8000 )
+      GXV_TRACE(( " this subtable is for vertical text only\n" ));
+    else
+      GXV_TRACE(( " this subtable is for horizontal text only\n" ));
+
+    if ( coverage & 0x4000 )
+      GXV_TRACE(( " this subtable is applied to glyph array in descending order\n" ));
+    else
+      GXV_TRACE(( " this subtable is applied to glyph array in ascending order\n" ));
+
+    if ( coverage & 0x2000 )
+      GXV_TRACE(( " this subtable is forcibly applied to vertical/horizontal text\n" ));
+
+    if ( coverage & 0x1FF8 )
+      GXV_TRACE(( " coverage has non-zero bits in reserved area\n" ));
+  }
+
+
+  static void
+  gxv_mort_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_mort_subtable_type0_validate, /* 0 */
+      gxv_mort_subtable_type1_validate, /* 1 */
+      gxv_mort_subtable_type2_validate, /* 2 */
+      NULL,                             /* 3 */
+      gxv_mort_subtable_type4_validate, /* 4 */
+      gxv_mort_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_UShort  length;
+      FT_UShort  coverage;
+      FT_ULong   subFeatureFlags;
+      FT_UInt    type;
+      FT_UInt    rest;
+
+
+      GXV_LIMIT_CHECK( 2 + 2 + 4 );
+      length          = FT_NEXT_USHORT( p );
+      coverage        = FT_NEXT_USHORT( p );
+      subFeatureFlags = FT_NEXT_ULONG( p );
+
+      GXV_TRACE(( "validate chain subtable %d/%d (%d bytes)\n",
+                                  i + 1, nSubtables, length ));
+      type = coverage & 0x0007;
+      rest = length - ( 2 + 2 + 4 );
+
+      GXV_LIMIT_CHECK( rest );
+      gxv_mort_coverage_validate( 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_mort_chain_validate( FT_Bytes       table,
+                           FT_Bytes       limit,
+                           GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_ULong   defaultFlags;
+    FT_ULong   chainLength;
+    FT_UShort  nFeatureFlags;
+    FT_UShort  nSubtables;
+
+
+    GXV_NAME_ENTER( "mort chain header" );
+
+    GXV_LIMIT_CHECK( 4 + 4 + 2 + 2 );
+    defaultFlags  = FT_NEXT_ULONG( p );
+    chainLength   = FT_NEXT_ULONG( p );
+    nFeatureFlags = FT_NEXT_USHORT( p );
+    nSubtables    = FT_NEXT_USHORT( p );
+
+    gxv_mort_featurearray_validate( p, table + chainLength, nFeatureFlags, valid );
+    p += valid->subtable_length;
+    gxv_mort_subtables_validate( p, table + chainLength, nSubtables, valid );
+    valid->subtable_length = chainLength;
+
+    GXV_EXIT;
+  }
+
+  FT_LOCAL_DEF( void )
+  gxv_mort_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;
+    limit       = valid->root->limit;
+
+    FT_TRACE3(( "validation mort table\n" ));
+    GXV_INIT;
+
+    GXV_LIMIT_CHECK( 4 + 4 );
+    version = FT_NEXT_ULONG( p );
+    nChains = FT_NEXT_ULONG( p );
+
+    if (version != 0x00010000)
+      FT_INVALID_FORMAT;
+
+    for ( i = 0; i < nChains; i++ )
+    {
+      GXV_TRACE(( "validate chain %d/%d\n", i + 1, nChains ));
+      GXV_32BIT_ALIGNMENT_VALIDATE( p - table );
+      gxv_mort_chain_validate( p, limit, valid );
+      p += valid->subtable_length;
+    }
+
+    FT_TRACE4(( "\n" ));
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort.h
@@ -1,0 +1,96 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort.h                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT common definition for mort table (specification).     */
+/*                                                                         */
+/*  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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#ifndef __GXVMORT_H__
+#define __GXVMORT_H__
+
+
+#include "gxvalid.h"
+#include "gxvcommn.h"
+
+#include FT_SFNT_NAMES_H
+
+
+  typedef struct  GXV_mort_featureRec_
+  {
+    FT_UShort featureType;
+    FT_UShort featureSetting;
+    FT_ULong  enableFlags;
+    FT_ULong  disableFlags;
+
+  } GXV_mort_featureRec, *GXV_mort_feature;
+
+#define GXV_MORT_FEATURE_OFF \
+  {0, 1, 0x00000000UL, 0x00000000UL}
+
+#define IS_GXV_MORT_FEATURE_OFF( f )            \
+        ( (f).featureType    == 0            || \
+          (f).featureSetting == 1            || \
+          (f).enableFlags    == 0x00000000UL || \
+          (f).disableFlags   == 0x00000000UL )
+
+
+  FT_LOCAL( void )
+  gxv_mort_feature_validate( GXV_mort_feature  f,
+                             GXV_Validator     valid );
+
+  FT_LOCAL( void )
+  gxv_mort_featurearray_validate( FT_Bytes       table,
+                                  FT_Bytes       limit,
+                                  FT_UInt        nFeatureFlags,
+                                  GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_coverage_validate( FT_UShort      coverage,
+                              GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_subtable_type0_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_subtable_type1_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_subtable_type2_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_subtable_type4_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid );
+
+  FT_LOCAL( void )
+  gxv_mort_subtable_type5_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid );
+
+
+#endif /* Not def: __GXVMORT_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort0.c
@@ -1,0 +1,122 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort0.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvmort.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+  static char* GXV_Mort_IndicScript_Msg [] =
+  {
+    "no change",
+    "Ax => xA",
+    "xD => Dx",
+    "AxD => DxA",
+    "ABx => xAB",
+    "ABx => xBA",
+    "xCD => CDx",
+    "xCD => DCx",
+    "AxCD => CDxA",
+    "AxCD => DCxA",
+    "ABxD => DxAB",
+    "ABxD => DxBA",
+    "ABxCD => CDxAB",
+    "ABxCD => CDxBA",
+    "ABxCD => DCxAB",
+    "ABxCD => DCxBA",
+
+  };
+
+
+  static void
+  gxv_mort_subtable_type0_entry_validate( FT_Byte                          state,
+                                          FT_UShort                        flags,
+                                          GXV_StateTable_GlyphOffsetDesc   glyphOffset,
+                                          FT_Bytes                         table,
+                                          FT_Bytes                         limit,
+                                          GXV_Validator                    valid )
+  {
+    FT_UShort markFirst;
+    FT_UShort dontAdvance;
+    FT_UShort markLast;
+    FT_UShort reserved;
+    FT_UShort verb;
+
+
+    markFirst   =   flags / 0x8000;
+    dontAdvance = ( flags & 0x4000 ) / 0x4000;
+    markLast    = ( flags & 0x2000 ) / 0x2000;
+    reserved    =   flags & 0x1FF0;
+    verb        =   flags & 0x000F;
+
+    FT_UNUSED( GXV_Mort_IndicScript_Msg[verb] );
+
+    GXV_TRACE(( "  IndicScript MorphRule for glyphOffset 0x%04x", glyphOffset.u ));
+    GXV_TRACE(( " markFirst=%01d", markFirst ));
+    GXV_TRACE(( " dontAdvance=%01d", dontAdvance ));
+    GXV_TRACE(( " markLast=%01d", markLast ));
+    GXV_TRACE(( " %02d", verb ));
+    GXV_TRACE(( " %s\n", GXV_Mort_IndicScript_Msg[verb] ));
+    if ( 0 < reserved )
+    {
+      GXV_TRACE(( " non-zero bits found in reserved range\n" ));
+      FT_INVALID_DATA;
+    }
+    else
+    {
+      GXV_TRACE(( "\n" ));
+    }
+  }
+
+  static void
+  gxv_mort_subtable_type0_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    GXV_NAME_ENTER( "mort chain subtable type0 (Indic-Script Rearrangement)" );
+
+    GXV_LIMIT_CHECK( GXV_STATETABLE_HEADER_SIZE );
+
+    valid->statetable.optdata               = NULL;
+    valid->statetable.optdata_load_func     = NULL;
+    valid->statetable.subtable_setup_func   = NULL;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
+    valid->statetable.entry_validate_func   = gxv_mort_subtable_type0_entry_validate;
+    gxv_StateTable_validate( p, limit, valid );
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort1.c
@@ -1,0 +1,226 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort1.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort table validation                                 */
+/*    body for type1 (Contextual 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvmort.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+  typedef struct  GXV_mort_subtable_type1_StateOptRec_
+  {
+    FT_UShort  substitutionTable;
+    FT_UShort  substitutionTable_length;
+
+  }  GXV_mort_subtable_type1_StateOptRec,
+    *GXV_mort_subtable_type1_StateOptRecData;
+
+#define  GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE ( GXV_STATETABLE_HEADER_SIZE + 2 )
+
+  static void
+  gxv_mort_subtable_type1_substitutionTable_load( FT_Bytes       table,
+                                                  FT_Bytes       limit,
+                                                  GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    GXV_mort_subtable_type1_StateOptRecData  optdata = valid->statetable.optdata;
+
+
+    GXV_LIMIT_CHECK( 2 );
+    optdata->substitutionTable = FT_NEXT_USHORT( p );
+  }
+
+
+  static void
+  gxv_mort_subtable_type1_subtable_setup( FT_UShort      table_size,
+                                          FT_UShort      classTable,
+                                          FT_UShort      stateArray,
+                                          FT_UShort      entryTable,
+                                          FT_UShort*     classTable_length_p,
+                                          FT_UShort*     stateArray_length_p,
+                                          FT_UShort*     entryTable_length_p,
+                                          GXV_Validator  valid )
+  {
+    FT_UShort  o[4];
+    FT_UShort  *l[4];
+    FT_UShort  buff[5];
+    GXV_mort_subtable_type1_StateOptRecData  optdata = valid->statetable.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_ushort_offset( o, l, buff, 4, table_size, valid );
+  }
+
+
+  static void
+  gxv_mort_subtable_type1_offset_to_subst_validate( FT_Short       wordOffset,
+                                                    FT_String*     tag,
+                                                    FT_Byte        state,
+                                                    GXV_Validator  valid )
+  {
+    FT_UShort  substTable;
+    FT_UShort  substTable_limit;
+    FT_UShort  min_gid;
+    FT_UShort  max_gid;
+
+    substTable       = ((GXV_mort_subtable_type1_StateOptRec *)
+                        (valid->statetable.optdata))->substitutionTable;
+    substTable_limit = substTable +
+                       ((GXV_mort_subtable_type1_StateOptRec *)
+                        (valid->statetable.optdata))->substitutionTable_length;
+
+    min_gid = ( substTable       - ( wordOffset * 2 ) ) / 2;
+    max_gid = ( substTable_limit - ( wordOffset * 2 ) ) / 2;
+    max_gid = FT_MAX( max_gid, valid->face->num_glyphs );
+
+    /* TODO: min_gid & max_gid comparison with ClassTable contents */
+  }
+
+
+  static void
+  gxv_mort_subtable_type1_entry_validate( FT_Byte                         state,
+                                          FT_UShort                       flags,
+                                          GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                          FT_Bytes                        table,
+                                          FT_Bytes                        limit,
+                                          GXV_Validator                   valid )
+  {
+    FT_UShort setMark;
+    FT_UShort dontAdvance;
+    FT_UShort reserved;
+    FT_Short  markOffset;
+    FT_Short  currentOffset;
+
+
+    setMark     =   flags / 0x8000;
+    dontAdvance = ( flags & 0x4000 ) / 0x4000;
+    reserved    =   flags & 0x3FFF;
+    markOffset    = GXV_USHORT_TO_SHORT( glyphOffset.ul / 0x00010000 );
+    currentOffset = GXV_USHORT_TO_SHORT( glyphOffset.ul & 0x0000FFFF );
+
+    if ( 0 < reserved )
+    {
+      GXV_TRACE(( " non-zero bits found in reserved range\n" ));
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_DATA;
+    }
+
+    gxv_mort_subtable_type1_offset_to_subst_validate( markOffset,
+                                                      "markOffset",
+                                                      state,
+                                                      valid );
+
+    gxv_mort_subtable_type1_offset_to_subst_validate( currentOffset,
+                                                      "currentOffset",
+                                                      state,
+                                                      valid );
+  }
+
+  static void
+  gxv_mort_subtable_type1_substTable_validate( FT_Bytes       table,
+                                               FT_Bytes       limit,
+                                               GXV_Validator  valid )
+  {
+    FT_Bytes   p = table;
+    FT_UShort  num_gids = ((GXV_mort_subtable_type1_StateOptRec *)
+                           (valid->statetable.optdata))->substitutionTable_length
+                          / 2;
+    FT_UShort  i;
+
+
+    GXV_NAME_ENTER(( "validate contents in substitionTable" ));
+    for ( i = 0; i < num_gids ; i ++ )
+    {
+      FT_UShort  dst_gid;
+
+
+      GXV_LIMIT_CHECK( 2 );
+      dst_gid = FT_NEXT_USHORT( p );
+
+      if ( dst_gid >= 0xFFFF )
+        continue;
+
+      if ( dst_gid > valid->face->num_glyphs )
+      {
+        GXV_TRACE(( "substTable include too-large gid[%d]=%d > max defined gid #%d\n",
+                     i, dst_gid, valid->face->num_glyphs ));
+        if ( valid->root->level >= FT_VALIDATE_PARANOID )
+          FT_INVALID_GLYPH_ID;
+      }
+    }
+
+    GXV_EXIT;
+  }
+
+  /*
+   * subtable for Contextual glyph substition is modified StateTable.
+   * In addition classTable, stateArray, entryTable, "substitutionTable"
+   * is added.
+   */
+  static void
+  gxv_mort_subtable_type1_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    GXV_mort_subtable_type1_StateOptRec  st_rec;
+
+
+    GXV_NAME_ENTER( "mort chain subtable type1 (Contextual Glyph Subst)" );
+
+    GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE1_HEADER_SIZE );
+
+    valid->statetable.optdata               = &st_rec;
+    valid->statetable.optdata_load_func     = gxv_mort_subtable_type1_substitutionTable_load;
+    valid->statetable.subtable_setup_func   = gxv_mort_subtable_type1_subtable_setup;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_ULONG;
+    valid->statetable.entry_validate_func   = gxv_mort_subtable_type1_entry_validate;
+    gxv_StateTable_validate( p, limit, valid );
+
+    gxv_mort_subtable_type1_substTable_validate( table
+                                                   + st_rec.substitutionTable,
+                                                 table
+                                                   + st_rec.substitutionTable
+                                                   + st_rec.substitutionTable_length,
+                                                 valid );
+
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort2.c
@@ -1,0 +1,243 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort2.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort table validation                                 */
+/*    body for type2 (Ligature Substitution) subtable.                     */
+/*                                                                         */
+/*  Copyright 2005 by suzuki toshiya, Masatake YAMATO, Red Hat K.K.,       */
+/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
+/*                                                                         */
+/*  This file is part of the FreeType project, and may only be used,       */
+/*  modified, and distributed under the terms of the FreeType project      */
+/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
+/*  this file you indicate that you have read the license and              */
+/*  understand and accept it fully.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+/***************************************************************************/
+/* gxvalid is derived from both gxlayout module and otvalid module.        */
+/* Development of gxlayout was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvmort.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+  typedef struct  GXV_mort_subtable_type2_StateOptRec_
+  {
+    FT_UShort  ligActionTable;
+    FT_UShort  componentTable;
+    FT_UShort  ligatureTable;
+    FT_UShort  ligActionTable_length;
+    FT_UShort  componentTable_length;
+    FT_UShort  ligatureTable_length;
+
+  }  GXV_mort_subtable_type2_StateOptRec,
+    *GXV_mort_subtable_type2_StateOptRecData;
+
+  #define  GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE ( GXV_STATETABLE_HEADER_SIZE + 2 + 2 + 2 )
+
+  static void
+  gxv_mort_subtable_type2_opttable_load( FT_Bytes       table,
+                                         FT_Bytes       limit,
+                                         GXV_Validator  valid )
+  {
+    FT_Bytes p = table;
+    GXV_mort_subtable_type2_StateOptRecData  optdata = valid->statetable.optdata;
+
+
+    GXV_LIMIT_CHECK( 2 + 2 + 2 );
+    optdata->ligActionTable = FT_NEXT_USHORT( p );
+    optdata->componentTable = FT_NEXT_USHORT( p );
+    optdata->ligatureTable  = FT_NEXT_USHORT( p );
+
+    GXV_TRACE(( "offset to ligActionTable=0x%04x\n", optdata->ligActionTable ));
+    GXV_TRACE(( "offset to componentTable=0x%04x\n", optdata->componentTable ));
+    GXV_TRACE(( "offset to ligatureTable=0x%04x\n",  optdata->ligatureTable ));
+  }
+
+  static void
+  gxv_mort_subtable_type2_subtable_setup( FT_UShort      table_size,
+                                          FT_UShort      classTable,
+                                          FT_UShort      stateArray,
+                                          FT_UShort      entryTable,
+                                          FT_UShort      *classTable_length_p,
+                                          FT_UShort      *stateArray_length_p,
+                                          FT_UShort      *entryTable_length_p,
+                                          GXV_Validator  valid )
+  {
+    FT_UShort  o[6];
+    FT_UShort  *l[6];
+    FT_UShort  buff[7];
+    GXV_mort_subtable_type2_StateOptRecData  optdata = valid->statetable.optdata;
+
+
+    GXV_NAME_ENTER( "subtable boundaries setup" );
+
+    o[0] = classTable;
+    o[1] = stateArray;
+    o[2] = entryTable;
+    o[3] = optdata->ligActionTable;
+    o[4] = optdata->componentTable;
+    o[5] = optdata->ligatureTable;
+    l[0] = classTable_length_p;
+    l[1] = stateArray_length_p;
+    l[2] = entryTable_length_p;
+    l[3] = &(optdata->ligActionTable_length);
+    l[4] = &(optdata->componentTable_length);
+    l[5] = &(optdata->ligatureTable_length);
+
+    gxv_set_length_by_ushort_offset( o, l, buff, 6, table_size, valid );
+
+    GXV_TRACE(( "classTable: offset=0x%04x length=0x%04x\n",
+                             classTable, *classTable_length_p));
+    GXV_TRACE(( "stateArray: offset=0x%04x length=0x%04x\n",
+                             stateArray, *stateArray_length_p));
+    GXV_TRACE(( "entryTable: offset=0x%04x length=0x%04x\n",
+                             entryTable, *entryTable_length_p));
+    GXV_TRACE(( "ligActionTable: offset=0x%04x length=0x%04x\n",
+                                 optdata->ligActionTable,
+                                 optdata->ligActionTable_length));
+    GXV_TRACE(( "componentTable: offset=0x%04x length=0x%04x\n",
+                                 optdata->componentTable,
+                                 optdata->componentTable_length));
+    GXV_TRACE(( "ligatureTable:  offset=0x%04x length=0x%04x\n",
+                                 optdata->ligatureTable,
+                                 optdata->ligatureTable_length));
+    GXV_EXIT;
+  }
+
+
+
+  static void
+  gxv_mort_subtable_type2_ligActionOffset_validate( FT_Bytes       table,
+                                                    FT_UShort      ligActionOffset,
+                                                    GXV_Validator  valid )
+  {
+    /* access ligActionTable */
+    GXV_mort_subtable_type2_StateOptRecData optdata = valid->statetable.optdata;
+    FT_Bytes lat_base  = table + optdata->ligActionTable;
+    FT_Bytes p         = table + ligActionOffset;
+    FT_Bytes lat_limit = lat_base + optdata->ligActionTable;
+
+
+    GXV_32BIT_ALIGNMENT_VALIDATE( ligActionOffset );
+    if ( p < lat_base )
+    {
+      GXV_TRACE(( "too short offset 0x%04x: p < lat_base (%d byte rewind)\n",
+                   ligActionOffset, lat_base - p ));
+
+      /* FontValidator, ftxvalidator, ftxdumperfuser warns but continues */
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_OFFSET;
+    }
+    else if ( lat_limit < p )
+    {
+      GXV_TRACE(( "too large offset 0x%04x: lat_limit < p (%d byte overrun)\n",
+                   ligActionOffset, p - lat_limit ));
+
+      /* FontValidator, ftxvalidator, ftxdumperfuser warns but continues */
+      if ( valid->root->level >= FT_VALIDATE_PARANOID )
+        FT_INVALID_OFFSET;
+    }
+    else
+    {
+      /* validate entry in ligActionTable */
+      FT_ULong   lig_action;
+      FT_UShort  last;
+      FT_UShort  store;
+      FT_ULong   offset;
+
+
+      lig_action = FT_NEXT_ULONG( p );
+      last   = (lig_action & 0x80000000) / 0x80000000;
+      store  = (lig_action & 0x40000000) / 0x40000000;
+      offset =  lig_action & 0x3FFFFFFF;
+    }
+  }
+
+  static void
+  gxv_mort_subtable_type2_entry_validate( FT_Byte                         state,
+                                          FT_UShort                       flags,
+                                          GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                          FT_Bytes                        table,
+                                          FT_Bytes                        limit,
+                                          GXV_Validator                   valid )
+  {
+    FT_UShort setComponent;
+    FT_UShort dontAdvance;
+    FT_UShort offset;
+
+
+    setComponent  = ( flags & 0x8000 ) / 0x8000;
+    dontAdvance   = ( flags & 0x4000 ) / 0x4000;
+    offset        =   flags & 0x3FFF;
+
+    if ( 0 < offset )
+      gxv_mort_subtable_type2_ligActionOffset_validate( table, offset, valid );
+  }
+
+  static void
+  gxv_mort_subtable_type2_ligatureTable_validate( FT_Bytes       table,
+                                                  GXV_Validator  valid )
+  {
+    GXV_mort_subtable_type2_StateOptRecData optdata = valid->statetable.optdata;
+    FT_Bytes p     = table + optdata->ligatureTable;
+    FT_Bytes limit = table + optdata->ligatureTable
+                           + optdata->ligatureTable_length;
+
+    GXV_NAME_ENTER( "mort chain subtable type2 - substitutionTable" );
+    if ( 0 != optdata->ligatureTable )
+    {
+      /* Apple does not give specification of ligatureTable format */
+      while ( p < limit )
+      {
+        FT_UShort  lig_gid;
+
+
+        GXV_LIMIT_CHECK( 2 );
+        lig_gid = FT_NEXT_USHORT( p );
+      }
+    }
+    GXV_EXIT;
+  }
+
+  static void
+  gxv_mort_subtable_type2_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    GXV_mort_subtable_type2_StateOptRec  lig_rec;
+
+
+    GXV_NAME_ENTER( "mort chain subtable type2 (Ligature Substitution)" );
+
+    GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE2_HEADER_SIZE );
+
+    valid->statetable.optdata               = &lig_rec;
+    valid->statetable.optdata_load_func     = gxv_mort_subtable_type2_opttable_load;
+    valid->statetable.subtable_setup_func   = gxv_mort_subtable_type2_subtable_setup;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_NONE;
+    valid->statetable.entry_validate_func   = gxv_mort_subtable_type2_entry_validate;
+    gxv_StateTable_validate( p, limit, valid );
+    p += valid->subtable_length;
+    gxv_mort_subtable_type2_ligatureTable_validate( table, valid );
+
+    valid->subtable_length = ( p - table );
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort4.c
@@ -1,0 +1,113 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort4.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort table validation                                 */
+/*    body for 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvmort.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+  static void
+  gxv_mort_subtable_type4_lookupval_validate( FT_UShort            glyph,
+                                              GXV_LookupValueDesc  value,
+                                              GXV_Validator        valid )
+  {
+    gxv_glyphid_validate( value.u, 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_mort_subtable_type4_lookupfmt4_transit( FT_UShort            relative_gindex,
+                                              GXV_LookupValueDesc  base_value,
+                                              FT_Bytes             lookuptbl_limit,
+                                              GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+
+    offset = base_value.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;
+  }
+
+  static void
+  gxv_mort_subtable_type4_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+
+
+    GXV_NAME_ENTER( "mort chain subtable type4 (Non-Contextual Glyph Substitution)" );
+
+    valid->lookupval_sign   = GXV_LOOKUPVALUE_UNSIGNED;
+    valid->lookupval_func   = gxv_mort_subtable_type4_lookupval_validate;
+    valid->lookupfmt4_trans = gxv_mort_subtable_type4_lookupfmt4_transit;
+    gxv_LookupTable_validate( p, limit, valid );
+
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmort5.c
@@ -1,0 +1,200 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmort5.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT mort table validation                                 */
+/*    body for type5 (Contextual Glyph Insertion) 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 was support of Information-technology Promotion */
+/* Agency(IPA), Japan.                                                     */
+/***************************************************************************/
+
+#include "gxvmort.h"
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_gxvmort
+
+
+/*
+ * mort subtable type5 (Contextual Glyph Insertion)
+ * has format of StateTable with insertion-glyph-list
+ * without name. the offset is given by glyphOffset in
+ * entryTable. there's no table location declaration
+ * like xxxTable.
+ */
+
+  typedef struct  GXV_mort_subtable_type5_StateOptRec_
+  {
+    FT_UShort   classTable;
+    FT_UShort   stateArray;
+    FT_UShort   entryTable;
+#define  GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE GXV_STATETABLE_HEADER_SIZE
+    FT_UShort*  classTable_length_p;
+    FT_UShort*  stateArray_length_p;
+    FT_UShort*  entryTable_length_p;
+  }  GXV_mort_subtable_type5_StateOptRec,
+    *GXV_mort_subtable_type5_StateOptRecData;
+
+
+  FT_LOCAL_DEF( void )
+  gxv_mort_subtable_type5_subtable_setup( FT_UShort      table_size,
+                                          FT_UShort      classTable,
+                                          FT_UShort      stateArray,
+                                          FT_UShort      entryTable,
+                                          FT_UShort*     classTable_length_p,
+                                          FT_UShort*     stateArray_length_p,
+                                          FT_UShort*     entryTable_length_p,
+                                          GXV_Validator  valid )
+  {
+    GXV_mort_subtable_type5_StateOptRecData  optdata = valid->statetable.optdata;
+    gxv_StateTable_subtable_setup( table_size,
+                                   classTable,
+                                   stateArray,
+                                   entryTable,
+                                   classTable_length_p,
+                                   stateArray_length_p,
+                                   entryTable_length_p,
+                                   valid );
+
+    optdata->classTable = classTable;
+    optdata->stateArray = stateArray;
+    optdata->entryTable = entryTable;
+    optdata->classTable_length_p = classTable_length_p;
+    optdata->stateArray_length_p = stateArray_length_p;
+    optdata->entryTable_length_p = entryTable_length_p;
+  }
+
+
+
+  static void
+  gxv_mort_subtable_type5_InsertList_validate( FT_UShort      offset,
+                                               FT_UShort      count,
+                                               FT_Bytes       table,
+                                               FT_Bytes       limit,
+                                               GXV_Validator  valid )
+  {
+    /*
+     * we don't know the range of insertion-glyph-list.
+     * set range by whole of state table
+     */
+    FT_Bytes  p = table + offset;
+    GXV_mort_subtable_type5_StateOptRecData  optdata = valid->statetable.optdata;
+
+    if ( optdata->classTable < offset &&
+         offset < optdata->classTable + *(optdata->classTable_length_p) )
+      GXV_TRACE(( " offset runs into ClassTable" ));
+    if ( optdata->stateArray < offset &&
+         offset < optdata->stateArray + *(optdata->stateArray_length_p) )
+      GXV_TRACE(( " offset runs into StateArray" ));
+    if ( optdata->entryTable < offset &&
+         offset < optdata->entryTable + *(optdata->entryTable_length_p) )
+      GXV_TRACE(( " offset runs into EntryTable" ));
+
+    while ( p < table + offset + ( count * 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_mort_subtable_type5_entry_validate( FT_Byte                         state,
+                                          FT_UShort                       flags,
+                                          GXV_StateTable_GlyphOffsetDesc  glyphOffset,
+                                          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_UShort  currentInsertList;
+    FT_UShort  markedInsertList;
+
+
+    setMark              = ( flags >> 15 ) & 1;
+    dontAdvance          = ( flags >> 14 ) & 1;
+    currentIsKashidaLike = ( flags >> 13 ) & 1;
+    markedIsKashidaLike  = ( flags >> 12 ) & 1;
+    currentInsertBefore  = ( flags >> 11 ) & 1;
+    markedInsertBefore   = ( flags >> 10 ) & 1;
+    currentInsertCount   = ( flags & 0x03E0 ) / 0x0020;
+    markedInsertCount    = ( flags & 0x001F );
+    currentInsertList    = glyphOffset.ul / 0x00010000;
+    markedInsertList     = glyphOffset.ul & 0x0000FFFF;
+
+    if ( 0 != currentInsertList && 0 != currentInsertCount )
+    {
+      gxv_mort_subtable_type5_InsertList_validate( currentInsertList,
+                                                   currentInsertCount,
+                                                   table,
+                                                   limit,
+                                                   valid );
+    }
+
+    if ( 0 != markedInsertList && 0 != markedInsertCount )
+    {
+      gxv_mort_subtable_type5_InsertList_validate( markedInsertList,
+                                                   markedInsertCount,
+                                                   table,
+                                                   limit,
+                                                   valid );
+    }
+  }
+
+
+  static void
+  gxv_mort_subtable_type5_validate( FT_Bytes       table,
+                                    FT_Bytes       limit,
+                                    GXV_Validator  valid )
+  {
+    FT_Bytes  p = table;
+    GXV_mort_subtable_type5_StateOptRec      et_rec;
+    GXV_mort_subtable_type5_StateOptRecData  et = &et_rec;
+
+
+    GXV_NAME_ENTER( "mort chain subtable type5 (Glyph Insertion)" );
+
+    GXV_LIMIT_CHECK( GXV_MORT_SUBTABLE_TYPE5_HEADER_SIZE );
+
+    valid->statetable.optdata               = et;
+    valid->statetable.optdata_load_func     = NULL;
+    valid->statetable.subtable_setup_func   = gxv_mort_subtable_type5_subtable_setup;
+    valid->statetable.entry_glyphoffset_fmt = GXV_GLYPHOFFSET_ULONG;
+    valid->statetable.entry_validate_func   = gxv_mort_subtable_type5_entry_validate;
+    gxv_StateTable_validate( p, limit, valid );
+    GXV_EXIT;
+  }
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmorx.c
@@ -1,0 +1,168 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmorx.c                                                              */
+/*                                                                         */
+/*    TrueTypeGX/AAT morx table validation (body).                         */
+/*                                                                         */
+/*  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 was support of 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_UInt   type;
+      FT_UInt   rest;
+
+
+      GXV_LIMIT_CHECK( 4 + 4 + 4 );
+      length          = FT_NEXT_ULONG( p );
+      coverage        = FT_NEXT_ULONG( p );
+      subFeatureFlags = FT_NEXT_ULONG( p );
+
+      GXV_TRACE(( "validate 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( ( 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;
+    gxv_morx_subtables_validate( p, table + chainLength, 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(( "validation morx table\n" ));
+    GXV_INIT;
+
+    GXV_LIMIT_CHECK( 4 + 4 );
+    version = FT_NEXT_ULONG( p );
+    nChains = FT_NEXT_ULONG( p );
+
+    if (version != 0x00020000)
+      FT_INVALID_FORMAT;
+
+    for ( i = 0; i < nChains; i++ )
+    {
+      GXV_TRACE(( "validate 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 */
--- /dev/null
+++ b/src/gxvalid/gxvmorx.h
@@ -1,0 +1,64 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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  /* Not def: __GXVMORX_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/gxvalid/gxvmorx0.c
@@ -1,0 +1,87 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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_GlyphOffsetDesc
+                                                         glyphOffset,
+                                          FT_Bytes       table,
+                                          FT_Bytes       limit,
+                                          GXV_Validator  valid )
+  {
+    FT_UShort markFirst;
+    FT_UShort dontAdvance;
+    FT_UShort markLast;
+    FT_UShort reserved;
+    FT_UShort verb;
+
+
+    markFirst   =   flags / 0x8000;
+    dontAdvance = ( flags & 0x4000 ) / 0x4000;
+    markLast    = ( flags & 0x2000 ) / 0x2000;
+    reserved    =   flags & 0x1FF0;
+    verb        =   flags & 0x000F;
+
+    if ( 0 < reserved )
+    {
+      GXV_TRACE(( " non-zero bits found in reserved range\n" ));
+      FT_INVALID_DATA;
+    }
+  }
+
+  static 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 */
--- /dev/null
+++ b/src/gxvalid/gxvmorx1.c
@@ -1,0 +1,238 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmorx1.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT morx table validation                                 */
+/*    body for type1 (Contextual 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 was support of 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 = 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 = 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_GlyphOffsetDesc
+                                                         glyphOffset,
+                                          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 = valid->xstatetable.optdata;
+
+
+    setMark      =   flags / 0x8000;
+    dontAdvance  = ( flags & 0x4000 ) / 0x4000;
+    reserved     =   flags & 0x3FFF;
+    markIndex    = GXV_USHORT_TO_SHORT( glyphOffset.ul / 0x00010000 );
+    currentIndex = GXV_USHORT_TO_SHORT( glyphOffset.ul & 0x0000FFFF );
+
+    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 = markIndex + 1;
+
+    if ( optdata->substitutionTable_num_lookupTables < currentIndex + 1 )
+      optdata->substitutionTable_num_lookupTables = currentIndex + 1;
+
+  }
+
+
+  static void
+  gxv_morx_subtable_type1_LookupValue_validate( FT_UShort            glyph,
+                                                GXV_LookupValueDesc  value,
+                                                GXV_Validator        valid )
+  {
+    GXV_TRACE(( "morx subtable type1 subst.: %d -> %d\n", glyph, value.u ));
+    if ( value.u > valid->face->num_glyphs )
+      FT_INVALID_GLYPH_ID;
+  }
+
+
+  static GXV_LookupValueDesc
+  gxv_morx_subtable_type1_LookupFmt4_transit( FT_UShort            relative_gindex,
+                                              GXV_LookupValueDesc  base_value,
+                                              FT_Bytes             lookuptbl_limit,
+                                              GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+
+    offset = base_value.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;
+    GXV_morx_subtable_type1_StateOptRecData  optdata = valid->xstatetable.optdata;
+    FT_UShort  i;
+
+
+    /* 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 substition is modified StateTable.
+   * In addition classTable, stateArray, entryTable, "substitutionTable"
+   * is added.
+   */
+  static 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 */
--- /dev/null
+++ b/src/gxvalid/gxvmorx2.c
@@ -1,0 +1,241 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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 = 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 = 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 = 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   = (lig_action & 0x80000000) / 0x80000000;
+      store  = (lig_action & 0x40000000) / 0x40000000;
+      offset =  lig_action & 0x3FFFFFFF;
+
+    }
+  }
+
+
+  static void
+  gxv_morx_subtable_type2_entry_validate( FT_UShort      state,
+                                          FT_UShort      flags,
+                                          GXV_StateTable_GlyphOffsetDesc
+                                                         glyphOffset,
+                                          FT_Bytes       table,
+                                          FT_Bytes       limit,
+                                          GXV_Validator  valid )
+  {
+    FT_UShort setComponent;
+    FT_UShort dontAdvance;
+    FT_UShort performAction;
+    FT_UShort reserved;
+    FT_UShort ligActionIndex;
+
+    setComponent   = ( flags & 0x8000 ) / 0x8000;
+    dontAdvance    = ( flags & 0x4000 ) / 0x4000;
+    performAction  = ( flags & 0x2000 ) / 0x2000;
+    reserved       =   flags & 0x1FFF;
+    ligActionIndex = glyphOffset.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 = 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;
+  }
+
+
+  static 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_MORT_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 */
--- /dev/null
+++ b/src/gxvalid/gxvmorx4.c
@@ -1,0 +1,50 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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_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 */
--- /dev/null
+++ b/src/gxvalid/gxvmorx5.c
@@ -1,0 +1,197 @@
+/***************************************************************************/
+/*                                                                         */
+/*  gxvmorx5.c                                                             */
+/*                                                                         */
+/*    TrueTypeGX/AAT morx table validation                                 */
+/*    body for type5 (Contextual Glyph Insertion) 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 was support of 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 StateTable with insertion-glyph-list
+ * without name. however, 32bit offset from the head
+ * of subtable to the i-g-l is given after "entryTable",
+ * without variable name specification (the exist of
+ * 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 = 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 = 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      index,
+                                               FT_UShort      count,
+                                               FT_Bytes       table,
+                                               FT_Bytes       limit,
+                                               GXV_Validator  valid )
+  {
+    FT_Bytes p = table + ( index * 2 );
+
+    while ( p < table + ( count * 2 ) + ( 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_GlyphOffsetDesc
+                                                         glyphOffset,
+                                          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_Bool    currentInsertCount;
+    FT_Byte    markedInsertCount;
+    FT_Byte    currentInsertList;
+    FT_UShort  markedInsertList;
+
+
+    setMark              = ( flags >> 15 ) & 1;
+    dontAdvance          = ( flags >> 14 ) & 1;
+    currentIsKashidaLike = ( flags >> 13 ) & 1;
+    markedIsKashidaLike  = ( flags >> 12 ) & 1;
+    currentInsertBefore  = ( flags >> 11 ) & 1;
+    markedInsertBefore   = ( flags >> 10 ) & 1;
+    currentInsertCount   = ( flags & 0x03E0 ) / 0x20;
+    markedInsertCount    = ( flags & 0x001F );
+    currentInsertList    = glyphOffset.ul / 0x00010000;
+    markedInsertList     = glyphOffset.ul & 0x0000FFFF;
+
+    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 );
+    }
+  }
+
+
+  static 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 */
--- /dev/null
+++ b/src/gxvalid/gxvopbd.c
@@ -1,0 +1,205 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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.                                        */
+/*                                                                         */
+/***************************************************************************/
+
+#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_LookupValueDesc  value,
+                                 GXV_Validator        valid )
+  {
+    /* offset in LookupTable is measured from the head of opbd table */
+    FT_Bytes   p     = valid->root->base + value.u;
+    FT_Bytes   limit = valid->root->limit;
+    FT_Short   delta_value;
+    int        i;
+
+
+    if ( value.u < GXV_OPBD_DATA( valueOffset_min ) )
+      GXV_OPBD_DATA( valueOffset_min ) = value.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_LookupValueDesc  base_value,
+                               FT_Bytes             lookuptbl_limit,
+                               GXV_Validator        valid )
+  {
+    GXV_LookupValueDesc  value;
+
+
+    value.u = base_value.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(( "validation opbd table\n" ));
+    GXV_INIT;
+    GXV_OPBD_DATA( valueOffset_min ) = 0xFFFF;
+
+
+    GXV_LIMIT_CHECK( 4 + 2 );
+    version                 = FT_NEXT_ULONG( p );
+    GXV_OPBD_DATA( format ) = FT_NEXT_USHORT( p );
+
+
+    /* 0x00010000 is only defined (1996) */
+    GXV_TRACE(( "(version=0x%08x)\n", version ));
+    if ( 0x00010000UL != version )
+      FT_INVALID_FORMAT;
+
+    /* 0, 1 are only 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 */
--- /dev/null
+++ b/src/gxvalid/gxvprop.c
@@ -1,0 +1,302 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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                      0x8000
+#define GXV_PROP_USE_COMPLEMENTARY_BRACKET    0x1000
+#define GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET 0x0F00
+#define GXV_PROP_ATTACHING_TO_RIGHT           0x0080
+#define GXV_PROP_RESERVED                     0x0060
+#define GXV_PROP_DIRECTIONALITY_CLASS         0x001F
+
+
+  /*************************************************************************/
+  /*************************************************************************/
+  /*****                                                               *****/
+  /*****                      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 = property & GXV_PROP_COMPLEMENTARY_BRACKET_OFFSET;
+      if ( offset == 0 )
+        FT_INVALID_DATA;
+
+      complement = offset >> 8;
+      if ( complement & 0x08 )
+      {
+        /* Top bit is set: nagative */
+
+        /* Calculated the absolute offset */
+        complement = ( 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( 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 ver 2.0 */
+    if ( property & GXV_PROP_ATTACHING_TO_RIGHT )
+    {
+      if ( GXV_PROP_DATA( version ) == 0x00010000 )
+        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 ) == 0x00010000 ||
+           GXV_PROP_DATA( version ) == 0x00020000 )
+        FT_INVALID_DATA;
+    }
+  }
+
+  static void
+  gxv_prop_LookupValue_validate( FT_UShort            glyph,
+                                 GXV_LookupValueDesc  value,
+                                 GXV_Validator        valid )
+  {
+    gxv_prop_property_validate( value.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_LookupValueDesc  base_value,
+                               FT_Bytes             lookuptbl_limit,
+                               GXV_Validator        valid )
+  {
+    FT_Bytes             p;
+    FT_Bytes             limit;
+    FT_UShort            offset;
+    GXV_LookupValueDesc  value;
+
+
+    offset = base_value.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(( "validation 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 );
+
+
+    /* version 1.0, 2.0, 3.0 are only defined (1996) */
+    if ( version != 0x00010000 &&
+         version != 0x00020000 &&
+         version != 0x00030000 )
+      FT_INVALID_FORMAT;
+
+
+    /* format 0x0000, 0x0001 are only 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, "
+                  "rest %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 */
--- /dev/null
+++ b/src/gxvalid/gxvtrak.c
@@ -1,0 +1,282 @@
+/***************************************************************************/
+/*                                                                         */
+/*  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 was support of 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                           *****/
+  /*****                                                               *****/
+  /*************************************************************************/
+  /*************************************************************************/
+
+    /*
+     * refered track table format specification:
+     * http://developer.apple.com/fonts/TTRefMan/RM06/Chap6trak.html
+     * last update is 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,
+                                FT_UShort      nSizes,
+                                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 ) = 0xFFFF;
+    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, nSizes, 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_UInt           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(( "validation 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 */
--- /dev/null
+++ b/src/gxvalid/module.mk
@@ -1,0 +1,21 @@
+#
+# FreeType 2 gxvalid module definition
+#
+
+# 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.
+
+
+make_module_list: add_gxvalid_module
+
+add_gxvalid_module:
+	$(OPEN_DRIVER)gxvalid_module_class$(CLOSE_DRIVER)
+	$(ECHO_DRIVER)gxvalid     $(ECHO_DRIVER_DESC)TrueTypeGX/AAT validation module$(ECHO_DRIVER_DONE)
+
+# EOF
--- /dev/null
+++ b/src/gxvalid/rules.mk
@@ -1,0 +1,93 @@
+#
+# 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)/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